[SCM] libopenmpt/master: New upstream version 0.3.1

jcowgill at users.alioth.debian.org jcowgill at users.alioth.debian.org
Mon Oct 2 18:16:44 UTC 2017


The following commit has been merged in the master branch:
commit 24b4ac9afef21e7b350bafb876e0134857788d10
Author: James Cowgill <jcowgill at debian.org>
Date:   Fri Sep 29 21:07:02 2017 +0100

    New upstream version 0.3.1

diff --git a/Doxyfile.in b/Doxyfile.in
index 7429f46..ee1e2db 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.8
+# Doxyfile 1.8.13
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
@@ -45,10 +45,10 @@ PROJECT_NAME           = "libopenmpt"
 
 PROJECT_BRIEF          = "cross-platform C++ and C library to decode tracked music files"
 
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
 
 PROJECT_LOGO           =
 
@@ -59,7 +59,7 @@ PROJECT_LOGO           =
 
 OUTPUT_DIRECTORY       = bin/docs
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
 # directories (in 2 levels) under the output directory of each output format and
 # will distribute the generated files over these directories. Enabling this
 # option can be useful when feeding doxygen a huge amount of source files, where
@@ -92,14 +92,14 @@ ALLOW_UNICODE_NAMES    = NO
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
 # descriptions after the members that are listed in the file and class
 # documentation (similar to Javadoc). Set to NO to disable this.
 # The default value is: YES.
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
 # description of a member or function before the detailed description
 #
 # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -134,7 +134,7 @@ ALWAYS_DETAILED_SEC    = NO
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
 # before files name in the file list and in the header files. If set to NO the
 # shortest path that makes the file name unique will be used
 # The default value is: YES.
@@ -204,9 +204,9 @@ MULTILINE_CPP_IS_BRIEF = NO
 
 INHERIT_DOCS           = YES
 
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
 # The default value is: NO.
 
 SEPARATE_MEMBER_PAGES  = NO
@@ -275,7 +275,7 @@ OPTIMIZE_OUTPUT_VHDL   = NO
 # instance to make doxygen treat .inc files as Fortran files (default is PHP),
 # and .f files as C (default is Fortran), use: inc=Fortran f=C.
 #
-# Note For files without extension you can use no_extension as a placeholder.
+# Note: For files without extension you can use no_extension as a placeholder.
 #
 # Note that for custom extensions you also need to set FILE_PATTERNS otherwise
 # the files are not read by doxygen.
@@ -292,10 +292,19 @@ EXTENSION_MAPPING      =
 
 MARKDOWN_SUPPORT       = YES
 
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
 # When enabled doxygen tries to link words that correspond to documented
 # classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
 # The default value is: YES.
 
 AUTOLINK_SUPPORT       = YES
@@ -335,13 +344,20 @@ SIP_SUPPORT            = NO
 IDL_PROPERTY_SUPPORT   = YES
 
 # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
+# tag is set to YES then doxygen will reuse the documentation of the first
 # member in the group (if any) for the other members of the group. By default
 # all members of a group must be documented explicitly.
 # The default value is: NO.
 
 DISTRIBUTE_GROUP_DOC   = NO
 
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
 # Set the SUBGROUPING tag to YES to allow class member groups of the same type
 # (for instance a group of public functions) to be put as a subgroup of that
 # type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -400,7 +416,7 @@ LOOKUP_CACHE_SIZE      = 0
 # Build related configuration options
 #---------------------------------------------------------------------------
 
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
 # documentation are documented, even if no documentation was available. Private
 # class members and static file members will be hidden unless the
 # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -410,35 +426,35 @@ LOOKUP_CACHE_SIZE      = 0
 
 EXTRACT_ALL            = YES
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
 # be included in the documentation.
 # The default value is: NO.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
 # scope will be included in the documentation.
 # The default value is: NO.
 
 EXTRACT_PACKAGE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
 # included in the documentation.
 # The default value is: NO.
 
 EXTRACT_STATIC         = YES
 
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
 # only classes defined in header files are included. Does not have any effect
 # for Java sources.
 # The default value is: YES.
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local methods,
+# This flag is only useful for Objective-C code. If set to YES, local methods,
 # which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
 # included.
 # The default value is: NO.
 
@@ -463,21 +479,21 @@ HIDE_UNDOC_MEMBERS     = NO
 
 # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
 # undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
 # The default value is: NO.
 
 HIDE_UNDOC_CLASSES     = NO
 
 # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
+# (class|struct|union) declarations. If set to NO, these declarations will be
 # included in the documentation.
 # The default value is: NO.
 
 HIDE_FRIEND_COMPOUNDS  = NO
 
 # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
+# documentation blocks found inside the body of a function. If set to NO, these
 # blocks will be appended to the function's detailed documentation block.
 # The default value is: NO.
 
@@ -491,7 +507,7 @@ HIDE_IN_BODY_DOCS      = NO
 INTERNAL_DOCS          = NO
 
 # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
+# names in lower-case letters. If set to YES, upper-case letters are also
 # allowed. This is useful if you have classes or files whose names only differ
 # in case and if your file system supports case sensitive file names. Windows
 # and Mac users are advised to set this option to NO.
@@ -500,12 +516,19 @@ INTERNAL_DOCS          = NO
 CASE_SENSE_NAMES       = YES
 
 # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
+# their full class and namespace scopes in the documentation. If set to YES, the
 # scope will be hidden.
 # The default value is: NO.
 
 HIDE_SCOPE_NAMES       = NO
 
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
 # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
 # the files that are included by a file in the documentation of that file.
 # The default value is: YES.
@@ -533,14 +556,14 @@ INLINE_INFO            = YES
 
 # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
 # (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
+# name. If set to NO, the members will appear in declaration order.
 # The default value is: YES.
 
 SORT_MEMBER_DOCS       = YES
 
 # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
 # descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
+# name. If set to NO, the members will appear in declaration order. Note that
 # this will also influence the order of the classes in the class list.
 # The default value is: NO.
 
@@ -585,27 +608,25 @@ SORT_BY_SCOPE_NAME     = NO
 
 STRICT_PROTO_MATCHING  = NO
 
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
 # The default value is: YES.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
 # The default value is: YES.
 
 GENERATE_TESTLIST      = YES
 
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
 # list. This list is created by putting \bug commands in the documentation.
 # The default value is: YES.
 
 GENERATE_BUGLIST       = YES
 
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
 # the deprecated list. This list is created by putting \deprecated commands in
 # the documentation.
 # The default value is: YES.
@@ -630,8 +651,8 @@ ENABLED_SECTIONS       =
 MAX_INITIALIZER_LINES  = 30
 
 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
 # The default value is: YES.
 
 SHOW_USED_FILES        = YES
@@ -695,7 +716,7 @@ CITE_BIB_FILES         =
 QUIET                  = YES
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
 # this implies that the warnings are on.
 #
 # Tip: Turn warnings on while writing the documentation.
@@ -703,7 +724,7 @@ QUIET                  = YES
 
 WARNINGS               = YES
 
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
 # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
 # will automatically be disabled.
 # The default value is: YES.
@@ -720,12 +741,18 @@ WARN_IF_DOC_ERROR      = YES
 
 # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
 # are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
 # The default value is: NO.
 
 WARN_NO_PARAMDOC       = NO
 
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
 # The WARN_FORMAT tag determines the format of the warning messages that doxygen
 # can produce. The string should contain the $file, $line, and $text tags, which
 # will be replaced by the file and line number from which the warning originated
@@ -749,7 +776,7 @@ WARN_LOGFILE           =
 # The INPUT tag is used to specify the files and/or directories that contain
 # documented source files. You may enter file names like myfile.cpp or
 # directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = libopenmpt/dox/index.dox \
@@ -762,6 +789,7 @@ INPUT                  = libopenmpt/dox/index.dox \
                          libopenmpt/dox/todo.md \
                          libopenmpt/libopenmpt.hpp \
                          libopenmpt/libopenmpt.h \
+                         libopenmpt/libopenmpt_stream_callbacks_buffer.h \
                          libopenmpt/libopenmpt_stream_callbacks_fd.h \
                          libopenmpt/libopenmpt_stream_callbacks_file.h \
                          libopenmpt/libopenmpt_config.h \
@@ -779,12 +807,17 @@ INPUT_ENCODING         = UTF-8
 
 # If the value of the INPUT tag contains directories, you can use the
 # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
 
 FILE_PATTERNS          =
 
@@ -879,6 +912,10 @@ IMAGE_PATH             =
 # Note that the filter must not add or remove lines; it is applied before the
 # code is scanned, but not when the output code is generated. If lines are added
 # or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
 
 INPUT_FILTER           =
 
@@ -888,11 +925,15 @@ INPUT_FILTER           =
 # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
 # filters are used. If the FILTER_PATTERNS tag is empty or if none of the
 # patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
 
 FILTER_PATTERNS        =
 
 # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
+# INPUT_FILTER) will also be used to filter the input files that are used for
 # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
 # The default value is: NO.
 
@@ -952,7 +993,7 @@ REFERENCED_BY_RELATION = NO
 REFERENCES_RELATION    = NO
 
 # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
 # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
 # link to the documentation.
 # The default value is: YES.
@@ -999,13 +1040,13 @@ USE_HTAGS              = NO
 
 VERBATIM_HEADERS       = YES
 
-# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
 # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
 # cost of reduced performance. This can be particularly helpful with template
 # rich C++ code for which doxygen's built-in parser lacks the necessary type
 # information.
 # Note: The availability of this option depends on whether or not doxygen was
-# compiled with the --with-libclang option.
+# generated with the -Duse-libclang=ON option for CMake.
 # The default value is: NO.
 
 CLANG_ASSISTED_PARSING = NO
@@ -1048,7 +1089,7 @@ IGNORE_PREFIX          =
 # Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
 # The default value is: YES.
 
 GENERATE_HTML          = YES
@@ -1114,10 +1155,10 @@ HTML_STYLESHEET        =
 # cascading style sheets that are included after the standard style sheets
 # created by doxygen. Using this option one can overrule certain style aspects.
 # This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
 # Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra stylesheet files is of importance (e.g. the last
-# stylesheet in the list overrules the setting of the previous ones in the
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
 # list). For an example see the documentation.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
@@ -1134,7 +1175,7 @@ HTML_EXTRA_STYLESHEET  =
 HTML_EXTRA_FILES       =
 
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
+# will adjust the colors in the style sheet and background images according to
 # this color. Hue is specified as an angle on a colorwheel, see
 # http://en.wikipedia.org/wiki/Hue for more information. For instance the value
 # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
@@ -1165,8 +1206,9 @@ HTML_COLORSTYLE_GAMMA  = 80
 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
 # page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_TIMESTAMP         = YES
@@ -1262,28 +1304,28 @@ GENERATE_HTMLHELP      = NO
 CHM_FILE               =
 
 # The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
 # doxygen will try to run the HTML help compiler on the generated index.hhp.
 # The file has to be specified with full path.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 HHC_LOCATION           =
 
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 GENERATE_CHI           = NO
 
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
 # and project file content.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 CHM_INDEX_ENCODING     =
 
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
 # enables the Previous and Next buttons.
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1397,7 +1439,7 @@ DISABLE_INDEX          = NO
 # index structure (just like the one that is generated for HTML Help). For this
 # to work a browser that supports JavaScript, DHTML, CSS and frames is required
 # (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
 # further fine-tune the look of the index. As an example, the default style
 # sheet generated by doxygen has an example that shows how to put an image at
 # the root of the tree instead of the PROJECT_NAME. Since the tree basically has
@@ -1425,7 +1467,7 @@ ENUM_VALUES_PER_LINE   = 4
 
 TREEVIEW_WIDTH         = 250
 
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
 # external symbols imported via tag files in a separate window.
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1454,7 +1496,7 @@ FORMULA_TRANSPARENT    = YES
 
 # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
 # http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
 # installed or if you want to formulas look prettier in the HTML output. When
 # enabled you may also need to install MathJax separately and configure the path
 # to it using the MATHJAX_RELPATH option.
@@ -1540,7 +1582,7 @@ SERVER_BASED_SEARCH    = NO
 # external search engine pointed to by the SEARCHENGINE_URL option to obtain the
 # search results.
 #
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
 # (doxysearch.cgi) which are based on the open source search engine library
 # Xapian (see: http://xapian.org/).
 #
@@ -1553,7 +1595,7 @@ EXTERNAL_SEARCH        = NO
 # The SEARCHENGINE_URL should point to a search engine hosted by a web server
 # which will return the search results when EXTERNAL_SEARCH is enabled.
 #
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
 # (doxysearch.cgi) which are based on the open source search engine library
 # Xapian (see: http://xapian.org/). See the section "External Indexing and
 # Searching" for details.
@@ -1591,7 +1633,7 @@ EXTRA_SEARCH_MAPPINGS  =
 # Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
 # The default value is: YES.
 
 GENERATE_LATEX         = NO
@@ -1622,7 +1664,7 @@ LATEX_CMD_NAME         = latex
 
 MAKEINDEX_CMD_NAME     = makeindex
 
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
 # documents. This may be useful for small projects and may help to save some
 # trees in general.
 # The default value is: NO.
@@ -1640,9 +1682,12 @@ COMPACT_LATEX          = NO
 PAPER_TYPE             = a4
 
 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
 # If left blank no extra packages will be included.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
 
@@ -1657,9 +1702,9 @@ EXTRA_PACKAGES         =
 # Note: Only use a user-defined header if you know what you are doing! The
 # following commands have a special meaning inside the header: $title,
 # $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
-# for the replacement values of the other commands the user is refered to
-# HTML_HEADER.
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_HEADER           =
@@ -1675,6 +1720,17 @@ LATEX_HEADER           =
 
 LATEX_FOOTER           =
 
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
 # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
 # other source files which should be copied to the LATEX_OUTPUT output
 # directory. Note that the files will be copied as-is; there are no commands or
@@ -1693,7 +1749,7 @@ LATEX_EXTRA_FILES      =
 PDF_HYPERLINKS         = YES
 
 # If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
 # higher quality PDF documentation.
 # The default value is: YES.
 # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1734,11 +1790,19 @@ LATEX_SOURCE_CODE      = NO
 
 LATEX_BIB_STYLE        = plain
 
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
 #---------------------------------------------------------------------------
 # Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
 # RTF output is optimized for Word 97 and may not look too pretty with other RTF
 # readers/editors.
 # The default value is: NO.
@@ -1753,7 +1817,7 @@ GENERATE_RTF           = NO
 
 RTF_OUTPUT             = rtf
 
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
 # documents. This may be useful for small projects and may help to save some
 # trees in general.
 # The default value is: NO.
@@ -1790,11 +1854,21 @@ RTF_STYLESHEET_FILE    =
 
 RTF_EXTENSIONS_FILE    =
 
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
 #---------------------------------------------------------------------------
 # Configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
 # classes and files.
 # The default value is: NO.
 
@@ -1838,7 +1912,7 @@ MAN_LINKS              = YES
 # Configuration options related to the XML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
 # captures the structure of the code including all documentation.
 # The default value is: NO.
 
@@ -1852,7 +1926,7 @@ GENERATE_XML           = NO
 
 XML_OUTPUT             = xml
 
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
 # listings (including syntax highlighting and cross-referencing information) to
 # the XML output. Note that enabling this will significantly increase the size
 # of the XML output.
@@ -1865,7 +1939,7 @@ XML_PROGRAMLISTING     = YES
 # Configuration options related to the DOCBOOK output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
 # that can be used to generate PDF.
 # The default value is: NO.
 
@@ -1879,7 +1953,7 @@ GENERATE_DOCBOOK       = NO
 
 DOCBOOK_OUTPUT         = docbook
 
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
 # program listings (including syntax highlighting and cross-referencing
 # information) to the DOCBOOK output. Note that enabling this will significantly
 # increase the size of the DOCBOOK output.
@@ -1892,10 +1966,10 @@ DOCBOOK_PROGRAMLISTING = NO
 # Configuration options for the AutoGen Definitions output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
 # The default value is: NO.
 
 GENERATE_AUTOGEN_DEF   = NO
@@ -1904,7 +1978,7 @@ GENERATE_AUTOGEN_DEF   = NO
 # Configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
 # file that captures the structure of the code including all documentation.
 #
 # Note that this feature is still experimental and incomplete at the moment.
@@ -1912,7 +1986,7 @@ GENERATE_AUTOGEN_DEF   = NO
 
 GENERATE_PERLMOD       = NO
 
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
 # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
 # output from the Perl module output.
 # The default value is: NO.
@@ -1920,9 +1994,9 @@ GENERATE_PERLMOD       = NO
 
 PERLMOD_LATEX          = NO
 
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
 # formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
+# understand what is going on. On the other hand, if this tag is set to NO, the
 # size of the Perl module output will be much smaller and Perl will parse it
 # just the same.
 # The default value is: YES.
@@ -1942,14 +2016,14 @@ PERLMOD_MAKEVAR_PREFIX =
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
 # C-preprocessor directives found in the sources and include files.
 # The default value is: YES.
 
 ENABLE_PREPROCESSING   = YES
 
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
 # performed. Macro expansion can be done in a controlled way by setting
 # EXPAND_ONLY_PREDEF to YES.
 # The default value is: NO.
@@ -1965,7 +2039,7 @@ MACRO_EXPANSION        = YES
 
 EXPAND_ONLY_PREDEF     = NO
 
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
 # INCLUDE_PATH will be searched if a #include is found.
 # The default value is: YES.
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -1995,8 +2069,7 @@ INCLUDE_FILE_PATTERNS  =
 # recursively expanded use the := operator instead of the = operator.
 # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
-PREDEFINED             = DOXYGEN \
-                         LIBOPENMPT_EXT_IS_EXPERIMENTAL
+PREDEFINED             = DOXYGEN
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
 # tag can be used to specify a list of macro names that should be expanded. The
@@ -2042,20 +2115,21 @@ TAGFILES               =
 
 GENERATE_TAGFILE       =
 
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
 # The default value is: NO.
 
 ALLEXTERNALS           = NO
 
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
 # listed.
 # The default value is: YES.
 
 EXTERNAL_GROUPS        = YES
 
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
 # the related pages index. If set to NO, only the current project's pages will
 # be listed.
 # The default value is: YES.
@@ -2072,7 +2146,7 @@ PERL_PATH              = /usr/bin/perl
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
 # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
 # NO turns the diagrams off. Note that this option also works with HAVE_DOT
 # disabled, but it is recommended to install and use dot, since it yields more
@@ -2097,7 +2171,7 @@ MSCGEN_PATH            =
 
 DIA_PATH               =
 
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# If set to YES the inheritance and collaboration graphs will hide inheritance
 # and usage relations if the target is undocumented or is not a class.
 # The default value is: YES.
 
@@ -2170,7 +2244,7 @@ COLLABORATION_GRAPH    = YES
 
 GROUP_GRAPHS           = YES
 
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
 # collaboration diagrams in a style similar to the OMG's Unified Modeling
 # Language.
 # The default value is: NO.
@@ -2222,7 +2296,8 @@ INCLUDED_BY_GRAPH      = YES
 #
 # Note that enabling this option will significantly increase the time of a run.
 # So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
 # The default value is: NO.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2233,7 +2308,8 @@ CALL_GRAPH             = NO
 #
 # Note that enabling this option will significantly increase the time of a run.
 # So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
 # The default value is: NO.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2256,13 +2332,17 @@ GRAPHICAL_HIERARCHY    = YES
 DIRECTORY_GRAPH        = YES
 
 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
 # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
 # to make the SVG files visible in IE 9+ (other browsers do not have this
 # requirement).
 # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
 # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
-# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
 # The default value is: png.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
@@ -2310,10 +2390,19 @@ DIAFILE_DIRS           =
 # PlantUML is not used or called during a preprocessing step. Doxygen will
 # generate a warning when it encounters a \startuml command in this case and
 # will not generate output for the diagram.
-# This tag requires that the tag HAVE_DOT is set to YES.
 
 PLANTUML_JAR_PATH      =
 
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
 # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
 # that will be shown in the graph. If the number of nodes in a graph becomes
 # larger than this value, doxygen will truncate the graph, which is visualized
@@ -2350,7 +2439,7 @@ MAX_DOT_GRAPH_DEPTH    = 0
 
 DOT_TRANSPARENT        = NO
 
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
 # files in one run (i.e. multiple -o and -T options on the command line). This
 # makes dot run faster, but since only newer versions of dot (>1.8.10) support
 # this, this feature is disabled by default.
@@ -2367,7 +2456,7 @@ DOT_MULTI_TARGETS      = YES
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
 # files that are used to generate the various graphs.
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
@@ -2375,3 +2464,4 @@ GENERATE_LEGEND        = YES
 DOT_CLEANUP            = YES
 PROJECT_NUMBER = @PACKAGE_VERSION@
 OUTPUT_DIRECTORY = doxygen-doc
+WARN_IF_DOC_ERROR = NO
diff --git a/Makefile.am b/Makefile.am
index 3023ce7..8f16c63 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,6 +13,7 @@ EXTRA_DIST += libopenmpt/dox/packaging.md
 EXTRA_DIST += libopenmpt/dox/quickstart.md
 EXTRA_DIST += libopenmpt/dox/tests.md
 EXTRA_DIST += libopenmpt/dox/todo.md
+EXTRA_DIST += libopenmpt/libopenmpt_version.mk
 EXTRA_DIST += test/test.xm
 EXTRA_DIST += test/test.s3m
 EXTRA_DIST += test/test.mptm
@@ -24,7 +25,6 @@ MOSTLYCLEANFILES =
 dist_doc_DATA = 
 dist_doc_DATA += LICENSE
 dist_doc_DATA += README.md
-dist_doc_DATA += TODO
 nobase_dist_doc_DATA = 
 nobase_dist_doc_DATA += examples/libopenmpt_example_cxx.cpp
 nobase_dist_doc_DATA += examples/libopenmpt_example_c_mem.c
@@ -103,229 +103,284 @@ pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = 
 nobase_include_HEADERS = 
 
+MPT_FILES_COMMON = 
+MPT_FILES_COMMON += common/BuildSettings.h
+MPT_FILES_COMMON += common/CompilerDetect.h
+MPT_FILES_COMMON += common/ComponentManager.cpp
+MPT_FILES_COMMON += common/ComponentManager.h
+MPT_FILES_COMMON += common/Endianness.h
+MPT_FILES_COMMON += common/FileReader.cpp
+MPT_FILES_COMMON += common/FileReader.h
+MPT_FILES_COMMON += common/FileReaderFwd.h
+MPT_FILES_COMMON += common/FlagSet.h
+MPT_FILES_COMMON += common/Logging.cpp
+MPT_FILES_COMMON += common/Logging.h
+MPT_FILES_COMMON += common/misc_util.cpp
+MPT_FILES_COMMON += common/misc_util.h
+MPT_FILES_COMMON += common/mptBufferIO.h
+MPT_FILES_COMMON += common/mptCPU.cpp
+MPT_FILES_COMMON += common/mptCPU.h
+MPT_FILES_COMMON += common/mptCRC.h
+MPT_FILES_COMMON += common/mptFileIO.cpp
+MPT_FILES_COMMON += common/mptFileIO.h
+MPT_FILES_COMMON += common/mptIO.cpp
+MPT_FILES_COMMON += common/mptIO.h
+MPT_FILES_COMMON += common/mptLibrary.cpp
+MPT_FILES_COMMON += common/mptLibrary.h
+MPT_FILES_COMMON += common/mptMutex.h
+MPT_FILES_COMMON += common/mptOS.cpp
+MPT_FILES_COMMON += common/mptOS.h
+MPT_FILES_COMMON += common/mptPathString.cpp
+MPT_FILES_COMMON += common/mptPathString.h
+MPT_FILES_COMMON += common/mptRandom.cpp
+MPT_FILES_COMMON += common/mptRandom.h
+MPT_FILES_COMMON += common/mptString.cpp
+MPT_FILES_COMMON += common/mptString.h
+MPT_FILES_COMMON += common/mptStringFormat.cpp
+MPT_FILES_COMMON += common/mptStringFormat.h
+MPT_FILES_COMMON += common/mptStringParse.cpp
+MPT_FILES_COMMON += common/mptStringParse.h
+MPT_FILES_COMMON += common/mptThread.h
+MPT_FILES_COMMON += common/mptTime.cpp
+MPT_FILES_COMMON += common/mptTime.h
+MPT_FILES_COMMON += common/mptTypeTraits.h
+MPT_FILES_COMMON += common/mptUUID.cpp
+MPT_FILES_COMMON += common/mptUUID.h
+MPT_FILES_COMMON += common/mptWine.cpp
+MPT_FILES_COMMON += common/mptWine.h
+MPT_FILES_COMMON += common/Profiler.cpp
+MPT_FILES_COMMON += common/Profiler.h
+MPT_FILES_COMMON += common/serialization_utils.cpp
+MPT_FILES_COMMON += common/serialization_utils.h
+MPT_FILES_COMMON += common/stdafx.cpp
+MPT_FILES_COMMON += common/stdafx.h
+MPT_FILES_COMMON += common/StringFixer.h
+MPT_FILES_COMMON += common/typedefs.cpp
+MPT_FILES_COMMON += common/typedefs.h
+MPT_FILES_COMMON += common/version.cpp
+MPT_FILES_COMMON += common/version.h
+MPT_FILES_COMMON += common/versionNumber.h
+MPT_FILES_SOUNDBASE = 
+MPT_FILES_SOUNDBASE += soundbase/SampleFormat.h
+MPT_FILES_SOUNDBASE += soundbase/SampleFormatConverters.h
+MPT_FILES_SOUNDBASE += soundbase/SampleFormatCopy.h
+MPT_FILES_SOUNDLIB = 
+MPT_FILES_SOUNDLIB += soundlib/AudioCriticalSection.cpp
+MPT_FILES_SOUNDLIB += soundlib/AudioCriticalSection.h
+MPT_FILES_SOUNDLIB += soundlib/AudioReadTarget.h
+MPT_FILES_SOUNDLIB += soundlib/ChunkReader.h
+MPT_FILES_SOUNDLIB += soundlib/ContainerMMCMP.cpp
+MPT_FILES_SOUNDLIB += soundlib/ContainerPP20.cpp
+MPT_FILES_SOUNDLIB += soundlib/ContainerUMX.cpp
+MPT_FILES_SOUNDLIB += soundlib/ContainerXPK.cpp
+MPT_FILES_SOUNDLIB += soundlib/Container.h
+MPT_FILES_SOUNDLIB += soundlib/Dither.cpp
+MPT_FILES_SOUNDLIB += soundlib/Dither.h
+MPT_FILES_SOUNDLIB += soundlib/Dlsbank.cpp
+MPT_FILES_SOUNDLIB += soundlib/Dlsbank.h
+MPT_FILES_SOUNDLIB += soundlib/Fastmix.cpp
+MPT_FILES_SOUNDLIB += soundlib/FloatMixer.h
+MPT_FILES_SOUNDLIB += soundlib/InstrumentExtensions.cpp
+MPT_FILES_SOUNDLIB += soundlib/IntMixer.h
+MPT_FILES_SOUNDLIB += soundlib/ITCompression.cpp
+MPT_FILES_SOUNDLIB += soundlib/ITCompression.h
+MPT_FILES_SOUNDLIB += soundlib/ITTools.cpp
+MPT_FILES_SOUNDLIB += soundlib/ITTools.h
+MPT_FILES_SOUNDLIB += soundlib/Load_669.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_amf.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_ams.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_dbm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_digi.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_dmf.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_dsm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_dtm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Loaders.h
+MPT_FILES_SOUNDLIB += soundlib/Load_far.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_gdm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_imf.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_it.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_itp.cpp
+MPT_FILES_SOUNDLIB += soundlib/load_j2b.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_mdl.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_med.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_mid.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_mo3.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_mod.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_mt2.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_mtm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_okt.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_plm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_psm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_ptm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_s3m.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_sfx.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_stm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_stp.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_uax.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_ult.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_wav.cpp
+MPT_FILES_SOUNDLIB += soundlib/Load_xm.cpp
+MPT_FILES_SOUNDLIB += soundlib/Message.cpp
+MPT_FILES_SOUNDLIB += soundlib/Message.h
+MPT_FILES_SOUNDLIB += soundlib/MIDIEvents.cpp
+MPT_FILES_SOUNDLIB += soundlib/MIDIEvents.h
+MPT_FILES_SOUNDLIB += soundlib/MIDIMacros.cpp
+MPT_FILES_SOUNDLIB += soundlib/MIDIMacros.h
+MPT_FILES_SOUNDLIB += soundlib/Mixer.h
+MPT_FILES_SOUNDLIB += soundlib/MixerInterface.h
+MPT_FILES_SOUNDLIB += soundlib/MixerLoops.cpp
+MPT_FILES_SOUNDLIB += soundlib/MixerLoops.h
+MPT_FILES_SOUNDLIB += soundlib/MixerSettings.cpp
+MPT_FILES_SOUNDLIB += soundlib/MixerSettings.h
+MPT_FILES_SOUNDLIB += soundlib/MixFuncTable.cpp
+MPT_FILES_SOUNDLIB += soundlib/MixFuncTable.h
+MPT_FILES_SOUNDLIB += soundlib/ModChannel.cpp
+MPT_FILES_SOUNDLIB += soundlib/ModChannel.h
+MPT_FILES_SOUNDLIB += soundlib/modcommand.cpp
+MPT_FILES_SOUNDLIB += soundlib/modcommand.h
+MPT_FILES_SOUNDLIB += soundlib/ModInstrument.cpp
+MPT_FILES_SOUNDLIB += soundlib/ModInstrument.h
+MPT_FILES_SOUNDLIB += soundlib/ModSample.cpp
+MPT_FILES_SOUNDLIB += soundlib/ModSample.h
+MPT_FILES_SOUNDLIB += soundlib/ModSampleCopy.h
+MPT_FILES_SOUNDLIB += soundlib/ModSequence.cpp
+MPT_FILES_SOUNDLIB += soundlib/ModSequence.h
+MPT_FILES_SOUNDLIB += soundlib/modsmp_ctrl.cpp
+MPT_FILES_SOUNDLIB += soundlib/modsmp_ctrl.h
+MPT_FILES_SOUNDLIB += soundlib/mod_specifications.cpp
+MPT_FILES_SOUNDLIB += soundlib/mod_specifications.h
+MPT_FILES_SOUNDLIB += soundlib/MPEGFrame.cpp
+MPT_FILES_SOUNDLIB += soundlib/MPEGFrame.h
+MPT_FILES_SOUNDLIB += soundlib/OggStream.cpp
+MPT_FILES_SOUNDLIB += soundlib/OggStream.h
+MPT_FILES_SOUNDLIB += soundlib/Paula.cpp
+MPT_FILES_SOUNDLIB += soundlib/Paula.h
+MPT_FILES_SOUNDLIB += soundlib/patternContainer.cpp
+MPT_FILES_SOUNDLIB += soundlib/patternContainer.h
+MPT_FILES_SOUNDLIB += soundlib/pattern.cpp
+MPT_FILES_SOUNDLIB += soundlib/pattern.h
+MPT_FILES_SOUNDLIB += soundlib/Resampler.h
+MPT_FILES_SOUNDLIB += soundlib/RowVisitor.cpp
+MPT_FILES_SOUNDLIB += soundlib/RowVisitor.h
+MPT_FILES_SOUNDLIB += soundlib/S3MTools.cpp
+MPT_FILES_SOUNDLIB += soundlib/S3MTools.h
+MPT_FILES_SOUNDLIB += soundlib/SampleFormats.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleFormatFLAC.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleFormatMediaFoundation.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleFormatMP3.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleFormatOpus.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleFormatVorbis.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleIO.cpp
+MPT_FILES_SOUNDLIB += soundlib/SampleIO.h
+MPT_FILES_SOUNDLIB += soundlib/Snd_defs.h
+MPT_FILES_SOUNDLIB += soundlib/Sndfile.cpp
+MPT_FILES_SOUNDLIB += soundlib/Sndfile.h
+MPT_FILES_SOUNDLIB += soundlib/Snd_flt.cpp
+MPT_FILES_SOUNDLIB += soundlib/Snd_fx.cpp
+MPT_FILES_SOUNDLIB += soundlib/Sndmix.cpp
+MPT_FILES_SOUNDLIB += soundlib/SoundFilePlayConfig.cpp
+MPT_FILES_SOUNDLIB += soundlib/SoundFilePlayConfig.h
+MPT_FILES_SOUNDLIB += soundlib/Tables.cpp
+MPT_FILES_SOUNDLIB += soundlib/Tables.h
+MPT_FILES_SOUNDLIB += soundlib/Tagging.cpp
+MPT_FILES_SOUNDLIB += soundlib/Tagging.h
+MPT_FILES_SOUNDLIB += soundlib/tuningbase.cpp
+MPT_FILES_SOUNDLIB += soundlib/tuningbase.h
+MPT_FILES_SOUNDLIB += soundlib/tuningCollection.cpp
+MPT_FILES_SOUNDLIB += soundlib/tuningcollection.h
+MPT_FILES_SOUNDLIB += soundlib/tuning.cpp
+MPT_FILES_SOUNDLIB += soundlib/tuning.h
+MPT_FILES_SOUNDLIB += soundlib/UMXTools.cpp
+MPT_FILES_SOUNDLIB += soundlib/UMXTools.h
+MPT_FILES_SOUNDLIB += soundlib/UpgradeModule.cpp
+MPT_FILES_SOUNDLIB += soundlib/WAVTools.cpp
+MPT_FILES_SOUNDLIB += soundlib/WAVTools.h
+MPT_FILES_SOUNDLIB += soundlib/WindowedFIR.cpp
+MPT_FILES_SOUNDLIB += soundlib/WindowedFIR.h
+MPT_FILES_SOUNDLIB += soundlib/XMTools.cpp
+MPT_FILES_SOUNDLIB += soundlib/XMTools.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/DMOPlugin.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/DMOPlugin.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Chorus.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Chorus.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Compressor.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Compressor.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Distortion.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Distortion.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Echo.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Echo.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Flanger.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Flanger.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Gargle.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/Gargle.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/I3DL2Reverb.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/I3DL2Reverb.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/ParamEq.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/ParamEq.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/WavesReverb.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/dmo/WavesReverb.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/DigiBoosterEcho.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/DigiBoosterEcho.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/LFOPlugin.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/LFOPlugin.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/PluginManager.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/PluginManager.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/PluginMixBuffer.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/PluginStructs.h
+MPT_FILES_SOUNDLIB += soundlib/plugins/PlugInterface.cpp
+MPT_FILES_SOUNDLIB += soundlib/plugins/PlugInterface.h
+MPT_FILES_SOUNDDSP = 
+MPT_FILES_SOUNDDSP += sounddsp/AGC.cpp
+MPT_FILES_SOUNDDSP += sounddsp/AGC.h
+MPT_FILES_SOUNDDSP += sounddsp/DSP.cpp
+MPT_FILES_SOUNDDSP += sounddsp/DSP.h
+MPT_FILES_SOUNDDSP += sounddsp/EQ.cpp
+MPT_FILES_SOUNDDSP += sounddsp/EQ.h
+MPT_FILES_SOUNDDSP += sounddsp/Reverb.cpp
+MPT_FILES_SOUNDDSP += sounddsp/Reverb.h
+
 pkgconfig_DATA += libopenmpt/libopenmpt.pc
 lib_LTLIBRARIES += libopenmpt.la
-libopenmpt_la_LDFLAGS = -version-info 0:26:0
-nobase_include_HEADERS += libopenmpt/libopenmpt.h libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_version.h libopenmpt/libopenmpt_config.h libopenmpt/libopenmpt_stream_callbacks_fd.h libopenmpt/libopenmpt_stream_callbacks_file.h libopenmpt/libopenmpt_ext.hpp
-libopenmpt_la_CPPFLAGS = -DLIBOPENMPT_BUILD -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(LTDL_CPPFLAGS) $(DL_CPPFLAGS)
+libopenmpt_la_LDFLAGS = -version-info $(LIBOPENMPT_LTVER_CURRENT):$(LIBOPENMPT_LTVER_REVISION):$(LIBOPENMPT_LTVER_AGE) -no-undefined
+nobase_include_HEADERS += libopenmpt/libopenmpt.h
+nobase_include_HEADERS += libopenmpt/libopenmpt.hpp
+nobase_include_HEADERS += libopenmpt/libopenmpt_version.h
+nobase_include_HEADERS += libopenmpt/libopenmpt_config.h
+nobase_include_HEADERS += libopenmpt/libopenmpt_stream_callbacks_buffer.h
+nobase_include_HEADERS += libopenmpt/libopenmpt_stream_callbacks_fd.h
+nobase_include_HEADERS += libopenmpt/libopenmpt_stream_callbacks_file.h
+nobase_include_HEADERS += libopenmpt/libopenmpt_ext.h
+nobase_include_HEADERS += libopenmpt/libopenmpt_ext.hpp
+libopenmpt_la_CPPFLAGS = -DLIBOPENMPT_BUILD -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
 libopenmpt_la_CXXFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
 libopenmpt_la_CFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
-libopenmpt_la_LIBADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LTDL_LIBS) $(DL_LIBS) $(LIBOPENMPT_WIN32_LIBS)
+libopenmpt_la_LIBADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIBS)
 libopenmpt_la_SOURCES = 
 libopenmpt_la_SOURCES += build/svn_version/svn_version.h
-libopenmpt_la_SOURCES += common/BuildSettings.h
-libopenmpt_la_SOURCES += common/CompilerDetect.h
-libopenmpt_la_SOURCES += common/ComponentManager.cpp
-libopenmpt_la_SOURCES += common/ComponentManager.h
-libopenmpt_la_SOURCES += common/Endianness.h
-libopenmpt_la_SOURCES += common/FileReader.cpp
-libopenmpt_la_SOURCES += common/FileReader.h
-libopenmpt_la_SOURCES += common/FlagSet.h
-libopenmpt_la_SOURCES += common/Logging.cpp
-libopenmpt_la_SOURCES += common/Logging.h
-libopenmpt_la_SOURCES += common/misc_util.cpp
-libopenmpt_la_SOURCES += common/misc_util.h
-libopenmpt_la_SOURCES += common/mptAtomic.h
-libopenmpt_la_SOURCES += common/mptBufferIO.h
-libopenmpt_la_SOURCES += common/mptCPU.cpp
-libopenmpt_la_SOURCES += common/mptCPU.h
-libopenmpt_la_SOURCES += common/mptCRC.h
-libopenmpt_la_SOURCES += common/mptFileIO.cpp
-libopenmpt_la_SOURCES += common/mptFileIO.h
-libopenmpt_la_SOURCES += common/mptIO.cpp
-libopenmpt_la_SOURCES += common/mptIO.h
-libopenmpt_la_SOURCES += common/mptLibrary.cpp
-libopenmpt_la_SOURCES += common/mptLibrary.h
-libopenmpt_la_SOURCES += common/mptMutex.h
-libopenmpt_la_SOURCES += common/mptOS.cpp
-libopenmpt_la_SOURCES += common/mptOS.h
-libopenmpt_la_SOURCES += common/mptPathString.cpp
-libopenmpt_la_SOURCES += common/mptPathString.h
-libopenmpt_la_SOURCES += common/mptRandom.cpp
-libopenmpt_la_SOURCES += common/mptRandom.h
-libopenmpt_la_SOURCES += common/mptString.cpp
-libopenmpt_la_SOURCES += common/mptString.h
-libopenmpt_la_SOURCES += common/mptStringFormat.cpp
-libopenmpt_la_SOURCES += common/mptStringFormat.h
-libopenmpt_la_SOURCES += common/mptStringParse.cpp
-libopenmpt_la_SOURCES += common/mptStringParse.h
-libopenmpt_la_SOURCES += common/mptThread.h
-libopenmpt_la_SOURCES += common/mptTime.cpp
-libopenmpt_la_SOURCES += common/mptTime.h
-libopenmpt_la_SOURCES += common/mptTypeTraits.h
-libopenmpt_la_SOURCES += common/mptUUID.cpp
-libopenmpt_la_SOURCES += common/mptUUID.h
-libopenmpt_la_SOURCES += common/Profiler.cpp
-libopenmpt_la_SOURCES += common/Profiler.h
-libopenmpt_la_SOURCES += common/serialization_utils.cpp
-libopenmpt_la_SOURCES += common/serialization_utils.h
-libopenmpt_la_SOURCES += common/stdafx.cpp
-libopenmpt_la_SOURCES += common/stdafx.h
-libopenmpt_la_SOURCES += common/StringFixer.h
-libopenmpt_la_SOURCES += common/typedefs.cpp
-libopenmpt_la_SOURCES += common/typedefs.h
-libopenmpt_la_SOURCES += common/version.cpp
-libopenmpt_la_SOURCES += common/version.h
-libopenmpt_la_SOURCES += common/versionNumber.h
-libopenmpt_la_SOURCES += soundlib/AudioCriticalSection.cpp
-libopenmpt_la_SOURCES += soundlib/AudioCriticalSection.h
-libopenmpt_la_SOURCES += soundlib/AudioReadTarget.h
-libopenmpt_la_SOURCES += soundlib/ChunkReader.h
-libopenmpt_la_SOURCES += soundlib/Dither.cpp
-libopenmpt_la_SOURCES += soundlib/Dither.h
-libopenmpt_la_SOURCES += soundlib/Dlsbank.cpp
-libopenmpt_la_SOURCES += soundlib/Dlsbank.h
-libopenmpt_la_SOURCES += soundlib/Fastmix.cpp
-libopenmpt_la_SOURCES += soundlib/FloatMixer.h
-libopenmpt_la_SOURCES += soundlib/InstrumentExtensions.cpp
-libopenmpt_la_SOURCES += soundlib/IntMixer.h
-libopenmpt_la_SOURCES += soundlib/ITCompression.cpp
-libopenmpt_la_SOURCES += soundlib/ITCompression.h
-libopenmpt_la_SOURCES += soundlib/ITTools.cpp
-libopenmpt_la_SOURCES += soundlib/ITTools.h
-libopenmpt_la_SOURCES += soundlib/Load_669.cpp
-libopenmpt_la_SOURCES += soundlib/Load_amf.cpp
-libopenmpt_la_SOURCES += soundlib/Load_ams.cpp
-libopenmpt_la_SOURCES += soundlib/Load_dbm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_digi.cpp
-libopenmpt_la_SOURCES += soundlib/Load_dmf.cpp
-libopenmpt_la_SOURCES += soundlib/Load_dsm.cpp
-libopenmpt_la_SOURCES += soundlib/Loaders.h
-libopenmpt_la_SOURCES += soundlib/Load_far.cpp
-libopenmpt_la_SOURCES += soundlib/Load_gdm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_imf.cpp
-libopenmpt_la_SOURCES += soundlib/Load_it.cpp
-libopenmpt_la_SOURCES += soundlib/Load_itp.cpp
-libopenmpt_la_SOURCES += soundlib/load_j2b.cpp
-libopenmpt_la_SOURCES += soundlib/Load_mdl.cpp
-libopenmpt_la_SOURCES += soundlib/Load_med.cpp
-libopenmpt_la_SOURCES += soundlib/Load_mid.cpp
-libopenmpt_la_SOURCES += soundlib/Load_mo3.cpp
-libopenmpt_la_SOURCES += soundlib/Load_mod.cpp
-libopenmpt_la_SOURCES += soundlib/Load_mt2.cpp
-libopenmpt_la_SOURCES += soundlib/Load_mtm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_okt.cpp
-libopenmpt_la_SOURCES += soundlib/Load_plm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_psm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_ptm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_s3m.cpp
-libopenmpt_la_SOURCES += soundlib/Load_sfx.cpp
-libopenmpt_la_SOURCES += soundlib/Load_stm.cpp
-libopenmpt_la_SOURCES += soundlib/Load_ult.cpp
-libopenmpt_la_SOURCES += soundlib/Load_umx.cpp
-libopenmpt_la_SOURCES += soundlib/Load_wav.cpp
-libopenmpt_la_SOURCES += soundlib/Load_xm.cpp
-libopenmpt_la_SOURCES += soundlib/Message.cpp
-libopenmpt_la_SOURCES += soundlib/Message.h
-libopenmpt_la_SOURCES += soundlib/MIDIEvents.cpp
-libopenmpt_la_SOURCES += soundlib/MIDIEvents.h
-libopenmpt_la_SOURCES += soundlib/MIDIMacros.cpp
-libopenmpt_la_SOURCES += soundlib/MIDIMacros.h
-libopenmpt_la_SOURCES += soundlib/Mixer.h
-libopenmpt_la_SOURCES += soundlib/MixerInterface.h
-libopenmpt_la_SOURCES += soundlib/MixerLoops.cpp
-libopenmpt_la_SOURCES += soundlib/MixerLoops.h
-libopenmpt_la_SOURCES += soundlib/MixerSettings.cpp
-libopenmpt_la_SOURCES += soundlib/MixerSettings.h
-libopenmpt_la_SOURCES += soundlib/MixFuncTable.cpp
-libopenmpt_la_SOURCES += soundlib/MixFuncTable.h
-libopenmpt_la_SOURCES += soundlib/Mmcmp.cpp
-libopenmpt_la_SOURCES += soundlib/ModChannel.cpp
-libopenmpt_la_SOURCES += soundlib/ModChannel.h
-libopenmpt_la_SOURCES += soundlib/modcommand.cpp
-libopenmpt_la_SOURCES += soundlib/modcommand.h
-libopenmpt_la_SOURCES += soundlib/ModInstrument.cpp
-libopenmpt_la_SOURCES += soundlib/ModInstrument.h
-libopenmpt_la_SOURCES += soundlib/ModSample.cpp
-libopenmpt_la_SOURCES += soundlib/ModSample.h
-libopenmpt_la_SOURCES += soundlib/ModSequence.cpp
-libopenmpt_la_SOURCES += soundlib/ModSequence.h
-libopenmpt_la_SOURCES += soundlib/modsmp_ctrl.cpp
-libopenmpt_la_SOURCES += soundlib/modsmp_ctrl.h
-libopenmpt_la_SOURCES += soundlib/mod_specifications.cpp
-libopenmpt_la_SOURCES += soundlib/mod_specifications.h
-libopenmpt_la_SOURCES += soundlib/MPEGFrame.cpp
-libopenmpt_la_SOURCES += soundlib/MPEGFrame.h
-libopenmpt_la_SOURCES += soundlib/OggStream.cpp
-libopenmpt_la_SOURCES += soundlib/OggStream.h
-libopenmpt_la_SOURCES += soundlib/patternContainer.cpp
-libopenmpt_la_SOURCES += soundlib/patternContainer.h
-libopenmpt_la_SOURCES += soundlib/pattern.cpp
-libopenmpt_la_SOURCES += soundlib/pattern.h
-libopenmpt_la_SOURCES += soundlib/Resampler.h
-libopenmpt_la_SOURCES += soundlib/RowVisitor.cpp
-libopenmpt_la_SOURCES += soundlib/RowVisitor.h
-libopenmpt_la_SOURCES += soundlib/S3MTools.cpp
-libopenmpt_la_SOURCES += soundlib/S3MTools.h
-libopenmpt_la_SOURCES += soundlib/SampleFormatConverters.h
-libopenmpt_la_SOURCES += soundlib/SampleFormat.h
-libopenmpt_la_SOURCES += soundlib/SampleFormats.cpp
-libopenmpt_la_SOURCES += soundlib/SampleIO.cpp
-libopenmpt_la_SOURCES += soundlib/SampleIO.h
-libopenmpt_la_SOURCES += soundlib/Snd_defs.h
-libopenmpt_la_SOURCES += soundlib/Sndfile.cpp
-libopenmpt_la_SOURCES += soundlib/Sndfile.h
-libopenmpt_la_SOURCES += soundlib/Snd_flt.cpp
-libopenmpt_la_SOURCES += soundlib/Snd_fx.cpp
-libopenmpt_la_SOURCES += soundlib/Sndmix.cpp
-libopenmpt_la_SOURCES += soundlib/SoundFilePlayConfig.cpp
-libopenmpt_la_SOURCES += soundlib/SoundFilePlayConfig.h
-libopenmpt_la_SOURCES += soundlib/Tables.cpp
-libopenmpt_la_SOURCES += soundlib/Tables.h
-libopenmpt_la_SOURCES += soundlib/Tagging.cpp
-libopenmpt_la_SOURCES += soundlib/Tagging.h
-libopenmpt_la_SOURCES += soundlib/tuningbase.cpp
-libopenmpt_la_SOURCES += soundlib/tuningbase.h
-libopenmpt_la_SOURCES += soundlib/tuningCollection.cpp
-libopenmpt_la_SOURCES += soundlib/tuningcollection.h
-libopenmpt_la_SOURCES += soundlib/tuning.cpp
-libopenmpt_la_SOURCES += soundlib/tuning.h
-libopenmpt_la_SOURCES += soundlib/UpgradeModule.cpp
-libopenmpt_la_SOURCES += soundlib/WAVTools.cpp
-libopenmpt_la_SOURCES += soundlib/WAVTools.h
-libopenmpt_la_SOURCES += soundlib/WindowedFIR.cpp
-libopenmpt_la_SOURCES += soundlib/WindowedFIR.h
-libopenmpt_la_SOURCES += soundlib/XMTools.cpp
-libopenmpt_la_SOURCES += soundlib/XMTools.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/DMOPlugin.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/DMOPlugin.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Compressor.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Compressor.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Distortion.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Distortion.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Echo.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Echo.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Gargle.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/Gargle.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/ParamEq.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/ParamEq.h
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/WavesReverb.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/dmo/WavesReverb.h
-libopenmpt_la_SOURCES += soundlib/plugins/DigiBoosterEcho.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/DigiBoosterEcho.h
-libopenmpt_la_SOURCES += soundlib/plugins/PluginManager.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/PluginManager.h
-libopenmpt_la_SOURCES += soundlib/plugins/PluginMixBuffer.h
-libopenmpt_la_SOURCES += soundlib/plugins/PluginStructs.h
-libopenmpt_la_SOURCES += soundlib/plugins/PlugInterface.cpp
-libopenmpt_la_SOURCES += soundlib/plugins/PlugInterface.h
+libopenmpt_la_SOURCES += $(MPT_FILES_COMMON)
+libopenmpt_la_SOURCES += $(MPT_FILES_SOUNDBASE)
+libopenmpt_la_SOURCES += $(MPT_FILES_SOUNDLIB)
+libopenmpt_la_SOURCES += $(MPT_FILES_SOUNDDSP)
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_c.cpp
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_cxx.cpp
-libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext.cpp
+libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext_impl.cpp
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_impl.cpp
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_config.h
+libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext.h
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext.hpp
+libopenmpt_la_SOURCES += libopenmpt/libopenmpt_ext_impl.hpp
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt.h
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt.hpp
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_impl.hpp
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_internal.h
+libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_buffer.h
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_fd.h
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file.h
 libopenmpt_la_SOURCES += libopenmpt/libopenmpt_version.h
 
 if ENABLE_LIBOPENMPT_MODPLUG
 lib_LTLIBRARIES += libopenmpt_modplug.la
-libopenmpt_modplug_la_LDFLAGS = -version-info 1:0:0
+libopenmpt_modplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
 libopenmpt_modplug_la_CPPFLAGS = -I$(srcdir)/
 libopenmpt_modplug_la_CXXFLAGS = 
 libopenmpt_modplug_la_CFLAGS = 
@@ -338,7 +393,7 @@ endif
 if ENABLE_LIBMODPLUG
 pkgconfig_DATA += libmodplug/libmodplug.pc
 lib_LTLIBRARIES += libmodplug.la
-libmodplug_la_LDFLAGS = -version-info 1:0:0
+libmodplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
 nobase_include_HEADERS += libmodplug/modplug.h libmodplug/sndfile.h libmodplug/stdafx.h
 libmodplug_la_CPPFLAGS = -I$(srcdir)/
 libmodplug_la_CXXFLAGS = 
@@ -351,10 +406,10 @@ endif
 
 if ENABLE_TESTS
 check_PROGRAMS += libopenmpttest
-libopenmpttest_CPPFLAGS = -DLIBOPENMPT_BUILD -DLIBOPENMPT_BUILD_TEST -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(LTDL_CPPFLAGS) $(DL_CPPFLAGS)
+libopenmpttest_CPPFLAGS = -DLIBOPENMPT_BUILD -DLIBOPENMPT_BUILD_TEST -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
 libopenmpttest_CXXFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(WIN32_CONSOLE_CXXFLAGS)
 libopenmpttest_CFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(WIN32_CONSOLE_CFLAGS)
-libopenmpttest_LDADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LTDL_LIBS) $(DL_LIBS) $(LIBOPENMPT_WIN32_LIB)
+libopenmpttest_LDADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIB)
 libopenmpttest_SOURCES = 
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_test.cpp
 libopenmpttest_SOURCES += test/test.cpp
@@ -364,214 +419,23 @@ libopenmpttest_SOURCES += test/TestToolsLib.cpp
 libopenmpttest_SOURCES += test/TestToolsLib.h
 libopenmpttest_SOURCES += test/TestToolsTracker.h
 libopenmpttest_SOURCES += build/svn_version/svn_version.h
-libopenmpttest_SOURCES += common/BuildSettings.h
-libopenmpttest_SOURCES += common/CompilerDetect.h
-libopenmpttest_SOURCES += common/ComponentManager.cpp
-libopenmpttest_SOURCES += common/ComponentManager.h
-libopenmpttest_SOURCES += common/Endianness.h
-libopenmpttest_SOURCES += common/FileReader.cpp
-libopenmpttest_SOURCES += common/FileReader.h
-libopenmpttest_SOURCES += common/FlagSet.h
-libopenmpttest_SOURCES += common/Logging.cpp
-libopenmpttest_SOURCES += common/Logging.h
-libopenmpttest_SOURCES += common/misc_util.cpp
-libopenmpttest_SOURCES += common/misc_util.h
-libopenmpttest_SOURCES += common/mptAtomic.h
-libopenmpttest_SOURCES += common/mptBufferIO.h
-libopenmpttest_SOURCES += common/mptCPU.cpp
-libopenmpttest_SOURCES += common/mptCPU.h
-libopenmpttest_SOURCES += common/mptCRC.h
-libopenmpttest_SOURCES += common/mptFileIO.cpp
-libopenmpttest_SOURCES += common/mptFileIO.h
-libopenmpttest_SOURCES += common/mptIO.cpp
-libopenmpttest_SOURCES += common/mptIO.h
-libopenmpttest_SOURCES += common/mptLibrary.cpp
-libopenmpttest_SOURCES += common/mptLibrary.h
-libopenmpttest_SOURCES += common/mptMutex.h
-libopenmpttest_SOURCES += common/mptOS.cpp
-libopenmpttest_SOURCES += common/mptOS.h
-libopenmpttest_SOURCES += common/mptPathString.cpp
-libopenmpttest_SOURCES += common/mptPathString.h
-libopenmpttest_SOURCES += common/mptRandom.cpp
-libopenmpttest_SOURCES += common/mptRandom.h
-libopenmpttest_SOURCES += common/mptString.cpp
-libopenmpttest_SOURCES += common/mptString.h
-libopenmpttest_SOURCES += common/mptStringFormat.cpp
-libopenmpttest_SOURCES += common/mptStringFormat.h
-libopenmpttest_SOURCES += common/mptStringParse.cpp
-libopenmpttest_SOURCES += common/mptStringParse.h
-libopenmpttest_SOURCES += common/mptThread.h
-libopenmpttest_SOURCES += common/mptTime.cpp
-libopenmpttest_SOURCES += common/mptTime.h
-libopenmpttest_SOURCES += common/mptTypeTraits.h
-libopenmpttest_SOURCES += common/mptUUID.cpp
-libopenmpttest_SOURCES += common/mptUUID.h
-libopenmpttest_SOURCES += common/Profiler.cpp
-libopenmpttest_SOURCES += common/Profiler.h
-libopenmpttest_SOURCES += common/serialization_utils.cpp
-libopenmpttest_SOURCES += common/serialization_utils.h
-libopenmpttest_SOURCES += common/stdafx.cpp
-libopenmpttest_SOURCES += common/stdafx.h
-libopenmpttest_SOURCES += common/StringFixer.h
-libopenmpttest_SOURCES += common/typedefs.cpp
-libopenmpttest_SOURCES += common/typedefs.h
-libopenmpttest_SOURCES += common/version.cpp
-libopenmpttest_SOURCES += common/version.h
-libopenmpttest_SOURCES += common/versionNumber.h
-libopenmpttest_SOURCES += soundlib/AudioCriticalSection.cpp
-libopenmpttest_SOURCES += soundlib/AudioCriticalSection.h
-libopenmpttest_SOURCES += soundlib/AudioReadTarget.h
-libopenmpttest_SOURCES += soundlib/ChunkReader.h
-libopenmpttest_SOURCES += soundlib/Dither.cpp
-libopenmpttest_SOURCES += soundlib/Dither.h
-libopenmpttest_SOURCES += soundlib/Dlsbank.cpp
-libopenmpttest_SOURCES += soundlib/Dlsbank.h
-libopenmpttest_SOURCES += soundlib/Fastmix.cpp
-libopenmpttest_SOURCES += soundlib/FloatMixer.h
-libopenmpttest_SOURCES += soundlib/InstrumentExtensions.cpp
-libopenmpttest_SOURCES += soundlib/IntMixer.h
-libopenmpttest_SOURCES += soundlib/ITCompression.cpp
-libopenmpttest_SOURCES += soundlib/ITCompression.h
-libopenmpttest_SOURCES += soundlib/ITTools.cpp
-libopenmpttest_SOURCES += soundlib/ITTools.h
-libopenmpttest_SOURCES += soundlib/Load_669.cpp
-libopenmpttest_SOURCES += soundlib/Load_amf.cpp
-libopenmpttest_SOURCES += soundlib/Load_ams.cpp
-libopenmpttest_SOURCES += soundlib/Load_dbm.cpp
-libopenmpttest_SOURCES += soundlib/Load_digi.cpp
-libopenmpttest_SOURCES += soundlib/Load_dmf.cpp
-libopenmpttest_SOURCES += soundlib/Load_dsm.cpp
-libopenmpttest_SOURCES += soundlib/Loaders.h
-libopenmpttest_SOURCES += soundlib/Load_far.cpp
-libopenmpttest_SOURCES += soundlib/Load_gdm.cpp
-libopenmpttest_SOURCES += soundlib/Load_imf.cpp
-libopenmpttest_SOURCES += soundlib/Load_it.cpp
-libopenmpttest_SOURCES += soundlib/Load_itp.cpp
-libopenmpttest_SOURCES += soundlib/load_j2b.cpp
-libopenmpttest_SOURCES += soundlib/Load_mdl.cpp
-libopenmpttest_SOURCES += soundlib/Load_med.cpp
-libopenmpttest_SOURCES += soundlib/Load_mid.cpp
-libopenmpttest_SOURCES += soundlib/Load_mo3.cpp
-libopenmpttest_SOURCES += soundlib/Load_mod.cpp
-libopenmpttest_SOURCES += soundlib/Load_mt2.cpp
-libopenmpttest_SOURCES += soundlib/Load_mtm.cpp
-libopenmpttest_SOURCES += soundlib/Load_okt.cpp
-libopenmpttest_SOURCES += soundlib/Load_plm.cpp
-libopenmpttest_SOURCES += soundlib/Load_psm.cpp
-libopenmpttest_SOURCES += soundlib/Load_ptm.cpp
-libopenmpttest_SOURCES += soundlib/Load_s3m.cpp
-libopenmpttest_SOURCES += soundlib/Load_sfx.cpp
-libopenmpttest_SOURCES += soundlib/Load_stm.cpp
-libopenmpttest_SOURCES += soundlib/Load_ult.cpp
-libopenmpttest_SOURCES += soundlib/Load_umx.cpp
-libopenmpttest_SOURCES += soundlib/Load_wav.cpp
-libopenmpttest_SOURCES += soundlib/Load_xm.cpp
-libopenmpttest_SOURCES += soundlib/Message.cpp
-libopenmpttest_SOURCES += soundlib/Message.h
-libopenmpttest_SOURCES += soundlib/MIDIEvents.cpp
-libopenmpttest_SOURCES += soundlib/MIDIEvents.h
-libopenmpttest_SOURCES += soundlib/MIDIMacros.cpp
-libopenmpttest_SOURCES += soundlib/MIDIMacros.h
-libopenmpttest_SOURCES += soundlib/Mixer.h
-libopenmpttest_SOURCES += soundlib/MixerInterface.h
-libopenmpttest_SOURCES += soundlib/MixerLoops.cpp
-libopenmpttest_SOURCES += soundlib/MixerLoops.h
-libopenmpttest_SOURCES += soundlib/MixerSettings.cpp
-libopenmpttest_SOURCES += soundlib/MixerSettings.h
-libopenmpttest_SOURCES += soundlib/MixFuncTable.cpp
-libopenmpttest_SOURCES += soundlib/MixFuncTable.h
-libopenmpttest_SOURCES += soundlib/Mmcmp.cpp
-libopenmpttest_SOURCES += soundlib/ModChannel.cpp
-libopenmpttest_SOURCES += soundlib/ModChannel.h
-libopenmpttest_SOURCES += soundlib/modcommand.cpp
-libopenmpttest_SOURCES += soundlib/modcommand.h
-libopenmpttest_SOURCES += soundlib/ModInstrument.cpp
-libopenmpttest_SOURCES += soundlib/ModInstrument.h
-libopenmpttest_SOURCES += soundlib/ModSample.cpp
-libopenmpttest_SOURCES += soundlib/ModSample.h
-libopenmpttest_SOURCES += soundlib/ModSequence.cpp
-libopenmpttest_SOURCES += soundlib/ModSequence.h
-libopenmpttest_SOURCES += soundlib/modsmp_ctrl.cpp
-libopenmpttest_SOURCES += soundlib/modsmp_ctrl.h
-libopenmpttest_SOURCES += soundlib/mod_specifications.cpp
-libopenmpttest_SOURCES += soundlib/mod_specifications.h
-libopenmpttest_SOURCES += soundlib/MPEGFrame.cpp
-libopenmpttest_SOURCES += soundlib/MPEGFrame.h
-libopenmpttest_SOURCES += soundlib/OggStream.cpp
-libopenmpttest_SOURCES += soundlib/OggStream.h
-libopenmpttest_SOURCES += soundlib/patternContainer.cpp
-libopenmpttest_SOURCES += soundlib/patternContainer.h
-libopenmpttest_SOURCES += soundlib/pattern.cpp
-libopenmpttest_SOURCES += soundlib/pattern.h
-libopenmpttest_SOURCES += soundlib/Resampler.h
-libopenmpttest_SOURCES += soundlib/RowVisitor.cpp
-libopenmpttest_SOURCES += soundlib/RowVisitor.h
-libopenmpttest_SOURCES += soundlib/S3MTools.cpp
-libopenmpttest_SOURCES += soundlib/S3MTools.h
-libopenmpttest_SOURCES += soundlib/SampleFormatConverters.h
-libopenmpttest_SOURCES += soundlib/SampleFormat.h
-libopenmpttest_SOURCES += soundlib/SampleFormats.cpp
-libopenmpttest_SOURCES += soundlib/SampleIO.cpp
-libopenmpttest_SOURCES += soundlib/SampleIO.h
-libopenmpttest_SOURCES += soundlib/Snd_defs.h
-libopenmpttest_SOURCES += soundlib/Sndfile.cpp
-libopenmpttest_SOURCES += soundlib/Sndfile.h
-libopenmpttest_SOURCES += soundlib/Snd_flt.cpp
-libopenmpttest_SOURCES += soundlib/Snd_fx.cpp
-libopenmpttest_SOURCES += soundlib/Sndmix.cpp
-libopenmpttest_SOURCES += soundlib/SoundFilePlayConfig.cpp
-libopenmpttest_SOURCES += soundlib/SoundFilePlayConfig.h
-libopenmpttest_SOURCES += soundlib/Tables.cpp
-libopenmpttest_SOURCES += soundlib/Tables.h
-libopenmpttest_SOURCES += soundlib/Tagging.cpp
-libopenmpttest_SOURCES += soundlib/Tagging.h
-libopenmpttest_SOURCES += soundlib/tuningbase.cpp
-libopenmpttest_SOURCES += soundlib/tuningbase.h
-libopenmpttest_SOURCES += soundlib/tuningCollection.cpp
-libopenmpttest_SOURCES += soundlib/tuningcollection.h
-libopenmpttest_SOURCES += soundlib/tuning.cpp
-libopenmpttest_SOURCES += soundlib/tuning.h
-libopenmpttest_SOURCES += soundlib/UpgradeModule.cpp
-libopenmpttest_SOURCES += soundlib/WAVTools.cpp
-libopenmpttest_SOURCES += soundlib/WAVTools.h
-libopenmpttest_SOURCES += soundlib/WindowedFIR.cpp
-libopenmpttest_SOURCES += soundlib/WindowedFIR.h
-libopenmpttest_SOURCES += soundlib/XMTools.cpp
-libopenmpttest_SOURCES += soundlib/XMTools.h
-libopenmpttest_SOURCES += soundlib/plugins/PlugInterface.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/DMOPlugin.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/DMOPlugin.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Compressor.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Compressor.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Distortion.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Distortion.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Echo.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Echo.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Echo.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Gargle.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/Gargle.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/ParamEq.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/ParamEq.h
-libopenmpttest_SOURCES += soundlib/plugins/dmo/WavesReverb.cpp
-libopenmpttest_SOURCES += soundlib/plugins/dmo/WavesReverb.h
-libopenmpttest_SOURCES += soundlib/plugins/DigiBoosterEcho.cpp
-libopenmpttest_SOURCES += soundlib/plugins/DigiBoosterEcho.h
-libopenmpttest_SOURCES += soundlib/plugins/PluginManager.cpp
-libopenmpttest_SOURCES += soundlib/plugins/PluginManager.h
-libopenmpttest_SOURCES += soundlib/plugins/PluginMixBuffer.h
-libopenmpttest_SOURCES += soundlib/plugins/PluginStructs.h
-libopenmpttest_SOURCES += soundlib/plugins/PlugInterface.cpp
-libopenmpttest_SOURCES += soundlib/plugins/PlugInterface.h
+libopenmpttest_SOURCES += $(MPT_FILES_COMMON)
+libopenmpttest_SOURCES += $(MPT_FILES_SOUNDBASE)
+libopenmpttest_SOURCES += $(MPT_FILES_SOUNDLIB)
+libopenmpttest_SOURCES += $(MPT_FILES_SOUNDDSP)
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_c.cpp
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_cxx.cpp
-libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext.cpp
+libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext_impl.cpp
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_impl.cpp
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_config.h
+libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext.h
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext.hpp
+libopenmpttest_SOURCES += libopenmpt/libopenmpt_ext_impl.hpp
 libopenmpttest_SOURCES += libopenmpt/libopenmpt.h
 libopenmpttest_SOURCES += libopenmpt/libopenmpt.hpp
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_impl.hpp
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_internal.h
+libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_buffer.h
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_fd.h
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_stream_callbacks_file.h
 libopenmpttest_SOURCES += libopenmpt/libopenmpt_version.h
@@ -579,84 +443,29 @@ endif
 
 if ENABLE_OPENMPT123
 
-bin_PROGRAMS += openmpt123
-openmpt123_CPPFLAGS = -I$(srcdir)/src/openmpt123 $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SDL_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS)
-openmpt123_CXXFLAGS = $(WIN32_CONSOLE_CXXFLAGS)
-openmpt123_LDADD = libopenmpt.la $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SDL_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS) $(OPENMPT123_WIN32_LIBS)
-openmpt123_SOURCES = 
-openmpt123_SOURCES += src/openmpt123/openmpt123_config.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123.cpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_flac.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_mmio.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_portaudio.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_pulseaudio.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_raw.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_sdl.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_sdl2.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_sndfile.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_stdout.hpp
-openmpt123_SOURCES += src/openmpt123/openmpt123_waveout.hpp
-#bin_PROGRAMS += openmpt123
-#openmpt123_CPPFLAGS = -I$(srcdir)/src/openmpt123 $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SDL_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS)
-#openmpt123_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SDL_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS)
-#openmpt123_SOURCES = 
-#openmpt123_SOURCES += openmpt123/openmpt123_config.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123.cpp
-#openmpt123_SOURCES += openmpt123/openmpt123_flac.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_mmio.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_portaudio.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_pulseaudio.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_raw.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_sdl.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_sdl2.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_sndfile.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_stdout.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_waveout.hpp
+bin_PROGRAMS += bin/openmpt123
+bin_openmpt123_CPPFLAGS = -I$(srcdir)/src/openmpt123 $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SDL_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS)
+bin_openmpt123_CXXFLAGS = $(WIN32_CONSOLE_CXXFLAGS)
+bin_openmpt123_LDADD = libopenmpt.la $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SDL_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS) $(OPENMPT123_WIN32_LIBS)
+bin_openmpt123_SOURCES = 
+bin_openmpt123_SOURCES += openmpt123/openmpt123_config.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123.cpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_flac.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_mmio.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_portaudio.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_pulseaudio.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_raw.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_sdl.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_sdl2.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_sndfile.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_stdout.hpp
+bin_openmpt123_SOURCES += openmpt123/openmpt123_waveout.hpp
 
 man1_MANS = man/openmpt123.1
 
 endif
 
-MOSTLYCLEANFILES += $(DX_CLEANFILES)
-
-if DX_COND_doc
-
-all-local: @DX_DOCDIR@/@PACKAGE at .tag
-
-install-data-local:
-	$(INSTALL) -d $(DESTDIR)$(docdir)/html/search
-	( cd @DX_DOCDIR@ && \
-	for f in `find html -type f \! -name "installdox"`; do	\
-		$(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f;	\
-	done )
-
-clean-local:
-	$(RM) -r html
-	$(RM) @DX_DOCDIR@/@PACKAGE at .tag
-
-uninstall-local:
-	$(RM) -r $(DESTDIR)$(docdir)/html
-
-if DX_COND_html
-DX_CLEAN_HTML = @DX_DOCDIR@/html
-endif DX_COND_html
-
-.PHONY: doxygen-run doxygen-doc
-
-.INTERMEDIATE: doxygen-run
-
-doxygen-run: @DX_DOCDIR@/@PACKAGE at .tag
-
-doxygen-doc: doxygen-run
-
- at DX_DOCDIR@/@PACKAGE at .tag: $(DX_CONFIG)
-	rm -rf @DX_DOCDIR@
-	$(DX_ENV) $(DX_DOXYGEN) $(DX_CONFIG)
-	touch $@
-
-DX_CLEANFILES = @DX_DOCDIR@/@PACKAGE at .tag @DX_DOCDIR@/doxygen_sqlite3.db -r $(DX_CLEAN_HTML) 
-
-endif DX_COND_doc
+ at DX_RULES@
 
+MOSTLYCLEANFILES += $(DX_CLEANFILES)
diff --git a/Makefile.in b/Makefile.in
index 37bb72f..60eb91f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# Makefile.in generated by automake 1.15 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -18,7 +18,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -96,30 +106,13 @@ check_PROGRAMS = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \
 @ENABLE_LIBMODPLUG_TRUE at am__append_6 = libmodplug.la
 @ENABLE_LIBMODPLUG_TRUE at am__append_7 = libmodplug/modplug.h libmodplug/sndfile.h libmodplug/stdafx.h
 @ENABLE_TESTS_TRUE at am__append_8 = libopenmpttest
- at ENABLE_OPENMPT123_TRUE@am__append_9 = openmpt123
+ at ENABLE_OPENMPT123_TRUE@am__append_9 = bin/openmpt123
 subdir = .
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/configure $(am__configure_deps) \
-	$(srcdir)/config.h.in \
-	$(top_srcdir)/libopenmpt/libopenmpt.pc.in \
-	$(top_srcdir)/libmodplug/libmodplug.pc.in \
-	$(srcdir)/Doxyfile.in $(top_srcdir)/build-aux/depcomp \
-	$(dist_doc_DATA) $(nobase_dist_doc_DATA) \
-	$(am__nobase_include_HEADERS_DIST) \
-	$(top_srcdir)/build-aux/test-driver TODO build-aux/ar-lib \
-	build-aux/compile build-aux/config.guess build-aux/config.sub \
-	build-aux/depcomp build-aux/install-sh build-aux/missing \
-	build-aux/ltmain.sh $(top_srcdir)/build-aux/ar-lib \
-	$(top_srcdir)/build-aux/compile \
-	$(top_srcdir)/build-aux/config.guess \
-	$(top_srcdir)/build-aux/config.sub \
-	$(top_srcdir)/build-aux/install-sh \
-	$(top_srcdir)/build-aux/ltmain.sh \
-	$(top_srcdir)/build-aux/missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_flag.m4 \
 	$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
 	$(top_srcdir)/m4/ax_check_compile_flag.m4 \
+	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_prog_doxygen.m4 \
 	$(top_srcdir)/m4/ax_require_defined.m4 \
@@ -129,6 +122,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_flag.m4 \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(dist_doc_DATA) $(nobase_dist_doc_DATA) \
+	$(am__nobase_include_HEADERS_DIST) $(am__DIST_COMMON)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
@@ -188,9 +184,8 @@ am__DEPENDENCIES_1 =
 libopenmpt_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
-am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
+am__objects_1 = common/libopenmpt_la-ComponentManager.lo \
 	common/libopenmpt_la-FileReader.lo \
 	common/libopenmpt_la-Logging.lo \
 	common/libopenmpt_la-misc_util.lo \
@@ -206,12 +201,18 @@ am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
 	common/libopenmpt_la-mptStringParse.lo \
 	common/libopenmpt_la-mptTime.lo \
 	common/libopenmpt_la-mptUUID.lo \
+	common/libopenmpt_la-mptWine.lo \
 	common/libopenmpt_la-Profiler.lo \
 	common/libopenmpt_la-serialization_utils.lo \
 	common/libopenmpt_la-stdafx.lo \
 	common/libopenmpt_la-typedefs.lo \
-	common/libopenmpt_la-version.lo \
-	soundlib/libopenmpt_la-AudioCriticalSection.lo \
+	common/libopenmpt_la-version.lo
+am__objects_2 =
+am__objects_3 = soundlib/libopenmpt_la-AudioCriticalSection.lo \
+	soundlib/libopenmpt_la-ContainerMMCMP.lo \
+	soundlib/libopenmpt_la-ContainerPP20.lo \
+	soundlib/libopenmpt_la-ContainerUMX.lo \
+	soundlib/libopenmpt_la-ContainerXPK.lo \
 	soundlib/libopenmpt_la-Dither.lo \
 	soundlib/libopenmpt_la-Dlsbank.lo \
 	soundlib/libopenmpt_la-Fastmix.lo \
@@ -225,6 +226,7 @@ am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
 	soundlib/libopenmpt_la-Load_digi.lo \
 	soundlib/libopenmpt_la-Load_dmf.lo \
 	soundlib/libopenmpt_la-Load_dsm.lo \
+	soundlib/libopenmpt_la-Load_dtm.lo \
 	soundlib/libopenmpt_la-Load_far.lo \
 	soundlib/libopenmpt_la-Load_gdm.lo \
 	soundlib/libopenmpt_la-Load_imf.lo \
@@ -245,8 +247,9 @@ am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
 	soundlib/libopenmpt_la-Load_s3m.lo \
 	soundlib/libopenmpt_la-Load_sfx.lo \
 	soundlib/libopenmpt_la-Load_stm.lo \
+	soundlib/libopenmpt_la-Load_stp.lo \
+	soundlib/libopenmpt_la-Load_uax.lo \
 	soundlib/libopenmpt_la-Load_ult.lo \
-	soundlib/libopenmpt_la-Load_umx.lo \
 	soundlib/libopenmpt_la-Load_wav.lo \
 	soundlib/libopenmpt_la-Load_xm.lo \
 	soundlib/libopenmpt_la-Message.lo \
@@ -255,7 +258,6 @@ am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
 	soundlib/libopenmpt_la-MixerLoops.lo \
 	soundlib/libopenmpt_la-MixerSettings.lo \
 	soundlib/libopenmpt_la-MixFuncTable.lo \
-	soundlib/libopenmpt_la-Mmcmp.lo \
 	soundlib/libopenmpt_la-ModChannel.lo \
 	soundlib/libopenmpt_la-modcommand.lo \
 	soundlib/libopenmpt_la-ModInstrument.lo \
@@ -265,11 +267,17 @@ am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
 	soundlib/libopenmpt_la-mod_specifications.lo \
 	soundlib/libopenmpt_la-MPEGFrame.lo \
 	soundlib/libopenmpt_la-OggStream.lo \
+	soundlib/libopenmpt_la-Paula.lo \
 	soundlib/libopenmpt_la-patternContainer.lo \
 	soundlib/libopenmpt_la-pattern.lo \
 	soundlib/libopenmpt_la-RowVisitor.lo \
 	soundlib/libopenmpt_la-S3MTools.lo \
 	soundlib/libopenmpt_la-SampleFormats.lo \
+	soundlib/libopenmpt_la-SampleFormatFLAC.lo \
+	soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo \
+	soundlib/libopenmpt_la-SampleFormatMP3.lo \
+	soundlib/libopenmpt_la-SampleFormatOpus.lo \
+	soundlib/libopenmpt_la-SampleFormatVorbis.lo \
 	soundlib/libopenmpt_la-SampleIO.lo \
 	soundlib/libopenmpt_la-Sndfile.lo \
 	soundlib/libopenmpt_la-Snd_flt.lo \
@@ -281,23 +289,33 @@ am_libopenmpt_la_OBJECTS = common/libopenmpt_la-ComponentManager.lo \
 	soundlib/libopenmpt_la-tuningbase.lo \
 	soundlib/libopenmpt_la-tuningCollection.lo \
 	soundlib/libopenmpt_la-tuning.lo \
+	soundlib/libopenmpt_la-UMXTools.lo \
 	soundlib/libopenmpt_la-UpgradeModule.lo \
 	soundlib/libopenmpt_la-WAVTools.lo \
 	soundlib/libopenmpt_la-WindowedFIR.lo \
 	soundlib/libopenmpt_la-XMTools.lo \
 	soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo \
+	soundlib/plugins/dmo/libopenmpt_la-Chorus.lo \
 	soundlib/plugins/dmo/libopenmpt_la-Compressor.lo \
 	soundlib/plugins/dmo/libopenmpt_la-Distortion.lo \
 	soundlib/plugins/dmo/libopenmpt_la-Echo.lo \
+	soundlib/plugins/dmo/libopenmpt_la-Flanger.lo \
 	soundlib/plugins/dmo/libopenmpt_la-Gargle.lo \
+	soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo \
 	soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo \
 	soundlib/plugins/dmo/libopenmpt_la-WavesReverb.lo \
 	soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo \
+	soundlib/plugins/libopenmpt_la-LFOPlugin.lo \
 	soundlib/plugins/libopenmpt_la-PluginManager.lo \
-	soundlib/plugins/libopenmpt_la-PlugInterface.lo \
+	soundlib/plugins/libopenmpt_la-PlugInterface.lo
+am__objects_4 = sounddsp/libopenmpt_la-AGC.lo \
+	sounddsp/libopenmpt_la-DSP.lo sounddsp/libopenmpt_la-EQ.lo \
+	sounddsp/libopenmpt_la-Reverb.lo
+am_libopenmpt_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
+	$(am__objects_3) $(am__objects_4) \
 	libopenmpt/libopenmpt_la-libopenmpt_c.lo \
 	libopenmpt/libopenmpt_la-libopenmpt_cxx.lo \
-	libopenmpt/libopenmpt_la-libopenmpt_ext.lo \
+	libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo \
 	libopenmpt/libopenmpt_la-libopenmpt_impl.lo
 libopenmpt_la_OBJECTS = $(am_libopenmpt_la_OBJECTS)
 libopenmpt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
@@ -318,7 +336,7 @@ libopenmpt_modplug_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
 	$(libopenmpt_modplug_la_LDFLAGS) $(LDFLAGS) -o $@
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE at am_libopenmpt_modplug_la_rpath =  \
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE@	-rpath $(libdir)
- at ENABLE_OPENMPT123_TRUE@am__EXEEXT_1 = openmpt123$(EXEEXT)
+ at ENABLE_OPENMPT123_TRUE@am__EXEEXT_1 = bin/openmpt123$(EXEEXT)
 @ENABLE_EXAMPLES_TRUE at am__EXEEXT_2 =  \
 @ENABLE_EXAMPLES_TRUE@	libopenmpt_example_c_stdout$(EXEEXT) \
 @ENABLE_EXAMPLES_TRUE@	libopenmpt_example_c_probe$(EXEEXT)
@@ -328,6 +346,30 @@ libopenmpt_modplug_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
 @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIOCPP_TRUE at am__EXEEXT_4 = libopenmpt_example_cxx$(EXEEXT)
 @ENABLE_TESTS_TRUE at am__EXEEXT_5 = libopenmpttest$(EXEEXT)
 PROGRAMS = $(bin_PROGRAMS)
+am__bin_openmpt123_SOURCES_DIST = openmpt123/openmpt123_config.hpp \
+	openmpt123/openmpt123.cpp openmpt123/openmpt123_flac.hpp \
+	openmpt123/openmpt123.hpp openmpt123/openmpt123_mmio.hpp \
+	openmpt123/openmpt123_portaudio.hpp \
+	openmpt123/openmpt123_pulseaudio.hpp \
+	openmpt123/openmpt123_raw.hpp openmpt123/openmpt123_sdl.hpp \
+	openmpt123/openmpt123_sdl2.hpp \
+	openmpt123/openmpt123_sndfile.hpp \
+	openmpt123/openmpt123_stdout.hpp \
+	openmpt123/openmpt123_waveout.hpp
+ at ENABLE_OPENMPT123_TRUE@am_bin_openmpt123_OBJECTS = openmpt123/bin_openmpt123-openmpt123.$(OBJEXT)
+bin_openmpt123_OBJECTS = $(am_bin_openmpt123_OBJECTS)
+ at ENABLE_OPENMPT123_TRUE@bin_openmpt123_DEPENDENCIES = libopenmpt.la \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
+ at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1)
+bin_openmpt123_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
 am__libopenmpt_example_c_SOURCES_DIST =  \
 	examples/libopenmpt_example_c.c
 @ENABLE_EXAMPLES_TRUE@@HAVE_PORTAUDIO_TRUE at am_libopenmpt_example_c_OBJECTS = examples/libopenmpt_example_c-libopenmpt_example_c.$(OBJEXT)
@@ -402,8 +444,8 @@ am__libopenmpttest_SOURCES_DIST = libopenmpt/libopenmpt_test.cpp \
 	common/BuildSettings.h common/CompilerDetect.h \
 	common/ComponentManager.cpp common/ComponentManager.h \
 	common/Endianness.h common/FileReader.cpp common/FileReader.h \
-	common/FlagSet.h common/Logging.cpp common/Logging.h \
-	common/misc_util.cpp common/misc_util.h common/mptAtomic.h \
+	common/FileReaderFwd.h common/FlagSet.h common/Logging.cpp \
+	common/Logging.h common/misc_util.cpp common/misc_util.h \
 	common/mptBufferIO.h common/mptCPU.cpp common/mptCPU.h \
 	common/mptCRC.h common/mptFileIO.cpp common/mptFileIO.h \
 	common/mptIO.cpp common/mptIO.h common/mptLibrary.cpp \
@@ -414,22 +456,27 @@ am__libopenmpttest_SOURCES_DIST = libopenmpt/libopenmpt_test.cpp \
 	common/mptStringFormat.h common/mptStringParse.cpp \
 	common/mptStringParse.h common/mptThread.h common/mptTime.cpp \
 	common/mptTime.h common/mptTypeTraits.h common/mptUUID.cpp \
-	common/mptUUID.h common/Profiler.cpp common/Profiler.h \
+	common/mptUUID.h common/mptWine.cpp common/mptWine.h \
+	common/Profiler.cpp common/Profiler.h \
 	common/serialization_utils.cpp common/serialization_utils.h \
 	common/stdafx.cpp common/stdafx.h common/StringFixer.h \
 	common/typedefs.cpp common/typedefs.h common/version.cpp \
 	common/version.h common/versionNumber.h \
-	soundlib/AudioCriticalSection.cpp \
+	soundbase/SampleFormat.h soundbase/SampleFormatConverters.h \
+	soundbase/SampleFormatCopy.h soundlib/AudioCriticalSection.cpp \
 	soundlib/AudioCriticalSection.h soundlib/AudioReadTarget.h \
-	soundlib/ChunkReader.h soundlib/Dither.cpp soundlib/Dither.h \
-	soundlib/Dlsbank.cpp soundlib/Dlsbank.h soundlib/Fastmix.cpp \
-	soundlib/FloatMixer.h soundlib/InstrumentExtensions.cpp \
-	soundlib/IntMixer.h soundlib/ITCompression.cpp \
-	soundlib/ITCompression.h soundlib/ITTools.cpp \
-	soundlib/ITTools.h soundlib/Load_669.cpp soundlib/Load_amf.cpp \
-	soundlib/Load_ams.cpp soundlib/Load_dbm.cpp \
-	soundlib/Load_digi.cpp soundlib/Load_dmf.cpp \
-	soundlib/Load_dsm.cpp soundlib/Loaders.h soundlib/Load_far.cpp \
+	soundlib/ChunkReader.h soundlib/ContainerMMCMP.cpp \
+	soundlib/ContainerPP20.cpp soundlib/ContainerUMX.cpp \
+	soundlib/ContainerXPK.cpp soundlib/Container.h \
+	soundlib/Dither.cpp soundlib/Dither.h soundlib/Dlsbank.cpp \
+	soundlib/Dlsbank.h soundlib/Fastmix.cpp soundlib/FloatMixer.h \
+	soundlib/InstrumentExtensions.cpp soundlib/IntMixer.h \
+	soundlib/ITCompression.cpp soundlib/ITCompression.h \
+	soundlib/ITTools.cpp soundlib/ITTools.h soundlib/Load_669.cpp \
+	soundlib/Load_amf.cpp soundlib/Load_ams.cpp \
+	soundlib/Load_dbm.cpp soundlib/Load_digi.cpp \
+	soundlib/Load_dmf.cpp soundlib/Load_dsm.cpp \
+	soundlib/Load_dtm.cpp soundlib/Loaders.h soundlib/Load_far.cpp \
 	soundlib/Load_gdm.cpp soundlib/Load_imf.cpp \
 	soundlib/Load_it.cpp soundlib/Load_itp.cpp \
 	soundlib/load_j2b.cpp soundlib/Load_mdl.cpp \
@@ -439,30 +486,34 @@ am__libopenmpttest_SOURCES_DIST = libopenmpt/libopenmpt_test.cpp \
 	soundlib/Load_okt.cpp soundlib/Load_plm.cpp \
 	soundlib/Load_psm.cpp soundlib/Load_ptm.cpp \
 	soundlib/Load_s3m.cpp soundlib/Load_sfx.cpp \
-	soundlib/Load_stm.cpp soundlib/Load_ult.cpp \
-	soundlib/Load_umx.cpp soundlib/Load_wav.cpp \
-	soundlib/Load_xm.cpp soundlib/Message.cpp soundlib/Message.h \
+	soundlib/Load_stm.cpp soundlib/Load_stp.cpp \
+	soundlib/Load_uax.cpp soundlib/Load_ult.cpp \
+	soundlib/Load_wav.cpp soundlib/Load_xm.cpp \
+	soundlib/Message.cpp soundlib/Message.h \
 	soundlib/MIDIEvents.cpp soundlib/MIDIEvents.h \
 	soundlib/MIDIMacros.cpp soundlib/MIDIMacros.h soundlib/Mixer.h \
 	soundlib/MixerInterface.h soundlib/MixerLoops.cpp \
 	soundlib/MixerLoops.h soundlib/MixerSettings.cpp \
 	soundlib/MixerSettings.h soundlib/MixFuncTable.cpp \
-	soundlib/MixFuncTable.h soundlib/Mmcmp.cpp \
-	soundlib/ModChannel.cpp soundlib/ModChannel.h \
-	soundlib/modcommand.cpp soundlib/modcommand.h \
-	soundlib/ModInstrument.cpp soundlib/ModInstrument.h \
-	soundlib/ModSample.cpp soundlib/ModSample.h \
+	soundlib/MixFuncTable.h soundlib/ModChannel.cpp \
+	soundlib/ModChannel.h soundlib/modcommand.cpp \
+	soundlib/modcommand.h soundlib/ModInstrument.cpp \
+	soundlib/ModInstrument.h soundlib/ModSample.cpp \
+	soundlib/ModSample.h soundlib/ModSampleCopy.h \
 	soundlib/ModSequence.cpp soundlib/ModSequence.h \
 	soundlib/modsmp_ctrl.cpp soundlib/modsmp_ctrl.h \
 	soundlib/mod_specifications.cpp soundlib/mod_specifications.h \
 	soundlib/MPEGFrame.cpp soundlib/MPEGFrame.h \
-	soundlib/OggStream.cpp soundlib/OggStream.h \
-	soundlib/patternContainer.cpp soundlib/patternContainer.h \
-	soundlib/pattern.cpp soundlib/pattern.h soundlib/Resampler.h \
+	soundlib/OggStream.cpp soundlib/OggStream.h soundlib/Paula.cpp \
+	soundlib/Paula.h soundlib/patternContainer.cpp \
+	soundlib/patternContainer.h soundlib/pattern.cpp \
+	soundlib/pattern.h soundlib/Resampler.h \
 	soundlib/RowVisitor.cpp soundlib/RowVisitor.h \
 	soundlib/S3MTools.cpp soundlib/S3MTools.h \
-	soundlib/SampleFormatConverters.h soundlib/SampleFormat.h \
-	soundlib/SampleFormats.cpp soundlib/SampleIO.cpp \
+	soundlib/SampleFormats.cpp soundlib/SampleFormatFLAC.cpp \
+	soundlib/SampleFormatMediaFoundation.cpp \
+	soundlib/SampleFormatMP3.cpp soundlib/SampleFormatOpus.cpp \
+	soundlib/SampleFormatVorbis.cpp soundlib/SampleIO.cpp \
 	soundlib/SampleIO.h soundlib/Snd_defs.h soundlib/Sndfile.cpp \
 	soundlib/Sndfile.h soundlib/Snd_flt.cpp soundlib/Snd_fx.cpp \
 	soundlib/Sndmix.cpp soundlib/SoundFilePlayConfig.cpp \
@@ -470,185 +521,195 @@ am__libopenmpttest_SOURCES_DIST = libopenmpt/libopenmpt_test.cpp \
 	soundlib/Tables.h soundlib/Tagging.cpp soundlib/Tagging.h \
 	soundlib/tuningbase.cpp soundlib/tuningbase.h \
 	soundlib/tuningCollection.cpp soundlib/tuningcollection.h \
-	soundlib/tuning.cpp soundlib/tuning.h \
-	soundlib/UpgradeModule.cpp soundlib/WAVTools.cpp \
-	soundlib/WAVTools.h soundlib/WindowedFIR.cpp \
-	soundlib/WindowedFIR.h soundlib/XMTools.cpp soundlib/XMTools.h \
-	soundlib/plugins/PlugInterface.h \
+	soundlib/tuning.cpp soundlib/tuning.h soundlib/UMXTools.cpp \
+	soundlib/UMXTools.h soundlib/UpgradeModule.cpp \
+	soundlib/WAVTools.cpp soundlib/WAVTools.h \
+	soundlib/WindowedFIR.cpp soundlib/WindowedFIR.h \
+	soundlib/XMTools.cpp soundlib/XMTools.h \
 	soundlib/plugins/dmo/DMOPlugin.cpp \
 	soundlib/plugins/dmo/DMOPlugin.h \
+	soundlib/plugins/dmo/Chorus.cpp soundlib/plugins/dmo/Chorus.h \
 	soundlib/plugins/dmo/Compressor.cpp \
 	soundlib/plugins/dmo/Compressor.h \
 	soundlib/plugins/dmo/Distortion.cpp \
-	soundlib/plugins/dmo/Distortion.h soundlib/plugins/dmo/Echo.h \
-	soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/Gargle.cpp \
-	soundlib/plugins/dmo/Gargle.h soundlib/plugins/dmo/ParamEq.cpp \
+	soundlib/plugins/dmo/Distortion.h \
+	soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/Echo.h \
+	soundlib/plugins/dmo/Flanger.cpp \
+	soundlib/plugins/dmo/Flanger.h soundlib/plugins/dmo/Gargle.cpp \
+	soundlib/plugins/dmo/Gargle.h \
+	soundlib/plugins/dmo/I3DL2Reverb.cpp \
+	soundlib/plugins/dmo/I3DL2Reverb.h \
+	soundlib/plugins/dmo/ParamEq.cpp \
 	soundlib/plugins/dmo/ParamEq.h \
 	soundlib/plugins/dmo/WavesReverb.cpp \
 	soundlib/plugins/dmo/WavesReverb.h \
 	soundlib/plugins/DigiBoosterEcho.cpp \
 	soundlib/plugins/DigiBoosterEcho.h \
+	soundlib/plugins/LFOPlugin.cpp soundlib/plugins/LFOPlugin.h \
 	soundlib/plugins/PluginManager.cpp \
 	soundlib/plugins/PluginManager.h \
 	soundlib/plugins/PluginMixBuffer.h \
 	soundlib/plugins/PluginStructs.h \
-	soundlib/plugins/PlugInterface.cpp libopenmpt/libopenmpt_c.cpp \
-	libopenmpt/libopenmpt_cxx.cpp libopenmpt/libopenmpt_ext.cpp \
+	soundlib/plugins/PlugInterface.cpp \
+	soundlib/plugins/PlugInterface.h sounddsp/AGC.cpp \
+	sounddsp/AGC.h sounddsp/DSP.cpp sounddsp/DSP.h sounddsp/EQ.cpp \
+	sounddsp/EQ.h sounddsp/Reverb.cpp sounddsp/Reverb.h \
+	libopenmpt/libopenmpt_c.cpp libopenmpt/libopenmpt_cxx.cpp \
+	libopenmpt/libopenmpt_ext_impl.cpp \
 	libopenmpt/libopenmpt_impl.cpp libopenmpt/libopenmpt_config.h \
-	libopenmpt/libopenmpt_ext.hpp libopenmpt/libopenmpt.h \
+	libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp \
+	libopenmpt/libopenmpt_ext_impl.hpp libopenmpt/libopenmpt.h \
 	libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_impl.hpp \
 	libopenmpt/libopenmpt_internal.h \
+	libopenmpt/libopenmpt_stream_callbacks_buffer.h \
 	libopenmpt/libopenmpt_stream_callbacks_fd.h \
 	libopenmpt/libopenmpt_stream_callbacks_file.h \
 	libopenmpt/libopenmpt_version.h
+am__objects_5 = common/libopenmpttest-ComponentManager.$(OBJEXT) \
+	common/libopenmpttest-FileReader.$(OBJEXT) \
+	common/libopenmpttest-Logging.$(OBJEXT) \
+	common/libopenmpttest-misc_util.$(OBJEXT) \
+	common/libopenmpttest-mptCPU.$(OBJEXT) \
+	common/libopenmpttest-mptFileIO.$(OBJEXT) \
+	common/libopenmpttest-mptIO.$(OBJEXT) \
+	common/libopenmpttest-mptLibrary.$(OBJEXT) \
+	common/libopenmpttest-mptOS.$(OBJEXT) \
+	common/libopenmpttest-mptPathString.$(OBJEXT) \
+	common/libopenmpttest-mptRandom.$(OBJEXT) \
+	common/libopenmpttest-mptString.$(OBJEXT) \
+	common/libopenmpttest-mptStringFormat.$(OBJEXT) \
+	common/libopenmpttest-mptStringParse.$(OBJEXT) \
+	common/libopenmpttest-mptTime.$(OBJEXT) \
+	common/libopenmpttest-mptUUID.$(OBJEXT) \
+	common/libopenmpttest-mptWine.$(OBJEXT) \
+	common/libopenmpttest-Profiler.$(OBJEXT) \
+	common/libopenmpttest-serialization_utils.$(OBJEXT) \
+	common/libopenmpttest-stdafx.$(OBJEXT) \
+	common/libopenmpttest-typedefs.$(OBJEXT) \
+	common/libopenmpttest-version.$(OBJEXT)
+am__objects_6 =  \
+	soundlib/libopenmpttest-AudioCriticalSection.$(OBJEXT) \
+	soundlib/libopenmpttest-ContainerMMCMP.$(OBJEXT) \
+	soundlib/libopenmpttest-ContainerPP20.$(OBJEXT) \
+	soundlib/libopenmpttest-ContainerUMX.$(OBJEXT) \
+	soundlib/libopenmpttest-ContainerXPK.$(OBJEXT) \
+	soundlib/libopenmpttest-Dither.$(OBJEXT) \
+	soundlib/libopenmpttest-Dlsbank.$(OBJEXT) \
+	soundlib/libopenmpttest-Fastmix.$(OBJEXT) \
+	soundlib/libopenmpttest-InstrumentExtensions.$(OBJEXT) \
+	soundlib/libopenmpttest-ITCompression.$(OBJEXT) \
+	soundlib/libopenmpttest-ITTools.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_669.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_amf.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_ams.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_dbm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_digi.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_dmf.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_dsm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_dtm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_far.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_gdm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_imf.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_it.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_itp.$(OBJEXT) \
+	soundlib/libopenmpttest-load_j2b.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_mdl.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_med.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_mid.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_mo3.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_mod.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_mt2.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_mtm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_okt.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_plm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_psm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_ptm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_s3m.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_sfx.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_stm.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_stp.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_uax.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_ult.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_wav.$(OBJEXT) \
+	soundlib/libopenmpttest-Load_xm.$(OBJEXT) \
+	soundlib/libopenmpttest-Message.$(OBJEXT) \
+	soundlib/libopenmpttest-MIDIEvents.$(OBJEXT) \
+	soundlib/libopenmpttest-MIDIMacros.$(OBJEXT) \
+	soundlib/libopenmpttest-MixerLoops.$(OBJEXT) \
+	soundlib/libopenmpttest-MixerSettings.$(OBJEXT) \
+	soundlib/libopenmpttest-MixFuncTable.$(OBJEXT) \
+	soundlib/libopenmpttest-ModChannel.$(OBJEXT) \
+	soundlib/libopenmpttest-modcommand.$(OBJEXT) \
+	soundlib/libopenmpttest-ModInstrument.$(OBJEXT) \
+	soundlib/libopenmpttest-ModSample.$(OBJEXT) \
+	soundlib/libopenmpttest-ModSequence.$(OBJEXT) \
+	soundlib/libopenmpttest-modsmp_ctrl.$(OBJEXT) \
+	soundlib/libopenmpttest-mod_specifications.$(OBJEXT) \
+	soundlib/libopenmpttest-MPEGFrame.$(OBJEXT) \
+	soundlib/libopenmpttest-OggStream.$(OBJEXT) \
+	soundlib/libopenmpttest-Paula.$(OBJEXT) \
+	soundlib/libopenmpttest-patternContainer.$(OBJEXT) \
+	soundlib/libopenmpttest-pattern.$(OBJEXT) \
+	soundlib/libopenmpttest-RowVisitor.$(OBJEXT) \
+	soundlib/libopenmpttest-S3MTools.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleFormats.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleFormatFLAC.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleFormatMediaFoundation.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleFormatMP3.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleFormatOpus.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleFormatVorbis.$(OBJEXT) \
+	soundlib/libopenmpttest-SampleIO.$(OBJEXT) \
+	soundlib/libopenmpttest-Sndfile.$(OBJEXT) \
+	soundlib/libopenmpttest-Snd_flt.$(OBJEXT) \
+	soundlib/libopenmpttest-Snd_fx.$(OBJEXT) \
+	soundlib/libopenmpttest-Sndmix.$(OBJEXT) \
+	soundlib/libopenmpttest-SoundFilePlayConfig.$(OBJEXT) \
+	soundlib/libopenmpttest-Tables.$(OBJEXT) \
+	soundlib/libopenmpttest-Tagging.$(OBJEXT) \
+	soundlib/libopenmpttest-tuningbase.$(OBJEXT) \
+	soundlib/libopenmpttest-tuningCollection.$(OBJEXT) \
+	soundlib/libopenmpttest-tuning.$(OBJEXT) \
+	soundlib/libopenmpttest-UMXTools.$(OBJEXT) \
+	soundlib/libopenmpttest-UpgradeModule.$(OBJEXT) \
+	soundlib/libopenmpttest-WAVTools.$(OBJEXT) \
+	soundlib/libopenmpttest-WindowedFIR.$(OBJEXT) \
+	soundlib/libopenmpttest-XMTools.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-DMOPlugin.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-Chorus.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-Compressor.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-Distortion.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-Echo.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-Flanger.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-Gargle.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-ParamEq.$(OBJEXT) \
+	soundlib/plugins/dmo/libopenmpttest-WavesReverb.$(OBJEXT) \
+	soundlib/plugins/libopenmpttest-DigiBoosterEcho.$(OBJEXT) \
+	soundlib/plugins/libopenmpttest-LFOPlugin.$(OBJEXT) \
+	soundlib/plugins/libopenmpttest-PluginManager.$(OBJEXT) \
+	soundlib/plugins/libopenmpttest-PlugInterface.$(OBJEXT)
+am__objects_7 = sounddsp/libopenmpttest-AGC.$(OBJEXT) \
+	sounddsp/libopenmpttest-DSP.$(OBJEXT) \
+	sounddsp/libopenmpttest-EQ.$(OBJEXT) \
+	sounddsp/libopenmpttest-Reverb.$(OBJEXT)
 @ENABLE_TESTS_TRUE at am_libopenmpttest_OBJECTS = libopenmpt/libopenmpttest-libopenmpt_test.$(OBJEXT) \
 @ENABLE_TESTS_TRUE@	test/libopenmpttest-test.$(OBJEXT) \
 @ENABLE_TESTS_TRUE@	test/libopenmpttest-TestToolsLib.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-ComponentManager.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-FileReader.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-Logging.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-misc_util.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptCPU.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptFileIO.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptIO.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptLibrary.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptOS.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptPathString.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptRandom.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptString.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptStringFormat.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptStringParse.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptTime.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-mptUUID.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-Profiler.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-serialization_utils.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-stdafx.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-typedefs.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	common/libopenmpttest-version.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-AudioCriticalSection.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Dither.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Dlsbank.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Fastmix.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-InstrumentExtensions.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-ITCompression.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-ITTools.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_669.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_amf.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_ams.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_dbm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_digi.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_dmf.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_dsm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_far.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_gdm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_imf.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_it.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_itp.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-load_j2b.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_mdl.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_med.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_mid.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_mo3.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_mod.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_mt2.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_mtm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_okt.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_plm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_psm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_ptm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_s3m.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_sfx.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_stm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_ult.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_umx.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_wav.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Load_xm.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Message.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-MIDIEvents.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-MIDIMacros.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-MixerLoops.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-MixerSettings.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-MixFuncTable.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Mmcmp.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-ModChannel.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-modcommand.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-ModInstrument.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-ModSample.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-ModSequence.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-modsmp_ctrl.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-mod_specifications.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-MPEGFrame.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-OggStream.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-patternContainer.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-pattern.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-RowVisitor.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-S3MTools.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-SampleFormats.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-SampleIO.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Sndfile.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Snd_flt.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Snd_fx.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Sndmix.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-SoundFilePlayConfig.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Tables.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-Tagging.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-tuningbase.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-tuningCollection.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-tuning.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-UpgradeModule.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-WAVTools.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-WindowedFIR.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/libopenmpttest-XMTools.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-DMOPlugin.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-Compressor.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-Distortion.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-Echo.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-Gargle.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-ParamEq.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/libopenmpttest-WavesReverb.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/libopenmpttest-DigiBoosterEcho.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/libopenmpttest-PluginManager.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/libopenmpttest-PlugInterface.$(OBJEXT) \
+ at ENABLE_TESTS_TRUE@	$(am__objects_5) $(am__objects_2) \
+ at ENABLE_TESTS_TRUE@	$(am__objects_6) $(am__objects_7) \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpttest-libopenmpt_c.$(OBJEXT) \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpttest-libopenmpt_cxx.$(OBJEXT) \
- at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpttest-libopenmpt_ext.$(OBJEXT) \
+ at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpttest-libopenmpt_ext_impl.$(OBJEXT) \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpttest-libopenmpt_impl.$(OBJEXT)
 libopenmpttest_OBJECTS = $(am_libopenmpttest_OBJECTS)
 @ENABLE_TESTS_TRUE at libopenmpttest_DEPENDENCIES =  \
 @ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 @ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- at ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 @ENABLE_TESTS_TRUE@	$(am__DEPENDENCIES_1)
 libopenmpttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
 	$(libopenmpttest_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
 	$(LDFLAGS) -o $@
-am__openmpt123_SOURCES_DIST = src/openmpt123/openmpt123_config.hpp \
-	src/openmpt123/openmpt123.cpp \
-	src/openmpt123/openmpt123_flac.hpp \
-	src/openmpt123/openmpt123.hpp \
-	src/openmpt123/openmpt123_mmio.hpp \
-	src/openmpt123/openmpt123_portaudio.hpp \
-	src/openmpt123/openmpt123_pulseaudio.hpp \
-	src/openmpt123/openmpt123_raw.hpp \
-	src/openmpt123/openmpt123_sdl.hpp \
-	src/openmpt123/openmpt123_sdl2.hpp \
-	src/openmpt123/openmpt123_sndfile.hpp \
-	src/openmpt123/openmpt123_stdout.hpp \
-	src/openmpt123/openmpt123_waveout.hpp
- at ENABLE_OPENMPT123_TRUE@am_openmpt123_OBJECTS = src/openmpt123/openmpt123-openmpt123.$(OBJEXT)
-openmpt123_OBJECTS = $(am_openmpt123_OBJECTS)
- at ENABLE_OPENMPT123_TRUE@openmpt123_DEPENDENCIES = libopenmpt.la \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1) \
- at ENABLE_OPENMPT123_TRUE@	$(am__DEPENDENCIES_1)
-openmpt123_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(openmpt123_CXXFLAGS) \
-	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -702,25 +763,24 @@ am__v_CXXLD_ = $(am__v_CXXLD_ at AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
 SOURCES = $(libmodplug_la_SOURCES) $(libopenmpt_la_SOURCES) \
-	$(libopenmpt_modplug_la_SOURCES) \
+	$(libopenmpt_modplug_la_SOURCES) $(bin_openmpt123_SOURCES) \
 	$(libopenmpt_example_c_SOURCES) \
 	$(libopenmpt_example_c_mem_SOURCES) \
 	$(libopenmpt_example_c_probe_SOURCES) \
 	$(libopenmpt_example_c_stdout_SOURCES) \
 	$(libopenmpt_example_c_unsafe_SOURCES) \
-	$(libopenmpt_example_cxx_SOURCES) $(libopenmpttest_SOURCES) \
-	$(openmpt123_SOURCES)
+	$(libopenmpt_example_cxx_SOURCES) $(libopenmpttest_SOURCES)
 DIST_SOURCES = $(am__libmodplug_la_SOURCES_DIST) \
 	$(libopenmpt_la_SOURCES) \
 	$(am__libopenmpt_modplug_la_SOURCES_DIST) \
+	$(am__bin_openmpt123_SOURCES_DIST) \
 	$(am__libopenmpt_example_c_SOURCES_DIST) \
 	$(am__libopenmpt_example_c_mem_SOURCES_DIST) \
 	$(am__libopenmpt_example_c_probe_SOURCES_DIST) \
 	$(am__libopenmpt_example_c_stdout_SOURCES_DIST) \
 	$(am__libopenmpt_example_c_unsafe_SOURCES_DIST) \
 	$(am__libopenmpt_example_cxx_SOURCES_DIST) \
-	$(am__libopenmpttest_SOURCES_DIST) \
-	$(am__openmpt123_SOURCES_DIST)
+	$(am__libopenmpttest_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -733,10 +793,11 @@ DATA = $(dist_doc_DATA) $(nobase_dist_doc_DATA) $(pkgconfig_DATA)
 am__nobase_include_HEADERS_DIST = libopenmpt/libopenmpt.h \
 	libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_version.h \
 	libopenmpt/libopenmpt_config.h \
+	libopenmpt/libopenmpt_stream_callbacks_buffer.h \
 	libopenmpt/libopenmpt_stream_callbacks_fd.h \
 	libopenmpt/libopenmpt_stream_callbacks_file.h \
-	libopenmpt/libopenmpt_ext.hpp libmodplug/modplug.h \
-	libmodplug/sndfile.h libmodplug/stdafx.h
+	libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp \
+	libmodplug/modplug.h libmodplug/sndfile.h libmodplug/stdafx.h
 HEADERS = $(nobase_include_HEADERS)
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
 	$(LISP)config.h.in
@@ -936,6 +997,21 @@ TEST_LOGS = $(am__test_logs2:.test.log=.log)
 TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
 TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
 	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Doxyfile.in $(srcdir)/Makefile.in \
+	$(srcdir)/config.h.in $(top_srcdir)/build-aux/ar-lib \
+	$(top_srcdir)/build-aux/compile \
+	$(top_srcdir)/build-aux/config.guess \
+	$(top_srcdir)/build-aux/config.sub \
+	$(top_srcdir)/build-aux/depcomp \
+	$(top_srcdir)/build-aux/install-sh \
+	$(top_srcdir)/build-aux/ltmain.sh \
+	$(top_srcdir)/build-aux/missing \
+	$(top_srcdir)/build-aux/test-driver \
+	$(top_srcdir)/libmodplug/libmodplug.pc.in \
+	$(top_srcdir)/libopenmpt/libopenmpt.pc.in build-aux/ar-lib \
+	build-aux/compile build-aux/config.guess build-aux/config.sub \
+	build-aux/depcomp build-aux/install-sh build-aux/ltmain.sh \
+	build-aux/missing
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -974,8 +1050,6 @@ CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DLLTOOL = @DLLTOOL@
-DL_CPPFLAGS = @DL_CPPFLAGS@
-DL_LIBS = @DL_LIBS@
 DOXYGEN_PAPER_SIZE = @DOXYGEN_PAPER_SIZE@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
@@ -1021,15 +1095,17 @@ LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
 LIBOPENMPT_LIBS_PRIVATE = @LIBOPENMPT_LIBS_PRIVATE@
+LIBOPENMPT_LTVER_AGE = @LIBOPENMPT_LTVER_AGE@
+LIBOPENMPT_LTVER_CURRENT = @LIBOPENMPT_LTVER_CURRENT@
+LIBOPENMPT_LTVER_REVISION = @LIBOPENMPT_LTVER_REVISION@
 LIBOPENMPT_REQUIRES_PRIVATE = @LIBOPENMPT_REQUIRES_PRIVATE@
 LIBOPENMPT_WIN32_LIBS = @LIBOPENMPT_WIN32_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
-LTDL_CPPFLAGS = @LTDL_CPPFLAGS@
-LTDL_LIBS = @LTDL_LIBS@
 LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
@@ -1126,6 +1202,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -1140,11 +1217,12 @@ EXTRA_DIST = m4/emptydir libopenmpt/libopenmpt.pc.in \
 	libopenmpt/dox/changelog.md libopenmpt/dox/dependencies.md \
 	libopenmpt/dox/index.dox libopenmpt/dox/packaging.md \
 	libopenmpt/dox/quickstart.md libopenmpt/dox/tests.md \
-	libopenmpt/dox/todo.md test/test.xm test/test.s3m \
-	test/test.mptm man/openmpt123.1 examples/.clang-format \
+	libopenmpt/dox/todo.md libopenmpt/libopenmpt_version.mk \
+	test/test.xm test/test.s3m test/test.mptm man/openmpt123.1 \
+	examples/.clang-format \
 	libopenmpt/bindings/freebasic/libopenmpt.bi
 MOSTLYCLEANFILES = $(DX_CLEANFILES)
-dist_doc_DATA = LICENSE README.md TODO
+dist_doc_DATA = LICENSE README.md
 nobase_dist_doc_DATA = examples/libopenmpt_example_cxx.cpp \
 	examples/libopenmpt_example_c_mem.c \
 	examples/libopenmpt_example_c_unsafe.c \
@@ -1181,20 +1259,16 @@ pkgconfig_DATA = libopenmpt/libopenmpt.pc $(am__append_5)
 nobase_include_HEADERS = libopenmpt/libopenmpt.h \
 	libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_version.h \
 	libopenmpt/libopenmpt_config.h \
+	libopenmpt/libopenmpt_stream_callbacks_buffer.h \
 	libopenmpt/libopenmpt_stream_callbacks_fd.h \
 	libopenmpt/libopenmpt_stream_callbacks_file.h \
-	libopenmpt/libopenmpt_ext.hpp $(am__append_7)
-libopenmpt_la_LDFLAGS = -version-info 0:26:0
-libopenmpt_la_CPPFLAGS = -DLIBOPENMPT_BUILD -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(LTDL_CPPFLAGS) $(DL_CPPFLAGS)
-libopenmpt_la_CXXFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
-libopenmpt_la_CFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
-libopenmpt_la_LIBADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LTDL_LIBS) $(DL_LIBS) $(LIBOPENMPT_WIN32_LIBS)
-libopenmpt_la_SOURCES = build/svn_version/svn_version.h \
-	common/BuildSettings.h common/CompilerDetect.h \
+	libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp \
+	$(am__append_7)
+MPT_FILES_COMMON = common/BuildSettings.h common/CompilerDetect.h \
 	common/ComponentManager.cpp common/ComponentManager.h \
 	common/Endianness.h common/FileReader.cpp common/FileReader.h \
-	common/FlagSet.h common/Logging.cpp common/Logging.h \
-	common/misc_util.cpp common/misc_util.h common/mptAtomic.h \
+	common/FileReaderFwd.h common/FlagSet.h common/Logging.cpp \
+	common/Logging.h common/misc_util.cpp common/misc_util.h \
 	common/mptBufferIO.h common/mptCPU.cpp common/mptCPU.h \
 	common/mptCRC.h common/mptFileIO.cpp common/mptFileIO.h \
 	common/mptIO.cpp common/mptIO.h common/mptLibrary.cpp \
@@ -1205,22 +1279,29 @@ libopenmpt_la_SOURCES = build/svn_version/svn_version.h \
 	common/mptStringFormat.h common/mptStringParse.cpp \
 	common/mptStringParse.h common/mptThread.h common/mptTime.cpp \
 	common/mptTime.h common/mptTypeTraits.h common/mptUUID.cpp \
-	common/mptUUID.h common/Profiler.cpp common/Profiler.h \
+	common/mptUUID.h common/mptWine.cpp common/mptWine.h \
+	common/Profiler.cpp common/Profiler.h \
 	common/serialization_utils.cpp common/serialization_utils.h \
 	common/stdafx.cpp common/stdafx.h common/StringFixer.h \
 	common/typedefs.cpp common/typedefs.h common/version.cpp \
-	common/version.h common/versionNumber.h \
-	soundlib/AudioCriticalSection.cpp \
+	common/version.h common/versionNumber.h
+MPT_FILES_SOUNDBASE = soundbase/SampleFormat.h \
+	soundbase/SampleFormatConverters.h \
+	soundbase/SampleFormatCopy.h
+MPT_FILES_SOUNDLIB = soundlib/AudioCriticalSection.cpp \
 	soundlib/AudioCriticalSection.h soundlib/AudioReadTarget.h \
-	soundlib/ChunkReader.h soundlib/Dither.cpp soundlib/Dither.h \
-	soundlib/Dlsbank.cpp soundlib/Dlsbank.h soundlib/Fastmix.cpp \
-	soundlib/FloatMixer.h soundlib/InstrumentExtensions.cpp \
-	soundlib/IntMixer.h soundlib/ITCompression.cpp \
-	soundlib/ITCompression.h soundlib/ITTools.cpp \
-	soundlib/ITTools.h soundlib/Load_669.cpp soundlib/Load_amf.cpp \
-	soundlib/Load_ams.cpp soundlib/Load_dbm.cpp \
-	soundlib/Load_digi.cpp soundlib/Load_dmf.cpp \
-	soundlib/Load_dsm.cpp soundlib/Loaders.h soundlib/Load_far.cpp \
+	soundlib/ChunkReader.h soundlib/ContainerMMCMP.cpp \
+	soundlib/ContainerPP20.cpp soundlib/ContainerUMX.cpp \
+	soundlib/ContainerXPK.cpp soundlib/Container.h \
+	soundlib/Dither.cpp soundlib/Dither.h soundlib/Dlsbank.cpp \
+	soundlib/Dlsbank.h soundlib/Fastmix.cpp soundlib/FloatMixer.h \
+	soundlib/InstrumentExtensions.cpp soundlib/IntMixer.h \
+	soundlib/ITCompression.cpp soundlib/ITCompression.h \
+	soundlib/ITTools.cpp soundlib/ITTools.h soundlib/Load_669.cpp \
+	soundlib/Load_amf.cpp soundlib/Load_ams.cpp \
+	soundlib/Load_dbm.cpp soundlib/Load_digi.cpp \
+	soundlib/Load_dmf.cpp soundlib/Load_dsm.cpp \
+	soundlib/Load_dtm.cpp soundlib/Loaders.h soundlib/Load_far.cpp \
 	soundlib/Load_gdm.cpp soundlib/Load_imf.cpp \
 	soundlib/Load_it.cpp soundlib/Load_itp.cpp \
 	soundlib/load_j2b.cpp soundlib/Load_mdl.cpp \
@@ -1230,30 +1311,34 @@ libopenmpt_la_SOURCES = build/svn_version/svn_version.h \
 	soundlib/Load_okt.cpp soundlib/Load_plm.cpp \
 	soundlib/Load_psm.cpp soundlib/Load_ptm.cpp \
 	soundlib/Load_s3m.cpp soundlib/Load_sfx.cpp \
-	soundlib/Load_stm.cpp soundlib/Load_ult.cpp \
-	soundlib/Load_umx.cpp soundlib/Load_wav.cpp \
-	soundlib/Load_xm.cpp soundlib/Message.cpp soundlib/Message.h \
+	soundlib/Load_stm.cpp soundlib/Load_stp.cpp \
+	soundlib/Load_uax.cpp soundlib/Load_ult.cpp \
+	soundlib/Load_wav.cpp soundlib/Load_xm.cpp \
+	soundlib/Message.cpp soundlib/Message.h \
 	soundlib/MIDIEvents.cpp soundlib/MIDIEvents.h \
 	soundlib/MIDIMacros.cpp soundlib/MIDIMacros.h soundlib/Mixer.h \
 	soundlib/MixerInterface.h soundlib/MixerLoops.cpp \
 	soundlib/MixerLoops.h soundlib/MixerSettings.cpp \
 	soundlib/MixerSettings.h soundlib/MixFuncTable.cpp \
-	soundlib/MixFuncTable.h soundlib/Mmcmp.cpp \
-	soundlib/ModChannel.cpp soundlib/ModChannel.h \
-	soundlib/modcommand.cpp soundlib/modcommand.h \
-	soundlib/ModInstrument.cpp soundlib/ModInstrument.h \
-	soundlib/ModSample.cpp soundlib/ModSample.h \
+	soundlib/MixFuncTable.h soundlib/ModChannel.cpp \
+	soundlib/ModChannel.h soundlib/modcommand.cpp \
+	soundlib/modcommand.h soundlib/ModInstrument.cpp \
+	soundlib/ModInstrument.h soundlib/ModSample.cpp \
+	soundlib/ModSample.h soundlib/ModSampleCopy.h \
 	soundlib/ModSequence.cpp soundlib/ModSequence.h \
 	soundlib/modsmp_ctrl.cpp soundlib/modsmp_ctrl.h \
 	soundlib/mod_specifications.cpp soundlib/mod_specifications.h \
 	soundlib/MPEGFrame.cpp soundlib/MPEGFrame.h \
-	soundlib/OggStream.cpp soundlib/OggStream.h \
-	soundlib/patternContainer.cpp soundlib/patternContainer.h \
-	soundlib/pattern.cpp soundlib/pattern.h soundlib/Resampler.h \
+	soundlib/OggStream.cpp soundlib/OggStream.h soundlib/Paula.cpp \
+	soundlib/Paula.h soundlib/patternContainer.cpp \
+	soundlib/patternContainer.h soundlib/pattern.cpp \
+	soundlib/pattern.h soundlib/Resampler.h \
 	soundlib/RowVisitor.cpp soundlib/RowVisitor.h \
 	soundlib/S3MTools.cpp soundlib/S3MTools.h \
-	soundlib/SampleFormatConverters.h soundlib/SampleFormat.h \
-	soundlib/SampleFormats.cpp soundlib/SampleIO.cpp \
+	soundlib/SampleFormats.cpp soundlib/SampleFormatFLAC.cpp \
+	soundlib/SampleFormatMediaFoundation.cpp \
+	soundlib/SampleFormatMP3.cpp soundlib/SampleFormatOpus.cpp \
+	soundlib/SampleFormatVorbis.cpp soundlib/SampleIO.cpp \
 	soundlib/SampleIO.h soundlib/Snd_defs.h soundlib/Sndfile.cpp \
 	soundlib/Sndfile.h soundlib/Snd_flt.cpp soundlib/Snd_fx.cpp \
 	soundlib/Sndmix.cpp soundlib/SoundFilePlayConfig.cpp \
@@ -1261,46 +1346,67 @@ libopenmpt_la_SOURCES = build/svn_version/svn_version.h \
 	soundlib/Tables.h soundlib/Tagging.cpp soundlib/Tagging.h \
 	soundlib/tuningbase.cpp soundlib/tuningbase.h \
 	soundlib/tuningCollection.cpp soundlib/tuningcollection.h \
-	soundlib/tuning.cpp soundlib/tuning.h \
-	soundlib/UpgradeModule.cpp soundlib/WAVTools.cpp \
-	soundlib/WAVTools.h soundlib/WindowedFIR.cpp \
-	soundlib/WindowedFIR.h soundlib/XMTools.cpp soundlib/XMTools.h \
+	soundlib/tuning.cpp soundlib/tuning.h soundlib/UMXTools.cpp \
+	soundlib/UMXTools.h soundlib/UpgradeModule.cpp \
+	soundlib/WAVTools.cpp soundlib/WAVTools.h \
+	soundlib/WindowedFIR.cpp soundlib/WindowedFIR.h \
+	soundlib/XMTools.cpp soundlib/XMTools.h \
 	soundlib/plugins/dmo/DMOPlugin.cpp \
 	soundlib/plugins/dmo/DMOPlugin.h \
+	soundlib/plugins/dmo/Chorus.cpp soundlib/plugins/dmo/Chorus.h \
 	soundlib/plugins/dmo/Compressor.cpp \
 	soundlib/plugins/dmo/Compressor.h \
 	soundlib/plugins/dmo/Distortion.cpp \
 	soundlib/plugins/dmo/Distortion.h \
 	soundlib/plugins/dmo/Echo.cpp soundlib/plugins/dmo/Echo.h \
-	soundlib/plugins/dmo/Gargle.cpp soundlib/plugins/dmo/Gargle.h \
+	soundlib/plugins/dmo/Flanger.cpp \
+	soundlib/plugins/dmo/Flanger.h soundlib/plugins/dmo/Gargle.cpp \
+	soundlib/plugins/dmo/Gargle.h \
+	soundlib/plugins/dmo/I3DL2Reverb.cpp \
+	soundlib/plugins/dmo/I3DL2Reverb.h \
 	soundlib/plugins/dmo/ParamEq.cpp \
 	soundlib/plugins/dmo/ParamEq.h \
 	soundlib/plugins/dmo/WavesReverb.cpp \
 	soundlib/plugins/dmo/WavesReverb.h \
 	soundlib/plugins/DigiBoosterEcho.cpp \
 	soundlib/plugins/DigiBoosterEcho.h \
+	soundlib/plugins/LFOPlugin.cpp soundlib/plugins/LFOPlugin.h \
 	soundlib/plugins/PluginManager.cpp \
 	soundlib/plugins/PluginManager.h \
 	soundlib/plugins/PluginMixBuffer.h \
 	soundlib/plugins/PluginStructs.h \
 	soundlib/plugins/PlugInterface.cpp \
-	soundlib/plugins/PlugInterface.h libopenmpt/libopenmpt_c.cpp \
-	libopenmpt/libopenmpt_cxx.cpp libopenmpt/libopenmpt_ext.cpp \
+	soundlib/plugins/PlugInterface.h
+MPT_FILES_SOUNDDSP = sounddsp/AGC.cpp sounddsp/AGC.h sounddsp/DSP.cpp \
+	sounddsp/DSP.h sounddsp/EQ.cpp sounddsp/EQ.h \
+	sounddsp/Reverb.cpp sounddsp/Reverb.h
+libopenmpt_la_LDFLAGS = -version-info $(LIBOPENMPT_LTVER_CURRENT):$(LIBOPENMPT_LTVER_REVISION):$(LIBOPENMPT_LTVER_AGE) -no-undefined
+libopenmpt_la_CPPFLAGS = -DLIBOPENMPT_BUILD -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
+libopenmpt_la_CXXFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
+libopenmpt_la_CFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
+libopenmpt_la_LIBADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIBS)
+libopenmpt_la_SOURCES = build/svn_version/svn_version.h \
+	$(MPT_FILES_COMMON) $(MPT_FILES_SOUNDBASE) \
+	$(MPT_FILES_SOUNDLIB) $(MPT_FILES_SOUNDDSP) \
+	libopenmpt/libopenmpt_c.cpp libopenmpt/libopenmpt_cxx.cpp \
+	libopenmpt/libopenmpt_ext_impl.cpp \
 	libopenmpt/libopenmpt_impl.cpp libopenmpt/libopenmpt_config.h \
-	libopenmpt/libopenmpt_ext.hpp libopenmpt/libopenmpt.h \
+	libopenmpt/libopenmpt_ext.h libopenmpt/libopenmpt_ext.hpp \
+	libopenmpt/libopenmpt_ext_impl.hpp libopenmpt/libopenmpt.h \
 	libopenmpt/libopenmpt.hpp libopenmpt/libopenmpt_impl.hpp \
 	libopenmpt/libopenmpt_internal.h \
+	libopenmpt/libopenmpt_stream_callbacks_buffer.h \
 	libopenmpt/libopenmpt_stream_callbacks_fd.h \
 	libopenmpt/libopenmpt_stream_callbacks_file.h \
 	libopenmpt/libopenmpt_version.h
- at ENABLE_LIBOPENMPT_MODPLUG_TRUE@libopenmpt_modplug_la_LDFLAGS = -version-info 1:0:0
+ at ENABLE_LIBOPENMPT_MODPLUG_TRUE@libopenmpt_modplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE at libopenmpt_modplug_la_CPPFLAGS = -I$(srcdir)/
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE at libopenmpt_modplug_la_CXXFLAGS = 
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE at libopenmpt_modplug_la_CFLAGS = 
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE at libopenmpt_modplug_la_LIBADD = libopenmpt.la
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE at libopenmpt_modplug_la_SOURCES = libopenmpt/libopenmpt_modplug.c \
 @ENABLE_LIBOPENMPT_MODPLUG_TRUE@	libopenmpt/libopenmpt_modplug_cpp.cpp
- at ENABLE_LIBMODPLUG_TRUE@libmodplug_la_LDFLAGS = -version-info 1:0:0
+ at ENABLE_LIBMODPLUG_TRUE@libmodplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
 @ENABLE_LIBMODPLUG_TRUE at libmodplug_la_CPPFLAGS = -I$(srcdir)/
 @ENABLE_LIBMODPLUG_TRUE at libmodplug_la_CXXFLAGS = 
 @ENABLE_LIBMODPLUG_TRUE at libmodplug_la_CFLAGS = 
@@ -1308,206 +1414,52 @@ libopenmpt_la_SOURCES = build/svn_version/svn_version.h \
 @ENABLE_LIBMODPLUG_TRUE at libmodplug_la_SOURCES =  \
 @ENABLE_LIBMODPLUG_TRUE@	libopenmpt/libopenmpt_modplug.c \
 @ENABLE_LIBMODPLUG_TRUE@	libopenmpt/libopenmpt_modplug_cpp.cpp
- at ENABLE_TESTS_TRUE@libopenmpttest_CPPFLAGS = -DLIBOPENMPT_BUILD -DLIBOPENMPT_BUILD_TEST -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(LTDL_CPPFLAGS) $(DL_CPPFLAGS)
+ at ENABLE_TESTS_TRUE@libopenmpttest_CPPFLAGS = -DLIBOPENMPT_BUILD -DLIBOPENMPT_BUILD_TEST -I$(srcdir)/build/svn_version -I$(srcdir)/ -I$(srcdir)/common $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS)
 @ENABLE_TESTS_TRUE at libopenmpttest_CXXFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(WIN32_CONSOLE_CXXFLAGS)
 @ENABLE_TESTS_TRUE at libopenmpttest_CFLAGS = $(ZLIB_CFLAGS) $(MPG123_CFLAGS) $(OGG_CFLAGS) $(VORBIS_CFLAGS) $(VORBISFILE_CFLAGS) $(WIN32_CONSOLE_CFLAGS)
- at ENABLE_TESTS_TRUE@libopenmpttest_LDADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LTDL_LIBS) $(DL_LIBS) $(LIBOPENMPT_WIN32_LIB)
+ at ENABLE_TESTS_TRUE@libopenmpttest_LDADD = $(ZLIB_LIBS) $(MPG123_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(VORBISFILE_LIBS) $(LIBOPENMPT_WIN32_LIB)
 @ENABLE_TESTS_TRUE at libopenmpttest_SOURCES =  \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_test.cpp \
 @ENABLE_TESTS_TRUE@	test/test.cpp test/test.h test/TestTools.h \
 @ENABLE_TESTS_TRUE@	test/TestToolsLib.cpp test/TestToolsLib.h \
 @ENABLE_TESTS_TRUE@	test/TestToolsTracker.h \
 @ENABLE_TESTS_TRUE@	build/svn_version/svn_version.h \
- at ENABLE_TESTS_TRUE@	common/BuildSettings.h \
- at ENABLE_TESTS_TRUE@	common/CompilerDetect.h \
- at ENABLE_TESTS_TRUE@	common/ComponentManager.cpp \
- at ENABLE_TESTS_TRUE@	common/ComponentManager.h \
- at ENABLE_TESTS_TRUE@	common/Endianness.h common/FileReader.cpp \
- at ENABLE_TESTS_TRUE@	common/FileReader.h common/FlagSet.h \
- at ENABLE_TESTS_TRUE@	common/Logging.cpp common/Logging.h \
- at ENABLE_TESTS_TRUE@	common/misc_util.cpp common/misc_util.h \
- at ENABLE_TESTS_TRUE@	common/mptAtomic.h common/mptBufferIO.h \
- at ENABLE_TESTS_TRUE@	common/mptCPU.cpp common/mptCPU.h \
- at ENABLE_TESTS_TRUE@	common/mptCRC.h common/mptFileIO.cpp \
- at ENABLE_TESTS_TRUE@	common/mptFileIO.h common/mptIO.cpp \
- at ENABLE_TESTS_TRUE@	common/mptIO.h common/mptLibrary.cpp \
- at ENABLE_TESTS_TRUE@	common/mptLibrary.h common/mptMutex.h \
- at ENABLE_TESTS_TRUE@	common/mptOS.cpp common/mptOS.h \
- at ENABLE_TESTS_TRUE@	common/mptPathString.cpp \
- at ENABLE_TESTS_TRUE@	common/mptPathString.h common/mptRandom.cpp \
- at ENABLE_TESTS_TRUE@	common/mptRandom.h common/mptString.cpp \
- at ENABLE_TESTS_TRUE@	common/mptString.h \
- at ENABLE_TESTS_TRUE@	common/mptStringFormat.cpp \
- at ENABLE_TESTS_TRUE@	common/mptStringFormat.h \
- at ENABLE_TESTS_TRUE@	common/mptStringParse.cpp \
- at ENABLE_TESTS_TRUE@	common/mptStringParse.h common/mptThread.h \
- at ENABLE_TESTS_TRUE@	common/mptTime.cpp common/mptTime.h \
- at ENABLE_TESTS_TRUE@	common/mptTypeTraits.h common/mptUUID.cpp \
- at ENABLE_TESTS_TRUE@	common/mptUUID.h common/Profiler.cpp \
- at ENABLE_TESTS_TRUE@	common/Profiler.h \
- at ENABLE_TESTS_TRUE@	common/serialization_utils.cpp \
- at ENABLE_TESTS_TRUE@	common/serialization_utils.h \
- at ENABLE_TESTS_TRUE@	common/stdafx.cpp common/stdafx.h \
- at ENABLE_TESTS_TRUE@	common/StringFixer.h common/typedefs.cpp \
- at ENABLE_TESTS_TRUE@	common/typedefs.h common/version.cpp \
- at ENABLE_TESTS_TRUE@	common/version.h common/versionNumber.h \
- at ENABLE_TESTS_TRUE@	soundlib/AudioCriticalSection.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/AudioCriticalSection.h \
- at ENABLE_TESTS_TRUE@	soundlib/AudioReadTarget.h \
- at ENABLE_TESTS_TRUE@	soundlib/ChunkReader.h soundlib/Dither.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Dither.h soundlib/Dlsbank.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Dlsbank.h soundlib/Fastmix.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/FloatMixer.h \
- at ENABLE_TESTS_TRUE@	soundlib/InstrumentExtensions.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/IntMixer.h \
- at ENABLE_TESTS_TRUE@	soundlib/ITCompression.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/ITCompression.h \
- at ENABLE_TESTS_TRUE@	soundlib/ITTools.cpp soundlib/ITTools.h \
- at ENABLE_TESTS_TRUE@	soundlib/Load_669.cpp soundlib/Load_amf.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_ams.cpp soundlib/Load_dbm.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_digi.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_dmf.cpp soundlib/Load_dsm.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Loaders.h soundlib/Load_far.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_gdm.cpp soundlib/Load_imf.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_it.cpp soundlib/Load_itp.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/load_j2b.cpp soundlib/Load_mdl.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_med.cpp soundlib/Load_mid.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_mo3.cpp soundlib/Load_mod.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_mt2.cpp soundlib/Load_mtm.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_okt.cpp soundlib/Load_plm.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_psm.cpp soundlib/Load_ptm.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_s3m.cpp soundlib/Load_sfx.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_stm.cpp soundlib/Load_ult.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_umx.cpp soundlib/Load_wav.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Load_xm.cpp soundlib/Message.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Message.h soundlib/MIDIEvents.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/MIDIEvents.h \
- at ENABLE_TESTS_TRUE@	soundlib/MIDIMacros.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/MIDIMacros.h soundlib/Mixer.h \
- at ENABLE_TESTS_TRUE@	soundlib/MixerInterface.h \
- at ENABLE_TESTS_TRUE@	soundlib/MixerLoops.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/MixerLoops.h \
- at ENABLE_TESTS_TRUE@	soundlib/MixerSettings.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/MixerSettings.h \
- at ENABLE_TESTS_TRUE@	soundlib/MixFuncTable.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/MixFuncTable.h soundlib/Mmcmp.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/ModChannel.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/ModChannel.h \
- at ENABLE_TESTS_TRUE@	soundlib/modcommand.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/modcommand.h \
- at ENABLE_TESTS_TRUE@	soundlib/ModInstrument.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/ModInstrument.h \
- at ENABLE_TESTS_TRUE@	soundlib/ModSample.cpp soundlib/ModSample.h \
- at ENABLE_TESTS_TRUE@	soundlib/ModSequence.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/ModSequence.h \
- at ENABLE_TESTS_TRUE@	soundlib/modsmp_ctrl.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/modsmp_ctrl.h \
- at ENABLE_TESTS_TRUE@	soundlib/mod_specifications.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/mod_specifications.h \
- at ENABLE_TESTS_TRUE@	soundlib/MPEGFrame.cpp soundlib/MPEGFrame.h \
- at ENABLE_TESTS_TRUE@	soundlib/OggStream.cpp soundlib/OggStream.h \
- at ENABLE_TESTS_TRUE@	soundlib/patternContainer.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/patternContainer.h \
- at ENABLE_TESTS_TRUE@	soundlib/pattern.cpp soundlib/pattern.h \
- at ENABLE_TESTS_TRUE@	soundlib/Resampler.h \
- at ENABLE_TESTS_TRUE@	soundlib/RowVisitor.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/RowVisitor.h soundlib/S3MTools.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/S3MTools.h \
- at ENABLE_TESTS_TRUE@	soundlib/SampleFormatConverters.h \
- at ENABLE_TESTS_TRUE@	soundlib/SampleFormat.h \
- at ENABLE_TESTS_TRUE@	soundlib/SampleFormats.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/SampleIO.cpp soundlib/SampleIO.h \
- at ENABLE_TESTS_TRUE@	soundlib/Snd_defs.h soundlib/Sndfile.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Sndfile.h soundlib/Snd_flt.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/Snd_fx.cpp soundlib/Sndmix.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/SoundFilePlayConfig.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/SoundFilePlayConfig.h \
- at ENABLE_TESTS_TRUE@	soundlib/Tables.cpp soundlib/Tables.h \
- at ENABLE_TESTS_TRUE@	soundlib/Tagging.cpp soundlib/Tagging.h \
- at ENABLE_TESTS_TRUE@	soundlib/tuningbase.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/tuningbase.h \
- at ENABLE_TESTS_TRUE@	soundlib/tuningCollection.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/tuningcollection.h \
- at ENABLE_TESTS_TRUE@	soundlib/tuning.cpp soundlib/tuning.h \
- at ENABLE_TESTS_TRUE@	soundlib/UpgradeModule.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/WAVTools.cpp soundlib/WAVTools.h \
- at ENABLE_TESTS_TRUE@	soundlib/WindowedFIR.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/WindowedFIR.h soundlib/XMTools.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/XMTools.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PlugInterface.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/DMOPlugin.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/DMOPlugin.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Compressor.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Compressor.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Distortion.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Distortion.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Echo.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Echo.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Echo.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Gargle.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/Gargle.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/ParamEq.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/ParamEq.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/WavesReverb.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/dmo/WavesReverb.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/DigiBoosterEcho.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/DigiBoosterEcho.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PluginManager.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PluginManager.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PluginMixBuffer.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PluginStructs.h \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PlugInterface.cpp \
- at ENABLE_TESTS_TRUE@	soundlib/plugins/PlugInterface.h \
+ at ENABLE_TESTS_TRUE@	$(MPT_FILES_COMMON) $(MPT_FILES_SOUNDBASE) \
+ at ENABLE_TESTS_TRUE@	$(MPT_FILES_SOUNDLIB) $(MPT_FILES_SOUNDDSP) \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_c.cpp \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_cxx.cpp \
- at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_ext.cpp \
+ at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_ext_impl.cpp \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_impl.cpp \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_config.h \
+ at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_ext.h \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_ext.hpp \
+ at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_ext_impl.hpp \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt.h \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt.hpp \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_impl.hpp \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_internal.h \
+ at ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_stream_callbacks_buffer.h \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_stream_callbacks_fd.h \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_stream_callbacks_file.h \
 @ENABLE_TESTS_TRUE@	libopenmpt/libopenmpt_version.h
- at ENABLE_OPENMPT123_TRUE@openmpt123_CPPFLAGS = -I$(srcdir)/src/openmpt123 $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SDL_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS)
- at ENABLE_OPENMPT123_TRUE@openmpt123_CXXFLAGS = $(WIN32_CONSOLE_CXXFLAGS)
- at ENABLE_OPENMPT123_TRUE@openmpt123_LDADD = libopenmpt.la $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SDL_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS) $(OPENMPT123_WIN32_LIBS)
- at ENABLE_OPENMPT123_TRUE@openmpt123_SOURCES =  \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_config.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123.cpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_flac.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_mmio.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_portaudio.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_pulseaudio.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_raw.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_sdl.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_sdl2.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_sndfile.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_stdout.hpp \
- at ENABLE_OPENMPT123_TRUE@	src/openmpt123/openmpt123_waveout.hpp
-#bin_PROGRAMS += openmpt123
-#openmpt123_CPPFLAGS = -I$(srcdir)/src/openmpt123 $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SDL_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS)
-#openmpt123_LDADD = $(lib_LTLIBRARIES) $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SDL_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS)
-#openmpt123_SOURCES = 
-#openmpt123_SOURCES += openmpt123/openmpt123_config.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123.cpp
-#openmpt123_SOURCES += openmpt123/openmpt123_flac.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_mmio.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_portaudio.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_pulseaudio.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_raw.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_sdl.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_sdl2.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_sndfile.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_stdout.hpp
-#openmpt123_SOURCES += openmpt123/openmpt123_waveout.hpp
+ at ENABLE_OPENMPT123_TRUE@bin_openmpt123_CPPFLAGS = -I$(srcdir)/src/openmpt123 $(PORTAUDIO_CFLAGS) $(PULSEAUDIO_CFLAGS) $(SDL2_CFLAGS) $(SDL_CFLAGS) $(SNDFILE_CFLAGS) $(FLAC_CFLAGS)
+ at ENABLE_OPENMPT123_TRUE@bin_openmpt123_CXXFLAGS = $(WIN32_CONSOLE_CXXFLAGS)
+ at ENABLE_OPENMPT123_TRUE@bin_openmpt123_LDADD = libopenmpt.la $(PORTAUDIO_LIBS) $(PULSEAUDIO_LIBS) $(SDL2_LIBS) $(SDL_LIBS) $(SNDFILE_LIBS) $(FLAC_LIBS) $(OPENMPT123_WIN32_LIBS)
+ at ENABLE_OPENMPT123_TRUE@bin_openmpt123_SOURCES =  \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_config.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123.cpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_flac.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_mmio.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_portaudio.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_pulseaudio.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_raw.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_sdl.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_sdl2.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_sndfile.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_stdout.hpp \
+ at ENABLE_OPENMPT123_TRUE@	openmpt123/openmpt123_waveout.hpp
 @ENABLE_OPENMPT123_TRUE at man1_MANS = man/openmpt123.1
- at DX_COND_doc_TRUE@@DX_COND_html_TRUE at DX_CLEAN_HTML = @DX_DOCDIR@/html
- at DX_COND_doc_TRUE@DX_CLEANFILES = @DX_DOCDIR@/@PACKAGE at .tag @DX_DOCDIR@/doxygen_sqlite3.db -r $(DX_CLEAN_HTML) 
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -1528,7 +1480,6 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -1656,6 +1607,8 @@ common/libopenmpt_la-mptTime.lo: common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 common/libopenmpt_la-mptUUID.lo: common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
+common/libopenmpt_la-mptWine.lo: common/$(am__dirstamp) \
+	common/$(DEPDIR)/$(am__dirstamp)
 common/libopenmpt_la-Profiler.lo: common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 common/libopenmpt_la-serialization_utils.lo: common/$(am__dirstamp) \
@@ -1674,6 +1627,14 @@ soundlib/$(DEPDIR)/$(am__dirstamp):
 	@: > soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-AudioCriticalSection.lo:  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-ContainerMMCMP.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-ContainerPP20.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-ContainerUMX.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-ContainerXPK.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Dither.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Dlsbank.lo: soundlib/$(am__dirstamp) \
@@ -1700,6 +1661,8 @@ soundlib/libopenmpt_la-Load_dmf.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Load_dsm.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-Load_dtm.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Load_far.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Load_gdm.lo: soundlib/$(am__dirstamp) \
@@ -1740,9 +1703,11 @@ soundlib/libopenmpt_la-Load_sfx.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Load_stm.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
-soundlib/libopenmpt_la-Load_ult.lo: soundlib/$(am__dirstamp) \
+soundlib/libopenmpt_la-Load_stp.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
-soundlib/libopenmpt_la-Load_umx.lo: soundlib/$(am__dirstamp) \
+soundlib/libopenmpt_la-Load_uax.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-Load_ult.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Load_wav.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
@@ -1760,8 +1725,6 @@ soundlib/libopenmpt_la-MixerSettings.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-MixFuncTable.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
-soundlib/libopenmpt_la-Mmcmp.lo: soundlib/$(am__dirstamp) \
-	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-ModChannel.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-modcommand.lo: soundlib/$(am__dirstamp) \
@@ -1780,6 +1743,8 @@ soundlib/libopenmpt_la-MPEGFrame.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-OggStream.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-Paula.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-patternContainer.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-pattern.lo: soundlib/$(am__dirstamp) \
@@ -1790,6 +1755,16 @@ soundlib/libopenmpt_la-S3MTools.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-SampleFormats.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-SampleFormatFLAC.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo:  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-SampleFormatMP3.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-SampleFormatOpus.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-SampleFormatVorbis.lo:  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-SampleIO.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-Sndfile.lo: soundlib/$(am__dirstamp) \
@@ -1812,6 +1787,8 @@ soundlib/libopenmpt_la-tuningCollection.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-tuning.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpt_la-UMXTools.lo: soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-UpgradeModule.lo: soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpt_la-WAVTools.lo: soundlib/$(am__dirstamp) \
@@ -1829,6 +1806,9 @@ soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp):
 soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo:  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/dmo/libopenmpt_la-Chorus.lo:  \
+	soundlib/plugins/dmo/$(am__dirstamp) \
+	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/dmo/libopenmpt_la-Compressor.lo:  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
@@ -1838,9 +1818,15 @@ soundlib/plugins/dmo/libopenmpt_la-Distortion.lo:  \
 soundlib/plugins/dmo/libopenmpt_la-Echo.lo:  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/dmo/libopenmpt_la-Flanger.lo:  \
+	soundlib/plugins/dmo/$(am__dirstamp) \
+	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/dmo/libopenmpt_la-Gargle.lo:  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo:  \
+	soundlib/plugins/dmo/$(am__dirstamp) \
+	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo:  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
@@ -1856,18 +1842,35 @@ soundlib/plugins/$(DEPDIR)/$(am__dirstamp):
 soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo:  \
 	soundlib/plugins/$(am__dirstamp) \
 	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/libopenmpt_la-LFOPlugin.lo:  \
+	soundlib/plugins/$(am__dirstamp) \
+	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/libopenmpt_la-PluginManager.lo:  \
 	soundlib/plugins/$(am__dirstamp) \
 	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/libopenmpt_la-PlugInterface.lo:  \
 	soundlib/plugins/$(am__dirstamp) \
 	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
+sounddsp/$(am__dirstamp):
+	@$(MKDIR_P) sounddsp
+	@: > sounddsp/$(am__dirstamp)
+sounddsp/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) sounddsp/$(DEPDIR)
+	@: > sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpt_la-AGC.lo: sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpt_la-DSP.lo: sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpt_la-EQ.lo: sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpt_la-Reverb.lo: sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
 libopenmpt/libopenmpt_la-libopenmpt_c.lo: libopenmpt/$(am__dirstamp) \
 	libopenmpt/$(DEPDIR)/$(am__dirstamp)
 libopenmpt/libopenmpt_la-libopenmpt_cxx.lo:  \
 	libopenmpt/$(am__dirstamp) \
 	libopenmpt/$(DEPDIR)/$(am__dirstamp)
-libopenmpt/libopenmpt_la-libopenmpt_ext.lo:  \
+libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo:  \
 	libopenmpt/$(am__dirstamp) \
 	libopenmpt/$(DEPDIR)/$(am__dirstamp)
 libopenmpt/libopenmpt_la-libopenmpt_impl.lo:  \
@@ -1943,6 +1946,22 @@ clean-checkPROGRAMS:
 	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
 	echo " rm -f" $$list; \
 	rm -f $$list
+openmpt123/$(am__dirstamp):
+	@$(MKDIR_P) openmpt123
+	@: > openmpt123/$(am__dirstamp)
+openmpt123/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) openmpt123/$(DEPDIR)
+	@: > openmpt123/$(DEPDIR)/$(am__dirstamp)
+openmpt123/bin_openmpt123-openmpt123.$(OBJEXT):  \
+	openmpt123/$(am__dirstamp) \
+	openmpt123/$(DEPDIR)/$(am__dirstamp)
+bin/$(am__dirstamp):
+	@$(MKDIR_P) bin
+	@: > bin/$(am__dirstamp)
+
+bin/openmpt123$(EXEEXT): $(bin_openmpt123_OBJECTS) $(bin_openmpt123_DEPENDENCIES) $(EXTRA_bin_openmpt123_DEPENDENCIES) bin/$(am__dirstamp)
+	@rm -f bin/openmpt123$(EXEEXT)
+	$(AM_V_CXXLD)$(bin_openmpt123_LINK) $(bin_openmpt123_OBJECTS) $(bin_openmpt123_LDADD) $(LIBS)
 examples/$(am__dirstamp):
 	@$(MKDIR_P) examples
 	@: > examples/$(am__dirstamp)
@@ -2030,6 +2049,8 @@ common/libopenmpttest-mptTime.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 common/libopenmpttest-mptUUID.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
+common/libopenmpttest-mptWine.$(OBJEXT): common/$(am__dirstamp) \
+	common/$(DEPDIR)/$(am__dirstamp)
 common/libopenmpttest-Profiler.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 common/libopenmpttest-serialization_utils.$(OBJEXT):  \
@@ -2042,6 +2063,14 @@ common/libopenmpttest-version.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-AudioCriticalSection.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-ContainerMMCMP.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-ContainerPP20.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-ContainerUMX.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-ContainerXPK.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Dither.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Dlsbank.$(OBJEXT): soundlib/$(am__dirstamp) \
@@ -2068,6 +2097,8 @@ soundlib/libopenmpttest-Load_dmf.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Load_dsm.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-Load_dtm.$(OBJEXT): soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Load_far.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Load_gdm.$(OBJEXT): soundlib/$(am__dirstamp) \
@@ -2108,9 +2139,11 @@ soundlib/libopenmpttest-Load_sfx.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Load_stm.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
-soundlib/libopenmpttest-Load_ult.$(OBJEXT): soundlib/$(am__dirstamp) \
+soundlib/libopenmpttest-Load_stp.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
-soundlib/libopenmpttest-Load_umx.$(OBJEXT): soundlib/$(am__dirstamp) \
+soundlib/libopenmpttest-Load_uax.$(OBJEXT): soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-Load_ult.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Load_wav.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
@@ -2128,8 +2161,6 @@ soundlib/libopenmpttest-MixerSettings.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-MixFuncTable.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
-soundlib/libopenmpttest-Mmcmp.$(OBJEXT): soundlib/$(am__dirstamp) \
-	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-ModChannel.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-modcommand.$(OBJEXT):  \
@@ -2148,6 +2179,8 @@ soundlib/libopenmpttest-MPEGFrame.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-OggStream.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-Paula.$(OBJEXT): soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-patternContainer.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-pattern.$(OBJEXT): soundlib/$(am__dirstamp) \
@@ -2158,6 +2191,16 @@ soundlib/libopenmpttest-S3MTools.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-SampleFormats.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-SampleFormatFLAC.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-SampleFormatMediaFoundation.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-SampleFormatMP3.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-SampleFormatOpus.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-SampleFormatVorbis.$(OBJEXT):  \
+	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-SampleIO.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-Sndfile.$(OBJEXT): soundlib/$(am__dirstamp) \
@@ -2180,6 +2223,8 @@ soundlib/libopenmpttest-tuningCollection.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-tuning.$(OBJEXT): soundlib/$(am__dirstamp) \
 	soundlib/$(DEPDIR)/$(am__dirstamp)
+soundlib/libopenmpttest-UMXTools.$(OBJEXT): soundlib/$(am__dirstamp) \
+	soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-UpgradeModule.$(OBJEXT):  \
 	soundlib/$(am__dirstamp) soundlib/$(DEPDIR)/$(am__dirstamp)
 soundlib/libopenmpttest-WAVTools.$(OBJEXT): soundlib/$(am__dirstamp) \
@@ -2191,6 +2236,9 @@ soundlib/libopenmpttest-XMTools.$(OBJEXT): soundlib/$(am__dirstamp) \
 soundlib/plugins/dmo/libopenmpttest-DMOPlugin.$(OBJEXT):  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/dmo/libopenmpttest-Chorus.$(OBJEXT):  \
+	soundlib/plugins/dmo/$(am__dirstamp) \
+	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/dmo/libopenmpttest-Compressor.$(OBJEXT):  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
@@ -2200,9 +2248,15 @@ soundlib/plugins/dmo/libopenmpttest-Distortion.$(OBJEXT):  \
 soundlib/plugins/dmo/libopenmpttest-Echo.$(OBJEXT):  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/dmo/libopenmpttest-Flanger.$(OBJEXT):  \
+	soundlib/plugins/dmo/$(am__dirstamp) \
+	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/dmo/libopenmpttest-Gargle.$(OBJEXT):  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.$(OBJEXT):  \
+	soundlib/plugins/dmo/$(am__dirstamp) \
+	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/dmo/libopenmpttest-ParamEq.$(OBJEXT):  \
 	soundlib/plugins/dmo/$(am__dirstamp) \
 	soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
@@ -2212,19 +2266,30 @@ soundlib/plugins/dmo/libopenmpttest-WavesReverb.$(OBJEXT):  \
 soundlib/plugins/libopenmpttest-DigiBoosterEcho.$(OBJEXT):  \
 	soundlib/plugins/$(am__dirstamp) \
 	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
+soundlib/plugins/libopenmpttest-LFOPlugin.$(OBJEXT):  \
+	soundlib/plugins/$(am__dirstamp) \
+	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/libopenmpttest-PluginManager.$(OBJEXT):  \
 	soundlib/plugins/$(am__dirstamp) \
 	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
 soundlib/plugins/libopenmpttest-PlugInterface.$(OBJEXT):  \
 	soundlib/plugins/$(am__dirstamp) \
 	soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpttest-AGC.$(OBJEXT): sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpttest-DSP.$(OBJEXT): sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpttest-EQ.$(OBJEXT): sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
+sounddsp/libopenmpttest-Reverb.$(OBJEXT): sounddsp/$(am__dirstamp) \
+	sounddsp/$(DEPDIR)/$(am__dirstamp)
 libopenmpt/libopenmpttest-libopenmpt_c.$(OBJEXT):  \
 	libopenmpt/$(am__dirstamp) \
 	libopenmpt/$(DEPDIR)/$(am__dirstamp)
 libopenmpt/libopenmpttest-libopenmpt_cxx.$(OBJEXT):  \
 	libopenmpt/$(am__dirstamp) \
 	libopenmpt/$(DEPDIR)/$(am__dirstamp)
-libopenmpt/libopenmpttest-libopenmpt_ext.$(OBJEXT):  \
+libopenmpt/libopenmpttest-libopenmpt_ext_impl.$(OBJEXT):  \
 	libopenmpt/$(am__dirstamp) \
 	libopenmpt/$(DEPDIR)/$(am__dirstamp)
 libopenmpt/libopenmpttest-libopenmpt_impl.$(OBJEXT):  \
@@ -2234,19 +2299,6 @@ libopenmpt/libopenmpttest-libopenmpt_impl.$(OBJEXT):  \
 libopenmpttest$(EXEEXT): $(libopenmpttest_OBJECTS) $(libopenmpttest_DEPENDENCIES) $(EXTRA_libopenmpttest_DEPENDENCIES) 
 	@rm -f libopenmpttest$(EXEEXT)
 	$(AM_V_CXXLD)$(libopenmpttest_LINK) $(libopenmpttest_OBJECTS) $(libopenmpttest_LDADD) $(LIBS)
-src/openmpt123/$(am__dirstamp):
-	@$(MKDIR_P) src/openmpt123
-	@: > src/openmpt123/$(am__dirstamp)
-src/openmpt123/$(DEPDIR)/$(am__dirstamp):
-	@$(MKDIR_P) src/openmpt123/$(DEPDIR)
-	@: > src/openmpt123/$(DEPDIR)/$(am__dirstamp)
-src/openmpt123/openmpt123-openmpt123.$(OBJEXT):  \
-	src/openmpt123/$(am__dirstamp) \
-	src/openmpt123/$(DEPDIR)/$(am__dirstamp)
-
-openmpt123$(EXEEXT): $(openmpt123_OBJECTS) $(openmpt123_DEPENDENCIES) $(EXTRA_openmpt123_DEPENDENCIES) 
-	@rm -f openmpt123$(EXEEXT)
-	$(AM_V_CXXLD)$(openmpt123_LINK) $(openmpt123_OBJECTS) $(openmpt123_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -2255,13 +2307,15 @@ mostlyclean-compile:
 	-rm -f examples/*.$(OBJEXT)
 	-rm -f libopenmpt/*.$(OBJEXT)
 	-rm -f libopenmpt/*.lo
+	-rm -f openmpt123/*.$(OBJEXT)
+	-rm -f sounddsp/*.$(OBJEXT)
+	-rm -f sounddsp/*.lo
 	-rm -f soundlib/*.$(OBJEXT)
 	-rm -f soundlib/*.lo
 	-rm -f soundlib/plugins/*.$(OBJEXT)
 	-rm -f soundlib/plugins/*.lo
 	-rm -f soundlib/plugins/dmo/*.$(OBJEXT)
 	-rm -f soundlib/plugins/dmo/*.lo
-	-rm -f src/openmpt123/*.$(OBJEXT)
 	-rm -f test/*.$(OBJEXT)
 
 distclean-compile:
@@ -2284,6 +2338,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-mptStringParse.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-mptTime.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-mptUUID.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-mptWine.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-serialization_utils.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-stdafx.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpt_la-typedefs.Plo at am__quote@
@@ -2305,6 +2360,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-mptStringParse.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-mptTime.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-mptUUID.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-mptWine.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-serialization_utils.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-stdafx.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/libopenmpttest-typedefs.Po at am__quote@
@@ -2319,16 +2375,29 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libmodplug_la-libopenmpt_modplug_cpp.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_c.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_cxx.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext_impl.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_impl.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_modplug_la-libopenmpt_modplug.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpt_modplug_la-libopenmpt_modplug_cpp.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_cxx.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_test.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-AudioCriticalSection.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Dither.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Dlsbank.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Fastmix.Plo at am__quote@
@@ -2342,6 +2411,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_digi.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_dmf.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_dsm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_gdm.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_imf.Plo at am__quote@
@@ -2361,8 +2431,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_s3m.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_sfx.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_stm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_umx.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Load_xm.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-MIDIEvents.Plo at am__quote@
@@ -2372,14 +2443,19 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-MixFuncTable.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-MixerLoops.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-MixerSettings.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Mmcmp.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ModInstrument.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ModSample.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-ModSequence.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-OggStream.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-RowVisitor.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-S3MTools.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleFormats.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Snd_flt.Plo at am__quote@
@@ -2389,6 +2465,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-SoundFilePlayConfig.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Tables.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-Tagging.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-WAVTools.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-WindowedFIR.Plo at am__quote@
@@ -2403,6 +2480,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-tuningCollection.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpt_la-tuningbase.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-AudioCriticalSection.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Dither.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Dlsbank.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Fastmix.Po at am__quote@
@@ -2416,6 +2497,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_digi.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_dmf.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_dsm.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_gdm.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_imf.Po at am__quote@
@@ -2435,8 +2517,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_s3m.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_sfx.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_stm.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Load_xm.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-MIDIEvents.Po at am__quote@
@@ -2446,14 +2529,19 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-MixFuncTable.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-MixerLoops.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-MixerSettings.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ModInstrument.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ModSample.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-ModSequence.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-OggStream.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Paula.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-RowVisitor.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-S3MTools.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleFormats.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Snd_flt.Po at am__quote@
@@ -2463,6 +2551,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-SoundFilePlayConfig.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Tables.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-Tagging.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-WAVTools.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-WindowedFIR.Po at am__quote@
@@ -2477,26 +2566,33 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-tuningCollection.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/$(DEPDIR)/libopenmpttest-tuningbase.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpt_la-DigiBoosterEcho.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpt_la-PlugInterface.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpttest-DigiBoosterEcho.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpttest-PlugInterface.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-DMOPlugin.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Distortion.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Echo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-WavesReverb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-DMOPlugin.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Distortion.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Echo.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-WavesReverb.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/libopenmpttest-TestToolsLib.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/libopenmpttest-test.Po at am__quote@
 
@@ -2751,6 +2847,13 @@ common/libopenmpt_la-mptUUID.lo: common/mptUUID.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptUUID.lo `test -f 'common/mptUUID.cpp' || echo '$(srcdir)/'`common/mptUUID.cpp
 
+common/libopenmpt_la-mptWine.lo: common/mptWine.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-mptWine.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-mptWine.Tpo -c -o common/libopenmpt_la-mptWine.lo `test -f 'common/mptWine.cpp' || echo '$(srcdir)/'`common/mptWine.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-mptWine.Tpo common/$(DEPDIR)/libopenmpt_la-mptWine.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='common/mptWine.cpp' object='common/libopenmpt_la-mptWine.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpt_la-mptWine.lo `test -f 'common/mptWine.cpp' || echo '$(srcdir)/'`common/mptWine.cpp
+
 common/libopenmpt_la-Profiler.lo: common/Profiler.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpt_la-Profiler.lo -MD -MP -MF common/$(DEPDIR)/libopenmpt_la-Profiler.Tpo -c -o common/libopenmpt_la-Profiler.lo `test -f 'common/Profiler.cpp' || echo '$(srcdir)/'`common/Profiler.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpt_la-Profiler.Tpo common/$(DEPDIR)/libopenmpt_la-Profiler.Plo
@@ -2793,6 +2896,34 @@ soundlib/libopenmpt_la-AudioCriticalSection.lo: soundlib/AudioCriticalSection.cp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-AudioCriticalSection.lo `test -f 'soundlib/AudioCriticalSection.cpp' || echo '$(srcdir)/'`soundlib/AudioCriticalSection.cpp
 
+soundlib/libopenmpt_la-ContainerMMCMP.lo: soundlib/ContainerMMCMP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerMMCMP.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Tpo -c -o soundlib/libopenmpt_la-ContainerMMCMP.lo `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerMMCMP.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerMMCMP.cpp' object='soundlib/libopenmpt_la-ContainerMMCMP.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerMMCMP.lo `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp
+
+soundlib/libopenmpt_la-ContainerPP20.lo: soundlib/ContainerPP20.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerPP20.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Tpo -c -o soundlib/libopenmpt_la-ContainerPP20.lo `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerPP20.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerPP20.cpp' object='soundlib/libopenmpt_la-ContainerPP20.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerPP20.lo `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp
+
+soundlib/libopenmpt_la-ContainerUMX.lo: soundlib/ContainerUMX.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerUMX.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Tpo -c -o soundlib/libopenmpt_la-ContainerUMX.lo `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerUMX.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerUMX.cpp' object='soundlib/libopenmpt_la-ContainerUMX.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerUMX.lo `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp
+
+soundlib/libopenmpt_la-ContainerXPK.lo: soundlib/ContainerXPK.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ContainerXPK.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Tpo -c -o soundlib/libopenmpt_la-ContainerXPK.lo `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ContainerXPK.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerXPK.cpp' object='soundlib/libopenmpt_la-ContainerXPK.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-ContainerXPK.lo `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp
+
 soundlib/libopenmpt_la-Dither.lo: soundlib/Dither.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Dither.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Dither.Tpo -c -o soundlib/libopenmpt_la-Dither.lo `test -f 'soundlib/Dither.cpp' || echo '$(srcdir)/'`soundlib/Dither.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Dither.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Dither.Plo
@@ -2884,6 +3015,13 @@ soundlib/libopenmpt_la-Load_dsm.lo: soundlib/Load_dsm.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dsm.lo `test -f 'soundlib/Load_dsm.cpp' || echo '$(srcdir)/'`soundlib/Load_dsm.cpp
 
+soundlib/libopenmpt_la-Load_dtm.lo: soundlib/Load_dtm.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_dtm.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Tpo -c -o soundlib/libopenmpt_la-Load_dtm.lo `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_dtm.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_dtm.cpp' object='soundlib/libopenmpt_la-Load_dtm.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_dtm.lo `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp
+
 soundlib/libopenmpt_la-Load_far.lo: soundlib/Load_far.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_far.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Tpo -c -o soundlib/libopenmpt_la-Load_far.lo `test -f 'soundlib/Load_far.cpp' || echo '$(srcdir)/'`soundlib/Load_far.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_far.Plo
@@ -3024,6 +3162,20 @@ soundlib/libopenmpt_la-Load_stm.lo: soundlib/Load_stm.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_stm.lo `test -f 'soundlib/Load_stm.cpp' || echo '$(srcdir)/'`soundlib/Load_stm.cpp
 
+soundlib/libopenmpt_la-Load_stp.lo: soundlib/Load_stp.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_stp.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Tpo -c -o soundlib/libopenmpt_la-Load_stp.lo `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_stp.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_stp.cpp' object='soundlib/libopenmpt_la-Load_stp.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_stp.lo `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp
+
+soundlib/libopenmpt_la-Load_uax.lo: soundlib/Load_uax.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_uax.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Tpo -c -o soundlib/libopenmpt_la-Load_uax.lo `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_uax.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_uax.cpp' object='soundlib/libopenmpt_la-Load_uax.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_uax.lo `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp
+
 soundlib/libopenmpt_la-Load_ult.lo: soundlib/Load_ult.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_ult.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Tpo -c -o soundlib/libopenmpt_la-Load_ult.lo `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_ult.Plo
@@ -3031,13 +3183,6 @@ soundlib/libopenmpt_la-Load_ult.lo: soundlib/Load_ult.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_ult.lo `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp
 
-soundlib/libopenmpt_la-Load_umx.lo: soundlib/Load_umx.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_umx.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_umx.Tpo -c -o soundlib/libopenmpt_la-Load_umx.lo `test -f 'soundlib/Load_umx.cpp' || echo '$(srcdir)/'`soundlib/Load_umx.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_umx.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_umx.Plo
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_umx.cpp' object='soundlib/libopenmpt_la-Load_umx.lo' libtool=yes @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Load_umx.lo `test -f 'soundlib/Load_umx.cpp' || echo '$(srcdir)/'`soundlib/Load_umx.cpp
-
 soundlib/libopenmpt_la-Load_wav.lo: soundlib/Load_wav.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Load_wav.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Tpo -c -o soundlib/libopenmpt_la-Load_wav.lo `test -f 'soundlib/Load_wav.cpp' || echo '$(srcdir)/'`soundlib/Load_wav.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Load_wav.Plo
@@ -3094,13 +3239,6 @@ soundlib/libopenmpt_la-MixFuncTable.lo: soundlib/MixFuncTable.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-MixFuncTable.lo `test -f 'soundlib/MixFuncTable.cpp' || echo '$(srcdir)/'`soundlib/MixFuncTable.cpp
 
-soundlib/libopenmpt_la-Mmcmp.lo: soundlib/Mmcmp.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Mmcmp.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Mmcmp.Tpo -c -o soundlib/libopenmpt_la-Mmcmp.lo `test -f 'soundlib/Mmcmp.cpp' || echo '$(srcdir)/'`soundlib/Mmcmp.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Mmcmp.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Mmcmp.Plo
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Mmcmp.cpp' object='soundlib/libopenmpt_la-Mmcmp.lo' libtool=yes @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Mmcmp.lo `test -f 'soundlib/Mmcmp.cpp' || echo '$(srcdir)/'`soundlib/Mmcmp.cpp
-
 soundlib/libopenmpt_la-ModChannel.lo: soundlib/ModChannel.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-ModChannel.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Tpo -c -o soundlib/libopenmpt_la-ModChannel.lo `test -f 'soundlib/ModChannel.cpp' || echo '$(srcdir)/'`soundlib/ModChannel.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Tpo soundlib/$(DEPDIR)/libopenmpt_la-ModChannel.Plo
@@ -3164,6 +3302,13 @@ soundlib/libopenmpt_la-OggStream.lo: soundlib/OggStream.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-OggStream.lo `test -f 'soundlib/OggStream.cpp' || echo '$(srcdir)/'`soundlib/OggStream.cpp
 
+soundlib/libopenmpt_la-Paula.lo: soundlib/Paula.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-Paula.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-Paula.Tpo -c -o soundlib/libopenmpt_la-Paula.lo `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-Paula.Tpo soundlib/$(DEPDIR)/libopenmpt_la-Paula.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Paula.cpp' object='soundlib/libopenmpt_la-Paula.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-Paula.lo `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp
+
 soundlib/libopenmpt_la-patternContainer.lo: soundlib/patternContainer.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-patternContainer.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Tpo -c -o soundlib/libopenmpt_la-patternContainer.lo `test -f 'soundlib/patternContainer.cpp' || echo '$(srcdir)/'`soundlib/patternContainer.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Tpo soundlib/$(DEPDIR)/libopenmpt_la-patternContainer.Plo
@@ -3199,6 +3344,41 @@ soundlib/libopenmpt_la-SampleFormats.lo: soundlib/SampleFormats.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormats.lo `test -f 'soundlib/SampleFormats.cpp' || echo '$(srcdir)/'`soundlib/SampleFormats.cpp
 
+soundlib/libopenmpt_la-SampleFormatFLAC.lo: soundlib/SampleFormatFLAC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatFLAC.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Tpo -c -o soundlib/libopenmpt_la-SampleFormatFLAC.lo `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatFLAC.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatFLAC.cpp' object='soundlib/libopenmpt_la-SampleFormatFLAC.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatFLAC.lo `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp
+
+soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo: soundlib/SampleFormatMediaFoundation.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Tpo -c -o soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMediaFoundation.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatMediaFoundation.cpp' object='soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatMediaFoundation.lo `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp
+
+soundlib/libopenmpt_la-SampleFormatMP3.lo: soundlib/SampleFormatMP3.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatMP3.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Tpo -c -o soundlib/libopenmpt_la-SampleFormatMP3.lo `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatMP3.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatMP3.cpp' object='soundlib/libopenmpt_la-SampleFormatMP3.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatMP3.lo `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp
+
+soundlib/libopenmpt_la-SampleFormatOpus.lo: soundlib/SampleFormatOpus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatOpus.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Tpo -c -o soundlib/libopenmpt_la-SampleFormatOpus.lo `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatOpus.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatOpus.cpp' object='soundlib/libopenmpt_la-SampleFormatOpus.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatOpus.lo `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp
+
+soundlib/libopenmpt_la-SampleFormatVorbis.lo: soundlib/SampleFormatVorbis.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleFormatVorbis.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Tpo -c -o soundlib/libopenmpt_la-SampleFormatVorbis.lo `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleFormatVorbis.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatVorbis.cpp' object='soundlib/libopenmpt_la-SampleFormatVorbis.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-SampleFormatVorbis.lo `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp
+
 soundlib/libopenmpt_la-SampleIO.lo: soundlib/SampleIO.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-SampleIO.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Tpo -c -o soundlib/libopenmpt_la-SampleIO.lo `test -f 'soundlib/SampleIO.cpp' || echo '$(srcdir)/'`soundlib/SampleIO.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Tpo soundlib/$(DEPDIR)/libopenmpt_la-SampleIO.Plo
@@ -3276,6 +3456,13 @@ soundlib/libopenmpt_la-tuning.lo: soundlib/tuning.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-tuning.lo `test -f 'soundlib/tuning.cpp' || echo '$(srcdir)/'`soundlib/tuning.cpp
 
+soundlib/libopenmpt_la-UMXTools.lo: soundlib/UMXTools.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-UMXTools.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Tpo -c -o soundlib/libopenmpt_la-UMXTools.lo `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Tpo soundlib/$(DEPDIR)/libopenmpt_la-UMXTools.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/UMXTools.cpp' object='soundlib/libopenmpt_la-UMXTools.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpt_la-UMXTools.lo `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp
+
 soundlib/libopenmpt_la-UpgradeModule.lo: soundlib/UpgradeModule.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpt_la-UpgradeModule.lo -MD -MP -MF soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Tpo -c -o soundlib/libopenmpt_la-UpgradeModule.lo `test -f 'soundlib/UpgradeModule.cpp' || echo '$(srcdir)/'`soundlib/UpgradeModule.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Tpo soundlib/$(DEPDIR)/libopenmpt_la-UpgradeModule.Plo
@@ -3311,6 +3498,13 @@ soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo: soundlib/plugins/dmo/DMOPlugin.
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-DMOPlugin.lo `test -f 'soundlib/plugins/dmo/DMOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/DMOPlugin.cpp
 
+soundlib/plugins/dmo/libopenmpt_la-Chorus.lo: soundlib/plugins/dmo/Chorus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Chorus.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Chorus.lo `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Chorus.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/Chorus.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Chorus.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Chorus.lo `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp
+
 soundlib/plugins/dmo/libopenmpt_la-Compressor.lo: soundlib/plugins/dmo/Compressor.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Compressor.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Compressor.lo `test -f 'soundlib/plugins/dmo/Compressor.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Compressor.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Compressor.Plo
@@ -3332,6 +3526,13 @@ soundlib/plugins/dmo/libopenmpt_la-Echo.lo: soundlib/plugins/dmo/Echo.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Echo.lo `test -f 'soundlib/plugins/dmo/Echo.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Echo.cpp
 
+soundlib/plugins/dmo/libopenmpt_la-Flanger.lo: soundlib/plugins/dmo/Flanger.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Flanger.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Flanger.lo `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Flanger.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/Flanger.cpp' object='soundlib/plugins/dmo/libopenmpt_la-Flanger.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Flanger.lo `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp
+
 soundlib/plugins/dmo/libopenmpt_la-Gargle.lo: soundlib/plugins/dmo/Gargle.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-Gargle.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-Gargle.lo `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-Gargle.Plo
@@ -3339,6 +3540,13 @@ soundlib/plugins/dmo/libopenmpt_la-Gargle.lo: soundlib/plugins/dmo/Gargle.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-Gargle.lo `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp
 
+soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo: soundlib/plugins/dmo/I3DL2Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-I3DL2Reverb.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/I3DL2Reverb.cpp' object='soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpt_la-I3DL2Reverb.lo `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp
+
 soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo: soundlib/plugins/dmo/ParamEq.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Tpo -c -o soundlib/plugins/dmo/libopenmpt_la-ParamEq.lo `test -f 'soundlib/plugins/dmo/ParamEq.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/ParamEq.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpt_la-ParamEq.Plo
@@ -3360,6 +3568,13 @@ soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo: soundlib/plugins/DigiBoosterE
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-DigiBoosterEcho.lo `test -f 'soundlib/plugins/DigiBoosterEcho.cpp' || echo '$(srcdir)/'`soundlib/plugins/DigiBoosterEcho.cpp
 
+soundlib/plugins/libopenmpt_la-LFOPlugin.lo: soundlib/plugins/LFOPlugin.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-LFOPlugin.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Tpo -c -o soundlib/plugins/libopenmpt_la-LFOPlugin.lo `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-LFOPlugin.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/LFOPlugin.cpp' object='soundlib/plugins/libopenmpt_la-LFOPlugin.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-LFOPlugin.lo `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp
+
 soundlib/plugins/libopenmpt_la-PluginManager.lo: soundlib/plugins/PluginManager.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpt_la-PluginManager.lo -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Tpo -c -o soundlib/plugins/libopenmpt_la-PluginManager.lo `test -f 'soundlib/plugins/PluginManager.cpp' || echo '$(srcdir)/'`soundlib/plugins/PluginManager.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Tpo soundlib/plugins/$(DEPDIR)/libopenmpt_la-PluginManager.Plo
@@ -3374,6 +3589,34 @@ soundlib/plugins/libopenmpt_la-PlugInterface.lo: soundlib/plugins/PlugInterface.
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpt_la-PlugInterface.lo `test -f 'soundlib/plugins/PlugInterface.cpp' || echo '$(srcdir)/'`soundlib/plugins/PlugInterface.cpp
 
+sounddsp/libopenmpt_la-AGC.lo: sounddsp/AGC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-AGC.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Tpo -c -o sounddsp/libopenmpt_la-AGC.lo `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-AGC.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/AGC.cpp' object='sounddsp/libopenmpt_la-AGC.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-AGC.lo `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp
+
+sounddsp/libopenmpt_la-DSP.lo: sounddsp/DSP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-DSP.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Tpo -c -o sounddsp/libopenmpt_la-DSP.lo `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-DSP.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/DSP.cpp' object='sounddsp/libopenmpt_la-DSP.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-DSP.lo `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp
+
+sounddsp/libopenmpt_la-EQ.lo: sounddsp/EQ.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-EQ.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Tpo -c -o sounddsp/libopenmpt_la-EQ.lo `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-EQ.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/EQ.cpp' object='sounddsp/libopenmpt_la-EQ.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-EQ.lo `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp
+
+sounddsp/libopenmpt_la-Reverb.lo: sounddsp/Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpt_la-Reverb.lo -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Tpo -c -o sounddsp/libopenmpt_la-Reverb.lo `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Tpo sounddsp/$(DEPDIR)/libopenmpt_la-Reverb.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/Reverb.cpp' object='sounddsp/libopenmpt_la-Reverb.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpt_la-Reverb.lo `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp
+
 libopenmpt/libopenmpt_la-libopenmpt_c.lo: libopenmpt/libopenmpt_c.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpt_la-libopenmpt_c.lo -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_c.Tpo -c -o libopenmpt/libopenmpt_la-libopenmpt_c.lo `test -f 'libopenmpt/libopenmpt_c.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_c.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_c.Tpo libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_c.Plo
@@ -3388,12 +3631,12 @@ libopenmpt/libopenmpt_la-libopenmpt_cxx.lo: libopenmpt/libopenmpt_cxx.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpt_la-libopenmpt_cxx.lo `test -f 'libopenmpt/libopenmpt_cxx.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_cxx.cpp
 
-libopenmpt/libopenmpt_la-libopenmpt_ext.lo: libopenmpt/libopenmpt_ext.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpt_la-libopenmpt_ext.lo -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext.Tpo -c -o libopenmpt/libopenmpt_la-libopenmpt_ext.lo `test -f 'libopenmpt/libopenmpt_ext.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext.Tpo libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext.Plo
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='libopenmpt/libopenmpt_ext.cpp' object='libopenmpt/libopenmpt_la-libopenmpt_ext.lo' libtool=yes @AMDEPBACKSLASH@
+libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo: libopenmpt/libopenmpt_ext_impl.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext_impl.Tpo -c -o libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_ext_impl.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='libopenmpt/libopenmpt_ext_impl.cpp' object='libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpt_la-libopenmpt_ext.lo `test -f 'libopenmpt/libopenmpt_ext.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext.cpp
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpt_la-libopenmpt_ext_impl.lo `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp
 
 libopenmpt/libopenmpt_la-libopenmpt_impl.lo: libopenmpt/libopenmpt_impl.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_la_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpt_la-libopenmpt_impl.lo -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpt_la-libopenmpt_impl.Tpo -c -o libopenmpt/libopenmpt_la-libopenmpt_impl.lo `test -f 'libopenmpt/libopenmpt_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_impl.cpp
@@ -3409,6 +3652,20 @@ libopenmpt/libopenmpt_modplug_la-libopenmpt_modplug_cpp.lo: libopenmpt/libopenmp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_modplug_la_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_modplug_la_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpt_modplug_la-libopenmpt_modplug_cpp.lo `test -f 'libopenmpt/libopenmpt_modplug_cpp.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_modplug_cpp.cpp
 
+openmpt123/bin_openmpt123-openmpt123.o: openmpt123/openmpt123.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -MT openmpt123/bin_openmpt123-openmpt123.o -MD -MP -MF openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo -c -o openmpt123/bin_openmpt123-openmpt123.o `test -f 'openmpt123/openmpt123.cpp' || echo '$(srcdir)/'`openmpt123/openmpt123.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='openmpt123/openmpt123.cpp' object='openmpt123/bin_openmpt123-openmpt123.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -c -o openmpt123/bin_openmpt123-openmpt123.o `test -f 'openmpt123/openmpt123.cpp' || echo '$(srcdir)/'`openmpt123/openmpt123.cpp
+
+openmpt123/bin_openmpt123-openmpt123.obj: openmpt123/openmpt123.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -MT openmpt123/bin_openmpt123-openmpt123.obj -MD -MP -MF openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo -c -o openmpt123/bin_openmpt123-openmpt123.obj `if test -f 'openmpt123/openmpt123.cpp'; then $(CYGPATH_W) 'openmpt123/openmpt123.cpp'; else $(CYGPATH_W) '$(srcdir)/openmpt123/openmpt123.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Tpo openmpt123/$(DEPDIR)/bin_openmpt123-openmpt123.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='openmpt123/openmpt123.cpp' object='openmpt123/bin_openmpt123-openmpt123.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bin_openmpt123_CPPFLAGS) $(CPPFLAGS) $(bin_openmpt123_CXXFLAGS) $(CXXFLAGS) -c -o openmpt123/bin_openmpt123-openmpt123.obj `if test -f 'openmpt123/openmpt123.cpp'; then $(CYGPATH_W) 'openmpt123/openmpt123.cpp'; else $(CYGPATH_W) '$(srcdir)/openmpt123/openmpt123.cpp'; fi`
+
 examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o: examples/libopenmpt_example_cxx.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpt_example_cxx_CPPFLAGS) $(CPPFLAGS) $(libopenmpt_example_cxx_CXXFLAGS) $(CXXFLAGS) -MT examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o -MD -MP -MF examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Tpo -c -o examples/libopenmpt_example_cxx-libopenmpt_example_cxx.o `test -f 'examples/libopenmpt_example_cxx.cpp' || echo '$(srcdir)/'`examples/libopenmpt_example_cxx.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Tpo examples/$(DEPDIR)/libopenmpt_example_cxx-libopenmpt_example_cxx.Po
@@ -3689,6 +3946,20 @@ common/libopenmpttest-mptUUID.obj: common/mptUUID.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptUUID.obj `if test -f 'common/mptUUID.cpp'; then $(CYGPATH_W) 'common/mptUUID.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptUUID.cpp'; fi`
 
+common/libopenmpttest-mptWine.o: common/mptWine.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptWine.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptWine.Tpo -c -o common/libopenmpttest-mptWine.o `test -f 'common/mptWine.cpp' || echo '$(srcdir)/'`common/mptWine.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptWine.Tpo common/$(DEPDIR)/libopenmpttest-mptWine.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='common/mptWine.cpp' object='common/libopenmpttest-mptWine.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptWine.o `test -f 'common/mptWine.cpp' || echo '$(srcdir)/'`common/mptWine.cpp
+
+common/libopenmpttest-mptWine.obj: common/mptWine.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-mptWine.obj -MD -MP -MF common/$(DEPDIR)/libopenmpttest-mptWine.Tpo -c -o common/libopenmpttest-mptWine.obj `if test -f 'common/mptWine.cpp'; then $(CYGPATH_W) 'common/mptWine.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptWine.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-mptWine.Tpo common/$(DEPDIR)/libopenmpttest-mptWine.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='common/mptWine.cpp' object='common/libopenmpttest-mptWine.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o common/libopenmpttest-mptWine.obj `if test -f 'common/mptWine.cpp'; then $(CYGPATH_W) 'common/mptWine.cpp'; else $(CYGPATH_W) '$(srcdir)/common/mptWine.cpp'; fi`
+
 common/libopenmpttest-Profiler.o: common/Profiler.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT common/libopenmpttest-Profiler.o -MD -MP -MF common/$(DEPDIR)/libopenmpttest-Profiler.Tpo -c -o common/libopenmpttest-Profiler.o `test -f 'common/Profiler.cpp' || echo '$(srcdir)/'`common/Profiler.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/libopenmpttest-Profiler.Tpo common/$(DEPDIR)/libopenmpttest-Profiler.Po
@@ -3773,6 +4044,62 @@ soundlib/libopenmpttest-AudioCriticalSection.obj: soundlib/AudioCriticalSection.
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-AudioCriticalSection.obj `if test -f 'soundlib/AudioCriticalSection.cpp'; then $(CYGPATH_W) 'soundlib/AudioCriticalSection.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/AudioCriticalSection.cpp'; fi`
 
+soundlib/libopenmpttest-ContainerMMCMP.o: soundlib/ContainerMMCMP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerMMCMP.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo -c -o soundlib/libopenmpttest-ContainerMMCMP.o `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerMMCMP.cpp' object='soundlib/libopenmpttest-ContainerMMCMP.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerMMCMP.o `test -f 'soundlib/ContainerMMCMP.cpp' || echo '$(srcdir)/'`soundlib/ContainerMMCMP.cpp
+
+soundlib/libopenmpttest-ContainerMMCMP.obj: soundlib/ContainerMMCMP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerMMCMP.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo -c -o soundlib/libopenmpttest-ContainerMMCMP.obj `if test -f 'soundlib/ContainerMMCMP.cpp'; then $(CYGPATH_W) 'soundlib/ContainerMMCMP.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerMMCMP.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerMMCMP.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerMMCMP.cpp' object='soundlib/libopenmpttest-ContainerMMCMP.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerMMCMP.obj `if test -f 'soundlib/ContainerMMCMP.cpp'; then $(CYGPATH_W) 'soundlib/ContainerMMCMP.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerMMCMP.cpp'; fi`
+
+soundlib/libopenmpttest-ContainerPP20.o: soundlib/ContainerPP20.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerPP20.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo -c -o soundlib/libopenmpttest-ContainerPP20.o `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerPP20.cpp' object='soundlib/libopenmpttest-ContainerPP20.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerPP20.o `test -f 'soundlib/ContainerPP20.cpp' || echo '$(srcdir)/'`soundlib/ContainerPP20.cpp
+
+soundlib/libopenmpttest-ContainerPP20.obj: soundlib/ContainerPP20.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerPP20.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo -c -o soundlib/libopenmpttest-ContainerPP20.obj `if test -f 'soundlib/ContainerPP20.cpp'; then $(CYGPATH_W) 'soundlib/ContainerPP20.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerPP20.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerPP20.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerPP20.cpp' object='soundlib/libopenmpttest-ContainerPP20.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerPP20.obj `if test -f 'soundlib/ContainerPP20.cpp'; then $(CYGPATH_W) 'soundlib/ContainerPP20.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerPP20.cpp'; fi`
+
+soundlib/libopenmpttest-ContainerUMX.o: soundlib/ContainerUMX.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerUMX.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo -c -o soundlib/libopenmpttest-ContainerUMX.o `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerUMX.cpp' object='soundlib/libopenmpttest-ContainerUMX.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerUMX.o `test -f 'soundlib/ContainerUMX.cpp' || echo '$(srcdir)/'`soundlib/ContainerUMX.cpp
+
+soundlib/libopenmpttest-ContainerUMX.obj: soundlib/ContainerUMX.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerUMX.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo -c -o soundlib/libopenmpttest-ContainerUMX.obj `if test -f 'soundlib/ContainerUMX.cpp'; then $(CYGPATH_W) 'soundlib/ContainerUMX.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerUMX.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerUMX.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerUMX.cpp' object='soundlib/libopenmpttest-ContainerUMX.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerUMX.obj `if test -f 'soundlib/ContainerUMX.cpp'; then $(CYGPATH_W) 'soundlib/ContainerUMX.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerUMX.cpp'; fi`
+
+soundlib/libopenmpttest-ContainerXPK.o: soundlib/ContainerXPK.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerXPK.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo -c -o soundlib/libopenmpttest-ContainerXPK.o `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerXPK.cpp' object='soundlib/libopenmpttest-ContainerXPK.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerXPK.o `test -f 'soundlib/ContainerXPK.cpp' || echo '$(srcdir)/'`soundlib/ContainerXPK.cpp
+
+soundlib/libopenmpttest-ContainerXPK.obj: soundlib/ContainerXPK.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ContainerXPK.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo -c -o soundlib/libopenmpttest-ContainerXPK.obj `if test -f 'soundlib/ContainerXPK.cpp'; then $(CYGPATH_W) 'soundlib/ContainerXPK.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerXPK.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Tpo soundlib/$(DEPDIR)/libopenmpttest-ContainerXPK.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/ContainerXPK.cpp' object='soundlib/libopenmpttest-ContainerXPK.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-ContainerXPK.obj `if test -f 'soundlib/ContainerXPK.cpp'; then $(CYGPATH_W) 'soundlib/ContainerXPK.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/ContainerXPK.cpp'; fi`
+
 soundlib/libopenmpttest-Dither.o: soundlib/Dither.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Dither.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Dither.Tpo -c -o soundlib/libopenmpttest-Dither.o `test -f 'soundlib/Dither.cpp' || echo '$(srcdir)/'`soundlib/Dither.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Dither.Tpo soundlib/$(DEPDIR)/libopenmpttest-Dither.Po
@@ -3955,6 +4282,20 @@ soundlib/libopenmpttest-Load_dsm.obj: soundlib/Load_dsm.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dsm.obj `if test -f 'soundlib/Load_dsm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dsm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dsm.cpp'; fi`
 
+soundlib/libopenmpttest-Load_dtm.o: soundlib/Load_dtm.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dtm.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo -c -o soundlib/libopenmpttest-Load_dtm.o `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_dtm.cpp' object='soundlib/libopenmpttest-Load_dtm.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dtm.o `test -f 'soundlib/Load_dtm.cpp' || echo '$(srcdir)/'`soundlib/Load_dtm.cpp
+
+soundlib/libopenmpttest-Load_dtm.obj: soundlib/Load_dtm.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_dtm.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo -c -o soundlib/libopenmpttest-Load_dtm.obj `if test -f 'soundlib/Load_dtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dtm.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_dtm.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_dtm.cpp' object='soundlib/libopenmpttest-Load_dtm.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_dtm.obj `if test -f 'soundlib/Load_dtm.cpp'; then $(CYGPATH_W) 'soundlib/Load_dtm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_dtm.cpp'; fi`
+
 soundlib/libopenmpttest-Load_far.o: soundlib/Load_far.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_far.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_far.Tpo -c -o soundlib/libopenmpttest-Load_far.o `test -f 'soundlib/Load_far.cpp' || echo '$(srcdir)/'`soundlib/Load_far.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_far.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_far.Po
@@ -4235,6 +4576,34 @@ soundlib/libopenmpttest-Load_stm.obj: soundlib/Load_stm.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stm.obj `if test -f 'soundlib/Load_stm.cpp'; then $(CYGPATH_W) 'soundlib/Load_stm.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stm.cpp'; fi`
 
+soundlib/libopenmpttest-Load_stp.o: soundlib/Load_stp.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stp.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo -c -o soundlib/libopenmpttest-Load_stp.o `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_stp.cpp' object='soundlib/libopenmpttest-Load_stp.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stp.o `test -f 'soundlib/Load_stp.cpp' || echo '$(srcdir)/'`soundlib/Load_stp.cpp
+
+soundlib/libopenmpttest-Load_stp.obj: soundlib/Load_stp.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_stp.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo -c -o soundlib/libopenmpttest-Load_stp.obj `if test -f 'soundlib/Load_stp.cpp'; then $(CYGPATH_W) 'soundlib/Load_stp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stp.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_stp.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_stp.cpp' object='soundlib/libopenmpttest-Load_stp.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_stp.obj `if test -f 'soundlib/Load_stp.cpp'; then $(CYGPATH_W) 'soundlib/Load_stp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_stp.cpp'; fi`
+
+soundlib/libopenmpttest-Load_uax.o: soundlib/Load_uax.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_uax.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo -c -o soundlib/libopenmpttest-Load_uax.o `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_uax.cpp' object='soundlib/libopenmpttest-Load_uax.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_uax.o `test -f 'soundlib/Load_uax.cpp' || echo '$(srcdir)/'`soundlib/Load_uax.cpp
+
+soundlib/libopenmpttest-Load_uax.obj: soundlib/Load_uax.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_uax.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo -c -o soundlib/libopenmpttest-Load_uax.obj `if test -f 'soundlib/Load_uax.cpp'; then $(CYGPATH_W) 'soundlib/Load_uax.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_uax.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_uax.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_uax.cpp' object='soundlib/libopenmpttest-Load_uax.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_uax.obj `if test -f 'soundlib/Load_uax.cpp'; then $(CYGPATH_W) 'soundlib/Load_uax.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_uax.cpp'; fi`
+
 soundlib/libopenmpttest-Load_ult.o: soundlib/Load_ult.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_ult.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Tpo -c -o soundlib/libopenmpttest-Load_ult.o `test -f 'soundlib/Load_ult.cpp' || echo '$(srcdir)/'`soundlib/Load_ult.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_ult.Po
@@ -4249,20 +4618,6 @@ soundlib/libopenmpttest-Load_ult.obj: soundlib/Load_ult.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_ult.obj `if test -f 'soundlib/Load_ult.cpp'; then $(CYGPATH_W) 'soundlib/Load_ult.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_ult.cpp'; fi`
 
-soundlib/libopenmpttest-Load_umx.o: soundlib/Load_umx.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_umx.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Tpo -c -o soundlib/libopenmpttest-Load_umx.o `test -f 'soundlib/Load_umx.cpp' || echo '$(srcdir)/'`soundlib/Load_umx.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_umx.cpp' object='soundlib/libopenmpttest-Load_umx.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_umx.o `test -f 'soundlib/Load_umx.cpp' || echo '$(srcdir)/'`soundlib/Load_umx.cpp
-
-soundlib/libopenmpttest-Load_umx.obj: soundlib/Load_umx.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_umx.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Tpo -c -o soundlib/libopenmpttest-Load_umx.obj `if test -f 'soundlib/Load_umx.cpp'; then $(CYGPATH_W) 'soundlib/Load_umx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_umx.cpp'; fi`
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_umx.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Load_umx.cpp' object='soundlib/libopenmpttest-Load_umx.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Load_umx.obj `if test -f 'soundlib/Load_umx.cpp'; then $(CYGPATH_W) 'soundlib/Load_umx.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Load_umx.cpp'; fi`
-
 soundlib/libopenmpttest-Load_wav.o: soundlib/Load_wav.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Load_wav.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Tpo -c -o soundlib/libopenmpttest-Load_wav.o `test -f 'soundlib/Load_wav.cpp' || echo '$(srcdir)/'`soundlib/Load_wav.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Tpo soundlib/$(DEPDIR)/libopenmpttest-Load_wav.Po
@@ -4375,20 +4730,6 @@ soundlib/libopenmpttest-MixFuncTable.obj: soundlib/MixFuncTable.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-MixFuncTable.obj `if test -f 'soundlib/MixFuncTable.cpp'; then $(CYGPATH_W) 'soundlib/MixFuncTable.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/MixFuncTable.cpp'; fi`
 
-soundlib/libopenmpttest-Mmcmp.o: soundlib/Mmcmp.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Mmcmp.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Tpo -c -o soundlib/libopenmpttest-Mmcmp.o `test -f 'soundlib/Mmcmp.cpp' || echo '$(srcdir)/'`soundlib/Mmcmp.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Mmcmp.cpp' object='soundlib/libopenmpttest-Mmcmp.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Mmcmp.o `test -f 'soundlib/Mmcmp.cpp' || echo '$(srcdir)/'`soundlib/Mmcmp.cpp
-
-soundlib/libopenmpttest-Mmcmp.obj: soundlib/Mmcmp.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Mmcmp.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Tpo -c -o soundlib/libopenmpttest-Mmcmp.obj `if test -f 'soundlib/Mmcmp.cpp'; then $(CYGPATH_W) 'soundlib/Mmcmp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Mmcmp.cpp'; fi`
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Tpo soundlib/$(DEPDIR)/libopenmpttest-Mmcmp.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Mmcmp.cpp' object='soundlib/libopenmpttest-Mmcmp.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Mmcmp.obj `if test -f 'soundlib/Mmcmp.cpp'; then $(CYGPATH_W) 'soundlib/Mmcmp.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Mmcmp.cpp'; fi`
-
 soundlib/libopenmpttest-ModChannel.o: soundlib/ModChannel.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-ModChannel.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Tpo -c -o soundlib/libopenmpttest-ModChannel.o `test -f 'soundlib/ModChannel.cpp' || echo '$(srcdir)/'`soundlib/ModChannel.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Tpo soundlib/$(DEPDIR)/libopenmpttest-ModChannel.Po
@@ -4515,6 +4856,20 @@ soundlib/libopenmpttest-OggStream.obj: soundlib/OggStream.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-OggStream.obj `if test -f 'soundlib/OggStream.cpp'; then $(CYGPATH_W) 'soundlib/OggStream.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/OggStream.cpp'; fi`
 
+soundlib/libopenmpttest-Paula.o: soundlib/Paula.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Paula.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo -c -o soundlib/libopenmpttest-Paula.o `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo soundlib/$(DEPDIR)/libopenmpttest-Paula.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Paula.cpp' object='soundlib/libopenmpttest-Paula.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Paula.o `test -f 'soundlib/Paula.cpp' || echo '$(srcdir)/'`soundlib/Paula.cpp
+
+soundlib/libopenmpttest-Paula.obj: soundlib/Paula.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-Paula.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo -c -o soundlib/libopenmpttest-Paula.obj `if test -f 'soundlib/Paula.cpp'; then $(CYGPATH_W) 'soundlib/Paula.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Paula.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-Paula.Tpo soundlib/$(DEPDIR)/libopenmpttest-Paula.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/Paula.cpp' object='soundlib/libopenmpttest-Paula.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-Paula.obj `if test -f 'soundlib/Paula.cpp'; then $(CYGPATH_W) 'soundlib/Paula.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/Paula.cpp'; fi`
+
 soundlib/libopenmpttest-patternContainer.o: soundlib/patternContainer.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-patternContainer.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Tpo -c -o soundlib/libopenmpttest-patternContainer.o `test -f 'soundlib/patternContainer.cpp' || echo '$(srcdir)/'`soundlib/patternContainer.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Tpo soundlib/$(DEPDIR)/libopenmpttest-patternContainer.Po
@@ -4585,6 +4940,76 @@ soundlib/libopenmpttest-SampleFormats.obj: soundlib/SampleFormats.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormats.obj `if test -f 'soundlib/SampleFormats.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormats.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormats.cpp'; fi`
 
+soundlib/libopenmpttest-SampleFormatFLAC.o: soundlib/SampleFormatFLAC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatFLAC.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo -c -o soundlib/libopenmpttest-SampleFormatFLAC.o `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatFLAC.cpp' object='soundlib/libopenmpttest-SampleFormatFLAC.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatFLAC.o `test -f 'soundlib/SampleFormatFLAC.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatFLAC.cpp
+
+soundlib/libopenmpttest-SampleFormatFLAC.obj: soundlib/SampleFormatFLAC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatFLAC.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo -c -o soundlib/libopenmpttest-SampleFormatFLAC.obj `if test -f 'soundlib/SampleFormatFLAC.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatFLAC.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatFLAC.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatFLAC.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatFLAC.cpp' object='soundlib/libopenmpttest-SampleFormatFLAC.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatFLAC.obj `if test -f 'soundlib/SampleFormatFLAC.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatFLAC.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatFLAC.cpp'; fi`
+
+soundlib/libopenmpttest-SampleFormatMediaFoundation.o: soundlib/SampleFormatMediaFoundation.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMediaFoundation.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.o `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatMediaFoundation.cpp' object='soundlib/libopenmpttest-SampleFormatMediaFoundation.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.o `test -f 'soundlib/SampleFormatMediaFoundation.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMediaFoundation.cpp
+
+soundlib/libopenmpttest-SampleFormatMediaFoundation.obj: soundlib/SampleFormatMediaFoundation.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMediaFoundation.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.obj `if test -f 'soundlib/SampleFormatMediaFoundation.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMediaFoundation.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMediaFoundation.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMediaFoundation.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatMediaFoundation.cpp' object='soundlib/libopenmpttest-SampleFormatMediaFoundation.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMediaFoundation.obj `if test -f 'soundlib/SampleFormatMediaFoundation.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMediaFoundation.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMediaFoundation.cpp'; fi`
+
+soundlib/libopenmpttest-SampleFormatMP3.o: soundlib/SampleFormatMP3.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMP3.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo -c -o soundlib/libopenmpttest-SampleFormatMP3.o `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatMP3.cpp' object='soundlib/libopenmpttest-SampleFormatMP3.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMP3.o `test -f 'soundlib/SampleFormatMP3.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatMP3.cpp
+
+soundlib/libopenmpttest-SampleFormatMP3.obj: soundlib/SampleFormatMP3.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatMP3.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo -c -o soundlib/libopenmpttest-SampleFormatMP3.obj `if test -f 'soundlib/SampleFormatMP3.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMP3.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMP3.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatMP3.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatMP3.cpp' object='soundlib/libopenmpttest-SampleFormatMP3.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatMP3.obj `if test -f 'soundlib/SampleFormatMP3.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatMP3.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatMP3.cpp'; fi`
+
+soundlib/libopenmpttest-SampleFormatOpus.o: soundlib/SampleFormatOpus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatOpus.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo -c -o soundlib/libopenmpttest-SampleFormatOpus.o `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatOpus.cpp' object='soundlib/libopenmpttest-SampleFormatOpus.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatOpus.o `test -f 'soundlib/SampleFormatOpus.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatOpus.cpp
+
+soundlib/libopenmpttest-SampleFormatOpus.obj: soundlib/SampleFormatOpus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatOpus.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo -c -o soundlib/libopenmpttest-SampleFormatOpus.obj `if test -f 'soundlib/SampleFormatOpus.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatOpus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatOpus.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatOpus.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatOpus.cpp' object='soundlib/libopenmpttest-SampleFormatOpus.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatOpus.obj `if test -f 'soundlib/SampleFormatOpus.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatOpus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatOpus.cpp'; fi`
+
+soundlib/libopenmpttest-SampleFormatVorbis.o: soundlib/SampleFormatVorbis.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatVorbis.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo -c -o soundlib/libopenmpttest-SampleFormatVorbis.o `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatVorbis.cpp' object='soundlib/libopenmpttest-SampleFormatVorbis.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatVorbis.o `test -f 'soundlib/SampleFormatVorbis.cpp' || echo '$(srcdir)/'`soundlib/SampleFormatVorbis.cpp
+
+soundlib/libopenmpttest-SampleFormatVorbis.obj: soundlib/SampleFormatVorbis.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleFormatVorbis.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo -c -o soundlib/libopenmpttest-SampleFormatVorbis.obj `if test -f 'soundlib/SampleFormatVorbis.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatVorbis.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatVorbis.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleFormatVorbis.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/SampleFormatVorbis.cpp' object='soundlib/libopenmpttest-SampleFormatVorbis.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-SampleFormatVorbis.obj `if test -f 'soundlib/SampleFormatVorbis.cpp'; then $(CYGPATH_W) 'soundlib/SampleFormatVorbis.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/SampleFormatVorbis.cpp'; fi`
+
 soundlib/libopenmpttest-SampleIO.o: soundlib/SampleIO.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-SampleIO.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Tpo -c -o soundlib/libopenmpttest-SampleIO.o `test -f 'soundlib/SampleIO.cpp' || echo '$(srcdir)/'`soundlib/SampleIO.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Tpo soundlib/$(DEPDIR)/libopenmpttest-SampleIO.Po
@@ -4739,6 +5164,20 @@ soundlib/libopenmpttest-tuning.obj: soundlib/tuning.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-tuning.obj `if test -f 'soundlib/tuning.cpp'; then $(CYGPATH_W) 'soundlib/tuning.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/tuning.cpp'; fi`
 
+soundlib/libopenmpttest-UMXTools.o: soundlib/UMXTools.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UMXTools.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo -c -o soundlib/libopenmpttest-UMXTools.o `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/UMXTools.cpp' object='soundlib/libopenmpttest-UMXTools.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-UMXTools.o `test -f 'soundlib/UMXTools.cpp' || echo '$(srcdir)/'`soundlib/UMXTools.cpp
+
+soundlib/libopenmpttest-UMXTools.obj: soundlib/UMXTools.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UMXTools.obj -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo -c -o soundlib/libopenmpttest-UMXTools.obj `if test -f 'soundlib/UMXTools.cpp'; then $(CYGPATH_W) 'soundlib/UMXTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/UMXTools.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Tpo soundlib/$(DEPDIR)/libopenmpttest-UMXTools.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/UMXTools.cpp' object='soundlib/libopenmpttest-UMXTools.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/libopenmpttest-UMXTools.obj `if test -f 'soundlib/UMXTools.cpp'; then $(CYGPATH_W) 'soundlib/UMXTools.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/UMXTools.cpp'; fi`
+
 soundlib/libopenmpttest-UpgradeModule.o: soundlib/UpgradeModule.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/libopenmpttest-UpgradeModule.o -MD -MP -MF soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Tpo -c -o soundlib/libopenmpttest-UpgradeModule.o `test -f 'soundlib/UpgradeModule.cpp' || echo '$(srcdir)/'`soundlib/UpgradeModule.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Tpo soundlib/$(DEPDIR)/libopenmpttest-UpgradeModule.Po
@@ -4809,6 +5248,20 @@ soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj: soundlib/plugins/dmo/DMOPlugi
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-DMOPlugin.obj `if test -f 'soundlib/plugins/dmo/DMOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/DMOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/DMOPlugin.cpp'; fi`
 
+soundlib/plugins/dmo/libopenmpttest-Chorus.o: soundlib/plugins/dmo/Chorus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Chorus.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.o `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/Chorus.cpp' object='soundlib/plugins/dmo/libopenmpttest-Chorus.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.o `test -f 'soundlib/plugins/dmo/Chorus.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Chorus.cpp
+
+soundlib/plugins/dmo/libopenmpttest-Chorus.obj: soundlib/plugins/dmo/Chorus.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Chorus.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.obj `if test -f 'soundlib/plugins/dmo/Chorus.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Chorus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Chorus.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Chorus.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/Chorus.cpp' object='soundlib/plugins/dmo/libopenmpttest-Chorus.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Chorus.obj `if test -f 'soundlib/plugins/dmo/Chorus.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Chorus.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Chorus.cpp'; fi`
+
 soundlib/plugins/dmo/libopenmpttest-Compressor.o: soundlib/plugins/dmo/Compressor.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Compressor.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Compressor.o `test -f 'soundlib/plugins/dmo/Compressor.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Compressor.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Compressor.Po
@@ -4851,6 +5304,20 @@ soundlib/plugins/dmo/libopenmpttest-Echo.obj: soundlib/plugins/dmo/Echo.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Echo.obj `if test -f 'soundlib/plugins/dmo/Echo.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Echo.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Echo.cpp'; fi`
 
+soundlib/plugins/dmo/libopenmpttest-Flanger.o: soundlib/plugins/dmo/Flanger.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Flanger.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.o `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/Flanger.cpp' object='soundlib/plugins/dmo/libopenmpttest-Flanger.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.o `test -f 'soundlib/plugins/dmo/Flanger.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Flanger.cpp
+
+soundlib/plugins/dmo/libopenmpttest-Flanger.obj: soundlib/plugins/dmo/Flanger.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Flanger.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.obj `if test -f 'soundlib/plugins/dmo/Flanger.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Flanger.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Flanger.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Flanger.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/Flanger.cpp' object='soundlib/plugins/dmo/libopenmpttest-Flanger.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Flanger.obj `if test -f 'soundlib/plugins/dmo/Flanger.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Flanger.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Flanger.cpp'; fi`
+
 soundlib/plugins/dmo/libopenmpttest-Gargle.o: soundlib/plugins/dmo/Gargle.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-Gargle.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-Gargle.o `test -f 'soundlib/plugins/dmo/Gargle.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/Gargle.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-Gargle.Po
@@ -4865,6 +5332,20 @@ soundlib/plugins/dmo/libopenmpttest-Gargle.obj: soundlib/plugins/dmo/Gargle.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-Gargle.obj `if test -f 'soundlib/plugins/dmo/Gargle.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/Gargle.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/Gargle.cpp'; fi`
 
+soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o: soundlib/plugins/dmo/I3DL2Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/I3DL2Reverb.cpp' object='soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.o `test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/I3DL2Reverb.cpp
+
+soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj: soundlib/plugins/dmo/I3DL2Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj `if test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/I3DL2Reverb.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-I3DL2Reverb.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/dmo/I3DL2Reverb.cpp' object='soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/dmo/libopenmpttest-I3DL2Reverb.obj `if test -f 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; then $(CYGPATH_W) 'soundlib/plugins/dmo/I3DL2Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/dmo/I3DL2Reverb.cpp'; fi`
+
 soundlib/plugins/dmo/libopenmpttest-ParamEq.o: soundlib/plugins/dmo/ParamEq.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/dmo/libopenmpttest-ParamEq.o -MD -MP -MF soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Tpo -c -o soundlib/plugins/dmo/libopenmpttest-ParamEq.o `test -f 'soundlib/plugins/dmo/ParamEq.cpp' || echo '$(srcdir)/'`soundlib/plugins/dmo/ParamEq.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Tpo soundlib/plugins/dmo/$(DEPDIR)/libopenmpttest-ParamEq.Po
@@ -4907,6 +5388,20 @@ soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj: soundlib/plugins/DigiBooste
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-DigiBoosterEcho.obj `if test -f 'soundlib/plugins/DigiBoosterEcho.cpp'; then $(CYGPATH_W) 'soundlib/plugins/DigiBoosterEcho.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/DigiBoosterEcho.cpp'; fi`
 
+soundlib/plugins/libopenmpttest-LFOPlugin.o: soundlib/plugins/LFOPlugin.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-LFOPlugin.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo -c -o soundlib/plugins/libopenmpttest-LFOPlugin.o `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/LFOPlugin.cpp' object='soundlib/plugins/libopenmpttest-LFOPlugin.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-LFOPlugin.o `test -f 'soundlib/plugins/LFOPlugin.cpp' || echo '$(srcdir)/'`soundlib/plugins/LFOPlugin.cpp
+
+soundlib/plugins/libopenmpttest-LFOPlugin.obj: soundlib/plugins/LFOPlugin.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-LFOPlugin.obj -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo -c -o soundlib/plugins/libopenmpttest-LFOPlugin.obj `if test -f 'soundlib/plugins/LFOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/LFOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/LFOPlugin.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-LFOPlugin.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='soundlib/plugins/LFOPlugin.cpp' object='soundlib/plugins/libopenmpttest-LFOPlugin.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-LFOPlugin.obj `if test -f 'soundlib/plugins/LFOPlugin.cpp'; then $(CYGPATH_W) 'soundlib/plugins/LFOPlugin.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/LFOPlugin.cpp'; fi`
+
 soundlib/plugins/libopenmpttest-PluginManager.o: soundlib/plugins/PluginManager.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT soundlib/plugins/libopenmpttest-PluginManager.o -MD -MP -MF soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Tpo -c -o soundlib/plugins/libopenmpttest-PluginManager.o `test -f 'soundlib/plugins/PluginManager.cpp' || echo '$(srcdir)/'`soundlib/plugins/PluginManager.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Tpo soundlib/plugins/$(DEPDIR)/libopenmpttest-PluginManager.Po
@@ -4935,6 +5430,62 @@ soundlib/plugins/libopenmpttest-PlugInterface.obj: soundlib/plugins/PlugInterfac
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o soundlib/plugins/libopenmpttest-PlugInterface.obj `if test -f 'soundlib/plugins/PlugInterface.cpp'; then $(CYGPATH_W) 'soundlib/plugins/PlugInterface.cpp'; else $(CYGPATH_W) '$(srcdir)/soundlib/plugins/PlugInterface.cpp'; fi`
 
+sounddsp/libopenmpttest-AGC.o: sounddsp/AGC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-AGC.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo -c -o sounddsp/libopenmpttest-AGC.o `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/AGC.cpp' object='sounddsp/libopenmpttest-AGC.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-AGC.o `test -f 'sounddsp/AGC.cpp' || echo '$(srcdir)/'`sounddsp/AGC.cpp
+
+sounddsp/libopenmpttest-AGC.obj: sounddsp/AGC.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-AGC.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo -c -o sounddsp/libopenmpttest-AGC.obj `if test -f 'sounddsp/AGC.cpp'; then $(CYGPATH_W) 'sounddsp/AGC.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/AGC.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-AGC.Tpo sounddsp/$(DEPDIR)/libopenmpttest-AGC.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/AGC.cpp' object='sounddsp/libopenmpttest-AGC.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-AGC.obj `if test -f 'sounddsp/AGC.cpp'; then $(CYGPATH_W) 'sounddsp/AGC.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/AGC.cpp'; fi`
+
+sounddsp/libopenmpttest-DSP.o: sounddsp/DSP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-DSP.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo -c -o sounddsp/libopenmpttest-DSP.o `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/DSP.cpp' object='sounddsp/libopenmpttest-DSP.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-DSP.o `test -f 'sounddsp/DSP.cpp' || echo '$(srcdir)/'`sounddsp/DSP.cpp
+
+sounddsp/libopenmpttest-DSP.obj: sounddsp/DSP.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-DSP.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo -c -o sounddsp/libopenmpttest-DSP.obj `if test -f 'sounddsp/DSP.cpp'; then $(CYGPATH_W) 'sounddsp/DSP.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/DSP.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-DSP.Tpo sounddsp/$(DEPDIR)/libopenmpttest-DSP.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/DSP.cpp' object='sounddsp/libopenmpttest-DSP.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-DSP.obj `if test -f 'sounddsp/DSP.cpp'; then $(CYGPATH_W) 'sounddsp/DSP.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/DSP.cpp'; fi`
+
+sounddsp/libopenmpttest-EQ.o: sounddsp/EQ.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-EQ.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo -c -o sounddsp/libopenmpttest-EQ.o `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/EQ.cpp' object='sounddsp/libopenmpttest-EQ.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-EQ.o `test -f 'sounddsp/EQ.cpp' || echo '$(srcdir)/'`sounddsp/EQ.cpp
+
+sounddsp/libopenmpttest-EQ.obj: sounddsp/EQ.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-EQ.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo -c -o sounddsp/libopenmpttest-EQ.obj `if test -f 'sounddsp/EQ.cpp'; then $(CYGPATH_W) 'sounddsp/EQ.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/EQ.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-EQ.Tpo sounddsp/$(DEPDIR)/libopenmpttest-EQ.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/EQ.cpp' object='sounddsp/libopenmpttest-EQ.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-EQ.obj `if test -f 'sounddsp/EQ.cpp'; then $(CYGPATH_W) 'sounddsp/EQ.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/EQ.cpp'; fi`
+
+sounddsp/libopenmpttest-Reverb.o: sounddsp/Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-Reverb.o -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo -c -o sounddsp/libopenmpttest-Reverb.o `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/Reverb.cpp' object='sounddsp/libopenmpttest-Reverb.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-Reverb.o `test -f 'sounddsp/Reverb.cpp' || echo '$(srcdir)/'`sounddsp/Reverb.cpp
+
+sounddsp/libopenmpttest-Reverb.obj: sounddsp/Reverb.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT sounddsp/libopenmpttest-Reverb.obj -MD -MP -MF sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo -c -o sounddsp/libopenmpttest-Reverb.obj `if test -f 'sounddsp/Reverb.cpp'; then $(CYGPATH_W) 'sounddsp/Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/Reverb.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Tpo sounddsp/$(DEPDIR)/libopenmpttest-Reverb.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='sounddsp/Reverb.cpp' object='sounddsp/libopenmpttest-Reverb.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o sounddsp/libopenmpttest-Reverb.obj `if test -f 'sounddsp/Reverb.cpp'; then $(CYGPATH_W) 'sounddsp/Reverb.cpp'; else $(CYGPATH_W) '$(srcdir)/sounddsp/Reverb.cpp'; fi`
+
 libopenmpt/libopenmpttest-libopenmpt_c.o: libopenmpt/libopenmpt_c.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_c.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_c.o `test -f 'libopenmpt/libopenmpt_c.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_c.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_c.Po
@@ -4963,19 +5514,19 @@ libopenmpt/libopenmpttest-libopenmpt_cxx.obj: libopenmpt/libopenmpt_cxx.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_cxx.obj `if test -f 'libopenmpt/libopenmpt_cxx.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_cxx.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_cxx.cpp'; fi`
 
-libopenmpt/libopenmpttest-libopenmpt_ext.o: libopenmpt/libopenmpt_ext.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_ext.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_ext.o `test -f 'libopenmpt/libopenmpt_ext.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='libopenmpt/libopenmpt_ext.cpp' object='libopenmpt/libopenmpttest-libopenmpt_ext.o' libtool=no @AMDEPBACKSLASH@
+libopenmpt/libopenmpttest-libopenmpt_ext_impl.o: libopenmpt/libopenmpt_ext_impl.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_ext_impl.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.o `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='libopenmpt/libopenmpt_ext_impl.cpp' object='libopenmpt/libopenmpttest-libopenmpt_ext_impl.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_ext.o `test -f 'libopenmpt/libopenmpt_ext.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext.cpp
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.o `test -f 'libopenmpt/libopenmpt_ext_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_ext_impl.cpp
 
-libopenmpt/libopenmpttest-libopenmpt_ext.obj: libopenmpt/libopenmpt_ext.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_ext.obj -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_ext.obj `if test -f 'libopenmpt/libopenmpt_ext.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_ext.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_ext.cpp'; fi`
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='libopenmpt/libopenmpt_ext.cpp' object='libopenmpt/libopenmpttest-libopenmpt_ext.obj' libtool=no @AMDEPBACKSLASH@
+libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj: libopenmpt/libopenmpt_ext_impl.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj `if test -f 'libopenmpt/libopenmpt_ext_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_ext_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_ext_impl.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Tpo libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_ext_impl.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='libopenmpt/libopenmpt_ext_impl.cpp' object='libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_ext.obj `if test -f 'libopenmpt/libopenmpt_ext.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_ext.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_ext.cpp'; fi`
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_ext_impl.obj `if test -f 'libopenmpt/libopenmpt_ext_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_ext_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_ext_impl.cpp'; fi`
 
 libopenmpt/libopenmpttest-libopenmpt_impl.o: libopenmpt/libopenmpt_impl.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -MT libopenmpt/libopenmpttest-libopenmpt_impl.o -MD -MP -MF libopenmpt/$(DEPDIR)/libopenmpttest-libopenmpt_impl.Tpo -c -o libopenmpt/libopenmpttest-libopenmpt_impl.o `test -f 'libopenmpt/libopenmpt_impl.cpp' || echo '$(srcdir)/'`libopenmpt/libopenmpt_impl.cpp
@@ -4991,27 +5542,15 @@ libopenmpt/libopenmpttest-libopenmpt_impl.obj: libopenmpt/libopenmpt_impl.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenmpttest_CPPFLAGS) $(CPPFLAGS) $(libopenmpttest_CXXFLAGS) $(CXXFLAGS) -c -o libopenmpt/libopenmpttest-libopenmpt_impl.obj `if test -f 'libopenmpt/libopenmpt_impl.cpp'; then $(CYGPATH_W) 'libopenmpt/libopenmpt_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/libopenmpt/libopenmpt_impl.cpp'; fi`
 
-src/openmpt123/openmpt123-openmpt123.o: src/openmpt123/openmpt123.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(openmpt123_CPPFLAGS) $(CPPFLAGS) $(openmpt123_CXXFLAGS) $(CXXFLAGS) -MT src/openmpt123/openmpt123-openmpt123.o -MD -MP -MF src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Tpo -c -o src/openmpt123/openmpt123-openmpt123.o `test -f 'src/openmpt123/openmpt123.cpp' || echo '$(srcdir)/'`src/openmpt123/openmpt123.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Tpo src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/openmpt123/openmpt123.cpp' object='src/openmpt123/openmpt123-openmpt123.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(openmpt123_CPPFLAGS) $(CPPFLAGS) $(openmpt123_CXXFLAGS) $(CXXFLAGS) -c -o src/openmpt123/openmpt123-openmpt123.o `test -f 'src/openmpt123/openmpt123.cpp' || echo '$(srcdir)/'`src/openmpt123/openmpt123.cpp
-
-src/openmpt123/openmpt123-openmpt123.obj: src/openmpt123/openmpt123.cpp
- at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(openmpt123_CPPFLAGS) $(CPPFLAGS) $(openmpt123_CXXFLAGS) $(CXXFLAGS) -MT src/openmpt123/openmpt123-openmpt123.obj -MD -MP -MF src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Tpo -c -o src/openmpt123/openmpt123-openmpt123.obj `if test -f 'src/openmpt123/openmpt123.cpp'; then $(CYGPATH_W) 'src/openmpt123/openmpt123.cpp'; else $(CYGPATH_W) '$(srcdir)/src/openmpt123/openmpt123.cpp'; fi`
- at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Tpo src/openmpt123/$(DEPDIR)/openmpt123-openmpt123.Po
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/openmpt123/openmpt123.cpp' object='src/openmpt123/openmpt123-openmpt123.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(openmpt123_CPPFLAGS) $(CPPFLAGS) $(openmpt123_CXXFLAGS) $(CXXFLAGS) -c -o src/openmpt123/openmpt123-openmpt123.obj `if test -f 'src/openmpt123/openmpt123.cpp'; then $(CYGPATH_W) 'src/openmpt123/openmpt123.cpp'; else $(CYGPATH_W) '$(srcdir)/src/openmpt123/openmpt123.cpp'; fi`
-
 mostlyclean-libtool:
 	-rm -f *.lo
 
 clean-libtool:
 	-rm -rf .libs _libs
+	-rm -rf bin/.libs bin/_libs
 	-rm -rf common/.libs common/_libs
 	-rm -rf libopenmpt/.libs libopenmpt/_libs
+	-rm -rf sounddsp/.libs sounddsp/_libs
 	-rm -rf soundlib/.libs soundlib/_libs
 	-rm -rf soundlib/plugins/.libs soundlib/plugins/_libs
 	-rm -rf soundlib/plugins/dmo/.libs soundlib/plugins/dmo/_libs
@@ -5239,7 +5778,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
 	if test -n "$$am__remaking_logs"; then \
 	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
 	       "recursion detected" >&2; \
-	else \
+	elif test -n "$$redo_logs"; then \
 	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
 	fi; \
 	if $(am__make_dryrun); then :; else \
@@ -5428,15 +5967,15 @@ dist-xz: distdir
 	$(am__post_remove_distdir)
 
 dist-tarZ: distdir
-	@echo WARNING: "Support for shar distribution archives is" \
-	               "deprecated." >&2
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
 	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
 	$(am__post_remove_distdir)
 
 dist-shar: distdir
-	@echo WARNING: "Support for distribution archives compressed with" \
-		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
 	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
@@ -5472,17 +6011,17 @@ distcheck: dist
 	esac
 	chmod -R a-w $(distdir)
 	chmod u+w $(distdir)
-	mkdir $(distdir)/_build $(distdir)/_inst
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
 	chmod a-w $(distdir)
 	test -d $(distdir)/_build || exit 0; \
 	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
 	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
 	  && am__cwd=`pwd` \
-	  && $(am__cd) $(distdir)/_build \
-	  && ../configure \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
 	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
-	    --srcdir=.. --prefix="$$dc_install_base" \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
 	  && $(MAKE) $(AM_MAKEFLAGS) \
 	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
@@ -5539,9 +6078,8 @@ check-am: all-am
 	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
 	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
 check: check-am
- at DX_COND_doc_FALSE@all-local:
 all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) $(DATA) $(HEADERS) \
-		config.h all-local
+		config.h
 install-binPROGRAMS: install-libLTLIBRARIES
 
 installdirs:
@@ -5578,37 +6116,37 @@ clean-generic:
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f bin/$(am__dirstamp)
 	-rm -f common/$(DEPDIR)/$(am__dirstamp)
 	-rm -f common/$(am__dirstamp)
 	-rm -f examples/$(DEPDIR)/$(am__dirstamp)
 	-rm -f examples/$(am__dirstamp)
 	-rm -f libopenmpt/$(DEPDIR)/$(am__dirstamp)
 	-rm -f libopenmpt/$(am__dirstamp)
+	-rm -f openmpt123/$(DEPDIR)/$(am__dirstamp)
+	-rm -f openmpt123/$(am__dirstamp)
+	-rm -f sounddsp/$(DEPDIR)/$(am__dirstamp)
+	-rm -f sounddsp/$(am__dirstamp)
 	-rm -f soundlib/$(DEPDIR)/$(am__dirstamp)
 	-rm -f soundlib/$(am__dirstamp)
 	-rm -f soundlib/plugins/$(DEPDIR)/$(am__dirstamp)
 	-rm -f soundlib/plugins/$(am__dirstamp)
 	-rm -f soundlib/plugins/dmo/$(DEPDIR)/$(am__dirstamp)
 	-rm -f soundlib/plugins/dmo/$(am__dirstamp)
-	-rm -f src/openmpt123/$(DEPDIR)/$(am__dirstamp)
-	-rm -f src/openmpt123/$(am__dirstamp)
 	-rm -f test/$(DEPDIR)/$(am__dirstamp)
 	-rm -f test/$(am__dirstamp)
 
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
- at DX_COND_doc_FALSE@uninstall-local:
- at DX_COND_doc_FALSE@install-data-local:
- at DX_COND_doc_FALSE@clean-local:
 clean: clean-am
 
 clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
-	clean-libLTLIBRARIES clean-libtool clean-local mostlyclean-am
+	clean-libLTLIBRARIES clean-libtool mostlyclean-am
 
 distclean: distclean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-	-rm -rf common/$(DEPDIR) examples/$(DEPDIR) libopenmpt/$(DEPDIR) soundlib/$(DEPDIR) soundlib/plugins/$(DEPDIR) soundlib/plugins/dmo/$(DEPDIR) src/openmpt123/$(DEPDIR) test/$(DEPDIR)
+	-rm -rf common/$(DEPDIR) examples/$(DEPDIR) libopenmpt/$(DEPDIR) openmpt123/$(DEPDIR) sounddsp/$(DEPDIR) soundlib/$(DEPDIR) soundlib/plugins/$(DEPDIR) soundlib/plugins/dmo/$(DEPDIR) test/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-libtool distclean-tags
@@ -5625,7 +6163,7 @@ info: info-am
 
 info-am:
 
-install-data-am: install-data-local install-dist_docDATA install-man \
+install-data-am: install-dist_docDATA install-man \
 	install-nobase_dist_docDATA install-nobase_includeHEADERS \
 	install-pkgconfigDATA
 
@@ -5658,7 +6196,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
 	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
 	-rm -rf $(top_srcdir)/autom4te.cache
-	-rm -rf common/$(DEPDIR) examples/$(DEPDIR) libopenmpt/$(DEPDIR) soundlib/$(DEPDIR) soundlib/plugins/$(DEPDIR) soundlib/plugins/dmo/$(DEPDIR) src/openmpt123/$(DEPDIR) test/$(DEPDIR)
+	-rm -rf common/$(DEPDIR) examples/$(DEPDIR) libopenmpt/$(DEPDIR) openmpt123/$(DEPDIR) sounddsp/$(DEPDIR) soundlib/$(DEPDIR) soundlib/plugins/$(DEPDIR) soundlib/plugins/dmo/$(DEPDIR) test/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
@@ -5676,7 +6214,7 @@ ps: ps-am
 ps-am:
 
 uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \
-	uninstall-libLTLIBRARIES uninstall-local uninstall-man \
+	uninstall-libLTLIBRARIES uninstall-man \
 	uninstall-nobase_dist_docDATA uninstall-nobase_includeHEADERS \
 	uninstall-pkgconfigDATA
 
@@ -5684,19 +6222,18 @@ uninstall-man: uninstall-man1
 
 .MAKE: all check-am install-am install-strip
 
-.PHONY: CTAGS GTAGS TAGS all all-am all-local am--refresh check \
-	check-TESTS check-am clean clean-binPROGRAMS \
-	clean-checkPROGRAMS clean-cscope clean-generic \
-	clean-libLTLIBRARIES clean-libtool clean-local cscope \
-	cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-TESTS \
+	check-am clean clean-binPROGRAMS clean-checkPROGRAMS \
+	clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \
+	cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
 	dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
 	distcheck distclean distclean-compile distclean-generic \
 	distclean-hdr distclean-libtool distclean-tags distcleancheck \
 	distdir distuninstallcheck dvi dvi-am html html-am info \
 	info-am install install-am install-binPROGRAMS install-data \
-	install-data-am install-data-local install-dist_docDATA \
-	install-dvi install-dvi-am install-exec install-exec-am \
-	install-html install-html-am install-info install-info-am \
+	install-data-am install-dist_docDATA install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am \
 	install-libLTLIBRARIES install-man install-man1 \
 	install-nobase_dist_docDATA install-nobase_includeHEADERS \
 	install-pdf install-pdf-am install-pkgconfigDATA install-ps \
@@ -5705,40 +6242,14 @@ uninstall-man: uninstall-man1
 	mostlyclean mostlyclean-compile mostlyclean-generic \
 	mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
 	uninstall uninstall-am uninstall-binPROGRAMS \
-	uninstall-dist_docDATA uninstall-libLTLIBRARIES \
-	uninstall-local uninstall-man uninstall-man1 \
-	uninstall-nobase_dist_docDATA uninstall-nobase_includeHEADERS \
-	uninstall-pkgconfigDATA
+	uninstall-dist_docDATA uninstall-libLTLIBRARIES uninstall-man \
+	uninstall-man1 uninstall-nobase_dist_docDATA \
+	uninstall-nobase_includeHEADERS uninstall-pkgconfigDATA
 
+.PRECIOUS: Makefile
 
- at DX_COND_doc_TRUE@all-local: @DX_DOCDIR@/@PACKAGE at .tag
-
- at DX_COND_doc_TRUE@install-data-local:
- at DX_COND_doc_TRUE@	$(INSTALL) -d $(DESTDIR)$(docdir)/html/search
- at DX_COND_doc_TRUE@	( cd @DX_DOCDIR@ && \
- at DX_COND_doc_TRUE@	for f in `find html -type f \! -name "installdox"`; do	\
- at DX_COND_doc_TRUE@		$(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f;	\
- at DX_COND_doc_TRUE@	done )
-
- at DX_COND_doc_TRUE@clean-local:
- at DX_COND_doc_TRUE@	$(RM) -r html
- at DX_COND_doc_TRUE@	$(RM) @DX_DOCDIR@/@PACKAGE at .tag
-
- at DX_COND_doc_TRUE@uninstall-local:
- at DX_COND_doc_TRUE@	$(RM) -r $(DESTDIR)$(docdir)/html
-
- at DX_COND_doc_TRUE@.PHONY: doxygen-run doxygen-doc
-
- at DX_COND_doc_TRUE@.INTERMEDIATE: doxygen-run
-
- at DX_COND_doc_TRUE@doxygen-run: @DX_DOCDIR@/@PACKAGE at .tag
-
- at DX_COND_doc_TRUE@doxygen-doc: doxygen-run
 
- at DX_COND_doc_TRUE@@DX_DOCDIR@/@PACKAGE at .tag: $(DX_CONFIG)
- at DX_COND_doc_TRUE@	rm -rf @DX_DOCDIR@
- at DX_COND_doc_TRUE@	$(DX_ENV) $(DX_DOXYGEN) $(DX_CONFIG)
- at DX_COND_doc_TRUE@	touch $@
+ at DX_RULES@
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/README.md b/README.md
index 12aea8f..36206a3 100644
--- a/README.md
+++ b/README.md
@@ -14,43 +14,14 @@ How to compile
 
  -  Supported Visual Studio versions:
 
-     -  Visual Studio 2008 Service Pack 1 Standard/Professional/Team Edition
-        (Express Edition is not supported as it does not include MFC).
-
-        You need the DirectX SDK 2010-June to enable DirectSound output. If you
-        don't want this, comment out `#define MPT_WITH_DSOUND` in the file
-        `common/BuildSettings.h`.
-
-        To compile the project, open `build/vs2008/OpenMPT.sln` and hit the
-        compile button.
-
-     -  Visual Studio 2010 Service Pack 1 Professional/Premium/Ultimate (Express
-        version is not supported as it does not include MFC).
-
-        You need the DirectX SDK 2010-June to enable DirectSound output. If you
-        don't want this, comment out `#define MPT_WITH_DSOUND` in the file
-        `common/BuildSettings.h`.
-
-        To compile the project, open `build/vs2010/OpenMPT.sln` and hit the
-        compile button.
-
-     -  Visual Studio 2012 Update 4 Professional/Premium/Ultimate (Express
-        version is not supported as it does not include MFC).
-
-        To compile the project, open `build/vs2012/OpenMPT.sln` and hit the
-        compile button.
-
-     -  Visual Studio 2013 Update 4 Community/Professional/Premium/Ultimate
-        Edition with MBCS MFC Add-On (available at
-        [microsoft.com](https://www.microsoft.com/en-us/download/details.aspx?id=40770)
-        ).
+     -  Visual Studio 2015 Update 3 Community/Professional/Enterprise
 
-        To compile the project, open `build/vs2013/OpenMPT.sln` and hit the
+        To compile the project, open `build/vs2015/OpenMPT.sln` and hit the
         compile button.
 
-     -  Visual Studio 2015 Update 3 Community/Professional/Enterprise
+     -  Visual Studio 2017 Community/Professional/Enterprise
 
-        To compile the project, open `build/vs2015/OpenMPT.sln` and hit the
+        To compile the project, open `build/vs2017/OpenMPT.sln` and hit the
         compile button.
 
  -  The VST and ASIO SDKs are needed for compiling with VST and ASIO support.
@@ -58,6 +29,13 @@ How to compile
     If you don't want this, uncomment `#define NO_VST` and comment out
     `#define MPT_WITH_ASIO` in the file `common/BuildSettings.h`.
 
+    The ASIO and VST SDKs can be downloaded automatically on Windows 7 or later
+    with 7-Zip installed by just running the `build/download_externals.cmd`
+    script.
+
+    If you do not want to or cannot use this script, you may follow these manual
+    steps instead:
+
      -  ASIO:
 
         If you use `#define MPT_WITH_ASIO`, you will need to put the ASIO SDK in
@@ -85,13 +63,13 @@ How to compile
         [steinberg.net](http://www.steinberg.net/en/company/developers.html) to
         download the SDK.
 
-    Alternatively, both, the ASIO and the VST SDK, can be downloaded
-    automatically on Windows 7 or later with 7-Zip installed by just running the
-    `build/download_externals.cmd` script (works when run from either the
-    project root or directly from the build directory).
-
     If you need further help with the VST and ASIO SDKs, get in touch with the
-    main developers. 
+    main OpenMPT developers. 
+
+ -  7-Zip is required to be installed in the default path in order to build the
+    required files for OpenMPT Wine integration.
+
+    Please visit [7-zip.org](http://www.7-zip.org/) to download 7-Zip.
 
 
 ### libopenmpt and openmpt123
@@ -109,22 +87,24 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
 
  -  Visual Studio:
 
-     -  You will find solutions for Visual Studio 2008 to 2015 in the
+     -  You will find solutions for Visual Studio 2015 to 2017 in the
         corresponding `build/vsVERSION/` folder.
+        Projects that target Windows versions before Windows 7 are available in
+        `build/vsVERSIONxp/`
         Most projects are supported with any of the mentioned Visual Studio
         verions, with the following exceptions:
 
-         -  libopenmpt_example_cxx: Requires VS2010 because it makes use of
-            C++11 features that VS2008 does not support..
-
-         -  foo_openmpt: Requires VS2010 because the foobar2000 SDK uses VS2010.
-
          -  in_openmpt: Requires Visual Studio with MFC.
 
          -  xmp-openmpt: Requires Visual Studio with MFC.
 
-     -  You will need the Winamp 5 SDK and the xmplay SDK if you want to
-        compile the plugins for these 2 players:
+     -  You will need the Winamp 5 SDK and the XMPlay SDK if you want to
+        compile the plugins for these 2 players. They can be downloaded
+        automatically on Windows 7 or later with 7-Zip installed by just running
+        the `build/download_externals.cmd` script.
+
+        If you do not want to or cannot use this script, you may follow these
+        manual steps instead:
 
          -  Winamp 5 SDK:
 
@@ -136,33 +116,27 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
             download the SDK.
             You can disable in_openmpt in the solution configuration.
 
-         -  xmplay SDK:
+         -  XMPlay SDK:
 
-            To build libopenmpt with xmplay input plugin support, copy the
+            To build libopenmpt with XMPlay input plugin support, copy the
             contents of xmp-sdk.zip into include/xmplay/.
 
             Please visit [un4seen.com](http://www.un4seen.com/xmplay.html) to
-            download to SDK.
+            download the SDK.
             You can disable xmp-openmpt in the solution configuration.
 
-        Alternatively, both, the Winamp and the xmplay SDK, can be downloaded
-        automatically on Windows 7 or later with 7-Zip installed by just running
-        the `build/download_externals.cmd` script (works when run from either
-        the project root or directly from the build directory).
-
  -  Makefile
 
     The makefile supports different build environments and targets via the
     `CONFIG=` parameter directly to the make invocation.
-    Use 'make CONFIG=$newconfig clean' when switching between different configs
+    Use `make CONFIG=$newconfig clean` when switching between different configs
     because the makefile cleans only intermediates and target that are active
     for the current config and no configuration state is kept around across
     invocations.
 
      -  mingw-w64:
 
-        The required version should be at least 4.3. Only 4.6 and up are
-        tested.
+        The required version is at least 4.8.
 
             make CONFIG=mingw64-win32    # for win32
 
@@ -172,9 +146,9 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
 
         The minimum required compiler versions are:
 
-         -  gcc 4.3
+         -  gcc 4.8
 
-         -  clang 3.0
+         -  clang 3.4
 
         The Makefile requires pkg-config for native builds.
         For sound output in openmpt123, PortAudio or SDL is required.
@@ -195,13 +169,9 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
 
         which will try to guess the compiler based on your operating system.
 
-        GCC versions 4.1 and 4.2 are partially supported, run:
-
-            make CONFIG=gcc ANCIENT=1
-
      -  emscripten (on Unix-like systems):
 
-        libopenmpt has been tested and verified to work with emscripten 1.21 or
+        libopenmpt has been tested and verified to work with emscripten 1.31 or
         later (earlier versions might or might not work).
 
         Run:
@@ -214,11 +184,6 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
         `node.js` binary, you might have to edit
         `build/make/config-emscripten.mk`.
 
-        Older and obsolete versions of emscripten may require a slightly
-        different configuration:
-
-            make CONFIG=emscripten-old
-
      -  Haiku:
 
         To compile libopenmpt on Haiku (using the 32-bit gcc2h), run:
@@ -228,11 +193,18 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
      -  American Fuzzy Lop:
 
         To compile libopenmpt with fuzzing instrumentation for afl-fuzz, run:
-
+        
             make CONFIG=afl
         
         For more detailed instructions, read contrib/fuzzing/readme.md
 
+     -  other compilers:
+
+        To compiler libopenmpt with other C++11 compliant compilers, run:
+        
+            make CONFIG=generic
+        
+    
     The `Makefile` supports some customizations. You might want to read the top
     which should get you some possible make settings, like e.g.
     `make DYNLINK=0` or similar. Cross compiling or different compiler would
@@ -271,8 +243,6 @@ Coding conventions
 
 (see below for an example)
 
-- Functions / methods are "underlined" (The `//------` comment, see below for
-  an example what it should look like).
 - Place curly braces at the beginning of the line, not at the end
 - Generally make use of the custom index types like `SAMPLEINDEX` or
   `ORDERINDEX` when referring to samples, orders, etc.
@@ -286,7 +256,6 @@ Coding conventions
 
 ~~~~{.cpp}
 void Foo::Bar(int foobar)
-//-----------------------
 {
     while(true)
     {
@@ -394,33 +363,3 @@ int foo::bar() const {
 
 } // namespace openmpt
 ~~~~
-
-
-A few words from the readme of the original MPT 1.16 source drop by Olivier
----------------------------------------------------------------------------
-
-> The sound library was originally written to support VOC/WAV and MOD files under
-> DOS, and supported such things as PC-Speaker, SoundBlaster 1/2/Pro, and the
-> famous Gravis UltraSound.
-> 
-> It was then ported to Win32 in 1995 (through the Mod95 project, mostly for use
-> within Render32).
-> 
-> What does this mean?
-> It means the code base is quite old and is showing its age (over 10 years now)
-> It means that many things are poorly named (CSoundFile), and not very clean, and
-> if I was to rewrite the engine today, it would look much different.
-> 
-> Some tips for future development and cleanup:
-> - Probably the main improvement would be to separate the Song, Channel, Mixer
-> and Low-level mixing routines in separate interface-based classes.
-> - Get rid of globals (many globals creeped up over time, mostly because of the
-> hack to allow simultaneous playback of 2 songs in Modplug Player -> ReadMix()).
-> This is a major problem for writing a DShow source filter, or any other COM
-> object (A DShow source would allow playback of MOD files in WMP, which would be
-> much easier than rewriting a different player).
-> - The MPT UI code is MFC-based, and I would say is fairly clean (as a rough
-> rule, the more recent the code is, the cleaner it is), though the UI code is
-> tightly integrated with the implementation (this could make it somewhat more
-> difficult to implement such things as a skin-based UI - but hey, if it was easy,
-> I probably would have done it already :).
diff --git a/TODO b/TODO
deleted file mode 100644
index 5f7473b..0000000
--- a/TODO
+++ /dev/null
@@ -1,17 +0,0 @@
-Of course there is still something that can be improved in OpenMPT, but there
-are some things which definitely should be done at some point. Those include:
-
-* Getting rid of the buggy MFC code. Instead use something like Qt.
-* While we're at it, make OpenMPT cross-platform. :)
-* Developement of a proper MPTM format. Currently, it's just based on the
-  Impulse Tracker format and new features are hacked on at the end of the file.
-  Not very nice!
-* Better VST support. Currently, many great VST 2.4 features like buses are not
-  supported.
-
-
-Some things that could also be implemented:
-
-* Resizable channels with multiple effect columns. This might not be trivial at
-  all, especially when dealing with effects which could interfer with each other
-  (f.e. porta up in one column, porta down in another).
\ No newline at end of file
diff --git a/aclocal.m4 b/aclocal.m4
index 28ec358..b4b72ba 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -20,7 +20,7 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
 # generated from the m4 files accompanying Automake X.Y.
 # (This private macro should not be called outside this file.)
 AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.14'
+[am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.14.1], [],
+m4_if([$1], [1.15], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -51,12 +51,12 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.14.1])dnl
+[AM_AUTOMAKE_VERSION([1.15])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
-# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+# Copyright (C) 2011-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -118,7 +118,7 @@ AC_SUBST([AR])dnl
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -170,7 +170,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -201,7 +201,7 @@ AC_CONFIG_COMMANDS_PRE(
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -392,7 +392,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -468,7 +468,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -558,8 +558,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 AC_REQUIRE([AC_PROG_AWK])dnl
 AC_REQUIRE([AC_PROG_MAKE_SET])dnl
 AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@@ -633,6 +633,9 @@ END
     AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
   fi
 fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
 ])
 
 dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
@@ -662,7 +665,7 @@ for _am_header in $config_headers :; do
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -673,7 +676,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
 # Define $install_sh.
 AC_DEFUN([AM_PROG_INSTALL_SH],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -683,7 +686,7 @@ if test x"${install_sh}" != xset; then
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -704,7 +707,7 @@ AC_SUBST([am__leading_dot])])
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -754,7 +757,7 @@ rm -f confinc confmf
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -793,7 +796,7 @@ fi
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -822,7 +825,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -869,7 +872,7 @@ AC_LANG_POP([C])])
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -888,7 +891,7 @@ AC_DEFUN([AM_RUN_LOG],
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -969,7 +972,7 @@ AC_CONFIG_COMMANDS_PRE(
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Copyright (C) 2009-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1029,7 +1032,7 @@ AC_SUBST([AM_BACKSLASH])dnl
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1057,7 +1060,7 @@ fi
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+# Copyright (C) 2006-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1076,7 +1079,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+# Copyright (C) 2004-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1210,6 +1213,7 @@ AC_SUBST([am__untar])
 m4_include([m4/ax_append_flag.m4])
 m4_include([m4/ax_cflags_warn_all.m4])
 m4_include([m4/ax_check_compile_flag.m4])
+m4_include([m4/ax_cxx_compile_stdcxx.m4])
 m4_include([m4/ax_cxx_compile_stdcxx_11.m4])
 m4_include([m4/ax_prog_doxygen.m4])
 m4_include([m4/ax_require_defined.m4])
diff --git a/build-aux/ar-lib b/build-aux/ar-lib
index fe2301e..463b9ec 100755
--- a/build-aux/ar-lib
+++ b/build-aux/ar-lib
@@ -4,7 +4,7 @@
 me=ar-lib
 scriptversion=2012-03-01.08; # UTC
 
-# Copyright (C) 2010-2013 Free Software Foundation, Inc.
+# Copyright (C) 2010-2014 Free Software Foundation, Inc.
 # Written by Peter Rosin <peda at lysator.liu.se>.
 #
 # This program is free software; you can redistribute it and/or modify
diff --git a/build-aux/compile b/build-aux/compile
index 531136b..a85b723 100755
--- a/build-aux/compile
+++ b/build-aux/compile
@@ -3,7 +3,7 @@
 
 scriptversion=2012-10-14.11; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 # Written by Tom Tromey <tromey at cygnus.com>.
 #
 # This program is free software; you can redistribute it and/or modify
diff --git a/build-aux/config.guess b/build-aux/config.guess
index 1f5c50c..2e9ad7f 100755
--- a/build-aux/config.guess
+++ b/build-aux/config.guess
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2014 Free Software Foundation, Inc.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2014-03-23'
+timestamp='2016-10-02'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -24,12 +24,12 @@ timestamp='2014-03-23'
 # program.  This Exception is an additional permission under section 7
 # of the GNU General Public License, version 3 ("GPLv3").
 #
-# Originally written by Per Bothner.
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 #
-# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+# Please send patches to <config-patches at gnu.org>.
 
 
 me=`echo "$0" | sed -e 's,.*/,,'`
@@ -50,7 +50,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	# Note: NetBSD doesn't particularly care about the vendor
 	# portion of the name.  We always set it to "unknown".
 	sysctl="sysctl -n hw.machine_arch"
-	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
-	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	    /sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || \
+	    echo unknown)`
 	case "${UNAME_MACHINE_ARCH}" in
 	    armeb) machine=armeb-unknown ;;
 	    arm*) machine=arm-unknown ;;
 	    sh3el) machine=shl-unknown ;;
 	    sh3eb) machine=sh-unknown ;;
 	    sh5el) machine=sh5le-unknown ;;
+	    earmv*)
+		arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine=${arch}${endian}-unknown
+		;;
 	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
 	esac
 	# The Operating System including object format, if it has switched
-	# to ELF recently, or will in the future.
+	# to ELF recently (or will in the future) and ABI.
 	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		os=netbsdelf
+		;;
 	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
 		eval $set_cc_for_build
 		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
@@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 		os=netbsd
 		;;
 	esac
+	# Determine ABI tags.
+	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+		;;
+	esac
 	# The OS release
 	# Debian GNU/NetBSD machines have a different userland, and
 	# thus, need a distinct triplet. However, they do not need
@@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 		release='-gnu'
 		;;
 	    *)
-		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
 		;;
 	esac
 	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
 	# contains redundant information, the shorter form:
 	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-	echo "${machine}-${os}${release}"
+	echo "${machine}-${os}${release}${abi}"
 	exit ;;
     *:Bitrig:*:*)
 	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
 	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
 	exit ;;
+    *:LibertyBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+	exit ;;
     *:ekkoBSD:*:*)
 	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
 	exit ;;
@@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:MirBSD:*:*)
 	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
 	exit ;;
+    *:Sortix:*:*)
+	echo ${UNAME_MACHINE}-unknown-sortix
+	exit ;;
     alpha:OSF1:*:*)
 	case $UNAME_RELEASE in
 	*4.0)
@@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
 	case "$ALPHA_CPU_TYPE" in
 	    "EV4 (21064)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "EV4.5 (21064)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "LCA4 (21066/21068)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "EV5 (21164)")
-		UNAME_MACHINE="alphaev5" ;;
+		UNAME_MACHINE=alphaev5 ;;
 	    "EV5.6 (21164A)")
-		UNAME_MACHINE="alphaev56" ;;
+		UNAME_MACHINE=alphaev56 ;;
 	    "EV5.6 (21164PC)")
-		UNAME_MACHINE="alphapca56" ;;
+		UNAME_MACHINE=alphapca56 ;;
 	    "EV5.7 (21164PC)")
-		UNAME_MACHINE="alphapca57" ;;
+		UNAME_MACHINE=alphapca57 ;;
 	    "EV6 (21264)")
-		UNAME_MACHINE="alphaev6" ;;
+		UNAME_MACHINE=alphaev6 ;;
 	    "EV6.7 (21264A)")
-		UNAME_MACHINE="alphaev67" ;;
+		UNAME_MACHINE=alphaev67 ;;
 	    "EV6.8CB (21264C)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.8AL (21264B)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.8CX (21264D)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.9A (21264/EV69A)")
-		UNAME_MACHINE="alphaev69" ;;
+		UNAME_MACHINE=alphaev69 ;;
 	    "EV7 (21364)")
-		UNAME_MACHINE="alphaev7" ;;
+		UNAME_MACHINE=alphaev7 ;;
 	    "EV7.9 (21364A)")
-		UNAME_MACHINE="alphaev79" ;;
+		UNAME_MACHINE=alphaev79 ;;
 	esac
 	# A Pn.n version is a patched version.
 	# A Vn.n version is a released version.
 	# A Tn.n version is a released field test version.
 	# A Xn.n version is an unreleased experimental baselevel.
 	# 1.2 uses "1.2" for uname -r.
-	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
 	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
 	exitcode=$?
 	trap '' 0
@@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
 	eval $set_cc_for_build
-	SUN_ARCH="i386"
+	SUN_ARCH=i386
 	# If there is a compiler, see if it is configured for 64-bit objects.
 	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
 	# This test works for both compilers.
-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
 	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
 		grep IS_64BIT_ARCH >/dev/null
 	    then
-		SUN_ARCH="x86_64"
+		SUN_ARCH=x86_64
 	    fi
 	fi
 	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	exit ;;
     sun*:*:4.2BSD:*)
 	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
 	case "`/bin/arch`" in
 	    sun3)
 		echo m68k-sun-sunos${UNAME_RELEASE}
@@ -579,8 +603,9 @@ EOF
 	else
 		IBM_ARCH=powerpc
 	fi
-	if [ -x /usr/bin/oslevel ] ; then
-		IBM_REV=`/usr/bin/oslevel`
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
 	else
 		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
 	fi
@@ -617,13 +642,13 @@ EOF
 		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
 		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
 		    case "${sc_cpu_version}" in
-		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
 		      532)                      # CPU_PA_RISC2_0
 			case "${sc_kernel_bits}" in
-			  32) HP_ARCH="hppa2.0n" ;;
-			  64) HP_ARCH="hppa2.0w" ;;
-			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			  32) HP_ARCH=hppa2.0n ;;
+			  64) HP_ARCH=hppa2.0w ;;
+			  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
 			esac ;;
 		    esac
 		fi
@@ -662,11 +687,11 @@ EOF
 		    exit (0);
 		}
 EOF
-		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
 		    test -z "$HP_ARCH" && HP_ARCH=hppa
 		fi ;;
 	esac
-	if [ ${HP_ARCH} = "hppa2.0w" ]
+	if [ ${HP_ARCH} = hppa2.0w ]
 	then
 	    eval $set_cc_for_build
 
@@ -679,12 +704,12 @@ EOF
 	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
 	    # => hppa64-hp-hpux11.23
 
-	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+	    if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
 		grep -q __LP64__
 	    then
-		HP_ARCH="hppa2.0w"
+		HP_ARCH=hppa2.0w
 	    else
-		HP_ARCH="hppa64"
+		HP_ARCH=hppa64
 	    fi
 	fi
 	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -789,14 +814,14 @@ EOF
 	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
 	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
 	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     5000:UNIX_System_V:4.*:*)
-	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
 	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -878,7 +903,7 @@ EOF
 	exit ;;
     *:GNU/*:*:*)
 	# other systems with GNU libc and userland
-	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
 	exit ;;
     i*86:Minix:*:*)
 	echo ${UNAME_MACHINE}-pc-minix
@@ -901,7 +926,7 @@ EOF
 	  EV68*) UNAME_MACHINE=alphaev68 ;;
 	esac
 	objdump --private-headers /bin/sh | grep -q ld.so.1
-	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
     arc:Linux:*:* | arceb:Linux:*:*)
@@ -932,6 +957,9 @@ EOF
     crisv32:Linux:*:*)
 	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
 	exit ;;
+    e2k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
     frv:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
@@ -944,6 +972,9 @@ EOF
     ia64:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
+    k1om:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
     m32r*:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
@@ -969,6 +1000,9 @@ EOF
 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
 	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
 	;;
+    mips64el:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
     openrisc*:Linux:*:*)
 	echo or1k-unknown-linux-${LIBC}
 	exit ;;
@@ -1001,6 +1035,9 @@ EOF
     ppcle:Linux:*:*)
 	echo powerpcle-unknown-linux-${LIBC}
 	exit ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
 	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
 	exit ;;
@@ -1020,7 +1057,7 @@ EOF
 	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
 	exit ;;
     x86_64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
 	exit ;;
     xtensa*:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@@ -1099,7 +1136,7 @@ EOF
 	# uname -m prints for DJGPP always 'pc', but it prints nothing about
 	# the processor, so we play safe by assuming i586.
 	# Note: whatever this is, it MUST be the same as what config.sub
-	# prints for the "djgpp" host, or else GDB configury will decide that
+	# prints for the "djgpp" host, or else GDB configure will decide that
 	# this is a cross-build.
 	echo i586-pc-msdosdjgpp
 	exit ;;
@@ -1248,6 +1285,9 @@ EOF
     SX-8R:SUPER-UX:*:*)
 	echo sx8r-nec-superux${UNAME_RELEASE}
 	exit ;;
+    SX-ACE:SUPER-UX:*:*)
+	echo sxace-nec-superux${UNAME_RELEASE}
+	exit ;;
     Power*:Rhapsody:*:*)
 	echo powerpc-apple-rhapsody${UNAME_RELEASE}
 	exit ;;
@@ -1261,9 +1301,9 @@ EOF
 	    UNAME_PROCESSOR=powerpc
 	fi
 	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
-	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
 		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
 		    grep IS_64BIT_ARCH >/dev/null
 		then
 		    case $UNAME_PROCESSOR in
@@ -1285,7 +1325,7 @@ EOF
 	exit ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
 	UNAME_PROCESSOR=`uname -p`
-	if test "$UNAME_PROCESSOR" = "x86"; then
+	if test "$UNAME_PROCESSOR" = x86; then
 		UNAME_PROCESSOR=i386
 		UNAME_MACHINE=pc
 	fi
@@ -1316,7 +1356,7 @@ EOF
 	# "uname -m" is not consistent, so use $cputype instead. 386
 	# is converted to i386 for consistency with other x86
 	# operating systems.
-	if test "$cputype" = "386"; then
+	if test "$cputype" = 386; then
 	    UNAME_MACHINE=i386
 	else
 	    UNAME_MACHINE="$cputype"
@@ -1358,7 +1398,7 @@ EOF
 	echo i386-pc-xenix
 	exit ;;
     i*86:skyos:*:*)
-	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
 	exit ;;
     i*86:rdos:*:*)
 	echo ${UNAME_MACHINE}-pc-rdos
@@ -1369,23 +1409,25 @@ EOF
     x86_64:VMkernel:*:*)
 	echo ${UNAME_MACHINE}-unknown-esx
 	exit ;;
+    amd64:Isilon\ OneFS:*:*)
+	echo x86_64-unknown-onefs
+	exit ;;
 esac
 
 cat >&2 <<EOF
 $0: unable to guess system type
 
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
 
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 and
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches at gnu.org> in order to provide the needed
-information to handle your system.
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches at gnu.org to
+provide the necessary information to handle your system.
 
 config.guess timestamp = $timestamp
 
diff --git a/build-aux/config.sub b/build-aux/config.sub
index bba4efb..dd2ca93 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2014 Free Software Foundation, Inc.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2014-09-11'
+timestamp='2016-11-04'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ timestamp='2014-09-11'
 # of the GNU General Public License, version 3 ("GPLv3").
 
 
-# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+# Please send patches to <config-patches at gnu.org>.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
@@ -33,7 +33,7 @@ timestamp='2014-09-11'
 # Otherwise, we print the canonical config type on stdout and succeed.
 
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
@@ -53,8 +53,7 @@ timestamp='2014-09-11'
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
-       $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
 
 Canonicalize a configuration name.
 
@@ -68,7 +67,7 @@ Report bugs and patches to <config-patches at gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
   nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
   linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
-  knetbsd*-gnu* | netbsd*-gnu* | \
-  kopensolaris*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | cloudabi*-eabi* | \
   storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
@@ -255,12 +254,13 @@ case $basic_machine in
 	| arc | arceb \
 	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
 	| avr | avr32 \
+	| ba \
 	| be32 | be64 \
 	| bfin \
 	| c4x | c8051 | clipper \
 	| d10v | d30v | dlx | dsp16xx \
-	| epiphany \
-	| fido | fr30 | frv \
+	| e2k | epiphany \
+	| fido | fr30 | frv | ft32 \
 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 	| hexagon \
 	| i370 | i860 | i960 | ia64 \
@@ -301,11 +301,12 @@ case $basic_machine in
 	| open8 | or1k | or1knd | or32 \
 	| pdp10 | pdp11 | pj | pjl \
 	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pru \
 	| pyramid \
 	| riscv32 | riscv64 \
 	| rl78 | rx \
 	| score \
-	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
 	| sh64 | sh64le \
 	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
 	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -313,6 +314,7 @@ case $basic_machine in
 	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
 	| ubicom32 \
 	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| visium \
 	| we32k \
 	| x86 | xc16x | xstormy16 | xtensa \
 	| z8k | z80)
@@ -327,6 +329,9 @@ case $basic_machine in
 	c6x)
 		basic_machine=tic6x-unknown
 		;;
+	leon|leon[3-9])
+		basic_machine=sparc-$basic_machine
+		;;
 	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
 		basic_machine=$basic_machine-unknown
 		os=-none
@@ -372,12 +377,13 @@ case $basic_machine in
 	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
 	| avr-* | avr32-* \
+	| ba-* \
 	| be32-* | be64-* \
 	| bfin-* | bs2000-* \
 	| c[123]* | c30-* | [cjt]90-* | c4x-* \
 	| c8051-* | clipper-* | craynv-* | cydra-* \
 	| d10v-* | d30v-* | dlx-* \
-	| elxsi-* \
+	| e2k-* | elxsi-* \
 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
 	| h8300-* | h8500-* \
 	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@@ -423,13 +429,15 @@ case $basic_machine in
 	| orion-* \
 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
 	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pru-* \
 	| pyramid-* \
+	| riscv32-* | riscv64-* \
 	| rl78-* | romp-* | rs6000-* | rx-* \
 	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
 	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
 	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
 	| sparclite-* \
-	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
 	| tahoe-* \
 	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
 	| tile*-* \
@@ -437,6 +445,7 @@ case $basic_machine in
 	| ubicom32-* \
 	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
 	| vax-* \
+	| visium-* \
 	| we32k-* \
 	| x86-* | x86_64-* | xc16x-* | xps100-* \
 	| xstormy16-* | xtensa*-* \
@@ -513,6 +522,9 @@ case $basic_machine in
 		basic_machine=i386-pc
 		os=-aros
 		;;
+	asmjs)
+		basic_machine=asmjs-unknown
+		;;
 	aux)
 		basic_machine=m68k-apple
 		os=-aux
@@ -633,6 +645,14 @@ case $basic_machine in
 		basic_machine=m68k-bull
 		os=-sysv3
 		;;
+	e500v[12])
+		basic_machine=powerpc-unknown
+		os=$os"spe"
+		;;
+	e500v[12]-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=$os"spe"
+		;;
 	ebmon29k)
 		basic_machine=a29k-amd
 		os=-ebmon
@@ -774,6 +794,9 @@ case $basic_machine in
 		basic_machine=m68k-isi
 		os=-sysv
 		;;
+	leon-*|leon[3-9]-*)
+		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+		;;
 	m68knommu)
 		basic_machine=m68k-unknown
 		os=-linux
@@ -1009,7 +1032,7 @@ case $basic_machine in
 	ppc-* | ppcbe-*)
 		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
-	ppcle | powerpclittle | ppc-le | powerpc-little)
+	ppcle | powerpclittle)
 		basic_machine=powerpcle-unknown
 		;;
 	ppcle-* | powerpclittle-*)
@@ -1019,7 +1042,7 @@ case $basic_machine in
 		;;
 	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
-	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+	ppc64le | powerpc64little)
 		basic_machine=powerpc64le-unknown
 		;;
 	ppc64le-* | powerpc64little-*)
@@ -1365,18 +1388,18 @@ case $os in
 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
 	      | -sym* | -kopensolaris* | -plan9* \
 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-	      | -aos* | -aros* \
+	      | -aos* | -aros* | -cloudabi* | -sortix* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
 	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
-	      | -bitrig* | -openbsd* | -solidbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
 	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
 	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
 	      | -chorusos* | -chorusrdb* | -cegcc* \
 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
 	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
 	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
@@ -1385,7 +1408,8 @@ case $os in
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+	      | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
 	-qnx*)
@@ -1517,6 +1541,8 @@ case $os in
 		;;
 	-nacl*)
 		;;
+	-ios)
+		;;
 	-none)
 		;;
 	*)
diff --git a/build-aux/depcomp b/build-aux/depcomp
index 4ebd5b3..fc98710 100755
--- a/build-aux/depcomp
+++ b/build-aux/depcomp
@@ -3,7 +3,7 @@
 
 scriptversion=2013-05-30.07; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff --git a/build-aux/install-sh b/build-aux/install-sh
index 756420d..59990a1 100755
--- a/build-aux/install-sh
+++ b/build-aux/install-sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 # install - install a program, script, or datafile
 
-scriptversion=2011-11-20.07; # UTC
+scriptversion=2014-09-12.12; # UTC
 
 # This originates from X11R5 (mit/util/scripts/install.sh), which was
 # later released in X11R6 (xc/config/util/install.sh) with the
@@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
 # This script is compatible with the BSD install script, but was written
 # from scratch.
 
+tab='	'
 nl='
 '
-IFS=" ""	$nl"
+IFS=" $tab$nl"
 
-# set DOITPROG to echo to test this script
+# Set DOITPROG to "echo" to test this script.
 
-# Don't use :- since 4.3BSD and earlier shells don't like it.
 doit=${DOITPROG-}
-if test -z "$doit"; then
-  doit_exec=exec
-else
-  doit_exec=$doit
-fi
+doit_exec=${doit:-exec}
 
 # Put in absolute file names if you don't have them in your path;
 # or use environment vars.
@@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
 rmprog=${RMPROG-rm}
 stripprog=${STRIPPROG-strip}
 
-posix_glob='?'
-initialize_posix_glob='
-  test "$posix_glob" != "?" || {
-    if (set -f) 2>/dev/null; then
-      posix_glob=
-    else
-      posix_glob=:
-    fi
-  }
-'
-
 posix_mkdir=
 
 # Desired mode of installed file.
@@ -97,7 +82,7 @@ dir_arg=
 dst_arg=
 
 copy_on_change=false
-no_target_directory=
+is_target_a_directory=possibly
 
 usage="\
 Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@@ -137,46 +122,57 @@ while test $# -ne 0; do
     -d) dir_arg=true;;
 
     -g) chgrpcmd="$chgrpprog $2"
-	shift;;
+        shift;;
 
     --help) echo "$usage"; exit $?;;
 
     -m) mode=$2
-	case $mode in
-	  *' '* | *'	'* | *'
-'*	  | *'*'* | *'?'* | *'['*)
-	    echo "$0: invalid mode: $mode" >&2
-	    exit 1;;
-	esac
-	shift;;
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
 
     -o) chowncmd="$chownprog $2"
-	shift;;
+        shift;;
 
     -s) stripcmd=$stripprog;;
 
-    -t) dst_arg=$2
-	# Protect names problematic for 'test' and other utilities.
-	case $dst_arg in
-	  -* | [=\(\)!]) dst_arg=./$dst_arg;;
-	esac
-	shift;;
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
 
-    -T) no_target_directory=true;;
+    -T) is_target_a_directory=never;;
 
     --version) echo "$0 $scriptversion"; exit $?;;
 
-    --)	shift
-	break;;
+    --) shift
+        break;;
 
-    -*)	echo "$0: invalid option: $1" >&2
-	exit 1;;
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
 
     *)  break;;
   esac
   shift
 done
 
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
+
 if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
   # When -d is used, all remaining arguments are directories to create.
   # When -t is used, the destination is already specified.
@@ -208,6 +204,15 @@ if test $# -eq 0; then
 fi
 
 if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
+
+if test -z "$dir_arg"; then
   do_exit='(exit $ret); exit $ret'
   trap "ret=129; $do_exit" 1
   trap "ret=130; $do_exit" 2
@@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
 
     *[0-7])
       if test -z "$stripcmd"; then
-	u_plus_rw=
+        u_plus_rw=
       else
-	u_plus_rw='% 200'
+        u_plus_rw='% 200'
       fi
       cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
     *)
       if test -z "$stripcmd"; then
-	u_plus_rw=
+        u_plus_rw=
       else
-	u_plus_rw=,u+rw
+        u_plus_rw=,u+rw
       fi
       cp_umask=$mode$u_plus_rw;;
   esac
@@ -269,41 +274,15 @@ do
     # If destination is a directory, append the input filename; won't work
     # if double slashes aren't ignored.
     if test -d "$dst"; then
-      if test -n "$no_target_directory"; then
-	echo "$0: $dst_arg: Is a directory" >&2
-	exit 1
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
       fi
       dstdir=$dst
       dst=$dstdir/`basename "$src"`
       dstdir_status=0
     else
-      # Prefer dirname, but fall back on a substitute if dirname fails.
-      dstdir=`
-	(dirname "$dst") 2>/dev/null ||
-	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	     X"$dst" : 'X\(//\)[^/]' \| \
-	     X"$dst" : 'X\(//\)$' \| \
-	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
-	echo X"$dst" |
-	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-		   s//\1/
-		   q
-		 }
-		 /^X\(\/\/\)[^/].*/{
-		   s//\1/
-		   q
-		 }
-		 /^X\(\/\/\)$/{
-		   s//\1/
-		   q
-		 }
-		 /^X\(\/\).*/{
-		   s//\1/
-		   q
-		 }
-		 s/.*/./; q'
-      `
-
+      dstdir=`dirname "$dst"`
       test -d "$dstdir"
       dstdir_status=$?
     fi
@@ -314,81 +293,81 @@ do
   if test $dstdir_status != 0; then
     case $posix_mkdir in
       '')
-	# Create intermediate dirs using mode 755 as modified by the umask.
-	# This is like FreeBSD 'install' as of 1997-10-28.
-	umask=`umask`
-	case $stripcmd.$umask in
-	  # Optimize common cases.
-	  *[2367][2367]) mkdir_umask=$umask;;
-	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
-	  *[0-7])
-	    mkdir_umask=`expr $umask + 22 \
-	      - $umask % 100 % 40 + $umask % 20 \
-	      - $umask % 10 % 4 + $umask % 2
-	    `;;
-	  *) mkdir_umask=$umask,go-w;;
-	esac
-
-	# With -d, create the new directory with the user-specified mode.
-	# Otherwise, rely on $mkdir_umask.
-	if test -n "$dir_arg"; then
-	  mkdir_mode=-m$mode
-	else
-	  mkdir_mode=
-	fi
-
-	posix_mkdir=false
-	case $umask in
-	  *[123567][0-7][0-7])
-	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
-	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
-	    ;;
-	  *)
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
             # $RANDOM is not portable (e.g. dash);  use it when possible to
             # lower collision chance
-	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-	    trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
-
-	     # As "mkdir -p" follows symlinks and we work in /tmp possibly;  so
-	     # create the $tmpdir first (and fail if unsuccessful) to make sure
-	     # that nobody tries to guess the $tmpdir name.
-	    if (umask $mkdir_umask &&
-		$mkdirprog $mkdir_mode "$tmpdir" &&
-		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
-	    then
-	      if test -z "$dir_arg" || {
-		   # Check for POSIX incompatibilities with -m.
-		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-		   # other-writable bit of parent directory when it shouldn't.
-		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
-		   test_tmpdir="$tmpdir/a"
-		   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
-		   case $ls_ld_tmpdir in
-		     d????-?r-*) different_mode=700;;
-		     d????-?--*) different_mode=755;;
-		     *) false;;
-		   esac &&
-		   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
-		     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
-		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
-		   }
-		 }
-	      then posix_mkdir=:
-	      fi
-	      rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
-	    else
-	      # Remove any dirs left behind by ancient mkdir implementations.
-	      rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
-	    fi
-	    trap '' 0;;
-	esac;;
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            # As "mkdir -p" follows symlinks and we work in /tmp possibly;  so
+            # create the $tmpdir first (and fail if unsuccessful) to make sure
+            # that nobody tries to guess the $tmpdir name.
+            if (umask $mkdir_umask &&
+                $mkdirprog $mkdir_mode "$tmpdir" &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   test_tmpdir="$tmpdir/a"
+                   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
     esac
 
     if
       $posix_mkdir && (
-	umask $mkdir_umask &&
-	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
       )
     then :
     else
@@ -398,53 +377,51 @@ do
       # directory the slow way, step by step, checking for races as we go.
 
       case $dstdir in
-	/*) prefix='/';;
-	[-=\(\)!]*) prefix='./';;
-	*)  prefix='';;
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
       esac
 
-      eval "$initialize_posix_glob"
-
       oIFS=$IFS
       IFS=/
-      $posix_glob set -f
+      set -f
       set fnord $dstdir
       shift
-      $posix_glob set +f
+      set +f
       IFS=$oIFS
 
       prefixes=
 
       for d
       do
-	test X"$d" = X && continue
-
-	prefix=$prefix$d
-	if test -d "$prefix"; then
-	  prefixes=
-	else
-	  if $posix_mkdir; then
-	    (umask=$mkdir_umask &&
-	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
-	    # Don't fail if two instances are running concurrently.
-	    test -d "$prefix" || exit 1
-	  else
-	    case $prefix in
-	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
-	      *) qprefix=$prefix;;
-	    esac
-	    prefixes="$prefixes '$qprefix'"
-	  fi
-	fi
-	prefix=$prefix/
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
       done
 
       if test -n "$prefixes"; then
-	# Don't fail if two instances are running concurrently.
-	(umask $mkdir_umask &&
-	 eval "\$doit_exec \$mkdirprog $prefixes") ||
-	  test -d "$dstdir" || exit 1
-	obsolete_mkdir_used=true
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
       fi
     fi
   fi
@@ -479,15 +456,12 @@ do
 
     # If -C, don't bother to copy if it wouldn't change the file.
     if $copy_on_change &&
-       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
-       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
-
-       eval "$initialize_posix_glob" &&
-       $posix_glob set -f &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
        set X $old && old=:$2:$4:$5:$6 &&
        set X $new && new=:$2:$4:$5:$6 &&
-       $posix_glob set +f &&
-
+       set +f &&
        test "$old" = "$new" &&
        $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
     then
@@ -500,24 +474,24 @@ do
       # to itself, or perhaps because mv is so ancient that it does not
       # support -f.
       {
-	# Now remove or move aside any old file at destination location.
-	# We try this two ways since rm can't unlink itself on some
-	# systems and the destination file might be busy for other
-	# reasons.  In this case, the final cleanup might fail but the new
-	# file should still install successfully.
-	{
-	  test ! -f "$dst" ||
-	  $doit $rmcmd -f "$dst" 2>/dev/null ||
-	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
-	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
-	  } ||
-	  { echo "$0: cannot unlink or rename $dst" >&2
-	    (exit 1); exit 1
-	  }
-	} &&
-
-	# Now rename the file to the real destination.
-	$doit $mvcmd "$dsttmp" "$dst"
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
       }
     fi || exit 1
 
diff --git a/build-aux/ltmain.sh b/build-aux/ltmain.sh
index bffda54..a736cf9 100644
--- a/build-aux/ltmain.sh
+++ b/build-aux/ltmain.sh
@@ -1,9 +1,12 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+##               by inline-source v2014-01-03.01
 
-# libtool (GNU libtool) 2.4.2
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
 # Written by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
 
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
-# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
 # This is free software; see the source for copying conditions.  There is NO
 # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
@@ -23,881 +26,2112 @@
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING.  If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html,
-# or obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Usage: $progname [OPTION]... [MODE-ARG]...
-#
-# Provide generalized library-building support services.
-#
-#       --config             show all configuration variables
-#       --debug              enable verbose shell tracing
-#   -n, --dry-run            display commands without modifying any files
-#       --features           display basic configuration information and exit
-#       --mode=MODE          use operation mode MODE
-#       --preserve-dup-deps  don't remove duplicate dependency libraries
-#       --quiet, --silent    don't print informational messages
-#       --no-quiet, --no-silent
-#                            print informational messages (default)
-#       --no-warn            don't display warning messages
-#       --tag=TAG            use configuration variables from tag TAG
-#   -v, --verbose            print more informational messages than default
-#       --no-verbose         don't print the extra informational messages
-#       --version            print version information
-#   -h, --help, --help-all   print short, long, or detailed help message
-#
-# MODE must be one of the following:
-#
-#         clean              remove files from the build directory
-#         compile            compile a source file into a libtool object
-#         execute            automatically set library path, then run a program
-#         finish             complete the installation of libtool libraries
-#         install            install libraries or executables
-#         link               create a library or an executable
-#         uninstall          remove libraries from an installed directory
-#
-# MODE-ARGS vary depending on the MODE.  When passed as first option,
-# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
-# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
-#
-# When reporting a bug, please describe a test case to reproduce it and
-# include the following information:
-#
-#         host-triplet:	$host
-#         shell:		$SHELL
-#         compiler:		$LTCC
-#         compiler flags:		$LTCFLAGS
-#         linker:		$LD (gnu? $with_gnu_ld)
-#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1.11
-#         automake:	$automake_version
-#         autoconf:	$autoconf_version
-#
-# Report bugs to <bug-libtool at gnu.org>.
-# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
-# General help using GNU software: <http://www.gnu.org/gethelp/>.
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION="2.4.2 Debian-2.4.2-1.11"
-TIMESTAMP=""
-package_revision=1.3337
+VERSION="2.4.6 Debian-2.4.6-2"
+package_revision=2.4.6
 
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary at gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+#   . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
-  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
   # is contrary to our usage.  Disable this feature.
   alias -g '${1+"$@"}'='"$@"'
   setopt NO_GLOB_SUBST
 else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
 fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-}
 
-# NLS nuisances: We save the old values to restore during execute mode.
-lt_user_locale=
-lt_safe_locale=
-for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
 do
-  eval "if test \"\${$lt_var+set}\" = set; then
-          save_$lt_var=\$$lt_var
-          $lt_var=C
-	  export $lt_var
-	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
-	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+  eval "if test set = \"\${$_G_var+set}\"; then
+          save_$_G_var=\$$_G_var
+          $_G_var=C
+	  export $_G_var
+	  _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+	  _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
 	fi"
 done
-LC_ALL=C
-LANGUAGE=C
-export LANGUAGE LC_ALL
 
-$lt_unset CDPATH
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp	$nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
 
-# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
-# is ksh but when the shell is invoked as "sh" and the current value of
-# the _XPG environment variable is not equal to 1 (one), the special
-# positional parameter $0, within a function call, is the name of the
-# function.
-progpath="$0"
 
 
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+    test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+    _G_progs_list=$1
+    _G_check_func=$2
+    _G_PATH=${3-"$PATH"}
+
+    _G_path_prog_max=0
+    _G_path_prog_found=false
+    _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+    for _G_dir in $_G_PATH; do
+      IFS=$_G_save_IFS
+      test -z "$_G_dir" && _G_dir=.
+      for _G_prog_name in $_G_progs_list; do
+        for _exeext in '' .EXE; do
+          _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+          func_executable_p "$_G_path_prog" || continue
+          case `"$_G_path_prog" --version 2>&1` in
+            *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+            *)     $_G_check_func $_G_path_prog
+		   func_path_progs_result=$func_check_prog_result
+		   ;;
+          esac
+          $_G_path_prog_found && break 3
+        done
+      done
+    done
+    IFS=$_G_save_IFS
+    test -z "$func_path_progs_result" && {
+      echo "no acceptable sed could be found in \$PATH" >&2
+      exit 1
+    }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+  _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+  for _G_i in 1 2 3 4 5 6 7; do
+    _G_sed_script=$_G_sed_script$nl$_G_sed_script
+  done
+  echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+  _G_sed_script=
+
+  func_check_prog_sed ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo '' >> conftest.nl
+      "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+  rm -f conftest.sed
+  SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+  func_check_prog_grep ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    _G_path_prog_max=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo 'GREP' >> conftest.nl
+      "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+  GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables.  These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
 
 : ${CP="cp -f"}
-test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
 : ${MAKE="make"}
 : ${MKDIR="mkdir"}
 : ${MV="mv -f"}
 : ${RM="rm -f"}
 : ${SHELL="${CONFIG_SHELL-/bin/sh}"}
-: ${Xsed="$SED -e 1s/^X//"}
-
-# Global variables:
-EXIT_SUCCESS=0
-EXIT_FAILURE=1
-EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
-EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
-
-exit_status=$EXIT_SUCCESS
-
-# Make sure IFS has a sensible default
-lt_nl='
-'
-IFS=" 	$lt_nl"
 
-dirname="s,/[^/]*$,,"
-basename="s,^.*/,,"
 
-# func_dirname file append nondir_replacement
-# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
-# otherwise set result to NONDIR_REPLACEMENT.
-func_dirname ()
-{
-    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
-    if test "X$func_dirname_result" = "X${1}"; then
-      func_dirname_result="${3}"
-    else
-      func_dirname_result="$func_dirname_result${2}"
-    fi
-} # func_dirname may be replaced by extended shell implementation
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
 
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
 
-# func_basename file
-func_basename ()
-{
-    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
-} # func_basename may be replaced by extended shell implementation
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
 
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
 
-# func_dirname_and_basename file append nondir_replacement
-# perform func_basename and func_dirname in a single function
-# call:
-#   dirname:  Compute the dirname of FILE.  If nonempty,
-#             add APPEND to the result, otherwise set result
-#             to NONDIR_REPLACEMENT.
-#             value returned in "$func_dirname_result"
-#   basename: Compute filename of FILE.
-#             value retuned in "$func_basename_result"
-# Implementation must be kept synchronized with func_dirname
-# and func_basename. For efficiency, we do not delegate to
-# those functions but instead duplicate the functionality here.
-func_dirname_and_basename ()
-{
-    # Extract subdirectory from the argument.
-    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
-    if test "X$func_dirname_result" = "X${1}"; then
-      func_dirname_result="${3}"
-    else
-      func_dirname_result="$func_dirname_result${2}"
-    fi
-    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
-} # func_dirname_and_basename may be replaced by extended shell implementation
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
 
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same.  If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion.  Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'.  '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+  s/$_G_bs4/&\\
+/g
+  s/^$_G_bs2$_G_dollar/$_G_bs&/
+  s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+  s/\n//g"
 
-# func_stripname prefix suffix name
-# strip PREFIX and SUFFIX off of NAME.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-# func_strip_suffix prefix name
-func_stripname ()
-{
-    case ${2} in
-      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
-      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
-    esac
-} # func_stripname may be replaced by extended shell implementation
 
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
 
-# These SED scripts presuppose an absolute path with a trailing slash.
-pathcar='s,^/\([^/]*\).*$,\1,'
-pathcdr='s,^/[^/]*,,'
-removedotparts=':dotsl
-		s@/\./@/@g
-		t dotsl
-		s,/\.$,/,'
-collapseslashes='s@/\{1,\}@/@g'
-finalslash='s,/*$,/,'
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
 
-# func_normal_abspath PATH
-# Remove doubled-up and trailing slashes, "." path components,
-# and cancel out any ".." path components in PATH after making
-# it an absolute path.
-#             value returned in "$func_normal_abspath_result"
-func_normal_abspath ()
-{
-  # Start from root dir and reassemble the path.
-  func_normal_abspath_result=
-  func_normal_abspath_tpath=$1
-  func_normal_abspath_altnamespace=
-  case $func_normal_abspath_tpath in
-    "")
-      # Empty path, that just means $cwd.
-      func_stripname '' '/' "`pwd`"
-      func_normal_abspath_result=$func_stripname_result
-      return
-    ;;
-    # The next three entries are used to spot a run of precisely
-    # two leading slashes without using negated character classes;
-    # we take advantage of case's first-match behaviour.
-    ///*)
-      # Unusual form of absolute path, do nothing.
-    ;;
-    //*)
-      # Not necessarily an ordinary path; POSIX reserves leading '//'
-      # and for example Cygwin uses it to access remote file shares
-      # over CIFS/SMB, so we conserve a leading double slash if found.
-      func_normal_abspath_altnamespace=/
-    ;;
-    /*)
-      # Absolute path, do nothing.
-    ;;
-    *)
-      # Relative path, prepend $cwd.
-      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
-    ;;
-  esac
-  # Cancel out all the simple stuff to save iterations.  We also want
-  # the path to end with a slash for ease of parsing, so make sure
-  # there is one (and only one) here.
-  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
-        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
-  while :; do
-    # Processed it all yet?
-    if test "$func_normal_abspath_tpath" = / ; then
-      # If we ascended to the root using ".." the result may be empty now.
-      if test -z "$func_normal_abspath_result" ; then
-        func_normal_abspath_result=/
-      fi
-      break
-    fi
-    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
-        -e "$pathcar"`
-    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
-        -e "$pathcdr"`
-    # Figure out what to do with it
-    case $func_normal_abspath_tcomponent in
-      "")
-        # Trailing empty path component, ignore it.
-      ;;
-      ..)
-        # Parent dir; strip last assembled component from result.
-        func_dirname "$func_normal_abspath_result"
-        func_normal_abspath_result=$func_dirname_result
-      ;;
-      *)
-        # Actual path component, append it.
-        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
-      ;;
-    esac
-  done
-  # Restore leading double-slash if one was found on entry.
-  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
-}
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
 
-# func_relative_path SRCDIR DSTDIR
-# generates a relative path from SRCDIR to DSTDIR, with a trailing
-# slash if non-empty, suitable for immediately appending a filename
-# without needing to append a separator.
-#             value returned in "$func_relative_path_result"
-func_relative_path ()
-{
-  func_relative_path_result=
-  func_normal_abspath "$1"
-  func_relative_path_tlibdir=$func_normal_abspath_result
-  func_normal_abspath "$2"
-  func_relative_path_tbindir=$func_normal_abspath_result
-
-  # Ascend the tree starting from libdir
-  while :; do
-    # check if we have found a prefix of bindir
-    case $func_relative_path_tbindir in
-      $func_relative_path_tlibdir)
-        # found an exact match
-        func_relative_path_tcancelled=
-        break
-        ;;
-      $func_relative_path_tlibdir*)
-        # found a matching prefix
-        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
-        func_relative_path_tcancelled=$func_stripname_result
-        if test -z "$func_relative_path_result"; then
-          func_relative_path_result=.
-        fi
-        break
-        ;;
-      *)
-        func_dirname $func_relative_path_tlibdir
-        func_relative_path_tlibdir=${func_dirname_result}
-        if test "x$func_relative_path_tlibdir" = x ; then
-          # Have to descend all the way to the root!
-          func_relative_path_result=../$func_relative_path_result
-          func_relative_path_tcancelled=$func_relative_path_tbindir
-          break
-        fi
-        func_relative_path_result=../$func_relative_path_result
-        ;;
-    esac
-  done
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
 
-  # Now calculate path; take care to avoid doubling-up slashes.
-  func_stripname '' '/' "$func_relative_path_result"
-  func_relative_path_result=$func_stripname_result
-  func_stripname '/' '/' "$func_relative_path_tcancelled"
-  if test "x$func_stripname_result" != x ; then
-    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
-  fi
+# By convention, finish your script with:
+#
+#    exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
 
-  # Normalisation. If bindir is libdir, return empty string,
-  # else relative path ending with a slash; either way, target
-  # file name can be directly appended.
-  if test ! -z "$func_relative_path_result"; then
-    func_stripname './' '' "$func_relative_path_result/"
-    func_relative_path_result=$func_stripname_result
-  fi
-}
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
 
-# The name of this program:
-func_dirname_and_basename "$progpath"
-progname=$func_basename_result
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
 
-# Make sure we have an absolute path for reexecution:
+# Make sure we have an absolute progpath for reexecution:
 case $progpath in
   [\\/]*|[A-Za-z]:\\*) ;;
   *[\\/]*)
-     progdir=$func_dirname_result
+     progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
      progdir=`cd "$progdir" && pwd`
-     progpath="$progdir/$progname"
+     progpath=$progdir/$progname
      ;;
   *)
-     save_IFS="$IFS"
+     _G_IFS=$IFS
      IFS=${PATH_SEPARATOR-:}
      for progdir in $PATH; do
-       IFS="$save_IFS"
+       IFS=$_G_IFS
        test -x "$progdir/$progname" && break
      done
-     IFS="$save_IFS"
+     IFS=$_G_IFS
      test -n "$progdir" || progdir=`pwd`
-     progpath="$progdir/$progname"
+     progpath=$progdir/$progname
      ;;
 esac
 
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed="${SED}"' -e 1s/^X//'
-sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
 
-# Sed substitution that turns a string into a regex matching for the
-# string literally.
-sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
 
-# Sed substitution that converts a w32 file name or path
-# which contains forward slashes, into one that contains
-# (escaped) backslashes.  A very naive implementation.
-lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
-
-# Re-`\' parameter expansions in output of double_quote_subst that were
-# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
-# in input to double_quote_subst, that '$' was protected from expansion.
-# Since each input `\' is now two `\'s, look for any number of runs of
-# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
-bs='\\'
-bs2='\\\\'
-bs4='\\\\\\\\'
-dollar='\$'
-sed_double_backslash="\
-  s/$bs4/&\\
-/g
-  s/^$bs2$dollar/$bs&/
-  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
-  s/\n//g"
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
 
-# Standard options:
 opt_dry_run=false
-opt_help=false
 opt_quiet=false
 opt_verbose=false
-opt_warning=:
 
-# func_echo arg...
-# Echo program name prefixed message, along with the current mode
-# name if it has been set yet.
-func_echo ()
-{
-    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
-}
+# Categories 'all' and 'none' are always available.  Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
 
-# func_verbose arg...
-# Echo program name prefixed message in verbose mode only.
-func_verbose ()
-{
-    $opt_verbose && func_echo ${1+"$@"}
+# By default, display warnings according to 'opt_warning_types'.  Set
+# 'warning_func'  to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
 
-    # A bug in bash halts the script if the last line of a function
-    # fails when set -e is in force, so we need another command to
-    # work around that:
-    :
-}
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
 
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO "$*"
-}
 
-# func_error arg...
-# Echo program name prefixed message to standard error.
-func_error ()
-{
-    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
-}
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
 
-# func_warning arg...
-# Echo program name prefixed warning message to standard error.
-func_warning ()
-{
-    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
 
-    # bash bug again:
-    :
-}
 
-# func_fatal_error arg...
-# Echo program name prefixed message to standard error, and exit.
-func_fatal_error ()
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
 {
-    func_error ${1+"$@"}
-    exit $EXIT_FAILURE
-}
+    $debug_cmd
+
+    test -t 1 && {
+      # COLORTERM and USE_ANSI_COLORS environment variables take
+      # precedence, because most terminfo databases neglect to describe
+      # whether color sequences are supported.
+      test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+      if test 1 = "$USE_ANSI_COLORS"; then
+        # Standard ANSI escape sequences
+        tc_reset=''
+        tc_bold='';   tc_standout=''
+        tc_red='';   tc_green=''
+        tc_blue='';  tc_cyan=''
+      else
+        # Otherwise trust the terminfo database after all.
+        test -n "`tput sgr0 2>/dev/null`" && {
+          tc_reset=`tput sgr0`
+          test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+          tc_standout=$tc_bold
+          test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+          test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+          test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+          test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+          test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+        }
+      fi
+    }
 
-# func_fatal_help arg...
-# Echo program name prefixed message to standard error, followed by
-# a help hint, and exit.
-func_fatal_help ()
-{
-    func_error ${1+"$@"}
-    func_fatal_error "$help"
+    require_term_colors=:
 }
-help="Try \`$progname --help' for more information."  ## default
 
 
-# func_grep expression filename
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+  # We should try to minimise forks, especially on Windows where they are
+  # unreasonably slow, so skip the feature probes when bash or zsh are
+  # being used:
+  if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+    : ${_G_HAVE_ARITH_OP="yes"}
+    : ${_G_HAVE_XSI_OPS="yes"}
+    # The += operator was introduced in bash 3.1
+    case $BASH_VERSION in
+      [12].* | 3.0 | 3.0*) ;;
+      *)
+        : ${_G_HAVE_PLUSEQ_OP="yes"}
+        ;;
+    esac
+  fi
+
+  # _G_HAVE_PLUSEQ_OP
+  # Can be empty, in which case the shell is probed, "yes" if += is
+  # useable or anything else if it does not work.
+  test -z "$_G_HAVE_PLUSEQ_OP" \
+    && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+    && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_append ()
+  {
+    $debug_cmd
+
+    eval "$1+=\$2"
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_append ()
+  {
+    $debug_cmd
+
+    eval "$1=\$$1\$2"
+  }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+  eval 'func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1+=\\ \$func_quote_for_eval_result"
+  }'
+else
+  func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1=\$$1\\ \$func_quote_for_eval_result"
+  }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE.  For example:
+#
+#   func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+    $debug_cmd
+
+    eval _G_current_value='`$ECHO $'$1'`'
+    _G_delim=`expr "$2" : '\(.\)'`
+
+    case $_G_delim$_G_current_value$_G_delim in
+      *"$2$_G_delim"*) ;;
+      *) func_append "$@" ;;
+    esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+  test -z "$_G_HAVE_ARITH_OP" \
+    && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+    && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+  eval 'func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=$(( $* ))
+  }'
+else
+  func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=`expr "$@"`
+  }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  # If this shell supports suffix pattern removal, then use it to avoid
+  # forking. Hide the definitions single quotes in case the shell chokes
+  # on unsupported syntax...
+  _b='func_basename_result=${1##*/}'
+  _d='case $1 in
+        */*) func_dirname_result=${1%/*}$2 ;;
+        *  ) func_dirname_result=$3        ;;
+      esac'
+
+else
+  # ...otherwise fall back to using sed.
+  _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+  _d='func_dirname_result=`$ECHO "$1"  |$SED "$sed_dirname"`
+      if test "X$func_dirname_result" = "X$1"; then
+        func_dirname_result=$3
+      else
+        func_append func_dirname_result "$2"
+      fi'
+fi
+
+eval 'func_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+    $debug_cmd
+
+    '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+    '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    _G_infix=$1; shift
+    _G_indent=$_G_infix
+    _G_prefix="$progname: $_G_infix: "
+    _G_message=$*
+
+    # Strip color escape sequences before counting printable length
+    for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+    do
+      test -n "$_G_tc" && {
+        _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+        _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+      }
+    done
+    _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`"  " ## exclude from sc_prohibit_nested_quotes
+
+    func_echo_infix_1_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_infix_1_IFS
+      $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+      _G_prefix=$_G_indent
+    done
+    IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "  $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    $debug_cmd
+
+    func_error "$*"
+    exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
 # Check whether EXPRESSION matches any line of FILENAME, without output.
 func_grep ()
 {
+    $debug_cmd
+
     $GREP "$1" "$2" >/dev/null 2>&1
 }
 
 
-# func_mkdir_p directory-path
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+  test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=${#1}
+  }'
+else
+  func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+  }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
 # Make sure the entire path to DIRECTORY-PATH is available.
 func_mkdir_p ()
 {
-    my_directory_path="$1"
-    my_dir_list=
+    $debug_cmd
 
-    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+    _G_directory_path=$1
+    _G_dir_list=
 
-      # Protect directory names starting with `-'
-      case $my_directory_path in
-        -*) my_directory_path="./$my_directory_path" ;;
+    if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+      # Protect directory names starting with '-'
+      case $_G_directory_path in
+        -*) _G_directory_path=./$_G_directory_path ;;
       esac
 
       # While some portion of DIR does not yet exist...
-      while test ! -d "$my_directory_path"; do
+      while test ! -d "$_G_directory_path"; do
         # ...make a list in topmost first order.  Use a colon delimited
 	# list incase some portion of path contains whitespace.
-        my_dir_list="$my_directory_path:$my_dir_list"
+        _G_dir_list=$_G_directory_path:$_G_dir_list
 
         # If the last portion added has no slash in it, the list is done
-        case $my_directory_path in */*) ;; *) break ;; esac
+        case $_G_directory_path in */*) ;; *) break ;; esac
 
         # ...otherwise throw away the child directory and loop
-        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+        _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
       done
-      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+      _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
 
-      save_mkdir_p_IFS="$IFS"; IFS=':'
-      for my_dir in $my_dir_list; do
-	IFS="$save_mkdir_p_IFS"
-        # mkdir can fail with a `File exist' error if two processes
+      func_mkdir_p_IFS=$IFS; IFS=:
+      for _G_dir in $_G_dir_list; do
+	IFS=$func_mkdir_p_IFS
+        # mkdir can fail with a 'File exist' error if two processes
         # try to create one of the directories concurrently.  Don't
         # stop in that case!
-        $MKDIR "$my_dir" 2>/dev/null || :
+        $MKDIR "$_G_dir" 2>/dev/null || :
       done
-      IFS="$save_mkdir_p_IFS"
+      IFS=$func_mkdir_p_IFS
 
       # Bail out if we (or some other process) failed to create a directory.
-      test -d "$my_directory_path" || \
-        func_fatal_error "Failed to create \`$1'"
+      test -d "$_G_directory_path" || \
+        func_fatal_error "Failed to create '$1'"
     fi
 }
 
 
-# func_mktempdir [string]
+# func_mktempdir [BASENAME]
+# -------------------------
 # Make a temporary directory that won't clash with other running
 # libtool processes, and avoids race conditions if possible.  If
-# given, STRING is the basename for that directory.
+# given, BASENAME is the basename for that directory.
 func_mktempdir ()
 {
-    my_template="${TMPDIR-/tmp}/${1-$progname}"
+    $debug_cmd
+
+    _G_template=${TMPDIR-/tmp}/${1-$progname}
 
-    if test "$opt_dry_run" = ":"; then
+    if test : = "$opt_dry_run"; then
       # Return a directory name, but don't create it in dry-run mode
-      my_tmpdir="${my_template}-$$"
+      _G_tmpdir=$_G_template-$$
     else
 
       # If mktemp works, use that first and foremost
-      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+      _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
 
-      if test ! -d "$my_tmpdir"; then
+      if test ! -d "$_G_tmpdir"; then
         # Failing that, at least try and use $RANDOM to avoid a race
-        my_tmpdir="${my_template}-${RANDOM-0}$$"
+        _G_tmpdir=$_G_template-${RANDOM-0}$$
 
-        save_mktempdir_umask=`umask`
+        func_mktempdir_umask=`umask`
         umask 0077
-        $MKDIR "$my_tmpdir"
-        umask $save_mktempdir_umask
+        $MKDIR "$_G_tmpdir"
+        umask $func_mktempdir_umask
       fi
 
       # If we're not in dry-run mode, bomb out on failure
-      test -d "$my_tmpdir" || \
-        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+      test -d "$_G_tmpdir" || \
+        func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+    fi
+
+    $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+    $debug_cmd
+
+    # These SED scripts presuppose an absolute path with a trailing slash.
+    _G_pathcar='s|^/\([^/]*\).*$|\1|'
+    _G_pathcdr='s|^/[^/]*||'
+    _G_removedotparts=':dotsl
+		s|/\./|/|g
+		t dotsl
+		s|/\.$|/|'
+    _G_collapseslashes='s|/\{1,\}|/|g'
+    _G_finalslash='s|/*$|/|'
+
+    # Start from root dir and reassemble the path.
+    func_normal_abspath_result=
+    func_normal_abspath_tpath=$1
+    func_normal_abspath_altnamespace=
+    case $func_normal_abspath_tpath in
+      "")
+        # Empty path, that just means $cwd.
+        func_stripname '' '/' "`pwd`"
+        func_normal_abspath_result=$func_stripname_result
+        return
+        ;;
+      # The next three entries are used to spot a run of precisely
+      # two leading slashes without using negated character classes;
+      # we take advantage of case's first-match behaviour.
+      ///*)
+        # Unusual form of absolute path, do nothing.
+        ;;
+      //*)
+        # Not necessarily an ordinary path; POSIX reserves leading '//'
+        # and for example Cygwin uses it to access remote file shares
+        # over CIFS/SMB, so we conserve a leading double slash if found.
+        func_normal_abspath_altnamespace=/
+        ;;
+      /*)
+        # Absolute path, do nothing.
+        ;;
+      *)
+        # Relative path, prepend $cwd.
+        func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+        ;;
+    esac
+
+    # Cancel out all the simple stuff to save iterations.  We also want
+    # the path to end with a slash for ease of parsing, so make sure
+    # there is one (and only one) here.
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+    while :; do
+      # Processed it all yet?
+      if test / = "$func_normal_abspath_tpath"; then
+        # If we ascended to the root using ".." the result may be empty now.
+        if test -z "$func_normal_abspath_result"; then
+          func_normal_abspath_result=/
+        fi
+        break
+      fi
+      func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcar"`
+      func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcdr"`
+      # Figure out what to do with it
+      case $func_normal_abspath_tcomponent in
+        "")
+          # Trailing empty path component, ignore it.
+          ;;
+        ..)
+          # Parent dir; strip last assembled component from result.
+          func_dirname "$func_normal_abspath_result"
+          func_normal_abspath_result=$func_dirname_result
+          ;;
+        *)
+          # Actual path component, append it.
+          func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+          ;;
+      esac
+    done
+    # Restore leading double-slash if one was found on entry.
+    func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+    $debug_cmd
+
+    $opt_quiet || func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+    $debug_cmd
+
+    func_relative_path_result=
+    func_normal_abspath "$1"
+    func_relative_path_tlibdir=$func_normal_abspath_result
+    func_normal_abspath "$2"
+    func_relative_path_tbindir=$func_normal_abspath_result
+
+    # Ascend the tree starting from libdir
+    while :; do
+      # check if we have found a prefix of bindir
+      case $func_relative_path_tbindir in
+        $func_relative_path_tlibdir)
+          # found an exact match
+          func_relative_path_tcancelled=
+          break
+          ;;
+        $func_relative_path_tlibdir*)
+          # found a matching prefix
+          func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+          func_relative_path_tcancelled=$func_stripname_result
+          if test -z "$func_relative_path_result"; then
+            func_relative_path_result=.
+          fi
+          break
+          ;;
+        *)
+          func_dirname $func_relative_path_tlibdir
+          func_relative_path_tlibdir=$func_dirname_result
+          if test -z "$func_relative_path_tlibdir"; then
+            # Have to descend all the way to the root!
+            func_relative_path_result=../$func_relative_path_result
+            func_relative_path_tcancelled=$func_relative_path_tbindir
+            break
+          fi
+          func_relative_path_result=../$func_relative_path_result
+          ;;
+      esac
+    done
+
+    # Now calculate path; take care to avoid doubling-up slashes.
+    func_stripname '' '/' "$func_relative_path_result"
+    func_relative_path_result=$func_stripname_result
+    func_stripname '/' '/' "$func_relative_path_tcancelled"
+    if test -n "$func_stripname_result"; then
+      func_append func_relative_path_result "/$func_stripname_result"
+    fi
+
+    # Normalisation. If bindir is libdir, return '.' else relative path.
+    if test -n "$func_relative_path_result"; then
+      func_stripname './' '' "$func_relative_path_result"
+      func_relative_path_result=$func_stripname_result
     fi
 
-    $ECHO "$my_tmpdir"
+    test -n "$func_relative_path_result" || func_relative_path_result=.
+
+    :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+#   i) func_quote_for_eval_result
+#      double-quoted, suitable for a subsequent eval
+#  ii) func_quote_for_eval_unquoted_result
+#      has all characters that are still active within double
+#      quotes backslashified.
+func_quote_for_eval ()
+{
+    $debug_cmd
+
+    func_quote_for_eval_unquoted_result=
+    func_quote_for_eval_result=
+    while test 0 -lt $#; do
+      case $1 in
+        *[\\\`\"\$]*)
+	  _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+        *)
+          _G_unquoted_arg=$1 ;;
+      esac
+      if test -n "$func_quote_for_eval_unquoted_result"; then
+	func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+      else
+        func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+      fi
+
+      case $_G_unquoted_arg in
+        # Double-quote args containing shell metacharacters to delay
+        # word splitting, command substitution and variable expansion
+        # for a subsequent eval.
+        # Many Bourne shells cannot handle close brackets correctly
+        # in scan sets, so we specify it separately.
+        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+          _G_quoted_arg=\"$_G_unquoted_arg\"
+          ;;
+        *)
+          _G_quoted_arg=$_G_unquoted_arg
+	  ;;
+      esac
+
+      if test -n "$func_quote_for_eval_result"; then
+	func_append func_quote_for_eval_result " $_G_quoted_arg"
+      else
+        func_append func_quote_for_eval_result "$_G_quoted_arg"
+      fi
+      shift
+    done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    $debug_cmd
+
+    case $1 in
+      *[\\\`\"]*)
+	_G_arg=`$ECHO "$1" | $SED \
+	    -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        _G_arg=$1 ;;
+    esac
+
+    case $_G_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        _G_arg=\"$_G_arg\"
+        ;;
+    esac
+
+    func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_stripname ()
+  {
+    $debug_cmd
+
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary variable first.
+    func_stripname_result=$3
+    func_stripname_result=${func_stripname_result#"$1"}
+    func_stripname_result=${func_stripname_result%"$2"}
+  }'
+else
+  func_stripname ()
+  {
+    $debug_cmd
+
+    case $2 in
+      .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+      *)  func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+    esac
+  }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    func_quote_for_expand "$_G_cmd"
+    eval "func_notquiet $func_quote_for_expand_result"
+
+    $opt_dry_run || {
+      eval "$_G_cmd"
+      _G_status=$?
+      if test 0 -ne "$_G_status"; then
+	eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    $opt_quiet || {
+      func_quote_for_expand "$_G_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    $opt_dry_run || {
+      eval "$_G_user_locale
+	    $_G_cmd"
+      _G_status=$?
+      eval "$_G_safe_locale"
+      if test 0 -ne "$_G_status"; then
+	eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+    $debug_cmd
+
+    case $1 in
+    [0-9]* | *[!a-zA-Z0-9_]*)
+      func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+      ;;
+    * )
+      func_tr_sh_result=$1
+      ;;
+    esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $debug_cmd
+
+    $opt_verbose && func_echo "$*"
+
+    :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+    $debug_cmd
+
+    # CATEGORY must be in the warning_categories list!
+    case " $warning_categories " in
+      *" $1 "*) ;;
+      *) func_internal_error "invalid warning category '$1'" ;;
+    esac
+
+    _G_category=$1
+    shift
+
+    case " $opt_warning_types " in
+      *" $_G_category "*) $warning_func ${1+"$@"} ;;
+    esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+    $debug_cmd
+
+    printf '%s\n%s\n' "$1" "$2" \
+      | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false.  Use it like this:
+#
+#  func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+    $debug_cmd
+
+    test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2014-01-07.03; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary at gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+#   #!/bin/sh
+#   . relative/path/to/funclib.sh
+#   . relative/path/to/options-parser
+#   scriptversion=1.0
+#   func_options ${1+"$@"}
+#   eval set dummy "$func_options_result"; shift
+#   ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'.  Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+       --debug        enable verbose shell tracing
+   -W, --warnings=CATEGORY
+                      report the warnings falling in CATEGORY [all]
+   -v, --verbose      verbosely report processing
+       --version      print version information and exit
+   -h, --help         print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+       'all'          show all warnings
+       'none'         turn off all the warnings
+       'error'        warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code.  A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+    $debug_cmd
+
+    func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns.  FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not accept hook functions." ;;
+    esac
+
+    eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+    $debug_cmd
+
+    eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+    esac
+
+    eval _G_hook_fns=\$$1_hooks; shift
+
+    for _G_hook in $_G_hook_fns; do
+      eval $_G_hook '"$@"'
+
+      # store returned options list back into positional
+      # parameters for next 'cmd' execution.
+      eval _G_hook_result=\$${_G_hook}_result
+      eval set dummy "$_G_hook_result"; shift
+    done
+
+    func_quote_for_eval ${1+"$@"}
+    func_run_hooks_result=$func_quote_for_eval_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, remove any
+# options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'.  Like this:
+#
+#    my_options_prep ()
+#    {
+#        $debug_cmd
+#
+#        # Extend the existing usage message.
+#        usage_message=$usage_message'
+#      -s, --silent       don'\''t print informational messages
+#    '
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_options_prep_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_options_prep my_options_prep
+#
+#
+#    my_silent_option ()
+#    {
+#        $debug_cmd
+#
+#        # Note that for efficiency, we parse as many options as we can
+#        # recognise in a loop before passing the remainder back to the
+#        # caller on the first unrecognised argument we encounter.
+#        while test $# -gt 0; do
+#          opt=$1; shift
+#          case $opt in
+#            --silent|-s) opt_silent=: ;;
+#            # Separate non-argument short options:
+#            -s*)         func_split_short_opt "$_G_opt"
+#                         set dummy "$func_split_short_opt_name" \
+#                             "-$func_split_short_opt_arg" ${1+"$@"}
+#                         shift
+#                         ;;
+#            *)            set dummy "$_G_opt" "$*"; shift; break ;;
+#          esac
+#        done
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_silent_option_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_parse_options my_silent_option
+#
+#
+#    my_option_validation ()
+#    {
+#        $debug_cmd
+#
+#        $opt_silent && $opt_verbose && func_fatal_help "\
+#    '--silent' and '--verbose' options are mutually exclusive."
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_option_validation_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_validate_options my_option_validation
+#
+# You'll alse need to manually amend $usage_message to reflect the extra
+# options you parse.  It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+    $debug_cmd
+
+    func_options_prep ${1+"$@"}
+    eval func_parse_options \
+        ${func_options_prep_result+"$func_options_prep_result"}
+    eval func_validate_options \
+        ${func_parse_options_result+"$func_parse_options_result"}
+
+    eval func_run_hooks func_options \
+        ${func_validate_options_result+"$func_validate_options_result"}
+
+    # save modified positional parameters for caller
+    func_options_result=$func_run_hooks_result
 }
 
 
-# func_quote_for_eval arg
-# Aesthetically quote ARG to be evaled later.
-# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
-# is double-quoted, suitable for a subsequent eval, whereas
-# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
-# which are still active within double quotes backslashified.
-func_quote_for_eval ()
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters.  If a hook function modifies that list, and
+# needs to propogate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning.
+func_hookable func_options_prep
+func_options_prep ()
 {
-    case $1 in
-      *[\\\`\"\$]*)
-	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
-      *)
-        func_quote_for_eval_unquoted_result="$1" ;;
-    esac
+    $debug_cmd
 
-    case $func_quote_for_eval_unquoted_result in
-      # Double-quote args containing shell metacharacters to delay
-      # word splitting, command substitution and and variable
-      # expansion for a subsequent eval.
-      # Many Bourne shells cannot handle close brackets correctly
-      # in scan sets, so we specify it separately.
-      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
-        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
-        ;;
-      *)
-        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
-    esac
+    # Option defaults:
+    opt_verbose=false
+    opt_warning_types=
+
+    func_run_hooks func_options_prep ${1+"$@"}
+
+    # save modified positional parameters for caller
+    func_options_prep_result=$func_run_hooks_result
 }
 
 
-# func_quote_for_expand arg
-# Aesthetically quote ARG to be evaled later; same as above,
-# but do not quote variable references.
-func_quote_for_expand ()
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
 {
-    case $1 in
-      *[\\\`\"]*)
-	my_arg=`$ECHO "$1" | $SED \
-	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
-      *)
-        my_arg="$1" ;;
-    esac
+    $debug_cmd
 
-    case $my_arg in
-      # Double-quote args containing shell metacharacters to delay
-      # word splitting and command substitution for a subsequent eval.
-      # Many Bourne shells cannot handle close brackets correctly
-      # in scan sets, so we specify it separately.
-      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
-        my_arg="\"$my_arg\""
-        ;;
-    esac
+    func_parse_options_result=
 
-    func_quote_for_expand_result="$my_arg"
-}
+    # this just eases exit handling
+    while test $# -gt 0; do
+      # Defer to hook functions for initial option parsing, so they
+      # get priority in the event of reusing an option name.
+      func_run_hooks func_parse_options ${1+"$@"}
 
+      # Adjust func_parse_options positional parameters to match
+      eval set dummy "$func_run_hooks_result"; shift
 
-# func_show_eval cmd [fail_exp]
-# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
-# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
-# is given, then evaluate it.
-func_show_eval ()
-{
-    my_cmd="$1"
-    my_fail_exp="${2-:}"
+      # Break out of the loop if we already parsed every option.
+      test $# -gt 0 || break
 
-    ${opt_silent-false} || {
-      func_quote_for_expand "$my_cmd"
-      eval "func_echo $func_quote_for_expand_result"
-    }
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --debug|-x)   debug_cmd='set -x'
+                      func_echo "enabling shell trace mode"
+                      $debug_cmd
+                      ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                      set dummy --warnings none ${1+"$@"}
+                      shift
+		      ;;
 
-    if ${opt_dry_run-false}; then :; else
-      eval "$my_cmd"
-      my_status=$?
-      if test "$my_status" -eq 0; then :; else
-	eval "(exit $my_status); $my_fail_exp"
-      fi
-    fi
+        --warnings|--warning|-W)
+                      test $# = 0 && func_missing_arg $_G_opt && break
+                      case " $warning_categories $1" in
+                        *" $1 "*)
+                          # trailing space prevents matching last $1 above
+                          func_append_uniq opt_warning_types " $1"
+                          ;;
+                        *all)
+                          opt_warning_types=$warning_categories
+                          ;;
+                        *none)
+                          opt_warning_types=none
+                          warning_func=:
+                          ;;
+                        *error)
+                          opt_warning_types=$warning_categories
+                          warning_func=func_fatal_error
+                          ;;
+                        *)
+                          func_fatal_error \
+                             "unsupported warning category: '$1'"
+                          ;;
+                      esac
+                      shift
+                      ;;
+
+        --verbose|-v) opt_verbose=: ;;
+        --version)    func_version ;;
+        -\?|-h)       func_usage ;;
+        --help)       func_help ;;
+
+	# Separate optargs to long options (plugins may need this):
+	--*=*)        func_split_equals "$_G_opt"
+	              set dummy "$func_split_equals_lhs" \
+                          "$func_split_equals_rhs" ${1+"$@"}
+                      shift
+                      ;;
+
+       # Separate optargs to short options:
+        -W*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        # Separate non-argument short options:
+        -\?*|-h*|-v*|-x*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "-$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        --)           break ;;
+        -*)           func_fatal_help "unrecognised option: '$_G_opt'" ;;
+        *)            set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+      esac
+    done
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    func_parse_options_result=$func_quote_for_eval_result
 }
 
 
-# func_show_eval_locale cmd [fail_exp]
-# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
-# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
-# is given, then evaluate it.  Use the saved locale for evaluation.
-func_show_eval_locale ()
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
 {
-    my_cmd="$1"
-    my_fail_exp="${2-:}"
+    $debug_cmd
 
-    ${opt_silent-false} || {
-      func_quote_for_expand "$my_cmd"
-      eval "func_echo $func_quote_for_expand_result"
-    }
+    # Display all warnings if -W was not given.
+    test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
 
-    if ${opt_dry_run-false}; then :; else
-      eval "$lt_user_locale
-	    $my_cmd"
-      my_status=$?
-      eval "$lt_safe_locale"
-      if test "$my_status" -eq 0; then :; else
-	eval "(exit $my_status); $my_fail_exp"
-      fi
-    fi
-}
+    func_run_hooks func_validate_options ${1+"$@"}
 
-# func_tr_sh
-# Turn $1 into a string suitable for a shell variable name.
-# Result is stored in $func_tr_sh_result.  All characters
-# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
-# if $1 begins with a digit, a '_' is prepended as well.
-func_tr_sh ()
-{
-  case $1 in
-  [0-9]* | *[!a-zA-Z0-9_]*)
-    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
-    ;;
-  * )
-    func_tr_sh_result=$1
-    ;;
-  esac
+    # Bail if the options were screwed!
+    $exit_cmd $EXIT_FAILURE
+
+    # save modified positional parameters for caller
+    func_validate_options_result=$func_run_hooks_result
 }
 
 
-# func_version
-# Echo version message to standard output and exit.
-func_version ()
-{
-    $opt_debug
 
-    $SED -n '/(C)/!b go
-	:more
-	/\./!{
-	  N
-	  s/\n# / /
-	  b more
-	}
-	:go
-	/^# '$PROGRAM' (GNU /,/# warranty; / {
-        s/^# //
-	s/^# *$//
-        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
-        p
-     }' < "$progpath"
-     exit $?
-}
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
 
-# func_usage
-# Echo short help message to standard output and exit.
-func_usage ()
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
 {
-    $opt_debug
+    $debug_cmd
 
-    $SED -n '/^# Usage:/,/^#  *.*--help/ {
-        s/^# //
-	s/^# *$//
-	s/\$progname/'$progname'/
-	p
-    }' < "$progpath"
-    echo
-    $ECHO "run \`$progname --help | more' for full usage"
-    exit $?
+    eval \$ECHO \""Usage: $usage"\"
+    eval \$ECHO \""$fatal_help"\"
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
 }
 
-# func_help [NOEXIT]
-# Echo long help message to standard output and exit,
-# unless 'noexit' is passed as argument.
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
 func_help ()
 {
-    $opt_debug
-
-    $SED -n '/^# Usage:/,/# Report bugs to/ {
-	:print
-        s/^# //
-	s/^# *$//
-	s*\$progname*'$progname'*
-	s*\$host*'"$host"'*
-	s*\$SHELL*'"$SHELL"'*
-	s*\$LTCC*'"$LTCC"'*
-	s*\$LTCFLAGS*'"$LTCFLAGS"'*
-	s*\$LD*'"$LD"'*
-	s/\$with_gnu_ld/'"$with_gnu_ld"'/
-	s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
-	s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
-	p
-	d
-     }
-     /^# .* home page:/b print
-     /^# General help using/b print
-     ' < "$progpath"
-    ret=$?
-    if test -z "$1"; then
-      exit $ret
-    fi
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message"
+    exit 0
 }
 
-# func_missing_arg argname
+
+# func_missing_arg ARGNAME
+# ------------------------
 # Echo program name prefixed message to standard error and set global
 # exit_cmd.
 func_missing_arg ()
 {
-    $opt_debug
+    $debug_cmd
 
-    func_error "missing argument for $1."
+    func_error "Missing argument for '$1'."
     exit_cmd=exit
 }
 
 
-# func_split_short_opt shortopt
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=${1%%=*}
+      func_split_equals_rhs=${1#*=}
+      test "x$func_split_equals_lhs" = "x$1" \
+        && func_split_equals_rhs=
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+      func_split_equals_rhs=
+      test "x$func_split_equals_lhs" = "x$1" \
+        || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+  }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
 # Set func_split_short_opt_name and func_split_short_opt_arg shell
 # variables after splitting SHORTOPT after the 2nd character.
-func_split_short_opt ()
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_arg=${1#??}
+      func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+      func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+  }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
 {
-    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
-    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+    $debug_cmd
 
-    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
-    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
-} # func_split_short_opt may be replaced by extended shell implementation
+    func_usage_message
+    $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+    exit 0
+}
 
 
-# func_split_long_opt longopt
-# Set func_split_long_opt_name and func_split_long_opt_arg shell
-# variables after splitting LONGOPT at the `=' sign.
-func_split_long_opt ()
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
 {
-    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
-    my_sed_long_arg='1s/^--[^=]*=//'
+    $debug_cmd
 
-    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
-    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
-} # func_split_long_opt may be replaced by extended shell implementation
+    eval \$ECHO \""Usage: $usage"\"
+    echo
+    $SED -n 's|^# ||
+        /^Written by/{
+          x;p;x
+        }
+	h
+	/^Written by/q' < "$progpath"
+    echo
+    eval \$ECHO \""$usage_message"\"
+}
 
-exit_cmd=:
 
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $debug_cmd
 
+    printf '%s\n' "$progname $scriptversion"
+    $SED -n '
+        /(C)/!b go
+        :more
+        /\./!{
+          N
+          s|\n# | |
+          b more
+        }
+        :go
+        /^# Written by /,/# warranty; / {
+          s|^# ||
+          s|^# *$||
+          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+          p
+        }
+        /^# Written by / {
+          s|^# ||
+          p
+        }
+        /^warranty; /q' < "$progpath"
 
+    exit $?
+}
 
 
-magic="%%%MAGIC variable%%%"
-magic_exe="%%%MAGIC EXE variable%%%"
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
 
-# Global variables.
-nonopt=
-preserve_args=
-lo2o="s/\\.lo\$/.${objext}/"
-o2lo="s/\\.${objext}\$/.lo/"
-extracted_archives=
-extracted_serial=0
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
 
-# If this variable is set in any of the actions, the command in it
-# will be execed at the end.  This prevents here-documents from being
-# left over by shells.
-exec_cmd=
 
-# func_append var value
-# Append VALUE to the end of shell variable VAR.
-func_append ()
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
 {
-    eval "${1}=\$${1}\${2}"
-} # func_append may be replaced by extended shell implementation
+    $debug_cmd
 
-# func_append_quoted var value
-# Quote VALUE and append to the end of shell variable VAR, separated
-# by a space.
-func_append_quoted ()
-{
-    func_quote_for_eval "${2}"
-    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
-} # func_append_quoted may be replaced by extended shell implementation
+    _G_message=$*
 
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
 
-# func_arith arithmetic-term...
-func_arith ()
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
 {
-    func_arith_result=`expr "${@}"`
-} # func_arith may be replaced by extended shell implementation
+    $debug_cmd
 
+    $warning_func ${1+"$@"}
+}
 
-# func_len string
-# STRING may not start with a hyphen.
-func_len ()
-{
-    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
-} # func_len may be replaced by extended shell implementation
 
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+       --config             show all configuration variables
+       --debug              enable verbose shell tracing
+   -n, --dry-run            display commands without modifying any files
+       --features           display basic configuration information and exit
+       --mode=MODE          use operation mode MODE
+       --no-warnings        equivalent to '-Wnone'
+       --preserve-dup-deps  don't remove duplicate dependency libraries
+       --quiet, --silent    don't print informational messages
+       --tag=TAG            use configuration variables from tag TAG
+   -v, --verbose            print more informational messages than default
+       --version            print version information
+   -W, --warnings=CATEGORY  report the warnings falling in CATEGORY [all]
+   -h, --help, --help-all   print short, long, or detailed help message
+"
 
-# func_lo2o object
-func_lo2o ()
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
 {
-    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
-} # func_lo2o may be replaced by extended shell implementation
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+       clean           remove files from the build directory
+       compile         compile a source file into a libtool object
+       execute         automatically set library path, then run a program
+       finish          complete the installation of libtool libraries
+       install         install libraries or executables
+       link            create a library or an executable
+       uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+       host-triplet:   $host
+       shell:          $SHELL
+       compiler:       $LTCC
+       compiler flags: $LTCFLAGS
+       linker:         $LD (gnu? $with_gnu_ld)
+       version:        $progname $scriptversion Debian-2.4.6-2
+       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool at gnu.org>.
+GNU libtool home page: <http://www.gnu.org/s/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+    exit 0
+}
 
 
-# func_xform libobj-or-source
-func_xform ()
-{
-    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
-} # func_xform may be replaced by extended shell implementation
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_lo2o ()
+  {
+    case $1 in
+      *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+      *   ) func_lo2o_result=$1               ;;
+    esac
+  }'
+
+  # func_xform LIBOBJ-OR-SOURCE
+  # ---------------------------
+  # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+  # suffix to a '.lo' libtool-object suffix.
+  eval 'func_xform ()
+  {
+    func_xform_result=${1%.*}.lo
+  }'
+else
+  # ...otherwise fall back to using sed.
+  func_lo2o ()
+  {
+    func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+  }
+
+  func_xform ()
+  {
+    func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+  }
+fi
 
 
-# func_fatal_configuration arg...
+# func_fatal_configuration ARG...
+# -------------------------------
 # Echo program name prefixed message to standard error, followed by
 # a configuration failure hint, and exit.
 func_fatal_configuration ()
 {
-    func_error ${1+"$@"}
-    func_error "See the $PACKAGE documentation for more information."
-    func_fatal_error "Fatal configuration error."
+    func__fatal_error ${1+"$@"} \
+      "See the $PACKAGE documentation for more information." \
+      "Fatal configuration error."
 }
 
 
 # func_config
+# -----------
 # Display the configuration for all the tags in this script.
 func_config ()
 {
@@ -915,17 +2149,19 @@ func_config ()
     exit $?
 }
 
+
 # func_features
+# -------------
 # Display the features supported by this script.
 func_features ()
 {
     echo "host: $host"
-    if test "$build_libtool_libs" = yes; then
+    if test yes = "$build_libtool_libs"; then
       echo "enable shared libraries"
     else
       echo "disable shared libraries"
     fi
-    if test "$build_old_libs" = yes; then
+    if test yes = "$build_old_libs"; then
       echo "enable static libraries"
     else
       echo "disable static libraries"
@@ -934,314 +2170,350 @@ func_features ()
     exit $?
 }
 
-# func_enable_tag tagname
+
+# func_enable_tag TAGNAME
+# -----------------------
 # Verify that TAGNAME is valid, and either flag an error and exit, or
 # enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
 # variable here.
 func_enable_tag ()
 {
-  # Global variable:
-  tagname="$1"
+    # Global variable:
+    tagname=$1
 
-  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
-  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
-  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+    re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+    re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+    sed_extractcf=/$re_begincf/,/$re_endcf/p
 
-  # Validate tagname.
-  case $tagname in
-    *[!-_A-Za-z0-9,/]*)
-      func_fatal_error "invalid tag name: $tagname"
-      ;;
-  esac
+    # Validate tagname.
+    case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+        func_fatal_error "invalid tag name: $tagname"
+        ;;
+    esac
 
-  # Don't test for the "default" C tag, as we know it's
-  # there but not specially marked.
-  case $tagname in
-    CC) ;;
+    # Don't test for the "default" C tag, as we know it's
+    # there but not specially marked.
+    case $tagname in
+        CC) ;;
     *)
-      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
-	taglist="$taglist $tagname"
-
-	# Evaluate the configuration.  Be careful to quote the path
-	# and the sed script, to avoid splitting on whitespace, but
-	# also don't use non-portable quotes within backquotes within
-	# quotes we have to do it in 2 steps:
-	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
-	eval "$extractedcf"
-      else
-	func_error "ignoring unknown tag $tagname"
-      fi
-      ;;
-  esac
+        if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	  taglist="$taglist $tagname"
+
+	  # Evaluate the configuration.  Be careful to quote the path
+	  # and the sed script, to avoid splitting on whitespace, but
+	  # also don't use non-portable quotes within backquotes within
+	  # quotes we have to do it in 2 steps:
+	  extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	  eval "$extractedcf"
+        else
+	  func_error "ignoring unknown tag $tagname"
+        fi
+        ;;
+    esac
 }
 
+
 # func_check_version_match
+# ------------------------
 # Ensure that we are using m4 macros, and libtool script from the same
 # release of libtool.
 func_check_version_match ()
 {
-  if test "$package_revision" != "$macro_revision"; then
-    if test "$VERSION" != "$macro_version"; then
-      if test -z "$macro_version"; then
-        cat >&2 <<_LT_EOF
+    if test "$package_revision" != "$macro_revision"; then
+      if test "$VERSION" != "$macro_version"; then
+        if test -z "$macro_version"; then
+          cat >&2 <<_LT_EOF
 $progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
 $progname: definition of this LT_INIT comes from an older release.
 $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
 $progname: and run autoconf again.
 _LT_EOF
-      else
-        cat >&2 <<_LT_EOF
+        else
+          cat >&2 <<_LT_EOF
 $progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
 $progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
 $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
 $progname: and run autoconf again.
 _LT_EOF
-      fi
-    else
-      cat >&2 <<_LT_EOF
+        fi
+      else
+        cat >&2 <<_LT_EOF
 $progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
 $progname: but the definition of this LT_INIT comes from revision $macro_revision.
 $progname: You should recreate aclocal.m4 with macros from revision $package_revision
 $progname: of $PACKAGE $VERSION and run autoconf again.
 _LT_EOF
-    fi
+      fi
 
-    exit $EXIT_MISMATCH
-  fi
+      exit $EXIT_MISMATCH
+    fi
 }
 
 
-# Shorthand for --mode=foo, only valid as the first argument
-case $1 in
-clean|clea|cle|cl)
-  shift; set dummy --mode clean ${1+"$@"}; shift
-  ;;
-compile|compil|compi|comp|com|co|c)
-  shift; set dummy --mode compile ${1+"$@"}; shift
-  ;;
-execute|execut|execu|exec|exe|ex|e)
-  shift; set dummy --mode execute ${1+"$@"}; shift
-  ;;
-finish|finis|fini|fin|fi|f)
-  shift; set dummy --mode finish ${1+"$@"}; shift
-  ;;
-install|instal|insta|inst|ins|in|i)
-  shift; set dummy --mode install ${1+"$@"}; shift
-  ;;
-link|lin|li|l)
-  shift; set dummy --mode link ${1+"$@"}; shift
-  ;;
-uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
-  shift; set dummy --mode uninstall ${1+"$@"}; shift
-  ;;
-esac
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+    $debug_mode
 
+    # Option defaults:
+    opt_config=false
+    opt_dlopen=
+    opt_dry_run=false
+    opt_help=false
+    opt_mode=
+    opt_preserve_dup_deps=false
+    opt_quiet=false
 
+    nonopt=
+    preserve_args=
 
-# Option defaults:
-opt_debug=:
-opt_dry_run=false
-opt_config=false
-opt_preserve_dup_deps=false
-opt_features=false
-opt_finish=false
-opt_help=false
-opt_help_all=false
-opt_silent=:
-opt_warning=:
-opt_verbose=:
-opt_silent=false
-opt_verbose=false
+    # Shorthand for --mode=foo, only valid as the first argument
+    case $1 in
+    clean|clea|cle|cl)
+      shift; set dummy --mode clean ${1+"$@"}; shift
+      ;;
+    compile|compil|compi|comp|com|co|c)
+      shift; set dummy --mode compile ${1+"$@"}; shift
+      ;;
+    execute|execut|execu|exec|exe|ex|e)
+      shift; set dummy --mode execute ${1+"$@"}; shift
+      ;;
+    finish|finis|fini|fin|fi|f)
+      shift; set dummy --mode finish ${1+"$@"}; shift
+      ;;
+    install|instal|insta|inst|ins|in|i)
+      shift; set dummy --mode install ${1+"$@"}; shift
+      ;;
+    link|lin|li|l)
+      shift; set dummy --mode link ${1+"$@"}; shift
+      ;;
+    uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+      shift; set dummy --mode uninstall ${1+"$@"}; shift
+      ;;
+    esac
+
+    # Pass back the list of options.
+    func_quote_for_eval ${1+"$@"}
+    libtool_options_prep_result=$func_quote_for_eval_result
+}
+func_add_hook func_options_prep libtool_options_prep
 
 
-# Parse options once, thoroughly.  This comes as soon as possible in the
-# script to make things like `--version' happen as quickly as we can.
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
 {
-  # this just eases exit handling
-  while test $# -gt 0; do
-    opt="$1"
-    shift
-    case $opt in
-      --debug|-x)	opt_debug='set -x'
-			func_echo "enabling shell trace mode"
-			$opt_debug
-			;;
-      --dry-run|--dryrun|-n)
-			opt_dry_run=:
-			;;
-      --config)
-			opt_config=:
-func_config
-			;;
-      --dlopen|-dlopen)
-			optarg="$1"
-			opt_dlopen="${opt_dlopen+$opt_dlopen
-}$optarg"
-			shift
-			;;
-      --preserve-dup-deps)
-			opt_preserve_dup_deps=:
-			;;
-      --features)
-			opt_features=:
-func_features
-			;;
-      --finish)
-			opt_finish=:
-set dummy --mode finish ${1+"$@"}; shift
-			;;
-      --help)
-			opt_help=:
-			;;
-      --help-all)
-			opt_help_all=:
-opt_help=': help-all'
-			;;
-      --mode)
-			test $# = 0 && func_missing_arg $opt && break
-			optarg="$1"
-			opt_mode="$optarg"
-case $optarg in
-  # Valid mode arguments:
-  clean|compile|execute|finish|install|link|relink|uninstall) ;;
-
-  # Catch anything else as an error
-  *) func_error "invalid argument for $opt"
-     exit_cmd=exit
-     break
-     ;;
-esac
-			shift
-			;;
-      --no-silent|--no-quiet)
-			opt_silent=false
-func_append preserve_args " $opt"
-			;;
-      --no-warning|--no-warn)
-			opt_warning=false
-func_append preserve_args " $opt"
-			;;
-      --no-verbose)
-			opt_verbose=false
-func_append preserve_args " $opt"
-			;;
-      --silent|--quiet)
-			opt_silent=:
-func_append preserve_args " $opt"
-        opt_verbose=false
-			;;
-      --verbose|-v)
-			opt_verbose=:
-func_append preserve_args " $opt"
-opt_silent=false
-			;;
-      --tag)
-			test $# = 0 && func_missing_arg $opt && break
-			optarg="$1"
-			opt_tag="$optarg"
-func_append preserve_args " $opt $optarg"
-func_enable_tag "$optarg"
-			shift
-			;;
-
-      -\?|-h)		func_usage				;;
-      --help)		func_help				;;
-      --version)	func_version				;;
-
-      # Separate optargs to long options:
-      --*=*)
-			func_split_long_opt "$opt"
-			set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
-			shift
-			;;
-
-      # Separate non-argument short options:
-      -\?*|-h*|-n*|-v*)
-			func_split_short_opt "$opt"
-			set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
-			shift
-			;;
-
-      --)		break					;;
-      -*)		func_fatal_help "unrecognized option \`$opt'" ;;
-      *)		set dummy "$opt" ${1+"$@"};	shift; break  ;;
-    esac
-  done
+    $debug_cmd
 
-  # Validate options:
+    # Perform our own loop to consume as many options as possible in
+    # each iteration.
+    while test $# -gt 0; do
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --dry-run|--dryrun|-n)
+                        opt_dry_run=:
+                        ;;
+
+        --config)       func_config ;;
+
+        --dlopen|-dlopen)
+                        opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+                        shift
+                        ;;
+
+        --preserve-dup-deps)
+                        opt_preserve_dup_deps=: ;;
+
+        --features)     func_features ;;
+
+        --finish)       set dummy --mode finish ${1+"$@"}; shift ;;
+
+        --help)         opt_help=: ;;
+
+        --help-all)     opt_help=': help-all' ;;
+
+        --mode)         test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_mode=$1
+                        case $1 in
+                          # Valid mode arguments:
+                          clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+                          # Catch anything else as an error
+                          *) func_error "invalid argument for $_G_opt"
+                             exit_cmd=exit
+                             break
+                             ;;
+                        esac
+                        shift
+                        ;;
+
+        --no-silent|--no-quiet)
+                        opt_quiet=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                        opt_warning=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-verbose)
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --silent|--quiet)
+                        opt_quiet=:
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --tag)          test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_tag=$1
+                        func_append preserve_args " $_G_opt $1"
+                        func_enable_tag "$1"
+                        shift
+                        ;;
+
+        --verbose|-v)   opt_quiet=false
+                        opt_verbose=:
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+	# An option not handled by this hook function:
+        *)		set dummy "$_G_opt" ${1+"$@"};	shift; break  ;;
+      esac
+    done
 
-  # save first non-option argument
-  if test "$#" -gt 0; then
-    nonopt="$opt"
-    shift
-  fi
 
-  # preserve --debug
-  test "$opt_debug" = : || func_append preserve_args " --debug"
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    libtool_parse_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_parse_options libtool_parse_options
 
-  case $host in
-    *cygwin* | *mingw* | *pw32* | *cegcc*)
-      # don't eliminate duplications in $postdeps and $predeps
-      opt_duplicate_compiler_generated_deps=:
-      ;;
-    *)
-      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
-      ;;
-  esac
 
-  $opt_help || {
-    # Sanity checks first:
-    func_check_version_match
 
-    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
-      func_fatal_configuration "not configured to build any kind of library"
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+    # save first non-option argument
+    if test 0 -lt $#; then
+      nonopt=$1
+      shift
     fi
 
-    # Darwin sucks
-    eval std_shrext=\"$shrext_cmds\"
+    # preserve --debug
+    test : = "$debug_cmd" || func_append preserve_args " --debug"
 
-    # Only execute mode is allowed to have -dlopen flags.
-    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
-      func_error "unrecognized option \`-dlopen'"
-      $ECHO "$help" 1>&2
-      exit $EXIT_FAILURE
-    fi
+    case $host in
+      # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+      # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+      *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+        # don't eliminate duplications in $postdeps and $predeps
+        opt_duplicate_compiler_generated_deps=:
+        ;;
+      *)
+        opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+        ;;
+    esac
 
-    # Change the help message to a mode-specific one.
-    generic_help="$help"
-    help="Try \`$progname --help --mode=$opt_mode' for more information."
-  }
+    $opt_help || {
+      # Sanity checks first:
+      func_check_version_match
+
+      test yes != "$build_libtool_libs" \
+        && test yes != "$build_old_libs" \
+        && func_fatal_configuration "not configured to build any kind of library"
+
+      # Darwin sucks
+      eval std_shrext=\"$shrext_cmds\"
+
+      # Only execute mode is allowed to have -dlopen flags.
+      if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+        func_error "unrecognized option '-dlopen'"
+        $ECHO "$help" 1>&2
+        exit $EXIT_FAILURE
+      fi
 
+      # Change the help message to a mode-specific one.
+      generic_help=$help
+      help="Try '$progname --help --mode=$opt_mode' for more information."
+    }
 
-  # Bail if the options were screwed
-  $exit_cmd $EXIT_FAILURE
+    # Pass back the unparsed argument list
+    func_quote_for_eval ${1+"$@"}
+    libtool_validate_options_result=$func_quote_for_eval_result
 }
+func_add_hook func_validate_options libtool_validate_options
 
 
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
 
 
 ## ----------- ##
 ##    Main.    ##
 ## ----------- ##
 
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+  $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
 # func_lalib_p file
-# True iff FILE is a libtool `.la' library or `.lo' object file.
+# True iff FILE is a libtool '.la' library or '.lo' object file.
 # This function is only a basic sanity check; it will hardly flush out
 # determined imposters.
 func_lalib_p ()
 {
     test -f "$1" &&
-      $SED -e 4q "$1" 2>/dev/null \
-        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+      $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
 }
 
 # func_lalib_unsafe_p file
-# True iff FILE is a libtool `.la' library or `.lo' object file.
+# True iff FILE is a libtool '.la' library or '.lo' object file.
 # This function implements the same check as func_lalib_p without
 # resorting to external programs.  To this end, it redirects stdin and
 # closes it afterwards, without saving the original file descriptor.
 # As a safety measure, use it only where a negative result would be
-# fatal anyway.  Works if `file' does not exist.
+# fatal anyway.  Works if 'file' does not exist.
 func_lalib_unsafe_p ()
 {
     lalib_p=no
@@ -1249,13 +2521,13 @@ func_lalib_unsafe_p ()
 	for lalib_p_l in 1 2 3 4
 	do
 	    read lalib_p_line
-	    case "$lalib_p_line" in
+	    case $lalib_p_line in
 		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
 	    esac
 	done
 	exec 0<&5 5<&-
     fi
-    test "$lalib_p" = yes
+    test yes = "$lalib_p"
 }
 
 # func_ltwrapper_script_p file
@@ -1264,7 +2536,8 @@ func_lalib_unsafe_p ()
 # determined imposters.
 func_ltwrapper_script_p ()
 {
-    func_lalib_p "$1"
+    test -f "$1" &&
+      $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
 }
 
 # func_ltwrapper_executable_p file
@@ -1289,7 +2562,7 @@ func_ltwrapper_scriptname ()
 {
     func_dirname_and_basename "$1" "" "."
     func_stripname '' '.exe' "$func_basename_result"
-    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+    func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
 }
 
 # func_ltwrapper_p file
@@ -1308,11 +2581,13 @@ func_ltwrapper_p ()
 # FAIL_CMD may read-access the current command in variable CMD!
 func_execute_cmds ()
 {
-    $opt_debug
+    $debug_cmd
+
     save_ifs=$IFS; IFS='~'
     for cmd in $1; do
-      IFS=$save_ifs
+      IFS=$sp$nl
       eval cmd=\"$cmd\"
+      IFS=$save_ifs
       func_show_eval "$cmd" "${2-:}"
     done
     IFS=$save_ifs
@@ -1324,10 +2599,11 @@ func_execute_cmds ()
 # Note that it is not necessary on cygwin/mingw to append a dot to
 # FILE even if both FILE and FILE.exe exist: automatic-append-.exe
 # behavior happens only for exec(3), not for open(2)!  Also, sourcing
-# `FILE.' does not work on cygwin managed mounts.
+# 'FILE.' does not work on cygwin managed mounts.
 func_source ()
 {
-    $opt_debug
+    $debug_cmd
+
     case $1 in
     */* | *\\*)	. "$1" ;;
     *)		. "./$1" ;;
@@ -1354,10 +2630,10 @@ func_resolve_sysroot ()
 # store the result into func_replace_sysroot_result.
 func_replace_sysroot ()
 {
-  case "$lt_sysroot:$1" in
+  case $lt_sysroot:$1 in
   ?*:"$lt_sysroot"*)
     func_stripname "$lt_sysroot" '' "$1"
-    func_replace_sysroot_result="=$func_stripname_result"
+    func_replace_sysroot_result='='$func_stripname_result
     ;;
   *)
     # Including no sysroot.
@@ -1374,7 +2650,8 @@ func_replace_sysroot ()
 # arg is usually of the form 'gcc ...'
 func_infer_tag ()
 {
-    $opt_debug
+    $debug_cmd
+
     if test -n "$available_tags" && test -z "$tagname"; then
       CC_quoted=
       for arg in $CC; do
@@ -1393,7 +2670,7 @@ func_infer_tag ()
 	for z in $available_tags; do
 	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
 	    # Evaluate the configuration.
-	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
 	    CC_quoted=
 	    for arg in $CC; do
 	      # Double-quote args containing other shell metacharacters.
@@ -1418,7 +2695,7 @@ func_infer_tag ()
 	# line option must be used.
 	if test -z "$tagname"; then
 	  func_echo "unable to infer tagged configuration"
-	  func_fatal_error "specify a tag with \`--tag'"
+	  func_fatal_error "specify a tag with '--tag'"
 #	else
 #	  func_verbose "using $tagname tagged configuration"
 	fi
@@ -1434,15 +2711,15 @@ func_infer_tag ()
 # but don't create it if we're doing a dry run.
 func_write_libtool_object ()
 {
-    write_libobj=${1}
-    if test "$build_libtool_libs" = yes; then
-      write_lobj=\'${2}\'
+    write_libobj=$1
+    if test yes = "$build_libtool_libs"; then
+      write_lobj=\'$2\'
     else
       write_lobj=none
     fi
 
-    if test "$build_old_libs" = yes; then
-      write_oldobj=\'${3}\'
+    if test yes = "$build_old_libs"; then
+      write_oldobj=\'$3\'
     else
       write_oldobj=none
     fi
@@ -1450,7 +2727,7 @@ func_write_libtool_object ()
     $opt_dry_run || {
       cat >${write_libobj}T <<EOF
 # $write_libobj - a libtool object file
-# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
 #
 # Please DO NOT delete this file!
 # It is necessary for linking the library.
@@ -1462,7 +2739,7 @@ pic_object=$write_lobj
 non_pic_object=$write_oldobj
 
 EOF
-      $MV "${write_libobj}T" "${write_libobj}"
+      $MV "${write_libobj}T" "$write_libobj"
     }
 }
 
@@ -1482,8 +2759,9 @@ EOF
 # be empty on error (or when ARG is empty)
 func_convert_core_file_wine_to_w32 ()
 {
-  $opt_debug
-  func_convert_core_file_wine_to_w32_result="$1"
+  $debug_cmd
+
+  func_convert_core_file_wine_to_w32_result=$1
   if test -n "$1"; then
     # Unfortunately, winepath does not exit with a non-zero error code, so we
     # are forced to check the contents of stdout. On the other hand, if the
@@ -1491,9 +2769,9 @@ func_convert_core_file_wine_to_w32 ()
     # *an error message* to stdout. So we must check for both error code of
     # zero AND non-empty stdout, which explains the odd construction:
     func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
-    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+    if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
       func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
-        $SED -e "$lt_sed_naive_backslashify"`
+        $SED -e "$sed_naive_backslashify"`
     else
       func_convert_core_file_wine_to_w32_result=
     fi
@@ -1514,18 +2792,19 @@ func_convert_core_file_wine_to_w32 ()
 # are convertible, then the result may be empty.
 func_convert_core_path_wine_to_w32 ()
 {
-  $opt_debug
+  $debug_cmd
+
   # unfortunately, winepath doesn't convert paths, only file names
-  func_convert_core_path_wine_to_w32_result=""
+  func_convert_core_path_wine_to_w32_result=
   if test -n "$1"; then
     oldIFS=$IFS
     IFS=:
     for func_convert_core_path_wine_to_w32_f in $1; do
       IFS=$oldIFS
       func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
-      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+      if test -n "$func_convert_core_file_wine_to_w32_result"; then
         if test -z "$func_convert_core_path_wine_to_w32_result"; then
-          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+          func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
         else
           func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
         fi
@@ -1554,7 +2833,8 @@ func_convert_core_path_wine_to_w32 ()
 # environment variable; do not put it in $PATH.
 func_cygpath ()
 {
-  $opt_debug
+  $debug_cmd
+
   if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
     func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
     if test "$?" -ne 0; then
@@ -1563,7 +2843,7 @@ func_cygpath ()
     fi
   else
     func_cygpath_result=
-    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+    func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
   fi
 }
 #end: func_cygpath
@@ -1574,10 +2854,11 @@ func_cygpath ()
 # result in func_convert_core_msys_to_w32_result.
 func_convert_core_msys_to_w32 ()
 {
-  $opt_debug
+  $debug_cmd
+
   # awkward: cmd appends spaces to result
   func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
-    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+    $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
 }
 #end: func_convert_core_msys_to_w32
 
@@ -1588,13 +2869,14 @@ func_convert_core_msys_to_w32 ()
 # func_to_host_file_result to ARG1).
 func_convert_file_check ()
 {
-  $opt_debug
-  if test -z "$2" && test -n "$1" ; then
+  $debug_cmd
+
+  if test -z "$2" && test -n "$1"; then
     func_error "Could not determine host file name corresponding to"
-    func_error "  \`$1'"
+    func_error "  '$1'"
     func_error "Continuing, but uninstalled executables may not work."
     # Fallback:
-    func_to_host_file_result="$1"
+    func_to_host_file_result=$1
   fi
 }
 # end func_convert_file_check
@@ -1606,10 +2888,11 @@ func_convert_file_check ()
 # func_to_host_file_result to a simplistic fallback value (see below).
 func_convert_path_check ()
 {
-  $opt_debug
+  $debug_cmd
+
   if test -z "$4" && test -n "$3"; then
     func_error "Could not determine the host path corresponding to"
-    func_error "  \`$3'"
+    func_error "  '$3'"
     func_error "Continuing, but uninstalled executables may not work."
     # Fallback.  This is a deliberately simplistic "conversion" and
     # should not be "improved".  See libtool.info.
@@ -1618,7 +2901,7 @@ func_convert_path_check ()
       func_to_host_path_result=`echo "$3" |
         $SED -e "$lt_replace_pathsep_chars"`
     else
-      func_to_host_path_result="$3"
+      func_to_host_path_result=$3
     fi
   fi
 }
@@ -1630,9 +2913,10 @@ func_convert_path_check ()
 # and appending REPL if ORIG matches BACKPAT.
 func_convert_path_front_back_pathsep ()
 {
-  $opt_debug
+  $debug_cmd
+
   case $4 in
-  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+  $1 ) func_to_host_path_result=$3$func_to_host_path_result
     ;;
   esac
   case $4 in
@@ -1646,7 +2930,7 @@ func_convert_path_front_back_pathsep ()
 ##################################################
 # $build to $host FILE NAME CONVERSION FUNCTIONS #
 ##################################################
-# invoked via `$to_host_file_cmd ARG'
+# invoked via '$to_host_file_cmd ARG'
 #
 # In each case, ARG is the path to be converted from $build to $host format.
 # Result will be available in $func_to_host_file_result.
@@ -1657,7 +2941,8 @@ func_convert_path_front_back_pathsep ()
 # in func_to_host_file_result.
 func_to_host_file ()
 {
-  $opt_debug
+  $debug_cmd
+
   $to_host_file_cmd "$1"
 }
 # end func_to_host_file
@@ -1669,7 +2954,8 @@ func_to_host_file ()
 # in (the comma separated) LAZY, no conversion takes place.
 func_to_tool_file ()
 {
-  $opt_debug
+  $debug_cmd
+
   case ,$2, in
     *,"$to_tool_file_cmd",*)
       func_to_tool_file_result=$1
@@ -1687,7 +2973,7 @@ func_to_tool_file ()
 # Copy ARG to func_to_host_file_result.
 func_convert_file_noop ()
 {
-  func_to_host_file_result="$1"
+  func_to_host_file_result=$1
 }
 # end func_convert_file_noop
 
@@ -1698,11 +2984,12 @@ func_convert_file_noop ()
 # func_to_host_file_result.
 func_convert_file_msys_to_w32 ()
 {
-  $opt_debug
-  func_to_host_file_result="$1"
+  $debug_cmd
+
+  func_to_host_file_result=$1
   if test -n "$1"; then
     func_convert_core_msys_to_w32 "$1"
-    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result=$func_convert_core_msys_to_w32_result
   fi
   func_convert_file_check "$1" "$func_to_host_file_result"
 }
@@ -1714,8 +3001,9 @@ func_convert_file_msys_to_w32 ()
 # func_to_host_file_result.
 func_convert_file_cygwin_to_w32 ()
 {
-  $opt_debug
-  func_to_host_file_result="$1"
+  $debug_cmd
+
+  func_to_host_file_result=$1
   if test -n "$1"; then
     # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
     # LT_CYGPATH in this case.
@@ -1731,11 +3019,12 @@ func_convert_file_cygwin_to_w32 ()
 # and a working winepath. Returns result in func_to_host_file_result.
 func_convert_file_nix_to_w32 ()
 {
-  $opt_debug
-  func_to_host_file_result="$1"
+  $debug_cmd
+
+  func_to_host_file_result=$1
   if test -n "$1"; then
     func_convert_core_file_wine_to_w32 "$1"
-    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
   fi
   func_convert_file_check "$1" "$func_to_host_file_result"
 }
@@ -1747,12 +3036,13 @@ func_convert_file_nix_to_w32 ()
 # Returns result in func_to_host_file_result.
 func_convert_file_msys_to_cygwin ()
 {
-  $opt_debug
-  func_to_host_file_result="$1"
+  $debug_cmd
+
+  func_to_host_file_result=$1
   if test -n "$1"; then
     func_convert_core_msys_to_w32 "$1"
     func_cygpath -u "$func_convert_core_msys_to_w32_result"
-    func_to_host_file_result="$func_cygpath_result"
+    func_to_host_file_result=$func_cygpath_result
   fi
   func_convert_file_check "$1" "$func_to_host_file_result"
 }
@@ -1765,13 +3055,14 @@ func_convert_file_msys_to_cygwin ()
 # in func_to_host_file_result.
 func_convert_file_nix_to_cygwin ()
 {
-  $opt_debug
-  func_to_host_file_result="$1"
+  $debug_cmd
+
+  func_to_host_file_result=$1
   if test -n "$1"; then
     # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
     func_convert_core_file_wine_to_w32 "$1"
     func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
-    func_to_host_file_result="$func_cygpath_result"
+    func_to_host_file_result=$func_cygpath_result
   fi
   func_convert_file_check "$1" "$func_to_host_file_result"
 }
@@ -1781,7 +3072,7 @@ func_convert_file_nix_to_cygwin ()
 #############################################
 # $build to $host PATH CONVERSION FUNCTIONS #
 #############################################
-# invoked via `$to_host_path_cmd ARG'
+# invoked via '$to_host_path_cmd ARG'
 #
 # In each case, ARG is the path to be converted from $build to $host format.
 # The result will be available in $func_to_host_path_result.
@@ -1805,10 +3096,11 @@ func_convert_file_nix_to_cygwin ()
 to_host_path_cmd=
 func_init_to_host_path_cmd ()
 {
-  $opt_debug
+  $debug_cmd
+
   if test -z "$to_host_path_cmd"; then
     func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
-    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+    to_host_path_cmd=func_convert_path_$func_stripname_result
   fi
 }
 
@@ -1818,7 +3110,8 @@ func_init_to_host_path_cmd ()
 # in func_to_host_path_result.
 func_to_host_path ()
 {
-  $opt_debug
+  $debug_cmd
+
   func_init_to_host_path_cmd
   $to_host_path_cmd "$1"
 }
@@ -1829,7 +3122,7 @@ func_to_host_path ()
 # Copy ARG to func_to_host_path_result.
 func_convert_path_noop ()
 {
-  func_to_host_path_result="$1"
+  func_to_host_path_result=$1
 }
 # end func_convert_path_noop
 
@@ -1840,8 +3133,9 @@ func_convert_path_noop ()
 # func_to_host_path_result.
 func_convert_path_msys_to_w32 ()
 {
-  $opt_debug
-  func_to_host_path_result="$1"
+  $debug_cmd
+
+  func_to_host_path_result=$1
   if test -n "$1"; then
     # Remove leading and trailing path separator characters from ARG.  MSYS
     # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
@@ -1849,7 +3143,7 @@ func_convert_path_msys_to_w32 ()
     func_stripname : : "$1"
     func_to_host_path_tmp1=$func_stripname_result
     func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
-    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result=$func_convert_core_msys_to_w32_result
     func_convert_path_check : ";" \
       "$func_to_host_path_tmp1" "$func_to_host_path_result"
     func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
@@ -1863,8 +3157,9 @@ func_convert_path_msys_to_w32 ()
 # func_to_host_file_result.
 func_convert_path_cygwin_to_w32 ()
 {
-  $opt_debug
-  func_to_host_path_result="$1"
+  $debug_cmd
+
+  func_to_host_path_result=$1
   if test -n "$1"; then
     # See func_convert_path_msys_to_w32:
     func_stripname : : "$1"
@@ -1883,14 +3178,15 @@ func_convert_path_cygwin_to_w32 ()
 # a working winepath.  Returns result in func_to_host_file_result.
 func_convert_path_nix_to_w32 ()
 {
-  $opt_debug
-  func_to_host_path_result="$1"
+  $debug_cmd
+
+  func_to_host_path_result=$1
   if test -n "$1"; then
     # See func_convert_path_msys_to_w32:
     func_stripname : : "$1"
     func_to_host_path_tmp1=$func_stripname_result
     func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
-    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
     func_convert_path_check : ";" \
       "$func_to_host_path_tmp1" "$func_to_host_path_result"
     func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
@@ -1904,15 +3200,16 @@ func_convert_path_nix_to_w32 ()
 # Returns result in func_to_host_file_result.
 func_convert_path_msys_to_cygwin ()
 {
-  $opt_debug
-  func_to_host_path_result="$1"
+  $debug_cmd
+
+  func_to_host_path_result=$1
   if test -n "$1"; then
     # See func_convert_path_msys_to_w32:
     func_stripname : : "$1"
     func_to_host_path_tmp1=$func_stripname_result
     func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
     func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
-    func_to_host_path_result="$func_cygpath_result"
+    func_to_host_path_result=$func_cygpath_result
     func_convert_path_check : : \
       "$func_to_host_path_tmp1" "$func_to_host_path_result"
     func_convert_path_front_back_pathsep ":*" "*:" : "$1"
@@ -1927,8 +3224,9 @@ func_convert_path_msys_to_cygwin ()
 # func_to_host_file_result.
 func_convert_path_nix_to_cygwin ()
 {
-  $opt_debug
-  func_to_host_path_result="$1"
+  $debug_cmd
+
+  func_to_host_path_result=$1
   if test -n "$1"; then
     # Remove leading and trailing path separator characters from
     # ARG. msys behavior is inconsistent here, cygpath turns them
@@ -1937,7 +3235,7 @@ func_convert_path_nix_to_cygwin ()
     func_to_host_path_tmp1=$func_stripname_result
     func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
     func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
-    func_to_host_path_result="$func_cygpath_result"
+    func_to_host_path_result=$func_cygpath_result
     func_convert_path_check : : \
       "$func_to_host_path_tmp1" "$func_to_host_path_result"
     func_convert_path_front_back_pathsep ":*" "*:" : "$1"
@@ -1946,13 +3244,31 @@ func_convert_path_nix_to_cygwin ()
 # end func_convert_path_nix_to_cygwin
 
 
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+  $debug_cmd
+
+  func_dll_def_p_tmp=`$SED -n \
+    -e 's/^[	 ]*//' \
+    -e '/^\(;.*\)*$/d' \
+    -e 's/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p' \
+    -e q \
+    "$1"`
+  test DEF = "$func_dll_def_p_tmp"
+}
+
+
 # func_mode_compile arg...
 func_mode_compile ()
 {
-    $opt_debug
+    $debug_cmd
+
     # Get the compilation command and the source file.
     base_compile=
-    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    srcfile=$nonopt  #  always keep a non-empty value in "srcfile"
     suppress_opt=yes
     suppress_output=
     arg_mode=normal
@@ -1965,12 +3281,12 @@ func_mode_compile ()
       case $arg_mode in
       arg  )
 	# do not "continue".  Instead, add this to base_compile
-	lastarg="$arg"
+	lastarg=$arg
 	arg_mode=normal
 	;;
 
       target )
-	libobj="$arg"
+	libobj=$arg
 	arg_mode=normal
 	continue
 	;;
@@ -1980,7 +3296,7 @@ func_mode_compile ()
 	case $arg in
 	-o)
 	  test -n "$libobj" && \
-	    func_fatal_error "you cannot specify \`-o' more than once"
+	    func_fatal_error "you cannot specify '-o' more than once"
 	  arg_mode=target
 	  continue
 	  ;;
@@ -2009,12 +3325,12 @@ func_mode_compile ()
 	  func_stripname '-Wc,' '' "$arg"
 	  args=$func_stripname_result
 	  lastarg=
-	  save_ifs="$IFS"; IFS=','
+	  save_ifs=$IFS; IFS=,
 	  for arg in $args; do
-	    IFS="$save_ifs"
+	    IFS=$save_ifs
 	    func_append_quoted lastarg "$arg"
 	  done
-	  IFS="$save_ifs"
+	  IFS=$save_ifs
 	  func_stripname ' ' '' "$lastarg"
 	  lastarg=$func_stripname_result
 
@@ -2027,8 +3343,8 @@ func_mode_compile ()
 	  # Accept the current argument as the source file.
 	  # The previous "srcfile" becomes the current argument.
 	  #
-	  lastarg="$srcfile"
-	  srcfile="$arg"
+	  lastarg=$srcfile
+	  srcfile=$arg
 	  ;;
 	esac  #  case $arg
 	;;
@@ -2043,13 +3359,13 @@ func_mode_compile ()
       func_fatal_error "you must specify an argument for -Xcompile"
       ;;
     target)
-      func_fatal_error "you must specify a target with \`-o'"
+      func_fatal_error "you must specify a target with '-o'"
       ;;
     *)
       # Get the name of the library object.
       test -z "$libobj" && {
 	func_basename "$srcfile"
-	libobj="$func_basename_result"
+	libobj=$func_basename_result
       }
       ;;
     esac
@@ -2069,7 +3385,7 @@ func_mode_compile ()
     case $libobj in
     *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
     *)
-      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      func_fatal_error "cannot determine name of library object from '$libobj'"
       ;;
     esac
 
@@ -2078,8 +3394,8 @@ func_mode_compile ()
     for arg in $later; do
       case $arg in
       -shared)
-	test "$build_libtool_libs" != yes && \
-	  func_fatal_configuration "can not build a shared library"
+	test yes = "$build_libtool_libs" \
+	  || func_fatal_configuration "cannot build a shared library"
 	build_old_libs=no
 	continue
 	;;
@@ -2105,17 +3421,17 @@ func_mode_compile ()
     func_quote_for_eval "$libobj"
     test "X$libobj" != "X$func_quote_for_eval_result" \
       && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
-      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+      && func_warning "libobj name '$libobj' may not contain shell special characters."
     func_dirname_and_basename "$obj" "/" ""
-    objname="$func_basename_result"
-    xdir="$func_dirname_result"
-    lobj=${xdir}$objdir/$objname
+    objname=$func_basename_result
+    xdir=$func_dirname_result
+    lobj=$xdir$objdir/$objname
 
     test -z "$base_compile" && \
       func_fatal_help "you must specify a compilation command"
 
     # Delete any leftover library objects.
-    if test "$build_old_libs" = yes; then
+    if test yes = "$build_old_libs"; then
       removelist="$obj $lobj $libobj ${libobj}T"
     else
       removelist="$lobj $libobj ${libobj}T"
@@ -2127,16 +3443,16 @@ func_mode_compile ()
       pic_mode=default
       ;;
     esac
-    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+    if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
       # non-PIC code in shared libraries is not supported
       pic_mode=default
     fi
 
     # Calculate the filename of the output object if compiler does
     # not support -o with -c
-    if test "$compiler_c_o" = no; then
-      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
-      lockfile="$output_obj.lock"
+    if test no = "$compiler_c_o"; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+      lockfile=$output_obj.lock
     else
       output_obj=
       need_locks=no
@@ -2145,12 +3461,12 @@ func_mode_compile ()
 
     # Lock this critical section if it is needed
     # We use this script file to make the link, it avoids creating a new file
-    if test "$need_locks" = yes; then
+    if test yes = "$need_locks"; then
       until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
 	func_echo "Waiting for $lockfile to be removed"
 	sleep 2
       done
-    elif test "$need_locks" = warn; then
+    elif test warn = "$need_locks"; then
       if test -f "$lockfile"; then
 	$ECHO "\
 *** ERROR, $lockfile exists and contains:
@@ -2158,7 +3474,7 @@ func_mode_compile ()
 
 This indicates that another process is trying to use the same
 temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together.  If you
+your compiler does not support '-c' and '-o' together.  If you
 repeat this compilation, it may succeed, by chance, but you had better
 avoid parallel builds (make -j) in this platform, or get a better
 compiler."
@@ -2180,11 +3496,11 @@ compiler."
     qsrcfile=$func_quote_for_eval_result
 
     # Only build a PIC object if we are building libtool libraries.
-    if test "$build_libtool_libs" = yes; then
+    if test yes = "$build_libtool_libs"; then
       # Without this assignment, base_compile gets emptied.
       fbsd_hideous_sh_bug=$base_compile
 
-      if test "$pic_mode" != no; then
+      if test no != "$pic_mode"; then
 	command="$base_compile $qsrcfile $pic_flag"
       else
 	# Don't build PIC code
@@ -2201,7 +3517,7 @@ compiler."
       func_show_eval_locale "$command"	\
           'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
 
-      if test "$need_locks" = warn &&
+      if test warn = "$need_locks" &&
 	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
 	$ECHO "\
 *** ERROR, $lockfile contains:
@@ -2212,7 +3528,7 @@ $srcfile
 
 This indicates that another process is trying to use the same
 temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together.  If you
+your compiler does not support '-c' and '-o' together.  If you
 repeat this compilation, it may succeed, by chance, but you had better
 avoid parallel builds (make -j) in this platform, or get a better
 compiler."
@@ -2228,20 +3544,20 @@ compiler."
       fi
 
       # Allow error messages only from the first compilation.
-      if test "$suppress_opt" = yes; then
+      if test yes = "$suppress_opt"; then
 	suppress_output=' >/dev/null 2>&1'
       fi
     fi
 
     # Only build a position-dependent object if we build old libraries.
-    if test "$build_old_libs" = yes; then
-      if test "$pic_mode" != yes; then
+    if test yes = "$build_old_libs"; then
+      if test yes != "$pic_mode"; then
 	# Don't build PIC code
 	command="$base_compile $qsrcfile$pie_flag"
       else
 	command="$base_compile $qsrcfile $pic_flag"
       fi
-      if test "$compiler_c_o" = yes; then
+      if test yes = "$compiler_c_o"; then
 	func_append command " -o $obj"
       fi
 
@@ -2250,7 +3566,7 @@ compiler."
       func_show_eval_locale "$command" \
         '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
 
-      if test "$need_locks" = warn &&
+      if test warn = "$need_locks" &&
 	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
 	$ECHO "\
 *** ERROR, $lockfile contains:
@@ -2261,7 +3577,7 @@ $srcfile
 
 This indicates that another process is trying to use the same
 temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together.  If you
+your compiler does not support '-c' and '-o' together.  If you
 repeat this compilation, it may succeed, by chance, but you had better
 avoid parallel builds (make -j) in this platform, or get a better
 compiler."
@@ -2281,7 +3597,7 @@ compiler."
       func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
 
       # Unlock the critical section if it was locked
-      if test "$need_locks" != no; then
+      if test no != "$need_locks"; then
 	removelist=$lockfile
         $RM "$lockfile"
       fi
@@ -2291,7 +3607,7 @@ compiler."
 }
 
 $opt_help || {
-  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+  test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
 }
 
 func_mode_help ()
@@ -2311,7 +3627,7 @@ func_mode_help ()
 Remove files from the build directory.
 
 RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
 to RM.
 
 If FILE is a libtool library, object or program, all the files associated
@@ -2330,16 +3646,16 @@ This mode accepts the following additional options:
   -no-suppress      do not suppress compiler output for multiple passes
   -prefer-pic       try to build PIC objects only
   -prefer-non-pic   try to build non-PIC objects only
-  -shared           do not build a \`.o' file suitable for static linking
-  -static           only build a \`.o' file suitable for static linking
+  -shared           do not build a '.o' file suitable for static linking
+  -static           only build a '.o' file suitable for static linking
   -Wc,FLAG          pass FLAG directly to the compiler
 
-COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
 from the given SOURCEFILE.
 
 The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix \`.c' with the
-library object suffix, \`.lo'."
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
         ;;
 
       execute)
@@ -2352,7 +3668,7 @@ This mode accepts the following additional options:
 
   -dlopen FILE      add the directory containing FILE to the library path
 
-This mode sets the library path environment variable according to \`-dlopen'
+This mode sets the library path environment variable according to '-dlopen'
 flags.
 
 If any of the ARGS are libtool executable wrappers, then they are translated
@@ -2371,7 +3687,7 @@ Complete the installation of libtool libraries.
 Each LIBDIR is a directory that contains libtool libraries.
 
 The commands that this mode executes may require superuser privileges.  Use
-the \`--dry-run' option if you just want to see what would be executed."
+the '--dry-run' option if you just want to see what would be executed."
         ;;
 
       install)
@@ -2381,7 +3697,7 @@ the \`--dry-run' option if you just want to see what would be executed."
 Install executables or libraries.
 
 INSTALL-COMMAND is the installation command.  The first component should be
-either the \`install' or \`cp' program.
+either the 'install' or 'cp' program.
 
 The following components of INSTALL-COMMAND are treated specially:
 
@@ -2407,7 +3723,7 @@ The following components of LINK-COMMAND are treated specially:
   -avoid-version    do not add a version suffix if possible
   -bindir BINDIR    specify path to binaries directory (for systems where
                     libraries must be found in the PATH setting at runtime)
-  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlopen FILE      '-dlpreopen' FILE if it cannot be dlopened at runtime
   -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
   -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
   -export-symbols SYMFILE
@@ -2421,7 +3737,8 @@ The following components of LINK-COMMAND are treated specially:
   -no-install       link a not-installable executable
   -no-undefined     declare that a library does not refer to external symbols
   -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
-  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -objectlist FILE  use a list of object files found in FILE to specify objects
+  -os2dllname NAME  force a short DLL name on OS/2 (no effect on other OSes)
   -precious-files-regex REGEX
                     don't remove output files matching REGEX
   -release RELEASE  specify package release information
@@ -2441,20 +3758,20 @@ The following components of LINK-COMMAND are treated specially:
   -Xlinker FLAG     pass linker-specific FLAG directly to the linker
   -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
 
-All other options (arguments beginning with \`-') are ignored.
+All other options (arguments beginning with '-') are ignored.
 
-Every other argument is treated as a filename.  Files ending in \`.la' are
+Every other argument is treated as a filename.  Files ending in '.la' are
 treated as uninstalled libtool libraries, other files are standard or library
 object files.
 
-If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
-only library objects (\`.lo' files) may be specified, and \`-rpath' is
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
 required, except when creating a convenience library.
 
-If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
-using \`ar' and \`ranlib', or on Windows using \`lib'.
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
 
-If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
 is created, otherwise an executable program is created."
         ;;
 
@@ -2465,7 +3782,7 @@ is created, otherwise an executable program is created."
 Remove libraries from an installation directory.
 
 RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
 to RM.
 
 If FILE is a libtool library, all the files associated with it are deleted.
@@ -2473,17 +3790,17 @@ Otherwise, only FILE itself is deleted using RM."
         ;;
 
       *)
-        func_fatal_help "invalid operation mode \`$opt_mode'"
+        func_fatal_help "invalid operation mode '$opt_mode'"
         ;;
     esac
 
     echo
-    $ECHO "Try \`$progname --help' for more information about other modes."
+    $ECHO "Try '$progname --help' for more information about other modes."
 }
 
 # Now that we've collected a possible --mode arg, show help if necessary
 if $opt_help; then
-  if test "$opt_help" = :; then
+  if test : = "$opt_help"; then
     func_mode_help
   else
     {
@@ -2491,7 +3808,7 @@ if $opt_help; then
       for opt_mode in compile link execute install finish uninstall clean; do
 	func_mode_help
       done
-    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    } | $SED -n '1p; 2,$s/^Usage:/  or: /p'
     {
       func_help noexit
       for opt_mode in compile link execute install finish uninstall clean; do
@@ -2499,7 +3816,7 @@ if $opt_help; then
 	func_mode_help
       done
     } |
-    sed '1d
+    $SED '1d
       /^When reporting/,/^Report/{
 	H
 	d
@@ -2516,16 +3833,17 @@ fi
 # func_mode_execute arg...
 func_mode_execute ()
 {
-    $opt_debug
+    $debug_cmd
+
     # The first argument is the command name.
-    cmd="$nonopt"
+    cmd=$nonopt
     test -z "$cmd" && \
       func_fatal_help "you must specify a COMMAND"
 
     # Handle -dlopen flags immediately.
     for file in $opt_dlopen; do
       test -f "$file" \
-	|| func_fatal_help "\`$file' is not a file"
+	|| func_fatal_help "'$file' is not a file"
 
       dir=
       case $file in
@@ -2535,7 +3853,7 @@ func_mode_execute ()
 
 	# Check to see that this really is a libtool archive.
 	func_lalib_unsafe_p "$file" \
-	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+	  || func_fatal_help "'$lib' is not a valid libtool archive"
 
 	# Read the libtool library.
 	dlname=
@@ -2546,18 +3864,18 @@ func_mode_execute ()
 	if test -z "$dlname"; then
 	  # Warn if it was a shared library.
 	  test -n "$library_names" && \
-	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	    func_warning "'$file' was not linked with '-export-dynamic'"
 	  continue
 	fi
 
 	func_dirname "$file" "" "."
-	dir="$func_dirname_result"
+	dir=$func_dirname_result
 
 	if test -f "$dir/$objdir/$dlname"; then
 	  func_append dir "/$objdir"
 	else
 	  if test ! -f "$dir/$dlname"; then
-	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	    func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
 	  fi
 	fi
 	;;
@@ -2565,18 +3883,18 @@ func_mode_execute ()
       *.lo)
 	# Just add the directory containing the .lo file.
 	func_dirname "$file" "" "."
-	dir="$func_dirname_result"
+	dir=$func_dirname_result
 	;;
 
       *)
-	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
 	continue
 	;;
       esac
 
       # Get the absolute pathname.
       absdir=`cd "$dir" && pwd`
-      test -n "$absdir" && dir="$absdir"
+      test -n "$absdir" && dir=$absdir
 
       # Now add the directory to shlibpath_var.
       if eval "test -z \"\$$shlibpath_var\""; then
@@ -2588,7 +3906,7 @@ func_mode_execute ()
 
     # This variable tells wrapper scripts just to set shlibpath_var
     # rather than running their programs.
-    libtool_execute_magic="$magic"
+    libtool_execute_magic=$magic
 
     # Check if any of the arguments is a wrapper script.
     args=
@@ -2601,12 +3919,12 @@ func_mode_execute ()
 	if func_ltwrapper_script_p "$file"; then
 	  func_source "$file"
 	  # Transform arg to wrapped name.
-	  file="$progdir/$program"
+	  file=$progdir/$program
 	elif func_ltwrapper_executable_p "$file"; then
 	  func_ltwrapper_scriptname "$file"
 	  func_source "$func_ltwrapper_scriptname_result"
 	  # Transform arg to wrapped name.
-	  file="$progdir/$program"
+	  file=$progdir/$program
 	fi
 	;;
       esac
@@ -2614,7 +3932,15 @@ func_mode_execute ()
       func_append_quoted args "$file"
     done
 
-    if test "X$opt_dry_run" = Xfalse; then
+    if $opt_dry_run; then
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    else
       if test -n "$shlibpath_var"; then
 	# Export the shlibpath_var.
 	eval "export $shlibpath_var"
@@ -2631,25 +3957,18 @@ func_mode_execute ()
       done
 
       # Now prepare to actually exec the command.
-      exec_cmd="\$cmd$args"
-    else
-      # Display what would be done.
-      if test -n "$shlibpath_var"; then
-	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
-	echo "export $shlibpath_var"
-      fi
-      $ECHO "$cmd$args"
-      exit $EXIT_SUCCESS
+      exec_cmd=\$cmd$args
     fi
 }
 
-test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
 
 
 # func_mode_finish arg...
 func_mode_finish ()
 {
-    $opt_debug
+    $debug_cmd
+
     libs=
     libdirs=
     admincmds=
@@ -2663,11 +3982,11 @@ func_mode_finish ()
 	if func_lalib_unsafe_p "$opt"; then
 	  func_append libs " $opt"
 	else
-	  func_warning "\`$opt' is not a valid libtool archive"
+	  func_warning "'$opt' is not a valid libtool archive"
 	fi
 
       else
-	func_fatal_error "invalid argument \`$opt'"
+	func_fatal_error "invalid argument '$opt'"
       fi
     done
 
@@ -2682,12 +4001,12 @@ func_mode_finish ()
       # Remove sysroot references
       if $opt_dry_run; then
         for lib in $libs; do
-          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+          echo "removing references to $lt_sysroot and '=' prefixes from $lib"
         done
       else
         tmpdir=`func_mktempdir`
         for lib in $libs; do
-	  sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	  $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
 	    > $tmpdir/tmp-la
 	  mv -f $tmpdir/tmp-la $lib
 	done
@@ -2712,7 +4031,7 @@ func_mode_finish ()
     fi
 
     # Exit here if they wanted silent mode.
-    $opt_silent && exit $EXIT_SUCCESS
+    $opt_quiet && exit $EXIT_SUCCESS
 
     if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
       echo "----------------------------------------------------------------------"
@@ -2723,27 +4042,27 @@ func_mode_finish ()
       echo
       echo "If you ever happen to want to link against installed libraries"
       echo "in a given directory, LIBDIR, you must either use libtool, and"
-      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "specify the full pathname of the library, or use the '-LLIBDIR'"
       echo "flag during linking and do at least one of the following:"
       if test -n "$shlibpath_var"; then
-	echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+	echo "   - add LIBDIR to the '$shlibpath_var' environment variable"
 	echo "     during execution"
       fi
       if test -n "$runpath_var"; then
-	echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+	echo "   - add LIBDIR to the '$runpath_var' environment variable"
 	echo "     during linking"
       fi
       if test -n "$hardcode_libdir_flag_spec"; then
 	libdir=LIBDIR
 	eval flag=\"$hardcode_libdir_flag_spec\"
 
-	$ECHO "   - use the \`$flag' linker flag"
+	$ECHO "   - use the '$flag' linker flag"
       fi
       if test -n "$admincmds"; then
 	$ECHO "   - have your system administrator run these commands:$admincmds"
       fi
       if test -f /etc/ld.so.conf; then
-	echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+	echo "   - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
       fi
       echo
 
@@ -2762,18 +4081,20 @@ func_mode_finish ()
     exit $EXIT_SUCCESS
 }
 
-test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
 
 
 # func_mode_install arg...
 func_mode_install ()
 {
-    $opt_debug
+    $debug_cmd
+
     # There may be an optional sh(1) argument at the beginning of
     # install_prog (especially on Windows NT).
-    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+    if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
        # Allow the use of GNU shtool's install command.
-       case $nonopt in *shtool*) :;; *) false;; esac; then
+       case $nonopt in *shtool*) :;; *) false;; esac
+    then
       # Aesthetically quote it.
       func_quote_for_eval "$nonopt"
       install_prog="$func_quote_for_eval_result "
@@ -2800,7 +4121,7 @@ func_mode_install ()
     opts=
     prev=
     install_type=
-    isdir=no
+    isdir=false
     stripme=
     no_mode=:
     for arg
@@ -2813,7 +4134,7 @@ func_mode_install ()
       fi
 
       case $arg in
-      -d) isdir=yes ;;
+      -d) isdir=: ;;
       -f)
 	if $install_cp; then :; else
 	  prev=$arg
@@ -2831,7 +4152,7 @@ func_mode_install ()
       *)
 	# If the previous option needed an argument, then skip it.
 	if test -n "$prev"; then
-	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	  if test X-m = "X$prev" && test -n "$install_override_mode"; then
 	    arg2=$install_override_mode
 	    no_mode=false
 	  fi
@@ -2856,7 +4177,7 @@ func_mode_install ()
       func_fatal_help "you must specify an install program"
 
     test -n "$prev" && \
-      func_fatal_help "the \`$prev' option requires an argument"
+      func_fatal_help "the '$prev' option requires an argument"
 
     if test -n "$install_override_mode" && $no_mode; then
       if $install_cp; then :; else
@@ -2878,19 +4199,19 @@ func_mode_install ()
     dest=$func_stripname_result
 
     # Check to see that the destination is a directory.
-    test -d "$dest" && isdir=yes
-    if test "$isdir" = yes; then
-      destdir="$dest"
+    test -d "$dest" && isdir=:
+    if $isdir; then
+      destdir=$dest
       destname=
     else
       func_dirname_and_basename "$dest" "" "."
-      destdir="$func_dirname_result"
-      destname="$func_basename_result"
+      destdir=$func_dirname_result
+      destname=$func_basename_result
 
       # Not a directory, so check to see that there is only one file specified.
       set dummy $files; shift
       test "$#" -gt 1 && \
-	func_fatal_help "\`$dest' is not a directory"
+	func_fatal_help "'$dest' is not a directory"
     fi
     case $destdir in
     [\\/]* | [A-Za-z]:[\\/]*) ;;
@@ -2899,7 +4220,7 @@ func_mode_install ()
 	case $file in
 	*.lo) ;;
 	*)
-	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  func_fatal_help "'$destdir' must be an absolute directory name"
 	  ;;
 	esac
       done
@@ -2908,7 +4229,7 @@ func_mode_install ()
 
     # This variable tells wrapper scripts just to set variables rather
     # than running their programs.
-    libtool_install_magic="$magic"
+    libtool_install_magic=$magic
 
     staticlibs=
     future_libdirs=
@@ -2928,7 +4249,7 @@ func_mode_install ()
 
 	# Check to see that this really is a libtool archive.
 	func_lalib_unsafe_p "$file" \
-	  || func_fatal_help "\`$file' is not a valid libtool archive"
+	  || func_fatal_help "'$file' is not a valid libtool archive"
 
 	library_names=
 	old_library=
@@ -2950,7 +4271,7 @@ func_mode_install ()
 	fi
 
 	func_dirname "$file" "/" ""
-	dir="$func_dirname_result"
+	dir=$func_dirname_result
 	func_append dir "$objdir"
 
 	if test -n "$relink_command"; then
@@ -2964,7 +4285,7 @@ func_mode_install ()
 	  # are installed into $libdir/../bin (currently, that works fine)
 	  # but it's something to keep an eye on.
 	  test "$inst_prefix_dir" = "$destdir" && \
-	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+	    func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
 
 	  if test -n "$inst_prefix_dir"; then
 	    # Stick the inst_prefix_dir data into the link command.
@@ -2973,29 +4294,36 @@ func_mode_install ()
 	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
 	  fi
 
-	  func_warning "relinking \`$file'"
+	  func_warning "relinking '$file'"
 	  func_show_eval "$relink_command" \
-	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	    'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
 	fi
 
 	# See the names of the shared library.
 	set dummy $library_names; shift
 	if test -n "$1"; then
-	  realname="$1"
+	  realname=$1
 	  shift
 
-	  srcname="$realname"
-	  test -n "$relink_command" && srcname="$realname"T
+	  srcname=$realname
+	  test -n "$relink_command" && srcname=${realname}T
 
 	  # Install the shared library and build the symlinks.
 	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
 	      'exit $?'
-	  tstripme="$stripme"
+	  tstripme=$stripme
 	  case $host_os in
 	  cygwin* | mingw* | pw32* | cegcc*)
 	    case $realname in
 	    *.dll.a)
-	      tstripme=""
+	      tstripme=
+	      ;;
+	    esac
+	    ;;
+	  os2*)
+	    case $realname in
+	    *_dll.a)
+	      tstripme=
 	      ;;
 	    esac
 	    ;;
@@ -3006,7 +4334,7 @@ func_mode_install ()
 
 	  if test "$#" -gt 0; then
 	    # Delete the old symlinks, and create new ones.
-	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # Try 'ln -sf' first, because the 'ln' binary might depend on
 	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
 	    # so we also need to try rm && ln -s.
 	    for linkname
@@ -3017,14 +4345,14 @@ func_mode_install ()
 	  fi
 
 	  # Do each command in the postinstall commands.
-	  lib="$destdir/$realname"
+	  lib=$destdir/$realname
 	  func_execute_cmds "$postinstall_cmds" 'exit $?'
 	fi
 
 	# Install the pseudo-library for information purposes.
 	func_basename "$file"
-	name="$func_basename_result"
-	instname="$dir/$name"i
+	name=$func_basename_result
+	instname=$dir/${name}i
 	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
 
 	# Maybe install the static library, too.
@@ -3036,11 +4364,11 @@ func_mode_install ()
 
 	# Figure out destination file name, if it wasn't already specified.
 	if test -n "$destname"; then
-	  destfile="$destdir/$destname"
+	  destfile=$destdir/$destname
 	else
 	  func_basename "$file"
-	  destfile="$func_basename_result"
-	  destfile="$destdir/$destfile"
+	  destfile=$func_basename_result
+	  destfile=$destdir/$destfile
 	fi
 
 	# Deduce the name of the destination old-style object file.
@@ -3050,11 +4378,11 @@ func_mode_install ()
 	  staticdest=$func_lo2o_result
 	  ;;
 	*.$objext)
-	  staticdest="$destfile"
+	  staticdest=$destfile
 	  destfile=
 	  ;;
 	*)
-	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  func_fatal_help "cannot copy a libtool object to '$destfile'"
 	  ;;
 	esac
 
@@ -3063,7 +4391,7 @@ func_mode_install ()
 	  func_show_eval "$install_prog $file $destfile" 'exit $?'
 
 	# Install the old object if enabled.
-	if test "$build_old_libs" = yes; then
+	if test yes = "$build_old_libs"; then
 	  # Deduce the name of the old-style object file.
 	  func_lo2o "$file"
 	  staticobj=$func_lo2o_result
@@ -3075,23 +4403,23 @@ func_mode_install ()
       *)
 	# Figure out destination file name, if it wasn't already specified.
 	if test -n "$destname"; then
-	  destfile="$destdir/$destname"
+	  destfile=$destdir/$destname
 	else
 	  func_basename "$file"
-	  destfile="$func_basename_result"
-	  destfile="$destdir/$destfile"
+	  destfile=$func_basename_result
+	  destfile=$destdir/$destfile
 	fi
 
 	# If the file is missing, and there is a .exe on the end, strip it
 	# because it is most likely a libtool script we actually want to
 	# install
-	stripped_ext=""
+	stripped_ext=
 	case $file in
 	  *.exe)
 	    if test ! -f "$file"; then
 	      func_stripname '' '.exe' "$file"
 	      file=$func_stripname_result
-	      stripped_ext=".exe"
+	      stripped_ext=.exe
 	    fi
 	    ;;
 	esac
@@ -3119,19 +4447,19 @@ func_mode_install ()
 
 	  # Check the variables that should have been set.
 	  test -z "$generated_by_libtool_version" && \
-	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+	    func_fatal_error "invalid libtool wrapper script '$wrapper'"
 
-	  finalize=yes
+	  finalize=:
 	  for lib in $notinst_deplibs; do
 	    # Check to see that each library is installed.
 	    libdir=
 	    if test -f "$lib"; then
 	      func_source "$lib"
 	    fi
-	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
 	    if test -n "$libdir" && test ! -f "$libfile"; then
-	      func_warning "\`$lib' has not been installed in \`$libdir'"
-	      finalize=no
+	      func_warning "'$lib' has not been installed in '$libdir'"
+	      finalize=false
 	    fi
 	  done
 
@@ -3139,29 +4467,29 @@ func_mode_install ()
 	  func_source "$wrapper"
 
 	  outputname=
-	  if test "$fast_install" = no && test -n "$relink_command"; then
+	  if test no = "$fast_install" && test -n "$relink_command"; then
 	    $opt_dry_run || {
-	      if test "$finalize" = yes; then
+	      if $finalize; then
 	        tmpdir=`func_mktempdir`
 		func_basename "$file$stripped_ext"
-		file="$func_basename_result"
-	        outputname="$tmpdir/$file"
+		file=$func_basename_result
+	        outputname=$tmpdir/$file
 	        # Replace the output file specification.
 	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
 
-	        $opt_silent || {
+	        $opt_quiet || {
 	          func_quote_for_expand "$relink_command"
 		  eval "func_echo $func_quote_for_expand_result"
 	        }
 	        if eval "$relink_command"; then :
 	          else
-		  func_error "error: relink \`$file' with the above command before installing it"
+		  func_error "error: relink '$file' with the above command before installing it"
 		  $opt_dry_run || ${RM}r "$tmpdir"
 		  continue
 	        fi
-	        file="$outputname"
+	        file=$outputname
 	      else
-	        func_warning "cannot relink \`$file'"
+	        func_warning "cannot relink '$file'"
 	      fi
 	    }
 	  else
@@ -3198,10 +4526,10 @@ func_mode_install ()
 
     for file in $staticlibs; do
       func_basename "$file"
-      name="$func_basename_result"
+      name=$func_basename_result
 
       # Set up the ranlib parameters.
-      oldlib="$destdir/$name"
+      oldlib=$destdir/$name
       func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
       tool_oldlib=$func_to_tool_file_result
 
@@ -3216,18 +4544,18 @@ func_mode_install ()
     done
 
     test -n "$future_libdirs" && \
-      func_warning "remember to run \`$progname --finish$future_libdirs'"
+      func_warning "remember to run '$progname --finish$future_libdirs'"
 
     if test -n "$current_libdirs"; then
       # Maybe just do a dry run.
       $opt_dry_run && current_libdirs=" -n$current_libdirs"
-      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+      exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
     else
       exit $EXIT_SUCCESS
     fi
 }
 
-test "$opt_mode" = install && func_mode_install ${1+"$@"}
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
 
 
 # func_generate_dlsyms outputname originator pic_p
@@ -3235,16 +4563,17 @@ test "$opt_mode" = install && func_mode_install ${1+"$@"}
 # a dlpreopen symbol table.
 func_generate_dlsyms ()
 {
-    $opt_debug
-    my_outputname="$1"
-    my_originator="$2"
-    my_pic_p="${3-no}"
-    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    $debug_cmd
+
+    my_outputname=$1
+    my_originator=$2
+    my_pic_p=${3-false}
+    my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
     my_dlsyms=
 
-    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+    if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
       if test -n "$NM" && test -n "$global_symbol_pipe"; then
-	my_dlsyms="${my_outputname}S.c"
+	my_dlsyms=${my_outputname}S.c
       else
 	func_error "not configured to extract global symbols from dlpreopened files"
       fi
@@ -3255,7 +4584,7 @@ func_generate_dlsyms ()
       "") ;;
       *.c)
 	# Discover the nlist of each of the dlfiles.
-	nlist="$output_objdir/${my_outputname}.nm"
+	nlist=$output_objdir/$my_outputname.nm
 
 	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
 
@@ -3263,34 +4592,36 @@ func_generate_dlsyms ()
 	func_verbose "creating $output_objdir/$my_dlsyms"
 
 	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
-/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
-/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
 
 #ifdef __cplusplus
 extern \"C\" {
 #endif
 
-#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
 #pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
 #endif
 
 /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
    relocations are performed -- see ld's documentation on pseudo-relocs.  */
 # define LT_DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
 /* This system does not cope well with relocations in const data.  */
 # define LT_DLSYM_CONST
 #else
 # define LT_DLSYM_CONST const
 #endif
 
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
 /* External symbol declarations for the compiler. */\
 "
 
-	if test "$dlself" = yes; then
-	  func_verbose "generating symbol list for \`$output'"
+	if test yes = "$dlself"; then
+	  func_verbose "generating symbol list for '$output'"
 
 	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
 
@@ -3298,7 +4629,7 @@ extern \"C\" {
 	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
 	  for progfile in $progfiles; do
 	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
-	    func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+	    func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
 	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
 	  done
 
@@ -3318,10 +4649,10 @@ extern \"C\" {
 
 	  # Prepare the list of exported symbols
 	  if test -z "$export_symbols"; then
-	    export_symbols="$output_objdir/$outputname.exp"
+	    export_symbols=$output_objdir/$outputname.exp
 	    $opt_dry_run || {
 	      $RM $export_symbols
-	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
 	      case $host in
 	      *cygwin* | *mingw* | *cegcc* )
                 eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
@@ -3331,7 +4662,7 @@ extern \"C\" {
 	    }
 	  else
 	    $opt_dry_run || {
-	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
 	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
 	      eval '$MV "$nlist"T "$nlist"'
 	      case $host in
@@ -3345,22 +4676,22 @@ extern \"C\" {
 	fi
 
 	for dlprefile in $dlprefiles; do
-	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_verbose "extracting global C symbols from '$dlprefile'"
 	  func_basename "$dlprefile"
-	  name="$func_basename_result"
+	  name=$func_basename_result
           case $host in
 	    *cygwin* | *mingw* | *cegcc* )
 	      # if an import library, we need to obtain dlname
 	      if func_win32_import_lib_p "$dlprefile"; then
 	        func_tr_sh "$dlprefile"
 	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
-	        dlprefile_dlbasename=""
+	        dlprefile_dlbasename=
 	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
 	          # Use subshell, to avoid clobbering current variable values
 	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
-	          if test -n "$dlprefile_dlname" ; then
+	          if test -n "$dlprefile_dlname"; then
 	            func_basename "$dlprefile_dlname"
-	            dlprefile_dlbasename="$func_basename_result"
+	            dlprefile_dlbasename=$func_basename_result
 	          else
 	            # no lafile. user explicitly requested -dlpreopen <import library>.
 	            $sharedlib_from_linklib_cmd "$dlprefile"
@@ -3368,7 +4699,7 @@ extern \"C\" {
 	          fi
 	        fi
 	        $opt_dry_run || {
-	          if test -n "$dlprefile_dlbasename" ; then
+	          if test -n "$dlprefile_dlbasename"; then
 	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
 	          else
 	            func_warning "Could not compute DLL name from $name"
@@ -3424,6 +4755,11 @@ extern \"C\" {
 	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
 	  fi
 
+	  func_show_eval '$RM "${nlist}I"'
+	  if test -n "$global_symbol_to_import"; then
+	    eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+	  fi
+
 	  echo >> "$output_objdir/$my_dlsyms" "\
 
 /* The mapping between symbol names and symbols.  */
@@ -3432,11 +4768,30 @@ typedef struct {
   void *address;
 } lt_dlsymlist;
 extern LT_DLSYM_CONST lt_dlsymlist
-lt_${my_prefix}_LTX_preloaded_symbols[];
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+	  if test -s "$nlist"I; then
+	    echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+  LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+  for (; symbol->name; ++symbol)
+    {"
+	    $SED 's/.*/      if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+	    echo >> "$output_objdir/$my_dlsyms" "\
+    }
+}"
+	  fi
+	  echo >> "$output_objdir/$my_dlsyms" "\
 LT_DLSYM_CONST lt_dlsymlist
 lt_${my_prefix}_LTX_preloaded_symbols[] =
-{\
-  { \"$my_originator\", (void *) 0 },"
+{ {\"$my_originator\", (void *) 0},"
+
+	  if test -s "$nlist"I; then
+	    echo >> "$output_objdir/$my_dlsyms" "\
+  {\"@INIT@\", (void *) &lt_syminit},"
+	  fi
 
 	  case $need_lib_prefix in
 	  no)
@@ -3478,9 +4833,7 @@ static const void *lt_preloaded_setup() {
 	  *-*-hpux*)
 	    pic_flag_for_symtable=" $pic_flag"  ;;
 	  *)
-	    if test "X$my_pic_p" != Xno; then
-	      pic_flag_for_symtable=" $pic_flag"
-	    fi
+	    $my_pic_p && pic_flag_for_symtable=" $pic_flag"
 	    ;;
 	  esac
 	  ;;
@@ -3497,10 +4850,10 @@ static const void *lt_preloaded_setup() {
 	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
 
 	# Clean up the generated files.
-	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
 
 	# Transform the symbol file into the correct name.
-	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	symfileobj=$output_objdir/${my_outputname}S.$objext
 	case $host in
 	*cygwin* | *mingw* | *cegcc* )
 	  if test -f "$output_objdir/$my_outputname.def"; then
@@ -3518,7 +4871,7 @@ static const void *lt_preloaded_setup() {
 	esac
 	;;
       *)
-	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	func_fatal_error "unknown suffix for '$my_dlsyms'"
 	;;
       esac
     else
@@ -3532,6 +4885,32 @@ static const void *lt_preloaded_setup() {
     fi
 }
 
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
 # func_win32_libid arg
 # return the library type of file 'arg'
 #
@@ -3541,8 +4920,9 @@ static const void *lt_preloaded_setup() {
 # Despite the name, also deal with 64 bit binaries.
 func_win32_libid ()
 {
-  $opt_debug
-  win32_libid_type="unknown"
+  $debug_cmd
+
+  win32_libid_type=unknown
   win32_fileres=`file -L $1 2>/dev/null`
   case $win32_fileres in
   *ar\ archive\ import\ library*) # definitely import
@@ -3552,16 +4932,29 @@ func_win32_libid ()
     # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
     if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
        $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
-      func_to_tool_file "$1" func_convert_file_msys_to_w32
-      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
-	$SED -n -e '
+      case $nm_interface in
+      "MS dumpbin")
+	if func_cygming_ms_implib_p "$1" ||
+	   func_cygming_gnu_implib_p "$1"
+	then
+	  win32_nmres=import
+	else
+	  win32_nmres=
+	fi
+	;;
+      *)
+	func_to_tool_file "$1" func_convert_file_msys_to_w32
+	win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	  $SED -n -e '
 	    1,100{
 		/ I /{
-		    s,.*,import,
+		    s|.*|import|
 		    p
 		    q
 		}
 	    }'`
+	;;
+      esac
       case $win32_nmres in
       import*)  win32_libid_type="x86 archive import";;
       *)        win32_libid_type="x86 archive static";;
@@ -3593,7 +4986,8 @@ func_win32_libid ()
 #    $sharedlib_from_linklib_result
 func_cygming_dll_for_implib ()
 {
-  $opt_debug
+  $debug_cmd
+
   sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
 }
 
@@ -3610,7 +5004,8 @@ func_cygming_dll_for_implib ()
 # specified import library.
 func_cygming_dll_for_implib_fallback_core ()
 {
-  $opt_debug
+  $debug_cmd
+
   match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
   $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
     $SED '/^Contents of section '"$match_literal"':/{
@@ -3646,8 +5041,8 @@ func_cygming_dll_for_implib_fallback_core ()
       /./p' |
     # we now have a list, one entry per line, of the stringified
     # contents of the appropriate section of all members of the
-    # archive which possess that section. Heuristic: eliminate
-    # all those which have a first or second character that is
+    # archive that possess that section. Heuristic: eliminate
+    # all those that have a first or second character that is
     # a '.' (that is, objdump's representation of an unprintable
     # character.) This should work for all archives with less than
     # 0x302f exports -- but will fail for DLLs whose name actually
@@ -3658,30 +5053,6 @@ func_cygming_dll_for_implib_fallback_core ()
     $SED -e '/^\./d;/^.\./d;q'
 }
 
-# func_cygming_gnu_implib_p ARG
-# This predicate returns with zero status (TRUE) if
-# ARG is a GNU/binutils-style import library. Returns
-# with nonzero status (FALSE) otherwise.
-func_cygming_gnu_implib_p ()
-{
-  $opt_debug
-  func_to_tool_file "$1" func_convert_file_msys_to_w32
-  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
-  test -n "$func_cygming_gnu_implib_tmp"
-}
-
-# func_cygming_ms_implib_p ARG
-# This predicate returns with zero status (TRUE) if
-# ARG is an MS-style import library. Returns
-# with nonzero status (FALSE) otherwise.
-func_cygming_ms_implib_p ()
-{
-  $opt_debug
-  func_to_tool_file "$1" func_convert_file_msys_to_w32
-  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
-  test -n "$func_cygming_ms_implib_tmp"
-}
-
 # func_cygming_dll_for_implib_fallback ARG
 # Platform-specific function to extract the
 # name of the DLL associated with the specified
@@ -3695,16 +5066,17 @@ func_cygming_ms_implib_p ()
 #    $sharedlib_from_linklib_result
 func_cygming_dll_for_implib_fallback ()
 {
-  $opt_debug
-  if func_cygming_gnu_implib_p "$1" ; then
+  $debug_cmd
+
+  if func_cygming_gnu_implib_p "$1"; then
     # binutils import library
     sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
-  elif func_cygming_ms_implib_p "$1" ; then
+  elif func_cygming_ms_implib_p "$1"; then
     # ms-generated import library
     sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
   else
     # unknown
-    sharedlib_from_linklib_result=""
+    sharedlib_from_linklib_result=
   fi
 }
 
@@ -3712,10 +5084,11 @@ func_cygming_dll_for_implib_fallback ()
 # func_extract_an_archive dir oldlib
 func_extract_an_archive ()
 {
-    $opt_debug
-    f_ex_an_ar_dir="$1"; shift
-    f_ex_an_ar_oldlib="$1"
-    if test "$lock_old_archive_extraction" = yes; then
+    $debug_cmd
+
+    f_ex_an_ar_dir=$1; shift
+    f_ex_an_ar_oldlib=$1
+    if test yes = "$lock_old_archive_extraction"; then
       lockfile=$f_ex_an_ar_oldlib.lock
       until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
 	func_echo "Waiting for $lockfile to be removed"
@@ -3724,7 +5097,7 @@ func_extract_an_archive ()
     fi
     func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
 		   'stat=$?; rm -f "$lockfile"; exit $stat'
-    if test "$lock_old_archive_extraction" = yes; then
+    if test yes = "$lock_old_archive_extraction"; then
       $opt_dry_run || rm -f "$lockfile"
     fi
     if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
@@ -3738,22 +5111,23 @@ func_extract_an_archive ()
 # func_extract_archives gentop oldlib ...
 func_extract_archives ()
 {
-    $opt_debug
-    my_gentop="$1"; shift
+    $debug_cmd
+
+    my_gentop=$1; shift
     my_oldlibs=${1+"$@"}
-    my_oldobjs=""
-    my_xlib=""
-    my_xabs=""
-    my_xdir=""
+    my_oldobjs=
+    my_xlib=
+    my_xabs=
+    my_xdir=
 
     for my_xlib in $my_oldlibs; do
       # Extract the objects.
       case $my_xlib in
-	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
 	*) my_xabs=`pwd`"/$my_xlib" ;;
       esac
       func_basename "$my_xlib"
-      my_xlib="$func_basename_result"
+      my_xlib=$func_basename_result
       my_xlib_u=$my_xlib
       while :; do
         case " $extracted_archives " in
@@ -3765,7 +5139,7 @@ func_extract_archives ()
 	esac
       done
       extracted_archives="$extracted_archives $my_xlib_u"
-      my_xdir="$my_gentop/$my_xlib_u"
+      my_xdir=$my_gentop/$my_xlib_u
 
       func_mkdir_p "$my_xdir"
 
@@ -3778,22 +5152,23 @@ func_extract_archives ()
 	  cd $my_xdir || exit $?
 	  darwin_archive=$my_xabs
 	  darwin_curdir=`pwd`
-	  darwin_base_archive=`basename "$darwin_archive"`
+	  func_basename "$darwin_archive"
+	  darwin_base_archive=$func_basename_result
 	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
 	  if test -n "$darwin_arches"; then
 	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
 	    darwin_arch=
 	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
-	    for darwin_arch in  $darwin_arches ; do
-	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
-	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
-	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
-	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	    for darwin_arch in  $darwin_arches; do
+	      func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+	      cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+	      func_extract_an_archive "`pwd`" "$darwin_base_archive"
 	      cd "$darwin_curdir"
-	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	      $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
 	    done # $darwin_arches
             ## Okay now we've a bunch of thin objects, gotta fatten them up :)
-	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
 	    darwin_file=
 	    darwin_files=
 	    for darwin_file in $darwin_filelist; do
@@ -3815,7 +5190,7 @@ func_extract_archives ()
       my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
     done
 
-    func_extract_archives_result="$my_oldobjs"
+    func_extract_archives_result=$my_oldobjs
 }
 
 
@@ -3830,7 +5205,7 @@ func_extract_archives ()
 #
 # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
 # variable will take.  If 'yes', then the emitted script
-# will assume that the directory in which it is stored is
+# will assume that the directory where it is stored is
 # the $objdir directory.  This is a cygwin/mingw-specific
 # behavior.
 func_emit_wrapper ()
@@ -3841,7 +5216,7 @@ func_emit_wrapper ()
 #! $SHELL
 
 # $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
 #
 # The $output program cannot be directly executed until all the libtool
 # libraries that it depends on are installed.
@@ -3898,9 +5273,9 @@ _LTECHO_EOF'
 
 # Very basic option parsing. These options are (a) specific to
 # the libtool wrapper, (b) are identical between the wrapper
-# /script/ and the wrapper /executable/ which is used only on
+# /script/ and the wrapper /executable/ that is used only on
 # windows platforms, and (c) all begin with the string "--lt-"
-# (application programs are unlikely to have options which match
+# (application programs are unlikely to have options that match
 # this pattern).
 #
 # There are only two supported options: --lt-debug and
@@ -3933,7 +5308,7 @@ func_parse_lt_options ()
 
   # Print the debug banner immediately:
   if test -n \"\$lt_option_debug\"; then
-    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+    echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
   fi
 }
 
@@ -3944,7 +5319,7 @@ func_lt_dump_args ()
   lt_dump_args_N=1;
   for lt_arg
   do
-    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
     lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
   done
 }
@@ -3958,7 +5333,7 @@ func_exec_program_core ()
   *-*-mingw | *-*-os2* | *-cegcc*)
     $ECHO "\
       if test -n \"\$lt_option_debug\"; then
-        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
         func_lt_dump_args \${1+\"\$@\"} 1>&2
       fi
       exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
@@ -3968,7 +5343,7 @@ func_exec_program_core ()
   *)
     $ECHO "\
       if test -n \"\$lt_option_debug\"; then
-        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
         func_lt_dump_args \${1+\"\$@\"} 1>&2
       fi
       exec \"\$progdir/\$program\" \${1+\"\$@\"}
@@ -4043,13 +5418,13 @@ func_exec_program ()
   test -n \"\$absdir\" && thisdir=\"\$absdir\"
 "
 
-	if test "$fast_install" = yes; then
+	if test yes = "$fast_install"; then
 	  $ECHO "\
   program=lt-'$outputname'$exeext
   progdir=\"\$thisdir/$objdir\"
 
   if test ! -f \"\$progdir/\$program\" ||
-     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
        test \"X\$file\" != \"X\$progdir/\$program\"; }; then
 
     file=\"\$\$-\$program\"
@@ -4066,7 +5441,7 @@ func_exec_program ()
     if test -n \"\$relink_command\"; then
       if relink_command_output=\`eval \$relink_command 2>&1\`; then :
       else
-	$ECHO \"\$relink_command_output\" >&2
+	\$ECHO \"\$relink_command_output\" >&2
 	$RM \"\$progdir/\$file\"
 	exit 1
       fi
@@ -4101,7 +5476,7 @@ func_exec_program ()
 	fi
 
 	# Export our shlibpath_var if we have one.
-	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
 	  $ECHO "\
     # Add our own library path to $shlibpath_var
     $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
@@ -4121,7 +5496,7 @@ func_exec_program ()
     fi
   else
     # The program doesn't exist.
-    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
     \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
     \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
     exit 1
@@ -4140,7 +5515,7 @@ func_emit_cwrapperexe_src ()
 	cat <<EOF
 
 /* $cwrappersource - temporary wrapper executable for $objdir/$outputname
-   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+   Generated by $PROGRAM (GNU $PACKAGE) $VERSION
 
    The $output program cannot be directly executed until all the libtool
    libraries that it depends on are installed.
@@ -4175,47 +5550,45 @@ EOF
 #include <fcntl.h>
 #include <sys/stat.h>
 
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
 /* declarations of non-ANSI functions */
-#if defined(__MINGW32__)
+#if defined __MINGW32__
 # ifdef __STRICT_ANSI__
 int _putenv (const char *);
 # endif
-#elif defined(__CYGWIN__)
+#elif defined __CYGWIN__
 # ifdef __STRICT_ANSI__
 char *realpath (const char *, char *);
 int putenv (char *);
 int setenv (const char *, const char *, int);
 # endif
-/* #elif defined (other platforms) ... */
+/* #elif defined other_platform || defined ... */
 #endif
 
 /* portability defines, excluding path handling macros */
-#if defined(_MSC_VER)
+#if defined _MSC_VER
 # define setmode _setmode
 # define stat    _stat
 # define chmod   _chmod
 # define getcwd  _getcwd
 # define putenv  _putenv
 # define S_IXUSR _S_IEXEC
-# ifndef _INTPTR_T_DEFINED
-#  define _INTPTR_T_DEFINED
-#  define intptr_t int
-# endif
-#elif defined(__MINGW32__)
+#elif defined __MINGW32__
 # define setmode _setmode
 # define stat    _stat
 # define chmod   _chmod
 # define getcwd  _getcwd
 # define putenv  _putenv
-#elif defined(__CYGWIN__)
+#elif defined __CYGWIN__
 # define HAVE_SETENV
 # define FOPEN_WB "wb"
-/* #elif defined (other platforms) ... */
+/* #elif defined other platforms ... */
 #endif
 
-#if defined(PATH_MAX)
+#if defined PATH_MAX
 # define LT_PATHMAX PATH_MAX
-#elif defined(MAXPATHLEN)
+#elif defined MAXPATHLEN
 # define LT_PATHMAX MAXPATHLEN
 #else
 # define LT_PATHMAX 1024
@@ -4234,8 +5607,8 @@ int setenv (const char *, const char *, int);
 # define PATH_SEPARATOR ':'
 #endif
 
-#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
-  defined (__OS2__)
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+  defined __OS2__
 # define HAVE_DOS_BASED_FILE_SYSTEM
 # define FOPEN_WB "wb"
 # ifndef DIR_SEPARATOR_2
@@ -4268,10 +5641,10 @@ int setenv (const char *, const char *, int);
 
 #define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
 #define XFREE(stale) do { \
-  if (stale) { free ((void *) stale); stale = 0; } \
+  if (stale) { free (stale); stale = 0; } \
 } while (0)
 
-#if defined(LT_DEBUGWRAPPER)
+#if defined LT_DEBUGWRAPPER
 static int lt_debug = 1;
 #else
 static int lt_debug = 0;
@@ -4300,11 +5673,16 @@ void lt_dump_script (FILE *f);
 EOF
 
 	    cat <<EOF
-volatile const char * MAGIC_EXE = "$magic_exe";
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
 const char * LIB_PATH_VARNAME = "$shlibpath_var";
 EOF
 
-	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	    if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
               func_to_host_path "$temp_rpath"
 	      cat <<EOF
 const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
@@ -4328,7 +5706,7 @@ const char * EXE_PATH_VALUE   = "";
 EOF
 	    fi
 
-	    if test "$fast_install" = yes; then
+	    if test yes = "$fast_install"; then
 	      cat <<EOF
 const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
 EOF
@@ -4357,12 +5735,12 @@ main (int argc, char *argv[])
   char *actual_cwrapper_name;
   char *target_name;
   char *lt_argv_zero;
-  intptr_t rval = 127;
+  int rval = 127;
 
   int i;
 
   program_name = (char *) xstrdup (base_name (argv[0]));
-  newargz = XMALLOC (char *, argc + 1);
+  newargz = XMALLOC (char *, (size_t) argc + 1);
 
   /* very simple arg parsing; don't want to rely on getopt
    * also, copy all non cwrapper options to newargz, except
@@ -4371,10 +5749,10 @@ main (int argc, char *argv[])
   newargc=0;
   for (i = 1; i < argc; i++)
     {
-      if (strcmp (argv[i], dumpscript_opt) == 0)
+      if (STREQ (argv[i], dumpscript_opt))
 	{
 EOF
-	    case "$host" in
+	    case $host in
 	      *mingw* | *cygwin* )
 		# make stdout use "unix" line endings
 		echo "          setmode(1,_O_BINARY);"
@@ -4385,12 +5763,12 @@ EOF
 	  lt_dump_script (stdout);
 	  return 0;
 	}
-      if (strcmp (argv[i], debug_opt) == 0)
+      if (STREQ (argv[i], debug_opt))
 	{
           lt_debug = 1;
           continue;
 	}
-      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+      if (STREQ (argv[i], ltwrapper_option_prefix))
         {
           /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
              namespace, but it is not one of the ones we know about and
@@ -4413,7 +5791,7 @@ EOF
 EOF
 	    cat <<EOF
   /* The GNU banner must be the first non-error debug message */
-  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
 EOF
 	    cat <<"EOF"
   lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
@@ -4524,7 +5902,7 @@ EOF
 		cat <<"EOF"
   /* execv doesn't actually work on mingw as expected on unix */
   newargz = prepare_spawn (newargz);
-  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
   if (rval == -1)
     {
       /* failed to start process */
@@ -4569,7 +5947,7 @@ base_name (const char *name)
 {
   const char *base;
 
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
   /* Skip over the disk name in MSDOS pathnames. */
   if (isalpha ((unsigned char) name[0]) && name[1] == ':')
     name += 2;
@@ -4628,7 +6006,7 @@ find_executable (const char *wrapper)
   const char *p_next;
   /* static buffer for getcwd */
   char tmp[LT_PATHMAX + 1];
-  int tmp_len;
+  size_t tmp_len;
   char *concat_name;
 
   lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
@@ -4638,7 +6016,7 @@ find_executable (const char *wrapper)
     return NULL;
 
   /* Absolute path? */
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
   if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
     {
       concat_name = xstrdup (wrapper);
@@ -4656,7 +6034,7 @@ find_executable (const char *wrapper)
 	    return concat_name;
 	  XFREE (concat_name);
 	}
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
     }
 #endif
 
@@ -4679,7 +6057,7 @@ find_executable (const char *wrapper)
 	      for (q = p; *q; q++)
 		if (IS_PATH_SEPARATOR (*q))
 		  break;
-	      p_len = q - p;
+	      p_len = (size_t) (q - p);
 	      p_next = (*q == '\0' ? q : q + 1);
 	      if (p_len == 0)
 		{
@@ -4798,7 +6176,7 @@ strendzap (char *str, const char *pat)
   if (patlen <= len)
     {
       str += len - patlen;
-      if (strcmp (str, pat) == 0)
+      if (STREQ (str, pat))
 	*str = '\0';
     }
   return str;
@@ -4863,7 +6241,7 @@ lt_setenv (const char *name, const char *value)
     char *str = xstrdup (value);
     setenv (name, str, 1);
 #else
-    int len = strlen (name) + 1 + strlen (value) + 1;
+    size_t len = strlen (name) + 1 + strlen (value) + 1;
     char *str = XMALLOC (char, len);
     sprintf (str, "%s=%s", name, value);
     if (putenv (str) != EXIT_SUCCESS)
@@ -4880,8 +6258,8 @@ lt_extend_str (const char *orig_value, const char *add, int to_end)
   char *new_value;
   if (orig_value && *orig_value)
     {
-      int orig_value_len = strlen (orig_value);
-      int add_len = strlen (add);
+      size_t orig_value_len = strlen (orig_value);
+      size_t add_len = strlen (add);
       new_value = XMALLOC (char, add_len + orig_value_len + 1);
       if (to_end)
         {
@@ -4912,10 +6290,10 @@ lt_update_exe_path (const char *name, const char *value)
     {
       char *new_value = lt_extend_str (getenv (name), value, 0);
       /* some systems can't cope with a ':'-terminated path #' */
-      int len = strlen (new_value);
-      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+      size_t len = strlen (new_value);
+      while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
         {
-          new_value[len-1] = '\0';
+          new_value[--len] = '\0';
         }
       lt_setenv (name, new_value);
       XFREE (new_value);
@@ -5082,27 +6460,47 @@ EOF
 # True if ARG is an import lib, as indicated by $file_magic_cmd
 func_win32_import_lib_p ()
 {
-    $opt_debug
+    $debug_cmd
+
     case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
     *import*) : ;;
     *) false ;;
     esac
 }
 
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+    $debug_cmd
+
+    case " $compile_command " in
+    *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+      suncc_use_cstd_abi=no
+      ;;
+    *)
+      suncc_use_cstd_abi=yes
+      ;;
+    esac
+}
+
 # func_mode_link arg...
 func_mode_link ()
 {
-    $opt_debug
+    $debug_cmd
+
     case $host in
     *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
       # It is impossible to link a dll without this setting, and
       # we shouldn't force the makefile maintainer to figure out
-      # which system we are compiling for in order to pass an extra
+      # what system we are compiling for in order to pass an extra
       # flag for every libtool invocation.
       # allow_undefined=no
 
       # FIXME: Unfortunately, there are problems with the above when trying
-      # to make a dll which has undefined symbols, in which case not
+      # to make a dll that has undefined symbols, in which case not
       # even a static library is built.  For now, we need to specify
       # -no-undefined on the libtool link line when we can be certain
       # that all symbols are satisfied, otherwise we get a static library.
@@ -5146,10 +6544,11 @@ func_mode_link ()
     module=no
     no_install=no
     objs=
+    os2dllname=
     non_pic_objects=
     precious_files_regex=
     prefer_static_libs=no
-    preload=no
+    preload=false
     prev=
     prevarg=
     release=
@@ -5161,7 +6560,7 @@ func_mode_link ()
     vinfo=
     vinfo_number=no
     weak_libs=
-    single_module="${wl}-single_module"
+    single_module=$wl-single_module
     func_infer_tag $base_compile
 
     # We need to know -static, to get the right output filenames.
@@ -5169,15 +6568,15 @@ func_mode_link ()
     do
       case $arg in
       -shared)
-	test "$build_libtool_libs" != yes && \
-	  func_fatal_configuration "can not build a shared library"
+	test yes != "$build_libtool_libs" \
+	  && func_fatal_configuration "cannot build a shared library"
 	build_old_libs=no
 	break
 	;;
       -all-static | -static | -static-libtool-libs)
 	case $arg in
 	-all-static)
-	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	  if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
 	    func_warning "complete static linking is impossible in this configuration"
 	  fi
 	  if test -n "$link_static_flag"; then
@@ -5210,7 +6609,7 @@ func_mode_link ()
 
     # Go through the arguments, transforming them on the way.
     while test "$#" -gt 0; do
-      arg="$1"
+      arg=$1
       shift
       func_quote_for_eval "$arg"
       qarg=$func_quote_for_eval_unquoted_result
@@ -5227,21 +6626,21 @@ func_mode_link ()
 
 	case $prev in
 	bindir)
-	  bindir="$arg"
+	  bindir=$arg
 	  prev=
 	  continue
 	  ;;
 	dlfiles|dlprefiles)
-	  if test "$preload" = no; then
+	  $preload || {
 	    # Add the symbol object into the linking commands.
 	    func_append compile_command " @SYMFILE@"
 	    func_append finalize_command " @SYMFILE@"
-	    preload=yes
-	  fi
+	    preload=:
+	  }
 	  case $arg in
 	  *.la | *.lo) ;;  # We handle these cases below.
 	  force)
-	    if test "$dlself" = no; then
+	    if test no = "$dlself"; then
 	      dlself=needless
 	      export_dynamic=yes
 	    fi
@@ -5249,9 +6648,9 @@ func_mode_link ()
 	    continue
 	    ;;
 	  self)
-	    if test "$prev" = dlprefiles; then
+	    if test dlprefiles = "$prev"; then
 	      dlself=yes
-	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	    elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
 	      dlself=yes
 	    else
 	      dlself=needless
@@ -5261,7 +6660,7 @@ func_mode_link ()
 	    continue
 	    ;;
 	  *)
-	    if test "$prev" = dlfiles; then
+	    if test dlfiles = "$prev"; then
 	      func_append dlfiles " $arg"
 	    else
 	      func_append dlprefiles " $arg"
@@ -5272,14 +6671,14 @@ func_mode_link ()
 	  esac
 	  ;;
 	expsyms)
-	  export_symbols="$arg"
+	  export_symbols=$arg
 	  test -f "$arg" \
-	    || func_fatal_error "symbol file \`$arg' does not exist"
+	    || func_fatal_error "symbol file '$arg' does not exist"
 	  prev=
 	  continue
 	  ;;
 	expsyms_regex)
-	  export_symbols_regex="$arg"
+	  export_symbols_regex=$arg
 	  prev=
 	  continue
 	  ;;
@@ -5297,7 +6696,13 @@ func_mode_link ()
 	  continue
 	  ;;
 	inst_prefix)
-	  inst_prefix_dir="$arg"
+	  inst_prefix_dir=$arg
+	  prev=
+	  continue
+	  ;;
+	mllvm)
+	  # Clang does not use LLVM to link, so we can simply discard any
+	  # '-mllvm $arg' options when doing the link step.
 	  prev=
 	  continue
 	  ;;
@@ -5321,21 +6726,21 @@ func_mode_link ()
 
 		if test -z "$pic_object" ||
 		   test -z "$non_pic_object" ||
-		   test "$pic_object" = none &&
-		   test "$non_pic_object" = none; then
-		  func_fatal_error "cannot find name of object for \`$arg'"
+		   test none = "$pic_object" &&
+		   test none = "$non_pic_object"; then
+		  func_fatal_error "cannot find name of object for '$arg'"
 		fi
 
 		# Extract subdirectory from the argument.
 		func_dirname "$arg" "/" ""
-		xdir="$func_dirname_result"
+		xdir=$func_dirname_result
 
-		if test "$pic_object" != none; then
+		if test none != "$pic_object"; then
 		  # Prepend the subdirectory the object is found in.
-		  pic_object="$xdir$pic_object"
+		  pic_object=$xdir$pic_object
 
-		  if test "$prev" = dlfiles; then
-		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		  if test dlfiles = "$prev"; then
+		    if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
 		      func_append dlfiles " $pic_object"
 		      prev=
 		      continue
@@ -5346,7 +6751,7 @@ func_mode_link ()
 		  fi
 
 		  # CHECK ME:  I think I busted this.  -Ossama
-		  if test "$prev" = dlprefiles; then
+		  if test dlprefiles = "$prev"; then
 		    # Preload the old-style object.
 		    func_append dlprefiles " $pic_object"
 		    prev=
@@ -5354,23 +6759,23 @@ func_mode_link ()
 
 		  # A PIC object.
 		  func_append libobjs " $pic_object"
-		  arg="$pic_object"
+		  arg=$pic_object
 		fi
 
 		# Non-PIC object.
-		if test "$non_pic_object" != none; then
+		if test none != "$non_pic_object"; then
 		  # Prepend the subdirectory the object is found in.
-		  non_pic_object="$xdir$non_pic_object"
+		  non_pic_object=$xdir$non_pic_object
 
 		  # A standard non-PIC object
 		  func_append non_pic_objects " $non_pic_object"
-		  if test -z "$pic_object" || test "$pic_object" = none ; then
-		    arg="$non_pic_object"
+		  if test -z "$pic_object" || test none = "$pic_object"; then
+		    arg=$non_pic_object
 		  fi
 		else
 		  # If the PIC object exists, use it instead.
 		  # $xdir was prepended to $pic_object above.
-		  non_pic_object="$pic_object"
+		  non_pic_object=$pic_object
 		  func_append non_pic_objects " $non_pic_object"
 		fi
 	      else
@@ -5378,7 +6783,7 @@ func_mode_link ()
 		if $opt_dry_run; then
 		  # Extract subdirectory from the argument.
 		  func_dirname "$arg" "/" ""
-		  xdir="$func_dirname_result"
+		  xdir=$func_dirname_result
 
 		  func_lo2o "$arg"
 		  pic_object=$xdir$objdir/$func_lo2o_result
@@ -5386,24 +6791,29 @@ func_mode_link ()
 		  func_append libobjs " $pic_object"
 		  func_append non_pic_objects " $non_pic_object"
 	        else
-		  func_fatal_error "\`$arg' is not a valid libtool object"
+		  func_fatal_error "'$arg' is not a valid libtool object"
 		fi
 	      fi
 	    done
 	  else
-	    func_fatal_error "link input file \`$arg' does not exist"
+	    func_fatal_error "link input file '$arg' does not exist"
 	  fi
 	  arg=$save_arg
 	  prev=
 	  continue
 	  ;;
+	os2dllname)
+	  os2dllname=$arg
+	  prev=
+	  continue
+	  ;;
 	precious_regex)
-	  precious_files_regex="$arg"
+	  precious_files_regex=$arg
 	  prev=
 	  continue
 	  ;;
 	release)
-	  release="-$arg"
+	  release=-$arg
 	  prev=
 	  continue
 	  ;;
@@ -5415,7 +6825,7 @@ func_mode_link ()
 	    func_fatal_error "only absolute run-paths are allowed"
 	    ;;
 	  esac
-	  if test "$prev" = rpath; then
+	  if test rpath = "$prev"; then
 	    case "$rpath " in
 	    *" $arg "*) ;;
 	    *) func_append rpath " $arg" ;;
@@ -5430,7 +6840,7 @@ func_mode_link ()
 	  continue
 	  ;;
 	shrext)
-	  shrext_cmds="$arg"
+	  shrext_cmds=$arg
 	  prev=
 	  continue
 	  ;;
@@ -5470,7 +6880,7 @@ func_mode_link ()
 	esac
       fi # test -n "$prev"
 
-      prevarg="$arg"
+      prevarg=$arg
 
       case $arg in
       -all-static)
@@ -5484,7 +6894,7 @@ func_mode_link ()
 
       -allow-undefined)
 	# FIXME: remove this flag sometime in the future.
-	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	func_fatal_error "'-allow-undefined' must not be used because it is the default"
 	;;
 
       -avoid-version)
@@ -5516,7 +6926,7 @@ func_mode_link ()
 	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
 	  func_fatal_error "more than one -exported-symbols argument is not allowed"
 	fi
-	if test "X$arg" = "X-export-symbols"; then
+	if test X-export-symbols = "X$arg"; then
 	  prev=expsyms
 	else
 	  prev=expsyms_regex
@@ -5550,9 +6960,9 @@ func_mode_link ()
 	func_stripname "-L" '' "$arg"
 	if test -z "$func_stripname_result"; then
 	  if test "$#" -gt 0; then
-	    func_fatal_error "require no space between \`-L' and \`$1'"
+	    func_fatal_error "require no space between '-L' and '$1'"
 	  else
-	    func_fatal_error "need path for \`-L' option"
+	    func_fatal_error "need path for '-L' option"
 	  fi
 	fi
 	func_resolve_sysroot "$func_stripname_result"
@@ -5563,8 +6973,8 @@ func_mode_link ()
 	*)
 	  absdir=`cd "$dir" && pwd`
 	  test -z "$absdir" && \
-	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
-	  dir="$absdir"
+	    func_fatal_error "cannot determine absolute directory name of '$dir'"
+	  dir=$absdir
 	  ;;
 	esac
 	case "$deplibs " in
@@ -5599,7 +7009,7 @@ func_mode_link ()
 	;;
 
       -l*)
-	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	if test X-lc = "X$arg" || test X-lm = "X$arg"; then
 	  case $host in
 	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
 	    # These systems don't actually have a C or math library (as such)
@@ -5607,11 +7017,11 @@ func_mode_link ()
 	    ;;
 	  *-*-os2*)
 	    # These systems don't actually have a C library (as such)
-	    test "X$arg" = "X-lc" && continue
+	    test X-lc = "X$arg" && continue
 	    ;;
-	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
 	    # Do not include libc due to us having libc/libc_r.
-	    test "X$arg" = "X-lc" && continue
+	    test X-lc = "X$arg" && continue
 	    ;;
 	  *-*-rhapsody* | *-*-darwin1.[012])
 	    # Rhapsody C and math libraries are in the System framework
@@ -5620,16 +7030,16 @@ func_mode_link ()
 	    ;;
 	  *-*-sco3.2v5* | *-*-sco5v6*)
 	    # Causes problems with __ctype
-	    test "X$arg" = "X-lc" && continue
+	    test X-lc = "X$arg" && continue
 	    ;;
 	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
 	    # Compiler inserts libc in the correct place for threads to work
-	    test "X$arg" = "X-lc" && continue
+	    test X-lc = "X$arg" && continue
 	    ;;
 	  esac
-	elif test "X$arg" = "X-lc_r"; then
+	elif test X-lc_r = "X$arg"; then
 	 case $host in
-	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
 	   # Do not include libc_r directly, use -pthread flag.
 	   continue
 	   ;;
@@ -5639,6 +7049,11 @@ func_mode_link ()
 	continue
 	;;
 
+      -mllvm)
+	prev=mllvm
+	continue
+	;;
+
       -module)
 	module=yes
 	continue
@@ -5668,7 +7083,7 @@ func_mode_link ()
 	;;
 
       -multi_module)
-	single_module="${wl}-multi_module"
+	single_module=$wl-multi_module
 	continue
 	;;
 
@@ -5682,8 +7097,8 @@ func_mode_link ()
 	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
 	  # The PATH hackery in wrapper scripts is required on Windows
 	  # and Darwin in order for the loader to find any dlls it needs.
-	  func_warning "\`-no-install' is ignored for $host"
-	  func_warning "assuming \`-no-fast-install' instead"
+	  func_warning "'-no-install' is ignored for $host"
+	  func_warning "assuming '-no-fast-install' instead"
 	  fast_install=no
 	  ;;
 	*) no_install=yes ;;
@@ -5701,6 +7116,11 @@ func_mode_link ()
 	continue
 	;;
 
+      -os2dllname)
+	prev=os2dllname
+	continue
+	;;
+
       -o) prev=output ;;
 
       -precious-files-regex)
@@ -5788,14 +7208,14 @@ func_mode_link ()
 	func_stripname '-Wc,' '' "$arg"
 	args=$func_stripname_result
 	arg=
-	save_ifs="$IFS"; IFS=','
+	save_ifs=$IFS; IFS=,
 	for flag in $args; do
-	  IFS="$save_ifs"
+	  IFS=$save_ifs
           func_quote_for_eval "$flag"
 	  func_append arg " $func_quote_for_eval_result"
 	  func_append compiler_flags " $func_quote_for_eval_result"
 	done
-	IFS="$save_ifs"
+	IFS=$save_ifs
 	func_stripname ' ' '' "$arg"
 	arg=$func_stripname_result
 	;;
@@ -5804,15 +7224,15 @@ func_mode_link ()
 	func_stripname '-Wl,' '' "$arg"
 	args=$func_stripname_result
 	arg=
-	save_ifs="$IFS"; IFS=','
+	save_ifs=$IFS; IFS=,
 	for flag in $args; do
-	  IFS="$save_ifs"
+	  IFS=$save_ifs
           func_quote_for_eval "$flag"
 	  func_append arg " $wl$func_quote_for_eval_result"
 	  func_append compiler_flags " $wl$func_quote_for_eval_result"
 	  func_append linker_flags " $func_quote_for_eval_result"
 	done
-	IFS="$save_ifs"
+	IFS=$save_ifs
 	func_stripname ' ' '' "$arg"
 	arg=$func_stripname_result
 	;;
@@ -5835,7 +7255,7 @@ func_mode_link ()
       # -msg_* for osf cc
       -msg_*)
 	func_quote_for_eval "$arg"
-	arg="$func_quote_for_eval_result"
+	arg=$func_quote_for_eval_result
 	;;
 
       # Flags to be passed through unchanged, with rationale:
@@ -5847,25 +7267,49 @@ func_mode_link ()
       # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
       # -F/path              path to uninstalled frameworks, gcc on darwin
       # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # -fstack-protector*   stack protector flags for GCC
       # @file                GCC response files
       # -tp=*                Portland pgcc target processor selection
       # --sysroot=*          for sysroot support
-      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      # -specs=*             GCC specs files
+      # -stdlib=*            select c++ std lib with clang
+      # -fsanitize=*         Clang/GCC memory and address sanitizer
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
-      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+      -specs=*|-fsanitize=*)
         func_quote_for_eval "$arg"
-	arg="$func_quote_for_eval_result"
+	arg=$func_quote_for_eval_result
         func_append compile_command " $arg"
         func_append finalize_command " $arg"
         func_append compiler_flags " $arg"
         continue
         ;;
 
+      -Z*)
+        if test os2 = "`expr $host : '.*\(os2\)'`"; then
+          # OS/2 uses -Zxxx to specify OS/2-specific options
+	  compiler_flags="$compiler_flags $arg"
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  case $arg in
+	  -Zlinker | -Zstack)
+	    prev=xcompiler
+	    ;;
+	  esac
+	  continue
+        else
+	  # Otherwise treat like 'Some other compiler flag' below
+	  func_quote_for_eval "$arg"
+	  arg=$func_quote_for_eval_result
+        fi
+	;;
+
       # Some other compiler flag.
       -* | +*)
         func_quote_for_eval "$arg"
-	arg="$func_quote_for_eval_result"
+	arg=$func_quote_for_eval_result
 	;;
 
       *.$objext)
@@ -5886,21 +7330,21 @@ func_mode_link ()
 
 	  if test -z "$pic_object" ||
 	     test -z "$non_pic_object" ||
-	     test "$pic_object" = none &&
-	     test "$non_pic_object" = none; then
-	    func_fatal_error "cannot find name of object for \`$arg'"
+	     test none = "$pic_object" &&
+	     test none = "$non_pic_object"; then
+	    func_fatal_error "cannot find name of object for '$arg'"
 	  fi
 
 	  # Extract subdirectory from the argument.
 	  func_dirname "$arg" "/" ""
-	  xdir="$func_dirname_result"
+	  xdir=$func_dirname_result
 
-	  if test "$pic_object" != none; then
+	  test none = "$pic_object" || {
 	    # Prepend the subdirectory the object is found in.
-	    pic_object="$xdir$pic_object"
+	    pic_object=$xdir$pic_object
 
-	    if test "$prev" = dlfiles; then
-	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+	    if test dlfiles = "$prev"; then
+	      if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
 		func_append dlfiles " $pic_object"
 		prev=
 		continue
@@ -5911,7 +7355,7 @@ func_mode_link ()
 	    fi
 
 	    # CHECK ME:  I think I busted this.  -Ossama
-	    if test "$prev" = dlprefiles; then
+	    if test dlprefiles = "$prev"; then
 	      # Preload the old-style object.
 	      func_append dlprefiles " $pic_object"
 	      prev=
@@ -5919,23 +7363,23 @@ func_mode_link ()
 
 	    # A PIC object.
 	    func_append libobjs " $pic_object"
-	    arg="$pic_object"
-	  fi
+	    arg=$pic_object
+	  }
 
 	  # Non-PIC object.
-	  if test "$non_pic_object" != none; then
+	  if test none != "$non_pic_object"; then
 	    # Prepend the subdirectory the object is found in.
-	    non_pic_object="$xdir$non_pic_object"
+	    non_pic_object=$xdir$non_pic_object
 
 	    # A standard non-PIC object
 	    func_append non_pic_objects " $non_pic_object"
-	    if test -z "$pic_object" || test "$pic_object" = none ; then
-	      arg="$non_pic_object"
+	    if test -z "$pic_object" || test none = "$pic_object"; then
+	      arg=$non_pic_object
 	    fi
 	  else
 	    # If the PIC object exists, use it instead.
 	    # $xdir was prepended to $pic_object above.
-	    non_pic_object="$pic_object"
+	    non_pic_object=$pic_object
 	    func_append non_pic_objects " $non_pic_object"
 	  fi
 	else
@@ -5943,7 +7387,7 @@ func_mode_link ()
 	  if $opt_dry_run; then
 	    # Extract subdirectory from the argument.
 	    func_dirname "$arg" "/" ""
-	    xdir="$func_dirname_result"
+	    xdir=$func_dirname_result
 
 	    func_lo2o "$arg"
 	    pic_object=$xdir$objdir/$func_lo2o_result
@@ -5951,7 +7395,7 @@ func_mode_link ()
 	    func_append libobjs " $pic_object"
 	    func_append non_pic_objects " $non_pic_object"
 	  else
-	    func_fatal_error "\`$arg' is not a valid libtool object"
+	    func_fatal_error "'$arg' is not a valid libtool object"
 	  fi
 	fi
 	;;
@@ -5967,11 +7411,11 @@ func_mode_link ()
 	# A libtool-controlled library.
 
 	func_resolve_sysroot "$arg"
-	if test "$prev" = dlfiles; then
+	if test dlfiles = "$prev"; then
 	  # This library was specified with -dlopen.
 	  func_append dlfiles " $func_resolve_sysroot_result"
 	  prev=
-	elif test "$prev" = dlprefiles; then
+	elif test dlprefiles = "$prev"; then
 	  # The library was specified with -dlpreopen.
 	  func_append dlprefiles " $func_resolve_sysroot_result"
 	  prev=
@@ -5986,7 +7430,7 @@ func_mode_link ()
 	# Unknown arguments in both finalize_command and compile_command need
 	# to be aesthetically quoted because they are evaled later.
 	func_quote_for_eval "$arg"
-	arg="$func_quote_for_eval_result"
+	arg=$func_quote_for_eval_result
 	;;
       esac # arg
 
@@ -5998,9 +7442,9 @@ func_mode_link ()
     done # argument parsing loop
 
     test -n "$prev" && \
-      func_fatal_help "the \`$prevarg' option requires an argument"
+      func_fatal_help "the '$prevarg' option requires an argument"
 
-    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+    if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
       eval arg=\"$export_dynamic_flag_spec\"
       func_append compile_command " $arg"
       func_append finalize_command " $arg"
@@ -6009,20 +7453,23 @@ func_mode_link ()
     oldlibs=
     # calculate the name of the file, without its directory
     func_basename "$output"
-    outputname="$func_basename_result"
-    libobjs_save="$libobjs"
+    outputname=$func_basename_result
+    libobjs_save=$libobjs
 
     if test -n "$shlibpath_var"; then
       # get the directories listed in $shlibpath_var
-      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+      eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
     else
       shlib_search_path=
     fi
     eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
     eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
 
+    # Definition is injected by LT_CONFIG during libtool generation.
+    func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
     func_dirname "$output" "/" ""
-    output_objdir="$func_dirname_result$objdir"
+    output_objdir=$func_dirname_result$objdir
     func_to_tool_file "$output_objdir/"
     tool_output_objdir=$func_to_tool_file_result
     # Create the object directory.
@@ -6045,7 +7492,7 @@ func_mode_link ()
     # Find all interdependent deplibs by searching for libraries
     # that are linked more than once (e.g. -la -lb -la)
     for deplib in $deplibs; do
-      if $opt_preserve_dup_deps ; then
+      if $opt_preserve_dup_deps; then
 	case "$libs " in
 	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
 	esac
@@ -6053,7 +7500,7 @@ func_mode_link ()
       func_append libs " $deplib"
     done
 
-    if test "$linkmode" = lib; then
+    if test lib = "$linkmode"; then
       libs="$predeps $libs $compiler_lib_search_path $postdeps"
 
       # Compute libraries that are listed more than once in $predeps
@@ -6085,7 +7532,7 @@ func_mode_link ()
 	  case $file in
 	  *.la) ;;
 	  *)
-	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
 	    ;;
 	  esac
 	done
@@ -6093,7 +7540,7 @@ func_mode_link ()
     prog)
 	compile_deplibs=
 	finalize_deplibs=
-	alldeplibs=no
+	alldeplibs=false
 	newdlfiles=
 	newdlprefiles=
 	passes="conv scan dlopen dlpreopen link"
@@ -6105,32 +7552,32 @@ func_mode_link ()
     for pass in $passes; do
       # The preopen pass in lib mode reverses $deplibs; put it back here
       # so that -L comes before libs that need it for instance...
-      if test "$linkmode,$pass" = "lib,link"; then
+      if test lib,link = "$linkmode,$pass"; then
 	## FIXME: Find the place where the list is rebuilt in the wrong
 	##        order, and fix it there properly
         tmp_deplibs=
 	for deplib in $deplibs; do
 	  tmp_deplibs="$deplib $tmp_deplibs"
 	done
-	deplibs="$tmp_deplibs"
+	deplibs=$tmp_deplibs
       fi
 
-      if test "$linkmode,$pass" = "lib,link" ||
-	 test "$linkmode,$pass" = "prog,scan"; then
-	libs="$deplibs"
+      if test lib,link = "$linkmode,$pass" ||
+	 test prog,scan = "$linkmode,$pass"; then
+	libs=$deplibs
 	deplibs=
       fi
-      if test "$linkmode" = prog; then
+      if test prog = "$linkmode"; then
 	case $pass in
-	dlopen) libs="$dlfiles" ;;
-	dlpreopen) libs="$dlprefiles" ;;
+	dlopen) libs=$dlfiles ;;
+	dlpreopen) libs=$dlprefiles ;;
 	link)
 	  libs="$deplibs %DEPLIBS%"
 	  test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
 	  ;;
 	esac
       fi
-      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+      if test lib,dlpreopen = "$linkmode,$pass"; then
 	# Collect and forward deplibs of preopened libtool libs
 	for lib in $dlprefiles; do
 	  # Ignore non-libtool-libs
@@ -6151,26 +7598,26 @@ func_mode_link ()
 	    esac
 	  done
 	done
-	libs="$dlprefiles"
+	libs=$dlprefiles
       fi
-      if test "$pass" = dlopen; then
+      if test dlopen = "$pass"; then
 	# Collect dlpreopened libraries
-	save_deplibs="$deplibs"
+	save_deplibs=$deplibs
 	deplibs=
       fi
 
       for deplib in $libs; do
 	lib=
-	found=no
+	found=false
 	case $deplib in
 	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
         |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
-	  if test "$linkmode,$pass" = "prog,link"; then
+	  if test prog,link = "$linkmode,$pass"; then
 	    compile_deplibs="$deplib $compile_deplibs"
 	    finalize_deplibs="$deplib $finalize_deplibs"
 	  else
 	    func_append compiler_flags " $deplib"
-	    if test "$linkmode" = lib ; then
+	    if test lib = "$linkmode"; then
 		case "$new_inherited_linker_flags " in
 		    *" $deplib "*) ;;
 		    * ) func_append new_inherited_linker_flags " $deplib" ;;
@@ -6180,13 +7627,13 @@ func_mode_link ()
 	  continue
 	  ;;
 	-l*)
-	  if test "$linkmode" != lib && test "$linkmode" != prog; then
-	    func_warning "\`-l' is ignored for archives/objects"
+	  if test lib != "$linkmode" && test prog != "$linkmode"; then
+	    func_warning "'-l' is ignored for archives/objects"
 	    continue
 	  fi
 	  func_stripname '-l' '' "$deplib"
 	  name=$func_stripname_result
-	  if test "$linkmode" = lib; then
+	  if test lib = "$linkmode"; then
 	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
 	  else
 	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
@@ -6194,31 +7641,22 @@ func_mode_link ()
 	  for searchdir in $searchdirs; do
 	    for search_ext in .la $std_shrext .so .a; do
 	      # Search the libtool library
-	      lib="$searchdir/lib${name}${search_ext}"
+	      lib=$searchdir/lib$name$search_ext
 	      if test -f "$lib"; then
-		if test "$search_ext" = ".la"; then
-		  found=yes
+		if test .la = "$search_ext"; then
+		  found=:
 		else
-		  found=no
+		  found=false
 		fi
 		break 2
 	      fi
 	    done
 	  done
-	  if test "$found" != yes; then
-	    # deplib doesn't seem to be a libtool library
-	    if test "$linkmode,$pass" = "prog,link"; then
-	      compile_deplibs="$deplib $compile_deplibs"
-	      finalize_deplibs="$deplib $finalize_deplibs"
-	    else
-	      deplibs="$deplib $deplibs"
-	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
-	    fi
-	    continue
-	  else # deplib is a libtool library
+	  if $found; then
+	    # deplib is a libtool library
 	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
 	    # We need to do some special things here, and not later.
-	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    if test yes = "$allow_libtool_libs_with_static_runtimes"; then
 	      case " $predeps $postdeps " in
 	      *" $deplib "*)
 		if func_lalib_p "$lib"; then
@@ -6226,19 +7664,19 @@ func_mode_link ()
 		  old_library=
 		  func_source "$lib"
 		  for l in $old_library $library_names; do
-		    ll="$l"
+		    ll=$l
 		  done
-		  if test "X$ll" = "X$old_library" ; then # only static version available
-		    found=no
+		  if test "X$ll" = "X$old_library"; then # only static version available
+		    found=false
 		    func_dirname "$lib" "" "."
-		    ladir="$func_dirname_result"
+		    ladir=$func_dirname_result
 		    lib=$ladir/$old_library
-		    if test "$linkmode,$pass" = "prog,link"; then
+		    if test prog,link = "$linkmode,$pass"; then
 		      compile_deplibs="$deplib $compile_deplibs"
 		      finalize_deplibs="$deplib $finalize_deplibs"
 		    else
 		      deplibs="$deplib $deplibs"
-		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		      test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
 		    fi
 		    continue
 		  fi
@@ -6247,15 +7685,25 @@ func_mode_link ()
 	      *) ;;
 	      esac
 	    fi
+	  else
+	    # deplib doesn't seem to be a libtool library
+	    if test prog,link = "$linkmode,$pass"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
 	  fi
 	  ;; # -l
 	*.ltframework)
-	  if test "$linkmode,$pass" = "prog,link"; then
+	  if test prog,link = "$linkmode,$pass"; then
 	    compile_deplibs="$deplib $compile_deplibs"
 	    finalize_deplibs="$deplib $finalize_deplibs"
 	  else
 	    deplibs="$deplib $deplibs"
-	    if test "$linkmode" = lib ; then
+	    if test lib = "$linkmode"; then
 		case "$new_inherited_linker_flags " in
 		    *" $deplib "*) ;;
 		    * ) func_append new_inherited_linker_flags " $deplib" ;;
@@ -6268,18 +7716,18 @@ func_mode_link ()
 	  case $linkmode in
 	  lib)
 	    deplibs="$deplib $deplibs"
-	    test "$pass" = conv && continue
+	    test conv = "$pass" && continue
 	    newdependency_libs="$deplib $newdependency_libs"
 	    func_stripname '-L' '' "$deplib"
 	    func_resolve_sysroot "$func_stripname_result"
 	    func_append newlib_search_path " $func_resolve_sysroot_result"
 	    ;;
 	  prog)
-	    if test "$pass" = conv; then
+	    if test conv = "$pass"; then
 	      deplibs="$deplib $deplibs"
 	      continue
 	    fi
-	    if test "$pass" = scan; then
+	    if test scan = "$pass"; then
 	      deplibs="$deplib $deplibs"
 	    else
 	      compile_deplibs="$deplib $compile_deplibs"
@@ -6290,13 +7738,13 @@ func_mode_link ()
 	    func_append newlib_search_path " $func_resolve_sysroot_result"
 	    ;;
 	  *)
-	    func_warning "\`-L' is ignored for archives/objects"
+	    func_warning "'-L' is ignored for archives/objects"
 	    ;;
 	  esac # linkmode
 	  continue
 	  ;; # -L
 	-R*)
-	  if test "$pass" = link; then
+	  if test link = "$pass"; then
 	    func_stripname '-R' '' "$deplib"
 	    func_resolve_sysroot "$func_stripname_result"
 	    dir=$func_resolve_sysroot_result
@@ -6314,7 +7762,7 @@ func_mode_link ()
 	  lib=$func_resolve_sysroot_result
 	  ;;
 	*.$libext)
-	  if test "$pass" = conv; then
+	  if test conv = "$pass"; then
 	    deplibs="$deplib $deplibs"
 	    continue
 	  fi
@@ -6325,21 +7773,26 @@ func_mode_link ()
 	    case " $dlpreconveniencelibs " in
 	    *" $deplib "*) ;;
 	    *)
-	      valid_a_lib=no
+	      valid_a_lib=false
 	      case $deplibs_check_method in
 		match_pattern*)
 		  set dummy $deplibs_check_method; shift
 		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
 		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
 		    | $EGREP "$match_pattern_regex" > /dev/null; then
-		    valid_a_lib=yes
+		    valid_a_lib=:
 		  fi
 		;;
 		pass_all)
-		  valid_a_lib=yes
+		  valid_a_lib=:
 		;;
 	      esac
-	      if test "$valid_a_lib" != yes; then
+	      if $valid_a_lib; then
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      else
 		echo
 		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
 		echo "*** I have the capability to make that library automatically link in when"
@@ -6347,18 +7800,13 @@ func_mode_link ()
 		echo "*** shared version of the library, which you do not appear to have"
 		echo "*** because the file extensions .$libext of this argument makes me believe"
 		echo "*** that it is just a static archive that I should not use here."
-	      else
-		echo
-		$ECHO "*** Warning: Linking the shared library $output against the"
-		$ECHO "*** static library $deplib is not portable!"
-		deplibs="$deplib $deplibs"
 	      fi
 	      ;;
 	    esac
 	    continue
 	    ;;
 	  prog)
-	    if test "$pass" != link; then
+	    if test link != "$pass"; then
 	      deplibs="$deplib $deplibs"
 	    else
 	      compile_deplibs="$deplib $compile_deplibs"
@@ -6369,10 +7817,10 @@ func_mode_link ()
 	  esac # linkmode
 	  ;; # *.$libext
 	*.lo | *.$objext)
-	  if test "$pass" = conv; then
+	  if test conv = "$pass"; then
 	    deplibs="$deplib $deplibs"
-	  elif test "$linkmode" = prog; then
-	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	  elif test prog = "$linkmode"; then
+	    if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
 	      # If there is no dlopen support or we're linking statically,
 	      # we need to preload.
 	      func_append newdlprefiles " $deplib"
@@ -6385,22 +7833,20 @@ func_mode_link ()
 	  continue
 	  ;;
 	%DEPLIBS%)
-	  alldeplibs=yes
+	  alldeplibs=:
 	  continue
 	  ;;
 	esac # case $deplib
 
-	if test "$found" = yes || test -f "$lib"; then :
-	else
-	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
-	fi
+	$found || test -f "$lib" \
+	  || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
 
 	# Check to see that this really is a libtool archive.
 	func_lalib_unsafe_p "$lib" \
-	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+	  || func_fatal_error "'$lib' is not a valid libtool archive"
 
 	func_dirname "$lib" "" "."
-	ladir="$func_dirname_result"
+	ladir=$func_dirname_result
 
 	dlname=
 	dlopen=
@@ -6430,19 +7876,19 @@ func_mode_link ()
 	  done
 	fi
 	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-	if test "$linkmode,$pass" = "lib,link" ||
-	   test "$linkmode,$pass" = "prog,scan" ||
-	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	if test lib,link = "$linkmode,$pass" ||
+	   test prog,scan = "$linkmode,$pass" ||
+	   { test prog != "$linkmode" && test lib != "$linkmode"; }; then
 	  test -n "$dlopen" && func_append dlfiles " $dlopen"
 	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
 	fi
 
-	if test "$pass" = conv; then
+	if test conv = "$pass"; then
 	  # Only check for convenience libraries
 	  deplibs="$lib $deplibs"
 	  if test -z "$libdir"; then
 	    if test -z "$old_library"; then
-	      func_fatal_error "cannot find name of link library for \`$lib'"
+	      func_fatal_error "cannot find name of link library for '$lib'"
 	    fi
 	    # It is a libtool convenience library, so add in its objects.
 	    func_append convenience " $ladir/$objdir/$old_library"
@@ -6450,15 +7896,15 @@ func_mode_link ()
 	    tmp_libs=
 	    for deplib in $dependency_libs; do
 	      deplibs="$deplib $deplibs"
-	      if $opt_preserve_dup_deps ; then
+	      if $opt_preserve_dup_deps; then
 		case "$tmp_libs " in
 		*" $deplib "*) func_append specialdeplibs " $deplib" ;;
 		esac
 	      fi
 	      func_append tmp_libs " $deplib"
 	    done
-	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
-	    func_fatal_error "\`$lib' is not a convenience library"
+	  elif test prog != "$linkmode" && test lib != "$linkmode"; then
+	    func_fatal_error "'$lib' is not a convenience library"
 	  fi
 	  continue
 	fi # $pass = conv
@@ -6467,26 +7913,26 @@ func_mode_link ()
 	# Get the name of the library we link against.
 	linklib=
 	if test -n "$old_library" &&
-	   { test "$prefer_static_libs" = yes ||
-	     test "$prefer_static_libs,$installed" = "built,no"; }; then
+	   { test yes = "$prefer_static_libs" ||
+	     test built,no = "$prefer_static_libs,$installed"; }; then
 	  linklib=$old_library
 	else
 	  for l in $old_library $library_names; do
-	    linklib="$l"
+	    linklib=$l
 	  done
 	fi
 	if test -z "$linklib"; then
-	  func_fatal_error "cannot find name of link library for \`$lib'"
+	  func_fatal_error "cannot find name of link library for '$lib'"
 	fi
 
 	# This library was specified with -dlopen.
-	if test "$pass" = dlopen; then
-	  if test -z "$libdir"; then
-	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
-	  fi
+	if test dlopen = "$pass"; then
+	  test -z "$libdir" \
+	    && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
 	  if test -z "$dlname" ||
-	     test "$dlopen_support" != yes ||
-	     test "$build_libtool_libs" = no; then
+	     test yes != "$dlopen_support" ||
+	     test no = "$build_libtool_libs"
+	  then
 	    # If there is no dlname, no dlopen support or we're linking
 	    # statically, we need to preload.  We also need to preload any
 	    # dependent libraries so libltdl's deplib preloader doesn't
@@ -6500,40 +7946,40 @@ func_mode_link ()
 
 	# We need an absolute path.
 	case $ladir in
-	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
 	*)
 	  abs_ladir=`cd "$ladir" && pwd`
 	  if test -z "$abs_ladir"; then
-	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "cannot determine absolute directory name of '$ladir'"
 	    func_warning "passing it literally to the linker, although it might fail"
-	    abs_ladir="$ladir"
+	    abs_ladir=$ladir
 	  fi
 	  ;;
 	esac
 	func_basename "$lib"
-	laname="$func_basename_result"
+	laname=$func_basename_result
 
 	# Find the relevant object directory and library name.
-	if test "X$installed" = Xyes; then
+	if test yes = "$installed"; then
 	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
-	    func_warning "library \`$lib' was moved."
-	    dir="$ladir"
-	    absdir="$abs_ladir"
-	    libdir="$abs_ladir"
+	    func_warning "library '$lib' was moved."
+	    dir=$ladir
+	    absdir=$abs_ladir
+	    libdir=$abs_ladir
 	  else
-	    dir="$lt_sysroot$libdir"
-	    absdir="$lt_sysroot$libdir"
+	    dir=$lt_sysroot$libdir
+	    absdir=$lt_sysroot$libdir
 	  fi
-	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	  test yes = "$hardcode_automatic" && avoidtemprpath=yes
 	else
 	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
-	    dir="$ladir"
-	    absdir="$abs_ladir"
+	    dir=$ladir
+	    absdir=$abs_ladir
 	    # Remove this search path later
 	    func_append notinst_path " $abs_ladir"
 	  else
-	    dir="$ladir/$objdir"
-	    absdir="$abs_ladir/$objdir"
+	    dir=$ladir/$objdir
+	    absdir=$abs_ladir/$objdir
 	    # Remove this search path later
 	    func_append notinst_path " $abs_ladir"
 	  fi
@@ -6542,11 +7988,11 @@ func_mode_link ()
 	name=$func_stripname_result
 
 	# This library was specified with -dlpreopen.
-	if test "$pass" = dlpreopen; then
-	  if test -z "$libdir" && test "$linkmode" = prog; then
-	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	if test dlpreopen = "$pass"; then
+	  if test -z "$libdir" && test prog = "$linkmode"; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
 	  fi
-	  case "$host" in
+	  case $host in
 	    # special handling for platforms with PE-DLLs.
 	    *cygwin* | *mingw* | *cegcc* )
 	      # Linker will automatically link against shared library if both
@@ -6590,9 +8036,9 @@ func_mode_link ()
 
 	if test -z "$libdir"; then
 	  # Link the convenience library
-	  if test "$linkmode" = lib; then
+	  if test lib = "$linkmode"; then
 	    deplibs="$dir/$old_library $deplibs"
-	  elif test "$linkmode,$pass" = "prog,link"; then
+	  elif test prog,link = "$linkmode,$pass"; then
 	    compile_deplibs="$dir/$old_library $compile_deplibs"
 	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
 	  else
@@ -6602,14 +8048,14 @@ func_mode_link ()
 	fi
 
 
-	if test "$linkmode" = prog && test "$pass" != link; then
+	if test prog = "$linkmode" && test link != "$pass"; then
 	  func_append newlib_search_path " $ladir"
 	  deplibs="$lib $deplibs"
 
-	  linkalldeplibs=no
-	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
-	     test "$build_libtool_libs" = no; then
-	    linkalldeplibs=yes
+	  linkalldeplibs=false
+	  if test no != "$link_all_deplibs" || test -z "$library_names" ||
+	     test no = "$build_libtool_libs"; then
+	    linkalldeplibs=:
 	  fi
 
 	  tmp_libs=
@@ -6621,14 +8067,14 @@ func_mode_link ()
 		 ;;
 	    esac
 	    # Need to link against all dependency_libs?
-	    if test "$linkalldeplibs" = yes; then
+	    if $linkalldeplibs; then
 	      deplibs="$deplib $deplibs"
 	    else
 	      # Need to hardcode shared library paths
 	      # or/and link against static libraries
 	      newdependency_libs="$deplib $newdependency_libs"
 	    fi
-	    if $opt_preserve_dup_deps ; then
+	    if $opt_preserve_dup_deps; then
 	      case "$tmp_libs " in
 	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
 	      esac
@@ -6638,15 +8084,15 @@ func_mode_link ()
 	  continue
 	fi # $linkmode = prog...
 
-	if test "$linkmode,$pass" = "prog,link"; then
+	if test prog,link = "$linkmode,$pass"; then
 	  if test -n "$library_names" &&
-	     { { test "$prefer_static_libs" = no ||
-	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	     { { test no = "$prefer_static_libs" ||
+	         test built,yes = "$prefer_static_libs,$installed"; } ||
 	       test -z "$old_library"; }; then
 	    # We need to hardcode the library path
-	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
 	      # Make sure the rpath contains only unique directories.
-	      case "$temp_rpath:" in
+	      case $temp_rpath: in
 	      *"$absdir:"*) ;;
 	      *) func_append temp_rpath "$absdir:" ;;
 	      esac
@@ -6675,9 +8121,9 @@ func_mode_link ()
 	    esac
 	  fi # $linkmode,$pass = prog,link...
 
-	  if test "$alldeplibs" = yes &&
-	     { test "$deplibs_check_method" = pass_all ||
-	       { test "$build_libtool_libs" = yes &&
+	  if $alldeplibs &&
+	     { test pass_all = "$deplibs_check_method" ||
+	       { test yes = "$build_libtool_libs" &&
 		 test -n "$library_names"; }; }; then
 	    # We only need to search for static libraries
 	    continue
@@ -6686,19 +8132,19 @@ func_mode_link ()
 
 	link_static=no # Whether the deplib will be linked statically
 	use_static_libs=$prefer_static_libs
-	if test "$use_static_libs" = built && test "$installed" = yes; then
+	if test built = "$use_static_libs" && test yes = "$installed"; then
 	  use_static_libs=no
 	fi
 	if test -n "$library_names" &&
-	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	   { test no = "$use_static_libs" || test -z "$old_library"; }; then
 	  case $host in
-	  *cygwin* | *mingw* | *cegcc*)
+	  *cygwin* | *mingw* | *cegcc* | *os2*)
 	      # No point in relinking DLLs because paths are not encoded
 	      func_append notinst_deplibs " $lib"
 	      need_relink=no
 	    ;;
 	  *)
-	    if test "$installed" = no; then
+	    if test no = "$installed"; then
 	      func_append notinst_deplibs " $lib"
 	      need_relink=yes
 	    fi
@@ -6708,24 +8154,24 @@ func_mode_link ()
 
 	  # Warn about portability, can't link against -module's on some
 	  # systems (darwin).  Don't bleat about dlopened modules though!
-	  dlopenmodule=""
+	  dlopenmodule=
 	  for dlpremoduletest in $dlprefiles; do
 	    if test "X$dlpremoduletest" = "X$lib"; then
-	      dlopenmodule="$dlpremoduletest"
+	      dlopenmodule=$dlpremoduletest
 	      break
 	    fi
 	  done
-	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	  if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
 	    echo
-	    if test "$linkmode" = prog; then
+	    if test prog = "$linkmode"; then
 	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
 	    else
 	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
 	    fi
 	    $ECHO "*** $linklib is not portable!"
 	  fi
-	  if test "$linkmode" = lib &&
-	     test "$hardcode_into_libs" = yes; then
+	  if test lib = "$linkmode" &&
+	     test yes = "$hardcode_into_libs"; then
 	    # Hardcode the library path.
 	    # Skip directories that are in the system default run-time
 	    # search path.
@@ -6753,43 +8199,43 @@ func_mode_link ()
 	    # figure out the soname
 	    set dummy $library_names
 	    shift
-	    realname="$1"
+	    realname=$1
 	    shift
 	    libname=`eval "\\$ECHO \"$libname_spec\""`
 	    # use dlname if we got it. it's perfectly good, no?
 	    if test -n "$dlname"; then
-	      soname="$dlname"
+	      soname=$dlname
 	    elif test -n "$soname_spec"; then
 	      # bleh windows
 	      case $host in
-	      *cygwin* | mingw* | *cegcc*)
+	      *cygwin* | mingw* | *cegcc* | *os2*)
 	        func_arith $current - $age
 		major=$func_arith_result
-		versuffix="-$major"
+		versuffix=-$major
 		;;
 	      esac
 	      eval soname=\"$soname_spec\"
 	    else
-	      soname="$realname"
+	      soname=$realname
 	    fi
 
 	    # Make a new name for the extract_expsyms_cmds to use
-	    soroot="$soname"
+	    soroot=$soname
 	    func_basename "$soroot"
-	    soname="$func_basename_result"
+	    soname=$func_basename_result
 	    func_stripname 'lib' '.dll' "$soname"
 	    newlib=libimp-$func_stripname_result.a
 
 	    # If the library has no export list, then create one now
 	    if test -f "$output_objdir/$soname-def"; then :
 	    else
-	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_verbose "extracting exported symbol list from '$soname'"
 	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
 	    fi
 
 	    # Create $newlib
 	    if test -f "$output_objdir/$newlib"; then :; else
-	      func_verbose "generating import library for \`$soname'"
+	      func_verbose "generating import library for '$soname'"
 	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
 	    fi
 	    # make sure the library variables are pointing to the new library
@@ -6797,58 +8243,58 @@ func_mode_link ()
 	    linklib=$newlib
 	  fi # test -n "$old_archive_from_expsyms_cmds"
 
-	  if test "$linkmode" = prog || test "$opt_mode" != relink; then
+	  if test prog = "$linkmode" || test relink != "$opt_mode"; then
 	    add_shlibpath=
 	    add_dir=
 	    add=
 	    lib_linked=yes
 	    case $hardcode_action in
 	    immediate | unsupported)
-	      if test "$hardcode_direct" = no; then
-		add="$dir/$linklib"
+	      if test no = "$hardcode_direct"; then
+		add=$dir/$linklib
 		case $host in
-		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
-		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+		  *-*-sysv4*uw2*) add_dir=-L$dir ;;
 		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
-		    *-*-unixware7*) add_dir="-L$dir" ;;
+		    *-*-unixware7*) add_dir=-L$dir ;;
 		  *-*-darwin* )
-		    # if the lib is a (non-dlopened) module then we can not
+		    # if the lib is a (non-dlopened) module then we cannot
 		    # link against it, someone is ignoring the earlier warnings
 		    if /usr/bin/file -L $add 2> /dev/null |
-			 $GREP ": [^:]* bundle" >/dev/null ; then
+			 $GREP ": [^:]* bundle" >/dev/null; then
 		      if test "X$dlopenmodule" != "X$lib"; then
 			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
-			if test -z "$old_library" ; then
+			if test -z "$old_library"; then
 			  echo
 			  echo "*** And there doesn't seem to be a static archive available"
 			  echo "*** The link will probably fail, sorry"
 			else
-			  add="$dir/$old_library"
+			  add=$dir/$old_library
 			fi
 		      elif test -n "$old_library"; then
-			add="$dir/$old_library"
+			add=$dir/$old_library
 		      fi
 		    fi
 		esac
-	      elif test "$hardcode_minus_L" = no; then
+	      elif test no = "$hardcode_minus_L"; then
 		case $host in
-		*-*-sunos*) add_shlibpath="$dir" ;;
+		*-*-sunos*) add_shlibpath=$dir ;;
 		esac
-		add_dir="-L$dir"
-		add="-l$name"
-	      elif test "$hardcode_shlibpath_var" = no; then
-		add_shlibpath="$dir"
-		add="-l$name"
+		add_dir=-L$dir
+		add=-l$name
+	      elif test no = "$hardcode_shlibpath_var"; then
+		add_shlibpath=$dir
+		add=-l$name
 	      else
 		lib_linked=no
 	      fi
 	      ;;
 	    relink)
-	      if test "$hardcode_direct" = yes &&
-	         test "$hardcode_direct_absolute" = no; then
-		add="$dir/$linklib"
-	      elif test "$hardcode_minus_L" = yes; then
-		add_dir="-L$absdir"
+	      if test yes = "$hardcode_direct" &&
+	         test no = "$hardcode_direct_absolute"; then
+		add=$dir/$linklib
+	      elif test yes = "$hardcode_minus_L"; then
+		add_dir=-L$absdir
 		# Try looking first in the location we're being installed to.
 		if test -n "$inst_prefix_dir"; then
 		  case $libdir in
@@ -6857,10 +8303,10 @@ func_mode_link ()
 		      ;;
 		  esac
 		fi
-		add="-l$name"
-	      elif test "$hardcode_shlibpath_var" = yes; then
-		add_shlibpath="$dir"
-		add="-l$name"
+		add=-l$name
+	      elif test yes = "$hardcode_shlibpath_var"; then
+		add_shlibpath=$dir
+		add=-l$name
 	      else
 		lib_linked=no
 	      fi
@@ -6868,7 +8314,7 @@ func_mode_link ()
 	    *) lib_linked=no ;;
 	    esac
 
-	    if test "$lib_linked" != yes; then
+	    if test yes != "$lib_linked"; then
 	      func_fatal_configuration "unsupported hardcode properties"
 	    fi
 
@@ -6878,15 +8324,15 @@ func_mode_link ()
 	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
 	      esac
 	    fi
-	    if test "$linkmode" = prog; then
+	    if test prog = "$linkmode"; then
 	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
 	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
 	    else
 	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
 	      test -n "$add" && deplibs="$add $deplibs"
-	      if test "$hardcode_direct" != yes &&
-		 test "$hardcode_minus_L" != yes &&
-		 test "$hardcode_shlibpath_var" = yes; then
+	      if test yes != "$hardcode_direct" &&
+		 test yes != "$hardcode_minus_L" &&
+		 test yes = "$hardcode_shlibpath_var"; then
 		case :$finalize_shlibpath: in
 		*":$libdir:"*) ;;
 		*) func_append finalize_shlibpath "$libdir:" ;;
@@ -6895,33 +8341,33 @@ func_mode_link ()
 	    fi
 	  fi
 
-	  if test "$linkmode" = prog || test "$opt_mode" = relink; then
+	  if test prog = "$linkmode" || test relink = "$opt_mode"; then
 	    add_shlibpath=
 	    add_dir=
 	    add=
 	    # Finalize command for both is simple: just hardcode it.
-	    if test "$hardcode_direct" = yes &&
-	       test "$hardcode_direct_absolute" = no; then
-	      add="$libdir/$linklib"
-	    elif test "$hardcode_minus_L" = yes; then
-	      add_dir="-L$libdir"
-	      add="-l$name"
-	    elif test "$hardcode_shlibpath_var" = yes; then
+	    if test yes = "$hardcode_direct" &&
+	       test no = "$hardcode_direct_absolute"; then
+	      add=$libdir/$linklib
+	    elif test yes = "$hardcode_minus_L"; then
+	      add_dir=-L$libdir
+	      add=-l$name
+	    elif test yes = "$hardcode_shlibpath_var"; then
 	      case :$finalize_shlibpath: in
 	      *":$libdir:"*) ;;
 	      *) func_append finalize_shlibpath "$libdir:" ;;
 	      esac
-	      add="-l$name"
-	    elif test "$hardcode_automatic" = yes; then
+	      add=-l$name
+	    elif test yes = "$hardcode_automatic"; then
 	      if test -n "$inst_prefix_dir" &&
-		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
-		add="$inst_prefix_dir$libdir/$linklib"
+		 test -f "$inst_prefix_dir$libdir/$linklib"; then
+		add=$inst_prefix_dir$libdir/$linklib
 	      else
-		add="$libdir/$linklib"
+		add=$libdir/$linklib
 	      fi
 	    else
 	      # We cannot seem to hardcode it, guess we'll fake it.
-	      add_dir="-L$libdir"
+	      add_dir=-L$libdir
 	      # Try looking first in the location we're being installed to.
 	      if test -n "$inst_prefix_dir"; then
 		case $libdir in
@@ -6930,10 +8376,10 @@ func_mode_link ()
 		    ;;
 		esac
 	      fi
-	      add="-l$name"
+	      add=-l$name
 	    fi
 
-	    if test "$linkmode" = prog; then
+	    if test prog = "$linkmode"; then
 	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
 	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
 	    else
@@ -6941,43 +8387,43 @@ func_mode_link ()
 	      test -n "$add" && deplibs="$add $deplibs"
 	    fi
 	  fi
-	elif test "$linkmode" = prog; then
+	elif test prog = "$linkmode"; then
 	  # Here we assume that one of hardcode_direct or hardcode_minus_L
 	  # is not unsupported.  This is valid on all known static and
 	  # shared platforms.
-	  if test "$hardcode_direct" != unsupported; then
-	    test -n "$old_library" && linklib="$old_library"
+	  if test unsupported != "$hardcode_direct"; then
+	    test -n "$old_library" && linklib=$old_library
 	    compile_deplibs="$dir/$linklib $compile_deplibs"
 	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
 	  else
 	    compile_deplibs="-l$name -L$dir $compile_deplibs"
 	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
 	  fi
-	elif test "$build_libtool_libs" = yes; then
+	elif test yes = "$build_libtool_libs"; then
 	  # Not a shared library
-	  if test "$deplibs_check_method" != pass_all; then
+	  if test pass_all != "$deplibs_check_method"; then
 	    # We're trying link a shared library against a static one
 	    # but the system doesn't support it.
 
 	    # Just print a warning and add the library to dependency_libs so
 	    # that the program can be linked against the static library.
 	    echo
-	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    $ECHO "*** Warning: This system cannot link to static lib archive $lib."
 	    echo "*** I have the capability to make that library automatically link in when"
 	    echo "*** you link to this library.  But I can only do this if you have a"
 	    echo "*** shared version of the library, which you do not appear to have."
-	    if test "$module" = yes; then
+	    if test yes = "$module"; then
 	      echo "*** But as you try to build a module library, libtool will still create "
 	      echo "*** a static module, that should work as long as the dlopening application"
 	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
 	      if test -z "$global_symbol_pipe"; then
 		echo
 		echo "*** However, this would only work if libtool was able to extract symbol"
-		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
 		echo "*** not find such a program.  So, this module is probably useless."
-		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+		echo "*** 'nm' from GNU binutils and a full rebuild may help."
 	      fi
-	      if test "$build_old_libs" = no; then
+	      if test no = "$build_old_libs"; then
 		build_libtool_libs=module
 		build_old_libs=yes
 	      else
@@ -6990,11 +8436,11 @@ func_mode_link ()
 	  fi
 	fi # link shared/static library?
 
-	if test "$linkmode" = lib; then
+	if test lib = "$linkmode"; then
 	  if test -n "$dependency_libs" &&
-	     { test "$hardcode_into_libs" != yes ||
-	       test "$build_old_libs" = yes ||
-	       test "$link_static" = yes; }; then
+	     { test yes != "$hardcode_into_libs" ||
+	       test yes = "$build_old_libs" ||
+	       test yes = "$link_static"; }; then
 	    # Extract -R from dependency_libs
 	    temp_deplibs=
 	    for libdir in $dependency_libs; do
@@ -7008,12 +8454,12 @@ func_mode_link ()
 	      *) func_append temp_deplibs " $libdir";;
 	      esac
 	    done
-	    dependency_libs="$temp_deplibs"
+	    dependency_libs=$temp_deplibs
 	  fi
 
 	  func_append newlib_search_path " $absdir"
 	  # Link against this library
-	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
 	  # ... and its dependency_libs
 	  tmp_libs=
 	  for deplib in $dependency_libs; do
@@ -7023,7 +8469,7 @@ func_mode_link ()
                    func_resolve_sysroot "$func_stripname_result";;
               *) func_resolve_sysroot "$deplib" ;;
             esac
-	    if $opt_preserve_dup_deps ; then
+	    if $opt_preserve_dup_deps; then
 	      case "$tmp_libs " in
 	      *" $func_resolve_sysroot_result "*)
                 func_append specialdeplibs " $func_resolve_sysroot_result" ;;
@@ -7032,12 +8478,12 @@ func_mode_link ()
 	    func_append tmp_libs " $func_resolve_sysroot_result"
 	  done
 
-	  if test "$link_all_deplibs" != no; then
+	  if test no != "$link_all_deplibs"; then
 	    # Add the search paths of all dependency libraries
 	    for deplib in $dependency_libs; do
 	      path=
 	      case $deplib in
-	      -L*) path="$deplib" ;;
+	      -L*) path=$deplib ;;
 	      *.la)
 	        func_resolve_sysroot "$deplib"
 	        deplib=$func_resolve_sysroot_result
@@ -7045,12 +8491,12 @@ func_mode_link ()
 		dir=$func_dirname_result
 		# We need an absolute path.
 		case $dir in
-		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		[\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
 		*)
 		  absdir=`cd "$dir" && pwd`
 		  if test -z "$absdir"; then
-		    func_warning "cannot determine absolute directory name of \`$dir'"
-		    absdir="$dir"
+		    func_warning "cannot determine absolute directory name of '$dir'"
+		    absdir=$dir
 		  fi
 		  ;;
 		esac
@@ -7058,35 +8504,35 @@ func_mode_link ()
 		case $host in
 		*-*-darwin*)
 		  depdepl=
-		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
-		  if test -n "$deplibrary_names" ; then
-		    for tmp in $deplibrary_names ; do
+		  eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names"; then
+		    for tmp in $deplibrary_names; do
 		      depdepl=$tmp
 		    done
-		    if test -f "$absdir/$objdir/$depdepl" ; then
-		      depdepl="$absdir/$objdir/$depdepl"
-		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+		    if test -f "$absdir/$objdir/$depdepl"; then
+		      depdepl=$absdir/$objdir/$depdepl
+		      darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
                       if test -z "$darwin_install_name"; then
-                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                          darwin_install_name=`$OTOOL64 -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
                       fi
-		      func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
-		      func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+		      func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+		      func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
 		      path=
 		    fi
 		  fi
 		  ;;
 		*)
-		  path="-L$absdir/$objdir"
+		  path=-L$absdir/$objdir
 		  ;;
 		esac
 		else
-		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
 		  test -z "$libdir" && \
-		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		    func_fatal_error "'$deplib' is not a valid libtool archive"
 		  test "$absdir" != "$libdir" && \
-		    func_warning "\`$deplib' seems to be moved"
+		    func_warning "'$deplib' seems to be moved"
 
-		  path="-L$absdir"
+		  path=-L$absdir
 		fi
 		;;
 	      esac
@@ -7098,23 +8544,23 @@ func_mode_link ()
 	  fi # link_all_deplibs != no
 	fi # linkmode = lib
       done # for deplib in $libs
-      if test "$pass" = link; then
-	if test "$linkmode" = "prog"; then
+      if test link = "$pass"; then
+	if test prog = "$linkmode"; then
 	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
 	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
 	else
 	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
 	fi
       fi
-      dependency_libs="$newdependency_libs"
-      if test "$pass" = dlpreopen; then
+      dependency_libs=$newdependency_libs
+      if test dlpreopen = "$pass"; then
 	# Link the dlpreopened libraries before other libraries
 	for deplib in $save_deplibs; do
 	  deplibs="$deplib $deplibs"
 	done
       fi
-      if test "$pass" != dlopen; then
-	if test "$pass" != conv; then
+      if test dlopen != "$pass"; then
+	test conv = "$pass" || {
 	  # Make sure lib_search_path contains only unique directories.
 	  lib_search_path=
 	  for dir in $newlib_search_path; do
@@ -7124,12 +8570,12 @@ func_mode_link ()
 	    esac
 	  done
 	  newlib_search_path=
-	fi
+	}
 
-	if test "$linkmode,$pass" != "prog,link"; then
-	  vars="deplibs"
-	else
+	if test prog,link = "$linkmode,$pass"; then
 	  vars="compile_deplibs finalize_deplibs"
+	else
+	  vars=deplibs
 	fi
 	for var in $vars dependency_libs; do
 	  # Add libraries to $var in reverse order
@@ -7187,62 +8633,93 @@ func_mode_link ()
 	  eval $var=\"$tmp_libs\"
 	done # for var
       fi
+
+      # Add Sun CC postdeps if required:
+      test CXX = "$tagname" && {
+        case $host_os in
+        linux*)
+          case `$CC -V 2>&1 | sed 5q` in
+          *Sun\ C*) # Sun C++ 5.9
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+
+        solaris*)
+          func_cc_basename "$CC"
+          case $func_cc_basename_result in
+          CC* | sunCC*)
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+        esac
+      }
+
       # Last step: remove runtime libs from dependency_libs
       # (they stay in deplibs)
       tmp_libs=
-      for i in $dependency_libs ; do
+      for i in $dependency_libs; do
 	case " $predeps $postdeps $compiler_lib_search_path " in
 	*" $i "*)
-	  i=""
+	  i=
 	  ;;
 	esac
-	if test -n "$i" ; then
+	if test -n "$i"; then
 	  func_append tmp_libs " $i"
 	fi
       done
       dependency_libs=$tmp_libs
     done # for pass
-    if test "$linkmode" = prog; then
-      dlfiles="$newdlfiles"
+    if test prog = "$linkmode"; then
+      dlfiles=$newdlfiles
     fi
-    if test "$linkmode" = prog || test "$linkmode" = lib; then
-      dlprefiles="$newdlprefiles"
+    if test prog = "$linkmode" || test lib = "$linkmode"; then
+      dlprefiles=$newdlprefiles
     fi
 
     case $linkmode in
     oldlib)
-      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
-	func_warning "\`-dlopen' is ignored for archives"
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+	func_warning "'-dlopen' is ignored for archives"
       fi
 
       case " $deplibs" in
       *\ -l* | *\ -L*)
-	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+	func_warning "'-l' and '-L' are ignored for archives" ;;
       esac
 
       test -n "$rpath" && \
-	func_warning "\`-rpath' is ignored for archives"
+	func_warning "'-rpath' is ignored for archives"
 
       test -n "$xrpath" && \
-	func_warning "\`-R' is ignored for archives"
+	func_warning "'-R' is ignored for archives"
 
       test -n "$vinfo" && \
-	func_warning "\`-version-info/-version-number' is ignored for archives"
+	func_warning "'-version-info/-version-number' is ignored for archives"
 
       test -n "$release" && \
-	func_warning "\`-release' is ignored for archives"
+	func_warning "'-release' is ignored for archives"
 
       test -n "$export_symbols$export_symbols_regex" && \
-	func_warning "\`-export-symbols' is ignored for archives"
+	func_warning "'-export-symbols' is ignored for archives"
 
       # Now set the variables for building old libraries.
       build_libtool_libs=no
-      oldlibs="$output"
+      oldlibs=$output
       func_append objs "$old_deplibs"
       ;;
 
     lib)
-      # Make sure we only generate libraries of the form `libNAME.la'.
+      # Make sure we only generate libraries of the form 'libNAME.la'.
       case $outputname in
       lib*)
 	func_stripname 'lib' '.la' "$outputname"
@@ -7251,10 +8728,10 @@ func_mode_link ()
 	eval libname=\"$libname_spec\"
 	;;
       *)
-	test "$module" = no && \
-	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+	test no = "$module" \
+	  && func_fatal_help "libtool library '$output' must begin with 'lib'"
 
-	if test "$need_lib_prefix" != no; then
+	if test no != "$need_lib_prefix"; then
 	  # Add the "lib" prefix for modules if required
 	  func_stripname '' '.la' "$outputname"
 	  name=$func_stripname_result
@@ -7268,8 +8745,8 @@ func_mode_link ()
       esac
 
       if test -n "$objs"; then
-	if test "$deplibs_check_method" != pass_all; then
-	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	if test pass_all != "$deplibs_check_method"; then
+	  func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
 	else
 	  echo
 	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
@@ -7278,21 +8755,21 @@ func_mode_link ()
 	fi
       fi
 
-      test "$dlself" != no && \
-	func_warning "\`-dlopen self' is ignored for libtool libraries"
+      test no = "$dlself" \
+	|| func_warning "'-dlopen self' is ignored for libtool libraries"
 
       set dummy $rpath
       shift
-      test "$#" -gt 1 && \
-	func_warning "ignoring multiple \`-rpath's for a libtool library"
+      test 1 -lt "$#" \
+	&& func_warning "ignoring multiple '-rpath's for a libtool library"
 
-      install_libdir="$1"
+      install_libdir=$1
 
       oldlibs=
       if test -z "$rpath"; then
-	if test "$build_libtool_libs" = yes; then
+	if test yes = "$build_libtool_libs"; then
 	  # Building a libtool convenience library.
-	  # Some compilers have problems with a `.al' extension so
+	  # Some compilers have problems with a '.al' extension so
 	  # convenience libraries should have the same extension an
 	  # archive normally would.
 	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
@@ -7301,20 +8778,20 @@ func_mode_link ()
 	fi
 
 	test -n "$vinfo" && \
-	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+	  func_warning "'-version-info/-version-number' is ignored for convenience libraries"
 
 	test -n "$release" && \
-	  func_warning "\`-release' is ignored for convenience libraries"
+	  func_warning "'-release' is ignored for convenience libraries"
       else
 
 	# Parse the version information argument.
-	save_ifs="$IFS"; IFS=':'
+	save_ifs=$IFS; IFS=:
 	set dummy $vinfo 0 0 0
 	shift
-	IFS="$save_ifs"
+	IFS=$save_ifs
 
 	test -n "$7" && \
-	  func_fatal_help "too many parameters to \`-version-info'"
+	  func_fatal_help "too many parameters to '-version-info'"
 
 	# convert absolute version numbers to libtool ages
 	# this retains compatibility with .la files and attempts
@@ -7322,45 +8799,45 @@ func_mode_link ()
 
 	case $vinfo_number in
 	yes)
-	  number_major="$1"
-	  number_minor="$2"
-	  number_revision="$3"
+	  number_major=$1
+	  number_minor=$2
+	  number_revision=$3
 	  #
 	  # There are really only two kinds -- those that
 	  # use the current revision as the major version
 	  # and those that subtract age and use age as
 	  # a minor version.  But, then there is irix
-	  # which has an extra 1 added just for fun
+	  # that has an extra 1 added just for fun
 	  #
 	  case $version_type in
 	  # correct linux to gnu/linux during the next big refactor
-	  darwin|linux|osf|windows|none)
+	  darwin|freebsd-elf|linux|osf|windows|none)
 	    func_arith $number_major + $number_minor
 	    current=$func_arith_result
-	    age="$number_minor"
-	    revision="$number_revision"
+	    age=$number_minor
+	    revision=$number_revision
 	    ;;
-	  freebsd-aout|freebsd-elf|qnx|sunos)
-	    current="$number_major"
-	    revision="$number_minor"
-	    age="0"
+	  freebsd-aout|qnx|sunos)
+	    current=$number_major
+	    revision=$number_minor
+	    age=0
 	    ;;
 	  irix|nonstopux)
 	    func_arith $number_major + $number_minor
 	    current=$func_arith_result
-	    age="$number_minor"
-	    revision="$number_minor"
+	    age=$number_minor
+	    revision=$number_minor
 	    lt_irix_increment=no
 	    ;;
 	  *)
-	    func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+	    func_fatal_configuration "$modename: unknown library version type '$version_type'"
 	    ;;
 	  esac
 	  ;;
 	no)
-	  current="$1"
-	  revision="$2"
-	  age="$3"
+	  current=$1
+	  revision=$2
+	  age=$3
 	  ;;
 	esac
 
@@ -7368,30 +8845,30 @@ func_mode_link ()
 	case $current in
 	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
 	*)
-	  func_error "CURRENT \`$current' must be a nonnegative integer"
-	  func_fatal_error "\`$vinfo' is not valid version information"
+	  func_error "CURRENT '$current' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
 	  ;;
 	esac
 
 	case $revision in
 	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
 	*)
-	  func_error "REVISION \`$revision' must be a nonnegative integer"
-	  func_fatal_error "\`$vinfo' is not valid version information"
+	  func_error "REVISION '$revision' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
 	  ;;
 	esac
 
 	case $age in
 	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
 	*)
-	  func_error "AGE \`$age' must be a nonnegative integer"
-	  func_fatal_error "\`$vinfo' is not valid version information"
+	  func_error "AGE '$age' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
 	  ;;
 	esac
 
 	if test "$age" -gt "$current"; then
-	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
-	  func_fatal_error "\`$vinfo' is not valid version information"
+	  func_error "AGE '$age' is greater than the current interface number '$current'"
+	  func_fatal_error "'$vinfo' is not valid version information"
 	fi
 
 	# Calculate the version variables.
@@ -7406,26 +8883,36 @@ func_mode_link ()
 	  # verstring for coding it into the library header
 	  func_arith $current - $age
 	  major=.$func_arith_result
-	  versuffix="$major.$age.$revision"
+	  versuffix=$major.$age.$revision
 	  # Darwin ld doesn't like 0 for these options...
 	  func_arith $current + 1
 	  minor_current=$func_arith_result
-	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
 	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+          # On Darwin other compilers
+          case $CC in
+              nagfor*)
+                  verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+                  ;;
+              *)
+                  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+                  ;;
+          esac
 	  ;;
 
 	freebsd-aout)
-	  major=".$current"
-	  versuffix=".$current.$revision";
+	  major=.$current
+	  versuffix=.$current.$revision
 	  ;;
 
 	freebsd-elf)
-	  major=".$current"
-	  versuffix=".$current"
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
 	  ;;
 
 	irix | nonstopux)
-	  if test "X$lt_irix_increment" = "Xno"; then
+	  if test no = "$lt_irix_increment"; then
 	    func_arith $current - $age
 	  else
 	    func_arith $current - $age + 1
@@ -7436,69 +8923,74 @@ func_mode_link ()
 	    nonstopux) verstring_prefix=nonstopux ;;
 	    *)         verstring_prefix=sgi ;;
 	  esac
-	  verstring="$verstring_prefix$major.$revision"
+	  verstring=$verstring_prefix$major.$revision
 
 	  # Add in all the interfaces that we are compatible with.
 	  loop=$revision
-	  while test "$loop" -ne 0; do
+	  while test 0 -ne "$loop"; do
 	    func_arith $revision - $loop
 	    iface=$func_arith_result
 	    func_arith $loop - 1
 	    loop=$func_arith_result
-	    verstring="$verstring_prefix$major.$iface:$verstring"
+	    verstring=$verstring_prefix$major.$iface:$verstring
 	  done
 
-	  # Before this point, $major must not contain `.'.
+	  # Before this point, $major must not contain '.'.
 	  major=.$major
-	  versuffix="$major.$revision"
+	  versuffix=$major.$revision
 	  ;;
 
 	linux) # correct to gnu/linux during the next big refactor
 	  func_arith $current - $age
 	  major=.$func_arith_result
-	  versuffix="$major.$age.$revision"
+	  versuffix=$major.$age.$revision
 	  ;;
 
 	osf)
 	  func_arith $current - $age
 	  major=.$func_arith_result
-	  versuffix=".$current.$age.$revision"
-	  verstring="$current.$age.$revision"
+	  versuffix=.$current.$age.$revision
+	  verstring=$current.$age.$revision
 
 	  # Add in all the interfaces that we are compatible with.
 	  loop=$age
-	  while test "$loop" -ne 0; do
+	  while test 0 -ne "$loop"; do
 	    func_arith $current - $loop
 	    iface=$func_arith_result
 	    func_arith $loop - 1
 	    loop=$func_arith_result
-	    verstring="$verstring:${iface}.0"
+	    verstring=$verstring:$iface.0
 	  done
 
 	  # Make executables depend on our current version.
-	  func_append verstring ":${current}.0"
+	  func_append verstring ":$current.0"
 	  ;;
 
 	qnx)
-	  major=".$current"
-	  versuffix=".$current"
+	  major=.$current
+	  versuffix=.$current
+	  ;;
+
+	sco)
+	  major=.$current
+	  versuffix=.$current
 	  ;;
 
 	sunos)
-	  major=".$current"
-	  versuffix=".$current.$revision"
+	  major=.$current
+	  versuffix=.$current.$revision
 	  ;;
 
 	windows)
 	  # Use '-' rather than '.', since we only want one
-	  # extension on DOS 8.3 filesystems.
+	  # extension on DOS 8.3 file systems.
 	  func_arith $current - $age
 	  major=$func_arith_result
-	  versuffix="-$major"
+	  versuffix=-$major
 	  ;;
 
 	*)
-	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  func_fatal_configuration "unknown library version type '$version_type'"
 	  ;;
 	esac
 
@@ -7512,42 +9004,45 @@ func_mode_link ()
 	    verstring=
 	    ;;
 	  *)
-	    verstring="0.0"
+	    verstring=0.0
 	    ;;
 	  esac
-	  if test "$need_version" = no; then
+	  if test no = "$need_version"; then
 	    versuffix=
 	  else
-	    versuffix=".0.0"
+	    versuffix=.0.0
 	  fi
 	fi
 
 	# Remove version info from name if versioning should be avoided
-	if test "$avoid_version" = yes && test "$need_version" = no; then
+	if test yes,no = "$avoid_version,$need_version"; then
 	  major=
 	  versuffix=
-	  verstring=""
+	  verstring=
 	fi
 
 	# Check to see if the archive will have undefined symbols.
-	if test "$allow_undefined" = yes; then
-	  if test "$allow_undefined_flag" = unsupported; then
-	    func_warning "undefined symbols not allowed in $host shared libraries"
-	    build_libtool_libs=no
-	    build_old_libs=yes
+	if test yes = "$allow_undefined"; then
+	  if test unsupported = "$allow_undefined_flag"; then
+	    if test yes = "$build_old_libs"; then
+	      func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+	      build_libtool_libs=no
+	    else
+	      func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+	    fi
 	  fi
 	else
 	  # Don't allow undefined symbols.
-	  allow_undefined_flag="$no_undefined_flag"
+	  allow_undefined_flag=$no_undefined_flag
 	fi
 
       fi
 
-      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_generate_dlsyms "$libname" "$libname" :
       func_append libobjs " $symfileobj"
-      test "X$libobjs" = "X " && libobjs=
+      test " " = "$libobjs" && libobjs=
 
-      if test "$opt_mode" != relink; then
+      if test relink != "$opt_mode"; then
 	# Remove our outputs, but don't remove object files since they
 	# may have been created when compiling PIC objects.
 	removelist=
@@ -7556,8 +9051,8 @@ func_mode_link ()
 	  case $p in
 	    *.$objext | *.gcno)
 	       ;;
-	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
-	       if test "X$precious_files_regex" != "X"; then
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+	       if test -n "$precious_files_regex"; then
 		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
 		 then
 		   continue
@@ -7573,11 +9068,11 @@ func_mode_link ()
       fi
 
       # Now set the variables for building old libraries.
-      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+      if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
 	func_append oldlibs " $output_objdir/$libname.$libext"
 
 	# Transform .lo files to .o files.
-	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
       fi
 
       # Eliminate all temporary directories.
@@ -7598,13 +9093,13 @@ func_mode_link ()
 	  *) func_append finalize_rpath " $libdir" ;;
 	  esac
 	done
-	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
 	  dependency_libs="$temp_xrpath $dependency_libs"
 	fi
       fi
 
       # Make sure dlfiles contains only unique files that won't be dlpreopened
-      old_dlfiles="$dlfiles"
+      old_dlfiles=$dlfiles
       dlfiles=
       for lib in $old_dlfiles; do
 	case " $dlprefiles $dlfiles " in
@@ -7614,7 +9109,7 @@ func_mode_link ()
       done
 
       # Make sure dlprefiles contains only unique files
-      old_dlprefiles="$dlprefiles"
+      old_dlprefiles=$dlprefiles
       dlprefiles=
       for lib in $old_dlprefiles; do
 	case "$dlprefiles " in
@@ -7623,7 +9118,7 @@ func_mode_link ()
 	esac
       done
 
-      if test "$build_libtool_libs" = yes; then
+      if test yes = "$build_libtool_libs"; then
 	if test -n "$rpath"; then
 	  case $host in
 	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
@@ -7647,7 +9142,7 @@ func_mode_link ()
 	    ;;
 	  *)
 	    # Add libc to deplibs on all other systems if necessary.
-	    if test "$build_libtool_need_lc" = "yes"; then
+	    if test yes = "$build_libtool_need_lc"; then
 	      func_append deplibs " -lc"
 	    fi
 	    ;;
@@ -7663,9 +9158,9 @@ func_mode_link ()
 	# I'm not sure if I'm treating the release correctly.  I think
 	# release should show up in the -l (ie -lgmp5) so we don't want to
 	# add it in twice.  Is that correct?
-	release=""
-	versuffix=""
-	major=""
+	release=
+	versuffix=
+	major=
 	newdeplibs=
 	droppeddeps=no
 	case $deplibs_check_method in
@@ -7694,20 +9189,20 @@ EOF
 	      -l*)
 		func_stripname -l '' "$i"
 		name=$func_stripname_result
-		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		if test yes = "$allow_libtool_libs_with_static_runtimes"; then
 		  case " $predeps $postdeps " in
 		  *" $i "*)
 		    func_append newdeplibs " $i"
-		    i=""
+		    i=
 		    ;;
 		  esac
 		fi
-		if test -n "$i" ; then
+		if test -n "$i"; then
 		  libname=`eval "\\$ECHO \"$libname_spec\""`
 		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
 		  set dummy $deplib_matches; shift
 		  deplib_match=$1
-		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
 		    func_append newdeplibs " $i"
 		  else
 		    droppeddeps=yes
@@ -7737,20 +9232,20 @@ EOF
 		$opt_dry_run || $RM conftest
 		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
 		  ldd_output=`ldd conftest`
-		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  if test yes = "$allow_libtool_libs_with_static_runtimes"; then
 		    case " $predeps $postdeps " in
 		    *" $i "*)
 		      func_append newdeplibs " $i"
-		      i=""
+		      i=
 		      ;;
 		    esac
 		  fi
-		  if test -n "$i" ; then
+		  if test -n "$i"; then
 		    libname=`eval "\\$ECHO \"$libname_spec\""`
 		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
 		    set dummy $deplib_matches; shift
 		    deplib_match=$1
-		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
 		      func_append newdeplibs " $i"
 		    else
 		      droppeddeps=yes
@@ -7787,24 +9282,24 @@ EOF
 	    -l*)
 	      func_stripname -l '' "$a_deplib"
 	      name=$func_stripname_result
-	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      if test yes = "$allow_libtool_libs_with_static_runtimes"; then
 		case " $predeps $postdeps " in
 		*" $a_deplib "*)
 		  func_append newdeplibs " $a_deplib"
-		  a_deplib=""
+		  a_deplib=
 		  ;;
 		esac
 	      fi
-	      if test -n "$a_deplib" ; then
+	      if test -n "$a_deplib"; then
 		libname=`eval "\\$ECHO \"$libname_spec\""`
 		if test -n "$file_magic_glob"; then
 		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
 		else
 		  libnameglob=$libname
 		fi
-		test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+		test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
 		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
-		  if test "$want_nocaseglob" = yes; then
+		  if test yes = "$want_nocaseglob"; then
 		    shopt -s nocaseglob
 		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
 		    $nocaseglob
@@ -7822,25 +9317,25 @@ EOF
 		      # We might still enter an endless loop, since a link
 		      # loop can be closed while we follow links,
 		      # but so what?
-		      potlib="$potent_lib"
+		      potlib=$potent_lib
 		      while test -h "$potlib" 2>/dev/null; do
-			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
 			case $potliblink in
-			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
-			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			[\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+			*) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
 			esac
 		      done
 		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
 			 $SED -e 10q |
 			 $EGREP "$file_magic_regex" > /dev/null; then
 			func_append newdeplibs " $a_deplib"
-			a_deplib=""
+			a_deplib=
 			break 2
 		      fi
 		  done
 		done
 	      fi
-	      if test -n "$a_deplib" ; then
+	      if test -n "$a_deplib"; then
 		droppeddeps=yes
 		echo
 		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
@@ -7848,7 +9343,7 @@ EOF
 		echo "*** you link to this library.  But I can only do this if you have a"
 		echo "*** shared version of the library, which you do not appear to have"
 		echo "*** because I did check the linker path looking for a file starting"
-		if test -z "$potlib" ; then
+		if test -z "$potlib"; then
 		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
 		else
 		  $ECHO "*** with $libname and none of the candidates passed a file format test"
@@ -7871,30 +9366,30 @@ EOF
 	    -l*)
 	      func_stripname -l '' "$a_deplib"
 	      name=$func_stripname_result
-	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      if test yes = "$allow_libtool_libs_with_static_runtimes"; then
 		case " $predeps $postdeps " in
 		*" $a_deplib "*)
 		  func_append newdeplibs " $a_deplib"
-		  a_deplib=""
+		  a_deplib=
 		  ;;
 		esac
 	      fi
-	      if test -n "$a_deplib" ; then
+	      if test -n "$a_deplib"; then
 		libname=`eval "\\$ECHO \"$libname_spec\""`
 		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
 		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
 		  for potent_lib in $potential_libs; do
-		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    potlib=$potent_lib # see symlink-check above in file_magic test
 		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
 		       $EGREP "$match_pattern_regex" > /dev/null; then
 		      func_append newdeplibs " $a_deplib"
-		      a_deplib=""
+		      a_deplib=
 		      break 2
 		    fi
 		  done
 		done
 	      fi
-	      if test -n "$a_deplib" ; then
+	      if test -n "$a_deplib"; then
 		droppeddeps=yes
 		echo
 		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
@@ -7902,7 +9397,7 @@ EOF
 		echo "*** you link to this library.  But I can only do this if you have a"
 		echo "*** shared version of the library, which you do not appear to have"
 		echo "*** because I did check the linker path looking for a file starting"
-		if test -z "$potlib" ; then
+		if test -z "$potlib"; then
 		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
 		else
 		  $ECHO "*** with $libname and none of the candidates passed a file format test"
@@ -7918,18 +9413,18 @@ EOF
 	  done # Gone through all deplibs.
 	  ;;
 	none | unknown | *)
-	  newdeplibs=""
+	  newdeplibs=
 	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
-	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
-	    for i in $predeps $postdeps ; do
+	  if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+	    for i in $predeps $postdeps; do
 	      # can't use Xsed below, because $i might contain '/'
-	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
 	    done
 	  fi
 	  case $tmp_deplibs in
 	  *[!\	\ ]*)
 	    echo
-	    if test "X$deplibs_check_method" = "Xnone"; then
+	    if test none = "$deplibs_check_method"; then
 	      echo "*** Warning: inter-library dependencies are not supported in this platform."
 	    else
 	      echo "*** Warning: inter-library dependencies are not known to be supported."
@@ -7953,8 +9448,8 @@ EOF
 	  ;;
 	esac
 
-	if test "$droppeddeps" = yes; then
-	  if test "$module" = yes; then
+	if test yes = "$droppeddeps"; then
+	  if test yes = "$module"; then
 	    echo
 	    echo "*** Warning: libtool could not satisfy all declared inter-library"
 	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
@@ -7963,12 +9458,12 @@ EOF
 	    if test -z "$global_symbol_pipe"; then
 	      echo
 	      echo "*** However, this would only work if libtool was able to extract symbol"
-	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
 	      echo "*** not find such a program.  So, this module is probably useless."
-	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      echo "*** 'nm' from GNU binutils and a full rebuild may help."
 	    fi
-	    if test "$build_old_libs" = no; then
-	      oldlibs="$output_objdir/$libname.$libext"
+	    if test no = "$build_old_libs"; then
+	      oldlibs=$output_objdir/$libname.$libext
 	      build_libtool_libs=module
 	      build_old_libs=yes
 	    else
@@ -7979,14 +9474,14 @@ EOF
 	    echo "*** automatically added whenever a program is linked with this library"
 	    echo "*** or is declared to -dlopen it."
 
-	    if test "$allow_undefined" = no; then
+	    if test no = "$allow_undefined"; then
 	      echo
 	      echo "*** Since this library must not contain undefined symbols,"
 	      echo "*** because either the platform does not support them or"
 	      echo "*** it was explicitly requested with -no-undefined,"
 	      echo "*** libtool will only create a static version of it."
-	      if test "$build_old_libs" = no; then
-		oldlibs="$output_objdir/$libname.$libext"
+	      if test no = "$build_old_libs"; then
+		oldlibs=$output_objdir/$libname.$libext
 		build_libtool_libs=module
 		build_old_libs=yes
 	      else
@@ -8032,7 +9527,7 @@ EOF
 	*) func_append new_libs " $deplib" ;;
 	esac
       done
-      deplibs="$new_libs"
+      deplibs=$new_libs
 
       # All the library-specific variables (install_libdir is set above).
       library_names=
@@ -8040,25 +9535,25 @@ EOF
       dlname=
 
       # Test again, we may have decided not to build it any more
-      if test "$build_libtool_libs" = yes; then
-	# Remove ${wl} instances when linking with ld.
+      if test yes = "$build_libtool_libs"; then
+	# Remove $wl instances when linking with ld.
 	# FIXME: should test the right _cmds variable.
 	case $archive_cmds in
 	  *\$LD\ *) wl= ;;
         esac
-	if test "$hardcode_into_libs" = yes; then
+	if test yes = "$hardcode_into_libs"; then
 	  # Hardcode the library paths
 	  hardcode_libdirs=
 	  dep_rpath=
-	  rpath="$finalize_rpath"
-	  test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+	  rpath=$finalize_rpath
+	  test relink = "$opt_mode" || rpath=$compile_rpath$rpath
 	  for libdir in $rpath; do
 	    if test -n "$hardcode_libdir_flag_spec"; then
 	      if test -n "$hardcode_libdir_separator"; then
 		func_replace_sysroot "$libdir"
 		libdir=$func_replace_sysroot_result
 		if test -z "$hardcode_libdirs"; then
-		  hardcode_libdirs="$libdir"
+		  hardcode_libdirs=$libdir
 		else
 		  # Just accumulate the unique libdirs.
 		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
@@ -8083,7 +9578,7 @@ EOF
 	  # Substitute the hardcoded libdirs into the rpath.
 	  if test -n "$hardcode_libdir_separator" &&
 	     test -n "$hardcode_libdirs"; then
-	    libdir="$hardcode_libdirs"
+	    libdir=$hardcode_libdirs
 	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
 	  fi
 	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
@@ -8097,8 +9592,8 @@ EOF
 	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
 	fi
 
-	shlibpath="$finalize_shlibpath"
-	test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	shlibpath=$finalize_shlibpath
+	test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
 	if test -n "$shlibpath"; then
 	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
 	fi
@@ -8108,19 +9603,19 @@ EOF
 	eval library_names=\"$library_names_spec\"
 	set dummy $library_names
 	shift
-	realname="$1"
+	realname=$1
 	shift
 
 	if test -n "$soname_spec"; then
 	  eval soname=\"$soname_spec\"
 	else
-	  soname="$realname"
+	  soname=$realname
 	fi
 	if test -z "$dlname"; then
 	  dlname=$soname
 	fi
 
-	lib="$output_objdir/$realname"
+	lib=$output_objdir/$realname
 	linknames=
 	for link
 	do
@@ -8134,7 +9629,7 @@ EOF
 	delfiles=
 	if test -n "$export_symbols" && test -n "$include_expsyms"; then
 	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
-	  export_symbols="$output_objdir/$libname.uexp"
+	  export_symbols=$output_objdir/$libname.uexp
 	  func_append delfiles " $export_symbols"
 	fi
 
@@ -8143,31 +9638,31 @@ EOF
 	cygwin* | mingw* | cegcc*)
 	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
 	    # exporting using user supplied symfile
-	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	    func_dll_def_p "$export_symbols" || {
 	      # and it's NOT already a .def file. Must figure out
 	      # which of the given symbols are data symbols and tag
 	      # them as such. So, trigger use of export_symbols_cmds.
 	      # export_symbols gets reassigned inside the "prepare
 	      # the list of exported symbols" if statement, so the
 	      # include_expsyms logic still works.
-	      orig_export_symbols="$export_symbols"
+	      orig_export_symbols=$export_symbols
 	      export_symbols=
 	      always_export_symbols=yes
-	    fi
+	    }
 	  fi
 	  ;;
 	esac
 
 	# Prepare the list of exported symbols
 	if test -z "$export_symbols"; then
-	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
-	    func_verbose "generating symbol list for \`$libname.la'"
-	    export_symbols="$output_objdir/$libname.exp"
+	  if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for '$libname.la'"
+	    export_symbols=$output_objdir/$libname.exp
 	    $opt_dry_run || $RM $export_symbols
 	    cmds=$export_symbols_cmds
-	    save_ifs="$IFS"; IFS='~'
+	    save_ifs=$IFS; IFS='~'
 	    for cmd1 in $cmds; do
-	      IFS="$save_ifs"
+	      IFS=$save_ifs
 	      # Take the normal branch if the nm_file_list_spec branch
 	      # doesn't work or if tool conversion is not needed.
 	      case $nm_file_list_spec~$to_tool_file_cmd in
@@ -8181,7 +9676,7 @@ EOF
 		  try_normal_branch=no
 		  ;;
 	      esac
-	      if test "$try_normal_branch" = yes \
+	      if test yes = "$try_normal_branch" \
 		 && { test "$len" -lt "$max_cmd_len" \
 		      || test "$max_cmd_len" -le -1; }
 	      then
@@ -8192,7 +9687,7 @@ EOF
 		output_la=$func_basename_result
 		save_libobjs=$libobjs
 		save_output=$output
-		output=${output_objdir}/${output_la}.nm
+		output=$output_objdir/$output_la.nm
 		func_to_tool_file "$output"
 		libobjs=$nm_file_list_spec$func_to_tool_file_result
 		func_append delfiles " $output"
@@ -8215,8 +9710,8 @@ EOF
 		break
 	      fi
 	    done
-	    IFS="$save_ifs"
-	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	    IFS=$save_ifs
+	    if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
 	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
 	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
 	    fi
@@ -8224,16 +9719,16 @@ EOF
 	fi
 
 	if test -n "$export_symbols" && test -n "$include_expsyms"; then
-	  tmp_export_symbols="$export_symbols"
-	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  tmp_export_symbols=$export_symbols
+	  test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
 	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
 	fi
 
-	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
 	  # The given exports_symbols file has to be filtered, so filter it.
-	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
 	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
-	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # 's' commands, which not all seds can handle. GNU sed should be fine
 	  # though. Also, the filter scales superlinearly with the number of
 	  # global variables. join(1) would be nice here, but unfortunately
 	  # isn't a blessed tool.
@@ -8252,11 +9747,11 @@ EOF
 	    ;;
 	  esac
 	done
-	deplibs="$tmp_deplibs"
+	deplibs=$tmp_deplibs
 
 	if test -n "$convenience"; then
 	  if test -n "$whole_archive_flag_spec" &&
-	    test "$compiler_needs_object" = yes &&
+	    test yes = "$compiler_needs_object" &&
 	    test -z "$libobjs"; then
 	    # extract the archives, so we have objects to list.
 	    # TODO: could optimize this to just extract one archive.
@@ -8267,7 +9762,7 @@ EOF
 	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
 	    test "X$libobjs" = "X " && libobjs=
 	  else
-	    gentop="$output_objdir/${outputname}x"
+	    gentop=$output_objdir/${outputname}x
 	    func_append generated " $gentop"
 
 	    func_extract_archives $gentop $convenience
@@ -8276,18 +9771,18 @@ EOF
 	  fi
 	fi
 
-	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
 	  eval flag=\"$thread_safe_flag_spec\"
 	  func_append linker_flags " $flag"
 	fi
 
 	# Make a backup of the uninstalled library when relinking
-	if test "$opt_mode" = relink; then
+	if test relink = "$opt_mode"; then
 	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
 	fi
 
 	# Do each of the archive commands.
-	if test "$module" = yes && test -n "$module_cmds" ; then
+	if test yes = "$module" && test -n "$module_cmds"; then
 	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
 	    eval test_cmds=\"$module_expsym_cmds\"
 	    cmds=$module_expsym_cmds
@@ -8305,7 +9800,7 @@ EOF
 	  fi
 	fi
 
-	if test "X$skipped_export" != "X:" &&
+	if test : != "$skipped_export" &&
 	   func_len " $test_cmds" &&
 	   len=$func_len_result &&
 	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
@@ -8338,8 +9833,8 @@ EOF
 	  last_robj=
 	  k=1
 
-	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
-	    output=${output_objdir}/${output_la}.lnkscript
+	  if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+	    output=$output_objdir/$output_la.lnkscript
 	    func_verbose "creating GNU ld script: $output"
 	    echo 'INPUT (' > $output
 	    for obj in $save_libobjs
@@ -8351,14 +9846,14 @@ EOF
 	    func_append delfiles " $output"
 	    func_to_tool_file "$output"
 	    output=$func_to_tool_file_result
-	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
-	    output=${output_objdir}/${output_la}.lnk
+	  elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+	    output=$output_objdir/$output_la.lnk
 	    func_verbose "creating linker input file list: $output"
 	    : > $output
 	    set x $save_libobjs
 	    shift
 	    firstobj=
-	    if test "$compiler_needs_object" = yes; then
+	    if test yes = "$compiler_needs_object"; then
 	      firstobj="$1 "
 	      shift
 	    fi
@@ -8373,7 +9868,7 @@ EOF
 	  else
 	    if test -n "$save_libobjs"; then
 	      func_verbose "creating reloadable object files..."
-	      output=$output_objdir/$output_la-${k}.$objext
+	      output=$output_objdir/$output_la-$k.$objext
 	      eval test_cmds=\"$reload_cmds\"
 	      func_len " $test_cmds"
 	      len0=$func_len_result
@@ -8385,13 +9880,13 @@ EOF
 		func_len " $obj"
 		func_arith $len + $func_len_result
 		len=$func_arith_result
-		if test "X$objlist" = X ||
+		if test -z "$objlist" ||
 		   test "$len" -lt "$max_cmd_len"; then
 		  func_append objlist " $obj"
 		else
 		  # The command $test_cmds is almost too long, add a
 		  # command to the queue.
-		  if test "$k" -eq 1 ; then
+		  if test 1 -eq "$k"; then
 		    # The first file doesn't have a previous command to add.
 		    reload_objs=$objlist
 		    eval concat_cmds=\"$reload_cmds\"
@@ -8401,10 +9896,10 @@ EOF
 		    reload_objs="$objlist $last_robj"
 		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
 		  fi
-		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  last_robj=$output_objdir/$output_la-$k.$objext
 		  func_arith $k + 1
 		  k=$func_arith_result
-		  output=$output_objdir/$output_la-${k}.$objext
+		  output=$output_objdir/$output_la-$k.$objext
 		  objlist=" $obj"
 		  func_len " $last_robj"
 		  func_arith $len0 + $func_len_result
@@ -8416,9 +9911,9 @@ EOF
 	      # files will link in the last one created.
 	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
 	      reload_objs="$objlist $last_robj"
-	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      eval concat_cmds=\"\$concat_cmds$reload_cmds\"
 	      if test -n "$last_robj"; then
-	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	        eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
 	      fi
 	      func_append delfiles " $output"
 
@@ -8426,9 +9921,9 @@ EOF
 	      output=
 	    fi
 
-	    if ${skipped_export-false}; then
-	      func_verbose "generating symbol list for \`$libname.la'"
-	      export_symbols="$output_objdir/$libname.exp"
+	    ${skipped_export-false} && {
+	      func_verbose "generating symbol list for '$libname.la'"
+	      export_symbols=$output_objdir/$libname.exp
 	      $opt_dry_run || $RM $export_symbols
 	      libobjs=$output
 	      # Append the command to create the export file.
@@ -8437,16 +9932,16 @@ EOF
 	      if test -n "$last_robj"; then
 		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
 	      fi
-	    fi
+	    }
 
 	    test -n "$save_libobjs" &&
 	      func_verbose "creating a temporary reloadable object file: $output"
 
 	    # Loop through the commands generated above and execute them.
-	    save_ifs="$IFS"; IFS='~'
+	    save_ifs=$IFS; IFS='~'
 	    for cmd in $concat_cmds; do
-	      IFS="$save_ifs"
-	      $opt_silent || {
+	      IFS=$save_ifs
+	      $opt_quiet || {
 		  func_quote_for_expand "$cmd"
 		  eval "func_echo $func_quote_for_expand_result"
 	      }
@@ -8454,7 +9949,7 @@ EOF
 		lt_exit=$?
 
 		# Restore the uninstalled library and exit
-		if test "$opt_mode" = relink; then
+		if test relink = "$opt_mode"; then
 		  ( cd "$output_objdir" && \
 		    $RM "${realname}T" && \
 		    $MV "${realname}U" "$realname" )
@@ -8463,7 +9958,7 @@ EOF
 		exit $lt_exit
 	      }
 	    done
-	    IFS="$save_ifs"
+	    IFS=$save_ifs
 
 	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
 	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
@@ -8471,18 +9966,18 @@ EOF
 	    fi
 	  fi
 
-          if ${skipped_export-false}; then
+          ${skipped_export-false} && {
 	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
-	      tmp_export_symbols="$export_symbols"
-	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      tmp_export_symbols=$export_symbols
+	      test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
 	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
 	    fi
 
 	    if test -n "$orig_export_symbols"; then
 	      # The given exports_symbols file has to be filtered, so filter it.
-	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
 	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
-	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # 's' commands, which not all seds can handle. GNU sed should be fine
 	      # though. Also, the filter scales superlinearly with the number of
 	      # global variables. join(1) would be nice here, but unfortunately
 	      # isn't a blessed tool.
@@ -8491,7 +9986,7 @@ EOF
 	      export_symbols=$output_objdir/$libname.def
 	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
 	    fi
-	  fi
+	  }
 
 	  libobjs=$output
 	  # Restore the value of output.
@@ -8505,7 +10000,7 @@ EOF
 	  # value of $libobjs for piecewise linking.
 
 	  # Do each of the archive commands.
-	  if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test yes = "$module" && test -n "$module_cmds"; then
 	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
 	      cmds=$module_expsym_cmds
 	    else
@@ -8527,7 +10022,7 @@ EOF
 
 	# Add any objects from preloaded convenience libraries
 	if test -n "$dlprefiles"; then
-	  gentop="$output_objdir/${outputname}x"
+	  gentop=$output_objdir/${outputname}x
 	  func_append generated " $gentop"
 
 	  func_extract_archives $gentop $dlprefiles
@@ -8535,11 +10030,12 @@ EOF
 	  test "X$libobjs" = "X " && libobjs=
 	fi
 
-	save_ifs="$IFS"; IFS='~'
+	save_ifs=$IFS; IFS='~'
 	for cmd in $cmds; do
-	  IFS="$save_ifs"
+	  IFS=$sp$nl
 	  eval cmd=\"$cmd\"
-	  $opt_silent || {
+	  IFS=$save_ifs
+	  $opt_quiet || {
 	    func_quote_for_expand "$cmd"
 	    eval "func_echo $func_quote_for_expand_result"
 	  }
@@ -8547,7 +10043,7 @@ EOF
 	    lt_exit=$?
 
 	    # Restore the uninstalled library and exit
-	    if test "$opt_mode" = relink; then
+	    if test relink = "$opt_mode"; then
 	      ( cd "$output_objdir" && \
 	        $RM "${realname}T" && \
 		$MV "${realname}U" "$realname" )
@@ -8556,10 +10052,10 @@ EOF
 	    exit $lt_exit
 	  }
 	done
-	IFS="$save_ifs"
+	IFS=$save_ifs
 
 	# Restore the uninstalled library and exit
-	if test "$opt_mode" = relink; then
+	if test relink = "$opt_mode"; then
 	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
 
 	  if test -n "$convenience"; then
@@ -8579,39 +10075,39 @@ EOF
 	done
 
 	# If -module or -export-dynamic was specified, set the dlname.
-	if test "$module" = yes || test "$export_dynamic" = yes; then
+	if test yes = "$module" || test yes = "$export_dynamic"; then
 	  # On all known operating systems, these are identical.
-	  dlname="$soname"
+	  dlname=$soname
 	fi
       fi
       ;;
 
     obj)
-      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
-	func_warning "\`-dlopen' is ignored for objects"
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+	func_warning "'-dlopen' is ignored for objects"
       fi
 
       case " $deplibs" in
       *\ -l* | *\ -L*)
-	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+	func_warning "'-l' and '-L' are ignored for objects" ;;
       esac
 
       test -n "$rpath" && \
-	func_warning "\`-rpath' is ignored for objects"
+	func_warning "'-rpath' is ignored for objects"
 
       test -n "$xrpath" && \
-	func_warning "\`-R' is ignored for objects"
+	func_warning "'-R' is ignored for objects"
 
       test -n "$vinfo" && \
-	func_warning "\`-version-info' is ignored for objects"
+	func_warning "'-version-info' is ignored for objects"
 
       test -n "$release" && \
-	func_warning "\`-release' is ignored for objects"
+	func_warning "'-release' is ignored for objects"
 
       case $output in
       *.lo)
 	test -n "$objs$old_deplibs" && \
-	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+	  func_fatal_error "cannot build library object '$output' from non-libtool objects"
 
 	libobj=$output
 	func_lo2o "$libobj"
@@ -8619,7 +10115,7 @@ EOF
 	;;
       *)
 	libobj=
-	obj="$output"
+	obj=$output
 	;;
       esac
 
@@ -8632,17 +10128,19 @@ EOF
       # the extraction.
       reload_conv_objs=
       gentop=
-      # reload_cmds runs $LD directly, so let us get rid of
-      # -Wl from whole_archive_flag_spec and hope we can get by with
-      # turning comma into space..
-      wl=
-
+      # if reload_cmds runs $LD directly, get rid of -Wl from
+      # whole_archive_flag_spec and hope we can get by with turning comma
+      # into space.
+      case $reload_cmds in
+        *\$LD[\ \$]*) wl= ;;
+      esac
       if test -n "$convenience"; then
 	if test -n "$whole_archive_flag_spec"; then
 	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
-	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	  test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	  reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
 	else
-	  gentop="$output_objdir/${obj}x"
+	  gentop=$output_objdir/${obj}x
 	  func_append generated " $gentop"
 
 	  func_extract_archives $gentop $convenience
@@ -8651,12 +10149,12 @@ EOF
       fi
 
       # If we're not building shared, we need to use non_pic_objs
-      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+      test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
 
       # Create the old-style object.
-      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+      reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
 
-      output="$obj"
+      output=$obj
       func_execute_cmds "$reload_cmds" 'exit $?'
 
       # Exit if we aren't doing a library object file.
@@ -8668,7 +10166,7 @@ EOF
 	exit $EXIT_SUCCESS
       fi
 
-      if test "$build_libtool_libs" != yes; then
+      test yes = "$build_libtool_libs" || {
 	if test -n "$gentop"; then
 	  func_show_eval '${RM}r "$gentop"'
 	fi
@@ -8678,12 +10176,12 @@ EOF
 	# $show "echo timestamp > $libobj"
 	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
 	exit $EXIT_SUCCESS
-      fi
+      }
 
-      if test -n "$pic_flag" || test "$pic_mode" != default; then
+      if test -n "$pic_flag" || test default != "$pic_mode"; then
 	# Only do commands if we really have different PIC objects.
 	reload_objs="$libobjs $reload_conv_objs"
-	output="$libobj"
+	output=$libobj
 	func_execute_cmds "$reload_cmds" 'exit $?'
       fi
 
@@ -8700,16 +10198,14 @@ EOF
 	          output=$func_stripname_result.exe;;
       esac
       test -n "$vinfo" && \
-	func_warning "\`-version-info' is ignored for programs"
+	func_warning "'-version-info' is ignored for programs"
 
       test -n "$release" && \
-	func_warning "\`-release' is ignored for programs"
+	func_warning "'-release' is ignored for programs"
 
-      test "$preload" = yes \
-        && test "$dlopen_support" = unknown \
-	&& test "$dlopen_self" = unknown \
-	&& test "$dlopen_self_static" = unknown && \
-	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+      $preload \
+	&& test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+	&& func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
 
       case $host in
       *-*-rhapsody* | *-*-darwin1.[012])
@@ -8723,11 +10219,11 @@ EOF
       *-*-darwin*)
 	# Don't allow lazy linking, it breaks C++ global constructors
 	# But is supposedly fixed on 10.4 or later (yay!).
-	if test "$tagname" = CXX ; then
+	if test CXX = "$tagname"; then
 	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
 	    10.[0123])
-	      func_append compile_command " ${wl}-bind_at_load"
-	      func_append finalize_command " ${wl}-bind_at_load"
+	      func_append compile_command " $wl-bind_at_load"
+	      func_append finalize_command " $wl-bind_at_load"
 	    ;;
 	  esac
 	fi
@@ -8763,7 +10259,7 @@ EOF
 	*) func_append new_libs " $deplib" ;;
 	esac
       done
-      compile_deplibs="$new_libs"
+      compile_deplibs=$new_libs
 
 
       func_append compile_command " $compile_deplibs"
@@ -8787,7 +10283,7 @@ EOF
 	if test -n "$hardcode_libdir_flag_spec"; then
 	  if test -n "$hardcode_libdir_separator"; then
 	    if test -z "$hardcode_libdirs"; then
-	      hardcode_libdirs="$libdir"
+	      hardcode_libdirs=$libdir
 	    else
 	      # Just accumulate the unique libdirs.
 	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
@@ -8810,7 +10306,7 @@ EOF
 	fi
 	case $host in
 	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
-	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
 	  case :$dllsearchpath: in
 	  *":$libdir:"*) ;;
 	  ::) dllsearchpath=$libdir;;
@@ -8827,10 +10323,10 @@ EOF
       # Substitute the hardcoded libdirs into the rpath.
       if test -n "$hardcode_libdir_separator" &&
 	 test -n "$hardcode_libdirs"; then
-	libdir="$hardcode_libdirs"
+	libdir=$hardcode_libdirs
 	eval rpath=\" $hardcode_libdir_flag_spec\"
       fi
-      compile_rpath="$rpath"
+      compile_rpath=$rpath
 
       rpath=
       hardcode_libdirs=
@@ -8838,7 +10334,7 @@ EOF
 	if test -n "$hardcode_libdir_flag_spec"; then
 	  if test -n "$hardcode_libdir_separator"; then
 	    if test -z "$hardcode_libdirs"; then
-	      hardcode_libdirs="$libdir"
+	      hardcode_libdirs=$libdir
 	    else
 	      # Just accumulate the unique libdirs.
 	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
@@ -8863,45 +10359,43 @@ EOF
       # Substitute the hardcoded libdirs into the rpath.
       if test -n "$hardcode_libdir_separator" &&
 	 test -n "$hardcode_libdirs"; then
-	libdir="$hardcode_libdirs"
+	libdir=$hardcode_libdirs
 	eval rpath=\" $hardcode_libdir_flag_spec\"
       fi
-      finalize_rpath="$rpath"
+      finalize_rpath=$rpath
 
-      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+      if test -n "$libobjs" && test yes = "$build_old_libs"; then
 	# Transform all the library objects into standard objects.
 	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
 	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
       fi
 
-      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+      func_generate_dlsyms "$outputname" "@PROGRAM@" false
 
       # template prelinking step
       if test -n "$prelink_cmds"; then
 	func_execute_cmds "$prelink_cmds" 'exit $?'
       fi
 
-      wrappers_required=yes
+      wrappers_required=:
       case $host in
       *cegcc* | *mingw32ce*)
         # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
-        wrappers_required=no
+        wrappers_required=false
         ;;
       *cygwin* | *mingw* )
-        if test "$build_libtool_libs" != yes; then
-          wrappers_required=no
-        fi
+        test yes = "$build_libtool_libs" || wrappers_required=false
         ;;
       *)
-        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
-          wrappers_required=no
+        if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+          wrappers_required=false
         fi
         ;;
       esac
-      if test "$wrappers_required" = no; then
+      $wrappers_required || {
 	# Replace the output file specification.
 	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
-	link_command="$compile_command$compile_rpath"
+	link_command=$compile_command$compile_rpath
 
 	# We have no uninstalled library dependencies, so finalize right now.
 	exit_status=0
@@ -8914,12 +10408,12 @@ EOF
 	fi
 
 	# Delete the generated files.
-	if test -f "$output_objdir/${outputname}S.${objext}"; then
-	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	if test -f "$output_objdir/${outputname}S.$objext"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
 	fi
 
 	exit $exit_status
-      fi
+      }
 
       if test -n "$compile_shlibpath$finalize_shlibpath"; then
 	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
@@ -8949,9 +10443,9 @@ EOF
 	fi
       fi
 
-      if test "$no_install" = yes; then
+      if test yes = "$no_install"; then
 	# We don't need to create a wrapper script.
-	link_command="$compile_var$compile_command$compile_rpath"
+	link_command=$compile_var$compile_command$compile_rpath
 	# Replace the output file specification.
 	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
 	# Delete the old output file.
@@ -8968,27 +10462,28 @@ EOF
 	exit $EXIT_SUCCESS
       fi
 
-      if test "$hardcode_action" = relink; then
-	# Fast installation is not supported
-	link_command="$compile_var$compile_command$compile_rpath"
-	relink_command="$finalize_var$finalize_command$finalize_rpath"
+      case $hardcode_action,$fast_install in
+        relink,*)
+	  # Fast installation is not supported
+	  link_command=$compile_var$compile_command$compile_rpath
+	  relink_command=$finalize_var$finalize_command$finalize_rpath
 
-	func_warning "this platform does not like uninstalled shared libraries"
-	func_warning "\`$output' will be relinked during installation"
-      else
-	if test "$fast_install" != no; then
-	  link_command="$finalize_var$compile_command$finalize_rpath"
-	  if test "$fast_install" = yes; then
-	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
-	  else
-	    # fast_install is set to needless
-	    relink_command=
-	  fi
-	else
-	  link_command="$compile_var$compile_command$compile_rpath"
-	  relink_command="$finalize_var$finalize_command$finalize_rpath"
-	fi
-      fi
+	  func_warning "this platform does not like uninstalled shared libraries"
+	  func_warning "'$output' will be relinked during installation"
+	  ;;
+        *,yes)
+	  link_command=$finalize_var$compile_command$finalize_rpath
+	  relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+          ;;
+	*,no)
+	  link_command=$compile_var$compile_command$compile_rpath
+	  relink_command=$finalize_var$finalize_command$finalize_rpath
+          ;;
+	*,needless)
+	  link_command=$finalize_var$compile_command$finalize_rpath
+	  relink_command=
+          ;;
+      esac
 
       # Replace the output file specification.
       link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
@@ -9045,8 +10540,8 @@ EOF
 	    func_dirname_and_basename "$output" "" "."
 	    output_name=$func_basename_result
 	    output_path=$func_dirname_result
-	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
-	    cwrapper="$output_path/$output_name.exe"
+	    cwrappersource=$output_path/$objdir/lt-$output_name.c
+	    cwrapper=$output_path/$output_name.exe
 	    $RM $cwrappersource $cwrapper
 	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
 
@@ -9067,7 +10562,7 @@ EOF
 	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
 	    $opt_dry_run || {
 	      # note: this script will not be executed, so do not chmod.
-	      if test "x$build" = "x$host" ; then
+	      if test "x$build" = "x$host"; then
 		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
 	      else
 		func_emit_wrapper no > $func_ltwrapper_scriptname_result
@@ -9090,25 +10585,27 @@ EOF
     # See if we need to build an old-fashioned archive.
     for oldlib in $oldlibs; do
 
-      if test "$build_libtool_libs" = convenience; then
-	oldobjs="$libobjs_save $symfileobj"
-	addlibs="$convenience"
-	build_libtool_libs=no
-      else
-	if test "$build_libtool_libs" = module; then
-	  oldobjs="$libobjs_save"
+      case $build_libtool_libs in
+        convenience)
+	  oldobjs="$libobjs_save $symfileobj"
+	  addlibs=$convenience
 	  build_libtool_libs=no
-	else
+	  ;;
+	module)
+	  oldobjs=$libobjs_save
+	  addlibs=$old_convenience
+	  build_libtool_libs=no
+          ;;
+	*)
 	  oldobjs="$old_deplibs $non_pic_objects"
-	  if test "$preload" = yes && test -f "$symfileobj"; then
-	    func_append oldobjs " $symfileobj"
-	  fi
-	fi
-	addlibs="$old_convenience"
-      fi
+	  $preload && test -f "$symfileobj" \
+	    && func_append oldobjs " $symfileobj"
+	  addlibs=$old_convenience
+	  ;;
+      esac
 
       if test -n "$addlibs"; then
-	gentop="$output_objdir/${outputname}x"
+	gentop=$output_objdir/${outputname}x
 	func_append generated " $gentop"
 
 	func_extract_archives $gentop $addlibs
@@ -9116,13 +10613,13 @@ EOF
       fi
 
       # Do each command in the archive commands.
-      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+      if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
 	cmds=$old_archive_from_new_cmds
       else
 
 	# Add any objects from preloaded convenience libraries
 	if test -n "$dlprefiles"; then
-	  gentop="$output_objdir/${outputname}x"
+	  gentop=$output_objdir/${outputname}x
 	  func_append generated " $gentop"
 
 	  func_extract_archives $gentop $dlprefiles
@@ -9143,7 +10640,7 @@ EOF
 	  :
 	else
 	  echo "copying selected object files to avoid basename conflicts..."
-	  gentop="$output_objdir/${outputname}x"
+	  gentop=$output_objdir/${outputname}x
 	  func_append generated " $gentop"
 	  func_mkdir_p "$gentop"
 	  save_oldobjs=$oldobjs
@@ -9152,7 +10649,7 @@ EOF
 	  for obj in $save_oldobjs
 	  do
 	    func_basename "$obj"
-	    objbase="$func_basename_result"
+	    objbase=$func_basename_result
 	    case " $oldobjs " in
 	    " ") oldobjs=$obj ;;
 	    *[\ /]"$objbase "*)
@@ -9221,18 +10718,18 @@ EOF
 	    else
 	      # the above command should be used before it gets too long
 	      oldobjs=$objlist
-	      if test "$obj" = "$last_oldobj" ; then
+	      if test "$obj" = "$last_oldobj"; then
 		RANLIB=$save_RANLIB
 	      fi
 	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
-	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
 	      objlist=
 	      len=$len0
 	    fi
 	  done
 	  RANLIB=$save_RANLIB
 	  oldobjs=$objlist
-	  if test "X$oldobjs" = "X" ; then
+	  if test -z "$oldobjs"; then
 	    eval cmds=\"\$concat_cmds\"
 	  else
 	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
@@ -9249,7 +10746,7 @@ EOF
     case $output in
     *.la)
       old_library=
-      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      test yes = "$build_old_libs" && old_library=$libname.$libext
       func_verbose "creating $output"
 
       # Preserve any variables that may affect compiler behavior
@@ -9264,31 +10761,31 @@ EOF
 	fi
       done
       # Quote the link command for shipping.
-      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
       relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
-      if test "$hardcode_automatic" = yes ; then
+      if test yes = "$hardcode_automatic"; then
 	relink_command=
       fi
 
       # Only create the output if not a dry run.
       $opt_dry_run || {
 	for installed in no yes; do
-	  if test "$installed" = yes; then
+	  if test yes = "$installed"; then
 	    if test -z "$install_libdir"; then
 	      break
 	    fi
-	    output="$output_objdir/$outputname"i
+	    output=$output_objdir/${outputname}i
 	    # Replace all uninstalled libtool libraries with the installed ones
 	    newdependency_libs=
 	    for deplib in $dependency_libs; do
 	      case $deplib in
 	      *.la)
 		func_basename "$deplib"
-		name="$func_basename_result"
+		name=$func_basename_result
 		func_resolve_sysroot "$deplib"
-		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
 		test -z "$libdir" && \
-		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  func_fatal_error "'$deplib' is not a valid libtool archive"
 		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
 		;;
 	      -L*)
@@ -9304,23 +10801,23 @@ EOF
 	      *) func_append newdependency_libs " $deplib" ;;
 	      esac
 	    done
-	    dependency_libs="$newdependency_libs"
+	    dependency_libs=$newdependency_libs
 	    newdlfiles=
 
 	    for lib in $dlfiles; do
 	      case $lib in
 	      *.la)
 	        func_basename "$lib"
-		name="$func_basename_result"
-		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		name=$func_basename_result
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
 		test -z "$libdir" && \
-		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		  func_fatal_error "'$lib' is not a valid libtool archive"
 		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
 		;;
 	      *) func_append newdlfiles " $lib" ;;
 	      esac
 	    done
-	    dlfiles="$newdlfiles"
+	    dlfiles=$newdlfiles
 	    newdlprefiles=
 	    for lib in $dlprefiles; do
 	      case $lib in
@@ -9330,34 +10827,34 @@ EOF
 		# didn't already link the preopened objects directly into
 		# the library:
 		func_basename "$lib"
-		name="$func_basename_result"
-		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		name=$func_basename_result
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
 		test -z "$libdir" && \
-		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		  func_fatal_error "'$lib' is not a valid libtool archive"
 		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
 		;;
 	      esac
 	    done
-	    dlprefiles="$newdlprefiles"
+	    dlprefiles=$newdlprefiles
 	  else
 	    newdlfiles=
 	    for lib in $dlfiles; do
 	      case $lib in
-		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
 		*) abs=`pwd`"/$lib" ;;
 	      esac
 	      func_append newdlfiles " $abs"
 	    done
-	    dlfiles="$newdlfiles"
+	    dlfiles=$newdlfiles
 	    newdlprefiles=
 	    for lib in $dlprefiles; do
 	      case $lib in
-		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
 		*) abs=`pwd`"/$lib" ;;
 	      esac
 	      func_append newdlprefiles " $abs"
 	    done
-	    dlprefiles="$newdlprefiles"
+	    dlprefiles=$newdlprefiles
 	  fi
 	  $RM $output
 	  # place dlname in correct position for cygwin
@@ -9373,10 +10870,9 @@ EOF
 	  case $host,$output,$installed,$module,$dlname in
 	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
 	      # If a -bindir argument was supplied, place the dll there.
-	      if test "x$bindir" != x ;
-	      then
+	      if test -n "$bindir"; then
 		func_relative_path "$install_libdir" "$bindir"
-		tdlname=$func_relative_path_result$dlname
+		tdlname=$func_relative_path_result/$dlname
 	      else
 		# Otherwise fall back on heuristic.
 		tdlname=../bin/$dlname
@@ -9385,7 +10881,7 @@ EOF
 	  esac
 	  $ECHO > $output "\
 # $outputname - a libtool library file
-# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
 #
 # Please DO NOT delete this file!
 # It is necessary for linking the library.
@@ -9399,7 +10895,7 @@ library_names='$library_names'
 # The name of the static archive.
 old_library='$old_library'
 
-# Linker flags that can not go in dependency_libs.
+# Linker flags that cannot go in dependency_libs.
 inherited_linker_flags='$new_inherited_linker_flags'
 
 # Libraries that this one depends upon.
@@ -9425,7 +10921,7 @@ dlpreopen='$dlprefiles'
 
 # Directory that this library needs to be installed in:
 libdir='$install_libdir'"
-	  if test "$installed" = no && test "$need_relink" = yes; then
+	  if test no,yes = "$installed,$need_relink"; then
 	    $ECHO >> $output "\
 relink_command=\"$relink_command\""
 	  fi
@@ -9440,27 +10936,29 @@ relink_command=\"$relink_command\""
     exit $EXIT_SUCCESS
 }
 
-{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
-    func_mode_link ${1+"$@"}
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+  func_mode_link ${1+"$@"}
+fi
 
 
 # func_mode_uninstall arg...
 func_mode_uninstall ()
 {
-    $opt_debug
-    RM="$nonopt"
+    $debug_cmd
+
+    RM=$nonopt
     files=
-    rmforce=
+    rmforce=false
     exit_status=0
 
     # This variable tells wrapper scripts just to set variables rather
     # than running their programs.
-    libtool_install_magic="$magic"
+    libtool_install_magic=$magic
 
     for arg
     do
       case $arg in
-      -f) func_append RM " $arg"; rmforce=yes ;;
+      -f) func_append RM " $arg"; rmforce=: ;;
       -*) func_append RM " $arg" ;;
       *) func_append files " $arg" ;;
       esac
@@ -9473,18 +10971,18 @@ func_mode_uninstall ()
 
     for file in $files; do
       func_dirname "$file" "" "."
-      dir="$func_dirname_result"
-      if test "X$dir" = X.; then
-	odir="$objdir"
+      dir=$func_dirname_result
+      if test . = "$dir"; then
+	odir=$objdir
       else
-	odir="$dir/$objdir"
+	odir=$dir/$objdir
       fi
       func_basename "$file"
-      name="$func_basename_result"
-      test "$opt_mode" = uninstall && odir="$dir"
+      name=$func_basename_result
+      test uninstall = "$opt_mode" && odir=$dir
 
       # Remember odir for removal later, being careful to avoid duplicates
-      if test "$opt_mode" = clean; then
+      if test clean = "$opt_mode"; then
 	case " $rmdirs " in
 	  *" $odir "*) ;;
 	  *) func_append rmdirs " $odir" ;;
@@ -9499,11 +10997,11 @@ func_mode_uninstall ()
       elif test -d "$file"; then
 	exit_status=1
 	continue
-      elif test "$rmforce" = yes; then
+      elif $rmforce; then
 	continue
       fi
 
-      rmfiles="$file"
+      rmfiles=$file
 
       case $name in
       *.la)
@@ -9517,7 +11015,7 @@ func_mode_uninstall ()
 	  done
 	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
 
-	  case "$opt_mode" in
+	  case $opt_mode in
 	  clean)
 	    case " $library_names " in
 	    *" $dlname "*) ;;
@@ -9528,12 +11026,12 @@ func_mode_uninstall ()
 	  uninstall)
 	    if test -n "$library_names"; then
 	      # Do each command in the postuninstall commands.
-	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	      func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
 	    fi
 
 	    if test -n "$old_library"; then
 	      # Do each command in the old_postuninstall commands.
-	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	      func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
 	    fi
 	    # FIXME: should reinstall the best remaining shared library.
 	    ;;
@@ -9549,21 +11047,19 @@ func_mode_uninstall ()
 	  func_source $dir/$name
 
 	  # Add PIC object to the list of files to remove.
-	  if test -n "$pic_object" &&
-	     test "$pic_object" != none; then
+	  if test -n "$pic_object" && test none != "$pic_object"; then
 	    func_append rmfiles " $dir/$pic_object"
 	  fi
 
 	  # Add non-PIC object to the list of files to remove.
-	  if test -n "$non_pic_object" &&
-	     test "$non_pic_object" != none; then
+	  if test -n "$non_pic_object" && test none != "$non_pic_object"; then
 	    func_append rmfiles " $dir/$non_pic_object"
 	  fi
 	fi
 	;;
 
       *)
-	if test "$opt_mode" = clean ; then
+	if test clean = "$opt_mode"; then
 	  noexename=$name
 	  case $file in
 	  *.exe)
@@ -9590,12 +11086,12 @@ func_mode_uninstall ()
 
 	    # note $name still contains .exe if it was in $file originally
 	    # as does the version of $file that was added into $rmfiles
-	    func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
-	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	    func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+	    if test yes = "$fast_install" && test -n "$relink_command"; then
 	      func_append rmfiles " $odir/lt-$name"
 	    fi
-	    if test "X$noexename" != "X$name" ; then
-	      func_append rmfiles " $odir/lt-${noexename}.c"
+	    if test "X$noexename" != "X$name"; then
+	      func_append rmfiles " $odir/lt-$noexename.c"
 	    fi
 	  fi
 	fi
@@ -9604,7 +11100,7 @@ func_mode_uninstall ()
       func_show_eval "$RM $rmfiles" 'exit_status=1'
     done
 
-    # Try to remove the ${objdir}s in the directories where we deleted files
+    # Try to remove the $objdir's in the directories where we deleted files
     for dir in $rmdirs; do
       if test -d "$dir"; then
 	func_show_eval "rmdir $dir >/dev/null 2>&1"
@@ -9614,16 +11110,17 @@ func_mode_uninstall ()
     exit $exit_status
 }
 
-{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
-    func_mode_uninstall ${1+"$@"}
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+  func_mode_uninstall ${1+"$@"}
+fi
 
 test -z "$opt_mode" && {
-  help="$generic_help"
+  help=$generic_help
   func_fatal_help "you must specify a MODE"
 }
 
 test -z "$exec_cmd" && \
-  func_fatal_help "invalid operation mode \`$opt_mode'"
+  func_fatal_help "invalid operation mode '$opt_mode'"
 
 if test -n "$exec_cmd"; then
   eval exec "$exec_cmd"
@@ -9634,7 +11131,7 @@ exit $exit_status
 
 
 # The TAGs below are defined such that we never get into a situation
-# in which we disable both kinds of libraries.  Given conflicting
+# where we disable both kinds of libraries.  Given conflicting
 # choices, we go for a static library, that is the most portable,
 # since we can't tell whether shared libraries were disabled because
 # the user asked for that or because the platform doesn't support
@@ -9657,5 +11154,3 @@ build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
 # mode:shell-script
 # sh-indentation:2
 # End:
-# vi:sw=2
-
diff --git a/build-aux/missing b/build-aux/missing
index db98974..f62bbae 100755
--- a/build-aux/missing
+++ b/build-aux/missing
@@ -3,7 +3,7 @@
 
 scriptversion=2013-10-28.13; # UTC
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 # Originally written by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
 
 # This program is free software; you can redistribute it and/or modify
diff --git a/build-aux/test-driver b/build-aux/test-driver
index d306056..8e575b0 100755
--- a/build-aux/test-driver
+++ b/build-aux/test-driver
@@ -3,7 +3,7 @@
 
 scriptversion=2013-07-13.22; # UTC
 
-# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+# Copyright (C) 2011-2014 Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -106,11 +106,14 @@ trap "st=143; $do_exit" 15
 # Test script is run here.
 "$@" >$log_file 2>&1
 estatus=$?
+
 if test $enable_hard_errors = no && test $estatus -eq 99; then
-  estatus=1
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
 fi
 
-case $estatus:$expect_failure in
+case $tweaked_estatus:$expect_failure in
   0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
   0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
   77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
@@ -119,6 +122,12 @@ case $estatus:$expect_failure in
   *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
 esac
 
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
 # Report outcome to console.
 echo "${col}${res}${std}: $test_name"
 
diff --git a/common/BuildSettings.h b/common/BuildSettings.h
index 78df5a9..d1e2e10 100644
--- a/common/BuildSettings.h
+++ b/common/BuildSettings.h
@@ -20,16 +20,39 @@
 
 #if MPT_OS_WINDOWS
 
-#if (MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2010,0)) || MPT_COMPILER_MSVCCLANGC2
+#if defined(MPT_BUILD_MSVC)
+
 #if defined(MPT_BUILD_TARGET_XP)
+
+#if defined(_M_X64)
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0502 // _WIN32_WINNT_WS03
+#endif
+#else // !_M_X64
+#ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
-#else
+#endif
+#endif // _M_X64
+
+#else // MPT_BUILD_TARGET
+
+#ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x0601 // _WIN32_WINNT_WIN7
 #endif
-#else
-#define _WIN32_WINNT 0x0500 // _WIN32_WINNT_WIN2000
+
+#endif // MPT_BUILD_TARGET
+
+#else // !MPT_BUILD_MSVC
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
 #endif
+
+#endif // MPT_BUILD_MSVC
+
+#ifndef WINVER
 #define WINVER       _WIN32_WINNT
+#endif
 
 #endif // MPT_OS_WINDOWS
 
@@ -63,7 +86,7 @@
 
 
 // Dependencies from the MSVC build system
-#if MPT_COMPILER_MSVC || MPT_COMPILER_MSVCCLANGC2
+#if defined(MPT_BUILD_MSVC)
 
 // This section defines which dependencies are available when building with
 // MSVC. Other build systems provide MPT_WITH_* macros via command-line or other
@@ -81,8 +104,12 @@
 #define MPT_WITH_LHASA
 #define MPT_WITH_MINIZIP
 #define MPT_WITH_OPUS
+#define MPT_WITH_OPUSENC
 #define MPT_WITH_OPUSFILE
+#define MPT_WITH_PICOJSON
 #define MPT_WITH_PORTAUDIO
+//#define MPT_WITH_PULSEAUDIO
+//#define MPT_WITH_PULSEAUDIOSIMPLE
 #define MPT_WITH_SMBPITCHSHIFT
 #define MPT_WITH_UNRAR
 #define MPT_WITH_VORBISENC
@@ -99,10 +126,9 @@
 #endif
 //#define MPT_WITH_MINIMP3
 //#define MPT_WITH_MINIZ
-//#define MPT_WITH_MPG123
+#define MPT_WITH_MPG123
 #define MPT_WITH_OGG
 //#define MPT_WITH_STBVORBIS
-//#define MPT_WITH_UNMO3
 #define MPT_WITH_VORBIS
 #define MPT_WITH_VORBISFILE
 #define MPT_WITH_ZLIB
@@ -112,23 +138,42 @@
 #if defined(LIBOPENMPT_BUILD)
 
 // OpenMPT and libopenmpt dependencies (not for openmp123, player plugins or examples)
-#if defined(LIBOPENMPT_BUILD_SMALL)
+#if defined(LIBOPENMPT_BUILD_FULL) && defined(LIBOPENMPT_BUILD_SMALL)
+#error "only one of LIBOPENMPT_BUILD_FULL or LIBOPENMPT_BUILD_SMALL can be defined"
+#endif // LIBOPENMPT_BUILD_FULL && LIBOPENMPT_BUILD_SMALL
+
+#if defined(LIBOPENMPT_BUILD_FULL)
 
 //#define MPT_WITH_DL
 //#define MPT_WITH_FLAC
 //#define MPT_WITH_ICONV
 //#define MPT_WITH_LTDL
-#if MPT_OS_WINDOWS
+#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
 #if (_WIN32_WINNT >= 0x0601)
 #define MPT_WITH_MEDIAFOUNDATION
 #endif
 #endif
 //#define MPT_WITH_MINIMP3
+//#define MPT_WITH_MINIZ
+#define MPT_WITH_MPG123
+#define MPT_WITH_OGG
+//#define MPT_WITH_STBVORBIS
+#define MPT_WITH_VORBIS
+#define MPT_WITH_VORBISFILE
+#define MPT_WITH_ZLIB
+
+#elif defined(LIBOPENMPT_BUILD_SMALL)
+
+//#define MPT_WITH_DL
+//#define MPT_WITH_FLAC
+//#define MPT_WITH_ICONV
+//#define MPT_WITH_LTDL
+//#define MPT_WITH_MEDIAFOUNDATION
+#define MPT_WITH_MINIMP3
 #define MPT_WITH_MINIZ
 //#define MPT_WITH_MPG123
 //#define MPT_WITH_OGG
 #define MPT_WITH_STBVORBIS
-//#define MPT_WITH_UNMO3
 //#define MPT_WITH_VORBIS
 //#define MPT_WITH_VORBISFILE
 //#define MPT_WITH_ZLIB
@@ -139,17 +184,12 @@
 //#define MPT_WITH_FLAC
 //#define MPT_WITH_ICONV
 //#define MPT_WITH_LTDL
-#if MPT_OS_WINDOWS
-#if (_WIN32_WINNT >= 0x0601)
-#define MPT_WITH_MEDIAFOUNDATION
-#endif
-#endif
+//#define MPT_WITH_MEDIAFOUNDATION
 //#define MPT_WITH_MINIMP3
 //#define MPT_WITH_MINIZ
-//#define MPT_WITH_MPG123
+#define MPT_WITH_MPG123
 #define MPT_WITH_OGG
 //#define MPT_WITH_STBVORBIS
-//#define MPT_WITH_UNMO3
 #define MPT_WITH_VORBIS
 #define MPT_WITH_VORBISFILE
 #define MPT_WITH_ZLIB
@@ -158,7 +198,7 @@
 
 #endif // LIBOPENMPT_BUILD
 
-#endif // MPT_COMPILER_MSVC || MPT_COMPILER_MSVCCLANGC2
+#endif // MPT_BUILD_MSVC
 
 
 
@@ -187,9 +227,6 @@
 // Enable std::istream support in class FileReader (this is generally not needed for the tracker, local files can easily be mmapped as they have been before introducing std::istream support)
 //#define MPT_FILEREADER_STD_ISTREAM
 
-// Enable performance optimizations for seekable std::istream. Note that these probably will only payoff once FileReader::GetRawData() usage gets further reduced.
-//#define MPT_FILEREADER_STD_ISTREAM_SEEKABLE
-
 // Enable callback stream wrapper for FileReader (required by libopenmpt C API).
 //#define MPT_FILEREADER_CALLBACK_STREAM
 
@@ -208,7 +245,7 @@
 // Disable the built-in reverb effect
 //#define NO_REVERB
 
-// Disable built-in miscellaneous DSP effects (surround, mega bass, noise reduction) 
+// Disable built-in miscellaneous DSP effects (surround, mega bass, noise reduction)
 //#define NO_DSP
 
 // Disable the built-in equalizer.
@@ -226,15 +263,6 @@
 // (HACK) Define to build without any plugin support
 //#define NO_PLUGINS
 
-// Enable dynamic loading of libmpg123
-#define MPT_ENABLE_MPG123_DYNBIND
-
-// Enable dynamic loading of un4seen unmo3
-#define MPT_ENABLE_UNMO3_DYNBIND
-
-// Enable built-in MO3 decoder
-#define MPT_ENABLE_MO3_BUILTIN
-
 // Do not build libopenmpt C api
 #define NO_LIBOPENMPT_C
 
@@ -263,7 +291,6 @@
 #endif
 //#define NO_LOGGING
 #define MPT_FILEREADER_STD_ISTREAM
-#define MPT_FILEREADER_STD_ISTREAM_SEEKABLE
 #define MPT_FILEREADER_CALLBACK_STREAM
 //#define MPT_EXTERNAL_SAMPLES
 #if defined(ENABLE_TESTS) || defined(MPT_BUILD_HACK_ARCHIVE_SUPPORT)
@@ -278,31 +305,15 @@
 #else
 #define NO_ARCHIVE_SUPPORT
 #endif
-#define NO_REVERB
+//#define NO_REVERB
 #define NO_DSP
 #define NO_EQ
 #define NO_AGC
 #define NO_VST
-#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
-//#define NO_DMO
-#else
+//#if !MPT_OS_WINDOWS || MPT_OS_WINDOWS_WINRT || !MPT_COMPILER_MSVC || !defined(LIBOPENMPT_BUILD_FULL)
 #define NO_DMO
-#endif
+//#endif
 //#define NO_PLUGINS
-#if defined(MPT_ENABLE_DLOPEN)
-#if MPT_OS_WINDOWS || defined(MPT_WITH_LTDL) || defined(MPT_WITH_DL)
-#if !defined(MPT_WITH_MPG123)
-#define MPT_ENABLE_MPG123_DYNBIND
-#endif
-//#define MPT_ENABLE_UNMO3_DYNBIND
-#endif // MPT_OS_WINDOWS || defined(MPT_WITH_LTDL) || defined(MPT_WITH_DL)
-#else // !MPT_ENABLE_DLOPEN
-//#define MPT_ENABLE_MPG123_DYNBIND
-//#define MPT_ENABLE_UNMO3_DYNBIND
-#endif // MPT_ENABLE_DLOPEN
-#if ((defined(MPT_WITH_MPG123) || defined(MPT_ENABLE_MPG123_DYNBIND) || defined(MPT_WITH_MINIMP3)) || defined(MPT_WITH_MEDIAFOUNDATION)) && ((defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)) || defined(MPT_WITH_STBVORBIS))
-#define MPT_ENABLE_MO3_BUILTIN
-#endif
 //#define NO_LIBOPENMPT_C
 //#define NO_LIBOPENMPT_CXX
 
@@ -324,7 +335,7 @@
 
 #elif MPT_OS_EMSCRIPTEN
 
-	#define MPT_CHARSET_CODECVTUTF8
+	#define MPT_CHARSET_INTERNAL
 	#ifndef MPT_LOCALE_ASSUME_CHARSET
 	#define MPT_LOCALE_ASSUME_CHARSET CharsetUTF8
 	#endif
@@ -337,7 +348,7 @@
 		#define MPT_ICONV_NO_WCHAR
 		#endif
 	#else
-		#define MPT_CHARSET_CODECVTUTF8
+		#define MPT_CHARSET_INTERNAL
 	#endif
 	//#ifndef MPT_LOCALE_ASSUME_CHARSET
 	//#define MPT_LOCALE_ASSUME_CHARSET CharsetUTF8
@@ -380,7 +391,7 @@
 
 	// mpt::ToWString, mpt::wfmt, ConvertStrTo<std::wstring>
 	// Required by the tracker to ease interfacing with WinAPI.
-	// Required by MPT_USTRING_MODE_WIDE to ease type tunneling in mpt::String::Print.
+	// Required by MPT_USTRING_MODE_WIDE to ease type tunneling in mpt::format.
 	#define MPT_WSTRING_FORMAT 1
 
 #else
@@ -408,7 +419,7 @@
 // fixing stuff up
 
 #if defined(MPT_BUILD_TARGET_XP)
-// Also support Wine 1.6 in addiion to Windows XP
+// Also support Wine 1.6 in addition to Windows XP
 #ifndef MPT_QUIRK_NO_CPP_THREAD
 #define MPT_QUIRK_NO_CPP_THREAD
 #endif
@@ -420,6 +431,12 @@
 #endif
 #endif
 
+#if defined(MPT_BUILD_FUZZER)
+#ifndef MPT_FUZZ_TRACKER
+#define MPT_FUZZ_TRACKER
+#endif
+#endif
+
 #if !MPT_COMPILER_MSVC && defined(ENABLE_ASM)
 #undef ENABLE_ASM // inline assembly requires MSVC compiler
 #endif
@@ -456,14 +473,6 @@
 #endif // arch
 #endif // ENABLE_ASM
 
-#if !defined(ENABLE_MMX) && !defined(NO_REVERB)
-#define NO_REVERB // reverb requires mmx
-#endif
-
-#if !defined(ENABLE_X86) && !defined(NO_DSP)
-#define NO_DSP // DSP requires x86 inline asm
-#endif
-
 #if defined(ENABLE_TESTS) && defined(MODPLUG_NO_FILESAVE)
 #undef MODPLUG_NO_FILESAVE // tests recommend file saving
 #endif
@@ -477,10 +486,6 @@
 #undef MPT_WITH_MEDIAFOUNDATION // MediaFoundation requires Windows
 #endif
 
-#if MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2010,0) && defined(MPT_WITH_MEDIAFOUNDATION)
-#undef MPT_WITH_MEDIAFOUNDATION // MediaFoundation requires a modern SDK
-#endif
-
 #if defined(MPT_WITH_MEDIAFOUNDATION) && !defined(MPT_ENABLE_TEMPFILE)
 #define MPT_ENABLE_TEMPFILE
 #endif
@@ -497,20 +502,16 @@
 #define MPT_ENABLE_DYNBIND // Tracker requires dynamic library loading for export codecs
 #endif
 
-#if defined(MPT_ENABLE_MPG123_DYNBIND) && !defined(MPT_ENABLE_DYNBIND)
-#define MPT_ENABLE_DYNBIND // mpg123 is loaded dynamically
+#if defined(MPT_WITH_MPG123) && defined(MPT_BUILD_MSVC_STATIC) && !MPT_OS_WINDOWS_WINRT && !defined(MPT_ENABLE_DYNBIND)
+#define MPT_ENABLE_DYNBIND // static MSVC builds require dynbind to load delay-loaded DLLs
 #endif
 
-#if (defined(MPT_WITH_MPG123) || defined(MPT_ENABLE_MPG123_DYNBIND) || defined(MPT_WITH_MINIMP3)) && !defined(MPT_ENABLE_MP3_SAMPLES)
-#define MPT_ENABLE_MP3_SAMPLES
+#if defined(MPT_WITH_MEDIAFOUNDATION) && !defined(MPT_ENABLE_DYNBIND)
+#define MPT_ENABLE_DYNBIND // MediaFoundation needs dynamic loading in order to test availability of delay loaded libs
 #endif
 
-#if defined(MPT_WITH_UNMO3) || defined(MPT_ENABLE_UNMO3_DYNBIND) || defined(MPT_ENABLE_MO3_BUILTIN)
-#define MPT_ENABLE_MO3
-#endif
-
-#if defined(MPT_ENABLE_UNMO3_DYNBIND) && !defined(MPT_ENABLE_DYNBIND)
-#define MPT_ENABLE_DYNBIND // unmo3 is loaded dynamically
+#if (defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3)) && !defined(MPT_ENABLE_MP3_SAMPLES)
+#define MPT_ENABLE_MP3_SAMPLES
 #endif
 
 #if defined(ENABLE_TESTS)
@@ -529,10 +530,6 @@
 #define MPT_ENABLE_THREAD // Tracker requires threads
 #endif
 
-#if defined(MODPLUG_TRACKER) && !defined(MPT_ENABLE_ATOMIC)
-#define MPT_ENABLE_ATOMIC // Tracker requires threads
-#endif
-
 #if defined(MPT_EXTERNAL_SAMPLES) && !defined(MPT_ENABLE_FILEIO)
 #define MPT_ENABLE_FILEIO // External samples require disk file io
 #endif
@@ -666,10 +663,6 @@
 // happens for immutable classes (i.e. classes containing const members)
 #pragma warning(disable:4512) // assignment operator could not be generated
 
-#if MPT_MSVC_AT_LEAST(2012,0) && MPT_MSVC_BEFORE(2013,0)
-#pragma warning(disable:4250) // 'mpt::fstream' : inherits 'std::basic_istream<_Elem,_Traits>::std::basic_istream<_Elem,_Traits>::_Add_vtordisp1' via dominance
-#endif
-
 #pragma warning(error:4309) // Treat "truncation of constant value"-warning as error.
 
 #ifdef MPT_BUILD_ANALYZED
@@ -703,8 +696,8 @@
 #endif
 #endif
 
-#ifdef MPT_WITH_MINIZ
-#define MINIZ_HEADER_FILE_ONLY
+#ifdef MPT_WITH_PICOJSON
+#define PICOJSON_USE_INT64
 #endif
 
 #ifdef MPT_WITH_SMBPITCHSHIFT
diff --git a/common/CompilerDetect.h b/common/CompilerDetect.h
index 6b0dea4..bad9aa4 100644
--- a/common/CompilerDetect.h
+++ b/common/CompilerDetect.h
@@ -37,8 +37,8 @@
 #define MPT_CLANG_AT_LEAST(major,minor,patch)        (MPT_COMPILER_CLANG_VERSION >= MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
 #define MPT_CLANG_BEFORE(major,minor,patch)          (MPT_COMPILER_CLANG_VERSION <  MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
 
-#if MPT_CLANG_BEFORE(3,0,0)
-#error "clang version 3.0 required"
+#if MPT_CLANG_BEFORE(3,4,0)
+#error "clang version 3.4 required"
 #endif
 
 #if defined(__clang_analyzer__) 
@@ -54,14 +54,18 @@
 #define MPT_GCC_AT_LEAST(major,minor,patch)          (MPT_COMPILER_GCC_VERSION >= MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
 #define MPT_GCC_BEFORE(major,minor,patch)            (MPT_COMPILER_GCC_VERSION <  MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
 
-#if MPT_GCC_BEFORE(4,1,0)
-#error "GCC version 4.1 required"
+#if MPT_GCC_BEFORE(4,8,0)
+#error "GCC version 4.8 required"
 #endif
 
 #elif defined(_MSC_VER)
 
 #define MPT_COMPILER_MSVC                            1
-#if (_MSC_VER >= 1900)
+#if (_MSC_VER >= 1911)
+#define MPT_COMPILER_MSVC_VERSION                    MPT_COMPILER_MAKE_VERSION2(2017,3)
+#elif (_MSC_VER >= 1910)
+#define MPT_COMPILER_MSVC_VERSION                    MPT_COMPILER_MAKE_VERSION2(2017,0)
+#elif (_MSC_VER >= 1900)
 #define MPT_COMPILER_MSVC_VERSION                    MPT_COMPILER_MAKE_VERSION2(2015,0)
 #elif (_MSC_VER >= 1800)
 #define MPT_COMPILER_MSVC_VERSION                    MPT_COMPILER_MAKE_VERSION2(2013,0)
@@ -77,8 +81,8 @@
 #define MPT_MSVC_AT_LEAST(version,sp)                (MPT_COMPILER_MSVC_VERSION >= MPT_COMPILER_MAKE_VERSION2((version),(sp)))
 #define MPT_MSVC_BEFORE(version,sp)                  (MPT_COMPILER_MSVC_VERSION <  MPT_COMPILER_MAKE_VERSION2((version),(sp)))
 
-#if MPT_MSVC_BEFORE(2008,0)
-#error "MSVC version 2008 required"
+#if MPT_MSVC_BEFORE(2015,0)
+#error "MSVC version 2015 required"
 #endif
 
 #if defined(_PREFAST_)
@@ -89,7 +93,7 @@
 
 #else
 
-#error "Your compiler is unknown to openmpt and thus not supported. You might want to edit CompilerDetect.h und typedefs.h."
+#define MPT_COMPILER_GENERIC                         1
 
 #endif
 
@@ -121,23 +125,57 @@
 
 
 
+#if MPT_COMPILER_GENERIC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG
+
+#if (__cplusplus >= 201703)
+#define MPT_CXX 17
+#elif (__cplusplus >= 201402)
+#define MPT_CXX 14
+#else
+#define MPT_CXX 11
+#endif
+
+#elif MPT_COMPILER_MSVC
+
+#if MPT_MSVC_AT_LEAST(2017,0)
+#if (_MSVC_LANG >= 201402)
+#define MPT_CXX 14
+#else
+#define MPT_CXX 11
+#endif
+#else
+#define MPT_CXX 11
+#endif
+
+#else
+
+#define MPT_CXX 11
+
+#endif
+
+// MPT_CXX is stricter than just using __cplusplus directly.
+// We will only claim a language version as supported IFF all core language and
+// library fatures that we need are actually supported AND working correctly
+// (to our needs).
+
+#define MPT_CXX_AT_LEAST(version) (MPT_CXX >= (version))
+#define MPT_CXX_BEFORE(version)   (MPT_CXX <  (version))
+
+
+
 #if MPT_COMPILER_MSVC
 	#define MPT_PLATFORM_LITTLE_ENDIAN
 #elif MPT_COMPILER_GCC
-	#if MPT_GCC_AT_LEAST(4,6,0)
-		#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-			#define MPT_PLATFORM_BIG_ENDIAN
-		#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-			#define MPT_PLATFORM_LITTLE_ENDIAN
-		#endif
+	#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+		#define MPT_PLATFORM_BIG_ENDIAN
+	#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+		#define MPT_PLATFORM_LITTLE_ENDIAN
 	#endif
 #elif MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
-	#if MPT_CLANG_AT_LEAST(3,2,0)
-		#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-			#define MPT_PLATFORM_BIG_ENDIAN
-		#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-			#define MPT_PLATFORM_LITTLE_ENDIAN
-		#endif
+	#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+		#define MPT_PLATFORM_BIG_ENDIAN
+	#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+		#define MPT_PLATFORM_LITTLE_ENDIAN
 	#endif
 #endif
 
@@ -166,138 +204,46 @@
 		|| defined(__x86_64) || defined(__x86_64__) \
 		|| defined(_M_X64) || defined(__bfin__)
 			#define MPT_PLATFORM_LITTLE_ENDIAN
-	#else
-		#error "unknown endianness"
 	#endif
 #endif
 
-
-
-#if MPT_COMPILER_MSVC
-
-	#if defined(_M_X64)
-		#define MPT_ARCH_BITS 64
-		#define MPT_ARCH_BITS_32 0
-		#define MPT_ARCH_BITS_64 1
-	#elif defined(_M_IX86)
-		#define MPT_ARCH_BITS 32
-		#define MPT_ARCH_BITS_32 1
-		#define MPT_ARCH_BITS_64 0
-	#endif
-
-#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
-
-	#if defined(__SIZEOF_POINTER__)
-		#if (__SIZEOF_POINTER__ == 8)
-			#define MPT_ARCH_BITS 64
-			#define MPT_ARCH_BITS_32 0
-			#define MPT_ARCH_BITS_64 1
-		#elif (__SIZEOF_POINTER__ == 4)
-			#define MPT_ARCH_BITS 32
-			#define MPT_ARCH_BITS_32 1
-			#define MPT_ARCH_BITS_64 0
-		#endif
-	#endif
-
-#endif // MPT_COMPILER
+#if defined(MPT_PLATFORM_BIG_ENDIAN) || defined(MPT_PLATFORM_LITTLE_ENDIAN)
+#define MPT_PLATFORM_ENDIAN_KNOWN 1
+#else
+#define MPT_PLATFORM_ENDIAN_KNOWN 0
+#endif
 
 
 
-// Guess the supported C++ standard version
+// This should really be based on __STDCPP_THREADS__, but that is not defined by
+// GCC or clang. Stupid.
+// Just assume multithreaded and disable for platforms we know are
+// singlethreaded later on.
+#define MPT_PLATFORM_MULTITHREADED 1
 
-// This is only a rough estimate to facilitate conditional compilation
 
-#define MPT_CXX_98         199711L // STD
-#define MPT_CXX_03_TR1     200301L // custom
-#define MPT_CXX_11_PARTIAL 201100L // custom
-#define MPT_CXX_11_FULL    201103L // STD
-#define MPT_CXX_14_PARTIAL 201400L // custom
-#define MPT_CXX_14_FULL    201402L // STD
 
-#if MPT_COMPILER_GENERIC
-	#define MPT_CXX_VERSION __cplusplus
-#elif MPT_COMPILER_MSVCCLANGC2
-	#define MPT_CXX_VERSION MPT_CXX_14_PARTIAL
-#elif MPT_COMPILER_CLANG
-	#if MPT_CLANG_AT_LEAST(3,5,0)
-		#define MPT_CXX_VERSION MPT_CXX_11_FULL
-	#else
-		#define MPT_CXX_VERSION MPT_CXX_11_PARTIAL
-	#endif
-#elif MPT_COMPILER_GCC
-	#if MPT_GCC_AT_LEAST(4,9,0)
-		#define MPT_CXX_VERSION MPT_CXX_11_FULL
-	#elif MPT_GCC_AT_LEAST(4,3,0)
-		#define MPT_CXX_VERSION MPT_CXX_11_PARTIAL
-	#elif MPT_GCC_AT_LEAST(4,1,0)
-		#define MPT_CXX_VERSION MPT_CXX_03_TR1
-	#else
-		#define MPT_CXX_VERSION MPT_CXX_98
-	#endif
-#elif MPT_COMPILER_MSVC
-	#if MPT_MSVC_AT_LEAST(2010,0)
-		#define MPT_CXX_VERSION MPT_CXX_11_PARTIAL
-	#else
-		#define MPT_CXX_VERSION MPT_CXX_03_TR1
-	#endif
-#endif // MPT_COMPILER
+// specific C++ features
 
 
 
-// specific C++ features
+// C++11 constexpr
 
 #if MPT_COMPILER_MSVC
-#if MPT_MSVC_AT_LEAST(2010,0)
-#define MPT_COMPILER_HAS_RVALUE_REF 1
-#endif
-#elif MPT_COMPILER_GCC
-#if MPT_GCC_AT_LEAST(4,5,0)
-#define MPT_COMPILER_HAS_RVALUE_REF 1
-#endif
-#elif MPT_COMPILER_CLANG
-#if MPT_CLANG_AT_LEAST(3,0,0)
-#define MPT_COMPILER_HAS_RVALUE_REF 1
-#endif
-#elif MPT_COMPILER_MSVCCLANGC2
-#define MPT_COMPILER_HAS_RVALUE_REF 1
-#endif
-
-#ifndef MPT_COMPILER_HAS_RVALUE_REF
-#define MPT_COMPILER_HAS_RVALUE_REF 0
+#define MPT_COMPILER_QUIRK_CONSTEXPR_NO_STRING_LITERALS
 #endif
 
 
-// C++11 includes variadic macros.
-// C99 includes variadic macros.
 
-#if MPT_COMPILER_CLANG
-#if MPT_CLANG_AT_LEAST(3,0,0)
-#define MPT_COMPILER_HAS_VARIADIC_MACROS 1
-#endif
-#elif MPT_COMPILER_MSVCCLANGC2
-#define MPT_COMPILER_HAS_VARIADIC_MACROS 1
-#elif MPT_COMPILER_MSVC
-#if MPT_MSVC_AT_LEAST(2005,0)
-#define MPT_COMPILER_HAS_VARIADIC_MACROS 1
-#endif
-#elif MPT_COMPILER_GCC
-#if MPT_GCC_AT_LEAST(3,0,0)
-#define MPT_COMPILER_HAS_VARIADIC_MACROS 1
-#endif
-#endif
-
-#ifndef MPT_COMPILER_HAS_VARIADIC_MACROS
-#define MPT_COMPILER_HAS_VARIADIC_MACROS 0
+#if MPT_COMPILER_MSVC
+// Compiler has multiplication/division semantics when shifting signed integers.
+#define MPT_COMPILER_SHIFT_SIGNED 1
 #endif
 
-
-#if MPT_MSVC_AT_LEAST(2010,0) || MPT_CLANG_AT_LEAST(3,0,0) || MPT_GCC_AT_LEAST(4,5,0)
-#define MPT_COMPILER_HAS_TYPE_TRAITS 1
+#ifndef MPT_COMPILER_SHIFT_SIGNED
+#define MPT_COMPILER_SHIFT_SIGNED 0
 #endif
 
-#ifndef MPT_COMPILER_HAS_TYPE_TRAITS
-#define MPT_COMPILER_HAS_TYPE_TRAITS 0
-#endif
 
 
 #if MPT_COMPILER_GCC || MPT_COMPILER_MSVC
@@ -321,8 +267,29 @@
 // The order of the checks matters!
 #if defined(__EMSCRIPTEN__)
 	#define MPT_OS_EMSCRIPTEN 1
+	#if defined(__EMSCRIPTEN_major__) && defined(__EMSCRIPTEN_minor__)
+		#if (__EMSCRIPTEN_major__ > 1)
+			#define MPT_OS_EMSCRIPTEN_ANCIENT 0
+		#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ >= 36)
+			#define MPT_OS_EMSCRIPTEN_ANCIENT 0
+		#else
+			#define MPT_OS_EMSCRIPTEN_ANCIENT 1
+		#endif
+	#else
+		#define MPT_OS_EMSCRIPTEN_ANCIENT 1
+	#endif
 #elif defined(_WIN32)
 	#define MPT_OS_WINDOWS 1
+	#if defined(WINAPI_FAMILY)
+		#include <winapifamily.h>
+		#if (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
+			#define MPT_OS_WINDOWS_WINRT 0
+		#else
+			#define MPT_OS_WINDOWS_WINRT 1
+		#endif
+	#else // !WINAPI_FAMILY
+		#define MPT_OS_WINDOWS_WINRT 0
+	#endif // WINAPI_FAMILY
 #elif defined(__APPLE__)
 	#define MPT_OS_MACOSX_OR_IOS 1
 	//#include "TargetConditionals.h"
@@ -355,6 +322,9 @@
 #ifndef MPT_OS_WINDOWS
 #define MPT_OS_WINDOWS 0
 #endif
+#ifndef MPT_OS_WINDOWS_WINRT
+#define MPT_OS_WINDOWS_WINRT 0
+#endif
 #ifndef MPT_OS_MACOSX_OR_IOS
 #define MPT_OS_MACOSX_OR_IOS 0
 #endif
@@ -383,3 +353,13 @@
 #define MPT_OS_UNKNOWN 0
 #endif
 
+#ifndef MPT_OS_EMSCRIPTEN_ANCIENT
+#define MPT_OS_EMSCRIPTEN_ANCIENT 0
+#endif
+
+
+
+#if MPT_OS_EMSCRIPTEN
+#undef MPT_PLATFORM_MULTITHREADED
+#define MPT_PLATFORM_MULTITHREADED 0
+#endif
diff --git a/common/ComponentManager.cpp b/common/ComponentManager.cpp
index 2c77ed7..ebe158b 100644
--- a/common/ComponentManager.cpp
+++ b/common/ComponentManager.cpp
@@ -22,7 +22,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 ComponentBase::ComponentBase(ComponentType type)
-//----------------------------------------------
 	: m_Type(type)
 	, m_Initialized(false)
 	, m_Available(false)
@@ -32,56 +31,48 @@ ComponentBase::ComponentBase(ComponentType type)
 
 
 ComponentBase::~ComponentBase()
-//-----------------------------
 {
 	return;
 }
 
 
 void ComponentBase::SetInitialized()
-//----------------------------------
 {
 	m_Initialized = true;
 }
 
 
 void ComponentBase::SetAvailable()
-//--------------------------------
 {
 	m_Available = true;
 }
 
 
 ComponentType ComponentBase::GetType() const
-//------------------------------------------
 {
 	return m_Type;
 }
 
 
 bool ComponentBase::IsInitialized() const
-//---------------------------------------
 {
 	return m_Initialized;
 }
 
 
 bool ComponentBase::IsAvailable() const
-//-------------------------------------
 {
 	return m_Initialized && m_Available;
 }
 
 
 mpt::ustring ComponentBase::GetVersion() const
-//--------------------------------------------
 {
 	return mpt::ustring();
 }
 
 
 void ComponentBase::Initialize()
-//------------------------------
 {
 	if(IsInitialized())
 	{
@@ -99,7 +90,6 @@ void ComponentBase::Initialize()
 
 
 ComponentLibrary::ComponentLibrary(ComponentType type)
-//----------------------------------------------------
 	: ComponentBase(type)
 	, m_BindFailed(false)
 {
@@ -108,14 +98,12 @@ ComponentLibrary::ComponentLibrary(ComponentType type)
 
 
 ComponentLibrary::~ComponentLibrary()
-//-----------------------------------
 {
 	return;
 }
 
 
 bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath)
-//--------------------------------------------------------------------------------------------
 {
 	if(m_Libraries[libName].IsValid())
 	{
@@ -133,37 +121,32 @@ bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::Library
 
 
 void ComponentLibrary::ClearLibraries()
-//-------------------------------------
 {
 	m_Libraries.clear();
 }
 
 
 void ComponentLibrary::SetBindFailed()
-//------------------------------------
 {
 	m_BindFailed = true;
 }
 
 
 void ComponentLibrary::ClearBindFailed()
-//--------------------------------------
 {
 	m_BindFailed = false;
 }
 
 
 bool ComponentLibrary::HasBindFailed() const
-//------------------------------------------
 {
 	return m_BindFailed;
 }
 
 
 mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const
-//-------------------------------------------------------------------------
 {
-	TLibraryMap::const_iterator it = m_Libraries.find(libName);
+	const auto it = m_Libraries.find(libName);
 	if(it == m_Libraries.end())
 	{
 		return mpt::Library();
@@ -179,7 +162,6 @@ mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const
 
 
 ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::string &settingsKey)
-//-----------------------------------------------------------------------------------------------
 	: m_ID(id)
 	, m_SettingsKey(settingsKey)
 {
@@ -188,28 +170,24 @@ ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::str
 
 
 ComponentFactoryBase::~ComponentFactoryBase()
-//-------------------------------------------
 {
 	return;
 }
 
 
 std::string ComponentFactoryBase::GetID() const
-//---------------------------------------------
 {
 	return m_ID;
 }
 
 
 std::string ComponentFactoryBase::GetSettingsKey() const
-//------------------------------------------------------
 {
 	return m_SettingsKey;
 }
 
 
 void ComponentFactoryBase::PreConstruct() const
-//---------------------------------------------
 {
 	MPT_LOG(LogInformation, "Components", 
 		mpt::format(MPT_USTRING("Constructing Component %1"))
@@ -219,8 +197,7 @@ void ComponentFactoryBase::PreConstruct() const
 }
 
 
-void ComponentFactoryBase::Initialize(ComponentManager &componentManager, MPT_SHARED_PTR<IComponent> component) const
-//-------------------------------------------------------------------------------------------------------------------
+void ComponentFactoryBase::Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const
 {
 	if(componentManager.IsComponentBlocked(GetSettingsKey()))
 	{
@@ -243,21 +220,18 @@ void ComponentFactoryBase::Initialize(ComponentManager &componentManager, MPT_SH
 //  thus work fine for MSVC (currently).
 
 static mpt::mutex & ComponentListMutex()
-//---------------------------------------
 {
 	static mpt::mutex g_ComponentListMutex;
 	return g_ComponentListMutex;
 }
 
 static ComponentListEntry * & ComponentListHead()
-//-----------------------------------------------
 {
 	static ComponentListEntry *g_ComponentListHead = nullptr;
 	return g_ComponentListHead;
 }
 
 bool ComponentListPush(ComponentListEntry *entry)
-//-----------------------------------------------
 {
 	MPT_LOCK_GUARD<mpt::mutex> guard(ComponentListMutex());
 	entry->next = ComponentListHead();
@@ -266,35 +240,31 @@ bool ComponentListPush(ComponentListEntry *entry)
 }
 
 
-static MPT_SHARED_PTR<ComponentManager> g_ComponentManager;
+static std::shared_ptr<ComponentManager> g_ComponentManager;
 
 
 void ComponentManager::Init(const IComponentManagerSettings &settings)
-//--------------------------------------------------------------------
 {
 	MPT_LOG(LogInformation, "Components", MPT_USTRING("Init"));
 	// cannot use make_shared because the constructor is private
-	g_ComponentManager = MPT_SHARED_PTR<ComponentManager>(new ComponentManager(settings));
+	g_ComponentManager = std::shared_ptr<ComponentManager>(new ComponentManager(settings));
 }
 
 
 void ComponentManager::Release()
-//------------------------------
 {
 	MPT_LOG(LogInformation, "Components", MPT_USTRING("Release"));
-	g_ComponentManager = MPT_SHARED_PTR<ComponentManager>();
+	g_ComponentManager = nullptr;
 }
 
 
-MPT_SHARED_PTR<ComponentManager> ComponentManager::Instance()
-//-----------------------------------------------------------
+std::shared_ptr<ComponentManager> ComponentManager::Instance()
 {
 	return g_ComponentManager;
 }
 
 
 ComponentManager::ComponentManager(const IComponentManagerSettings &settings)
-//---------------------------------------------------------------------------
 	: m_Settings(settings)
 {
 	MPT_LOCK_GUARD<mpt::mutex> guard(ComponentListMutex());
@@ -306,7 +276,6 @@ ComponentManager::ComponentManager(const IComponentManagerSettings &settings)
 
 
 void ComponentManager::Register(const IComponentFactory &componentFactory)
-//------------------------------------------------------------------------
 {
 	if(m_Components.find(componentFactory.GetID()) != m_Components.end())
 	{
@@ -315,41 +284,40 @@ void ComponentManager::Register(const IComponentFactory &componentFactory)
 	RegisteredComponent registeredComponent;
 	registeredComponent.settingsKey = componentFactory.GetSettingsKey();
 	registeredComponent.factoryMethod = componentFactory.GetStaticConstructor();
-	registeredComponent.instance = MPT_SHARED_PTR<IComponent>();
+	registeredComponent.instance = nullptr;
+	registeredComponent.weakInstance = std::weak_ptr<IComponent>();
 	m_Components.insert(std::make_pair(componentFactory.GetID(), registeredComponent));
 }
 
 
 void ComponentManager::Startup()
-//------------------------------
 {
 	MPT_LOG(LogDebug, "Components", MPT_USTRING("Startup"));
 	if(m_Settings.LoadOnStartup())
 	{
-		for(TComponentMap::iterator it = m_Components.begin(); it != m_Components.end(); ++it)
+		for(auto &it : m_Components)
 		{
-			(*it).second.instance = (*it).second.factoryMethod(*this);
+			it.second.instance = it.second.factoryMethod(*this);
+			it.second.weakInstance = it.second.instance;
 		}
 	}
 	if(!m_Settings.KeepLoaded())
 	{
-		for(TComponentMap::iterator it = m_Components.begin(); it != m_Components.end(); ++it)
+		for(auto &it : m_Components)
 		{
-			(*it).second.instance = MPT_SHARED_PTR<IComponent>();
+			it.second.instance = nullptr;
 		}
 	}
 }
 
 
 bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const
-//-----------------------------------------------------------------------------
 {
 	return m_Settings.IsBlocked(settingsKey);
 }
 
 
-void ComponentManager::InitializeComponent(MPT_SHARED_PTR<IComponent> component) const
-//------------------------------------------------------------------------------------
+void ComponentManager::InitializeComponent(std::shared_ptr<IComponent> component) const
 {
 	if(!component)
 	{
@@ -363,11 +331,10 @@ void ComponentManager::InitializeComponent(MPT_SHARED_PTR<IComponent> component)
 }
 
 
-MPT_SHARED_PTR<IComponent> ComponentManager::GetComponent(const IComponentFactory &componentFactory)
-//--------------------------------------------------------------------------------------------------
+std::shared_ptr<const IComponent> ComponentManager::GetComponent(const IComponentFactory &componentFactory)
 {
-	MPT_SHARED_PTR<IComponent> component = MPT_SHARED_PTR<IComponent>();
-	TComponentMap::iterator it = m_Components.find(componentFactory.GetID());
+	std::shared_ptr<IComponent> component = nullptr;
+	auto it = m_Components.find(componentFactory.GetID());
 	if(it != m_Components.end())
 	{ // registered component
 		if((*it).second.instance)
@@ -375,11 +342,16 @@ MPT_SHARED_PTR<IComponent> ComponentManager::GetComponent(const IComponentFactor
 			component = (*it).second.instance;
 		} else
 		{ // not loaded
-			component = (*it).second.factoryMethod(*this);
+			component = (*it).second.weakInstance.lock();
+			if(!component)
+			{
+				component = (*it).second.factoryMethod(*this);
+			}
 			if(m_Settings.KeepLoaded())
 			{ // keep the component loaded
 				(*it).second.instance = component;
 			}
+			(*it).second.weakInstance = component;
 		}
 	} else
 	{ // unregistered component
@@ -390,16 +362,20 @@ MPT_SHARED_PTR<IComponent> ComponentManager::GetComponent(const IComponentFactor
 }
 
 
-MPT_SHARED_PTR<IComponent> ComponentManager::ReloadComponent(const IComponentFactory &componentFactory)
-//-----------------------------------------------------------------------------------------------------
+std::shared_ptr<const IComponent> ComponentManager::ReloadComponent(const IComponentFactory &componentFactory)
 {
-	MPT_SHARED_PTR<IComponent> component = MPT_SHARED_PTR<IComponent>();
-	TComponentMap::iterator it = m_Components.find(componentFactory.GetID());
+	std::shared_ptr<IComponent> component = nullptr;
+	auto it = m_Components.find(componentFactory.GetID());
 	if(it != m_Components.end())
 	{ // registered component
 		if((*it).second.instance)
 		{ // loaded
-			(*it).second.instance = MPT_SHARED_PTR<IComponent>();
+			(*it).second.instance = nullptr;
+			if(!(*it).second.weakInstance.expired())
+			{
+				throw std::runtime_error("Component not completely unloaded. Cannot reload.");
+			}
+			(*it).second.weakInstance = std::weak_ptr<IComponent>();
 		}
 		// not loaded
 		component = (*it).second.factoryMethod(*this);
@@ -407,6 +383,7 @@ MPT_SHARED_PTR<IComponent> ComponentManager::ReloadComponent(const IComponentFac
 		{ // keep the component loaded
 			(*it).second.instance = component;
 		}
+		(*it).second.weakInstance = component;
 	} else
 	{ // unregistered component
 		component = componentFactory.Construct(*this);
@@ -419,9 +396,10 @@ MPT_SHARED_PTR<IComponent> ComponentManager::ReloadComponent(const IComponentFac
 std::vector<std::string> ComponentManager::GetRegisteredComponents() const
 {
 	std::vector<std::string> result;
-	for(TComponentMap::const_iterator it = m_Components.begin(); it != m_Components.end(); ++it)
+	result.reserve(m_Components.size());
+	for(const auto &it : m_Components)
 	{
-		result.push_back((*it).first);
+		result.push_back(it.first);
 	}
 	return result;
 }
@@ -434,7 +412,7 @@ ComponentInfo ComponentManager::GetComponentInfo(std::string name) const
 	result.state = ComponentStateUnregistered;
 	result.settingsKey = "";
 	result.type = ComponentTypeUnknown;
-	TComponentMap::const_iterator it = m_Components.find(name);
+	const auto it = m_Components.find(name);
 	if(it == m_Components.end())
 	{
 		result.state = ComponentStateUnregistered;
@@ -446,7 +424,11 @@ ComponentInfo ComponentManager::GetComponentInfo(std::string name) const
 		result.state = ComponentStateBlocked;
 		return result;
 	}
-	MPT_SHARED_PTR<IComponent> component = ((*it).second.instance) ? it->second.instance : MPT_SHARED_PTR<IComponent>();
+	std::shared_ptr<IComponent> component = it->second.instance;
+	if(!component)
+	{
+		component = it->second.weakInstance.lock();
+	}
 	if(!component)
 	{
 		result.state = ComponentStateUnintialized;
@@ -468,6 +450,12 @@ ComponentInfo ComponentManager::GetComponentInfo(std::string name) const
 }
 
 
+mpt::PathString ComponentManager::GetComponentPath() const
+{
+	return m_Settings.Path();
+}
+
+
 #endif // MPT_COMPONENT_MANAGER
 
 
diff --git a/common/ComponentManager.h b/common/ComponentManager.h
index a99579f..2a2b799 100644
--- a/common/ComponentManager.h
+++ b/common/ComponentManager.h
@@ -13,6 +13,7 @@
 #include <map>
 #include <vector>
 #include "../common/misc_util.h"
+#include "../common/mptMutex.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
@@ -35,7 +36,7 @@ enum ComponentType
 {
 	ComponentTypeUnknown = 0,
 	ComponentTypeBuiltin,            // PortAudio
-	ComponentTypeSystem,             // uxtheme.dll, mf.dll
+	ComponentTypeSystem,             // mf.dll
 	ComponentTypeSystemInstallable,  // acm mp3 codec
 	ComponentTypeBundled,            // libsoundtouch
 	ComponentTypeForeign,            // libmp3lame
@@ -67,7 +68,7 @@ public:
 	virtual mpt::ustring GetVersion() const = 0;
 
 	virtual void Initialize() = 0;  // try to load the component
-	
+
 };
 
 
@@ -231,7 +232,7 @@ public:
 
 class ComponentManager;
 
-typedef MPT_SHARED_PTR<IComponent> (*ComponentFactoryMethod)(ComponentManager &componentManager);
+typedef std::shared_ptr<IComponent> (*ComponentFactoryMethod)(ComponentManager &componentManager);
 
 
 class IComponentFactory
@@ -243,7 +244,7 @@ public:
 public:
 	virtual std::string GetID() const = 0;
 	virtual std::string GetSettingsKey() const = 0;
-	virtual MPT_SHARED_PTR<IComponent> Construct(ComponentManager &componentManager) const = 0;
+	virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const = 0;
 	virtual ComponentFactoryMethod GetStaticConstructor() const = 0;
 };
 
@@ -257,12 +258,12 @@ private:
 protected:
 	ComponentFactoryBase(const std::string &id, const std::string &settingsKey);
 	void PreConstruct() const;
-	void Initialize(ComponentManager &componentManager, MPT_SHARED_PTR<IComponent> component) const;
+	void Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const;
 public:
 	virtual ~ComponentFactoryBase();
 	virtual std::string GetID() const;
 	virtual std::string GetSettingsKey() const;
-	virtual MPT_SHARED_PTR<IComponent> Construct(ComponentManager &componentManager) const = 0;
+	virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const = 0;
 	virtual ComponentFactoryMethod GetStaticConstructor() const = 0;
 };
 
@@ -282,14 +283,14 @@ public:
 		return;
 	}
 public:
-	virtual MPT_SHARED_PTR<IComponent> Construct(ComponentManager &componentManager) const
+	virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const
 	{
 		PreConstruct();
-		MPT_SHARED_PTR<IComponent> component = mpt::make_shared<T>();
+		std::shared_ptr<IComponent> component = std::make_shared<T>();
 		Initialize(componentManager, component);
 		return component;
 	}
-	static MPT_SHARED_PTR<IComponent> StaticConstruct(ComponentManager &componentManager)
+	static std::shared_ptr<IComponent> StaticConstruct(ComponentManager &componentManager)
 	{
 		return ComponentFactory().Construct(componentManager);
 	}
@@ -306,6 +307,7 @@ public:
 	virtual bool LoadOnStartup() const = 0;
 	virtual bool KeepLoaded() const = 0;
 	virtual bool IsBlocked(const std::string &key) const = 0;
+	virtual mpt::PathString Path() const = 0;
 };
 
 
@@ -316,6 +318,7 @@ public:
 	virtual bool LoadOnStartup() const { return false; }
 	virtual bool KeepLoaded() const { return true; }
 	virtual bool IsBlocked(const std::string & /*key*/ ) const { return false; }
+	virtual mpt::PathString Path() const { return mpt::PathString(); }
 };
 
 
@@ -344,7 +347,7 @@ class ComponentManager
 public:
 	static void Init(const IComponentManagerSettings &settings);
 	static void Release();
-	static MPT_SHARED_PTR<ComponentManager> Instance();
+	static std::shared_ptr<ComponentManager> Instance();
 private:
 	ComponentManager(const IComponentManagerSettings &settings);
 private:
@@ -352,21 +355,23 @@ private:
 	{
 		std::string settingsKey;
 		ComponentFactoryMethod factoryMethod;
-		MPT_SHARED_PTR<IComponent> instance;
+		std::shared_ptr<IComponent> instance;
+		std::weak_ptr<IComponent> weakInstance;
 	};
 	typedef std::map<std::string, RegisteredComponent> TComponentMap;
 	const IComponentManagerSettings &m_Settings;
 	TComponentMap m_Components;
 private:
 	bool IsComponentBlocked(const std::string &settingsKey) const;
-	void InitializeComponent(MPT_SHARED_PTR<IComponent> component) const;
+	void InitializeComponent(std::shared_ptr<IComponent> component) const;
 public:
 	void Register(const IComponentFactory &componentFactory);
 	void Startup();
-	MPT_SHARED_PTR<IComponent> GetComponent(const IComponentFactory &componentFactory);
-	MPT_SHARED_PTR<IComponent> ReloadComponent(const IComponentFactory &componentFactory);
+	std::shared_ptr<const IComponent> GetComponent(const IComponentFactory &componentFactory);
+	std::shared_ptr<const IComponent> ReloadComponent(const IComponentFactory &componentFactory);
 	std::vector<std::string> GetRegisteredComponents() const;
 	ComponentInfo GetComponentInfo(std::string name) const;
+	mpt::PathString GetComponentPath() const;
 };
 
 
@@ -386,23 +391,29 @@ bool ComponentListPush(ComponentListEntry *entry);
 		componentManager.Register(ComponentFactory< name >()); \
 	} \
 	static ComponentListEntry Component ## name ## ListEntry = { nullptr, & RegisterComponent ## name }; \
-	static bool Component ## name ## Registered = ComponentListPush(& Component ## name ## ListEntry ); \
+	bool Component ## name ## Registered = ComponentListPush(& Component ## name ## ListEntry ); \
 	const char * const name :: g_ID = #name ; \
 	const char * const name :: g_SettingsKey = settingsKey ; \
 /**/
 
 
 template <typename type>
-MPT_SHARED_PTR<type> GetComponent()
+std::shared_ptr<const type> GetComponent()
 {
-	return MPT_DYNAMIC_POINTER_CAST<type>(ComponentManager::Instance()->GetComponent(ComponentFactory<type>()));
+	return std::dynamic_pointer_cast<const type>(ComponentManager::Instance()->GetComponent(ComponentFactory<type>()));
 }
 
 
 template <typename type>
-MPT_SHARED_PTR<type> ReloadComponent()
+std::shared_ptr<const type> ReloadComponent()
+{
+	return std::dynamic_pointer_cast<const type>(ComponentManager::Instance()->ReloadComponent(ComponentFactory<type>()));
+}
+
+
+static inline mpt::PathString GetComponentPath()
 {
-	return MPT_DYNAMIC_POINTER_CAST<type>(ComponentManager::Instance()->ReloadComponent(ComponentFactory<type>()));
+	return ComponentManager::Instance()->GetComponentPath();
 }
 
 
@@ -415,28 +426,38 @@ MPT_SHARED_PTR<type> ReloadComponent()
 
 
 template <typename type>
-MPT_SHARED_PTR<type> GetComponent()
+std::shared_ptr<const type> GetComponent()
 {
-	MPT_SHARED_PTR<type> component = mpt::make_shared<type>();
+	static std::weak_ptr<type> cache;
+	static mpt::mutex m;
+	MPT_LOCK_GUARD<mpt::mutex> l(m);
+	std::shared_ptr<type> component = cache.lock();
 	if(!component)
 	{
-		return component;
+		component = std::make_shared<type>();
+		component->Initialize();
+		cache = component;
 	}
-	component->Initialize();
 	return component;
 }
 
 
+static inline mpt::PathString GetComponentPath()
+{
+	return mpt::PathString();
+}
+
+
 #endif // MPT_COMPONENT_MANAGER
 
 
-// Simple wrapper around MPT_SHARED_PTR<ComponentType> which automatically
+// Simple wrapper around std::shared_ptr<ComponentType> which automatically
 // gets a reference to the component (or constructs it) on initialization.
 template <typename T>
 class ComponentHandle
 {
 private:
-	MPT_SHARED_PTR<T> component;
+	std::shared_ptr<const T> component;
 public:
 	ComponentHandle()
 		: component(GetComponent<T>())
@@ -451,18 +472,25 @@ public:
 	{
 		return component && component->IsAvailable();
 	}
-	T *get() const
+	const T *get() const
 	{
 		return component.get();
 	}
-	T &operator*() const
+	const T &operator*() const
 	{
 		return *component;
 	}
-	T *operator->() const
+	const T *operator->() const
 	{
 		return &*component;
 	}
+#if MPT_COMPONENT_MANAGER
+	void Reload()
+	{
+		component = nullptr;
+		component = ReloadComponent<T>();
+	}
+#endif
 };
 
 
diff --git a/common/Endianness.h b/common/Endianness.h
index 10c0a26..52ef2df 100644
--- a/common/Endianness.h
+++ b/common/Endianness.h
@@ -2,7 +2,7 @@
  * Endianness.h
  * ------------
  * Purpose: Code for deadling with endianness.
- * Notes  : VC++ didn't like my compile-time endianness check - or rather, it didn't decide at compile time. ;_;
+ * Notes  : (currently none)
  * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  */
@@ -10,30 +10,133 @@
 
 #pragma once
 
-#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+#include <math.h>
+#include <stdlib.h>
 #if MPT_COMPILER_MSVC
 #include <intrin.h>
 #endif
 
+
+
+// Platform has native IEEE floating point representation _AND_ floating point
+// endianess is the same as integer endianness.
+// We just test __STDC_IEC_559__ for now.
+#if MPT_COMPILER_GENERIC
+	#define MPT_PLATFORM_IEEE_FLOAT 0
+#elif MPT_COMPILER_MSVC
+	#define MPT_PLATFORM_IEEE_FLOAT 1
+#else // MPT_COMPILER
+	#if MPT_PLATFORM_ENDIAN_KNOWN
+		#if defined(__STDC_IEC_559__)
+			#if (__STDC_IEC_559__)
+				#define MPT_PLATFORM_IEEE_FLOAT 1
+			#else
+				#define MPT_PLATFORM_IEEE_FLOAT 0
+			#endif
+		#else
+			#define MPT_PLATFORM_IEEE_FLOAT 0
+		#endif
+	#else
+		#define MPT_PLATFORM_IEEE_FLOAT 0
+	#endif
+#endif // MPT_COMPILER
+
+#if !MPT_PLATFORM_IEEE_FLOAT
+#include <array>
+#endif
+
+
+
 OPENMPT_NAMESPACE_BEGIN
 
+
+namespace mpt {
+
+struct endian_type { uint16 value; };
+static MPT_FORCEINLINE bool operator == (const endian_type & a, const endian_type & b) { return a.value == b.value; }
+static MPT_FORCEINLINE bool operator != (const endian_type & a, const endian_type & b) { return a.value != b.value; }
+
+static const endian_type endian_big    = { 0x1234u };
+static const endian_type endian_little = { 0x3412u };
+
+namespace detail {
+	static MPT_FORCEINLINE endian_type endian_probe()
+	{
+		STATIC_ASSERT(sizeof(endian_type) == 2);
+		const mpt::byte probe[2] = { 0x12, 0x34 };
+		endian_type test;
+		std::memcpy(&test, probe, 2);
+		return test;
+	}
+}
+
+static MPT_FORCEINLINE endian_type endian()
+{
+	#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
+		return endian_little;
+	#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+		return endian_big;
+	#else
+		return detail::endian_probe();
+	#endif
+}
+
+static MPT_FORCEINLINE bool endian_is_little()
+{
+	return endian() == endian_little;
+}
+
+static MPT_FORCEINLINE bool endian_is_big()
+{
+	return endian() == endian_big;
+}
+
+} // namespace mpt
+
+
+
+namespace mpt { namespace detail {
+enum Endianness
+{
+	BigEndian,
+	LittleEndian,
+#if MPT_PLATFORM_ENDIAN_KNOWN
+#if defined(MPT_PLATFORM_BIG_ENDIAN)
+	NativeEndian = BigEndian,
+#else
+	NativeEndian = LittleEndian,
+#endif
+#endif
+};
+} } // namespace mpt::detail
+
+struct BigEndian_tag
+{
+	static const mpt::detail::Endianness Endianness = mpt::detail::BigEndian;
+};
+
+struct LittleEndian_tag
+{
+	static const mpt::detail::Endianness Endianness = mpt::detail::LittleEndian;
+};
+
+
+
 // Ending swaps:
-// BigEndian(x) may be used either to:
-// -Convert DWORD x, which is in big endian format(for example read from file),
+// SwapBytesBE(x) and variants may be used either to:
+// -Convert integer x, which is in big endian format (for example read from file),
 //		to endian format of current architecture.
 // -Convert value x from endian format of current architecture to big endian format.
-// Similarly LittleEndian(x) converts known little endian format to format of current
-// endian architecture or value x in format of current architecture to little endian 
+// Similarly SwapBytesLE(x) converts known little endian format to format of current
+// endian architecture or value x in format of current architecture to little endian
 // format.
 
 #if MPT_COMPILER_GCC
-#if MPT_GCC_AT_LEAST(4,8,0)
 #define MPT_bswap16 __builtin_bswap16
-#endif
-#if MPT_GCC_AT_LEAST(4,3,0)
 #define MPT_bswap32 __builtin_bswap32
 #define MPT_bswap64 __builtin_bswap64
-#endif
 #elif MPT_COMPILER_MSVC
 #define MPT_bswap16 _byteswap_ushort
 #define MPT_bswap32 _byteswap_ulong
@@ -44,19 +147,19 @@ namespace mpt { namespace detail {
 // catch system macros
 #ifndef MPT_bswap16
 #ifdef bswap16
-static forceinline uint16 mpt_bswap16(uint16 x) { return bswap16(x); }
+static MPT_FORCEINLINE uint16 mpt_bswap16(uint16 x) { return bswap16(x); }
 #define MPT_bswap16 mpt::detail::mpt_bswap16
 #endif
 #endif
 #ifndef MPT_bswap32
 #ifdef bswap32
-static forceinline uint32 mpt_bswap32(uint32 x) { return bswap32(x); }
+static MPT_FORCEINLINE uint32 mpt_bswap32(uint32 x) { return bswap32(x); }
 #define MPT_bswap32 mpt::detail::mpt_bswap32
 #endif
 #endif
 #ifndef MPT_bswap64
 #ifdef bswap64
-static forceinline uint64 mpt_bswap64(uint64 x) { return bswap64(x); }
+static MPT_FORCEINLINE uint64 mpt_bswap64(uint64 x) { return bswap64(x); }
 #define MPT_bswap64 mpt::detail::mpt_bswap64
 #endif
 #endif
@@ -85,85 +188,149 @@ static forceinline uint64 mpt_bswap64(uint64 x) { return bswap64(x); }
 #ifndef MPT_bswap64
 #define MPT_bswap64(x) \
 	( uint64(0) \
-		| (((static_cast<uint64>(x) >>  0) & 0xffu) << 56) \
-		| (((static_cast<uint64>(x) >>  8) & 0xffu) << 48) \
-		| (((static_cast<uint64>(x) >> 16) & 0xffu) << 40) \
-		| (((static_cast<uint64>(x) >> 24) & 0xffu) << 32) \
-		| (((static_cast<uint64>(x) >> 32) & 0xffu) << 24) \
-		| (((static_cast<uint64>(x) >> 40) & 0xffu) << 16) \
-		| (((static_cast<uint64>(x) >> 48) & 0xffu) <<  8) \
-		| (((static_cast<uint64>(x) >> 56) & 0xffu) <<  0) \
+		| (((static_cast<uint64>(x) >>  0) & 0xffull) << 56) \
+		| (((static_cast<uint64>(x) >>  8) & 0xffull) << 48) \
+		| (((static_cast<uint64>(x) >> 16) & 0xffull) << 40) \
+		| (((static_cast<uint64>(x) >> 24) & 0xffull) << 32) \
+		| (((static_cast<uint64>(x) >> 32) & 0xffull) << 24) \
+		| (((static_cast<uint64>(x) >> 40) & 0xffull) << 16) \
+		| (((static_cast<uint64>(x) >> 48) & 0xffull) <<  8) \
+		| (((static_cast<uint64>(x) >> 56) & 0xffull) <<  0) \
 	) \
 /**/
 #endif
 
 
-// Deprecated. Use "SwapBytesXX" versions below.
-#ifdef MPT_PLATFORM_BIG_ENDIAN
-inline uint32 LittleEndian(uint32 x)	{ return MPT_bswap32(x); }
-inline uint16 LittleEndianW(uint16 x)	{ return MPT_bswap16(x); }
-#define BigEndian(x)					(x)
-#define BigEndianW(x)					(x)
-#else
-inline uint32 BigEndian(uint32 x)	{ return MPT_bswap32(x); }
-inline uint16 BigEndianW(uint16 x)	{ return MPT_bswap16(x); }
-#define LittleEndian(x)				(x)
-#define LittleEndianW(x)			(x)
-#endif
+#if MPT_PLATFORM_ENDIAN_KNOWN
 
 #if defined(MPT_PLATFORM_BIG_ENDIAN)
+
 #define MPT_bswap64le(x) MPT_bswap64(x)
 #define MPT_bswap32le(x) MPT_bswap32(x)
 #define MPT_bswap16le(x) MPT_bswap16(x)
 #define MPT_bswap64be(x) (x)
 #define MPT_bswap32be(x) (x)
 #define MPT_bswap16be(x) (x)
+
 #elif defined(MPT_PLATFORM_LITTLE_ENDIAN)
+
 #define MPT_bswap64be(x) MPT_bswap64(x)
 #define MPT_bswap32be(x) MPT_bswap32(x)
 #define MPT_bswap16be(x) MPT_bswap16(x)
 #define MPT_bswap64le(x) (x)
 #define MPT_bswap32le(x) (x)
 #define MPT_bswap16le(x) (x)
+
 #endif
 
-inline uint64 SwapBytesBE_(uint64 value) { return MPT_bswap64be(value); }
-inline uint32 SwapBytesBE_(uint32 value) { return MPT_bswap32be(value); }
-inline uint16 SwapBytesBE_(uint16 value) { return MPT_bswap16be(value); }
-inline uint64 SwapBytesLE_(uint64 value) { return MPT_bswap64le(value); }
-inline uint32 SwapBytesLE_(uint32 value) { return MPT_bswap32le(value); }
-inline uint16 SwapBytesLE_(uint16 value) { return MPT_bswap16le(value); }
-inline int64  SwapBytesBE_(int64  value) { return MPT_bswap64be(value); }
-inline int32  SwapBytesBE_(int32  value) { return MPT_bswap32be(value); }
-inline int16  SwapBytesBE_(int16  value) { return MPT_bswap16be(value); }
-inline int64  SwapBytesLE_(int64  value) { return MPT_bswap64le(value); }
-inline int32  SwapBytesLE_(int32  value) { return MPT_bswap32le(value); }
-inline int16  SwapBytesLE_(int16  value) { return MPT_bswap16le(value); }
+#else // !MPT_PLATFORM_ENDIAN_KNOWN
+
+template <typename T, typename Tendian, std::size_t size>
+static MPT_FORCEINLINE std::array<mpt::byte, size> EndianEncode(T val)
+{
+	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
+	STATIC_ASSERT(sizeof(T) == size);
+	typedef T base_type;
+	typedef typename std::make_unsigned<base_type>::type unsigned_base_type;
+	typedef Tendian endian_type;
+	unsigned_base_type uval = static_cast<unsigned_base_type>(val);
+	std::array<mpt::byte, size> data;
+	MPT_CONSTANT_IF(endian_type::Endianness == mpt::detail::LittleEndian)
+	{
+		for(std::size_t i = 0; i < sizeof(base_type); ++i)
+		{
+			data[i] = static_cast<mpt::byte>(static_cast<uint8>((uval >> (i*8)) & 0xffu));
+		}
+	} else
+	{
+		for(std::size_t i = 0; i < sizeof(base_type); ++i)
+		{
+			data[(sizeof(base_type)-1) - i] = static_cast<mpt::byte>(static_cast<uint8>((uval >> (i*8)) & 0xffu));
+		}
+	}
+	return data;
+}
+
+template <typename T, typename Tendian, std::size_t size>
+static MPT_FORCEINLINE T EndianDecode(std::array<mpt::byte, size> data)
+{
+	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
+	STATIC_ASSERT(sizeof(T) == size);
+	typedef T base_type;
+	typedef typename std::make_unsigned<base_type>::type unsigned_base_type;
+	typedef Tendian endian_type;
+	base_type val = base_type();
+	unsigned_base_type uval = unsigned_base_type();
+	MPT_CONSTANT_IF(endian_type::Endianness == mpt::detail::LittleEndian)
+	{
+		for(std::size_t i = 0; i < sizeof(base_type); ++i)
+		{
+			uval |= static_cast<unsigned_base_type>(static_cast<uint8>(data[i])) << (i*8);
+		}
+	} else
+	{
+		for(std::size_t i = 0; i < sizeof(base_type); ++i)
+		{
+			uval |= static_cast<unsigned_base_type>(static_cast<uint8>(data[(sizeof(base_type)-1) - i])) << (i*8);
+		}
+	}
+	val = static_cast<base_type>(uval);
+	return val;
+}
+
+template <typename Tendian, typename T>
+static MPT_FORCEINLINE T MPT_bswap_impl(T val)
+{
+	typedef typename std::make_unsigned<T>::type Tu;
+	std::array<mpt::byte, sizeof(T)> data = EndianEncode<Tu, Tendian, sizeof(T)>(val);
+	std::memcpy(&val, data.data(), sizeof(T));
+	return val;
+}
+
+#define MPT_bswap64be(x) MPT_bswap_impl<BigEndian_tag, uint64>(x)
+#define MPT_bswap32be(x) MPT_bswap_impl<BigEndian_tag, uint32>(x)
+#define MPT_bswap16be(x) MPT_bswap_impl<BigEndian_tag, uint16>(x)
+#define MPT_bswap64le(x) MPT_bswap_impl<LittleEndian_tag, uint64>(x)
+#define MPT_bswap32le(x) MPT_bswap_impl<LittleEndian_tag, uint32>(x)
+#define MPT_bswap16le(x) MPT_bswap_impl<LittleEndian_tag, uint16>(x)
+
+#endif // MPT_PLATFORM_ENDIAN_KNOWN
+
+static MPT_FORCEINLINE uint64 SwapBytesBE(uint64 value) { return MPT_bswap64be(value); }
+static MPT_FORCEINLINE uint32 SwapBytesBE(uint32 value) { return MPT_bswap32be(value); }
+static MPT_FORCEINLINE uint16 SwapBytesBE(uint16 value) { return MPT_bswap16be(value); }
+static MPT_FORCEINLINE uint64 SwapBytesLE(uint64 value) { return MPT_bswap64le(value); }
+static MPT_FORCEINLINE uint32 SwapBytesLE(uint32 value) { return MPT_bswap32le(value); }
+static MPT_FORCEINLINE uint16 SwapBytesLE(uint16 value) { return MPT_bswap16le(value); }
+static MPT_FORCEINLINE int64  SwapBytesBE(int64  value) { return MPT_bswap64be(value); }
+static MPT_FORCEINLINE int32  SwapBytesBE(int32  value) { return MPT_bswap32be(value); }
+static MPT_FORCEINLINE int16  SwapBytesBE(int16  value) { return MPT_bswap16be(value); }
+static MPT_FORCEINLINE int64  SwapBytesLE(int64  value) { return MPT_bswap64le(value); }
+static MPT_FORCEINLINE int32  SwapBytesLE(int32  value) { return MPT_bswap32le(value); }
+static MPT_FORCEINLINE int16  SwapBytesLE(int16  value) { return MPT_bswap16le(value); }
 
 // Do NOT remove these overloads, even if they seem useless.
 // We do not want risking to extend 8bit integers to int and then
 // endian-converting and casting back to int.
 // Thus these overloads.
-inline uint8  SwapBytesLE_(uint8  value) { return value; }
-inline int8   SwapBytesLE_(int8   value) { return value; }
-inline char   SwapBytesLE_(char   value) { return value; }
-inline uint8  SwapBytesBE_(uint8  value) { return value; }
-inline int8   SwapBytesBE_(int8   value) { return value; }
-inline char   SwapBytesBE_(char   value) { return value; }
-
-// SwapBytesLE/SwapBytesBE is mostly used throughout the code with in-place
-// argument-modifying semantics.
-// As GCC will (rightfully) not bind references to members of packed
-// structures, we implement reference semantics by explicitly assigning to a
-// macro argument.
-
-// In-place modifying version:
-#define SwapBytesBE(value) MPT_DO { (value) = SwapBytesBE_((value)); } MPT_WHILE_0
-#define SwapBytesLE(value) MPT_DO { (value) = SwapBytesLE_((value)); } MPT_WHILE_0
-
-// Alternative, function-style syntax:
-#define SwapBytesReturnBE(value) SwapBytesBE_((value))
-#define SwapBytesReturnLE(value) SwapBytesLE_((value))
+static MPT_FORCEINLINE uint8  SwapBytesLE(uint8  value) { return value; }
+static MPT_FORCEINLINE int8   SwapBytesLE(int8   value) { return value; }
+static MPT_FORCEINLINE char   SwapBytesLE(char   value) { return value; }
+static MPT_FORCEINLINE uint8  SwapBytesBE(uint8  value) { return value; }
+static MPT_FORCEINLINE int8   SwapBytesBE(int8   value) { return value; }
+static MPT_FORCEINLINE char   SwapBytesBE(char   value) { return value; }
+
+static MPT_FORCEINLINE uint64 SwapBytes(uint64 value) { return MPT_bswap64(value); }
+static MPT_FORCEINLINE uint32 SwapBytes(uint32 value) { return MPT_bswap32(value); }
+static MPT_FORCEINLINE uint16 SwapBytes(uint16 value) { return MPT_bswap16(value); }
+static MPT_FORCEINLINE int64  SwapBytes(int64  value) { return MPT_bswap64(value); }
+static MPT_FORCEINLINE int32  SwapBytes(int32  value) { return MPT_bswap32(value); }
+static MPT_FORCEINLINE int16  SwapBytes(int16  value) { return MPT_bswap16(value); }
+static MPT_FORCEINLINE uint8  SwapBytes(uint8  value) { return value; }
+static MPT_FORCEINLINE int8   SwapBytes(int8   value) { return value; }
+static MPT_FORCEINLINE char   SwapBytes(char   value) { return value; }
 
 #undef MPT_bswap16le
 #undef MPT_bswap32le
@@ -177,7 +344,7 @@ inline char   SwapBytesBE_(char   value) { return value; }
 
 
 // 1.0f --> 0x3f800000u
-static forceinline uint32 EncodeIEEE754binary32(float32 f)
+static MPT_FORCEINLINE uint32 EncodeIEEE754binary32(float32 f)
 {
 #if MPT_PLATFORM_IEEE_FLOAT
 	STATIC_ASSERT(sizeof(uint32) == sizeof(float32));
@@ -194,10 +361,32 @@ static forceinline uint32 EncodeIEEE754binary32(float32 f)
 		return i;
 	#endif
 #else
-	#error "IEEE754 single precision float support is required (for now)"
+	int e = 0;
+	float m = std::frexp(f, &e);
+	if(e == 0 && std::fabs(m) == 0.0f)
+	{
+		uint32 expo = 0u;
+		uint32 sign = std::signbit(m) ? 0x01u : 0x00u;
+		uint32 mant = 0u;
+		uint32 i = 0u;
+		i |= (mant <<  0) & 0x007fffffu;
+		i |= (expo << 23) & 0x7f800000u;
+		i |= (sign << 31) & 0x80000000u;
+		return i;
+	} else
+	{
+		uint32 expo = e + 127 - 1;
+		uint32 sign = std::signbit(m) ? 0x01u : 0x00u;
+		uint32 mant = static_cast<uint32>(std::fabs(std::ldexp(m, 24)));
+		uint32 i = 0u;
+		i |= (mant <<  0) & 0x007fffffu;
+		i |= (expo << 23) & 0x7f800000u;
+		i |= (sign << 31) & 0x80000000u;
+		return i;
+	}
 #endif
 }
-static forceinline uint64 EncodeIEEE754binary64(float64 f)
+static MPT_FORCEINLINE uint64 EncodeIEEE754binary64(float64 f)
 {
 #if MPT_PLATFORM_IEEE_FLOAT
 	STATIC_ASSERT(sizeof(uint64) == sizeof(float64));
@@ -214,12 +403,34 @@ static forceinline uint64 EncodeIEEE754binary64(float64 f)
 		return i;
 	#endif
 #else
-	#error "IEEE754 double precision float support is required (for now)"
+	int e = 0;
+	double m = std::frexp(f, &e);
+	if(e == 0 && std::fabs(m) == 0.0)
+	{
+		uint64 expo = 0u;
+		uint64 sign = std::signbit(m) ? 0x01u : 0x00u;
+		uint64 mant = 0u;
+		uint64 i = 0u;
+		i |= (mant <<  0) & 0x000fffffffffffffull;
+		i |= (expo << 52) & 0x7ff0000000000000ull;
+		i |= (sign << 63) & 0x8000000000000000ull;
+		return i;
+	} else
+	{
+		uint64 expo = e + 1023 - 1;
+		uint64 sign = std::signbit(m) ? 0x01u : 0x00u;
+		uint64 mant = static_cast<uint64>(std::fabs(std::ldexp(m, 53)));
+		uint64 i = 0u;
+		i |= (mant <<  0) & 0x000fffffffffffffull;
+		i |= (expo << 52) & 0x7ff0000000000000ull;
+		i |= (sign << 63) & 0x8000000000000000ull;
+		return i;
+	}
 #endif
 }
 
 // 0x3f800000u --> 1.0f
-static forceinline float32 DecodeIEEE754binary32(uint32 i)
+static MPT_FORCEINLINE float32 DecodeIEEE754binary32(uint32 i)
 {
 #if MPT_PLATFORM_IEEE_FLOAT
 	STATIC_ASSERT(sizeof(uint32) == sizeof(float32));
@@ -236,10 +447,26 @@ static forceinline float32 DecodeIEEE754binary32(uint32 i)
 		return f;
 	#endif
 #else
-	#error "IEEE754 single precision float support is required (for now)"
+	uint32 mant = (i & 0x007fffffu) >>  0;
+	uint32 expo = (i & 0x7f800000u) >> 23;
+	uint32 sign = (i & 0x80000000u) >> 31;
+	if(expo == 0)
+	{
+		float m = sign ? -static_cast<float>(mant) : static_cast<float>(mant);
+		int e = expo - 127 + 1 - 24;
+		float f = std::ldexp(m, e);
+		return static_cast<float32>(f);
+	} else
+	{
+		mant |= 0x00800000u;
+		float m = sign ? -static_cast<float>(mant) : static_cast<float>(mant);
+		int e = expo - 127 + 1 - 24;
+		float f = std::ldexp(m, e);
+		return static_cast<float32>(f);
+	}
 #endif
 }
-static forceinline float64 DecodeIEEE754binary64(uint64 i)
+static MPT_FORCEINLINE float64 DecodeIEEE754binary64(uint64 i)
 {
 #if MPT_PLATFORM_IEEE_FLOAT
 	STATIC_ASSERT(sizeof(uint64) == sizeof(float64));
@@ -256,7 +483,23 @@ static forceinline float64 DecodeIEEE754binary64(uint64 i)
 		return f;
 	#endif
 #else
-	#error "IEEE754 double precision float support is required (for now)"
+	uint64 mant = (i & 0x000fffffffffffffull) >>  0;
+	uint64 expo = (i & 0x7ff0000000000000ull) >> 52;
+	uint64 sign = (i & 0x8000000000000000ull) >> 63;
+	if(expo == 0)
+	{
+		double m = sign ? -static_cast<double>(mant) : static_cast<double>(mant);
+		int e = expo - 1023 + 1 - 53;
+		double f = std::ldexp(m, e);
+		return static_cast<float64>(f);
+	} else
+	{
+		mant |= 0x0010000000000000ull;
+		double m = sign ? -static_cast<double>(mant) : static_cast<double>(mant);
+		int e = expo - 1023 + 1 - 53;
+		double f = std::ldexp(m, e);
+		return static_cast<float64>(f);
+	}
 #endif
 }
 
@@ -269,30 +512,30 @@ private:
 	typedef IEEE754binary32Emulated<hihi,hilo,lohi,lolo> self_t;
 	mpt::byte bytes[4];
 public:
-	forceinline mpt::byte GetByte(std::size_t i) const
+	MPT_FORCEINLINE mpt::byte GetByte(std::size_t i) const
 	{
 		return bytes[i];
 	}
-	forceinline IEEE754binary32Emulated() { }
-	forceinline explicit IEEE754binary32Emulated(float32 f)
+	MPT_FORCEINLINE IEEE754binary32Emulated() { }
+	MPT_FORCEINLINE explicit IEEE754binary32Emulated(float32 f)
 	{
 		SetInt32(EncodeIEEE754binary32(f));
 	}
 	// b0...b3 are in memory order, i.e. depend on the endianness of this type
 	// little endian: (0x00,0x00,0x80,0x3f)
 	// big endian:    (0x3f,0x80,0x00,0x00)
-	forceinline explicit IEEE754binary32Emulated(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3)
+	MPT_FORCEINLINE explicit IEEE754binary32Emulated(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3)
 	{
 		bytes[0] = b0;
 		bytes[1] = b1;
 		bytes[2] = b2;
 		bytes[3] = b3;
 	}
-	forceinline operator float32 () const
+	MPT_FORCEINLINE operator float32 () const
 	{
 		return DecodeIEEE754binary32(GetInt32());
 	}
-	forceinline self_t & SetInt32(uint32 i)
+	MPT_FORCEINLINE self_t & SetInt32(uint32 i)
 	{
 		bytes[hihi] = static_cast<mpt::byte>(i >> 24);
 		bytes[hilo] = static_cast<mpt::byte>(i >> 16);
@@ -300,7 +543,7 @@ public:
 		bytes[lolo] = static_cast<mpt::byte>(i >>  0);
 		return *this;
 	}
-	forceinline uint32 GetInt32() const
+	MPT_FORCEINLINE uint32 GetInt32() const
 	{
 		return 0u
 			| (static_cast<uint32>(bytes[hihi]) << 24)
@@ -309,7 +552,7 @@ public:
 			| (static_cast<uint32>(bytes[lolo]) <<  0)
 			;
 	}
-	forceinline bool operator == (const self_t &cmp) const
+	MPT_FORCEINLINE bool operator == (const self_t &cmp) const
 	{
 		return true
 			&& bytes[0] == cmp.bytes[0]
@@ -318,7 +561,7 @@ public:
 			&& bytes[3] == cmp.bytes[3]
 			;
 	}
-	forceinline bool operator != (const self_t &cmp) const
+	MPT_FORCEINLINE bool operator != (const self_t &cmp) const
 	{
 		return !(*this == cmp);
 	}
@@ -330,16 +573,16 @@ private:
 	typedef IEEE754binary64Emulated<hihihi,hihilo,hilohi,hilolo,lohihi,lohilo,lolohi,lololo> self_t;
 	mpt::byte bytes[8];
 public:
-	forceinline mpt::byte GetByte(std::size_t i) const
+	MPT_FORCEINLINE mpt::byte GetByte(std::size_t i) const
 	{
 		return bytes[i];
 	}
-	forceinline IEEE754binary64Emulated() { }
-	forceinline explicit IEEE754binary64Emulated(float64 f)
+	MPT_FORCEINLINE IEEE754binary64Emulated() { }
+	MPT_FORCEINLINE explicit IEEE754binary64Emulated(float64 f)
 	{
 		SetInt64(EncodeIEEE754binary64(f));
 	}
-	forceinline explicit IEEE754binary64Emulated(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3, mpt::byte b4, mpt::byte b5, mpt::byte b6, mpt::byte b7)
+	MPT_FORCEINLINE explicit IEEE754binary64Emulated(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3, mpt::byte b4, mpt::byte b5, mpt::byte b6, mpt::byte b7)
 	{
 		bytes[0] = b0;
 		bytes[1] = b1;
@@ -350,11 +593,11 @@ public:
 		bytes[6] = b6;
 		bytes[7] = b7;
 	}
-	forceinline operator float64 () const
+	MPT_FORCEINLINE operator float64 () const
 	{
 		return DecodeIEEE754binary64(GetInt64());
 	}
-	forceinline self_t & SetInt64(uint64 i)
+	MPT_FORCEINLINE self_t & SetInt64(uint64 i)
 	{
 		bytes[hihihi] = static_cast<mpt::byte>(i >> 56);
 		bytes[hihilo] = static_cast<mpt::byte>(i >> 48);
@@ -366,7 +609,7 @@ public:
 		bytes[lololo] = static_cast<mpt::byte>(i >>  0);
 		return *this;
 	}
-	forceinline uint64 GetInt64() const
+	MPT_FORCEINLINE uint64 GetInt64() const
 	{
 		return 0u
 			| (static_cast<uint64>(bytes[hihihi]) << 56)
@@ -379,7 +622,7 @@ public:
 			| (static_cast<uint64>(bytes[lololo]) <<  0)
 			;
 	}
-	forceinline bool operator == (const self_t &cmp) const
+	MPT_FORCEINLINE bool operator == (const self_t &cmp) const
 	{
 		return true
 			&& bytes[0] == cmp.bytes[0]
@@ -392,20 +635,21 @@ public:
 			&& bytes[7] == cmp.bytes[7]
 			;
 	}
-	forceinline bool operator != (const self_t &cmp) const
+	MPT_FORCEINLINE bool operator != (const self_t &cmp) const
 	{
 		return !(*this == cmp);
 	}
 };
 
-namespace mpt {
-
-template <> struct is_binary_safe<IEEE754binary32Emulated<0,1,2,3> > : public mpt::true_type { };
-template <> struct is_binary_safe<IEEE754binary32Emulated<3,2,1,0> > : public mpt::true_type { };
-template <> struct is_binary_safe<IEEE754binary64Emulated<0,1,2,3,4,5,6,7> > : public mpt::true_type { };
-template <> struct is_binary_safe<IEEE754binary64Emulated<7,6,5,4,3,2,1,0> > : public mpt::true_type { };
+typedef IEEE754binary32Emulated<0,1,2,3> IEEE754binary32EmulatedBE;
+typedef IEEE754binary32Emulated<3,2,1,0> IEEE754binary32EmulatedLE;
+typedef IEEE754binary64Emulated<0,1,2,3,4,5,6,7> IEEE754binary64EmulatedBE;
+typedef IEEE754binary64Emulated<7,6,5,4,3,2,1,0> IEEE754binary64EmulatedLE;
 
-} // namespace mpt
+MPT_BINARY_STRUCT(IEEE754binary32EmulatedBE, 4)
+MPT_BINARY_STRUCT(IEEE754binary32EmulatedLE, 4)
+MPT_BINARY_STRUCT(IEEE754binary64EmulatedBE, 8)
+MPT_BINARY_STRUCT(IEEE754binary64EmulatedLE, 8)
 
 #if MPT_PLATFORM_IEEE_FLOAT
 
@@ -414,7 +658,7 @@ struct IEEE754binary32Native
 private:
 	float32 value;
 public:
-	forceinline mpt::byte GetByte(std::size_t i) const
+	MPT_FORCEINLINE mpt::byte GetByte(std::size_t i) const
 	{
 		#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
 			return static_cast<mpt::byte>(EncodeIEEE754binary32(value) >> (i*8));
@@ -424,15 +668,15 @@ public:
 			STATIC_ASSERT(false);
 		#endif
 	}
-	forceinline IEEE754binary32Native() { }
-	forceinline explicit IEEE754binary32Native(float32 f)
+	MPT_FORCEINLINE IEEE754binary32Native() { }
+	MPT_FORCEINLINE explicit IEEE754binary32Native(float32 f)
 	{
 		value = f;
 	}
 	// b0...b3 are in memory order, i.e. depend on the endianness of this type
 	// little endian: (0x00,0x00,0x80,0x3f)
 	// big endian:    (0x3f,0x80,0x00,0x00)
-	forceinline explicit IEEE754binary32Native(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3)
+	MPT_FORCEINLINE explicit IEEE754binary32Native(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3)
 	{
 		#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
 			value = DecodeIEEE754binary32(0u
@@ -452,24 +696,24 @@ public:
 			STATIC_ASSERT(false);
 		#endif
 	}
-	forceinline operator float32 () const
+	MPT_FORCEINLINE operator float32 () const
 	{
 		return value;
 	}
-	forceinline IEEE754binary32Native & SetInt32(uint32 i)
+	MPT_FORCEINLINE IEEE754binary32Native & SetInt32(uint32 i)
 	{
 		value = DecodeIEEE754binary32(i);
 		return *this;
 	}
-	forceinline uint32 GetInt32() const
+	MPT_FORCEINLINE uint32 GetInt32() const
 	{
 		return EncodeIEEE754binary32(value);
 	}
-	forceinline bool operator == (const IEEE754binary32Native &cmp) const
+	MPT_FORCEINLINE bool operator == (const IEEE754binary32Native &cmp) const
 	{
 		return value == cmp.value;
 	}
-	forceinline bool operator != (const IEEE754binary32Native &cmp) const
+	MPT_FORCEINLINE bool operator != (const IEEE754binary32Native &cmp) const
 	{
 		return value != cmp.value;
 	}
@@ -480,7 +724,7 @@ struct IEEE754binary64Native
 private:
 	float64 value;
 public:
-	forceinline mpt::byte GetByte(std::size_t i) const
+	MPT_FORCEINLINE mpt::byte GetByte(std::size_t i) const
 	{
 		#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
 			return static_cast<mpt::byte>(EncodeIEEE754binary64(value) >> (i*8));
@@ -490,12 +734,12 @@ public:
 			STATIC_ASSERT(false);
 		#endif
 	}
-	forceinline IEEE754binary64Native() { }
-	forceinline explicit IEEE754binary64Native(float64 f)
+	MPT_FORCEINLINE IEEE754binary64Native() { }
+	MPT_FORCEINLINE explicit IEEE754binary64Native(float64 f)
 	{
 		value = f;
 	}
-	forceinline explicit IEEE754binary64Native(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3, mpt::byte b4, mpt::byte b5, mpt::byte b6, mpt::byte b7)
+	MPT_FORCEINLINE explicit IEEE754binary64Native(mpt::byte b0, mpt::byte b1, mpt::byte b2, mpt::byte b3, mpt::byte b4, mpt::byte b5, mpt::byte b6, mpt::byte b7)
 	{
 		#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
 			value = DecodeIEEE754binary64(0ull
@@ -523,54 +767,57 @@ public:
 			STATIC_ASSERT(false);
 		#endif
 	}
-	forceinline operator float64 () const
+	MPT_FORCEINLINE operator float64 () const
 	{
 		return value;
 	}
-	forceinline IEEE754binary64Native & SetInt64(uint64 i)
+	MPT_FORCEINLINE IEEE754binary64Native & SetInt64(uint64 i)
 	{
 		value = DecodeIEEE754binary64(i);
 		return *this;
 	}
-	forceinline uint64 GetInt64() const
+	MPT_FORCEINLINE uint64 GetInt64() const
 	{
 		return EncodeIEEE754binary64(value);
 	}
-	forceinline bool operator == (const IEEE754binary64Native &cmp) const
+	MPT_FORCEINLINE bool operator == (const IEEE754binary64Native &cmp) const
 	{
 		return value == cmp.value;
 	}
-	forceinline bool operator != (const IEEE754binary64Native &cmp) const
+	MPT_FORCEINLINE bool operator != (const IEEE754binary64Native &cmp) const
 	{
 		return value != cmp.value;
 	}
 };
 
-namespace mpt {
-
-template <> struct is_binary_safe<IEEE754binary32Native> : public mpt::true_type { };
-template <> struct is_binary_safe<IEEE754binary64Native> : public mpt::true_type { };
+STATIC_ASSERT(sizeof(IEEE754binary32Native) == 4);
+STATIC_ASSERT(sizeof(IEEE754binary64Native) == 8);
 
-} // namespace mpt
+#if MPT_PLATFORM_IEEE_FLOAT
+namespace mpt {
+template <> struct is_binary_safe< IEEE754binary32Native > : public std::true_type { };
+template <> struct is_binary_safe< IEEE754binary64Native > : public std::true_type { };
+}
+#endif // MPT_PLATFORM_IEEE_FLOAT
 
 #if defined(MPT_PLATFORM_LITTLE_ENDIAN)
 typedef IEEE754binary32Native                    IEEE754binary32LE;
-typedef IEEE754binary32Emulated<0,1,2,3>         IEEE754binary32BE;
+typedef IEEE754binary32EmulatedBE                IEEE754binary32BE;
 typedef IEEE754binary64Native                    IEEE754binary64LE;
-typedef IEEE754binary64Emulated<0,1,2,3,4,5,6,7> IEEE754binary64BE;
+typedef IEEE754binary64EmulatedBE                IEEE754binary64BE;
 #elif defined(MPT_PLATFORM_BIG_ENDIAN)
-typedef IEEE754binary32Emulated<3,2,1,0>         IEEE754binary32LE;
+typedef IEEE754binary32EmulatedLE                IEEE754binary32LE;
 typedef IEEE754binary32Native                    IEEE754binary32BE;
-typedef IEEE754binary64Emulated<7,6,5,4,3,2,1,0> IEEE754binary64LE;
+typedef IEEE754binary64EmulatedLE                IEEE754binary64LE;
 typedef IEEE754binary64Native                    IEEE754binary64BE;
 #endif
 
 #else // !MPT_PLATFORM_IEEE_FLOAT
 
-typedef IEEE754binary32Emulated<3,2,1,0> IEEE754binary32LE;
-typedef IEEE754binary32Emulated<0,1,2,3> IEEE754binary32BE;
-typedef IEEE754binary64Emulated<7,6,5,4,3,2,1,0> IEEE754binary64LE;
-typedef IEEE754binary64Emulated<0,1,2,3,4,5,6,7> IEEE754binary64BE;
+typedef IEEE754binary32EmulatedLE IEEE754binary32LE;
+typedef IEEE754binary32EmulatedBE IEEE754binary32BE;
+typedef IEEE754binary64EmulatedLE IEEE754binary64LE;
+typedef IEEE754binary64EmulatedBE IEEE754binary64BE;
 
 #endif // MPT_PLATFORM_IEEE_FLOAT
 
@@ -579,6 +826,126 @@ STATIC_ASSERT(sizeof(IEEE754binary32BE) == 4);
 STATIC_ASSERT(sizeof(IEEE754binary64LE) == 8);
 STATIC_ASSERT(sizeof(IEEE754binary64BE) == 8);
 
+typedef IEEE754binary32LE float32le;
+typedef IEEE754binary32BE float32be;
+typedef IEEE754binary64LE float64le;
+typedef IEEE754binary64BE float64be;
+
+STATIC_ASSERT(sizeof(float32le) == 4);
+STATIC_ASSERT(sizeof(float32be) == 4);
+STATIC_ASSERT(sizeof(float64le) == 8);
+STATIC_ASSERT(sizeof(float64be) == 8);
+
+
+// On-disk integer types with defined endianness and no alignemnt requirements
+// Note: To easily debug module loaders (and anything else that uses this
+// wrapper struct), you can use the Debugger Visualizers available in
+// build/vs/debug/ to conveniently view the wrapped contents.
+
+template<typename T, typename Tendian>
+struct packed
+{
+public:
+	typedef T base_type;
+	typedef Tendian endian_type;
+private:
+#if MPT_PLATFORM_ENDIAN_KNOWN
+	mpt::byte data[sizeof(base_type)];
+#else // !MPT_PLATFORM_ENDIAN_KNOWN
+	std::array<mpt::byte, sizeof(base_type)> data;
+#endif // MPT_PLATFORM_ENDIAN_KNOWN
+public:
+	MPT_FORCEINLINE void set(base_type val)
+	{
+		STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+		#if MPT_PLATFORM_ENDIAN_KNOWN
+			MPT_CONSTANT_IF(mpt::detail::NativeEndian != endian_type::Endianness)
+			{
+				val = SwapBytes(val);
+			}
+			std::memcpy(data, &val, sizeof(val));
+		#else // !MPT_PLATFORM_ENDIAN_KNOWN
+			typedef typename std::make_unsigned<base_type>::type unsigned_base_type;
+			data = EndianEncode<unsigned_base_type, Tendian, sizeof(T)>(val);
+		#endif // MPT_PLATFORM_ENDIAN_KNOWN
+	}
+	MPT_FORCEINLINE base_type get() const
+	{
+		STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+		#if MPT_PLATFORM_ENDIAN_KNOWN
+			base_type val = base_type();
+			std::memcpy(&val, data, sizeof(val));
+			MPT_CONSTANT_IF(mpt::detail::NativeEndian != endian_type::Endianness)
+			{
+				val = SwapBytes(val);
+			}
+			return val;
+		#else // !MPT_PLATFORM_ENDIAN_KNOWN
+			typedef typename std::make_unsigned<base_type>::type unsigned_base_type;
+			return EndianDecode<unsigned_base_type, Tendian, sizeof(T)>(data);
+		#endif // MPT_PLATFORM_ENDIAN_KNOWN
+	}
+	MPT_FORCEINLINE packed & operator = (const base_type & val) { set(val); return *this; }
+	MPT_FORCEINLINE operator base_type () const { return get(); }
+public:
+	packed & operator &= (base_type val) { set(get() & val); return *this; }
+	packed & operator |= (base_type val) { set(get() | val); return *this; }
+	packed & operator ^= (base_type val) { set(get() ^ val); return *this; }
+	packed & operator += (base_type val) { set(get() + val); return *this; }
+	packed & operator -= (base_type val) { set(get() - val); return *this; }
+	packed & operator *= (base_type val) { set(get() * val); return *this; }
+	packed & operator /= (base_type val) { set(get() / val); return *this; }
+	packed & operator %= (base_type val) { set(get() % val); return *this; }
+	packed & operator ++ () { set(get() + 1); return *this; } // prefix
+	packed & operator -- () { set(get() - 1); return *this; } // prefix
+	base_type operator ++ (int) { base_type old = get(); set(old + 1); return old; } // postfix
+	base_type operator -- (int) { base_type old = get(); set(old - 1); return old; } // postfix
+};
+
+typedef packed< int64, LittleEndian_tag> int64le;
+typedef packed< int32, LittleEndian_tag> int32le;
+typedef packed< int16, LittleEndian_tag> int16le;
+typedef packed< int8 , LittleEndian_tag> int8le;
+typedef packed<uint64, LittleEndian_tag> uint64le;
+typedef packed<uint32, LittleEndian_tag> uint32le;
+typedef packed<uint16, LittleEndian_tag> uint16le;
+typedef packed<uint8 , LittleEndian_tag> uint8le;
+
+typedef packed< int64, BigEndian_tag> int64be;
+typedef packed< int32, BigEndian_tag> int32be;
+typedef packed< int16, BigEndian_tag> int16be;
+typedef packed< int8 , BigEndian_tag> int8be;
+typedef packed<uint64, BigEndian_tag> uint64be;
+typedef packed<uint32, BigEndian_tag> uint32be;
+typedef packed<uint16, BigEndian_tag> uint16be;
+typedef packed<uint8 , BigEndian_tag> uint8be;
+
+MPT_BINARY_STRUCT(int64le, 8)
+MPT_BINARY_STRUCT(int32le, 4)
+MPT_BINARY_STRUCT(int16le, 2)
+MPT_BINARY_STRUCT(int8le , 1)
+MPT_BINARY_STRUCT(uint64le, 8)
+MPT_BINARY_STRUCT(uint32le, 4)
+MPT_BINARY_STRUCT(uint16le, 2)
+MPT_BINARY_STRUCT(uint8le , 1)
+
+MPT_BINARY_STRUCT(int64be, 8)
+MPT_BINARY_STRUCT(int32be, 4)
+MPT_BINARY_STRUCT(int16be, 2)
+MPT_BINARY_STRUCT(int8be , 1)
+MPT_BINARY_STRUCT(uint64be, 8)
+MPT_BINARY_STRUCT(uint32be, 4)
+MPT_BINARY_STRUCT(uint16be, 2)
+MPT_BINARY_STRUCT(uint8be , 1)
+
+namespace mpt {
+
+template <typename T> struct make_le { typedef packed<T, LittleEndian_tag> type; };
+template <typename T> struct make_be { typedef packed<T, BigEndian_tag> type; };
+
+} // namespace mpt
+
+
 
 // Small helper class to support unaligned memory access on all platforms.
 // This is only used to make old module loaders work everywhere.
@@ -689,25 +1056,6 @@ public:
 	operator bool () const { return mem != nullptr; }
 };
 
-//  Reference binding to unaligned structure fields resulting from packed
-// structures result in undefined behaviour as soon as the reference gets used.
-//  Both Clang and GCC do not statically warn for this problem, but asan+ubsan
-// is able to catch it at runtime. Note however that this will not catch all
-// problematic accesses as actual alignedness may depend on the actual memory
-// layout at runtime and the sanitizers will only catch the cases where it is
-// actually misaligned at the particular point of occurence.
-//  read_unaligned_field() takes the argument by value which will cause the
-// compiler to copy it to an aligned stack slot or register.
-//  This has been verified to work with Clang (sanitizers won't warn anymore).
-// In case it does not work with GCC, at least all known offending call sites
-// can easily identified by grepping for read_unaligned_field.
-//  See https://bugs.openmpt.org/view.php?id=572 .
-// TODO: Verify this works as intended on GCC.
-template <typename T>
-T read_unaligned_field(T val)
-{
-	return val;
-}
 
 OPENMPT_NAMESPACE_END
 
diff --git a/common/FileReader.cpp b/common/FileReader.cpp
index 4b88098..6f7b33f 100644
--- a/common/FileReader.cpp
+++ b/common/FileReader.cpp
@@ -23,19 +23,59 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fileNameExtension)
-//----------------------------------------------------------------------------------------------
 	: m_IsTempFile(false)
 {
 	try
 	{
 		file.Rewind();
-#if defined(MPT_ENABLE_FILEIO)
 		if(file.GetFileName().empty())
 		{
-#endif // MPT_ENABLE_FILEIO
 			const mpt::PathString tempName = mpt::CreateTempFileName(MPT_PATHSTRING("OpenMPT"), fileNameExtension);
+
+#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+#if (_WIN32_WINNT < 0x0602)
+#define MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
+#endif
+#endif
+
+#ifdef MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
+
+			FILE * f = _wfopen(tempName.AsNative().c_str(), L"wb");
+			if(!f)
+			{
+				throw std::runtime_error("");
+			}
+			while(!file.EndOfFile())
+			{
+				FileReader::PinnedRawDataView view = file.ReadPinnedRawDataView(mpt::IO::BUFFERSIZE_NORMAL);
+				std::size_t towrite = view.size();
+				std::size_t written = 0;
+				do
+				{
+					std::size_t chunkSize = mpt::saturate_cast<std::size_t>(towrite);
+					std::size_t chunkDone = 0;
+					chunkDone = fwrite(view.data() + written, 1, chunkSize, f);
+					if(chunkDone != chunkSize)
+					{
+						fclose(f);
+						f = NULL;
+						throw std::runtime_error("");
+					}
+					towrite -= chunkDone;
+					written += chunkDone;
+				} while(towrite > 0);
+			}
+			fclose(f);
+			f = NULL;
+
+#else // !MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
+
 			HANDLE hFile = NULL;
-			hFile = CreateFileW(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
+			#if MPT_OS_WINDOWS_WINRT
+				hFile = CreateFile2(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL);
+			#else
+				hFile = CreateFileW(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
+			#endif
 			if(hFile == NULL || hFile == INVALID_HANDLE_VALUE)
 			{
 				throw std::runtime_error("");
@@ -53,6 +93,7 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
 					if(chunkDone != chunkSize)
 					{
 						CloseHandle(hFile);
+						hFile = NULL;
 						throw std::runtime_error("");
 					}
 					towrite -= chunkDone;
@@ -61,14 +102,15 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
 			}
 			CloseHandle(hFile);
 			hFile = NULL;
+
+#endif // MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
+
 			m_Filename = tempName;
 			m_IsTempFile = true;
-#if defined(MPT_ENABLE_FILEIO)
 		} else
 		{
 			m_Filename = file.GetFileName();
 		}
-#endif // MPT_ENABLE_FILEIO
 	} catch (const std::runtime_error &)
 	{
 		m_IsTempFile = false;
@@ -78,7 +120,6 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
 
 
 OnDiskFileWrapper::~OnDiskFileWrapper()
-//-------------------------------------
 {
 	if(m_IsTempFile)
 	{
@@ -90,14 +131,12 @@ OnDiskFileWrapper::~OnDiskFileWrapper()
 
 
 bool OnDiskFileWrapper::IsValid() const
-//-------------------------------------
 {
 	return !m_Filename.empty();
 }
 
 
 mpt::PathString OnDiskFileWrapper::GetFilename() const
-//----------------------------------------------------
 {
 	return m_Filename;
 }
diff --git a/common/FileReader.h b/common/FileReader.h
index 1138575..200fcd2 100644
--- a/common/FileReader.h
+++ b/common/FileReader.h
@@ -22,6 +22,8 @@
 #include <vector>
 #include <cstring>
 
+#include "FileReaderFwd.h"
+
 
 OPENMPT_NAMESPACE_BEGIN
 
@@ -31,168 +33,124 @@ OPENMPT_NAMESPACE_BEGIN
 #define FILEREADER_DEPRECATED
 
 
-//==============
-class FileReader
-//==============
+class FileReaderTraitsMemory
 {
 
 public:
 
-#if defined(MPT_FILEREADER_STD_ISTREAM)
-	typedef IFileDataContainer::off_t off_t;
-#else
 	typedef FileDataContainerMemory::off_t off_t;
-#endif
 
-private:
+	typedef FileDataContainerMemory data_type;
+	typedef const FileDataContainerMemory & ref_data_type;
+	typedef const FileDataContainerMemory & shared_data_type;
+	typedef FileDataContainerMemory value_data_type;
 
-#if defined(MPT_FILEREADER_STD_ISTREAM)
-	const IFileDataContainer & DataContainer() const { return *data; }
-	IFileDataContainer & DataContainer() { return *data; }
-	MPT_SHARED_PTR<IFileDataContainer> data;
-#else
-	const FileDataContainerMemory & DataContainer() const { return data; }
-	FileDataContainerMemory & DataContainer() { return data; }
-	FileDataContainerMemory data;
-#endif
+	static shared_data_type get_shared(const data_type & data) { return data; }
+	static ref_data_type get_ref(const data_type & data) { return data; }
 
-	off_t streamPos;		// Cursor location in the file
+	static value_data_type make_data() { return mpt::const_byte_span(); }
+	static value_data_type make_data(mpt::const_byte_span data) { return data; }
 
-#if defined(MPT_ENABLE_FILEIO)
-	const mpt::PathString *fileName;  // Filename that corresponds to this FileReader. It is only set if this FileReader represents the whole contents of fileName. May be nullptr.
-	#define MPT_FILEREADER_INIT_FILENAME ,fileName(nullptr)
-#else // !MPT_ENABLE_FILEIO
-	#define MPT_FILEREADER_INIT_FILENAME
-#endif // MPT_ENABLE_FILEIO
+	static value_data_type make_chunk(shared_data_type data, off_t position, off_t size)
+	{
+		return mpt::as_span(data.GetRawData() + position, size);
+	}
 
-public:
+};
 
 #if defined(MPT_FILEREADER_STD_ISTREAM)
 
-	// Initialize invalid file reader object.
-	FileReader() : data(mpt::make_shared<FileDataContainerDummy>()), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
+class FileReaderTraitsStdStream
+{
 
-	// Initialize file reader object with pointer to data and data length.
-	FileReader(mpt::span<const mpt::byte> bytedata) : data(mpt::make_shared<FileDataContainerMemory>(bytedata)), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
-#ifdef MODPLUG_TRACKER
-	FileReader(const char *chardata, off_t length) : data(mpt::make_shared<FileDataContainerMemory>(mpt::as_span(mpt::byte_cast<const mpt::byte *>(chardata), length))), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
-	FileReader(const uint8 *uint8data, off_t length) : data(mpt::make_shared<FileDataContainerMemory>(mpt::as_span(mpt::byte_cast<const mpt::byte *>(uint8data), length))), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
-#endif // MODPLUG_TRACKER
-#if defined(MPT_ENABLE_FILEIO)
-	FileReader(mpt::span<const mpt::byte> bytedata, const mpt::PathString *filename) : data(mpt::make_shared<FileDataContainerMemory>(bytedata)), streamPos(0), fileName(filename) { }
-#ifdef MODPLUG_TRACKER
-	FileReader(const char *chardata, off_t length, const mpt::PathString *filename) : data(mpt::make_shared<FileDataContainerMemory>(mpt::as_span(mpt::byte_cast<const mpt::byte *>(chardata), length))), streamPos(0), fileName(filename) { }
-	FileReader(const uint8 *uint8data, off_t length, const mpt::PathString *filename) : data(mpt::make_shared<FileDataContainerMemory>(mpt::as_span(mpt::byte_cast<const mpt::byte *>(uint8data), length))), streamPos(0), fileName(filename) { }
-#endif // MODPLUG_TRACKER
-#endif // MPT_ENABLE_FILEIO
+public:
 
-#if defined(MPT_FILEREADER_CALLBACK_STREAM)
-		// Initialize file reader object with a CallbackStream.
-	FileReader(CallbackStream s)
-		: data(
-#if defined(MPT_FILEREADER_STD_ISTREAM_SEEKABLE)
-				FileDataContainerCallbackStreamSeekable::IsSeekable(s) ?
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerCallbackStreamSeekable>(s))
-				:
-#endif // MPT_FILEREADER_STD_ISTREAM_SEEKABLE
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerCallbackStream>(s))
-			)
-		, streamPos(0)
-		MPT_FILEREADER_INIT_FILENAME
-	{
-		return;
-	}
-#if defined(MPT_ENABLE_FILEIO)
-	FileReader(CallbackStream s, const mpt::PathString *filename)
-		: data(
-#if defined(MPT_FILEREADER_STD_ISTREAM_SEEKABLE)
-				FileDataContainerCallbackStreamSeekable::IsSeekable(s) ?
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerCallbackStreamSeekable>(s))
-				:
-#endif // MPT_FILEREADER_STD_ISTREAM_SEEKABLE
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerCallbackStream>(s))
-			)
-		, streamPos(0)
-		, fileName(filename)
-	{
-		return;
-	}
-#endif // MPT_ENABLE_FILEIO
-#endif // MPT_FILEREADER_CALLBACK_STREAM
+	typedef IFileDataContainer::off_t off_t;
 
+	typedef std::shared_ptr<const IFileDataContainer> data_type;
+	typedef const IFileDataContainer & ref_data_type;
+	typedef std::shared_ptr<const IFileDataContainer> shared_data_type;
+	typedef std::shared_ptr<const IFileDataContainer> value_data_type;
 
-	// Initialize file reader object with a std::istream.
-	FileReader(std::istream *s)
-		: data(
-#if defined(MPT_FILEREADER_STD_ISTREAM_SEEKABLE)
-				FileDataContainerStdStreamSeekable::IsSeekable(s) ?
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerStdStreamSeekable>(s))
-				:
-#endif // MPT_FILEREADER_STD_ISTREAM_SEEKABLE
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerStdStream>(s))
-			)
-		, streamPos(0)
-		MPT_FILEREADER_INIT_FILENAME
-	{
-		return;
-	}
-#if defined(MPT_ENABLE_FILEIO)
-	FileReader(std::istream *s, const mpt::PathString *filename)
-		: data(
-#if defined(MPT_FILEREADER_STD_ISTREAM_SEEKABLE)
-				FileDataContainerStdStreamSeekable::IsSeekable(s) ?
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerStdStreamSeekable>(s))
-				:
-#endif // MPT_FILEREADER_STD_ISTREAM_SEEKABLE
-					MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerStdStream>(s))
-			)
-		, streamPos(0)
-		, fileName(filename)
+	static shared_data_type get_shared(const data_type & data) { return data; }
+	static ref_data_type get_ref(const data_type & data) { return *data; }
+
+	static value_data_type make_data() { return std::make_shared<FileDataContainerDummy>(); }
+	static value_data_type make_data(mpt::const_byte_span data) { return std::make_shared<FileDataContainerMemory>(data); }
+
+	static value_data_type make_chunk(shared_data_type data, off_t position, off_t size)
 	{
-		return;
+		return std::static_pointer_cast<IFileDataContainer>(std::make_shared<FileDataContainerWindow>(data, position, size));
 	}
-#endif // MPT_ENABLE_FILEIO
 
-	// Initialize file reader object based on an existing file reader object window.
-	FileReader(MPT_SHARED_PTR<IFileDataContainer> other) : data(other), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
+};
 
-	// Initialize file reader object based on an existing file reader object. The other object's stream position is copied.
-	FileReader(const FileReader &other) : data(other.data), streamPos(other.streamPos)
-#if defined(MPT_ENABLE_FILEIO)
-		, fileName(other.fileName)
-#endif // MPT_ENABLE_FILEIO
-	{ }
+typedef FileReaderTraitsStdStream FileReaderTraitsDefault;
 
 #else // !MPT_FILEREADER_STD_ISTREAM
 
+typedef FileReaderTraitsMemory FileReaderTraitsDefault;
+
+#endif // MPT_FILEREADER_STD_ISTREAM
+
+namespace detail {
+
+template <typename Ttraits>
+class FileReader
+{
+
+private:
+
+	typedef Ttraits traits_type;
+	
+public:
+
+	typedef typename traits_type::off_t off_t;
+
+	typedef typename traits_type::data_type        data_type;
+	typedef typename traits_type::ref_data_type    ref_data_type;
+	typedef typename traits_type::shared_data_type shared_data_type;
+	typedef typename traits_type::value_data_type  value_data_type;
+
+protected:
+
+	shared_data_type SharedDataContainer() const { return traits_type::get_shared(m_data); }
+	ref_data_type DataContainer() const { return traits_type::get_ref(m_data); }
+
+	static value_data_type DataInitializer() { return traits_type::make_data(); }
+	static value_data_type DataInitializer(mpt::const_byte_span data) { return traits_type::make_data(data); }
+
+	static value_data_type CreateChunkImpl(shared_data_type data, off_t position, off_t size) { return traits_type::make_chunk(data, position, size); }
+
+private:
+
+	data_type m_data;
+
+	off_t streamPos;		// Cursor location in the file
+
+	const mpt::PathString *fileName;  // Filename that corresponds to this FileReader. It is only set if this FileReader represents the whole contents of fileName. May be nullptr. Lifetime is managed outside of FileReader.
+
+public:
+
 	// Initialize invalid file reader object.
-	FileReader() : data(mpt::span<const mpt::byte>()), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
+	FileReader() : m_data(DataInitializer()), streamPos(0), fileName(nullptr) { }
 
 	// Initialize file reader object with pointer to data and data length.
-	FileReader(mpt::span<const mpt::byte> bytedata) : data(bytedata), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
-#ifdef MODPLUG_TRACKER
-	FileReader(const char *chardata, off_t length) : data(mpt::as_span(mpt::byte_cast<const mpt::byte *>(chardata), length)), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
-	FileReader(const uint8 *uint8data, off_t length) : data(mpt::as_span(mpt::byte_cast<const mpt::byte *>(uint8data), length)), streamPos(0) MPT_FILEREADER_INIT_FILENAME { }
-#endif // MODPLUG_TRACKER
-#if defined(MPT_ENABLE_FILEIO)
-	FileReader(mpt::span<const mpt::byte> bytedata, const mpt::PathString *filename) : data(bytedata), streamPos(0), fileName(filename) { }
-#ifdef MODPLUG_TRACKER
-	FileReader(const char *chardata, off_t length, const mpt::PathString *filename) : data(mpt::as_span(mpt::byte_cast<const mpt::byte *>(chardata), length)), streamPos(0), fileName(filename) { }
-	FileReader(const uint8 *uint8data, off_t length, const mpt::PathString *filename) : data(mpt::as_span(mpt::byte_cast<const mpt::byte *>(uint8data), length)), streamPos(0), fileName(filename) { }
-#endif // MODPLUG_TRACKER
-#endif // MPT_ENABLE_FILEIO
+	template <typename Tbyte> FileReader(mpt::span<Tbyte> bytedata, const mpt::PathString *filename = nullptr) : m_data(DataInitializer(mpt::byte_cast<mpt::const_byte_span>(bytedata))), streamPos(0), fileName(filename) { }
+
+	// Initialize file reader object based on an existing file reader object window.
+	explicit FileReader(value_data_type other, const mpt::PathString *filename = nullptr) : m_data(other), streamPos(0), fileName(filename) { }
 
 	// Initialize file reader object based on an existing file reader object. The other object's stream position is copied.
-	FileReader(const FileReader &other) : data(other.data), streamPos(other.streamPos)
-#if defined(MPT_ENABLE_FILEIO)
-		, fileName(other.fileName)
-#endif // MPT_ENABLE_FILEIO
-	{ }
+	FileReader(const FileReader &) = default;
+	FileReader& operator=(const FileReader &) = default;
 
-#endif // MPT_FILEREADER_STD_ISTREAM
+	// Move an existing file reader object
+	FileReader(FileReader &&) noexcept = default;
+	FileReader& operator=(FileReader &&) noexcept = default;
 
+public:
 
-#if defined(MPT_ENABLE_FILEIO)
 	mpt::PathString GetFileName() const
 	{
 		if(!fileName)
@@ -201,9 +159,14 @@ public:
 		}
 		return *fileName;
 	}
-#endif // MPT_ENABLE_FILEIO
 
-	// Returns true if the object points to a valid stream.
+	// Returns true if the object points to a valid (non-empty) stream.
+	operator bool() const
+	{
+		return IsValid();
+	}
+
+	// Returns true if the object points to a valid (non-empty) stream.
 	bool IsValid() const
 	{
 		return DataContainer().IsValid();
@@ -270,6 +233,14 @@ public:
 		return streamPos;
 	}
 
+	// Return true IFF seeking and GetLength() is fast.
+	// In particular, it returns false for unseekable stream where GetLength()
+	// requires pre-caching.
+	bool HasFastGetLength() const
+	{
+		return DataContainer().HasFastGetLength();
+	}
+
 	// Returns size of the mapped file in bytes.
 	FILEREADER_DEPRECATED off_t GetLength() const
 	{
@@ -321,11 +292,7 @@ protected:
 		{
 			return FileReader();
 		}
-		#if defined(MPT_FILEREADER_STD_ISTREAM)
-			return FileReader(MPT_STATIC_POINTER_CAST<IFileDataContainer>(mpt::make_shared<FileDataContainerWindow>(data, position, std::min(length, DataContainer().GetLength() - position))));
-		#else
-			return FileReader(mpt::as_span(DataContainer().GetRawData() + position, std::min(length, DataContainer().GetLength() - position)));
-		#endif
+		return FileReader(CreateChunkImpl(SharedDataContainer(), position, std::min(length, DataContainer().GetLength() - position)));
 	}
 
 public:
@@ -352,9 +319,7 @@ public:
 		return CreateChunk(position, length);
 	}
 
-	//=====================
 	class PinnedRawDataView
-	//=====================
 	{
 	private:
 		std::size_t size_;
@@ -412,7 +377,7 @@ public:
 			}
 		}
 	public:
-		mpt::span<const mpt::byte> GetSpan() const
+		mpt::const_byte_span GetSpan() const
 		{
 			if(pinnedData)
 			{
@@ -422,17 +387,17 @@ public:
 				return mpt::as_span(cache);
 			} else
 			{
-				return mpt::span<const mpt::byte>();
+				return mpt::const_byte_span();
 			}
 		}
-		mpt::span<const mpt::byte> span() const { return GetSpan(); }
+		mpt::const_byte_span span() const { return GetSpan(); }
 		void invalidate() { size_ = 0; pinnedData = nullptr; cache = std::vector<mpt::byte>(); }
 		const mpt::byte *data() const { return span().data(); }
 		std::size_t size() const { return size_; }
-		mpt::span<const mpt::byte>::iterator begin() const { return span().begin(); }
-		mpt::span<const mpt::byte>::iterator end() const { return span().end(); }
-		mpt::span<const mpt::byte>::const_iterator cbegin() const { return span().cbegin(); }
-		mpt::span<const mpt::byte>::const_iterator cend() const { return span().cend(); }
+		mpt::const_byte_span::iterator begin() const { return span().begin(); }
+		mpt::const_byte_span::iterator end() const { return span().end(); }
+		mpt::const_byte_span::const_iterator cbegin() const { return span().cbegin(); }
+		mpt::const_byte_span::const_iterator cend() const { return span().cend(); }
 	};
 
 	// Returns a pinned view into the remaining raw data from cursor position.
@@ -557,7 +522,7 @@ public:
 		T target;
 		if(Read(target))
 		{
-			return SwapBytesReturnLE(target);
+			return SwapBytesLE(target);
 		} else
 		{
 			return 0;
@@ -573,7 +538,7 @@ public:
 		T target;
 		if(Read(target))
 		{
-			return SwapBytesReturnBE(target);
+			return SwapBytesBE(target);
 		} else
 		{
 			return 0;
@@ -613,7 +578,7 @@ public:
 		}
 		T target;
 		std::memcpy(&target, buf, sizeof(T));
-		return SwapBytesReturnLE(target);
+		return SwapBytesLE(target);
 	}
 
 	// Read a supplied-size little endian integer to a fixed size variable.
@@ -785,6 +750,7 @@ public:
 	template <typename T>
 	bool ReadStruct(T &target)
 	{
+		STATIC_ASSERT(mpt::is_binary_safe<T>::value);
 		if(Read(target))
 		{
 			return true;
@@ -800,6 +766,7 @@ public:
 	template <typename T>
 	bool ReadStructPartial(T &target, off_t partialSize = sizeof(T))
 	{
+		STATIC_ASSERT(mpt::is_binary_safe<T>::value);
 		off_t copyBytes = std::min(partialSize, sizeof(T));
 		if(!CanRead(copyBytes))
 		{
@@ -811,26 +778,10 @@ public:
 		return true;
 	}
 
-	// Read a "T" object from the stream.
-	// If not enough bytes can be read, false is returned.
-	// If successful, the file cursor is advanced by the size of "T" and the object's "ConvertEndianness()" method is called.
-	template <typename T>
-	bool ReadConvertEndianness(T &target)
-	{
-		if(Read(target))
-		{
-			target.ConvertEndianness();
-			return true;
-		} else
-		{
-			return false;
-		}
-	}
-
 	// Read a string of length srcSize into fixed-length char array destBuffer using a given read mode.
 	// The file cursor is advanced by "srcSize" bytes.
 	// Returns true if at least one byte could be read or 0 bytes were requested.
-	template<mpt::String::ReadWriteMode mode, off_t destSize>
+	template<mpt::String::ReadWriteMode mode, size_t destSize>
 	bool ReadString(char (&destBuffer)[destSize], const off_t srcSize)
 	{
 		FileReader::PinnedRawDataView source = ReadPinnedRawDataView(srcSize); // Make sure the string is cached properly.
@@ -841,7 +792,7 @@ public:
 
 	// Read a string of length srcSize into a std::string dest using a given read mode.
 	// The file cursor is advanced by "srcSize" bytes.
-	// Returns true if at least one byte could be read or 0 bytes were requested.
+	// Returns true if at least one character could be read or 0 characters were requested.
 	template<mpt::String::ReadWriteMode mode>
 	bool ReadString(std::string &dest, const off_t srcSize)
 	{
@@ -851,55 +802,121 @@ public:
 		return (realSrcSize > 0 || srcSize == 0);
 	}
 
+	// Read a charset encoded string of length srcSize into a mpt::ustring dest using a given read mode.
+	// The file cursor is advanced by "srcSize" bytes.
+	// Returns true if at least one character could be read or 0 characters were requested.
+	template<mpt::String::ReadWriteMode mode>
+	bool ReadString(mpt::ustring &dest, mpt::Charset charset, const off_t srcSize)
+	{
+		FileReader::PinnedRawDataView source = ReadPinnedRawDataView(srcSize);	// Make sure the string is cached properly.
+		off_t realSrcSize = source.size();	// In case fewer bytes are available
+		mpt::String::Read<mode>(dest, charset, mpt::byte_cast<const char*>(source.data()), realSrcSize);
+		return (realSrcSize > 0 || srcSize == 0);
+	}
+
+	// Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode.
+	// The file cursor is advanced by the string length.
+	// Returns true if the size field could be read and at least one character could be read or 0 characters were requested.
+	template<typename Tsize, mpt::String::ReadWriteMode mode, size_t destSize>
+	bool ReadSizedString(char (&destBuffer)[destSize], const off_t maxLength = std::numeric_limits<off_t>::max())
+	{
+		packed<typename Tsize::base_type, typename Tsize::endian_type> srcSize;	// Enforce usage of a packed type by ensuring that the passed type has the required typedefs
+		if(!Read(srcSize))
+			return false;
+		return ReadString<mode>(destBuffer, std::min<off_t>(srcSize, maxLength));
+	}
+
+	// Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode.
+	// The file cursor is advanced by the string length.
+	// Returns true if the size field could be read and at least one character could be read or 0 characters were requested.
+	template<typename Tsize, mpt::String::ReadWriteMode mode>
+	bool ReadSizedString(std::string &dest, const off_t maxLength = std::numeric_limits<off_t>::max())
+	{
+		packed<typename Tsize::base_type, typename Tsize::endian_type> srcSize;	// Enforce usage of a packed type by ensuring that the passed type has the required typedefs
+		if(!Read(srcSize))
+			return false;
+		return ReadString<mode>(dest, std::min<off_t>(srcSize, maxLength));
+	}
+
 	// Read a null-terminated string into a std::string
-	bool ReadNullString(std::string &dest, const off_t maxLength = std::numeric_limits<std::size_t>::max())
+	bool ReadNullString(std::string &dest, const off_t maxLength = std::numeric_limits<off_t>::max())
 	{
 		dest.clear();
+		if(!CanRead(1))
+			return false;
 		try
 		{
-			char c = '\0';
-			while(Read(c) && c != '\0' && dest.length() < maxLength)
+			char buffer[64];
+			off_t avail = 0;
+			while((avail = std::min(DataContainer().Read(reinterpret_cast<mpt::byte*>(buffer), streamPos, sizeof(buffer)), maxLength - dest.length())) != 0)
 			{
-				dest += c;
+				auto end = std::find(buffer, buffer + avail, '\0');
+				dest.insert(dest.end(), buffer, end);
+				streamPos += (end - buffer);
+				if(end < buffer + avail)
+				{
+					// Found null char
+					streamPos++;
+					break;
+				}
 			}
-		} catch(MPTMemoryException)
+		} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 		{
+			MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		}
 		return dest.length() != 0;
 	}
 
-	// Read an array of byte-sized values.
-	// If successful, the file cursor is advanced by the size of the array.
-	// Otherwise, the target is zeroed.
-	template<typename T, off_t destSize>
-	bool ReadArray(T (&destArray)[destSize])
+private:
+	static MPT_FORCEINLINE bool IsLineEnding(char c) { return c == '\r' || c == '\n'; }
+public:
+	// Read a string up to the next line terminator into a std::string
+	bool ReadLine(std::string &dest, const off_t maxLength = std::numeric_limits<off_t>::max())
 	{
-		STATIC_ASSERT(sizeof(T) == 1);
-		if(CanRead(sizeof(destArray)))
+		dest.clear();
+		if(!CanRead(1))
+			return false;
+		try
 		{
-			for(std::size_t i = 0; i < destSize; ++i)
+			char buffer[64], c = '\0';
+			off_t avail = 0;
+			while((avail = std::min(DataContainer().Read(reinterpret_cast<mpt::byte*>(buffer), streamPos, sizeof(buffer)), maxLength - dest.length())) != 0)
 			{
-				Read(destArray[i]);
+				auto end = std::find_if(buffer, buffer + avail, IsLineEnding);
+				dest.insert(dest.end(), buffer, end);
+				streamPos += (end - buffer);
+				if(end < buffer + avail)
+				{
+					// Found line ending
+					streamPos++;
+					// Handle CRLF line ending
+					if(*end == '\r')
+					{
+						if(Read(c) && c != '\n')
+							SkipBack(1);
+					}
+					break;
+				}
 			}
-			return true;
-		} else
+		} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 		{
-			MemsetZero(destArray);
-			return false;
+			MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		}
+		return true;
 	}
 
-	// Read an array.
+	// Read an array of binary-safe T values.
 	// If successful, the file cursor is advanced by the size of the array.
 	// Otherwise, the target is zeroed.
 	template<typename T, off_t destSize>
-	bool ReadArrayLE(T (&destArray)[destSize])
+	bool ReadArray(T (&destArray)[destSize])
 	{
+		STATIC_ASSERT(mpt::is_binary_safe<T>::value);
 		if(CanRead(sizeof(destArray)))
 		{
-			for(std::size_t i = 0; i < destSize; ++i)
+			for(auto &element : destArray)
 			{
-				destArray[i] = ReadIntLE<T>();
+				Read(element);
 			}
 			return true;
 		} else
@@ -909,20 +926,19 @@ public:
 		}
 	}
 
-	// Read destSize elements of byte-sized type T into a vector.
+	// Read destSize elements of binary-safe type T into a vector.
 	// If successful, the file cursor is advanced by the size of the vector.
 	// Otherwise, the vector is resized to destSize, but possibly existing contents are not cleared.
 	template<typename T>
 	bool ReadVector(std::vector<T> &destVector, size_t destSize)
 	{
-		STATIC_ASSERT(sizeof(T) == 1);
-		const off_t readSize = sizeof(T) * destSize;
+		STATIC_ASSERT(mpt::is_binary_safe<T>::value);
 		destVector.resize(destSize);
-		if(CanRead(readSize))
+		if(CanRead(sizeof(T) * destSize))
 		{
-			for(std::size_t i = 0; i < destSize; ++i)
+			for(auto &element : destVector)
 			{
-				Read(destVector[i]);
+				Read(element);
 			}
 			return true;
 		} else
@@ -931,41 +947,29 @@ public:
 		}
 	}
 
-	// Read destSize elements of type T into a vector.
-	// If successful, the file cursor is advanced by the size of the vector.
-	// Otherwise, the vector is resized to destSize, but possibly existing contents are not cleared.
-	template<typename T>
-	bool ReadVectorLE(std::vector<T> &destVector, size_t destSize)
+	// Compare a magic string with the current stream position.
+	// Returns true if they are identical and advances the file cursor by the the length of the "magic" string.
+	// Returns false if the string could not be found. The file cursor is not advanced in this case.
+	template<size_t N>
+	bool ReadMagic(const char (&magic)[N])
 	{
-		const off_t readSize = sizeof(T) * destSize;
-		try
-		{
-			destVector.resize(destSize);
-		} catch(MPTMemoryException)
+		MPT_ASSERT(magic[N - 1] == '\0');
+		for(std::size_t i = 0; i < N - 1; ++i)
 		{
-			return false;
+			MPT_ASSERT(magic[i] != '\0');
 		}
-		if(CanRead(readSize))
+		if(CanRead(N - 1))
 		{
-			for(std::size_t i = 0; i < destSize; ++i)
+			mpt::byte bytes[N - 1];
+			STATIC_ASSERT(sizeof(bytes) == sizeof(magic) - 1);
+			DataContainer().Read(bytes, streamPos, N - 1);
+			if(!std::memcmp(bytes, magic, N - 1))
 			{
-				destVector[i] = ReadIntLE<T>();
+				streamPos += (N - 1);
+				return true;
 			}
-			return true;
-		} else
-		{
-			return false;
 		}
-	}
-
-	// Compare a magic string with the current stream position.
-	// Returns true if they are identical and advances the file cursor by the the length of the "magic" string.
-	// Returns false if the string could not be found. The file cursor is not advanced in this case.
-	template<size_t N>
-	bool ReadMagic(const char (&magic)[N])
-	{
-		MPT_ASSERT(magic[N - 1] == 0);
-		return ReadMagic(magic, N - 1);
+		return false;
 	}
 
 	bool ReadMagic(const char *const magic, off_t magicLength)
@@ -997,7 +1001,7 @@ public:
 		}
 	}
 
-	// Read variable-length integer (as found in MIDI files).
+	// Read variable-length unsigned integer (as found in MIDI files).
 	// If successful, the file cursor is advanced by the size of the integer and true is returned.
 	// False is returned if not enough bytes were left to finish reading of the integer or if an overflow happened (source doesn't fit into target integer).
 	// In case of an overflow, the target is also set to the maximum value supported by its data type.
@@ -1006,7 +1010,7 @@ public:
 	{
 		static_assert(std::numeric_limits<T>::is_integer == true
 			&& std::numeric_limits<T>::is_signed == false,
-			"Target type is a not an unsigned integer");
+			"Target type is not an unsigned integer");
 
 		if(NoBytesLeft())
 		{
@@ -1014,28 +1018,38 @@ public:
 			return false;
 		}
 
+		mpt::byte bytes[16];	// More than enough for any valid VarInt
+		off_t avail = DataContainer().Read(bytes, streamPos, sizeof(bytes)), readPos = 1;
+		
 		size_t writtenBits = 0;
-		uint8 b = ReadUint8();
+		uint8 b = bytes[0];
 		target = (b & 0x7F);
 
 		// Count actual bits used in most significant byte (i.e. this one)
 		for(size_t bit = 0; bit < 7; bit++)
 		{
-			if((b & (1 << bit)) != 0)
+			if((b & (1u << bit)) != 0)
 			{
 				writtenBits = bit + 1;
 			}
 		}
 
-		while(CanRead(1) && (b & 0x80) != 0)
+		while(readPos < avail && (b & 0x80) != 0)
 		{
-			b = ReadUint8();
+			b = bytes[readPos++];
 			target <<= 7;
 			target |= (b & 0x7F);
 			writtenBits += 7;
-		};
+			if(readPos == avail)
+			{
+				streamPos += readPos;
+				avail = DataContainer().Read(bytes, streamPos, sizeof(bytes));
+				readPos = 0;
+			}
+		}
+		streamPos += readPos;
 
-		if(writtenBits > sizeof(target) * 8)
+		if(writtenBits > sizeof(target) * 8u)
 		{
 			// Overflow
 			target = Util::MaxValueOfType<T>(target);
@@ -1050,9 +1064,57 @@ public:
 
 };
 
+} // namespace detail
+
+typedef detail::FileReader<FileReaderTraitsDefault> FileReader;
+
+typedef detail::FileReader<FileReaderTraitsMemory> MemoryFileReader;
+
+
+#if defined(LIBOPENMPT_BUILD)
+
+// Initialize file reader object with pointer to data and data length.
+template <typename Tbyte> static inline FileReader make_FileReader(mpt::span<Tbyte> bytedata, const mpt::PathString *filename = nullptr)
+{
+	return FileReader(mpt::byte_cast<mpt::const_byte_span>(bytedata), filename);
+}
+
+#if defined(MPT_FILEREADER_STD_ISTREAM)
+
+#if defined(MPT_FILEREADER_CALLBACK_STREAM)
+
+// Initialize file reader object with a CallbackStream.
+static inline FileReader make_FileReader(CallbackStream s, const mpt::PathString *filename = nullptr)
+{
+	return FileReader(
+				FileDataContainerCallbackStreamSeekable::IsSeekable(s) ?
+					std::static_pointer_cast<IFileDataContainer>(std::make_shared<FileDataContainerCallbackStreamSeekable>(s))
+				:
+					std::static_pointer_cast<IFileDataContainer>(std::make_shared<FileDataContainerCallbackStream>(s))
+			, filename
+		);
+}
+#endif // MPT_FILEREADER_CALLBACK_STREAM
+	
+// Initialize file reader object with a std::istream.
+static inline FileReader make_FileReader(std::istream *s, const mpt::PathString *filename = nullptr)
+{
+	return FileReader(
+				FileDataContainerStdStreamSeekable::IsSeekable(s) ?
+					std::static_pointer_cast<IFileDataContainer>(std::make_shared<FileDataContainerStdStreamSeekable>(s))
+				:
+					std::static_pointer_cast<IFileDataContainer>(std::make_shared<FileDataContainerStdStream>(s))
+			, filename
+		);
+}
+
+#endif // MPT_FILEREADER_STD_ISTREAM
+
+#endif // LIBOPENMT_BUILD
+
 
 #if defined(MPT_ENABLE_FILEIO)
-// templated in order to reduce header inter-depoendencies
+// templated in order to reduce header inter-dependencies
 template <typename TInputFile>
 FileReader GetFileReader(TInputFile &file)
 {
@@ -1066,18 +1128,10 @@ FileReader GetFileReader(TInputFile &file)
 		{
 			return FileReader();
 		}
-		#ifdef MPT_ENABLE_FILEIO
-			return FileReader(tmp.first, tmp.second);
-		#else
-			return FileReader(tmp.first);
-		#endif
+		return FileReader(tmp.first, tmp.second);
 	#else
 		typename TInputFile::ContentsRef tmp = file.Get();
-		#ifdef MPT_ENABLE_FILEIO
-			return FileReader(mpt::as_span(tmp.first.data, tmp.first.size), tmp.second);
-		#else
-			return FileReader(mpt::as_span(tmp.first.data, tmp.first.size));
-		#endif
+		return FileReader(mpt::as_span(tmp.first.data, tmp.first.size), tmp.second);
 	#endif
 }
 #endif // MPT_ENABLE_FILEIO
diff --git a/common/FileReaderFwd.h b/common/FileReaderFwd.h
new file mode 100644
index 0000000..794d7fd
--- /dev/null
+++ b/common/FileReaderFwd.h
@@ -0,0 +1,42 @@
+/*
+ * FileReaderFwd.h
+ * ---------------
+ * Purpose: Forward declaration for class FileReader.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "typedefs.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+class FileReaderTraitsMemory;
+
+#if defined(MPT_FILEREADER_STD_ISTREAM)
+
+class FileReaderTraitsStdStream;
+
+typedef FileReaderTraitsStdStream FileReaderTraitsDefault;
+
+#else // !MPT_FILEREADER_STD_ISTREAM
+
+typedef FileReaderTraitsMemory FileReaderTraitsDefault;
+
+#endif // MPT_FILEREADER_STD_ISTREAM
+
+namespace detail {
+
+template <typename Ttraits>
+class FileReader;
+
+} // namespace detail
+
+typedef detail::FileReader<FileReaderTraitsDefault> FileReader;
+
+typedef detail::FileReader<FileReaderTraitsMemory> MemoryFileReader;
+
+OPENMPT_NAMESPACE_END
+
diff --git a/common/FlagSet.h b/common/FlagSet.h
index 62f0c26..51ec8a0 100644
--- a/common/FlagSet.h
+++ b/common/FlagSet.h
@@ -22,7 +22,7 @@ OPENMPT_NAMESPACE_BEGIN
 template <typename Tenum>
 struct enum_traits
 {
-	typedef typename mpt::make_unsigned<Tenum>::type store_type;
+	typedef typename std::make_unsigned<Tenum>::type store_type;
 };
 
 
@@ -38,50 +38,50 @@ public:
 private:
 	store_type bits;
 public:
-	forceinline enum_value_type() : bits(0) { }
-	forceinline enum_value_type(const enum_value_type &x) : bits(x.bits) { }
-	forceinline enum_value_type(enum_type x) : bits(static_cast<store_type>(x)) { }
+	MPT_CONSTEXPR11_FUN enum_value_type() : bits(0) { }
+	MPT_CONSTEXPR11_FUN enum_value_type(const enum_value_type &x) : bits(x.bits) { }
+	MPT_CONSTEXPR11_FUN enum_value_type(enum_type x) : bits(static_cast<store_type>(x)) { }
 private:
-	explicit forceinline enum_value_type(store_type x) : bits(x) { } // private in order to prevent accidental conversions. use from_bits.
-	forceinline operator store_type () const { return bits; }  // private in order to prevent accidental conversions. use as_bits.
+	explicit MPT_CONSTEXPR11_FUN enum_value_type(store_type x) : bits(x) { } // private in order to prevent accidental conversions. use from_bits.
+	MPT_CONSTEXPR11_FUN operator store_type () const { return bits; }  // private in order to prevent accidental conversions. use as_bits.
 public:
-	static forceinline enum_value_type from_bits(store_type bits) { return value_type(bits); }
-	forceinline enum_type as_enum() const { return static_cast<enum_t>(bits); }
-	forceinline store_type as_bits() const { return bits; }
+	static MPT_CONSTEXPR11_FUN enum_value_type from_bits(store_type bits) { return value_type(bits); }
+	MPT_CONSTEXPR11_FUN enum_type as_enum() const { return static_cast<enum_t>(bits); }
+	MPT_CONSTEXPR11_FUN store_type as_bits() const { return bits; }
 public:
-	forceinline operator bool () const { return bits != store_type(); }
-	forceinline bool operator ! () const { return bits == store_type(); }
+	MPT_CONSTEXPR11_FUN operator bool () const { return bits != store_type(); }
+	MPT_CONSTEXPR11_FUN bool operator ! () const { return bits == store_type(); }
 
-	forceinline const enum_value_type operator ~ () const { return enum_value_type(~bits); }
+	MPT_CONSTEXPR11_FUN const enum_value_type operator ~ () const { return enum_value_type(~bits); }
 
-	friend forceinline bool operator == (enum_value_type a, enum_value_type b) { return a.bits == b.bits; }
-	friend forceinline bool operator != (enum_value_type a, enum_value_type b) { return a.bits != b.bits; }
+	friend MPT_CONSTEXPR11_FUN bool operator == (enum_value_type a, enum_value_type b) { return a.bits == b.bits; }
+	friend MPT_CONSTEXPR11_FUN bool operator != (enum_value_type a, enum_value_type b) { return a.bits != b.bits; }
 	
-	friend forceinline bool operator == (enum_value_type a, enum_t b) { return a == enum_value_type(b); }
-	friend forceinline bool operator != (enum_value_type a, enum_t b) { return a != enum_value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (enum_value_type a, enum_t b) { return a == enum_value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (enum_value_type a, enum_t b) { return a != enum_value_type(b); }
 	
-	friend forceinline bool operator == (enum_t a, enum_value_type b) { return enum_value_type(a) == b; }
-	friend forceinline bool operator != (enum_t a, enum_value_type b) { return enum_value_type(a) != b; }
+	friend MPT_CONSTEXPR11_FUN bool operator == (enum_t a, enum_value_type b) { return enum_value_type(a) == b; }
+	friend MPT_CONSTEXPR11_FUN bool operator != (enum_t a, enum_value_type b) { return enum_value_type(a) != b; }
 	
-	friend forceinline const enum_value_type operator | (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits | b.bits); }
-	friend forceinline const enum_value_type operator & (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits & b.bits); }
-	friend forceinline const enum_value_type operator ^ (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits ^ b.bits); }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits | b.bits); }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits & b.bits); }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits ^ b.bits); }
 	
-	friend forceinline const enum_value_type operator | (enum_value_type a, enum_t b) { return a | enum_value_type(b); }
-	friend forceinline const enum_value_type operator & (enum_value_type a, enum_t b) { return a & enum_value_type(b); }
-	friend forceinline const enum_value_type operator ^ (enum_value_type a, enum_t b) { return a ^ enum_value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_value_type a, enum_t b) { return a | enum_value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_value_type a, enum_t b) { return a & enum_value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_value_type a, enum_t b) { return a ^ enum_value_type(b); }
 	
-	friend forceinline const enum_value_type operator | (enum_t a, enum_value_type b) { return enum_value_type(a) | b; }
-	friend forceinline const enum_value_type operator & (enum_t a, enum_value_type b) { return enum_value_type(a) & b; }
-	friend forceinline const enum_value_type operator ^ (enum_t a, enum_value_type b) { return enum_value_type(a) ^ b; }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_t a, enum_value_type b) { return enum_value_type(a) | b; }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_t a, enum_value_type b) { return enum_value_type(a) & b; }
+	friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_t a, enum_value_type b) { return enum_value_type(a) ^ b; }
 	
-	forceinline enum_value_type &operator |= (enum_value_type b) { *this = *this | b; return *this; }
-	forceinline enum_value_type &operator &= (enum_value_type b) { *this = *this & b; return *this; }
-	forceinline enum_value_type &operator ^= (enum_value_type b) { *this = *this ^ b; return *this; }
+	MPT_CONSTEXPR14_FUN enum_value_type &operator |= (enum_value_type b) { *this = *this | b; return *this; }
+	MPT_CONSTEXPR14_FUN enum_value_type &operator &= (enum_value_type b) { *this = *this & b; return *this; }
+	MPT_CONSTEXPR14_FUN enum_value_type &operator ^= (enum_value_type b) { *this = *this ^ b; return *this; }
 
-	forceinline enum_value_type &operator |= (enum_t b) { *this = *this | b; return *this; }
-	forceinline enum_value_type &operator &= (enum_t b) { *this = *this & b; return *this; }
-	forceinline enum_value_type &operator ^= (enum_t b) { *this = *this ^ b; return *this; }
+	MPT_CONSTEXPR14_FUN enum_value_type &operator |= (enum_t b) { *this = *this | b; return *this; }
+	MPT_CONSTEXPR14_FUN enum_value_type &operator &= (enum_t b) { *this = *this & b; return *this; }
+	MPT_CONSTEXPR14_FUN enum_value_type &operator ^= (enum_t b) { *this = *this ^ b; return *this; }
 
 };
 
@@ -98,46 +98,46 @@ public:
 private:
 	enum_type value;
 public:
-	explicit forceinline Enum(enum_type val) : value(val) { }
-	forceinline operator enum_type () const { return value; }
-	forceinline Enum &operator = (enum_type val) { value = val; return *this; }
+	explicit MPT_CONSTEXPR11_FUN Enum(enum_type val) : value(val) { }
+	MPT_CONSTEXPR11_FUN operator enum_type () const { return value; }
+	MPT_CONSTEXPR14_FUN Enum &operator = (enum_type val) { value = val; return *this; }
 public:
-	forceinline const value_type operator ~ () const { return ~value_type(value); }
+	MPT_CONSTEXPR11_FUN const value_type operator ~ () const { return ~value_type(value); }
 
-	friend forceinline bool operator == (self_type a, self_type b) { return value_type(a) == value_type(b); }
-	friend forceinline bool operator != (self_type a, self_type b) { return value_type(a) != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, self_type b) { return value_type(a) == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, self_type b) { return value_type(a) != value_type(b); }
 
-	friend forceinline bool operator == (self_type a, value_type b) { return value_type(a) == value_type(b); }
-	friend forceinline bool operator != (self_type a, value_type b) { return value_type(a) != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, value_type b) { return value_type(a) == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, value_type b) { return value_type(a) != value_type(b); }
 
-	friend forceinline bool operator == (value_type a, self_type b) { return value_type(a) == value_type(b); }
-	friend forceinline bool operator != (value_type a, self_type b) { return value_type(a) != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (value_type a, self_type b) { return value_type(a) == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (value_type a, self_type b) { return value_type(a) != value_type(b); }
 
-	friend forceinline bool operator == (self_type a, enum_type b) { return value_type(a) == value_type(b); }
-	friend forceinline bool operator != (self_type a, enum_type b) { return value_type(a) != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, enum_type b) { return value_type(a) == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, enum_type b) { return value_type(a) != value_type(b); }
 
-	friend forceinline bool operator == (enum_type a, self_type b) { return value_type(a) == value_type(b); }
-	friend forceinline bool operator != (enum_type a, self_type b) { return value_type(a) != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (enum_type a, self_type b) { return value_type(a) == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (enum_type a, self_type b) { return value_type(a) != value_type(b); }
 
-	friend forceinline const value_type operator | (self_type a, self_type b) { return value_type(a) | value_type(b); }
-	friend forceinline const value_type operator & (self_type a, self_type b) { return value_type(a) & value_type(b); }
-	friend forceinline const value_type operator ^ (self_type a, self_type b) { return value_type(a) ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, self_type b) { return value_type(a) | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, self_type b) { return value_type(a) & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, self_type b) { return value_type(a) ^ value_type(b); }
 
-	friend forceinline const value_type operator | (self_type a, value_type b) { return value_type(a) | value_type(b); }
-	friend forceinline const value_type operator & (self_type a, value_type b) { return value_type(a) & value_type(b); }
-	friend forceinline const value_type operator ^ (self_type a, value_type b) { return value_type(a) ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, value_type b) { return value_type(a) | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, value_type b) { return value_type(a) & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, value_type b) { return value_type(a) ^ value_type(b); }
 
-	friend forceinline const value_type operator | (value_type a, self_type b) { return value_type(a) | value_type(b); }
-	friend forceinline const value_type operator & (value_type a, self_type b) { return value_type(a) & value_type(b); }
-	friend forceinline const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (value_type a, self_type b) { return value_type(a) | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (value_type a, self_type b) { return value_type(a) & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ value_type(b); }
 
-	friend forceinline const value_type operator | (self_type a, enum_type b) { return value_type(a) | value_type(b); }
-	friend forceinline const value_type operator & (self_type a, enum_type b) { return value_type(a) & value_type(b); }
-	friend forceinline const value_type operator ^ (self_type a, enum_type b) { return value_type(a) ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, enum_type b) { return value_type(a) | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, enum_type b) { return value_type(a) & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, enum_type b) { return value_type(a) ^ value_type(b); }
 
-	friend forceinline const value_type operator | (enum_type a, self_type b) { return value_type(a) | value_type(b); }
-	friend forceinline const value_type operator & (enum_type a, self_type b) { return value_type(a) & value_type(b); }
-	friend forceinline const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (enum_type a, self_type b) { return value_type(a) | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (enum_type a, self_type b) { return value_type(a) & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ value_type(b); }
 
 };
 
@@ -155,37 +155,33 @@ private:
 
 	// support truncated store_type ... :
 	store_type bits_;
-	static forceinline store_type store_from_value(value_type bits) { return static_cast<store_type>(bits.as_bits()); }
-	static forceinline value_type value_from_store(store_type bits) { return value_type::from_bits(static_cast<typename value_type::store_type>(bits)); }
+	static MPT_CONSTEXPR11_FUN store_type store_from_value(value_type bits) { return static_cast<store_type>(bits.as_bits()); }
+	static MPT_CONSTEXPR11_FUN value_type value_from_store(store_type bits) { return value_type::from_bits(static_cast<typename value_type::store_type>(bits)); }
 
-	forceinline void store(value_type bits) { bits_ = store_from_value(bits); }
-	forceinline value_type load() const { return value_from_store(bits_); }
+	MPT_CONSTEXPR14_FUN FlagSet & store(value_type bits) { bits_ = store_from_value(bits); return *this; }
+	MPT_CONSTEXPR11_FUN value_type load() const { return value_from_store(bits_); }
 
 public:
 
 	// Default constructor (no flags set)
-	forceinline FlagSet() : bits_(store_from_value(value_type()))
+	MPT_CONSTEXPR11_FUN FlagSet() : bits_(store_from_value(value_type()))
 	{
-		return;
 	}
 
 	// Value constructor
-	forceinline FlagSet(value_type flags) : bits_(store_from_value(value_type(flags)))
+	MPT_CONSTEXPR11_FUN FlagSet(value_type flags) : bits_(store_from_value(value_type(flags)))
 	{
-		return;
 	}
 
-	forceinline FlagSet(enum_type flag) : bits_(store_from_value(value_type(flag)))
+	MPT_CONSTEXPR11_FUN FlagSet(enum_type flag) : bits_(store_from_value(value_type(flag)))
 	{
-		return;
 	}
 
-	explicit forceinline FlagSet(store_type flags) : bits_(store_from_value(value_type::from_bits(flags)))
+	explicit MPT_CONSTEXPR11_FUN FlagSet(store_type flags) : bits_(store_from_value(value_type::from_bits(flags)))
 	{
-		return;
 	}
 	
-	forceinline operator bool () const
+	MPT_CONSTEXPR11_FUN operator bool () const
 	{
 		return load();
 	}
@@ -196,23 +192,23 @@ public:
 	// solution which just warns in some cases.
 	// The macro-based extended instrument fields writer in InstrumentExtensions.cpp currently needs this conversion,
 	// so it is not marked deprecated (for now).
-	/*MPT_DEPRECATED*/ forceinline operator store_type () const
+	/*MPT_DEPRECATED*/ MPT_CONSTEXPR11_FUN operator store_type () const
 	{
 		return load().as_bits();
 	}
 	
-	forceinline value_type value() const
+	MPT_CONSTEXPR11_FUN value_type value() const
 	{
 		return load();
 	}
 	
-	forceinline operator value_type () const
+	MPT_CONSTEXPR11_FUN operator value_type () const
 	{
 		return load();
 	}
 
 	// Test if one or more flags are set. Returns true if at least one of the given flags is set.
-	forceinline bool operator[] (value_type flags) const
+	MPT_CONSTEXPR11_FUN bool operator[] (value_type flags) const
 	{
 		return test(flags);
 	}
@@ -231,187 +227,182 @@ public:
 	}
 	
 	// Set one or more flags.
-	forceinline FlagSet &set(value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &set(value_type flags)
 	{
-		store(load() | flags);
-		return *this;
+		return store(load() | flags);
 	}
 
 	// Set or clear one or more flags.
-	forceinline FlagSet &set(value_type flags, bool val)
+	MPT_CONSTEXPR14_FUN FlagSet &set(value_type flags, bool val)
 	{
-		store((val ? (load() | flags) : (load() & ~flags)));
-		return *this;
+		return store((val ? (load() | flags) : (load() & ~flags)));
 	}
 
 	// Clear or flags.
-	forceinline FlagSet &reset()
+	MPT_CONSTEXPR14_FUN FlagSet &reset()
 	{
-		store(value_type());
-		return *this;
+		return store(value_type());
 	}
 
 	// Clear one or more flags.
-	forceinline FlagSet &reset(value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &reset(value_type flags)
 	{
-		store(load() & ~flags);
-		return *this;
+		return store(load() & ~flags);
 	}
 
 	// Toggle all flags.
-	forceinline FlagSet &flip()
+	MPT_CONSTEXPR14_FUN FlagSet &flip()
 	{
-		store(~load());
-		return *this;
+		return store(~load());
 	}
 
 	// Toggle one or more flags.
-	forceinline FlagSet &flip(value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &flip(value_type flags)
 	{
-		store(load() ^ flags);
-		return *this;
+		return store(load() ^ flags);
 	}
 
 	// Returns the size of the flag set in bytes
-	forceinline std::size_t size() const
+	MPT_CONSTEXPR11_FUN std::size_t size() const
 	{
 		return sizeof(store_type);
 	}
 
 	// Returns the size of the flag set in bits
-	forceinline std::size_t size_bits() const
+	MPT_CONSTEXPR11_FUN std::size_t size_bits() const
 	{
 		return size() * 8;
 	}
 	
 	// Test if one or more flags are set. Returns true if at least one of the given flags is set.
-	forceinline bool test(value_type flags) const
+	MPT_CONSTEXPR11_FUN bool test(value_type flags) const
 	{
 		return (load() & flags);
 	}
 
 	// Test if all specified flags are set.
-	forceinline bool test_all(value_type flags) const
+	MPT_CONSTEXPR11_FUN bool test_all(value_type flags) const
 	{
 		return (load() & flags) == flags;
 	}
 
+	// Test if any but the specified flags are set.
+	MPT_CONSTEXPR11_FUN bool test_any_except(value_type flags) const
+	{
+		return (load() & ~flags);
+	}
+
 	// Test if any flag is set.
-	forceinline bool any() const
+	MPT_CONSTEXPR11_FUN bool any() const
 	{
 		return load();
 	}
 
 	// Test if no flags are set.
-	forceinline bool none() const
+	MPT_CONSTEXPR11_FUN bool none() const
 	{
 		return !load();
 	}
 	
-	forceinline store_type GetRaw() const
+	MPT_CONSTEXPR11_FUN store_type GetRaw() const
 	{
 		return bits_;
 	}
 
-	forceinline void SetRaw(store_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet & SetRaw(store_type flags)
 	{
 		bits_ = flags;
+		return *this;
 	}
 
-	forceinline FlagSet &operator = (value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &operator = (value_type flags)
 	{
-		store(flags);
-		return *this;
+		return store(flags);
 	}
 	
-	forceinline FlagSet &operator = (enum_type flag)
+	MPT_CONSTEXPR14_FUN FlagSet &operator = (enum_type flag)
 	{
-		store(flag);
-		return *this;
+		return store(flag);
 	}
 
-	forceinline FlagSet &operator = (FlagSet flags)
+	MPT_CONSTEXPR14_FUN FlagSet &operator = (FlagSet flags)
 	{
-		store(flags.load());
-		return *this;
+		return store(flags.load());
 	}
 
-	forceinline FlagSet &operator &= (value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &operator &= (value_type flags)
 	{
-		store(load() & flags);
-		return *this;
+		return store(load() & flags);
 	}
 
-	forceinline FlagSet &operator |= (value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &operator |= (value_type flags)
 	{
-		store(load() | flags);
-		return *this;
+		return store(load() | flags);
 	}
 
-	forceinline FlagSet &operator ^= (value_type flags)
+	MPT_CONSTEXPR14_FUN FlagSet &operator ^= (value_type flags)
 	{
-		store(load() ^ flags);
-		return *this;
+		return store(load() ^ flags);
 	}
 	
-	friend forceinline bool operator == (self_type a, self_type b) { return a.load() == b.load(); }
-	friend forceinline bool operator != (self_type a, self_type b) { return a.load() != b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, self_type b) { return a.load() == b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, self_type b) { return a.load() != b.load(); }
 
-	friend forceinline bool operator == (self_type a, value_type b) { return a.load() == value_type(b); }
-	friend forceinline bool operator != (self_type a, value_type b) { return a.load() != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, value_type b) { return a.load() == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, value_type b) { return a.load() != value_type(b); }
 
-	friend forceinline bool operator == (value_type a, self_type b) { return value_type(a) == b.load(); }
-	friend forceinline bool operator != (value_type a, self_type b) { return value_type(a) != b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (value_type a, self_type b) { return value_type(a) == b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (value_type a, self_type b) { return value_type(a) != b.load(); }
 
-	friend forceinline bool operator == (self_type a, enum_type b) { return a.load() == value_type(b); }
-	friend forceinline bool operator != (self_type a, enum_type b) { return a.load() != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, enum_type b) { return a.load() == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, enum_type b) { return a.load() != value_type(b); }
 
-	friend forceinline bool operator == (enum_type a, self_type b) { return value_type(a) == b.load(); }
-	friend forceinline bool operator != (enum_type a, self_type b) { return value_type(a) != b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (enum_type a, self_type b) { return value_type(a) == b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (enum_type a, self_type b) { return value_type(a) != b.load(); }
 
-	friend forceinline bool operator == (self_type a, Enum<enum_type> b) { return a.load() == value_type(b); }
-	friend forceinline bool operator != (self_type a, Enum<enum_type> b) { return a.load() != value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, Enum<enum_type> b) { return a.load() == value_type(b); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, Enum<enum_type> b) { return a.load() != value_type(b); }
 
-	friend forceinline bool operator == (Enum<enum_type> a, self_type b) { return value_type(a) == b.load(); }
-	friend forceinline bool operator != (Enum<enum_type> a, self_type b) { return value_type(a) != b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator == (Enum<enum_type> a, self_type b) { return value_type(a) == b.load(); }
+	friend MPT_CONSTEXPR11_FUN bool operator != (Enum<enum_type> a, self_type b) { return value_type(a) != b.load(); }
 
-	friend forceinline const value_type operator | (self_type a, self_type b) { return a.load() | b.load(); }
-	friend forceinline const value_type operator & (self_type a, self_type b) { return a.load() & b.load(); }
-	friend forceinline const value_type operator ^ (self_type a, self_type b) { return a.load() ^ b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, self_type b) { return a.load() | b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, self_type b) { return a.load() & b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, self_type b) { return a.load() ^ b.load(); }
 
-	friend forceinline const value_type operator | (self_type a, value_type b) { return a.load() | value_type(b); }
-	friend forceinline const value_type operator & (self_type a, value_type b) { return a.load() & value_type(b); }
-	friend forceinline const value_type operator ^ (self_type a, value_type b) { return a.load() ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, value_type b) { return a.load() | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, value_type b) { return a.load() & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, value_type b) { return a.load() ^ value_type(b); }
 
-	friend forceinline const value_type operator | (value_type a, self_type b) { return value_type(a) | b.load(); }
-	friend forceinline const value_type operator & (value_type a, self_type b) { return value_type(a) & b.load(); }
-	friend forceinline const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (value_type a, self_type b) { return value_type(a) | b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (value_type a, self_type b) { return value_type(a) & b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ b.load(); }
 
-	friend forceinline const value_type operator | (self_type a, enum_type b) { return a.load() | value_type(b); }
-	friend forceinline const value_type operator & (self_type a, enum_type b) { return a.load() & value_type(b); }
-	friend forceinline const value_type operator ^ (self_type a, enum_type b) { return a.load() ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, enum_type b) { return a.load() | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, enum_type b) { return a.load() & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, enum_type b) { return a.load() ^ value_type(b); }
 
-	friend forceinline const value_type operator | (enum_type a, self_type b) { return value_type(a) | b.load(); }
-	friend forceinline const value_type operator & (enum_type a, self_type b) { return value_type(a) & b.load(); }
-	friend forceinline const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (enum_type a, self_type b) { return value_type(a) | b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (enum_type a, self_type b) { return value_type(a) & b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ b.load(); }
 
-	friend forceinline const value_type operator | (self_type a, Enum<enum_type> b) { return a.load() | value_type(b); }
-	friend forceinline const value_type operator & (self_type a, Enum<enum_type> b) { return a.load() & value_type(b); }
-	friend forceinline const value_type operator ^ (self_type a, Enum<enum_type> b) { return a.load() ^ value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, Enum<enum_type> b) { return a.load() | value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, Enum<enum_type> b) { return a.load() & value_type(b); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, Enum<enum_type> b) { return a.load() ^ value_type(b); }
 
-	friend forceinline const value_type operator | (Enum<enum_type> a, self_type b) { return value_type(a) | b.load(); }
-	friend forceinline const value_type operator & (Enum<enum_type> a, self_type b) { return value_type(a) & b.load(); }
-	friend forceinline const value_type operator ^ (Enum<enum_type> a, self_type b) { return value_type(a) ^ b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator | (Enum<enum_type> a, self_type b) { return value_type(a) | b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator & (Enum<enum_type> a, self_type b) { return value_type(a) & b.load(); }
+	friend MPT_CONSTEXPR11_FUN const value_type operator ^ (Enum<enum_type> a, self_type b) { return value_type(a) ^ b.load(); }
 
 };
 
 
 // Declare typesafe logical operators for enum_t
 #define MPT_DECLARE_ENUM(enum_t) \
-	forceinline enum_value_type<enum_t> operator | (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) | enum_value_type<enum_t>(b); } \
-	forceinline enum_value_type<enum_t> operator & (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) & enum_value_type<enum_t>(b); } \
-	forceinline enum_value_type<enum_t> operator ^ (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) ^ enum_value_type<enum_t>(b); } \
-	forceinline enum_value_type<enum_t> operator ~ (enum_t a) { return ~enum_value_type<enum_t>(a); } \
+	MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator | (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) | enum_value_type<enum_t>(b); } \
+	MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator & (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) & enum_value_type<enum_t>(b); } \
+	MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator ^ (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) ^ enum_value_type<enum_t>(b); } \
+	MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator ~ (enum_t a) { return ~enum_value_type<enum_t>(a); } \
 /**/
 
 // backwards compatibility
diff --git a/common/Logging.cpp b/common/Logging.cpp
index b07f692..7d2158e 100644
--- a/common/Logging.cpp
+++ b/common/Logging.cpp
@@ -13,7 +13,7 @@
 #include "Logging.h"
 #include "mptFileIO.h"
 #if defined(MODPLUG_TRACKER)
-#include "mptAtomic.h"
+#include <atomic>
 #endif
 #include "version.h"
 
@@ -89,7 +89,6 @@ bool IsFacilityActive(const char *facility)
 
 
 void Logger::SendLogMessage(const Context &context, LogLevel level, const char *facility, const mpt::ustring &text)
-//-----------------------------------------------------------------------------------------------------------------
 {
 #ifdef MPT_LOG_IS_DISABLED
 	MPT_UNREFERENCED_PARAMETER(context);
@@ -185,13 +184,11 @@ void Logger::SendLogMessage(const Context &context, LogLevel level, const char *
 }
 
 void LegacyLogger::operator () (const AnyStringLocale &text)
-//----------------------------------------------------------
 {
 	SendLogMessage(context, MPT_LEGACY_LOGLEVEL, "", text);
 }
 
 void LegacyLogger::operator () (const char *format, ...)
-//------------------------------------------------------
 {
 	static const std::size_t LOGBUF_SIZE = 1024;
 	char message[LOGBUF_SIZE];
@@ -204,7 +201,6 @@ void LegacyLogger::operator () (const char *format, ...)
 }
 
 void LegacyLogger::operator () (LogLevel level, const mpt::ustring &text)
-//-----------------------------------------------------------------------
 {
 	SendLogMessage(context, level, "", text);
 }
@@ -254,7 +250,7 @@ inline bool operator < (const Entry &a, const Entry &b)
 
 static std::vector<mpt::log::Trace::Entry> Entries;
 
-static mpt::atomic_uint32_t NextIndex = 0;
+static std::atomic<uint32> NextIndex(0);
 
 static uint32 ThreadIdGUI = 0;
 static uint32 ThreadIdAudio = 0;
diff --git a/common/Logging.h b/common/Logging.h
index 01a1ecc..9c96f92 100644
--- a/common/Logging.h
+++ b/common/Logging.h
@@ -121,7 +121,7 @@ extern bool ConsoleEnabled;
 void SetFacilities(const std::string &solo, const std::string &blocked);
 bool IsFacilityActive(const char *facility);
 #else
-static forceinline bool IsFacilityActive(const char * /*facility*/ ) { return true; }
+static MPT_FORCEINLINE bool IsFacilityActive(const char * /*facility*/ ) { return true; }
 #endif
 
 
@@ -133,14 +133,14 @@ struct Context
 	const char * const file;
 	const int line;
 	const char * const function;
-	forceinline Context(const char *file, int line, const char *function)
+	MPT_FORCEINLINE Context(const char *file, int line, const char *function)
 		: file(file)
 		, line(line)
 		, function(function)
 	{
 		return;
 	}
-	forceinline Context(const Context &c)
+	MPT_FORCEINLINE Context(const Context &c)
 		: file(c.file)
 		, line(c.line)
 		, function(c.function)
@@ -162,7 +162,7 @@ public:
 	void SendLogMessage(const Context &context, LogLevel level, const char *facility, const mpt::ustring &text);
 public:
 	// facility:ASCII, text:ASCII (only string literals)
-	template <std::size_t size> forceinline void SendLogMessage(const Context &context, LogLevel level, const char *facility, const char (&text)[size])
+	template <std::size_t size> MPT_FORCEINLINE void SendLogMessage(const Context &context, LogLevel level, const char *facility, const char (&text)[size])
 	{
 		SendLogMessage(context, level, facility, mpt::ToUnicode(mpt::CharsetASCII, text));
 	}
diff --git a/common/Profiler.cpp b/common/Profiler.cpp
index 14bd973..933097d 100644
--- a/common/Profiler.cpp
+++ b/common/Profiler.cpp
@@ -112,7 +112,7 @@ std::string Profiler::DumpProfiles()
 			case Profiler::Audio: cat = "Audio"; break;
 			case Profiler::Notify: cat = "Notify"; break;
 			}
-			ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::Format("%6.3f").ToString(stats.usage * 100.0) + "%\r\n";
+			ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::fmt::f("%6.3f", stats.usage * 100.0) + "%\r\n";
 		}
 	}
 	ret += "\r\n";
diff --git a/common/StringFixer.h b/common/StringFixer.h
index d1d2e9f..cff79ef 100644
--- a/common/StringFixer.h
+++ b/common/StringFixer.h
@@ -31,14 +31,12 @@ namespace mpt { namespace String
 	// Size of the array must be known at compile time.
 	template <size_t size>
 	void SetNullTerminator(char (&buffer)[size])
-	//------------------------------------------
 	{
 		STATIC_ASSERT(size > 0);
 		buffer[size - 1] = 0;
 	}
 
 	inline void SetNullTerminator(char *buffer, size_t size)
-	//------------------------------------------------------
 	{
 		MPT_ASSERT(size > 0);
 		buffer[size - 1] = 0;
@@ -46,14 +44,12 @@ namespace mpt { namespace String
 
 	template <size_t size>
 	void SetNullTerminator(wchar_t (&buffer)[size])
-	//---------------------------------------------
 	{
 		STATIC_ASSERT(size > 0);
 		buffer[size - 1] = 0;
 	}
 
 	inline void SetNullTerminator(wchar_t *buffer, size_t size)
-	//---------------------------------------------------------
 	{
 		MPT_ASSERT(size > 0);
 		buffer[size - 1] = 0;
@@ -63,7 +59,6 @@ namespace mpt { namespace String
 	// Remove any chars after the first null char
 	template <size_t size>
 	void FixNullString(char (&buffer)[size])
-	//--------------------------------------
 	{
 		STATIC_ASSERT(size > 0);
 		SetNullTerminator(buffer);
@@ -81,7 +76,6 @@ namespace mpt { namespace String
 	}
 
 	inline void FixNullString(std::string & str)
-	//------------------------------------------
 	{
 		for(std::size_t i = 0; i < str.length(); ++i)
 		{
@@ -123,12 +117,11 @@ namespace mpt { namespace String
 	// Copy a string from srcBuffer to destBuffer using a given read mode.
 	// Used for reading strings from files.
 	// Only use this version of the function if the size of the source buffer is variable.
-	template <ReadWriteMode mode>
-	void Read(std::string &dest, const char *srcBuffer, size_t srcSize)
-	//-----------------------------------------------------------------
+	template <ReadWriteMode mode, typename Tbyte>
+	void Read(std::string &dest, const Tbyte *srcBuffer, size_t srcSize)
 	{
 
-		const char *src = srcBuffer;
+		const char *src = mpt::byte_cast<const char*>(srcBuffer);
 
 		dest.clear();
 
@@ -148,8 +141,9 @@ namespace mpt { namespace String
 			try
 			{
 				dest.assign(src, std::find(src, src + srcSize, '\0'));
-			} catch(MPTMemoryException)
+			} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 			{
+				MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 			}
 
 		} else if(mode == spacePadded || mode == spacePaddedNull)
@@ -165,35 +159,54 @@ namespace mpt { namespace String
 
 				// Trim trailing spaces.
 				dest = mpt::String::RTrim(dest);
-			} catch(MPTMemoryException)
+			} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 			{
+				MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 			}
 
 		}
 	}
 
+	// Copy a charset encoded string from srcBuffer to destBuffer using a given read mode.
+	// Used for reading strings from files.
+	// Only use this version of the function if the size of the source buffer is variable.
+	template <ReadWriteMode mode, typename Tbyte>
+	void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte *srcBuffer, size_t srcSize)
+	{
+		std::string tmp;
+		Read<mode>(tmp, srcBuffer, srcSize);
+		dest = mpt::ToUnicode(charset, tmp);
+	}
+
 	// Used for reading strings from files.
 	// Preferrably use this version of the function, it is safer.
-	template <ReadWriteMode mode, size_t srcSize>
-	void Read(std::string &dest, const char (&srcBuffer)[srcSize])
-	//------------------------------------------------------------
+	template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
+	void Read(std::string &dest, const Tbyte (&srcBuffer)[srcSize])
 	{
 		STATIC_ASSERT(srcSize > 0);
 		Read<mode>(dest, srcBuffer, srcSize);
 	}
 
+	// Used for reading charset encoded strings from files.
+	// Preferrably use this version of the function, it is safer.
+	template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
+	void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte(&srcBuffer)[srcSize])
+	{
+		std::string tmp;
+		Read<mode>(tmp, srcBuffer);
+		dest = mpt::ToUnicode(charset, tmp);
+	}
 
 	// Copy a string from srcBuffer to destBuffer using a given read mode.
 	// Used for reading strings from files.
 	// Only use this version of the function if the size of the source buffer is variable.
-	template <ReadWriteMode mode, size_t destSize>
-	void Read(char (&destBuffer)[destSize], const char *srcBuffer, size_t srcSize)
-	//----------------------------------------------------------------------------
+	template <ReadWriteMode mode, size_t destSize, typename Tbyte>
+	void Read(char (&destBuffer)[destSize], const Tbyte *srcBuffer, size_t srcSize)
 	{
 		STATIC_ASSERT(destSize > 0);
 
 		char *dst = destBuffer;
-		const char *src = srcBuffer;
+		const char *src = mpt::byte_cast<const char*>(srcBuffer);
 
 		if(mode == nullTerminated || mode == spacePaddedNull)
 		{
@@ -238,9 +251,8 @@ namespace mpt { namespace String
 
 	// Used for reading strings from files.
 	// Preferrably use this version of the function, it is safer.
-	template <ReadWriteMode mode, size_t destSize, size_t srcSize>
-	void Read(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
-	//-----------------------------------------------------------------------
+	template <ReadWriteMode mode, size_t destSize, size_t srcSize, typename Tbyte>
+	void Read(char (&destBuffer)[destSize], const Tbyte (&srcBuffer)[srcSize])
 	{
 		STATIC_ASSERT(destSize > 0);
 		STATIC_ASSERT(srcSize > 0);
@@ -253,7 +265,6 @@ namespace mpt { namespace String
 	// otherwise use one of the safer overloads below.
 	template <ReadWriteMode mode>
 	void Write(char *destBuffer, const size_t destSize, const char *srcBuffer, const size_t srcSize)
-	//----------------------------------------------------------------------------------------------
 	{
 		MPT_ASSERT(destSize > 0);
 
@@ -296,10 +307,9 @@ namespace mpt { namespace String
 	// Only use this version of the function if the size of the source buffer is variable and the destination buffer also has variable size.
 	template <ReadWriteMode mode>
 	void Write(std::vector<char> &destBuffer, const char *srcBuffer, const size_t srcSize)
-	//------------------------------------------------------------------------------------
 	{
 		MPT_ASSERT(destBuffer.size() > 0);
-		Write<mode>(&destBuffer[0], destBuffer.size(), srcBuffer, srcSize);
+		Write<mode>(destBuffer.data(), destBuffer.size(), srcBuffer, srcSize);
 	}
 
 	// Copy a string from srcBuffer to destBuffer using a given write mode.
@@ -307,7 +317,6 @@ namespace mpt { namespace String
 	// Only use this version of the function if the size of the source buffer is variable.
 	template <ReadWriteMode mode, size_t destSize>
 	void Write(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize)
-	//-----------------------------------------------------------------------------------
 	{
 		STATIC_ASSERT(destSize > 0);
 		Write<mode>(destBuffer, destSize, srcBuffer, srcSize);
@@ -318,7 +327,6 @@ namespace mpt { namespace String
 	// Preferrably use this version of the function, it is safer.
 	template <ReadWriteMode mode, size_t destSize, size_t srcSize>
 	void Write(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
-	//------------------------------------------------------------------------
 	{
 		STATIC_ASSERT(destSize > 0);
 		STATIC_ASSERT(srcSize > 0);
@@ -327,7 +335,6 @@ namespace mpt { namespace String
 
 	template <ReadWriteMode mode>
 	void Write(char *destBuffer, const size_t destSize, const std::string &src)
-	//-------------------------------------------------------------------------
 	{
 		MPT_ASSERT(destSize > 0);
 		Write<mode>(destBuffer, destSize, src.c_str(), src.length());
@@ -335,7 +342,6 @@ namespace mpt { namespace String
 
 	template <ReadWriteMode mode>
 	void Write(std::vector<char> &destBuffer, const std::string &src)
-	//---------------------------------------------------------------
 	{
 		MPT_ASSERT(destBuffer.size() > 0);
 		Write<mode>(destBuffer, src.c_str(), src.length());
@@ -343,7 +349,6 @@ namespace mpt { namespace String
 
 	template <ReadWriteMode mode, size_t destSize>
 	void Write(char (&destBuffer)[destSize], const std::string &src)
-	//--------------------------------------------------------------
 	{
 		STATIC_ASSERT(destSize > 0);
 		Write<mode, destSize>(destBuffer, src.c_str(), src.length());
@@ -353,7 +358,6 @@ namespace mpt { namespace String
 	// Copy from a char array to a fixed size char array.
 	template <size_t destSize>
 	void CopyN(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
-	//------------------------------------------------------------------------------------------------------------------------
 	{
 		const size_t copySize = std::min(destSize - 1u, srcSize);
 		std::strncpy(destBuffer, srcBuffer, copySize);
@@ -362,7 +366,6 @@ namespace mpt { namespace String
 
 	// Copy at most srcSize characters from srcBuffer to a std::string.
 	static inline void CopyN(std::string &dest, const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
-	//---------------------------------------------------------------------------------------------------------------------------
 	{
 		dest.assign(srcBuffer, srcBuffer + mpt::strnlen(srcBuffer, srcSize));
 	}
@@ -371,7 +374,6 @@ namespace mpt { namespace String
 	// Copy from one fixed size char array to another one.
 	template <size_t destSize, size_t srcSize>
 	void Copy(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
-	//-----------------------------------------------------------------------
 	{
 		CopyN(destBuffer, srcBuffer, srcSize);
 	}
@@ -379,7 +381,6 @@ namespace mpt { namespace String
 	// Copy from a std::string to a fixed size char array.
 	template <size_t destSize>
 	void Copy(char (&destBuffer)[destSize], const std::string &src)
-	//-------------------------------------------------------------
 	{
 		CopyN(destBuffer, src.c_str(), src.length());
 	}
@@ -387,14 +388,12 @@ namespace mpt { namespace String
 	// Copy from a fixed size char array to a std::string.
 	template <size_t srcSize>
 	void Copy(std::string &dest, const char (&srcBuffer)[srcSize])
-	//------------------------------------------------------------
 	{
 		CopyN(dest, srcBuffer, srcSize);
 	}
 
 	// Copy from a std::string to a std::string.
 	static inline void Copy(std::string &dest, const std::string &src)
-	//----------------------------------------------------------------
 	{
 		dest.assign(src);
 	}
diff --git a/common/misc_util.cpp b/common/misc_util.cpp
index ce731fd..a30b7fb 100644
--- a/common/misc_util.cpp
+++ b/common/misc_util.cpp
@@ -75,21 +75,22 @@ static inline bool DecodeByte(uint8 &byte, MPT_UCHAR_TYPE c1, MPT_UCHAR_TYPE c2)
 	return true;
 }
 
-mpt::ustring BinToHex(const std::vector<char> &src)
+mpt::ustring BinToHex(mpt::const_byte_span src)
 {
 	mpt::ustring result;
-	for(std::size_t i = 0; i < src.size(); ++i)
+	result.reserve(src.size() * 2);
+	for(uint8 byte : src)
 	{
-		uint8 byte = src[i];
-		result.push_back(EncodeNibble[(byte&0xf0)>>4]);
-		result.push_back(EncodeNibble[byte&0x0f]);
+		result.push_back(EncodeNibble[(byte & 0xf0) >> 4]);
+		result.push_back(EncodeNibble[byte & 0x0f]);
 	}
 	return result;
 }
 
-std::vector<char> HexToBin(const mpt::ustring &src)
+std::vector<mpt::byte> HexToBin(const mpt::ustring &src)
 {
-	std::vector<char> result;
+	std::vector<mpt::byte> result;
+	result.reserve(src.size() / 2);
 	for(std::size_t i = 0; (i + 1) < src.size(); i += 2)
 	{
 		uint8 byte = 0;
@@ -106,21 +107,29 @@ std::vector<char> HexToBin(const mpt::ustring &src)
 } // namespace Util
 
 
+#if defined(MODPLUG_TRACKER) || (defined(LIBOPENMPT_BUILD) && defined(LIBOPENMPT_BUILD_TEST))
+
 namespace mpt
 {
 
 std::string getenv(const std::string &env_var, const std::string &def)
-//--------------------------------------------------------------------
 {
+#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+	MPT_UNREFERENCED_PARAMETER(env_var);
+	return def;
+#else
 	const char *val = std::getenv(env_var.c_str());
 	if(!val)
 	{
 		return def;
 	}
 	return val;
+#endif
 }
 
 } // namespace mpt
 
+#endif // MODPLUG_TRACKER || (LIBOPENMPT_BUILD && LIBOPENMPT_BUILD_TEST)
+
 
 OPENMPT_NAMESPACE_END
diff --git a/common/misc_util.h b/common/misc_util.h
index 2b5f880..b86cb24 100644
--- a/common/misc_util.h
+++ b/common/misc_util.h
@@ -14,7 +14,6 @@
 #include "mptCPU.h"
 #include "mptOS.h"
 #include "mptTime.h"
-#include "mptUUID.h"
 #include "mptLibrary.h"
 #include "mptTypeTraits.h"
 
@@ -53,7 +52,6 @@ namespace mpt { namespace String {
 // No escaping is performed.
 template<typename T>
 mpt::ustring Combine(const std::vector<T> &vals, const mpt::ustring &sep=MPT_USTRING(","))
-//----------------------------------------------------------------------------------------
 {
 	mpt::ustring str;
 	for(std::size_t i = 0; i < vals.size(); ++i)
@@ -62,13 +60,12 @@ mpt::ustring Combine(const std::vector<T> &vals, const mpt::ustring &sep=MPT_UST
 		{
 			str += sep;
 		}
-		str += mpt::ToUString(vals[i]);
+		str += mpt::ufmt::val(vals[i]);
 	}
 	return str;
 }
 template<typename T>
 std::string Combine(const std::vector<T> &vals, const std::string &sep=std::string(","))
-//--------------------------------------------------------------------------------------
 {
 	std::string str;
 	for(std::size_t i = 0; i < vals.size(); ++i)
@@ -77,7 +74,7 @@ std::string Combine(const std::vector<T> &vals, const std::string &sep=std::stri
 		{
 			str += sep;
 		}
-		str += mpt::ToString(vals[i]);
+		str += mpt::fmt::val(vals[i]);
 	}
 	return str;
 }
@@ -87,7 +84,6 @@ std::string Combine(const std::vector<T> &vals, const std::string &sep=std::stri
 // Leading or trailing separators result in a default-constructed element being inserted before or after the other elements.
 template<typename T>
 std::vector<T> Split(const mpt::ustring &str, const mpt::ustring &sep=MPT_USTRING(","))
-//-------------------------------------------------------------------------------------
 {
 	std::vector<T> vals;
 	std::size_t pos = 0;
@@ -104,7 +100,6 @@ std::vector<T> Split(const mpt::ustring &str, const mpt::ustring &sep=MPT_USTRIN
 }
 template<typename T>
 std::vector<T> Split(const std::string &str, const std::string &sep=std::string(","))
-//-----------------------------------------------------------------------------------
 {
 	std::vector<T> vals;
 	std::size_t pos = 0;
@@ -129,7 +124,7 @@ namespace mpt {
 // integer type narrower than int to double.
 //  As this is apparently valid by the current standard, Library Working Group
 // Issue #2735 has been filed (see
-// <https://cplusplus.github.io/LWG/lwg-active.html#2735>).
+// <https://cplusplus.github.io/LWG/lwg-defects.html#2735>).
 //  In any case, avoid this insanity and provide our own mpt::abs implementation
 // for signed integer and floating point types.
 //  Note: We stick to a C++98-style implementation only overloading int and
@@ -137,67 +132,79 @@ namespace mpt {
 // which a templated version returning the argument type would not do. OpenMPT
 // probably assumes this semantic when calling abs(int8) in various places.
 inline int abs(int x)
-//-------------------
 {
 	return std::abs(x);
 }
 inline long abs(long x)
-//---------------------
 {
 	return std::abs(x);
 }
 inline long long abs(long long x)
-//-------------------------------
 {
-	#if MPT_MSVC_BEFORE(2010,0)
-		return (x >= 0) ? x : -x;
-	#else
-		return std::abs(x);
-	#endif
+	return std::abs(x);
 }
 inline float abs(float x)
-//-----------------------
 {
 	return std::fabs(x);
 }
 inline double abs(double x)
-//-------------------------
 {
 	return std::fabs(x);
 }
 inline long double abs(long double x)
-//-----------------------------------
 {
 	return std::fabs(x);
 }
 
+// Modulo with more intuitive behaviour for some contexts:
+// Instead of being symmetrical around 0, the pattern for positive numbers is repeated in the negative range.
+// For example, wrapping_modulo(-1, m) == (m - 1).
+// Behaviour is undefined if m<=0.
+template<typename T, typename M>
+MPT_CONSTEXPR11_FUN auto wrapping_modulo(T x, M m) -> decltype(x % m)
+{
+	return (x >= 0) ? (x % m) : (m - 1 - ((-1 - x) % m));
+}
+
+template<typename T, typename D>
+MPT_CONSTEXPR11_FUN auto wrapping_divide(T x, D d) -> decltype(x / d)
+{
+	return (x >= 0) ? (x / d) : (((x + 1) / d) - 1);
+}
+
 } // namespace mpt
 
 
 // Memset given object to zero.
 template <class T>
 inline void MemsetZero(T &a)
-//--------------------------
 {
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 	static_assert(std::is_pointer<T>::value == false, "Won't memset pointers.");
-	static_assert(std::is_pod<T>::value == true, "Won't memset non-pods.");
+#if MPT_GCC_BEFORE(5,1,0) || MPT_CLANG_BEFORE(3,5,0) || (MPT_COMPILER_CLANG && defined(__GLIBCXX__))
+	MPT_STATIC_ASSERT(std::is_standard_layout<T>::value);
+	MPT_STATIC_ASSERT(std::is_trivial<T>::value); // approximation
+#else // default
+	MPT_STATIC_ASSERT(std::is_standard_layout<T>::value);
+	MPT_STATIC_ASSERT(std::is_trivially_copyable<T>::value); // C++11, but not supported on most compilers we care about
 #endif
 	std::memset(&a, 0, sizeof(T));
 }
 
 
+#ifdef MODPLUG_TRACKER
 // Copy given object to other location.
 template <class T>
-inline T &MemCopy(T &destination, const T &source)
-//------------------------------------------------
+void MemCopy(T &destination, const T &source)
 {
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 	static_assert(std::is_pointer<T>::value == false, "Won't copy pointers.");
-	static_assert(std::is_pod<T>::value == true, "Won't copy non-pods.");
+#if MPT_GCC_BEFORE(5,1,0) || MPT_CLANG_BEFORE(3,5,0) || (MPT_COMPILER_CLANG && defined(__GLIBCXX__))
+	MPT_STATIC_ASSERT(std::is_trivial<T>::value); // approximation
+#else // default
+	MPT_STATIC_ASSERT(std::is_trivially_copyable<T>::value); // C++11, but not supported on most compilers we care about
 #endif
-	return *static_cast<T *>(std::memcpy(&destination, &source, sizeof(T)));
+	std::memcpy(&destination, &source, sizeof(T));
 }
+#endif // MODPLUG_TRACKER
 
 
 namespace mpt {
@@ -280,7 +287,7 @@ template <typename T> inline span<T> as_span(T * beg, T * end) { return span<T>(
 
 template <typename T> inline span<T> as_span(T * data, std::size_t size) { return span<T>(data, size); }
 
-template <typename T, std::size_t N> inline span<T> as_span(T (&arr)[N]) { return span<T>(arr, N); }
+template <typename T, std::size_t N> inline span<T> as_span(T (&arr)[N]) { return span<T>(std::begin(arr), std::end(arr)); }
 
 template <typename T> inline span<T> as_span(std::vector<T> & cont) { return span<T>(cont); }
 
@@ -295,6 +302,19 @@ typedef mpt::span<mpt::byte> byte_span;
 typedef mpt::span<const mpt::byte> const_byte_span;
 
 
+
+template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(T * beg, T * end) { return std::vector<typename std::remove_const<T>::type>(beg, end); }
+
+template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(T * data, std::size_t size) { return std::vector<typename std::remove_const<T>::type>(data, data + size); }
+
+template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(mpt::span<T> data) { return std::vector<typename std::remove_const<T>::type>(data.data(), data.data() + data.size()); }
+
+template <typename T, std::size_t N> inline std::vector<typename std::remove_const<T>::type> make_vector(T (&arr)[N]) { return std::vector<typename std::remove_const<T>::type>(std::begin(arr), std::end(arr)); }
+
+template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(const std::basic_string<T> & str) { return std::vector<typename std::remove_const<T>::type>(str.begin(), str.end()); }
+
+
+
 template <typename Tdst, typename Tsrc>
 struct byte_cast_impl
 {
@@ -304,10 +324,8 @@ struct byte_cast_impl
 		STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
 		// not checking is_byte_castable here because we are actually
 		// doing a static_cast and converting the value
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tsrc>::value);
 		STATIC_ASSERT(std::is_integral<Tdst>::value);
-#endif
 		return static_cast<Tdst>(src);
 	}
 };
@@ -320,10 +338,8 @@ struct byte_cast_impl<mpt::span<Tdst>, mpt::span<Tsrc> >
 		STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
 		STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
 		STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tsrc>::value);
 		STATIC_ASSERT(std::is_integral<Tdst>::value);
-#endif
 		return mpt::as_span(mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.begin()), mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.end()));
 	}
 };
@@ -336,10 +352,8 @@ struct byte_cast_impl<Tdst*, Tsrc*>
 		STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
 		STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
 		STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tsrc>::value);
 		STATIC_ASSERT(std::is_integral<Tdst>::value);
-#endif
 		return reinterpret_cast<Tdst*>(src);
 	}
 };
@@ -354,9 +368,7 @@ struct void_cast_impl<Tdst*, void*>
 	{
 		STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
 		STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tdst>::value);
-#endif
 		return reinterpret_cast<Tdst*>(src);
 	}
 };
@@ -367,9 +379,7 @@ struct void_cast_impl<Tdst*, const void*>
 	{
 		STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
 		STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tdst>::value);
-#endif
 		return reinterpret_cast<Tdst*>(src);
 	}
 };
@@ -380,9 +390,7 @@ struct void_cast_impl<void*, Tsrc*>
 	{
 		STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
 		STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tsrc>::value);
-#endif
 		return reinterpret_cast<void*>(src);
 	}
 };
@@ -393,9 +401,7 @@ struct void_cast_impl<const void*, Tsrc*>
 	{
 		STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
 		STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 		STATIC_ASSERT(std::is_integral<Tsrc>::value);
-#endif
 		return reinterpret_cast<const void*>(src);
 	}
 };
@@ -418,7 +424,6 @@ inline Tdst void_cast(Tsrc src)
 // Saturate the value of src to the domain of Tdst
 template <typename Tdst, typename Tsrc>
 inline Tdst saturate_cast(Tsrc src)
-//---------------------------------
 {
 	// This code tries not only to obviously avoid overflows but also to avoid signed/unsigned comparison warnings and type truncation warnings (which in fact would be safe here) by explicit casting.
 	STATIC_ASSERT(std::numeric_limits<Tdst>::is_integer);
@@ -460,7 +465,6 @@ inline Tdst saturate_cast(Tsrc src)
 
 template <typename Tdst>
 inline Tdst saturate_cast(double src)
-//-----------------------------------
 {
 	if(src >= std::numeric_limits<Tdst>::max())
 	{
@@ -475,7 +479,6 @@ inline Tdst saturate_cast(double src)
 
 template <typename Tdst>
 inline Tdst saturate_cast(float src)
-//----------------------------------
 {
 	if(src >= std::numeric_limits<Tdst>::max())
 	{
@@ -492,13 +495,6 @@ inline Tdst saturate_cast(float src)
 } // namespace mpt
 
 
-#if MPT_MSVC_BEFORE(2010,0) || MPT_GCC_BEFORE(4,4,0)
-// Compiler too old.
-#ifndef MPT_MINMAX_MACROS
-#define MPT_MINMAX_MACROS
-#endif
-#endif
-
 #if defined(MODPLUG_TRACKER)
 // Tracker code requires MIN/MAX to work in constexpr contexts.
 // We could make MIN/MAX constexpr for supporting compilers,
@@ -528,13 +524,13 @@ inline Tdst saturate_cast(float src)
 namespace mpt { namespace Legacy {
 
 template <typename Ta, typename Tb>
-forceinline auto MAX(const Ta &a, const Tb &b) -> decltype((a>b)?a:b)
+MPT_FORCEINLINE auto MAX(const Ta &a, const Tb &b) -> decltype((a>b)?a:b)
 {
 	return (a > b) ? a : b;
 }
 
 template <typename Ta, typename Tb>
-forceinline auto MIN(const Ta &a, const Tb &b) -> decltype((a<b)?a:b)
+MPT_FORCEINLINE auto MIN(const Ta &a, const Tb &b) -> decltype((a<b)?a:b)
 {
 	return (a < b) ? a : b;
 }
@@ -607,16 +603,35 @@ inline T ExponentialGrow(const T &x)
 {
 	return Util::ExponentialGrow(x, std::numeric_limits<T>::max());
 }
-									
+
 } //namespace Util
 
 
+namespace mpt
+{
+
+// C++17 clamp
+
+template<typename T, typename Compare>
+MPT_CONSTEXPR11_FUN const T & clamp(const T & v, const T & lo, const T & hi, Compare comp)
+{
+	return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
+}
+
+template<typename T>
+MPT_CONSTEXPR11_FUN const T & clamp(const T & v, const T & lo, const T & hi)
+{
+	return clamp(v, lo, hi, std::less<T>());
+}
+
+} // namespace mpt
+
+
 // Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'.
 // Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'.
 // If 'lowerLimit' > 'upperLimit', 'val' won't be modified.
 template<class T, class C>
 inline void Limit(T& val, const C lowerLimit, const C upperLimit)
-//---------------------------------------------------------------
 {
 	if(lowerLimit > upperLimit) return;
 	if(val < lowerLimit) val = lowerLimit;
@@ -627,7 +642,6 @@ inline void Limit(T& val, const C lowerLimit, const C upperLimit)
 // Like Limit, but returns value
 template<class T, class C>
 inline T Clamp(T val, const C lowerLimit, const C upperLimit)
-//-----------------------------------------------------------
 {
 	if(val < lowerLimit) return lowerLimit;
 	else if(val > upperLimit) return upperLimit;
@@ -639,7 +653,6 @@ inline T Clamp(T val, const C lowerLimit, const C upperLimit)
 // GCC does not warn if the type is templated.
 template<typename T, typename C>
 inline bool IsInRange(T val, C lo, C hi)
-//--------------------------------------
 {
 	return lo <= val && val <= hi;
 }
@@ -647,7 +660,6 @@ inline bool IsInRange(T val, C lo, C hi)
 // Like Limit, but with upperlimit only.
 template<class T, class C>
 inline void LimitMax(T& val, const C upperLimit)
-//----------------------------------------------
 {
 	if(val > upperLimit)
 		val = upperLimit;
@@ -657,20 +669,107 @@ inline void LimitMax(T& val, const C upperLimit)
 // Returns sign of a number (-1 for negative numbers, 1 for positive numbers, 0 for 0)
 template <class T>
 int sgn(T value)
-//--------------
 {
 	return (value > T(0)) - (value < T(0));
 }
 
 
-namespace Util
+
+// mpt::rshift_signed
+// mpt::lshift_signed
+// Shift a signed integer value in a well-defined manner.
+// Does the same thing as MSVC would do. This is verified by the test suite.
+
+namespace mpt
 {
 
-	// Minimum of 3 values
-	template <class T> inline const T& Min(const T& a, const T& b, const T& c) {return std::min(std::min(a, b), c);}
+template <typename T>
+MPT_FORCEINLINE auto rshift_signed_standard(T x, int y) -> decltype(x >> y)
+{
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
+	typedef decltype(x >> y) result_type;
+	typedef typename std::make_unsigned<result_type>::type unsigned_result_type;
+	const unsigned_result_type roffset = static_cast<unsigned_result_type>(1) << ((sizeof(result_type) * 8) - 1);
+	result_type rx = x;
+	unsigned_result_type urx = static_cast<unsigned_result_type>(rx);
+	urx += roffset;
+	urx >>= y;
+	urx -= roffset >> y;
+	return static_cast<result_type>(urx);
+}
+
+template <typename T>
+MPT_FORCEINLINE auto lshift_signed_standard(T x, int y) -> decltype(x << y)
+{
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
+	typedef decltype(x << y) result_type;
+	typedef typename std::make_unsigned<result_type>::type unsigned_result_type;
+	const unsigned_result_type roffset = static_cast<unsigned_result_type>(1) << ((sizeof(result_type) * 8) - 1);
+	result_type rx = x;
+	unsigned_result_type urx = static_cast<unsigned_result_type>(rx);
+	urx += roffset;
+	urx <<= y;
+	urx -= roffset << y;
+	return static_cast<result_type>(urx);
+}
+
+#if MPT_COMPILER_SHIFT_SIGNED
+
+template <typename T>
+MPT_FORCEINLINE auto rshift_signed_undefined(T x, int y) -> decltype(x >> y)
+{
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
+	return x >> y;
+}
+
+template <typename T>
+MPT_FORCEINLINE auto lshift_signed_undefined(T x, int y) -> decltype(x << y)
+{
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
+	return x << y;
+}
+
+template <typename T>
+MPT_FORCEINLINE auto rshift_signed(T x, int y) -> decltype(x >> y)
+{
+	return mpt::rshift_signed_undefined(x, y);
+}
+
+template <typename T>
+MPT_FORCEINLINE auto lshift_signed(T x, int y) -> decltype(x << y)
+{
+	return mpt::lshift_signed_undefined(x, y);
+}
+
+#else
+
+template <typename T>
+MPT_FORCEINLINE auto rshift_signed(T x, int y) -> decltype(x >> y)
+{
+	return mpt::rshift_signed_standard(x, y);
+}
+
+template <typename T>
+MPT_FORCEINLINE auto lshift_signed(T x, int y) -> decltype(x << y)
+{
+	return mpt::lshift_signed_standard(x, y);
+}
+
+#endif
+
+} // namespace mpt
+
+
+
+namespace Util
+{
 
 	// Returns maximum value of given integer type.
-	template <class T> inline T MaxValueOfType(const T&) {static_assert(std::numeric_limits<T>::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits<T>::max)();}
+	template <class T> constexpr T MaxValueOfType(const T&) {static_assert(std::numeric_limits<T>::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits<T>::max)();}
 
 	// The following MPT_MAX_* macros are useful as std::numeric_limits is not
 	// usable in constexpr-like contexts like static_assert in pre-C++11
@@ -687,13 +786,20 @@ namespace Util
 	#define MPT_MAX_VALUE_OF_TYPE(integral_type) ( std::numeric_limits<integral_type>::is_signed ? MPT_MAX_SIGNED_VALUE(integral_type) : MPT_MAX_UNSIGNED_VALUE(integral_type) )
 
 	/// Returns value rounded to nearest integer.
-#if (MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2013,0)) || (MPT_COMPILER_GCC && MPT_GCC_BEFORE(4,3,0)) || MPT_OS_ANDROID || MPT_OS_EMSCRIPTEN
+#if (MPT_OS_EMSCRIPTEN && MPT_OS_EMSCRIPTEN_ANCIENT)
 	// MSVC before 2013 does not support C99/C++11.
-	// GCC before 4.3.0 does not support C++11.
-	// Android has std::round just missing even though it should be available.
 	// Certain emscripten versions and/or combinations with nodejs (at least the following combination: emscripten 1.34.8, clang 3.7.0, nodejs 0.10.38) fail assert(std::round(1.5)==2.0). The work-around always works.
 	inline double Round(const double& val) {if(val >= 0.0) return std::floor(val + 0.5); else return std::ceil(val - 0.5);}
 	inline float Round(const float& val) {if(val >= 0.0f) return std::floor(val + 0.5f); else return std::ceil(val - 0.5f);}
+#elif MPT_OS_ANDROID && defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
+	// NDK 12b gnustl_shared armeabi-v7a only provides round() in ::.
+	// NDK 12b gnustl_shared arm64-v8a has round() in std::.
+	// NDK 12b c++_shared armeabi-v7a has round() in std::.
+	// Just fallback to :: for Android gnustl_shared.
+	// This work-around can be removed once Android switches to LLVM libc++.
+	// Currently (ndk-r12b), libc++ has problems with exceptions.
+	inline double Round(const double& val) { return ::round(val); }
+	inline float Round(const float& val) { return ::roundf(val); }
 #else
 	inline double Round(const double& val) { return std::round(val); }
 	inline float Round(const float& val) { return std::round(val); }
@@ -736,45 +842,45 @@ namespace Util {
 
 	// Multiply two 32-bit integers, receive 64-bit result.
 	// MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul.
-	forceinline int64 mul32to64(int32 a, int32 b)
+	MPT_FORCEINLINE int64 mul32to64(int32 a, int32 b)
 	{
-#if MPT_COMPILER_MSVC
+#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
 		return __emul(a, b);
 #else
 		return static_cast<int64>(a) * b;
 #endif
 	}
 
-	forceinline uint64 mul32to64_unsigned(uint32 a, uint32 b)
+	MPT_FORCEINLINE uint64 mul32to64_unsigned(uint32 a, uint32 b)
 	{
-#if MPT_COMPILER_MSVC
+#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
 		return __emulu(a, b);
 #else
 		return static_cast<uint64>(a) * b;
 #endif
 	}
 
-	forceinline int32 muldiv(int32 a, int32 b, int32 c)
+	MPT_FORCEINLINE int32 muldiv(int32 a, int32 b, int32 c)
 	{
 		return mpt::saturate_cast<int32>( mul32to64( a, b ) / c );
 	}
 
-	forceinline int32 muldivr(int32 a, int32 b, int32 c)
+	MPT_FORCEINLINE int32 muldivr(int32 a, int32 b, int32 c)
 	{
 		return mpt::saturate_cast<int32>( ( mul32to64( a, b ) + ( c / 2 ) ) / c );
 	}
 
 	// Do not use overloading because catching unsigned version by accident results in slower X86 code.
-	forceinline uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
+	MPT_FORCEINLINE uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
 	{
 		return mpt::saturate_cast<uint32>( mul32to64_unsigned( a, b ) / c );
 	}
-	forceinline uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
+	MPT_FORCEINLINE uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
 	{
 		return mpt::saturate_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c );
 	}
 
-	forceinline int32 muldivrfloor(int64 a, uint32 b, uint32 c)
+	MPT_FORCEINLINE int32 muldivrfloor(int64 a, uint32 b, uint32 c)
 	{
 		a *= b;
 		a += c / 2u;
@@ -860,10 +966,19 @@ namespace Util {
 		}
 	}
 
+} // namespace Util
+
+
+namespace mpt
+{
+
 	// Greatest Common Divisor. Always returns non-negative number.
-	template <class T>
-	T gcd(T a, T b)
+	// compatible with C++17 std::gcd
+	template <typename A, typename B>
+	inline typename std::common_type<A, B>::type gcd(A a_, B b_)
 	{
+		typename std::common_type<A, B>::type a = a_;
+		typename std::common_type<A, B>::type b = b_;
 		if(a < 0)
 			a = -a;
 		if(b < 0)
@@ -880,18 +995,27 @@ namespace Util {
 	}
 
 	// Least Common Multiple. Always returns non-negative number.
-	template <class T>
-	int lcm(T a, T b)
+	// compatible with C++17 std::lcm
+	template <typename A, typename B>
+	inline typename std::common_type<A, B>::type lcm(A a_, B b_)
 	{
+		typename std::common_type<A, B>::type a = a_;
+		typename std::common_type<A, B>::type b = b_;
 		if(a < 0)
 			a = -a;
 		if(b < 0)
 			b = -b;
 		if((a | b) == 0)
 			return 0;
-		return a / gcd<T>(a, b) * b;
+		return a / mpt::gcd(a, b) * b;
 	}
 
+} // namespace mpt
+
+
+namespace Util
+{
+
 	template<typename T, std::size_t n>
 	class fixed_size_queue
 	{
@@ -984,12 +1108,16 @@ namespace Util {
 namespace Util
 {
 
-mpt::ustring BinToHex(const std::vector<char> &src);
-std::vector<char> HexToBin(const mpt::ustring &src);
+std::vector<mpt::byte> HexToBin(const mpt::ustring &src);
+mpt::ustring BinToHex(mpt::const_byte_span src);
+
+template <typename T> inline mpt::ustring BinToHex(mpt::span<T> src) { return Util::BinToHex(mpt::byte_cast<mpt::const_byte_span>(src)); }
 
 } // namespace Util
 
 
+#if defined(MODPLUG_TRACKER) || (defined(LIBOPENMPT_BUILD) && defined(LIBOPENMPT_BUILD_TEST))
+
 namespace mpt
 {
 
@@ -1000,5 +1128,7 @@ std::string getenv(const std::string &env_var, const std::string &def = std::str
 
 } // namespace mpt
 
+#endif // MODPLUG_TRACKER || (LIBOPENMPT_BUILD && LIBOPENMPT_BUILD_TEST)
+
 
 OPENMPT_NAMESPACE_END
diff --git a/common/mptAtomic.h b/common/mptAtomic.h
deleted file mode 100644
index 32fa04a..0000000
--- a/common/mptAtomic.h
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * mptAtomic.h
- * -----------
- * Purpose: Subset of C++11 std::atomic implementation as mpt::atomic_* and MPT_ATOMIC_PTR<T*>
- * Notes  : Only 32 bit signed and unsigned integer and pointers are supported.
- *          The interface (as far as implemented) is syntax-compatbile with C++11 
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
-
-
-#pragma once
-
-#if defined(MPT_ENABLE_ATOMIC)
-
-#if !(MPT_MSVC_BEFORE(2012,0) || MPT_GCC_BEFORE(4,4,0) || MPT_CLANG_BEFORE(3,1,0))
-#include <atomic>
-#endif // MPT_COMPILER
-
-#endif // MPT_ENABLE_ATOMIC
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-#if defined(MPT_ENABLE_ATOMIC)
-
-
-namespace mpt
-{
-
-
-#if MPT_GCC_BEFORE(4,4,0) || MPT_CLANG_BEFORE(3,1,0)
-
-template < typename T >
-class atomic_impl {
-
-private:
-	mutable T Data;
-
-private: // disabled
-	atomic_impl( const atomic_impl<T> & src );
-	atomic_impl<T> & operator = ( const atomic_impl<T> & src );
-
-public:
-	
-	atomic_impl() {
-		return;
-	}
-	atomic_impl( T init ) {
-		T old = __sync_fetch_and_add( &Data, 0 );
-		while ( old != __sync_val_compare_and_swap( &Data, old, init ) ) {
-			// nothing
-		}
-	}
-	T operator = ( T src ) {
-		T old = __sync_fetch_and_add( &Data, 0 );
-		while ( old != __sync_val_compare_and_swap( &Data, old, src ) ) {
-			// nothing
-		}
-		return src;
-	}
-
-	operator T () const {
-		return __sync_fetch_and_add( &Data, 0 );
-	}
-
-	bool is_lock_free() const {
-		return true;
-	}
-
-	T load() const {
-		return __sync_fetch_and_add( &Data, 0 );
-	}
-	void store( T val ) {
-		T old = __sync_fetch_and_add( &Data, 0 );
-		while ( old != __sync_val_compare_and_swap( &Data, old, val ) ) {
-			// nothing
-		}
-	}
-	T exchange( T val ) {
-		T old = __sync_fetch_and_add( &Data, 0 );
-		while ( old != __sync_val_compare_and_swap( &Data, old, val ) ) {
-			// nothing
-		}
-		return old;
-	}
-
-	bool compare_exchange_strong( T & expected, T new_value ) {
-		return __sync_bool_compare_and_swap( &Data, expected, new_value );
-	}
-	bool compare_exchange_weak( T & expected, T new_value ) {
-		return __sync_bool_compare_and_swap( &Data, expected, new_value );
-	}
-
-	T fetch_add( T val ) {
-		return __sync_fetch_and_add( &Data, val );
-	}
-	T fetch_sub( T val ) {
-		return __sync_fetch_and_sub( &Data, val );
-	}
-
-	T fetch_and( T val ) {
-		return __sync_fetch_and_and( &Data, val );
-	}
-	T fetch_or( T val ) {
-		return __sync_fetch_and_or( &Data, val );
-	}
-	T fetch_xor( T val ) {
-		return __sync_fetch_and_xor( &Data, val );
-	}
-
-}; // class atomic
-
-#elif MPT_MSVC_BEFORE(2012,0)
-
-template < typename T >
-class atomic_impl_32 {
-
-private:
-	mutable long Data;
-
-private: // disabled
-	atomic_impl_32( const atomic_impl_32<T> & src );
-	atomic_impl_32<T> & operator = ( const atomic_impl_32<T> & src );
-
-public:
-	
-	atomic_impl_32() {
-		return;
-	}
-	atomic_impl_32( T init ) {
-		_InterlockedExchange( &Data, init );
-	}
-	T operator = ( T src ) {
-		_InterlockedExchange( &Data, src );
-		return src;
-	}
-
-	operator T () const {
-		return _InterlockedExchangeAdd( &Data, 0 );
-	}
-
-	bool is_lock_free() const {
-		return true;
-	}
-
-	T load() const {
-		return _InterlockedExchangeAdd( &Data, 0 );
-	}
-	void store( T val ) {
-		_InterlockedExchange( &Data, val );
-	}
-	T exchange( T val ) {
-		return _InterlockedExchange( &Data, val );
-	}
-
-	bool compare_exchange_strong( T & expected, T new_value ) {
-		return _InterlockedCompareExchange( &Data, new_value, expected ) == expected;
-	}
-	bool compare_exchange_weak( T & expected, T new_value ) {
-		return _InterlockedCompareExchange( &Data, new_value, expected ) == expected;
-	}
-
-	T fetch_add( T val ) {
-		return _InterlockedExchangeAdd( &Data, val );
-	}
-	T fetch_sub( T val ) {
-		return _InterlockedExchangeAdd( &Data, -val );
-	}
-
-	T fetch_and( T val ) {
-		return _InterlockedAnd( &Data, val );
-	}
-	T fetch_or( T val ) {
-		return _InterlockedOr( &Data, val );
-	}
-	T fetch_xor( T val ) {
-		return _InterlockedXor( &Data, val );
-	}
-
-}; // class atomic_impl_32
-
-#if defined(_M_AMD64)
-
-template < typename T >
-class atomic_impl_64 {
-
-private:
-	mutable __int64 Data;
-
-private: // disabled
-	atomic_impl_64( const atomic_impl_64<T> & src );
-	atomic_impl_64<T> & operator = ( const atomic_impl_64<T> & src );
-
-public:
-	
-	atomic_impl_64() {
-		return;
-	}
-	atomic_impl_64( T init ) {
-		_InterlockedExchange64( &Data, init );
-	}
-	T operator = ( T src ) {
-		_InterlockedExchange64( &Data, src );
-		return src;
-	}
-
-	operator T () const {
-		return _InterlockedExchangeAdd64( &Data, 0 );
-	}
-
-	bool is_lock_free() const {
-		return true;
-	}
-
-	T load() const {
-		return _InterlockedExchangeAdd64( &Data, 0 );
-	}
-	void store( T val ) {
-		_InterlockedExchange64( &Data, val );
-	}
-	T exchange( T val ) {
-		return _InterlockedExchange64( &Data, val );
-	}
-
-	bool compare_exchange_strong( T & expected, T new_value ) {
-		return _InterlockedCompareExchange64( &Data, new_value, expected ) == expected;
-	}
-	bool compare_exchange_weak( T & expected, T new_value ) {
-		return _InterlockedCompareExchange64( &Data, new_value, expected ) == expected;
-	}
-
-	T fetch_add( T val ) {
-		return _InterlockedExchangeAdd64( &Data, val );
-	}
-	T fetch_sub( T val ) {
-		return _InterlockedExchangeAdd64( &Data, -val );
-	}
-
-	T fetch_and( T val ) {
-		return _InterlockedAnd64( &Data, val );
-	}
-	T fetch_or( T val ) {
-		return _InterlockedOr64( &Data, val );
-	}
-	T fetch_xor( T val ) {
-		return _InterlockedXor64( &Data, val );
-	}
-
-}; // class atomic_impl_64
-
-template < typename T >
-class atomic_impl_ptr {
-
-private:
-	mutable __int64 Data;
-
-private: // disabled
-	atomic_impl_ptr( const atomic_impl_ptr<T> & src );
-	atomic_impl_ptr<T> & operator = ( const atomic_impl_ptr<T> & src );
-
-public:
-	
-	atomic_impl_ptr() {
-		return;
-	}
-	atomic_impl_ptr( T init ) {
-		_InterlockedExchange64( &Data, reinterpret_cast<std::uintptr_t>( init ) );
-	}
-	T operator = ( T src ) {
-		_InterlockedExchange64( &Data, reinterpret_cast<std::uintptr_t>( src ) );
-		return src;
-	}
-
-	operator T () const {
-		return reinterpret_cast<T>( _InterlockedExchangeAdd64( &Data, reinterpret_cast<std::uintptr_t>( 0 ) ) );
-	}
-
-	bool is_lock_free() const {
-		return true;
-	}
-	
-	T load() const {
-		return reinterpret_cast<T>( _InterlockedExchangeAdd64( &Data, reinterpret_cast<std::uintptr_t>( 0 ) ) );
-	}
-	void store( T val ) {
-		_InterlockedExchange64( &Data, reinterpret_cast<std::uintptr_t>( val ) );
-	}
-	T exchange( T val ) {
-		return reinterpret_cast<T>( _InterlockedExchange64( &Data, reinterpret_cast<std::uintptr_t>( val ) ) );
-	}
-
-	bool compare_exchange_strong( T & expected, T new_value ) {
-		return reinterpret_cast<T>( _InterlockedCompareExchange64( &Data, new_value, reinterpret_cast<std::uintptr_t>( expected ) ) ) == expected;
-	}
-	bool compare_exchange_weak( T & expected, T new_value ) {
-		return reinterpret_cast<T>( _InterlockedCompareExchange64( &Data, new_value, reinterpret_cast<std::uintptr_t>( expected ) ) ) == expected;
-	}
-
-}; // class atomic_impl_ptr
-
-#elif defined(_M_X86)
-
-template < typename T >
-class atomic_impl_ptr {
-
-private:
-	mutable long Data;
-
-private: // disabled
-	atomic_impl_ptr( const atomic_impl_ptr<T> & src );
-	atomic_impl_ptr<T> & operator = ( const atomic_impl_ptr<T> & src );
-
-public:
-	
-	atomic_impl_ptr() {
-		return;
-	}
-	atomic_impl_ptr( T init ) {
-		_InterlockedExchange( &Data, reinterpret_cast<std::uintptr_t>( init ) );
-	}
-	T operator = ( T src ) {
-		_InterlockedExchange( &Data, reinterpret_cast<std::uintptr_t>( src ) );
-		return src;
-	}
-
-	operator T () const {
-		return reinterpret_cast<T>( _InterlockedExchangeAdd( &Data, reinterpret_cast<std::uintptr_t>( 0 ) ) );
-	}
-
-	bool is_lock_free() const {
-		return true;
-	}
-	
-	T load() const {
-		return reinterpret_cast<T>( _InterlockedExchangeAdd( &Data, reinterpret_cast<std::uintptr_t>( 0 ) ) );
-	}
-	void store( T val ) {
-		_InterlockedExchange( &Data, reinterpret_cast<std::uintptr_t>( val ) );
-	}
-	T exchange( T val ) {
-		return reinterpret_cast<T>( _InterlockedExchange( &Data, reinterpret_cast<std::uintptr_t>( val ) ) );
-	}
-
-	bool compare_exchange_strong( T & expected, T new_value ) {
-		return reinterpret_cast<T>( _InterlockedCompareExchange( &Data, new_value, reinterpret_cast<std::uintptr_t>( expected ) ) ) == expected;
-	}
-	bool compare_exchange_weak( T & expected, T new_value ) {
-		return reinterpret_cast<T>( _InterlockedCompareExchange( &Data, new_value, reinterpret_cast<std::uintptr_t>( expected ) ) ) == expected;
-	}
-
-}; // class atomic_impl_ptr
-
-#endif // X86 || AMD64
-
-#endif // MPT_COMPILER
-
-#if MPT_GCC_BEFORE(4,4,0) || MPT_CLANG_BEFORE(3,1,0)
-typedef mpt::atomic_impl<uint32> atomic_uint32_t;
-typedef mpt::atomic_impl<int32> atomic_int32_t;
-#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
-typedef mpt::atomic_impl<uint64> atomic_uint64_t;
-typedef mpt::atomic_impl<int64> atomic_int64_t;
-#define MPT_ATOMIC_HAVE_64
-#endif
-#define MPT_ATOMIC_PTR mpt::atomic_impl // use as MPT_ATOMIC_PTR<T*>
-#elif MPT_MSVC_BEFORE(2012,0)
-typedef mpt::atomic_impl_32<uint32> atomic_uint32_t;
-typedef mpt::atomic_impl_32<int32> atomic_int32_t;
-#if defined(_M_AMD64)
-typedef mpt::atomic_impl_64<uint64> atomic_uint64_t;
-typedef mpt::atomic_impl_64<int64> atomic_int64_t;
-#define MPT_ATOMIC_HAVE_64
-#endif
-#define MPT_ATOMIC_PTR mpt::atomic_impl_ptr // use as MPT_ATOMIC_PTR<T*>
-#else // MPT_COMPILER_GENERIC
-typedef std::atomic<uint32> atomic_uint32_t;
-typedef std::atomic<int32> atomic_int32_t;
-typedef std::atomic<uint64> atomic_uint64_t;
-typedef std::atomic<int64> atomic_int64_t;
-#define MPT_ATOMIC_HAVE_64
-#define MPT_ATOMIC_PTR std::atomic // use as MPT_ATOMIC_PTR<T*>
-#endif // MPT_COMPILER
-
-
-#if !defined(MPT_ATOMIC_HAVE_64)
-
-} // namespace mpt
-OPENMPT_NAMESPACE_END
-#include "mptMutex.h"
-OPENMPT_NAMESPACE_BEGIN
-namespace mpt {
-
-template < typename T >
-class atomic_impl_locked {
-
-private:
-	mutable mpt::mutex Mutex;
-	mutable T Data;
-
-private: // disabled
-	atomic_impl_locked( const atomic_impl_locked<T> & src );
-	atomic_impl_locked<T> & operator = ( const atomic_impl_locked<T> & src );
-
-public:
-	
-	atomic_impl_locked() {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-	}
-	atomic_impl_locked( T init ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		Data = init;
-	}
-	T operator = ( T src ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		Data = src;
-		return Data;
-	}
-
-	operator T () const {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		return Data;
-	}
-
-	bool is_lock_free() const {
-		return false;
-	}
-
-	T load() const {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		return Data;
-	}
-	void store( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		Data = val;
-	}
-	T exchange( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		T old = Data;
-		Data = val;
-		return old;
-	}
-
-	bool compare_exchange_strong( T & expected, T new_value ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		if(Data != expected)
-		{
-			return false;
-		}
-		Data = new_value;
-		return true;
-	}
-	bool compare_exchange_weak( T & expected, T new_value ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		if(Data != expected)
-		{
-			return false;
-		}
-		Data = new_value;
-		return true;
-	}
-
-	T fetch_add( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		T old = Data;
-		Data += val;
-		return old;
-	}
-	T fetch_sub( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		T old = Data;
-		Data -= val;
-		return old;
-	}
-
-	T fetch_and( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		T old = Data;
-		Data &= val;
-		return old;
-	}
-	T fetch_or( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		T old = Data;
-		Data |= val;
-		return old;
-	}
-	T fetch_xor( T val ) {
-		MPT_LOCK_GUARD<mpt::mutex> guard(Mutex);
-		T old = Data;
-		Data ^= val;
-		return old;
-	}
-
-}; // class atomic_impl_locked
-
-typedef mpt::atomic_impl_locked<uint64> atomic_uint64_t;
-typedef mpt::atomic_impl_locked<int64> atomic_int64_t;
-#define MPT_ATOMIC_HAVE_64
-
-#endif // !MPT_ATOMIC_HAVE_64
-
-
-} // namespace mpt
-
-
-#endif // MPT_ENABLE_ATOMIC
-
-
-OPENMPT_NAMESPACE_END
diff --git a/common/mptCPU.cpp b/common/mptCPU.cpp
index 1535d1d..e5b7067 100644
--- a/common/mptCPU.cpp
+++ b/common/mptCPU.cpp
@@ -61,7 +61,6 @@ struct cpuid_result {
 
 
 static cpuid_result cpuid(uint32 function)
-//----------------------------------------
 {
 	cpuid_result result;
 	int CPUInfo[4];
@@ -74,32 +73,24 @@ static cpuid_result cpuid(uint32 function)
 }
 
 
+#if 0
+
 static cpuid_result cpuidex(uint32 function_a, uint32 function_c)
-//---------------------------------------------------------------
 {
 	cpuid_result result;
-	#if MPT_MSVC_AT_LEAST(2010,0)
-		int CPUInfo[4];
-		__cpuidex(CPUInfo, function_a, function_c);
-		result.a = CPUInfo[0];
-		result.b = CPUInfo[1];
-		result.c = CPUInfo[2];
-		result.d = CPUInfo[3];
-	#else
-		// just do not test modern cpuid features with older compiler
-		MPT_UNREFERENCED_PARAMETER(function_a);
-		MPT_UNREFERENCED_PARAMETER(function_c);
-		result.a = 0;
-		result.b = 0;
-		result.c = 0;
-		result.d = 0;
-	#endif
+	int CPUInfo[4];
+	__cpuidex(CPUInfo, function_a, function_c);
+	result.a = CPUInfo[0];
+	result.b = CPUInfo[1];
+	result.c = CPUInfo[2];
+	result.d = CPUInfo[3];
 	return result;
 }
 
+#endif
+
 
 static MPT_NOINLINE bool has_cpuid()
-//----------------------------------
 {
 	const size_t eflags_cpuid = 1 << 21;
 	size_t eflags_old = __readeflags();
@@ -112,7 +103,6 @@ static MPT_NOINLINE bool has_cpuid()
 
 
 void InitProcSupport()
-//--------------------
 {
 
 	RealProcSupport = 0;
@@ -140,17 +130,39 @@ void InitProcSupport()
 			uint32 BaseFamily = (StandardFeatureFlags.a >>  8) & 0x0f;
 			uint32 ExtModel   = (StandardFeatureFlags.a >> 16) & 0x0f;
 			uint32 ExtFamily  = (StandardFeatureFlags.a >> 20) & 0xff;
-			if(BaseFamily < 0xf)
+			if(VendorString.as_string() == "GenuineIntel")
 			{
-				ProcFamily = static_cast<uint16>(BaseFamily);
-				ProcModel = static_cast<uint8>(BaseModel);
-				ProcStepping = static_cast<uint8>(Stepping);
+				if(BaseFamily == 0xf)
+				{
+					ProcFamily = static_cast<uint16>(ExtFamily + BaseFamily);
+				} else
+				{
+					ProcFamily = static_cast<uint16>(BaseFamily);
+				}
+				if(BaseFamily == 0x6 || BaseFamily == 0xf)
+				{
+					ProcModel = static_cast<uint8>((ExtModel << 4) | (BaseModel << 0));
+				} else
+				{
+					ProcModel = static_cast<uint8>(BaseModel);
+				}
+			} else if(VendorString.as_string() == "AuthenticAMD")
+			{
+				if(BaseFamily == 0xf)
+				{
+					ProcFamily = static_cast<uint16>(ExtFamily + BaseFamily);
+					ProcModel = static_cast<uint8>((ExtModel << 4) | (BaseModel << 0));
+				} else
+				{
+					ProcFamily = static_cast<uint16>(BaseFamily);
+					ProcModel = static_cast<uint8>(BaseModel);
+				}
 			} else
 			{
-				ProcFamily = static_cast<uint16>(ExtFamily + BaseFamily);
-				ProcModel = static_cast<uint8>((ExtModel << 4) | (BaseModel << 0));
-				ProcStepping = static_cast<uint8>(Stepping);
+				ProcFamily = static_cast<uint16>(BaseFamily);
+				ProcModel = static_cast<uint8>(BaseModel);
 			}
+			ProcStepping = static_cast<uint8>(Stepping);
 			if(StandardFeatureFlags.d & (1<< 4)) ProcSupport |= PROCSUPPORT_TSC;
 			if(StandardFeatureFlags.d & (1<<15)) ProcSupport |= PROCSUPPORT_CMOV;
 			if(StandardFeatureFlags.d & (1<< 0)) ProcSupport |= PROCSUPPORT_FPU;
@@ -277,7 +289,6 @@ void InitProcSupport()
 
 
 void InitProcSupport()
-//--------------------
 {
 	ProcSupport = 0;
 }
@@ -291,8 +302,32 @@ void InitProcSupport()
 #ifdef MODPLUG_TRACKER
 
 
+uint32 GetMinimumProcSupportFlags()
+{
+	uint32 flags = 0;
+	#ifdef ENABLE_ASM
+		#if MPT_COMPILER_MSVC
+			#if defined(_M_X64)
+				flags |= PROCSUPPORT_AMD64;
+			#elif defined(_M_IX86)
+				#if defined(_M_IX86_FP)
+					#if (_M_IX86_FP >= 2)
+						flags |= PROCSUPPORT_x86_SSE2;
+					#elif (_M_IX86_FP == 1)
+						flags |= PROCSUPPORT_x86_SSE;
+					#endif
+				#else
+					flags |= PROCSUPPORT_i586;
+				#endif
+			#endif
+		#endif	
+	#endif // ENABLE_ASM
+	return flags;
+}
+
+
+
 int GetMinimumSSEVersion()
-//------------------------
 {
 	int minimumSSEVersion = 0;
 	#if MPT_COMPILER_MSVC
@@ -313,7 +348,6 @@ int GetMinimumSSEVersion()
 
 
 int GetMinimumAVXVersion()
-//------------------------
 {
 	int minimumAVXVersion = 0;
 	#if MPT_COMPILER_MSVC
diff --git a/common/mptCPU.h b/common/mptCPU.h
index 680d6ee..241e6b4 100644
--- a/common/mptCPU.h
+++ b/common/mptCPU.h
@@ -15,6 +15,7 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 #ifdef ENABLE_ASM
+
 #define PROCSUPPORT_CPUID        0x00001 // Processor supports CPUID instruction (i586)
 #define PROCSUPPORT_TSC          0x00002 // Processor supports RDTSC instruction (i586)
 #define PROCSUPPORT_CMOV         0x00004 // Processor supports conditional move instructions (i686)
@@ -29,18 +30,29 @@ OPENMPT_NAMESPACE_BEGIN
 #define PROCSUPPORT_SSSE3        0x00800 // Processor supports SSSE3 instructions
 #define PROCSUPPORT_SSE4_1       0x01000 // Processor supports SSE4.1 instructions
 #define PROCSUPPORT_SSE4_2       0x02000 // Processor supports SSE4.2 instructions
+
+static const uint32 PROCSUPPORT_i486     = 0u                                        | PROCSUPPORT_FPU                                     ;
+static const uint32 PROCSUPPORT_i586     = 0u | PROCSUPPORT_CPUID                    | PROCSUPPORT_FPU                                     ;
+static const uint32 PROCSUPPORT_i686     = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_FPU                                     ;
+static const uint32 PROCSUPPORT_x86_SSE  = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_FPU | PROCSUPPORT_SSE                   ;
+static const uint32 PROCSUPPORT_x86_SSE2 = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_FPU | PROCSUPPORT_SSE | PROCSUPPORT_SSE2;
+static const uint32 PROCSUPPORT_AMD64    = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV                   | PROCSUPPORT_SSE | PROCSUPPORT_SSE2;
+
 extern uint32 RealProcSupport;
 extern uint32 ProcSupport;
 extern char ProcVendorID[16+1];
 extern uint16 ProcFamily;
 extern uint8 ProcModel;
 extern uint8 ProcStepping;
+
 void InitProcSupport();
+
 // enabled processor features for inline asm and intrinsics
 static inline uint32 GetProcSupport()
 {
 	return ProcSupport;
 }
+
 // available processor features
 static inline uint32 GetRealProcSupport()
 {
@@ -51,6 +63,7 @@ static inline uint32 GetRealProcSupport()
 
 
 #ifdef MODPLUG_TRACKER
+uint32 GetMinimumProcSupportFlags();
 int GetMinimumSSEVersion();
 int GetMinimumAVXVersion();
 #endif
diff --git a/common/mptFileIO.cpp b/common/mptFileIO.cpp
index c6b6fb1..ecaa58e 100644
--- a/common/mptFileIO.cpp
+++ b/common/mptFileIO.cpp
@@ -94,19 +94,95 @@ bool SetFilesystemCompression(const mpt::PathString &filename)
 
 
 
+namespace mpt {
+
+LazyFileRef & LazyFileRef::operator = (const std::vector<mpt::byte> &data)
+{
+	mpt::ofstream file(m_Filename, std::ios::binary);
+	file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+	mpt::IO::WriteRaw(file, data.data(), data.size());
+	mpt::IO::Flush(file);
+	return *this;
+}
+
+LazyFileRef & LazyFileRef::operator = (const std::vector<char> &data)
+{
+	mpt::ofstream file(m_Filename, std::ios::binary);
+	file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+	mpt::IO::WriteRaw(file, data.data(), data.size());
+	mpt::IO::Flush(file);
+	return *this;
+}
+
+LazyFileRef & LazyFileRef::operator = (const std::string &data)
+{
+	mpt::ofstream file(m_Filename, std::ios::binary);
+	file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+	mpt::IO::WriteRaw(file, data.data(), data.size());
+	mpt::IO::Flush(file);
+	return *this;
+}
+
+LazyFileRef::operator std::vector<mpt::byte> () const
+{
+	mpt::ifstream file(m_Filename, std::ios::binary);
+	if(!mpt::IO::IsValid(file))
+	{
+		return std::vector<mpt::byte>();
+	}
+	file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+	mpt::IO::SeekEnd(file);
+	std::vector<mpt::byte> buf(mpt::saturate_cast<std::size_t>(mpt::IO::TellRead(file)));
+	mpt::IO::SeekBegin(file);
+	mpt::IO::ReadRaw(file, buf.data(), buf.size());
+	return buf;
+}
+
+LazyFileRef::operator std::vector<char> () const
+{
+	mpt::ifstream file(m_Filename, std::ios::binary);
+	if(!mpt::IO::IsValid(file))
+	{
+		return std::vector<char>();
+	}
+	file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+	mpt::IO::SeekEnd(file);
+	std::vector<char> buf(mpt::saturate_cast<std::size_t>(mpt::IO::TellRead(file)));
+	mpt::IO::SeekBegin(file);
+	mpt::IO::ReadRaw(file, buf.data(), buf.size());
+	return buf;
+}
+
+LazyFileRef::operator std::string () const
+{
+	mpt::ifstream file(m_Filename, std::ios::binary);
+	if(!mpt::IO::IsValid(file))
+	{
+		return std::string();
+	}
+	file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+	mpt::IO::SeekEnd(file);
+	std::vector<char> buf(mpt::saturate_cast<std::size_t>(mpt::IO::TellRead(file)));
+	mpt::IO::SeekBegin(file);
+	mpt::IO::ReadRaw(file, buf.data(), buf.size());
+	return std::string(buf.begin(), buf.end());
+}
+
+} // namespace mpt
+
+
+
 #ifdef MODPLUG_TRACKER
 
 #if MPT_OS_WINDOWS
 
 CMappedFile::~CMappedFile()
-//-------------------------
 {
 	Close();
 }
 
 
 bool CMappedFile::Open(const mpt::PathString &filename)
-//-----------------------------------------------------
 {
 	m_hFile = CreateFileW(
 		filename.AsNativePrefixed().c_str(),
@@ -127,7 +203,6 @@ bool CMappedFile::Open(const mpt::PathString &filename)
 
 
 void CMappedFile::Close()
-//-----------------------
 {
 	m_FileName = mpt::PathString();
 	// Unlock file
@@ -156,7 +231,6 @@ void CMappedFile::Close()
 
 
 size_t CMappedFile::GetLength()
-//-----------------------------
 {
 	LARGE_INTEGER size;
 	if(GetFileSizeEx(m_hFile, &size) == FALSE)
@@ -168,7 +242,6 @@ size_t CMappedFile::GetLength()
 
 
 const mpt::byte *CMappedFile::Lock()
-//----------------------------------
 {
 	size_t length = GetLength();
 	if(!length) return nullptr;
diff --git a/common/mptFileIO.h b/common/mptFileIO.h
index c0bade6..164ac57 100644
--- a/common/mptFileIO.h
+++ b/common/mptFileIO.h
@@ -33,7 +33,6 @@ OPENMPT_NAMESPACE_BEGIN
 #if defined(MPT_ENABLE_FILEIO_STDIO)
 
 static inline FILE * mpt_fopen(const mpt::PathString &filename, const char *mode)
-//-------------------------------------------------------------------------------
 {
 	#if MPT_OS_WINDOWS
 		return _wfopen(filename.AsNativePrefixed().c_str(), mode ? mpt::ToWide(mpt::CharsetASCII, mode).c_str() : L"");
@@ -64,15 +63,7 @@ bool SetFilesystemCompression(const mpt::PathString &filename);
 namespace mpt
 {
 
-#if MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2010,0)
-
-// VS2008 converts char filenames with CRT mbcs string conversion functions to wchar_t filenames.
-// This is totally wrong for Win32 GUI applications because the C locale does not necessarily match the current windows ANSI codepage (CP_ACP).
-// Work around this insanity by using our own string conversions for the std::fstream filenames.
-
-#define MPT_FSTREAM_DO_CONVERSIONS
-
-#elif MPT_COMPILER_GCC
+#if MPT_COMPILER_GCC
 
 #if MPT_OS_WINDOWS
 // GCC C++ library has no wchar_t overloads
@@ -240,6 +231,29 @@ public:
 
 
 
+// LazyFileRef is a simple reference to an on-disk file by the means of a
+// filename which allows easy assignment of the whole file contents to and from
+// byte buffers.
+class LazyFileRef {
+private:
+	const mpt::PathString m_Filename;
+public:
+	LazyFileRef(const mpt::PathString &filename)
+		: m_Filename(filename)
+	{
+		return;
+	}
+public:
+	LazyFileRef & operator = (const std::vector<mpt::byte> &data);
+	LazyFileRef & operator = (const std::vector<char> &data);
+	LazyFileRef & operator = (const std::string &data);
+	operator std::vector<mpt::byte> () const;
+	operator std::vector<char> () const;
+	operator std::string () const;
+};
+
+
+
 #if defined(MPT_ENABLE_FILEIO_STDIO)
 
 // class FILE_ostream, FILE_output_streambuf and FILE_output_buffered_streambuf
@@ -400,7 +414,7 @@ public:
 		: FILE_output_streambuf(f)
 		, buf((bufSize > 0) ? bufSize : 1)
 	{
-		setp(&buf[0], &buf[0] + buf.size());
+		setp(buf.data(), buf.data() + buf.size());
 	}
 	~FILE_output_buffered_streambuf()
 	{
@@ -515,9 +529,7 @@ public:
 
 #ifdef MODPLUG_TRACKER
 #if MPT_OS_WINDOWS
-//===============
 class CMappedFile
-//===============
 {
 protected:
 	HANDLE m_hFile;
@@ -541,9 +553,7 @@ public:
 #endif // MODPLUG_TRACKER
 
 
-//=============
 class InputFile
-//=============
 {
 private:
 	mpt::PathString m_Filename;
diff --git a/common/mptIO.cpp b/common/mptIO.cpp
index 6875fbf..ba42afa 100644
--- a/common/mptIO.cpp
+++ b/common/mptIO.cpp
@@ -132,22 +132,10 @@ bool IsValid(std::istream & f) { return !f.fail(); }
 bool IsValid(std::iostream & f) { return !f.fail(); }
 IO::Offset TellRead(std::istream & f)
 {
-	#if MPT_MSVC_BEFORE(2010, 0)
-		if(StreamIsStringStreamAndValidAndEmpty(f))
-		{
-			return 0;
-		}
-	#endif
 	return f.tellg();
 }
 IO::Offset TellWrite(std::ostream & f)
 {
-	#if MPT_MSVC_BEFORE(2010, 0)
-		if(StreamIsStringStreamAndValidAndEmpty(f))
-		{
-			return 0;
-		}
-	#endif
 	return f.tellp();
 }
 bool SeekBegin(std::ostream & f)
@@ -373,7 +361,7 @@ void FileDataContainerSeekable::CacheStream() const
 		return;
 	}
 	cache.resize(streamLength);
-	InternalRead(&cache[0], 0, streamLength);
+	InternalRead(cache.data(), 0, streamLength);
 	cached = true;
 }
 
@@ -382,6 +370,11 @@ bool FileDataContainerSeekable::IsValid() const
 	return true;
 }
 
+bool FileDataContainerSeekable::HasFastGetLength() const
+{
+	return true;
+}
+
 bool FileDataContainerSeekable::HasPinnedView() const
 {
 	return cached;
@@ -390,7 +383,7 @@ bool FileDataContainerSeekable::HasPinnedView() const
 const mpt::byte *FileDataContainerSeekable::GetRawData() const
 {
 	CacheStream();
-	return &cache[0];
+	return cache.data();
 }
 
 IFileDataContainer::off_t FileDataContainerSeekable::GetLength() const
@@ -568,6 +561,11 @@ bool FileDataContainerUnseekable::IsValid() const
 	return true;
 }
 
+bool FileDataContainerUnseekable::HasFastGetLength() const
+{
+	return false;
+}
+
 bool FileDataContainerUnseekable::HasPinnedView() const
 {
 	return true; // we have the cache which is required for seeking anyway
@@ -576,7 +574,7 @@ bool FileDataContainerUnseekable::HasPinnedView() const
 const mpt::byte *FileDataContainerUnseekable::GetRawData() const
 {
 	CacheStream();
-	return &cache[0];
+	return cache.data();
 }
 
 IFileDataContainer::off_t FileDataContainerUnseekable::GetLength() const
diff --git a/common/mptIO.h b/common/mptIO.h
index 8a584d0..4899124 100644
--- a/common/mptIO.h
+++ b/common/mptIO.h
@@ -191,20 +191,27 @@ inline bool WriteRaw(Tfile & f, const Tbyte * data, std::size_t size)
 template <typename Tbinary, typename Tfile>
 inline bool Read(Tfile & f, Tbinary & v)
 {
-	return IO::ReadRaw(f, mpt::GetRawBytes(v), sizeof(Tbinary)) == sizeof(Tbinary);
+	return IO::ReadRaw(f, mpt::as_raw_memory(v), sizeof(Tbinary)) == sizeof(Tbinary);
 }
 
 template <typename Tbinary, typename Tfile>
 inline bool Write(Tfile & f, const Tbinary & v)
 {
-	return IO::WriteRaw(f, mpt::GetRawBytes(v), sizeof(Tbinary));
+	return IO::WriteRaw(f, mpt::as_raw_memory(v), sizeof(Tbinary));
+}
+
+template <typename T, typename Tfile>
+inline bool WritePartial(Tfile & f, const T & v, size_t size = sizeof(T))
+{
+	MPT_ASSERT(size <= sizeof(T));
+	return IO::WriteRaw(f, mpt::as_raw_memory(v), size);
 }
 
 template <typename T, typename Tfile>
 inline bool ReadBinaryTruncatedLE(Tfile & f, T & v, std::size_t size)
 {
 	bool result = false;
-	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
 	mpt::byte bytes[sizeof(T)];
 	std::memset(bytes, 0, sizeof(T));
 	const IO::Offset readResult = IO::ReadRaw(f, bytes, std::min(size, sizeof(T)));
@@ -239,7 +246,7 @@ inline bool ReadIntLE(Tfile & f, T & v)
 	}
 	T val = 0;
 	std::memcpy(&val, bytes, sizeof(T));
-	v = SwapBytesReturnLE(val);
+	v = SwapBytesLE(val);
 	return result;
 }
 
@@ -260,7 +267,7 @@ inline bool ReadIntBE(Tfile & f, T & v)
 	}
 	T val = 0;
 	std::memcpy(&val, bytes, sizeof(T));
-	v = SwapBytesReturnBE(val);
+	v = SwapBytesBE(val);
 	return result;
 }
 
@@ -355,7 +362,7 @@ template <typename T, typename Tfile>
 inline bool WriteIntLE(Tfile & f, const T v)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	const T val = SwapBytesReturnLE(v);
+	const T val = SwapBytesLE(v);
 	mpt::byte bytes[sizeof(T)];
 	std::memcpy(bytes, &val, sizeof(T));
 	return IO::WriteRaw(f, bytes, sizeof(T));
@@ -365,7 +372,7 @@ template <typename T, typename Tfile>
 inline bool WriteIntBE(Tfile & f, const T v)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	const T val = SwapBytesReturnBE(v);
+	const T val = SwapBytesBE(v);
 	mpt::byte bytes[sizeof(T)];
 	std::memcpy(bytes, &val, sizeof(T));
 	return IO::WriteRaw(f, bytes, sizeof(T));
@@ -461,7 +468,7 @@ bool WriteVarInt(Tfile & f, const T v, size_t *bytesWritten = nullptr)
 		}
 	}
 	out[numBytes++] = static_cast<mpt::byte>(v & 0x7F);
-	MPT_ASSERT(numBytes <= CountOf(out));
+	MPT_ASSERT(numBytes <= mpt::size(out));
 	if(bytesWritten != nullptr) *bytesWritten = numBytes;
 	return mpt::IO::WriteRaw(f, out, numBytes);
 }
@@ -486,13 +493,34 @@ inline bool WriteSizedStringLE(Tfile & f, const std::string & str)
 	return true;
 }
 
-template <typename T, typename Tfile>
-inline bool WriteConvertEndianness(Tfile & f, T & v)
+template <typename Tfile>
+inline bool WriteText(Tfile &f, const std::string &s)
 {
-	v.ConvertEndianness();
-	bool result = IO::WriteRaw(f, reinterpret_cast<const mpt::byte *>(&v), sizeof(T));
-	v.ConvertEndianness();
-	return result;
+	return mpt::IO::WriteRaw(f, s.data(), s.size());
+}
+
+template <typename Tfile>
+inline bool WriteTextCRLF(Tfile &f)
+{
+	return mpt::IO::WriteText(f, "\r\n");
+}
+
+template <typename Tfile>
+inline bool WriteTextLF(Tfile &f)
+{
+	return mpt::IO::WriteText(f, "\n");
+}
+
+template <typename Tfile>
+inline bool WriteTextCRLF(Tfile &f, const std::string &s)
+{
+	return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextCRLF(f);
+}
+
+template <typename Tfile>
+inline bool WriteTextLF(Tfile &f, const std::string &s)
+{
+	return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextLF(f);
 }
 
 } // namespace IO
@@ -513,6 +541,7 @@ public:
 	virtual ~IFileDataContainer() { }
 public:
 	virtual bool IsValid() const = 0;
+	virtual bool HasFastGetLength() const = 0;
 	virtual bool HasPinnedView() const = 0;
 	virtual const mpt::byte *GetRawData() const = 0;
 	virtual off_t GetLength() const = 0;
@@ -554,6 +583,11 @@ public:
 		return false;
 	}
 
+	bool HasFastGetLength() const
+	{
+		return true;
+	}
+
 	bool HasPinnedView() const
 	{
 		return true;
@@ -578,17 +612,21 @@ public:
 class FileDataContainerWindow : public IFileDataContainer
 {
 private:
-	MPT_SHARED_PTR<IFileDataContainer> data;
+	std::shared_ptr<const IFileDataContainer> data;
 	const off_t dataOffset;
 	const off_t dataLength;
 public:
-	FileDataContainerWindow(MPT_SHARED_PTR<IFileDataContainer> src, off_t off, off_t len) : data(src), dataOffset(off), dataLength(len) { }
+	FileDataContainerWindow(std::shared_ptr<const IFileDataContainer> src, off_t off, off_t len) : data(src), dataOffset(off), dataLength(len) { }
 	virtual ~FileDataContainerWindow() { }
 
 	bool IsValid() const
 	{
 		return data->IsValid();
 	}
+	bool HasFastGetLength() const
+	{
+		return data->HasFastGetLength();
+	}
 	bool HasPinnedView() const
 	{
 		return data->HasPinnedView();
@@ -650,6 +688,7 @@ private:
 public:
 
 	bool IsValid() const;
+	bool HasFastGetLength() const;
 	bool HasPinnedView() const;
 	const mpt::byte *GetRawData() const;
 	off_t GetLength() const;
@@ -712,6 +751,7 @@ private:
 public:
 
 	bool IsValid() const;
+	bool HasFastGetLength() const;
 	bool HasPinnedView() const;
 	const mpt::byte *GetRawData() const;
 	off_t GetLength() const;
@@ -813,7 +853,7 @@ private:
 
 public:
 	FileDataContainerMemory() : streamData(nullptr), streamLength(0) { }
-	FileDataContainerMemory(mpt::span<const mpt::byte> data) : streamData(data.data()), streamLength(data.size()) { }
+	FileDataContainerMemory(mpt::const_byte_span data) : streamData(data.data()), streamLength(data.size()) { }
 #if defined(MPT_FILEREADER_STD_ISTREAM)
 	virtual
 #endif
@@ -826,6 +866,11 @@ public:
 		return streamData != nullptr;
 	}
 
+	bool HasFastGetLength() const
+	{
+		return true;
+	}
+
 	bool HasPinnedView() const
 	{
 		return true;
diff --git a/common/mptLibrary.cpp b/common/mptLibrary.cpp
index ad4c8f2..2bc01fe 100644
--- a/common/mptLibrary.cpp
+++ b/common/mptLibrary.cpp
@@ -52,33 +52,6 @@ namespace mpt
 #endif
 
 
-mpt::PathString GetAppPath()
-{
-	std::vector<WCHAR> exeFileName(MAX_PATH);
-	while(GetModuleFileNameW(0, &exeFileName[0], mpt::saturate_cast<DWORD>(exeFileName.size())) >= exeFileName.size())
-	{
-		if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-		{
-			return mpt::PathString();
-		}
-		exeFileName.resize(exeFileName.size() * 2);
-	}
-	return mpt::GetAbsolutePath(mpt::PathString::FromNative(&exeFileName[0]).GetPath());
-}
-
-
-mpt::PathString GetSystemPath()
-{
-	DWORD size = GetSystemDirectoryW(nullptr, 0);
-	std::vector<WCHAR> path(size + 1);
-	if(!GetSystemDirectoryW(&path[0], size + 1))
-	{
-		return mpt::PathString();
-	}
-	return mpt::PathString::FromNative(&path[0]) + MPT_PATHSTRING("\\");
-}
-
-
 class LibraryHandle
 {
 
@@ -92,6 +65,34 @@ public:
 		: hModule(NULL)
 	{
 
+#if MPT_OS_WINDOWS_WINRT
+
+#if (_WIN32_WINNT < 0x0602)
+		(void)path;
+		hModule = NULL; // unsupported
+#else
+		switch(path.GetSearchPath())
+		{
+			case mpt::LibrarySearchPathDefault:
+				hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0);
+				break;
+			case mpt::LibrarySearchPathApplication:
+				hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0);
+				break;
+			case mpt::LibrarySearchPathSystem:
+				hModule = NULL; // Only application packaged libraries can be loaded dynamically in WinRT
+				break;
+			case mpt::LibrarySearchPathFullPath:
+				hModule = NULL; // Absolute path is not supported in WinRT
+				break;
+			case mpt::LibrarySearchPathInvalid:
+				MPT_ASSERT_NOTREACHED();
+				break;
+		}
+#endif
+
+#else // !MPT_OS_WINDOWS_WINRT
+
 		mpt::Windows::Version WindowsVersion = mpt::Windows::Version::Current();
 
 		// Check for KB2533623:
@@ -151,6 +152,9 @@ public:
 					hModule = LoadLibraryExW(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
 					break;
 #endif
+				case mpt::LibrarySearchPathInvalid:
+					MPT_ASSERT_NOTREACHED();
+					break;
 			}
 		} else
 		{
@@ -180,8 +184,14 @@ public:
 				case mpt::LibrarySearchPathFullPath:
 					hModule = LoadLibraryW(path.GetFileName().AsNative().c_str());
 					break;
+				case mpt::LibrarySearchPathInvalid:
+					MPT_ASSERT_NOTREACHED();
+					break;
 			}
 		}
+
+#endif // MPT_OS_WINDOWS_WINRT
+
 	}
 
 	~LibraryHandle()
@@ -400,7 +410,6 @@ public:
 
 
 LibraryPath::LibraryPath(mpt::LibrarySearchPath searchPath, class mpt::PathString const &fileName)
-//------------------------------------------------------------------------------------------------
 	: searchPath(searchPath)
 	, fileName(fileName)
 {
@@ -409,21 +418,18 @@ LibraryPath::LibraryPath(mpt::LibrarySearchPath searchPath, class mpt::PathStrin
 
 
 mpt::LibrarySearchPath LibraryPath::GetSearchPath() const
-//-------------------------------------------------------
 {
 	return searchPath;
 }
 
 
 mpt::PathString LibraryPath::GetFileName() const
-//----------------------------------------------
 {
 	return fileName;
 }
 
 
 mpt::PathString LibraryPath::GetDefaultPrefix()
-//---------------------------------------------
 {
 	#if MPT_OS_WINDOWS
 		return MPT_PATHSTRING("");
@@ -440,7 +446,6 @@ mpt::PathString LibraryPath::GetDefaultPrefix()
 
 
 mpt::PathString LibraryPath::GetDefaultSuffix()
-//---------------------------------------------
 {
 	#if MPT_OS_WINDOWS
 		return MPT_PATHSTRING(".dll");
@@ -457,63 +462,76 @@ mpt::PathString LibraryPath::GetDefaultSuffix()
 
 
 LibraryPath LibraryPath::App(const mpt::PathString &basename)
-//-----------------------------------------------------------
 {
 	return LibraryPath(mpt::LibrarySearchPathApplication, GetDefaultPrefix() + basename + GetDefaultSuffix());
 }
 
 
 LibraryPath LibraryPath::AppFullName(const mpt::PathString &fullname)
-//-------------------------------------------------------------------
 {
 	return LibraryPath(mpt::LibrarySearchPathApplication, fullname + GetDefaultSuffix());
 }
 
 
+#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
+
+LibraryPath LibraryPath::AppDataFullName(const mpt::PathString &fullname, const mpt::PathString &appdata)
+{
+	if(appdata.empty())
+	{
+		return LibraryPath(mpt::LibrarySearchPathInvalid, MPT_PATHSTRING(""));
+	}
+	return LibraryPath(mpt::LibrarySearchPathFullPath, appdata.WithTrailingSlash() + fullname + GetDefaultSuffix());
+}
+
+#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
+
+
 LibraryPath LibraryPath::System(const mpt::PathString &basename)
-//--------------------------------------------------------------
 {
 	return LibraryPath(mpt::LibrarySearchPathSystem, GetDefaultPrefix() + basename + GetDefaultSuffix());
 }
 
 
 LibraryPath LibraryPath::FullPath(const mpt::PathString &path)
-//------------------------------------------------------------
 {
 	return LibraryPath(mpt::LibrarySearchPathFullPath, path);
 }
 
 
 Library::Library()
-//----------------
 {
 	return;
 }
 
 
 Library::Library(const mpt::LibraryPath &path)
-//--------------------------------------------
 {
-	m_Handle = mpt::make_shared<LibraryHandle>(path);
+	if(path.GetSearchPath() == mpt::LibrarySearchPathInvalid)
+	{
+		return;
+	}
+	if(path.GetFileName().empty())
+	{
+		return;
+	}
+	m_Handle = std::make_shared<LibraryHandle>(path);
 }
 
 
 void Library::Unload()
-//--------------------
 {
 	*this = mpt::Library();
 }
 
 
 bool Library::IsValid() const
-//---------------------------
 {
 	return m_Handle && m_Handle->IsValid();
 }
 
 
 FuncPtr Library::GetProcAddress(const std::string &symbol) const
-//--------------------------------------------------------------
 {
 	if(!IsValid())
 	{
diff --git a/common/mptLibrary.h b/common/mptLibrary.h
index e440d20..36a7148 100644
--- a/common/mptLibrary.h
+++ b/common/mptLibrary.h
@@ -20,23 +20,13 @@ namespace mpt
 {
 
 
-#if MPT_OS_WINDOWS
-
-// Returns the application path or an empty string (if unknown), e.g. "C:\mptrack\"
-mpt::PathString GetAppPath();
-
-// Returns the system directory path, e.g. "C:\Windows\System32\"
-mpt::PathString GetSystemPath();
-
-#endif // MPT_OS_WINDOWS
-
-
 typedef void* (*FuncPtr)(); // pointer to function returning void*
 
 class LibraryHandle;
 
 enum LibrarySearchPath
 {
+	LibrarySearchPathInvalid,
 	LibrarySearchPathDefault,
 	LibrarySearchPathApplication,
 	LibrarySearchPathSystem,
@@ -77,6 +67,14 @@ public:
 	// e.g.: fullname = "libunmo3" --> "libunmo3.so" / "apppath/libunmo3.dll" 
 	static LibraryPath AppFullName(const mpt::PathString &fullname);
 
+#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
+
+	// Returns the library path in the application data directory, with os-specific suffix added to fullname.
+	// e.g.: fullname = "libunmo3" --> "libunmo3.so" / "appdata/libunmo3.dll" (appdata == C:\Users\SOMEUSER\AppData\OpenMPT\Components\)
+	static LibraryPath AppDataFullName(const mpt::PathString &fullname, const mpt::PathString &appdata);
+
+#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
+
 	// Returns a system library name with os-specific prefix and suffix added to basename, but without any full path in order to be searched in the default search path.
 	// e.g.: basename = "unmo3" --> "libunmo3.so" / "unmo3.dll"
 	static LibraryPath System(const mpt::PathString &basename);
@@ -90,7 +88,7 @@ public:
 class Library
 {
 protected:
-	MPT_SHARED_PTR<LibraryHandle> m_Handle;
+	std::shared_ptr<LibraryHandle> m_Handle;
 public:
 	Library();
 	Library(const mpt::LibraryPath &path);
@@ -101,13 +99,10 @@ public:
 	template <typename Tfunc>
 	bool Bind(Tfunc * & f, const std::string &symbol) const
 	{
-		#if MPT_COMPILER_HAS_TYPE_TRAITS
-			#if ((MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2013,0)) || !MPT_COMPILER_MSVC) && !(MPT_OS_WINDOWS && MPT_COMPILER_GCC)
-				// MSVC std::is_function is always false for non __cdecl functions.
-				// See https://connect.microsoft.com/VisualStudio/feedback/details/774720/stl-is-function-bug .
-				// MinGW64 has the same problem.
-				STATIC_ASSERT(std::is_function<Tfunc>::value);
-			#endif
+		#if !(MPT_OS_WINDOWS && MPT_COMPILER_GCC)
+			// MinGW64 std::is_function is always false for non __cdecl functions.
+			// See https://connect.microsoft.com/VisualStudio/feedback/details/774720/stl-is-function-bug .
+			STATIC_ASSERT(std::is_function<Tfunc>::value);
 		#endif
 		const FuncPtr addr = GetProcAddress(symbol);
 		f = reinterpret_cast<Tfunc*>(addr);
diff --git a/common/mptMutex.h b/common/mptMutex.h
index eac7371..26d0971 100644
--- a/common/mptMutex.h
+++ b/common/mptMutex.h
@@ -11,9 +11,9 @@
 
 #include <vector> // some C++ header in order to have the C++ standard library version information available
 
-#if MPT_OS_ANDROID
+#if !MPT_PLATFORM_MULTITHREADED
 #define MPT_MUTEX_STD     0
-#define MPT_MUTEX_PTHREAD 1
+#define MPT_MUTEX_PTHREAD 0
 #define MPT_MUTEX_WIN32   0
 #elif MPT_OS_EMSCRIPTEN
 #define MPT_MUTEX_STD     0
@@ -23,19 +23,19 @@
 #define MPT_MUTEX_STD     1
 #define MPT_MUTEX_PTHREAD 0
 #define MPT_MUTEX_WIN32   0
-#elif MPT_MSVC_AT_LEAST(2012,0) && !defined(MPT_QUIRK_NO_CPP_THREAD)
+#elif MPT_COMPILER_MSVC && !defined(MPT_QUIRK_NO_CPP_THREAD)
 #define MPT_MUTEX_STD     1
 #define MPT_MUTEX_PTHREAD 0
 #define MPT_MUTEX_WIN32   0
-#elif MPT_GCC_AT_LEAST(4,4,0) && !MPT_OS_WINDOWS && !defined(MPT_QUIRK_NO_CPP_THREAD)
+#elif MPT_COMPILER_GCC && !MPT_OS_WINDOWS && !defined(MPT_QUIRK_NO_CPP_THREAD)
 #define MPT_MUTEX_STD     1
 #define MPT_MUTEX_PTHREAD 0
 #define MPT_MUTEX_WIN32   0
-#elif MPT_CLANG_AT_LEAST(3,2,0) && defined(__GLIBCXX__) && !defined(MPT_QUIRK_NO_CPP_THREAD)
+#elif MPT_COMPILER_CLANG && defined(__GLIBCXX__) && !defined(MPT_QUIRK_NO_CPP_THREAD)
 #define MPT_MUTEX_STD     1
 #define MPT_MUTEX_PTHREAD 0
 #define MPT_MUTEX_WIN32   0
-#elif (MPT_OS_MACOSX_OR_IOS || MPT_OS_FREEBSD) && MPT_CLANG_AT_LEAST(3,0,0) && !defined(MPT_QUIRK_NO_CPP_THREAD)
+#elif (MPT_OS_MACOSX_OR_IOS || MPT_OS_FREEBSD) && MPT_COMPILER_CLANG && !defined(MPT_QUIRK_NO_CPP_THREAD)
 #define MPT_MUTEX_STD     1
 #define MPT_MUTEX_PTHREAD 0
 #define MPT_MUTEX_WIN32   0
diff --git a/common/mptOS.cpp b/common/mptOS.cpp
index 7ae608b..89c15f6 100644
--- a/common/mptOS.cpp
+++ b/common/mptOS.cpp
@@ -28,22 +28,25 @@ namespace Windows
 #if MPT_OS_WINDOWS
 
 
+#if !MPT_OS_WINDOWS_WINRT
+
 static uint32 VersionDecimalTo_WIN32_WINNT(uint32 major, uint32 minor)
 {
 	// GetVersionEx returns decimal.
 	// _WIN32_WINNT macro uses BCD for the minor byte (see Windows 98 / ME).
 	// We use what _WIN32_WINNT does.
 	uint32 result = 0;
-	minor = Clamp(minor, 0u, 99u);
+	minor = mpt::clamp<uint32>(minor, 0, 99);
 	result |= major;
 	result <<= 8;
 	result |= minor/10*0x10 + minor%10;
 	return result;
 }
 
+#endif // !MPT_OS_WINDOWS_WINRT
+
 
-static void GatherWindowsVersion(bool & SystemIsNT, uint32 & SystemVersion)
-//-------------------------------------------------------------------------
+static void GatherWindowsVersion(uint32 & SystemVersion)
 {
 	// Initialize to used SDK version
 	SystemVersion =
@@ -57,6 +60,8 @@ static void GatherWindowsVersion(bool & SystemIsNT, uint32 & SystemVersion)
 			mpt::Windows::Version::Win7
 		#elif NTDDI_VERSION >= 0x06000000 // NTDDI_VISTA
 			mpt::Windows::Version::WinVista
+		#elif NTDDI_VERSION >= 0x05020000 // NTDDI_WS03
+			mpt::Windows::Version::WinXP64
 		#elif NTDDI_VERSION >= NTDDI_WINXP
 			mpt::Windows::Version::WinXP
 		#elif NTDDI_VERSION >= NTDDI_WIN2K
@@ -65,12 +70,27 @@ static void GatherWindowsVersion(bool & SystemIsNT, uint32 & SystemVersion)
 			mpt::Windows::Version::WinNT4
 		#endif
 		;
+#if !MPT_OS_WINDOWS_WINRT
 	OSVERSIONINFOEXW versioninfoex;
 	MemsetZero(versioninfoex);
 	versioninfoex.dwOSVersionInfoSize = sizeof(versioninfoex);
+#if MPT_COMPILER_MSVC
+#pragma warning(push)
+#pragma warning(disable:4996) // 'GetVersionExW': was declared deprecated
+#endif // MPT_COMPILER_MSVC
+#if MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif // MPT_COMPILER_CLANG
 	GetVersionExW((LPOSVERSIONINFOW)&versioninfoex);
-	SystemIsNT = (versioninfoex.dwPlatformId == VER_PLATFORM_WIN32_NT);
+#if MPT_COMPILER_MSVC
+#pragma warning(pop)
+#endif // MPT_COMPILER_MSVC
+#if MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
+#pragma clang diagnostic pop
+#endif // MPT_COMPILER_CLANG
 	SystemVersion = VersionDecimalTo_WIN32_WINNT(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion);
+#endif // !MPT_OS_WINDOWS_WINRT
 }
 
 
@@ -79,22 +99,18 @@ static void GatherWindowsVersion(bool & SystemIsNT, uint32 & SystemVersion)
 namespace {
 struct WindowsVersionCache
 {
-	bool SystemIsNT;
 	uint32 SystemVersion;
 	WindowsVersionCache()
-		: SystemIsNT(false)
-		, SystemVersion(mpt::Windows::Version::WinNT4)
+		: SystemVersion(mpt::Windows::Version::WinNT4)
 	{
-		GatherWindowsVersion(SystemIsNT, SystemVersion);
+		GatherWindowsVersion(SystemVersion);
 	}
 };
 }
 
-static void GatherWindowsVersionFromCache(bool & SystemIsNT, uint32 & SystemVersion)
-//----------------------------------------------------------------------------------
+static void GatherWindowsVersionFromCache(uint32 & SystemVersion)
 {
 	static WindowsVersionCache gs_WindowsVersionCache;
-	SystemIsNT = gs_WindowsVersionCache.SystemIsNT;
 	SystemVersion = gs_WindowsVersionCache.SystemVersion;
 }
 
@@ -105,9 +121,7 @@ static void GatherWindowsVersionFromCache(bool & SystemIsNT, uint32 & SystemVers
 
 
 Version::Version()
-//----------------
 	: SystemIsWindows(false)
-	, SystemIsNT(true)
 	, SystemVersion(mpt::Windows::Version::WinNT4)
 {
 	return;
@@ -115,15 +129,14 @@ Version::Version()
 
 
 mpt::Windows::Version Version::Current()
-//--------------------------------------
 {
 	mpt::Windows::Version result;
 	#if MPT_OS_WINDOWS
 		result.SystemIsWindows = true;
 		#ifdef MODPLUG_TRACKER
-			GatherWindowsVersionFromCache(result.SystemIsNT, result.SystemVersion);
+			GatherWindowsVersionFromCache(result.SystemVersion);
 		#else // !MODPLUG_TRACKER
-			GatherWindowsVersion(result.SystemIsNT, result.SystemVersion);
+			GatherWindowsVersion(result.SystemVersion);
 		#endif // MODPLUG_TRACKER
 	#endif // MPT_OS_WINDOWS
 	return result;
@@ -131,14 +144,12 @@ mpt::Windows::Version Version::Current()
 
 
 bool Version::IsWindows() const
-//-----------------------------
 {
 	return SystemIsWindows;
 }
 
 
 bool Version::IsBefore(mpt::Windows::Version::Number version) const
-//-----------------------------------------------------------------
 {
 	if(!SystemIsWindows)
 	{
@@ -149,7 +160,6 @@ bool Version::IsBefore(mpt::Windows::Version::Number version) const
 
 
 bool Version::IsAtLeast(mpt::Windows::Version::Number version) const
-//------------------------------------------------------------------
 {
 	if(!SystemIsWindows)
 	{
@@ -159,53 +169,35 @@ bool Version::IsAtLeast(mpt::Windows::Version::Number version) const
 }
 
 
-bool Version::Is9x() const
-//------------------------
+static MPT_CONSTEXPR11_VAR struct { Version::Number version; const MPT_UCHAR_TYPE * name; } versionMap[] =
 {
-	if(!SystemIsWindows)
-	{
-		return false;
-	}
-	return !SystemIsNT;
-}
-
-
-bool Version::IsNT() const
-//------------------------
-{
-	if(!SystemIsWindows)
-	{
-		return false;
-	}
-	return SystemIsNT;
-}
+	{ mpt::Windows::Version::WinNewer, MPT_ULITERAL("Windows 10 (or newer)") },
+	{ mpt::Windows::Version::Win10, MPT_ULITERAL("Windows 10") },
+	{ mpt::Windows::Version::Win81, MPT_ULITERAL("Windows 8.1") },
+	{ mpt::Windows::Version::Win8, MPT_ULITERAL("Windows 8") },
+	{ mpt::Windows::Version::Win7, MPT_ULITERAL("Windows 7") },
+	{ mpt::Windows::Version::WinVista, MPT_ULITERAL("Windows Vista") },
+	{ mpt::Windows::Version::WinXP64, MPT_ULITERAL("Windows XP x64 / Windows Server 2003") },
+	{ mpt::Windows::Version::WinXP, MPT_ULITERAL("Windows XP") },
+	{ mpt::Windows::Version::Win2000, MPT_ULITERAL("Windows 2000") },
+	{ mpt::Windows::Version::WinME, MPT_ULITERAL("Windows ME") },
+	{ mpt::Windows::Version::Win98, MPT_ULITERAL("Windows 98") },
+	{ mpt::Windows::Version::WinNT4, MPT_ULITERAL("Windows NT4") }
+};
 
 
 mpt::ustring Version::VersionToString(uint16 version)
-//---------------------------------------------------
 {
 	mpt::ustring result;
-	std::vector<std::pair<uint16, mpt::ustring> > versionMap;
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::WinNewer), MPT_USTRING("Windows 10 (or newer)")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::Win10), MPT_USTRING("Windows 10")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::Win81), MPT_USTRING("Windows 8.1")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::Win8), MPT_USTRING("Windows 8")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::Win7), MPT_USTRING("Windows 7")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::WinVista), MPT_USTRING("Windows Vista")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::WinXP), MPT_USTRING("Windows XP")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::Win2000), MPT_USTRING("Windows 2000")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::WinME), MPT_USTRING("Windows ME")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::Win98), MPT_USTRING("Windows 98")));
-	versionMap.push_back(std::make_pair(static_cast<uint16>(mpt::Windows::Version::WinNT4), MPT_USTRING("Windows NT4")));
-	for(std::size_t i = 0; i < versionMap.size(); ++i)
+	for(const auto &v : versionMap)
 	{
-		if(version > versionMap[i].first)
+		if(version > v.version)
 		{
-			result = MPT_USTRING("> ") + versionMap[i].second;
+			result = MPT_USTRING("> ") + v.name;
 			break;
-		} else if(version == versionMap[i].first)
+		} else if(version == v.version)
 		{
-			result = versionMap[i].second;
+			result = v.name;
 			break;
 		}
 	}
@@ -217,54 +209,22 @@ mpt::ustring Version::VersionToString(uint16 version)
 }
 
 
+
+mpt::ustring Version::VersionToString(Number version)
+{
+	return VersionToString(static_cast<uint16>(version));
+}
+
+
 mpt::ustring Version::GetName() const
-//-----------------------------------
 {
-	mpt::ustring name;
-	if(mpt::Windows::Version::IsNT())
+	mpt::ustring name = MPT_USTRING("Generic Windows NT");
+	for(const auto &v : versionMap)
 	{
-		if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::WinNewer))
-		{
-			name = MPT_USTRING("Windows 10 (or newer)");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::Win10))
-		{
-			name = MPT_USTRING("Windows 10");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::Win81))
-		{
-			name = MPT_USTRING("Windows 8.1");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::Win8))
+		if(mpt::Windows::Version::IsAtLeast(v.version))
 		{
-			name = MPT_USTRING("Windows 8");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::Win7))
-		{
-			name = MPT_USTRING("Windows 7");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::WinVista))
-		{
-			name = MPT_USTRING("Windows Vista");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::WinXP))
-		{
-			name = MPT_USTRING("Windows XP");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::Win2000))
-		{
-			name = MPT_USTRING("Windows 2000");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::WinNT4))
-		{
-			name = MPT_USTRING("Windows NT4");
-		} else
-		{
-			name = MPT_USTRING("Generic Windows NT");
-		}
-	} else
-	{
-		if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::WinME))
-		{
-			name = MPT_USTRING("Windows ME (or newer)");
-		} else if(mpt::Windows::Version::IsAtLeast(mpt::Windows::Version::Win98))
-		{
-			name = MPT_USTRING("Windows 98");
-		} else
-		{
-			name = MPT_USTRING("Generic Windows 9x");
+			name = v.name;
+			break;
 		}
 	}
 	mpt::ustring result = name;
@@ -293,7 +253,6 @@ mpt::ustring Version::GetName() const
 
 #ifdef MODPLUG_TRACKER
 mpt::ustring Version::GetNameShort() const
-//----------------------------------------
 {
 	mpt::ustring name;
 	if(mpt::Windows::IsWine())
@@ -304,16 +263,12 @@ mpt::ustring Version::GetNameShort() const
 			name = mpt::format(MPT_USTRING("wine-%1"))(v.Version().AsString());
 		} else if(v.RawVersion().length() > 0)
 		{
-			std::string rawVersion = v.RawVersion();
-			std::vector<char> bytes(rawVersion.begin(), rawVersion.end());
-			name = MPT_USTRING("wine-") + Util::BinToHex(bytes);
+			name = MPT_USTRING("wine-") + Util::BinToHex(mpt::as_span(v.RawVersion()));
 		} else
 		{
 			name = MPT_USTRING("wine-");
 		}
-		std::string rawHostSysName = v.RawHostSysName();
-		std::vector<char> bytes(rawHostSysName.begin(), rawHostSysName.end());
-		name += MPT_USTRING("-") + Util::BinToHex(bytes);
+		name += MPT_USTRING("-") + Util::BinToHex(mpt::as_span(v.RawHostSysName()));
 	} else
 	{
 		name = mpt::format(MPT_USTRING("%1.%2"))(mpt::ufmt::dec(SystemVersion >> 8), mpt::ufmt::HEX0<2>(SystemVersion & 0xFF));
@@ -323,33 +278,27 @@ mpt::ustring Version::GetNameShort() const
 #endif // MODPLUG_TRACKER
 
 
-uint16 Version::GetMinimumKernelLevel()
-//-------------------------------------
+mpt::Windows::Version::Number Version::GetMinimumKernelLevel()
 {
 	uint16 minimumKernelVersion = 0;
 	#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
-		#if MPT_MSVC_AT_LEAST(2012, 0) && !defined(MPT_BUILD_TARGET_XP)
+		#if !defined(MPT_BUILD_TARGET_XP)
 			minimumKernelVersion = std::max<uint16>(minimumKernelVersion, mpt::Windows::Version::WinVista);
-		#elif MPT_MSVC_AT_LEAST(2012, 0) && defined(MPT_BUILD_TARGET_XP)
+		#else
 			minimumKernelVersion = std::max<uint16>(minimumKernelVersion, mpt::Windows::Version::WinXP);
-		#elif MPT_MSVC_AT_LEAST(2010, 0)
-			minimumKernelVersion = std::max<uint16>(minimumKernelVersion, mpt::Windows::Version::Win2000);
-		#elif MPT_MSVC_AT_LEAST(2008, 0)
-			minimumKernelVersion = std::max<uint16>(minimumKernelVersion, mpt::Windows::Version::Win98);
 		#endif
 	#endif
-	return minimumKernelVersion;
+	return static_cast<mpt::Windows::Version::Number>(minimumKernelVersion);
 }
 
 
-uint16 Version::GetMinimumAPILevel()
-//----------------------------------
+mpt::Windows::Version::Number Version::GetMinimumAPILevel()
 {
 	uint16 minimumApiVersion = 0;
 	#if MPT_OS_WINDOWS && defined(_WIN32_WINNT)
 		minimumApiVersion = std::max<uint16>(minimumApiVersion, _WIN32_WINNT);
 	#endif
-	return minimumApiVersion;
+	return static_cast<mpt::Windows::Version::Number>(minimumApiVersion);
 }
 
 
@@ -359,7 +308,6 @@ uint16 Version::GetMinimumAPILevel()
 #if MPT_OS_WINDOWS
 
 static bool GatherSystemIsWine()
-//------------------------------
 {
 	bool SystemIsWine = false;
 	HMODULE hNTDLL = LoadLibraryW(L"ntdll.dll");
@@ -414,19 +362,16 @@ static bool SystemIsWine(bool allowDetection = true)
 }
 
 void PreventWineDetection()
-//-------------------------
 {
 	SystemIsWine(false);
 }
 
 bool IsOriginal()
-//---------------
 {
 	return mpt::Windows::Version::Current().IsWindows() && !SystemIsWine();
 }
 
 bool IsWine()
-//-----------
 {
 	return mpt::Windows::Version::Current().IsWindows() && SystemIsWine();
 }
@@ -449,7 +394,6 @@ namespace Wine
 
 
 Version::Version()
-//----------------
 	: valid(false)
 	, vmajor(0)
 	, vminor(0)
@@ -460,7 +404,6 @@ Version::Version()
 
 
 Version::Version(const mpt::ustring &rawVersion)
-//----------------------------------------------
 	: valid(false)
 	, vmajor(0)
 	, vminor(0)
@@ -493,7 +436,6 @@ Version::Version(const mpt::ustring &rawVersion)
 
 
 Version::Version(uint8 vmajor, uint8 vminor, uint8 vupdate)
-//---------------------------------------------------------
 	: valid((vmajor > 0) || (vminor > 0) || (vupdate > 0)) 
 	, vmajor(vmajor)
 	, vminor(vminor)
@@ -504,7 +446,6 @@ Version::Version(uint8 vmajor, uint8 vminor, uint8 vupdate)
 
 
 mpt::Wine::Version Version::FromInteger(uint32 version)
-//-----------------------------------------------------
 {
 	mpt::Wine::Version result;
 	result.valid = (version <= 0xffffff);
@@ -516,21 +457,18 @@ mpt::Wine::Version Version::FromInteger(uint32 version)
 
 
 bool Version::IsValid() const
-//---------------------------
 {
 	return valid;
 }
 
 
 mpt::ustring Version::AsString() const
-//------------------------------------
 {
 	return mpt::ufmt::dec(vmajor) + MPT_USTRING(".") + mpt::ufmt::dec(vminor) + MPT_USTRING(".") + mpt::ufmt::dec(vupdate);
 }
 
 
 uint32 Version::AsInteger() const
-//-------------------------------
 {
 	uint32 version = 0;
 	version |= static_cast<uint32>(vmajor) << 16;
@@ -541,7 +479,6 @@ uint32 Version::AsInteger() const
 
 
 bool Version::IsBefore(mpt::Wine::Version other) const
-//----------------------------------------------------
 {
 	if(!IsValid())
 	{
@@ -552,7 +489,6 @@ bool Version::IsBefore(mpt::Wine::Version other) const
 
 
 bool Version::IsAtLeast(mpt::Wine::Version other) const
-//-----------------------------------------------------
 {
 	if(!IsValid())
 	{
@@ -562,10 +498,24 @@ bool Version::IsAtLeast(mpt::Wine::Version other) const
 }
 
 
+mpt::Wine::Version GetMinimumWineVersion()
+{
+	mpt::Wine::Version minimumWineVersion = mpt::Wine::Version(0,0,0);
+	#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
+		#if !defined(MPT_BUILD_TARGET_XP)
+			minimumWineVersion = mpt::Wine::Version(1,8,0);
+		#else
+			minimumWineVersion = mpt::Wine::Version(1,6,0);
+		#endif
+	#endif
+	return minimumWineVersion;
+}
+
+
 VersionContext::VersionContext()
-//------------------------------
 	: m_IsWine(false)
 	, m_HostIsLinux(false)
+	, m_HostIsBSD(false)
 {
 	#if MPT_OS_WINDOWS
 		m_IsWine = mpt::Windows::IsWine();
@@ -599,6 +549,7 @@ VersionContext::VersionContext()
 		}
 		m_Version = mpt::Wine::Version(mpt::ToUnicode(mpt::CharsetUTF8, m_RawVersion));
 		m_HostIsLinux = (m_RawHostSysName == "Linux");
+		m_HostIsBSD = (m_RawHostSysName == "FreeBSD" || m_RawHostSysName == "DragonFly" || m_RawHostSysName == "NetBSD" || m_RawHostSysName == "OpenBSD");
 	#endif // MPT_OS_WINDOWS
 }
 
diff --git a/common/mptOS.h b/common/mptOS.h
index a18c00c..fe213d1 100644
--- a/common/mptOS.h
+++ b/common/mptOS.h
@@ -30,14 +30,12 @@ public:
 	enum Number
 	{
 
-		// Win9x
+		WinNT4   = 0x0400,
 		Win98    = 0x0410,
 		WinME    = 0x0490,
-
-		// WinNT
-		WinNT4   = 0x0400,
 		Win2000  = 0x0500,
 		WinXP    = 0x0501,
+		WinXP64  = 0x0502,
 		WinVista = 0x0600,
 		Win7     = 0x0601,
 		Win8     = 0x0602,
@@ -49,12 +47,12 @@ public:
 	};
 
 	static mpt::ustring VersionToString(uint16 version);
+	static mpt::ustring VersionToString(Number version);
 
 private:
 
 	bool SystemIsWindows;
 
-	bool SystemIsNT;
 	uint32 SystemVersion;
 
 private:
@@ -72,9 +70,6 @@ public:
 	bool IsBefore(mpt::Windows::Version::Number version) const;
 	bool IsAtLeast(mpt::Windows::Version::Number version) const;
 
-	bool Is9x() const;
-	bool IsNT() const;
-
 	mpt::ustring GetName() const;
 #ifdef MODPLUG_TRACKER
 	mpt::ustring GetNameShort() const;
@@ -82,8 +77,8 @@ public:
 
 public:
 
-	static uint16 GetMinimumKernelLevel();
-	static uint16 GetMinimumAPILevel();
+	static mpt::Windows::Version::Number GetMinimumKernelLevel();
+	static mpt::Windows::Version::Number GetMinimumAPILevel();
 
 }; // class Version
 
@@ -130,6 +125,8 @@ public:
 	bool IsAtLeast(mpt::Wine::Version other) const;
 };
 
+mpt::Wine::Version GetMinimumWineVersion();
+
 class VersionContext
 {
 protected:
@@ -141,6 +138,7 @@ protected:
 	std::string m_RawHostRelease;
 	mpt::Wine::Version m_Version;
 	bool m_HostIsLinux;
+	bool m_HostIsBSD;
 public:
 	VersionContext();
 public:
@@ -152,6 +150,7 @@ public:
 	std::string RawHostRelease() const { return m_RawHostRelease; }
 	mpt::Wine::Version Version() const { return m_Version; }
 	bool HostIsLinux() const { return m_HostIsLinux; }
+	bool HostIsBSD() const { return m_HostIsBSD; }
 };
 
 } // namespace Wine
diff --git a/common/mptPathString.cpp b/common/mptPathString.cpp
index 8b047fa..ba679f8 100644
--- a/common/mptPathString.cpp
+++ b/common/mptPathString.cpp
@@ -12,6 +12,8 @@
 
 #include "misc_util.h"
 
+#include "mptUUID.h"
+
 #if MPT_OS_WINDOWS
 #include <windows.h>
 #if defined(MODPLUG_TRACKER)
@@ -19,17 +21,23 @@
 #endif
 #endif
 
+#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+#if defined(__MINGW32__) || defined(__MINGW64__)
+// MinGW-w64 headers do not declare this for WinRT, which is wrong.
+extern "C" {
+WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart);
+}
+#endif
+#endif
 
 OPENMPT_NAMESPACE_BEGIN
 
-
 #if MPT_OS_WINDOWS
 #define MPT_PATHSTRING_LITERAL(x) ( L ## x )
 #else
 #define MPT_PATHSTRING_LITERAL(x) ( x )
 #endif
 
-
 #if MPT_OS_WINDOWS
 
 namespace mpt
@@ -37,30 +45,101 @@ namespace mpt
 
 
 RawPathString PathString::AsNativePrefixed() const
-//------------------------------------------------
 {
-	if(path.length() <= MAX_PATH || path.substr(0, 4) == L"\\\\?\\")
+	if(path.length() <= MAX_PATH || path.substr(0, 4) == MPT_PATHSTRING_LITERAL("\\\\?\\"))
 	{
 		// Path is short enough or already in prefixed form
 		return path;
 	}
 	const RawPathString absPath = mpt::GetAbsolutePath(path).AsNative();
-	if(absPath.substr(0, 2) == L"\\\\")
+	if(absPath.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\\\"))
 	{
 		// Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar
-		return L"\\\\?\\UNC" + absPath.substr(1);
+		return MPT_PATHSTRING_LITERAL("\\\\?\\UNC") + absPath.substr(1);
 	} else
 	{
 		// Regular file: C:\foo.bar -> \\?\C:\foo.bar
-		return L"\\\\?\\" + absPath;
+		return MPT_PATHSTRING_LITERAL("\\\\?\\") + absPath;
 	}
 }
 
 
+#if !MPT_OS_WINDOWS_WINRT
+
 int PathString::CompareNoCase(const PathString & a, const PathString & b)
-//-----------------------------------------------------------------------
 {
-	return lstrcmpiW(a.ToWide().c_str(), b.ToWide().c_str());
+	return lstrcmpiW(a.path.c_str(), b.path.c_str());
+}
+
+#endif // !MPT_OS_WINDOWS_WINRT
+
+
+// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries
+// Note: We use our own implementation as PathCanonicalize is limited to MAX_PATH
+// and unlimited versions are only available on Windows 8 and later.
+// Furthermore, we also convert forward-slashes to backslashes and always remove trailing slashes.
+PathString PathString::Simplify() const
+{
+	if(path.empty())
+		return PathString();
+
+	std::vector<RawPathString> components;
+	RawPathString root;
+	RawPathString::size_type startPos = 0;
+	if(path.size() >= 2 && path[1] == MPT_PATHSTRING_LITERAL(':'))
+	{
+		// Drive letter
+		root = path.substr(0, 2) + MPT_PATHSTRING_LITERAL('\\');
+		startPos = 2;
+	} else if(path.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\\\"))
+	{
+		// Network share
+		root = MPT_PATHSTRING_LITERAL("\\\\");
+		startPos = 2;
+	} else if(path.substr(0, 2) == MPT_PATHSTRING_LITERAL(".\\") || path.substr(0, 2) == MPT_PATHSTRING_LITERAL("./"))
+	{
+		// Special case for relative paths
+		root = MPT_PATHSTRING_LITERAL(".\\");
+		startPos = 2;
+	} else if(path.size() >= 1 && (path[0] == MPT_PATHSTRING_LITERAL('\\') || path[0] == MPT_PATHSTRING_LITERAL('/')))
+	{
+		// Special case for relative paths
+		root = MPT_PATHSTRING_LITERAL("\\");
+		startPos = 1;
+	}
+
+	while(startPos < path.size())
+	{
+		auto pos = path.find_first_of(MPT_PATHSTRING_LITERAL("\\/"), startPos);
+		if(pos == RawPathString::npos)
+			pos = path.size();
+		mpt::RawPathString dir = path.substr(startPos, pos - startPos);
+		if(dir == MPT_PATHSTRING_LITERAL(".."))
+		{
+			// Go back one directory
+			if(!components.empty())
+			{
+				components.pop_back();
+			}
+		} else if(dir == MPT_PATHSTRING_LITERAL("."))
+		{
+			// nop
+		} else if(!dir.empty())
+		{
+			components.push_back(std::move(dir));
+		}
+		startPos = pos + 1;
+	}
+
+	RawPathString result = root;
+	result.reserve(path.size());
+	for(const auto &component : components)
+	{
+		result += component + MPT_PATHSTRING_LITERAL("\\");
+	}
+	if(!components.empty())
+		result.pop_back();
+	return result;
 }
 
 } // namespace mpt
@@ -72,10 +151,9 @@ namespace mpt
 {
 
 
-#if MPT_OS_WINDOWS && defined(MPT_ENABLE_DYNBIND)
+#if MPT_OS_WINDOWS && (defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE))
 
 void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const
-//------------------------------------------------------------------------------------------------------
 {
 	// We cannot use CRT splitpath here, because:
 	//  * limited to _MAX_PATH or similar
@@ -157,42 +235,36 @@ void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname
 }
 
 PathString PathString::GetDrive() const
-//-------------------------------------
 {
 	PathString drive;
 	SplitPath(&drive, nullptr, nullptr, nullptr);
 	return drive;
 }
 PathString PathString::GetDir() const
-//-----------------------------------
 {
 	PathString dir;
 	SplitPath(nullptr, &dir, nullptr, nullptr);
 	return dir;
 }
 PathString PathString::GetPath() const
-//------------------------------------
 {
 	PathString drive, dir;
 	SplitPath(&drive, &dir, nullptr, nullptr);
 	return drive + dir;
 }
 PathString PathString::GetFileName() const
-//----------------------------------------
 {
 	PathString fname;
 	SplitPath(nullptr, nullptr, &fname, nullptr);
 	return fname;
 }
 PathString PathString::GetFileExt() const
-//---------------------------------------
 {
 	PathString ext;
 	SplitPath(nullptr, nullptr, nullptr, &ext);
 	return ext;
 }
 PathString PathString::GetFullFileName() const
-//--------------------------------------------
 {
 	PathString name, ext;
 	SplitPath(nullptr, nullptr, &name, &ext);
@@ -201,28 +273,45 @@ PathString PathString::GetFullFileName() const
 
 
 bool PathString::IsDirectory() const
-//----------------------------------
 {
 	// Using PathIsDirectoryW here instead would increase libopenmpt dependencies by shlwapi.dll.
 	// GetFileAttributesW also does the job just fine.
-	DWORD dwAttrib = ::GetFileAttributesW(path.c_str());
+	#if MPT_OS_WINDOWS_WINRT
+		WIN32_FILE_ATTRIBUTE_DATA data;
+		MemsetZero(data);
+		if(::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0)
+		{
+			return false;
+		}
+		DWORD dwAttrib = data.dwFileAttributes;
+	#else // !MPT_OS_WINDOWS_WINRT
+		DWORD dwAttrib = ::GetFileAttributesW(path.c_str());
+	#endif // MPT_OS_WINDOWS_WINRT
 	return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
 }
 
 bool PathString::IsFile() const
-//-----------------------------
 {
-	DWORD dwAttrib = ::GetFileAttributesW(path.c_str());
+	#if MPT_OS_WINDOWS_WINRT
+		WIN32_FILE_ATTRIBUTE_DATA data;
+		MemsetZero(data);
+		if (::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0)
+		{
+			return false;
+		}
+		DWORD dwAttrib = data.dwFileAttributes;
+	#else // !MPT_OS_WINDOWS_WINRT
+		DWORD dwAttrib = ::GetFileAttributesW(path.c_str());
+	#endif // MPT_OS_WINDOWS_WINRT
 	return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
 }
 
-#endif // MPT_OS_WINDOWS && MPT_ENABLE_DYNBIND
+#endif // MPT_OS_WINDOWS && (MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE)
 
 
 #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
 
 bool PathString::FileOrDirectoryExists() const
-//--------------------------------------------
 {
 	return ::PathFileExistsW(path.c_str()) != FALSE;
 }
@@ -233,14 +322,12 @@ bool PathString::FileOrDirectoryExists() const
 #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
 
 PathString PathString::ReplaceExt(const mpt::PathString &newExt) const
-//--------------------------------------------------------------------
 {
 	return GetDrive() + GetDir() + GetFileName() + newExt;
 }
 
 
 PathString PathString::SanitizeComponent() const
-//----------------------------------------------
 {
 	PathString result = *this;
 	SanitizeFilename(result);
@@ -250,7 +337,6 @@ PathString PathString::SanitizeComponent() const
 
 // Convert an absolute path to a path that's relative to "&relativeTo".
 PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) const
-//-------------------------------------------------------------------------------
 {
 	mpt::PathString result = path;
 	if(path.empty())
@@ -273,19 +359,18 @@ PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) cons
 
 // Convert a path that is relative to "&relativeTo" to an absolute path.
 PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) const
-//-------------------------------------------------------------------------------
 {
 	mpt::PathString result = path;
 	if(path.empty())
 	{
 		return result;
 	}
-	if(AsNative().length() >= 2 && AsNative().at(0) == L'\\' && AsNative().at(1) != L'\\')
+	if(path.length() >= 2 && path.at(0) == MPT_PATHSTRING_LITERAL('\\') && path.at(1) != MPT_PATHSTRING_LITERAL('\\'))
 	{
 		// Path is on the same drive as OpenMPT ("\Somepath\" => "C:\Somepath\"), but ignore network paths starting with "\\"
 		result = mpt::PathString::FromNative(relativeTo.AsNative().substr(0, 2));
 		result += path;
-	} else if(AsNative().length() >= 2 && AsNative().substr(0, 2) == L".\\")
+	} else if(path.length() >= 2 && path.substr(0, 2) == MPT_PATHSTRING_LITERAL(".\\"))
 	{
 		// Path is OpenMPT's directory or a sub directory (".\Somepath\" => "C:\OpenMPT\Somepath\")
 		result = relativeTo; // "C:\OpenMPT\"
@@ -298,7 +383,6 @@ PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) cons
 #if defined(_MFC_VER)
 
 mpt::PathString PathString::TunnelOutofCString(const CString &path)
-//-----------------------------------------------------------------
 {
 	#ifdef UNICODE
 		return mpt::PathString::FromWide(path.GetString());
@@ -321,7 +405,6 @@ mpt::PathString PathString::TunnelOutofCString(const CString &path)
 
 
 CString PathString::TunnelIntoCString(const mpt::PathString &path)
-//----------------------------------------------------------------
 {
 	#ifdef UNICODE
 		return path.ToWide().c_str();
@@ -379,7 +462,6 @@ bool PathIsAbsolute(const mpt::PathString &path) {
 #if MPT_OS_WINDOWS
 
 mpt::PathString GetAbsolutePath(const mpt::PathString &path)
-//----------------------------------------------------------
 {
 	DWORD size = GetFullPathNameW(path.AsNative().c_str(), 0, nullptr, nullptr);
 	if(size == 0)
@@ -387,11 +469,11 @@ mpt::PathString GetAbsolutePath(const mpt::PathString &path)
 		return path;
 	}
 	std::vector<WCHAR> fullPathName(size, L'\0');
-	if(GetFullPathNameW(path.AsNative().c_str(), size, &fullPathName[0], nullptr) == 0)
+	if(GetFullPathNameW(path.AsNative().c_str(), size, fullPathName.data(), nullptr) == 0)
 	{
 		return path;
 	}
-	return mpt::PathString::FromNative(&fullPathName[0]);
+	return mpt::PathString::FromNative(fullPathName.data());
 }
 
 #ifdef MODPLUG_TRACKER
@@ -402,6 +484,10 @@ bool DeleteWholeDirectoryTree(mpt::PathString path)
 	{
 		return false;
 	}
+	if(PathIsRelativeW(path.AsNative().c_str()) == TRUE)
+	{
+		return false;
+	}
 	if(!path.FileOrDirectoryExists())
 	{
 		return true;
@@ -451,19 +537,64 @@ bool DeleteWholeDirectoryTree(mpt::PathString path)
 
 #endif // MPT_OS_WINDOWS
 
+
+
+#if MPT_OS_WINDOWS
+
+#if defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE)
+
+mpt::PathString GetAppPath()
+{
+	std::vector<WCHAR> exeFileName(MAX_PATH);
+	while(GetModuleFileNameW(0, exeFileName.data(), mpt::saturate_cast<DWORD>(exeFileName.size())) >= exeFileName.size())
+	{
+		if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+		{
+			return mpt::PathString();
+		}
+		exeFileName.resize(exeFileName.size() * 2);
+	}
+	return mpt::GetAbsolutePath(mpt::PathString::FromNative(exeFileName.data()).GetPath());
+}
+
+#endif // MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE
+
+
+#if defined(MPT_ENABLE_DYNBIND)
+
+#if !MPT_OS_WINDOWS_WINRT
+
+mpt::PathString GetSystemPath()
+{
+	DWORD size = GetSystemDirectoryW(nullptr, 0);
+	std::vector<WCHAR> path(size + 1);
+	if(!GetSystemDirectoryW(path.data(), size + 1))
+	{
+		return mpt::PathString();
+	}
+	return mpt::PathString::FromNative(path.data()) + MPT_PATHSTRING("\\");
+}
+
+#endif // !MPT_OS_WINDOWS_WINRT
+
+#endif // MPT_ENABLE_DYNBIND
+
+#endif // MPT_OS_WINDOWS
+
+
+
 #if defined(MPT_ENABLE_TEMPFILE)
 #if MPT_OS_WINDOWS
 
 mpt::PathString GetTempDirectory()
-//--------------------------------
 {
 	DWORD size = GetTempPathW(0, nullptr);
 	if(size)
 	{
 		std::vector<WCHAR> tempPath(size + 1);
-		if(GetTempPathW(size + 1, &tempPath[0]))
+		if(GetTempPathW(size + 1, tempPath.data()))
 		{
-			return mpt::PathString::FromNative(&tempPath[0]);
+			return mpt::PathString::FromNative(tempPath.data());
 		}
 	}
 	// use app directory as fallback
@@ -471,7 +602,6 @@ mpt::PathString GetTempDirectory()
 }
 
 mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix, const mpt::PathString &fileNameExtension)
-//-----------------------------------------------------------------------------------------------------------------
 {
 	mpt::PathString filename = mpt::GetTempDirectory();
 	filename += (!fileNamePrefix.empty() ? fileNamePrefix + MPT_PATHSTRING("_") : mpt::PathString());
@@ -539,7 +669,6 @@ TempDirGuard::~TempDirGuard()
 #if defined(MODPLUG_TRACKER)
 
 static inline char SanitizeFilenameChar(char c)
-//---------------------------------------------
 {
 	if(	c == '\\' ||
 		c == '\"' ||
@@ -557,7 +686,6 @@ static inline char SanitizeFilenameChar(char c)
 }
 
 static inline wchar_t SanitizeFilenameChar(wchar_t c)
-//---------------------------------------------------
 {
 	if(	c == L'\\' ||
 		c == L'\"' ||
@@ -575,18 +703,16 @@ static inline wchar_t SanitizeFilenameChar(wchar_t c)
 }
 
 void SanitizeFilename(mpt::PathString &filename)
-//----------------------------------------------
 {
 	mpt::RawPathString tmp = filename.AsNative();
-	for(mpt::RawPathString::iterator it = tmp.begin(); it != tmp.end(); ++it)
+	for(auto &c : tmp)
 	{
-		*it = SanitizeFilenameChar(*it);
+		c = SanitizeFilenameChar(c);
 	}
 	filename = mpt::PathString::FromNative(tmp);
 }
 
 void SanitizeFilename(char *beg, char *end)
-//-----------------------------------------
 {
 	for(char *it = beg; it != end; ++it)
 	{
@@ -595,7 +721,6 @@ void SanitizeFilename(char *beg, char *end)
 }
 
 void SanitizeFilename(wchar_t *beg, wchar_t *end)
-//-----------------------------------------------
 {
 	for(wchar_t *it = beg; it != end; ++it)
 	{
@@ -604,7 +729,6 @@ void SanitizeFilename(wchar_t *beg, wchar_t *end)
 }
 
 void SanitizeFilename(std::string &str)
-//-------------------------------------
 {
 	for(size_t i = 0; i < str.length(); i++)
 	{
@@ -613,7 +737,6 @@ void SanitizeFilename(std::string &str)
 }
 
 void SanitizeFilename(std::wstring &str)
-//--------------------------------------
 {
 	for(size_t i = 0; i < str.length(); i++)
 	{
@@ -623,7 +746,6 @@ void SanitizeFilename(std::wstring &str)
 
 #if defined(_MFC_VER)
 void SanitizeFilename(CString &str)
-//---------------------------------
 {
 	for(int i = 0; i < str.GetLength(); i++)
 	{
@@ -639,7 +761,6 @@ void SanitizeFilename(CString &str)
 
 
 mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
-//----------------------------------------------------------------------------
 {
 	mpt::PathString filter;
 	if(GetShortName().empty() || GetExtensions().empty())
@@ -653,12 +774,12 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
 	{
 		filter += mpt::PathString::FromUnicode(GetShortName());
 	}
-	const std::vector<mpt::PathString> extensions = GetExtensions();
+	const auto extensions = GetExtensions();
 	if(format[FileTypeFormatShowExtensions])
 	{
 		filter += MPT_PATHSTRING(" (");
 		bool first = true;
-		for(std::vector<mpt::PathString>::const_iterator it = extensions.begin(); it != extensions.end(); ++it)
+		for(const auto &ext : extensions)
 		{
 			if(first)
 			{
@@ -668,14 +789,14 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
 				filter += MPT_PATHSTRING(",");
 			}
 			filter += MPT_PATHSTRING("*.");
-			filter += (*it);
+			filter += ext;
 		}
 		filter += MPT_PATHSTRING(")");
 	}
 	filter += MPT_PATHSTRING("|");
 	{
 		bool first = true;
-		for(std::vector<mpt::PathString>::const_iterator it = extensions.begin(); it != extensions.end(); ++it)
+		for(const auto &ext : extensions)
 		{
 			if(first)
 			{
@@ -685,7 +806,7 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
 				filter += MPT_PATHSTRING(";");
 			}
 			filter += MPT_PATHSTRING("*.");
-			filter += (*it);
+			filter += ext;
 		}
 	}
 	filter += MPT_PATHSTRING("|");
@@ -694,13 +815,12 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
 
 
 mpt::PathString FileType::AsFilterOnlyString() const
-//--------------------------------------------------
 {
 	mpt::PathString filter;
-	const std::vector<mpt::PathString> extensions = GetExtensions();
+	const auto extensions = GetExtensions();
 	{
 		bool first = true;
-		for(std::vector<mpt::PathString>::const_iterator it = extensions.begin(); it != extensions.end(); ++it)
+		for(const auto &ext : extensions)
 		{
 			if(first)
 			{
@@ -710,7 +830,7 @@ mpt::PathString FileType::AsFilterOnlyString() const
 				filter += MPT_PATHSTRING(";");
 			}
 			filter += MPT_PATHSTRING("*.");
-			filter += (*it);
+			filter += ext;
 		}
 	}
 	return filter;
@@ -718,26 +838,23 @@ mpt::PathString FileType::AsFilterOnlyString() const
 
 
 mpt::PathString ToFilterString(const FileType &fileType, FlagSet<FileTypeFormat> format)
-//--------------------------------------------------------------------------------------
 {
 	return fileType.AsFilterString(format);
 }
 
 
 mpt::PathString ToFilterString(const std::vector<FileType> &fileTypes, FlagSet<FileTypeFormat> format)
-//----------------------------------------------------------------------------------------------------
 {
 	mpt::PathString filter;
-	for(std::vector<FileType>::const_iterator it = fileTypes.begin(); it != fileTypes.end(); ++it)
+	for(const auto &type : fileTypes)
 	{
-		filter += it->AsFilterString(format);
+		filter += type.AsFilterString(format);
 	}
 	return filter;
 }
 
 
 mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty)
-//---------------------------------------------------------------------------------------------
 {
 	mpt::PathString filter = fileType.AsFilterOnlyString();
 	return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? MPT_PATHSTRING(";") : MPT_PATHSTRING("")) + filter;
@@ -745,12 +862,11 @@ mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicol
 
 
 mpt::PathString ToFilterOnlyString(const std::vector<FileType> &fileTypes, bool prependSemicolonWhenNotEmpty)
-//-----------------------------------------------------------------------------------------------------------
 {
 	mpt::PathString filter;
-	for(std::vector<FileType>::const_iterator it = fileTypes.begin(); it != fileTypes.end(); ++it)
+	for(const auto &type : fileTypes)
 	{
-		filter += it->AsFilterOnlyString();
+		filter += type.AsFilterOnlyString();
 	}
 	return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? MPT_PATHSTRING(";") : MPT_PATHSTRING("")) + filter;
 }
@@ -759,4 +875,5 @@ mpt::PathString ToFilterOnlyString(const std::vector<FileType> &fileTypes, bool
 #endif // MODPLUG_TRACKER
 
 
+
 OPENMPT_NAMESPACE_END
diff --git a/common/mptPathString.h b/common/mptPathString.h
index 216610f..5d7a263 100644
--- a/common/mptPathString.h
+++ b/common/mptPathString.h
@@ -17,9 +17,12 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
+
 #define MPT_DEPRECATED_PATH
 //#define MPT_DEPRECATED_PATH MPT_DEPRECATED
 
+
+
 namespace mpt
 {
 
@@ -29,17 +32,25 @@ typedef std::wstring RawPathString;
 typedef std::string RawPathString;
 #endif // if MPT_OS_WINDOWS
 
+
+
 class PathString
 {
+
 private:
+
 	RawPathString path;
+
 private:
+
 	PathString(const RawPathString & path)
 		: path(path)
 	{
 		return;
 	}
+
 public:
+
 	PathString()
 	{
 		return;
@@ -67,10 +78,12 @@ public:
 	{
 		return append(other);
 	}
+
 	friend PathString operator + (const PathString & a, const PathString & b)
 	{
 		return PathString(a).append(b);
 	}
+
 	friend bool operator < (const PathString & a, const PathString & b)
 	{
 		return a.AsNative() < b.AsNative();
@@ -83,17 +96,22 @@ public:
 	{
 		return a.AsNative() != b.AsNative();
 	}
+
 	bool empty() const { return path.empty(); }
 
-#if MPT_OS_WINDOWS
-	static int CompareNoCase(const PathString & a, const PathString & b);
-#endif
+	std::size_t Length() const { return path.size(); }
+
+
 
 public:
 
-	size_t Length() const { return path.size(); }
+#if MPT_OS_WINDOWS
+#if !MPT_OS_WINDOWS_WINRT
+	static int CompareNoCase(const PathString & a, const PathString & b);
+#endif // !MPT_OS_WINDOWS_WINRT
+#endif
 
-#if MPT_OS_WINDOWS && defined(MPT_ENABLE_DYNBIND)
+#if MPT_OS_WINDOWS && (defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE))
 
 	void SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const;
 	// \\?\ prefixes will be removed and \\?\\UNC prefixes converted to canonical \\ form.
@@ -109,7 +127,7 @@ public:
 	// Verify if this path exists and is a file on the file system.
 	bool IsFile() const;
 
-#endif // MPT_OS_WINDOWS && MPT_ENABLE_DYNBIND
+#endif // MPT_OS_WINDOWS && (MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE)
 
 #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
 
@@ -223,6 +241,9 @@ public:
 #endif
 #endif
 
+	// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries
+	mpt::PathString Simplify() const;
+
 #else // !MPT_OS_WINDOWS
 
 	// conversions
@@ -259,13 +280,19 @@ public:
 	static PathString FromNative(const RawPathString &path) { return PathString(path); }
 #endif // MPT_ENABLE_CHARSET_LOCALE
 
+	// Convert a path to its simplified form (currently only implemented on Windows)
+	MPT_DEPRECATED mpt::PathString Simplify() const { return path; }
+
 #endif // MPT_OS_WINDOWS
 
 };
 
+
+
 #if defined(MPT_ENABLE_CHARSET_LOCALE)
 MPT_DEPRECATED_PATH static inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::CharsetLocale, x.ToUnicode()); }
 #endif
+static inline mpt::ustring ToUString(const mpt::PathString & x) { return x.ToUnicode(); }
 #if MPT_WSTRING_FORMAT
 static inline std::wstring ToWString(const mpt::PathString & x) { return x.ToWide(); }
 #endif
@@ -285,13 +312,12 @@ static inline std::wstring ToWString(const mpt::PathString & x) { return x.ToWid
 namespace mpt
 {
 
+bool IsPathSeparator(mpt::RawPathString::value_type c);
 
 
-bool IsPathSeparator(mpt::RawPathString::value_type c);
 
 bool PathIsAbsolute(const mpt::PathString &path);
 
-
 #if MPT_OS_WINDOWS
 
 // Returns the absolute path for a potentially relative path and removes ".." or "." components. (same as GetFullPathNameW)
@@ -301,13 +327,33 @@ mpt::PathString GetAbsolutePath(const mpt::PathString &path);
 
 // Deletes a complete directory tree. Handle with EXTREME care.
 // Returns false if any file could not be removed and aborts as soon as it
-// encounters any error.
+// encounters any error. path must be absolute.
 bool DeleteWholeDirectoryTree(mpt::PathString path);
 
 #endif // MODPLUG_TRACKER
 
 #endif // MPT_OS_WINDOWS
 
+#if MPT_OS_WINDOWS
+
+#if defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE)
+
+// Returns the application path or an empty string (if unknown), e.g. "C:\mptrack\"
+mpt::PathString GetAppPath();
+
+#endif // MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE
+
+#if defined(MPT_ENABLE_DYNBIND)
+
+#if !MPT_OS_WINDOWS_WINRT
+// Returns the system directory path, e.g. "C:\Windows\System32\"
+mpt::PathString GetSystemPath();
+#endif // !MPT_OS_WINDOWS_WINRT
+
+#endif // MPT_ENABLE_DYNBIND
+
+#endif // MPT_OS_WINDOWS
+
 #if defined(MPT_ENABLE_TEMPFILE)
 #if MPT_OS_WINDOWS
 
@@ -317,6 +363,8 @@ mpt::PathString GetTempDirectory();
 // Returns a new unique absolute path.
 mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix = mpt::PathString(), const mpt::PathString &fileNameExtension = MPT_PATHSTRING("tmp"));
 
+
+
 // Scoped temporary file guard. Deletes the file when going out of scope.
 // The file itself is not created automatically.
 class TempFileGuard
@@ -350,6 +398,8 @@ public:
 
 } // namespace mpt
 
+
+
 #if defined(MODPLUG_TRACKER)
 
 // Sanitize a filename (remove special chars)
@@ -363,7 +413,6 @@ void SanitizeFilename(std::wstring &str);
 
 template <std::size_t size>
 void SanitizeFilename(char (&buffer)[size])
-//-----------------------------------------
 {
 	STATIC_ASSERT(size > 0);
 	SanitizeFilename(buffer, buffer + size);
@@ -371,7 +420,6 @@ void SanitizeFilename(char (&buffer)[size])
 
 template <std::size_t size>
 void SanitizeFilename(wchar_t (&buffer)[size])
-//--------------------------------------------
 {
 	STATIC_ASSERT(size > 0);
 	SanitizeFilename(buffer, buffer + size);
@@ -405,11 +453,11 @@ public:
 	FileType() { }
 	FileType(const std::vector<FileType> &group)
 	{
-		for(std::vector<FileType>::const_iterator it = group.begin(); it != group.end(); ++it)
+		for(const auto &type : group)
 		{
-			m_MimeTypes.insert(m_MimeTypes.end(), it->m_MimeTypes.begin(), it->m_MimeTypes.end());
-			m_Extensions.insert(m_Extensions.end(), it->m_Extensions.begin(), it->m_Extensions.end());
-			m_Prefixes.insert(m_Prefixes.end(), it->m_Prefixes.begin(), it->m_Prefixes.end());
+			m_MimeTypes.insert(m_MimeTypes.end(), type.m_MimeTypes.begin(), type.m_MimeTypes.end());
+			m_Extensions.insert(m_Extensions.end(), type.m_Extensions.begin(), type.m_Extensions.end());
+			m_Prefixes.insert(m_Prefixes.end(), type.m_Prefixes.begin(), type.m_Prefixes.end());
 		}
 	}
 	static FileType Any()
diff --git a/common/mptRandom.cpp b/common/mptRandom.cpp
index 4f767f9..5689a4e 100644
--- a/common/mptRandom.cpp
+++ b/common/mptRandom.cpp
@@ -39,43 +39,9 @@ static T log2(T x)
 }
 
 
-static inline int lower_bound_entropy_bits(unsigned int x)
+static MPT_CONSTEXPR11_FUN int lower_bound_entropy_bits(unsigned int x)
 {
-	// easy to compile-time evaluate even for stupid compilers
-	return
-		x >= 0xffffffffu ? 32 :
-		x >= 0x7fffffffu ? 31 :
-		x >= 0x3fffffffu ? 30 :
-		x >= 0x1fffffffu ? 29 :
-		x >= 0x0fffffffu ? 28 :
-		x >= 0x07ffffffu ? 27 :
-		x >= 0x03ffffffu ? 26 :
-		x >= 0x01ffffffu ? 25 :
-		x >= 0x00ffffffu ? 24 :
-		x >= 0x007fffffu ? 23 :
-		x >= 0x003fffffu ? 22 :
-		x >= 0x001fffffu ? 21 :
-		x >= 0x000fffffu ? 20 :
-		x >= 0x0007ffffu ? 19 :
-		x >= 0x0003ffffu ? 18 :
-		x >= 0x0001ffffu ? 17 :
-		x >= 0x0000ffffu ? 16 :
-		x >= 0x00007fffu ? 15 :
-		x >= 0x00003fffu ? 14 :
-		x >= 0x00001fffu ? 13 :
-		x >= 0x00000fffu ? 12 :
-		x >= 0x000007ffu ? 11 :
-		x >= 0x000003ffu ? 10 :
-		x >= 0x000001ffu ?  9 :
-		x >= 0x000000ffu ?  8 :
-		x >= 0x0000007fu ?  7 :
-		x >= 0x0000003fu ?  6 :
-		x >= 0x0000001fu ?  5 :
-		x >= 0x0000000fu ?  4 :
-		x >= 0x00000007u ?  3 :
-		x >= 0x00000003u ?  2 :
-		x >= 0x00000001u ?  1 :
-		0;
+	return detail::lower_bound_entropy_bits(x);
 }
 
 
@@ -83,7 +49,7 @@ template <typename T>
 static inline bool is_mask(T x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	typedef typename mpt::make_unsigned<T>::type unsigned_T;
+	typedef typename std::make_unsigned<T>::type unsigned_T;
 	unsigned_T ux = static_cast<unsigned_T>(x);
 	unsigned_T mask = 0;
 	for(std::size_t bits = 0; bits <= (sizeof(unsigned_T) * 8); ++bits)
@@ -132,20 +98,22 @@ static T generate_timeseed()
 		#endif // MPT_OS_WINDOWS
 		mpt::byte bytes[sizeof(t)];
 		std::memcpy(bytes, &t, sizeof(t));
-		#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
-			std::reverse(bytes + 0, bytes + CountOf(bytes));
-		#endif
-		hash(bytes + 0, bytes + CountOf(bytes));
+		MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
+		{
+			std::reverse(std::begin(bytes), std::end(bytes));
+		}
+		hash(std::begin(bytes), std::end(bytes));
 	}
 
 	{
 		std::clock_t c = std::clock();
 		mpt::byte bytes[sizeof(c)];
 		std::memcpy(bytes, &c, sizeof(c));
-		#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
-			std::reverse(bytes + 0, bytes + CountOf(bytes));
-		#endif
-		hash(bytes + 0, bytes + CountOf(bytes));
+		MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
+		{
+			std::reverse(std::begin(bytes), std::end(bytes));
+		}
+		hash(std::begin(bytes), std::end(bytes));
 	}
 
 	return static_cast<T>(hash.result());
@@ -165,21 +133,6 @@ void crand::reseed(uint32 seed)
 	std::srand(seed);
 }
 
-crand::result_type crand::min()
-{
-	return 0;
-}
-
-crand::result_type crand::max()
-{
-	return RAND_MAX;
-}
-
-int crand::result_bits()
-{
-	return lower_bound_entropy_bits(RAND_MAX);
-}
-
 crand::result_type crand::operator()()
 {
 	return std::rand();
@@ -189,91 +142,96 @@ crand::result_type crand::operator()()
 
 #endif // MODPLUG_TRACKER
 
-#if MPT_STD_RANDOM
-
 sane_random_device::sane_random_device()
 	: rd_reliable(rd.entropy() > 0.0)
 {
 	if(!rd_reliable)
 	{
-		uint64 seed_val = mpt::generate_timeseed<uint64>();
-		unsigned int seeds[2];
-		seeds[0] = static_cast<uint32>(seed_val >> 32);
-		seeds[1] = static_cast<uint32>(seed_val >>  0);
-		std::seed_seq seed(seeds + 0, seeds + 2);
-		rd_fallback = mpt::scoped_ptr<std::mt19937>::initializer(new std::mt19937(seed));
+		init_fallback();
 	}
 }
 
-sane_random_device::sane_random_device(const std::string & token)
-	: rd(token)
+sane_random_device::sane_random_device(const std::string & token_)
+	: token(token_)
+	, rd(token)
 	, rd_reliable(rd.entropy() > 0.0)
 {
 	if(!rd_reliable)
 	{
-		uint64 seed_val = mpt::generate_timeseed<uint64>();
-		std::vector<unsigned int> seeds;
-		seeds.push_back(static_cast<uint32>(seed_val >> 32));
-		seeds.push_back(static_cast<uint32>(seed_val >>  0));
-		for(std::size_t i = 0; i < token.length(); ++i)
-		{
-			seeds.push_back(static_cast<unsigned int>(static_cast<unsigned char>(token[i])));
-		}
-		std::seed_seq seed(seeds.begin(), seeds.end());
-		rd_fallback = mpt::scoped_ptr<std::mt19937>::initializer(new std::mt19937(seed));
+		init_fallback();
 	}
 }
 
-sane_random_device::result_type sane_random_device::min()
-{
-	return std::numeric_limits<result_type>::min();
-}
-
-sane_random_device::result_type sane_random_device::max()
+void sane_random_device::init_fallback()
 {
-	return std::numeric_limits<result_type>::max();
-}
-
-int sane_random_device::result_bits()
-{
-	return sizeof(result_type) * 8;
+	if(!rd_fallback)
+	{
+		if(token.length() > 0)
+		{
+			uint64 seed_val = mpt::generate_timeseed<uint64>();
+			std::vector<unsigned int> seeds;
+			seeds.push_back(static_cast<uint32>(seed_val >> 32));
+			seeds.push_back(static_cast<uint32>(seed_val >>  0));
+			for(std::size_t i = 0; i < token.length(); ++i)
+			{
+				seeds.push_back(static_cast<unsigned int>(static_cast<unsigned char>(token[i])));
+			}
+			std::seed_seq seed(seeds.begin(), seeds.end());
+			rd_fallback = mpt::make_unique<std::mt19937>(seed);
+		} else
+		{
+			uint64 seed_val = mpt::generate_timeseed<uint64>();
+			unsigned int seeds[2];
+			seeds[0] = static_cast<uint32>(seed_val >> 32);
+			seeds[1] = static_cast<uint32>(seed_val >>  0);
+			std::seed_seq seed(seeds + 0, seeds + 2);
+			rd_fallback = mpt::make_unique<std::mt19937>(seed);
+		}
+	}
 }
 
 sane_random_device::result_type sane_random_device::operator()()
 {
 	MPT_LOCK_GUARD<mpt::mutex> l(m);
 	result_type result = 0;
-	if(rd.min() != 0 || !mpt::is_mask(rd.max()))
-	{ // insane std::random_device
-		//  This implementation is not exactly uniformly distributed but good enough
-		// for OpenMPT.
-		double rd_min = static_cast<double>(rd.min());
-		double rd_max = static_cast<double>(rd.max());
-		double rd_range = rd_max - rd_min;
-		double rd_size = rd_range + 1.0;
-		double rd_entropy = mpt::log2(rd_size);
-		int iterations = static_cast<int>(std::ceil(result_bits() / rd_entropy));
-		double tmp = 0.0;
-		for(int i = 0; i < iterations; ++i)
-		{
-			tmp = (tmp * rd_size) + (static_cast<double>(rd()) - rd_min);
-		}
-		double result_01 = std::floor(tmp / std::pow(rd_size, iterations));
-		result = static_cast<result_type>(std::floor(result_01 * (static_cast<double>(max() - min()) + 1.0))) + min();
-	} else
-	{ // sane std::random_device
-		result = 0;
-		std::size_t rd_bits = mpt::lower_bound_entropy_bits(rd.max());
-		for(std::size_t entropy = 0; entropy < (sizeof(result_type) * 8); entropy += rd_bits)
-		{
-			if(rd_bits < (sizeof(result_type) * 8))
+	try
+	{
+		if(rd.min() != 0 || !mpt::is_mask(rd.max()))
+		{ // insane std::random_device
+			//  This implementation is not exactly uniformly distributed but good enough
+			// for OpenMPT.
+			double rd_min = static_cast<double>(rd.min());
+			double rd_max = static_cast<double>(rd.max());
+			double rd_range = rd_max - rd_min;
+			double rd_size = rd_range + 1.0;
+			double rd_entropy = mpt::log2(rd_size);
+			int iterations = static_cast<int>(std::ceil(result_bits() / rd_entropy));
+			double tmp = 0.0;
+			for(int i = 0; i < iterations; ++i)
 			{
-				result = (result << rd_bits) | static_cast<result_type>(rd());
-			} else
+				tmp = (tmp * rd_size) + (static_cast<double>(rd()) - rd_min);
+			}
+			double result_01 = std::floor(tmp / std::pow(rd_size, iterations));
+			result = static_cast<result_type>(std::floor(result_01 * (static_cast<double>(max() - min()) + 1.0))) + min();
+		} else
+		{ // sane std::random_device
+			result = 0;
+			std::size_t rd_bits = mpt::lower_bound_entropy_bits(rd.max());
+			for(std::size_t entropy = 0; entropy < (sizeof(result_type) * 8); entropy += rd_bits)
 			{
-				result = result | static_cast<result_type>(rd());
+				if(rd_bits < (sizeof(result_type) * 8))
+				{
+					result = (result << rd_bits) | static_cast<result_type>(rd());
+				} else
+				{
+					result = result | static_cast<result_type>(rd());
+				}
 			}
 		}
+	} catch(const std::exception &)
+	{
+		rd_reliable = false;
+		init_fallback();
 	}
 	if(!rd_reliable)
 	{ // std::random_device is unreliable
@@ -287,8 +245,6 @@ sane_random_device::result_type sane_random_device::operator()()
 	return result;
 }
 
-#endif // MPT_STD_RANDOM
-
 prng_random_device_seeder::prng_random_device_seeder()
 {
 	return;
diff --git a/common/mptRandom.h b/common/mptRandom.h
index cc6fe0f..97db580 100644
--- a/common/mptRandom.h
+++ b/common/mptRandom.h
@@ -12,16 +12,12 @@
 
 #include "mptMutex.h"
 
-#if MPT_COMPILER_GENERIC || (MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2010,0)) || (MPT_COMPILER_GCC && MPT_GCC_AT_LEAST(4,5,0)) || (MPT_COMPILER_CLANG && MPT_CLANG_AT_LEAST(3,0,0)) || MPT_COMPILER_MSVCCLANGC2
-#define MPT_STD_RANDOM 1
-#else // MPT_COMPILER
-#define MPT_STD_RANDOM 0
-#endif // MPT_COMPILER
-
 #include <limits>
-#if MPT_STD_RANDOM
 #include <random>
-#endif // MPT_STD_RANDOM
+
+#ifdef MODPLUG_TRACKER
+#include <cstdlib>
+#endif // MODPLUG_TRACKER
 
 
 OPENMPT_NAMESPACE_BEGIN
@@ -50,10 +46,55 @@ static const uint32 FUZZER_RNG_SEED = 3141592653u; // pi
 #endif // MPT_BUILD_FUZZER
 
 
+namespace detail
+{
+
+MPT_CONSTEXPR11_FUN int lower_bound_entropy_bits(unsigned int x)
+{
+	// easy to compile-time evaluate even for stupid compilers
+	return
+		x >= 0xffffffffu ? 32 :
+		x >= 0x7fffffffu ? 31 :
+		x >= 0x3fffffffu ? 30 :
+		x >= 0x1fffffffu ? 29 :
+		x >= 0x0fffffffu ? 28 :
+		x >= 0x07ffffffu ? 27 :
+		x >= 0x03ffffffu ? 26 :
+		x >= 0x01ffffffu ? 25 :
+		x >= 0x00ffffffu ? 24 :
+		x >= 0x007fffffu ? 23 :
+		x >= 0x003fffffu ? 22 :
+		x >= 0x001fffffu ? 21 :
+		x >= 0x000fffffu ? 20 :
+		x >= 0x0007ffffu ? 19 :
+		x >= 0x0003ffffu ? 18 :
+		x >= 0x0001ffffu ? 17 :
+		x >= 0x0000ffffu ? 16 :
+		x >= 0x00007fffu ? 15 :
+		x >= 0x00003fffu ? 14 :
+		x >= 0x00001fffu ? 13 :
+		x >= 0x00000fffu ? 12 :
+		x >= 0x000007ffu ? 11 :
+		x >= 0x000003ffu ? 10 :
+		x >= 0x000001ffu ?  9 :
+		x >= 0x000000ffu ?  8 :
+		x >= 0x0000007fu ?  7 :
+		x >= 0x0000003fu ?  6 :
+		x >= 0x0000001fu ?  5 :
+		x >= 0x0000000fu ?  4 :
+		x >= 0x00000007u ?  3 :
+		x >= 0x00000003u ?  2 :
+		x >= 0x00000001u ?  1 :
+		0;
+}
+
+}
+
+
 template <typename Trng> struct engine_traits
 {
 	typedef typename Trng::result_type result_type;
-	static inline int result_bits()
+	static MPT_CONSTEXPR11_FUN int result_bits()
 	{
 		return Trng::result_bits();
 	}
@@ -69,14 +110,15 @@ template <typename T, typename Trng>
 inline T random(Trng & rng)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	typedef typename mpt::make_unsigned<T>::type unsigned_T;
+	typedef typename std::make_unsigned<T>::type unsigned_T;
 	const unsigned int rng_bits = mpt::engine_traits<Trng>::result_bits();
 	unsigned_T result = 0;
 	for(std::size_t entropy = 0; entropy < (sizeof(T) * 8); entropy += rng_bits)
 	{
 		MPT_CONSTANT_IF(rng_bits < (sizeof(T) * 8))
 		{
-			result = (result << rng_bits) ^ static_cast<unsigned_T>(rng());
+			MPT_CONSTEXPR11_VAR unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however)
+			result = (result << shift_bits) ^ static_cast<unsigned_T>(rng());
 		} else
 		{
 			result = static_cast<unsigned_T>(rng());
@@ -89,14 +131,15 @@ template <typename T, std::size_t required_entropy_bits, typename Trng>
 inline T random(Trng & rng)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	typedef typename mpt::make_unsigned<T>::type unsigned_T;
+	typedef typename std::make_unsigned<T>::type unsigned_T;
 	const unsigned int rng_bits = mpt::engine_traits<Trng>::result_bits();
 	unsigned_T result = 0;
 	for(std::size_t entropy = 0; entropy < std::min<std::size_t>(required_entropy_bits, sizeof(T) * 8); entropy += rng_bits)
 	{
-		if(rng_bits < (sizeof(T) * 8))
+		MPT_CONSTANT_IF(rng_bits < (sizeof(T) * 8))
 		{
-			result = (result << rng_bits) ^ static_cast<unsigned_T>(rng());
+			MPT_CONSTEXPR11_VAR unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however)
+			result = (result << shift_bits) ^ static_cast<unsigned_T>(rng());
 		} else
 		{
 			result = static_cast<unsigned_T>(rng());
@@ -115,14 +158,15 @@ template <typename T, typename Trng>
 inline T random(Trng & rng, std::size_t required_entropy_bits)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	typedef typename mpt::make_unsigned<T>::type unsigned_T;
+	typedef typename std::make_unsigned<T>::type unsigned_T;
 	const unsigned int rng_bits = mpt::engine_traits<Trng>::result_bits();
 	unsigned_T result = 0;
 	for(std::size_t entropy = 0; entropy < std::min<std::size_t>(required_entropy_bits, sizeof(T) * 8); entropy += rng_bits)
 	{
-		if(rng_bits < (sizeof(T) * 8))
+		MPT_CONSTANT_IF(rng_bits < (sizeof(T) * 8))
 		{
-			result = (result << rng_bits) ^ static_cast<unsigned_T>(rng());
+			MPT_CONSTEXPR11_VAR unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however)
+			result = (result << shift_bits) ^ static_cast<unsigned_T>(rng());
 		} else
 		{
 			result = static_cast<unsigned_T>(rng());
@@ -169,7 +213,7 @@ public:
 	{
 		typedef typename float_traits<T>::mantissa_uint_type uint_type;
 		const int bits = float_traits<T>::mantissa_bits;
-		return ((b - a) * static_cast<T>(mpt::random<uint_type, bits>(rng)) / static_cast<T>((static_cast<uint_type>(1u) << bits) - 1u)) + a;
+		return ((b - a) * static_cast<T>(mpt::random<uint_type, bits>(rng)) / static_cast<T>((static_cast<uint_type>(1u) << bits))) + a;
 	}
 };
 
@@ -213,16 +257,16 @@ public:
 		operator()(); // we return results from the current state and update state after returning. results in better pipelining.
 	}
 public:
-	static inline result_type min()
+	static MPT_CONSTEXPR11_FUN result_type min()
 	{
 		return static_cast<result_type>(0);
 	}
-	static inline result_type max()
+	static MPT_CONSTEXPR11_FUN result_type max()
 	{
 		STATIC_ASSERT(((result_mask >> result_shift) << result_shift) == result_mask);
 		return static_cast<result_type>(result_mask >> result_shift);
 	}
-	static inline int result_bits()
+	static MPT_CONSTEXPR11_FUN int result_bits()
 	{
 		STATIC_ASSERT(((static_cast<Tstate>(1) << result_bits_) - 1) == (result_mask >> result_shift));
 		return result_bits_;
@@ -271,9 +315,18 @@ public:
 	crand() { }
 	explicit crand(const std::string &) { }
 public:
-	static result_type min();
-	static result_type max();
-	static int result_bits();
+	static MPT_CONSTEXPR11_FUN result_type min()
+	{
+		return 0;
+	}
+	static MPT_CONSTEXPR11_FUN result_type max()
+	{
+		return RAND_MAX;
+	}
+	static MPT_CONSTEXPR11_FUN int result_bits()
+	{
+		return detail::lower_bound_entropy_bits(RAND_MAX);
+	}
 	result_type operator()();
 };
 
@@ -282,9 +335,6 @@ public:
 #endif // MODPLUG_TRACKER
 
 
-#if MPT_STD_RANDOM
-
-
 //  C++11 std::random_device may be implemented as a deterministic PRNG.
 //  There is no way to seed this PRNG and it is allowed to be seeded with the
 // same value on each program invocation. This makes std::random_device
@@ -295,17 +345,29 @@ class sane_random_device
 {
 private:
 	mpt::mutex m;
+	std::string token;
 	std::random_device rd;
 	bool rd_reliable;
-	mpt::scoped_ptr<std::mt19937> rd_fallback;
+	std::unique_ptr<std::mt19937> rd_fallback;
 public:
 	typedef unsigned int result_type;
+private:
+	void init_fallback();
 public:
 	sane_random_device();
 	sane_random_device(const std::string & token);
-	static result_type min();
-	static result_type max();
-	static int result_bits();
+	static MPT_CONSTEXPR11_FUN result_type min()
+	{
+		return std::numeric_limits<result_type>::min();
+	}
+	static MPT_CONSTEXPR11_FUN result_type max()
+	{
+		return std::numeric_limits<result_type>::max();
+	}
+	static MPT_CONSTEXPR11_FUN int result_bits()
+	{
+		return sizeof(result_type) * 8;
+	}
 	result_type operator()();
 };
 
@@ -343,7 +405,7 @@ template <> struct engine_traits<std::mt19937> {
 	static const std::size_t seed_bits = sizeof(std::mt19937::result_type) * 8 * std::mt19937::state_size;
 	typedef std::mt19937 rng_type;
 	typedef rng_type::result_type result_type;
-	static inline int result_bits() { return rng_type::word_size; }
+	static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
 	template<typename Trd> static inline rng_type make(Trd & rd)
 	{
 		mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
@@ -356,7 +418,7 @@ template <> struct engine_traits<std::mt19937_64> {
 	static const std::size_t seed_bits = sizeof(std::mt19937_64::result_type) * 8 * std::mt19937_64::state_size;
 	typedef std::mt19937_64 rng_type;
 	typedef rng_type::result_type result_type;
-	static inline int result_bits() { return rng_type::word_size; }
+	static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
 	template<typename Trd> static inline rng_type make(Trd & rd)
 	{
 		mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
@@ -369,7 +431,7 @@ template <> struct engine_traits<std::ranlux24_base> {
 	static const std::size_t seed_bits = std::ranlux24_base::word_size;
 	typedef std::ranlux24_base rng_type;
 	typedef rng_type::result_type result_type;
-	static inline int result_bits() { return rng_type::word_size; }
+	static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
 	template<typename Trd> static inline rng_type make(Trd & rd)
 	{
 		mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
@@ -382,7 +444,7 @@ template <> struct engine_traits<std::ranlux48_base> {
 	static const std::size_t seed_bits = std::ranlux48_base::word_size;
 	typedef std::ranlux48_base rng_type;
 	typedef rng_type::result_type result_type;
-	static inline int result_bits() { return rng_type::word_size; }
+	static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
 	template<typename Trd> static inline rng_type make(Trd & rd)
 	{
 		mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
@@ -395,7 +457,7 @@ template <> struct engine_traits<std::ranlux24> {
 	static const std::size_t seed_bits = std::ranlux24_base::word_size;
 	typedef std::ranlux24 rng_type;
 	typedef rng_type::result_type result_type;
-	static inline int result_bits() { return std::ranlux24_base::word_size; }
+	static MPT_CONSTEXPR11_FUN int result_bits() { return std::ranlux24_base::word_size; }
 	template<typename Trd> static inline rng_type make(Trd & rd)
 	{
 		mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
@@ -408,7 +470,7 @@ template <> struct engine_traits<std::ranlux48> {
 	static const std::size_t seed_bits = std::ranlux48_base::word_size;
 	typedef std::ranlux48 rng_type;
 	typedef rng_type::result_type result_type;
-	static inline int result_bits() { return std::ranlux48_base::word_size; }
+	static MPT_CONSTEXPR11_FUN int result_bits() { return std::ranlux48_base::word_size; }
 	template<typename Trd> static inline rng_type make(Trd & rd)
 	{
 		mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
@@ -418,9 +480,6 @@ template <> struct engine_traits<std::ranlux48> {
 };
 
 
-#endif // MPT_STD_RANDOM
-
-
 class prng_random_device_seeder
 {
 private:
@@ -459,15 +518,15 @@ public:
 	{
 		return;
 	}
-	static result_type min()
+	static MPT_CONSTEXPR11_FUN result_type min()
 	{
 		return std::numeric_limits<unsigned int>::min();
 	}
-	static result_type max()
+	static MPT_CONSTEXPR11_FUN result_type max()
 	{
 		return std::numeric_limits<unsigned int>::max();
 	}
-	static int result_bits()
+	static MPT_CONSTEXPR11_FUN int result_bits()
 	{
 		return sizeof(unsigned int) * 8;
 	}
@@ -492,8 +551,6 @@ typedef mpt::rng::lcg_musl best_prng;
 
 #else // !MPT_BUILD_FUZZER
 
-#if MPT_STD_RANDOM
-
 // mpt::random_device always generates 32 bits of entropy
 typedef mpt::sane_random_device random_device;
 
@@ -503,18 +560,6 @@ typedef mpt::rng::lcg_msvc fast_prng; // about 3 ALU operations, ~32bit of state
 typedef std::mt19937       main_prng;
 typedef std::ranlux48      best_prng;
 
-#else // !MPT_STD_RANDOM
-
-// easy to implement fallbacks, only used on very old compilers
-
-typedef mpt::prng_random_device<mpt::rng::lcg_musl> random_device;
-
-typedef mpt::rng::lcg_msvc fast_prng;
-typedef mpt::rng::lcg_c99  main_prng;
-typedef mpt::rng::lcg_musl best_prng;
-
-#endif // MPT_STD_RANDOM
-
 #endif // MPT_BUILD_FUZZER
 
 
@@ -550,15 +595,15 @@ public:
 		return;
 	}
 public:
-	static typename engine_traits<Trng>::result_type min()
+	static MPT_CONSTEXPR11_FUN typename engine_traits<Trng>::result_type min()
 	{
 		return Trng::min();
 	}
-	static typename engine_traits<Trng>::result_type max()
+	static MPT_CONSTEXPR11_FUN typename engine_traits<Trng>::result_type max()
 	{
 		return Trng::max();
 	}
-	static int result_bits()
+	static MPT_CONSTEXPR11_FUN int result_bits()
 	{
 		return engine_traits<Trng>::result_bits();
 	}
diff --git a/common/mptString.cpp b/common/mptString.cpp
index 594c2f9..dbf6822 100644
--- a/common/mptString.cpp
+++ b/common/mptString.cpp
@@ -10,6 +10,8 @@
 #include "stdafx.h"
 #include "mptString.h"
 
+#include "Endianness.h"
+
 #if defined(MPT_CHARSET_CODECVTUTF8)
 #include <codecvt>
 #endif
@@ -26,12 +28,6 @@
 #endif // MODPLUG_TRACKER
 
 #if defined(MODPLUG_TRACKER)
-#if MPT_COMPILER_GCC || MPT_COMPILER_CLANG
-#include <strings.h> // for strncasecmp
-#endif
-#endif // MODPLUG_TRACKER
-
-#if defined(MODPLUG_TRACKER)
 #include <wctype.h>
 #endif // MODPLUG_TRACKER
 
@@ -68,7 +64,7 @@ List of string types
 --------------------
 
  *  std::string (OpenMPT, libopenmpt)
-    C++ string of unspedicifed 8bit encoding. Try to always document the
+    C++ string of unspecifed 8bit encoding. Try to always document the
     encoding if not clear from context. Do not use unless there is an obvious
     reason to do so.
 
@@ -88,14 +84,14 @@ List of string types
 
  *  CString (OpenMPT)
     MFC string type, either encoded in locale/CP_ACP (if !UNICODE) or UTF16 (if
-    UNICODE). Specify literals with _T(""). Use in MFC gui code.
+    UNICODE). Specify literals with _T(""). Use in MFC GUI code.
 
  *  CStringA (OpenMPT)
     MFC ANSI string type. The encoding is always CP_ACP. Do not use unless there
     is an obvious reason to do so.
 
  *  CStringW (OpenMPT)
-    MFC Unicode string type. Use in MFC gui code when explicit Unicode support
+    MFC Unicode string type. Use in MFC GUI code when explicit Unicode support
     is required.
 
  *  mpt::PathString (OpenMPT, libopenmpt)
@@ -117,6 +113,15 @@ List of string types
     runtime conversion. Only use for string literals containing non-ascii
     characters (use MPT_USTRING otherwise).
 
+ *  MPT_ULITERAL / MPT_UCHAR / MPT_UCHAR_TYPE (OpenMPT, libopenmpt)
+    Macros which generate string literals, char literals and the char literal
+    type respectively. These are especially useful in constexpr contexts or
+    global data where MPT_USTRING is either unusable or requires a global
+    contructor to run. Do NOT use as a performance optimization in place of
+    MPT_USTRING however, because MPT_USTRING can be converted to C++11/14 user
+    defined literals eventually, while MPT_ULITERAL cannot because of constexpr
+    requirements.
+
  *  mpt::RawPathString (OpenMPT, libopenmpt)
     Internal representation of mpt::PathString. Only use for parsing path
     fragments.
@@ -164,7 +169,7 @@ Encoding of 8bit strings
 ------------------------
 
 8bit strings have an unspecified encoding. When the string is contained within a
-CSoundFile object, the encoding is most likely CSoundFile::GetCharset(),
+CSoundFile object, the encoding is most likely CSoundFile::GetCharsetInternal(),
 otherwise, try to gather the most probable encoding from surrounding or related
 code sections.
 
@@ -196,7 +201,7 @@ if in libopenmpt
 else
  if performance critical inner loop
   if needs unicode support
-   T = wchar_t*
+   T = MPT_UCHAR_TYPE* / MPT_ULITERAL
   else
    T = char*, document the encoding if not clear from context 
   fi
@@ -222,7 +227,11 @@ else
   if directly interfacing with wide winapi
    T = std::wstring
   else
-   T = mpt::ustring
+   if constexpr context or global data
+    T = MPT_UCHAR_TYPE* / MPT_ULITERAL
+   else
+    T = mpt::ustring
+	 fi
   fi
  fi
 fi
@@ -295,31 +304,6 @@ ToTcharStr, FromTcharStr.
 
 
 
-namespace mpt {
-
-
-#ifdef MODPLUG_TRACKER
-
-// We cannot use the C runtime version in libopenmpt as it depends on the
-// global C locale.
-// We provide a plain ASCII version as mpt::CompareNoCaseAscci().
-
-int strnicmp(const char *a, const char *b, size_t count)
-//------------------------------------------------------
-{
-#if MPT_COMPILER_MSVC
-	return _strnicmp(a, b, count);
-#else
-	return strncasecmp(a, b, count);
-#endif
-}
-
-#endif // MODPLUG_TRACKER
-
-
-} // namespace mpt
-
-
 namespace mpt { namespace String {
 
 
@@ -458,14 +442,13 @@ static const uint32 CharsetTableCP437AMS2[256] = {
 #endif
 
 static std::wstring From8bit(const std::string &str, const uint32 (&table)[256], wchar_t replacement = L'\uFFFD')
-//---------------------------------------------------------------------------------------------------------------
 {
 	std::wstring res;
 	res.reserve(str.length());
 	for(std::size_t i = 0; i < str.length(); ++i)
 	{
 		uint32 c = static_cast<uint32>(static_cast<uint8>(str[i]));
-		if(c < CountOf(table))
+		if(c < mpt::size(table))
 		{
 			res.push_back(static_cast<wchar_t>(static_cast<uint32>(table[c])));
 		} else
@@ -477,7 +460,6 @@ static std::wstring From8bit(const std::string &str, const uint32 (&table)[256],
 }
 
 static std::string To8bit(const std::wstring &str, const uint32 (&table)[256], char replacement = '?')
-//----------------------------------------------------------------------------------------------------
 {
 	std::string res;
 	res.reserve(str.length());
@@ -488,7 +470,7 @@ static std::string To8bit(const std::wstring &str, const uint32 (&table)[256], c
 		// Try non-control characters first.
 		// In cases where there are actual characters mirrored in this range (like in AMS/AMS2 character sets),
 		// characters in the common range are preferred this way.
-		for(std::size_t x = 0x20; x < CountOf(table); ++x)
+		for(std::size_t x = 0x20; x < mpt::size(table); ++x)
 		{
 			if(c == table[x])
 			{
@@ -500,7 +482,7 @@ static std::string To8bit(const std::wstring &str, const uint32 (&table)[256], c
 		if(!found)
 		{
 			// try control characters
-			for(std::size_t x = 0x00; x < CountOf(table) && x < 0x20; ++x)
+			for(std::size_t x = 0x00; x < mpt::size(table) && x < 0x20; ++x)
 			{
 				if(c == table[x])
 				{
@@ -521,7 +503,6 @@ static std::string To8bit(const std::wstring &str, const uint32 (&table)[256], c
 #if defined(MPT_CHARSET_CODECVTUTF8) || defined(MPT_CHARSET_INTERNAL) || defined(MPT_CHARSET_WIN32)
 
 static std::wstring FromAscii(const std::string &str, wchar_t replacement = L'\uFFFD')
-//------------------------------------------------------------------------------------
 {
 	std::wstring res;
 	res.reserve(str.length());
@@ -540,7 +521,6 @@ static std::wstring FromAscii(const std::string &str, wchar_t replacement = L'\u
 }
 
 static std::string ToAscii(const std::wstring &str, char replacement = '?')
-//-------------------------------------------------------------------------
 {
 	std::string res;
 	res.reserve(str.length());
@@ -559,7 +539,6 @@ static std::string ToAscii(const std::wstring &str, char replacement = '?')
 }
 
 static std::wstring FromISO_8859_1(const std::string &str, wchar_t replacement = L'\uFFFD')
-//-----------------------------------------------------------------------------------------
 {
 	MPT_UNREFERENCED_PARAMETER(replacement);
 	std::wstring res;
@@ -573,7 +552,6 @@ static std::wstring FromISO_8859_1(const std::string &str, wchar_t replacement =
 }
 
 static std::string ToISO_8859_1(const std::wstring &str, char replacement = '?')
-//------------------------------------------------------------------------------
 {
 	std::string res;
 	res.reserve(str.length());
@@ -608,7 +586,6 @@ static std::string ToISO_8859_1(const std::wstring &str, char replacement = '?')
 // following non-convertible characters are not a problem.
 
 static std::wstring LocaleDecode(const std::string &str, const std::locale & locale, wchar_t replacement = L'\uFFFD', int retry = 0, bool * progress = nullptr)
-//-------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	if(str.empty())
 	{
@@ -663,9 +640,9 @@ static std::wstring LocaleDecode(const std::string &str, const std::locale & loc
 		{
 			if(result == codecvt_type::error && in_next == in_begin && out_next == out_begin)
 			{
-				bool progress = true;
-				LocaleDecode(std::string(" ") + str, locale, replacement, 1, &progress);
-				if(!progress)
+				bool made_progress = true;
+				LocaleDecode(std::string(" ") + str, locale, replacement, 1, &made_progress);
+				if(!made_progress)
 				{
 					return LocaleDecode(str, locale, replacement, 2);
 				}
@@ -694,7 +671,6 @@ static std::wstring LocaleDecode(const std::string &str, const std::locale & loc
 }
 
 static std::string LocaleEncode(const std::wstring &str, const std::locale & locale, char replacement = '?', int retry = 0, bool * progress = nullptr)
-//----------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	if(str.empty())
 	{
@@ -749,9 +725,9 @@ static std::string LocaleEncode(const std::wstring &str, const std::locale & loc
 		{
 			if(result == codecvt_type::error && in_next == in_begin && out_next == out_begin)
 			{
-				bool progress = true;
-				LocaleEncode(std::wstring(L" ") + str, locale, replacement, 1, &progress);
-				if(!progress)
+				bool made_progress = true;
+				LocaleEncode(std::wstring(L" ") + str, locale, replacement, 1, &made_progress);
+				if(!made_progress)
 				{
 					return LocaleEncode(str, locale, replacement, 2);
 				}
@@ -780,7 +756,6 @@ static std::string LocaleEncode(const std::wstring &str, const std::locale & loc
 }
 
 static std::wstring FromLocale(const std::string &str, wchar_t replacement = L'\uFFFD')
-//-------------------------------------------------------------------------------------
 {
 	try
 	{
@@ -811,7 +786,6 @@ static std::wstring FromLocale(const std::string &str, wchar_t replacement = L'\
 }
 
 static std::string ToLocale(const std::wstring &str, char replacement = '?')
-//--------------------------------------------------------------------------
 {
 	try
 	{
@@ -848,7 +822,6 @@ static std::string ToLocale(const std::wstring &str, char replacement = '?')
 #if defined(MPT_CHARSET_CODECVTUTF8)
 
 static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uFFFD')
-//-----------------------------------------------------------------------------------
 {
 	MPT_UNREFERENCED_PARAMETER(replacement);
 	std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
@@ -856,7 +829,6 @@ static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uF
 }
 
 static std::string ToUTF8(const std::wstring &str, char replacement = '?')
-//------------------------------------------------------------------------
 {
 	MPT_UNREFERENCED_PARAMETER(replacement);
 	std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
@@ -868,7 +840,6 @@ static std::string ToUTF8(const std::wstring &str, char replacement = '?')
 #if defined(MPT_CHARSET_INTERNAL) || defined(MPT_CHARSET_WIN32)
 
 static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uFFFD')
-//-----------------------------------------------------------------------------------
 {
 	const std::string &in = str;
 
@@ -878,9 +849,7 @@ static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uF
 	std::size_t charsleft = 0;
 	uint32 ucs4 = 0;
 
-	for ( std::string::const_iterator i = in.begin(); i != in.end(); ++i ) {
-
-		uint8 c = *i;
+	for ( uint8 c : in ) {
 
 		if ( charsleft == 0 ) {
 
@@ -949,7 +918,6 @@ static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uF
 }
 
 static std::string ToUTF8(const std::wstring &str, char replacement = '?')
-//------------------------------------------------------------------------
 {
 	const std::wstring &in = str;
 
@@ -1131,23 +1099,25 @@ static const char * Charset_wchar_t()
 		if(sizeof(wchar_t) == 2)
 		{
 			// "UTF-16" generates BOM
-			#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
+			MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
+			{
 				return "UTF-16LE";
-			#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+			}
+			MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big())
+			{
 				return "UTF-16BE";
-			#else
-				STATIC_ASSERT(false);
-			#endif
+			}
 		} else if(sizeof(wchar_t) == 4)
 		{
 			// "UTF-32" generates BOM
-			#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
+			MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
+			{
 				return "UTF-32LE";
-			#elif defined(MPT_PLATFORM_BIG_ENDIAN)
+			}
+			MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big())
+			{
 				return "UTF-32BE";
-			#else
-				STATIC_ASSERT(false);
-			#endif
+			}
 		}
 		return "";
 	#endif // !MPT_ICONV_NO_WCHAR | MPT_ICONV_NO_WCHAR
@@ -1193,8 +1163,8 @@ Tdststring EncodeImpl(Charset charset, const std::wstring &src)
 			return Tdststring();
 		}
 		std::vector<CHAR> encoded_string(required_size);
-		WideCharToMultiByte(codepage, 0, src.c_str(), -1, &encoded_string[0], required_size, nullptr, nullptr);
-		return reinterpret_cast<const typename Tdststring::value_type*>(&encoded_string[0]);
+		WideCharToMultiByte(codepage, 0, src.c_str(), -1, encoded_string.data(), required_size, nullptr, nullptr);
+		return reinterpret_cast<const typename Tdststring::value_type*>(encoded_string.data());
 	#elif defined(MPT_CHARSET_ICONV)
 		iconv_t conv = iconv_t();
 		conv = iconv_open(CharsetToStringTranslit(charset), Charset_wchar_t());
@@ -1208,9 +1178,9 @@ Tdststring EncodeImpl(Charset charset, const std::wstring &src)
 		}
 		std::vector<wchar_t> wide_string(src.c_str(), src.c_str() + src.length() + 1);
 		std::vector<char> encoded_string(wide_string.size() * 8); // large enough
-		char * inbuf = reinterpret_cast<char*>(&wide_string[0]);
+		char * inbuf = reinterpret_cast<char*>(wide_string.data());
 		size_t inbytesleft = wide_string.size() * sizeof(wchar_t);
-		char * outbuf = &encoded_string[0];
+		char * outbuf = encoded_string.data();
 		size_t outbytesleft = encoded_string.size();
 		while(iconv(conv, &inbuf, &inbytesleft, &outbuf, &outbytesleft) == static_cast<size_t>(-1))
 		{
@@ -1231,7 +1201,7 @@ Tdststring EncodeImpl(Charset charset, const std::wstring &src)
 		}
 		iconv_close(conv);
 		conv = iconv_t();
-		return reinterpret_cast<const typename Tdststring::value_type*>(&encoded_string[0]);
+		return reinterpret_cast<const typename Tdststring::value_type*>(encoded_string.data());
 	#else
 		return EncodeImplFallback<Tdststring>(charset, src);
 	#endif
@@ -1300,8 +1270,8 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
 			return std::wstring();
 		}
 		std::vector<WCHAR> decoded_string(required_size);
-		MultiByteToWideChar(codepage, 0, reinterpret_cast<const char*>(src.c_str()), -1, &decoded_string[0], required_size);
-		return &decoded_string[0];
+		MultiByteToWideChar(codepage, 0, reinterpret_cast<const char*>(src.c_str()), -1, decoded_string.data(), required_size);
+		return decoded_string.data();
 	#elif defined(MPT_CHARSET_ICONV)
 		iconv_t conv = iconv_t();
 		conv = iconv_open(Charset_wchar_t(), CharsetToString(charset));
@@ -1311,9 +1281,9 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
 		}
 		std::vector<char> encoded_string(reinterpret_cast<const char*>(src.c_str()), reinterpret_cast<const char*>(src.c_str()) + src.length() + 1);
 		std::vector<wchar_t> wide_string(encoded_string.size() * 8); // large enough
-		char * inbuf = &encoded_string[0];
+		char * inbuf = encoded_string.data();
 		size_t inbytesleft = encoded_string.size();
-		char * outbuf = reinterpret_cast<char*>(&wide_string[0]);
+		char * outbuf = reinterpret_cast<char*>(wide_string.data());
 		size_t outbytesleft = wide_string.size() * sizeof(wchar_t);
 		while(iconv(conv, &inbuf, &inbytesleft, &outbuf, &outbytesleft) == static_cast<size_t>(-1))
 		{
@@ -1325,10 +1295,19 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
 				{
 					outbuf[i] = 0;
 				}
-				#ifdef MPT_PLATFORM_BIG_ENDIAN
+				#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
+					outbuf[1] = uint8(0xff); outbuf[0] = uint8(0xfd);
+				#elif defined(MPT_PLATFORM_BIG_ENDIAN)
 					outbuf[sizeof(wchar_t)-1 - 1] = uint8(0xff); outbuf[sizeof(wchar_t)-1 - 0] = uint8(0xfd);
 				#else
-					outbuf[1] = uint8(0xff); outbuf[0] = uint8(0xfd);
+					MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
+					{
+						outbuf[1] = uint8(0xff); outbuf[0] = uint8(0xfd);
+					}
+					MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big())
+					{
+						outbuf[sizeof(wchar_t)-1 - 1] = uint8(0xff); outbuf[sizeof(wchar_t)-1 - 0] = uint8(0xfd);
+					}
 				#endif
 				outbuf += sizeof(wchar_t);
 				outbytesleft -= sizeof(wchar_t);
@@ -1342,7 +1321,7 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
 		}
 		iconv_close(conv);
 		conv = iconv_t();
-		return &wide_string[0];
+		return wide_string.data();
 	#else
 		return DecodeImplFallback<Tsrcstring>(charset, src);
 	#endif
@@ -1402,9 +1381,9 @@ Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
 		}
 		std::vector<char> src_string(reinterpret_cast<const char*>(src.c_str()), reinterpret_cast<const char*>(src.c_str()) + src.length() + 1);
 		std::vector<char> dst_string(src_string.size() * 8); // large enough
-		char * inbuf = &src_string[0];
+		char * inbuf = src_string.data();
 		size_t inbytesleft = src_string.size();
-		char * outbuf = &dst_string[0];
+		char * outbuf = dst_string.data();
 		size_t outbytesleft = dst_string.size();
 		while(iconv(conv, &inbuf, &inbytesleft, &outbuf, &outbytesleft) == static_cast<size_t>(-1))
 		{
@@ -1425,7 +1404,7 @@ Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
 		}
 		iconv_close(conv);
 		conv = iconv_t();
-		return reinterpret_cast<const typename Tdststring::value_type*>(&dst_string[0]);
+		return reinterpret_cast<const typename Tdststring::value_type*>(dst_string.data());
 	#else
 		return EncodeImpl<Tdststring>(to, DecodeImpl(from, src));
 	#endif
@@ -1436,7 +1415,6 @@ Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
 
 
 bool IsUTF8(const std::string &str)
-//---------------------------------
 {
 	return (str == String::EncodeImpl<std::string>(mpt::CharsetUTF8, String::DecodeImpl<std::string>(mpt::CharsetUTF8, str)));
 }
@@ -1667,12 +1645,18 @@ int CompareNoCaseAscii(const std::string &a, const std::string &b)
 mpt::ustring ToLowerCase(const mpt::ustring &s)
 {
 	#if defined(_MFC_VER)
-		CStringW tmp = mpt::ToCStringW(s);
-		tmp.MakeLower();
-		return mpt::ToUnicode(tmp);
+		#if defined(UNICODE)
+			CString tmp = mpt::ToCString(s);
+			tmp.MakeLower();
+			return mpt::ToUnicode(tmp);
+		#else // !UNICODE
+			CStringW tmp = mpt::ToCStringW(s);
+			tmp.MakeLower();
+			return mpt::ToUnicode(tmp);
+		#endif // UNICODE
 	#else // !_MFC_VER
 		std::wstring ws = mpt::ToWide(s);
-		std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);	
+		std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);
 		return mpt::ToUnicode(ws);
 	#endif // _MFC_VER
 }
@@ -1680,12 +1664,18 @@ mpt::ustring ToLowerCase(const mpt::ustring &s)
 mpt::ustring ToUpperCase(const mpt::ustring &s)
 {
 	#if defined(_MFC_VER)
-		CStringW tmp = mpt::ToCStringW(s);
-		tmp.MakeUpper();
-		return mpt::ToUnicode(tmp);
+		#if defined(UNICODE)
+			CString tmp = mpt::ToCString(s);
+			tmp.MakeUpper();
+			return mpt::ToUnicode(tmp);
+		#else // !UNICODE
+			CStringW tmp = mpt::ToCStringW(s);
+			tmp.MakeUpper();
+			return mpt::ToUnicode(tmp);
+		#endif // UNICODE
 	#else // !_MFC_VER
 		std::wstring ws = mpt::ToWide(s);
-		std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);	
+		std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);
 		return mpt::ToUnicode(ws);
 	#endif // _MFC_VER
 }
diff --git a/common/mptString.h b/common/mptString.h
index d8d5270..157a0e4 100644
--- a/common/mptString.h
+++ b/common/mptString.h
@@ -46,7 +46,6 @@ template <> struct Traits<std::wstring> {
 // Remove whitespace at start of string
 template <typename Tstring>
 inline Tstring LTrim(Tstring str, const Tstring &whitespace = Tstring(mpt::String::Traits<Tstring>::GetDefaultWhitespace()))
-//--------------------------------------------------------------------------------------------------------------------------
 {
 	typename Tstring::size_type pos = str.find_first_not_of(whitespace);
 	if(pos != Tstring::npos)
@@ -63,7 +62,6 @@ inline Tstring LTrim(Tstring str, const Tstring &whitespace = Tstring(mpt::Strin
 // Remove whitespace at end of string
 template <typename Tstring>
 inline Tstring RTrim(Tstring str, const Tstring &whitespace = Tstring(mpt::String::Traits<Tstring>::GetDefaultWhitespace()))
-//--------------------------------------------------------------------------------------------------------------------------
 {
 	typename Tstring::size_type pos = str.find_last_not_of(whitespace);
 	if(pos != Tstring::npos)
@@ -80,7 +78,6 @@ inline Tstring RTrim(Tstring str, const Tstring &whitespace = Tstring(mpt::Strin
 // Remove whitespace at start and end of string
 template <typename Tstring>
 inline Tstring Trim(Tstring str, const Tstring &whitespace = Tstring(mpt::String::Traits<Tstring>::GetDefaultWhitespace()))
-//-------------------------------------------------------------------------------------------------------------------------
 {
 	return RTrim(LTrim(str, whitespace), whitespace);
 }
@@ -88,7 +85,6 @@ inline Tstring Trim(Tstring str, const Tstring &whitespace = Tstring(mpt::String
 
 template <typename Tstring, typename Tstring2, typename Tstring3>
 inline Tstring Replace(Tstring str, const Tstring2 &oldStr_, const Tstring3 &newStr_)
-//-----------------------------------------------------------------------------------
 {
 	std::size_t pos = 0;
 	const Tstring oldStr = oldStr_;
@@ -106,7 +102,6 @@ inline Tstring Replace(Tstring str, const Tstring2 &oldStr_, const Tstring3 &new
 
 
 static inline std::size_t strnlen(const char *str, std::size_t n)
-//---------------------------------------------------------------
 {
 #if MPT_COMPILER_MSVC
 	return ::strnlen(str, n);
@@ -127,11 +122,6 @@ static inline std::size_t strnlen(const char *str, std::size_t n)
 }
 
 
-#ifdef MODPLUG_TRACKER
-int strnicmp(const char *a, const char *b, size_t count);
-#endif // MODPLUG_TRACKER
-
-
 enum Charset {
 #if defined(MPT_ENABLE_CHARSET_LOCALE)
 	CharsetLocale, // CP_ACP on windows, current C locale otherwise
@@ -264,7 +254,7 @@ std::string ToCharset(Charset to, const CString &str);
 MPT_DEPRECATED static inline CString ToCStringW(const CString &str) { return ToCString(str); }
 MPT_DEPRECATED static inline CString ToCStringW(const std::wstring &str) { return ToCString(str); }
 MPT_DEPRECATED static inline CString ToCStringW(Charset from, const std::string &str) { return ToCString(from, str); }
-MPT_DEPRECATED static inline CString ToCStringW(Charset from, const char * str) { return ToCStringW(from, str ? std::string(str) : std::string()); }
+MPT_DEPRECATED static inline CString ToCStringW(Charset from, const char * str) { return ToCString(from, str ? std::string(str) : std::string()); }
 #else // !UNICODE
 CStringW ToCStringW(const CString &str);
 CStringW ToCStringW(const std::wstring &str);
@@ -389,7 +379,7 @@ static inline CStringW ToCStringW(const mpt::ustring &str) { return ToCStringW(T
 
 #ifdef MODPLUG_TRACKER
 
-#if defined(MPT_OS_WINDOWS)
+#if MPT_OS_WINDOWS
 
 namespace String { namespace detail
 {
@@ -416,7 +406,7 @@ namespace String { namespace detail
 		STATIC_ASSERT(size > 0);
 		MemsetZero(buf);
 		std::string encoded = mpt::ToCharset(charset, str);
-		std::copy(encoded.data(), std::min(encoded.length(), size - 1), buf);
+		std::copy(encoded.data(), encoded.data() + std::min(encoded.length(), size - 1), buf);
 		buf[size - 1] = '\0';
 		return (encoded.length() <= size - 1);
 	}
@@ -427,7 +417,7 @@ namespace String { namespace detail
 		STATIC_ASSERT(size > 0);
 		MemsetZero(buf);
 		std::wstring encoded = mpt::ToWide(str);
-		std::copy(encoded.data(), std::min(encoded.length(), size - 1), buf);
+		std::copy(encoded.data(), encoded.data() + std::min(encoded.length(), size - 1), buf);
 		buf[size - 1] = L'\0';
 		return (encoded.length() <= size - 1);
 	}
@@ -480,21 +470,47 @@ inline bool ToTcharBuf(Tchar (&buf)[size], const mpt::ustring &str)
 	return mpt::String::detail::StringToBuffer<mpt::CharsetLocale>(buf, str);
 }
 
-// mpt::FromTcharStr
+// mpt::ToTcharStr
 // Converts mpt::ustring to std::basic_stringy<TCHAR>,
 // which is usable in both ANSI and UNICODE builds.
 // Useful when going through CString is not appropriate.
 
-template <typename Tchar> std::basic_string<Tchar> ToTcharStr(const mpt::ustring &str);
-template <> inline std::string ToTcharStr<char>(const mpt::ustring &str)
+template <typename Tchar> std::basic_string<Tchar> ToTcharStrImpl(const mpt::ustring &str);
+template <> inline std::string ToTcharStrImpl<char>(const mpt::ustring &str)
 {
 	return mpt::ToCharset(mpt::CharsetLocale, str);
 }
-template <> inline std::wstring ToTcharStr<wchar_t>(const mpt::ustring &str)
+template <> inline std::wstring ToTcharStrImpl<wchar_t>(const mpt::ustring &str)
 {
 	return mpt::ToWide(str);
 }
 
+inline std::basic_string<TCHAR> ToTcharStr(const mpt::ustring &str)
+{
+	return ToTcharStrImpl<TCHAR>(str);
+}
+
+#if defined(_MFC_VER)
+
+template <std::size_t size>
+inline CString CStringFromBuffer(const TCHAR (&buf)[size])
+{
+	MPT_STATIC_ASSERT(size > 0);
+	std::size_t len = std::find(buf, buf + size, _T('\0')) - buf; // terminate at \0
+	return CString(buf, len);
+}
+
+template <std::size_t size>
+inline void CopyCStringToBuffer(TCHAR (&buf)[size], const CString &str)
+{
+	MPT_STATIC_ASSERT(size > 0);
+	MemsetZero(buf);
+	std::copy(str.GetString(), str.GetString() + std::min(static_cast<std::size_t>(str.GetLength()), size - 1), buf);
+	buf[size - 1] = _T('\0');
+}
+
+#endif // _MFC_VER
+
 #endif // MPT_OS_WINDOWS
 
 #endif // MODPLUG_TRACKER
@@ -565,9 +581,7 @@ public:
 
 	// unicode
 	BasicAnyString(const mpt::ustring &str) : mpt::ustring(str) { }
-#if MPT_COMPILER_HAS_RVALUE_REF
 	BasicAnyString(mpt::ustring &&str) : mpt::ustring(std::move(str)) { }
-#endif
 #if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_CONVERT
 	BasicAnyString(const std::wstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
 #endif
@@ -585,9 +599,7 @@ public:
 
 	// fallback for custom string types
 	template <typename Tstring> BasicAnyString(const Tstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
-#if MPT_COMPILER_HAS_RVALUE_REF
 	template <typename Tstring> BasicAnyString(Tstring &&str) : mpt::ustring(mpt::ToUnicode(std::forward<Tstring>(str))) { }
-#endif
 
 };
 
@@ -599,9 +611,7 @@ public:
 
 	// unicode
 	AnyUnicodeString(const mpt::ustring &str) : mpt::ustring(str) { }
-#if MPT_COMPILER_HAS_RVALUE_REF
 	AnyUnicodeString(mpt::ustring &&str) : mpt::ustring(std::move(str)) { }
-#endif
 #if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_CONVERT
 	AnyUnicodeString(const std::wstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
 #endif
@@ -619,9 +629,7 @@ public:
 
 	// fallback for custom string types
 	template <typename Tstring> AnyUnicodeString(const Tstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
-#if MPT_COMPILER_HAS_RVALUE_REF
 	template <typename Tstring> AnyUnicodeString(Tstring &&str) : mpt::ustring(mpt::ToUnicode(std::forward<Tstring>(str))) { }
-#endif
 
 };
 
diff --git a/common/mptStringFormat.cpp b/common/mptStringFormat.cpp
index 14d15e0..cbf21e0 100644
--- a/common/mptStringFormat.cpp
+++ b/common/mptStringFormat.cpp
@@ -76,6 +76,52 @@ std::string ToString(const float & x) { return ToStringHelper(x); }
 std::string ToString(const double & x) { return ToStringHelper(x); }
 std::string ToString(const long double & x) { return ToStringHelper(x); }
 
+mpt::ustring ToUString(const std::string & x) { return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, x); }
+mpt::ustring ToUString(const char * const & x) { return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, x); }
+mpt::ustring ToUString(const char & x) { return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, std::string(1, x)); }
+#if MPT_WSTRING_FORMAT
+#if MPT_USTRING_MODE_UTF8
+mpt::ustring ToUString(const std::wstring & x) { return mpt::ToUnicode(x); }
+#endif
+mpt::ustring ToUString(const wchar_t * const & x) { return mpt::ToUnicode(x); }
+mpt::ustring ToUString(const wchar_t & x) { return mpt::ToUnicode(std::wstring(1, x)); }
+#endif
+#if defined(_MFC_VER)
+mpt::ustring ToUString(const CString & x)  { return mpt::ToUnicode(x); }
+#endif
+#if MPT_USTRING_MODE_WIDE
+mpt::ustring ToUString(const bool & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const signed char & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const unsigned char & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const signed short & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const unsigned short & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const signed int & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const unsigned int & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const signed long & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const unsigned long & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const signed long long & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const unsigned long long & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const float & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const double & x) { return ToWStringHelper(x); }
+mpt::ustring ToUString(const long double & x) { return ToWStringHelper(x); }
+#endif
+#if MPT_USTRING_MODE_UTF8
+mpt::ustring ToUString(const bool & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const signed char & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const unsigned char & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const signed short & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const unsigned short & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const signed int & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const unsigned int & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const signed long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const unsigned long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const signed long long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const unsigned long long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const float & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const double & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+mpt::ustring ToUString(const long double & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
+#endif
+
 #if MPT_WSTRING_FORMAT
 std::wstring ToWString(const std::string & x) { return mpt::ToWide(mpt::CharsetLocaleOrUTF8, x); }
 std::wstring ToWString(const char * const & x) { return mpt::ToWide(mpt::CharsetLocaleOrUTF8, x); }
@@ -104,7 +150,7 @@ std::wstring ToWString(const long double & x) { return ToWStringHelper(x); }
 
 
 template<typename Tostream>
-inline void ApplyFormat(Tostream & o, const Format & format)
+inline void ApplyFormat(Tostream & o, const FormatSpec & format)
 {
 	FormatFlags f = format.GetFlags();
 	std::size_t width = format.GetWidth();
@@ -132,7 +178,7 @@ inline void ApplyFormat(Tostream & o, const Format & format)
 
 
 template<typename T>
-inline std::string FormatValHelper(const T & x, const Format & f)
+inline std::string FormatValHelper(const T & x, const FormatSpec & f)
 {
 	std::ostringstream o;
 	o.imbue(std::locale::classic());
@@ -143,7 +189,7 @@ inline std::string FormatValHelper(const T & x, const Format & f)
 
 #if MPT_WSTRING_FORMAT
 template<typename T>
-inline std::wstring FormatValWHelper(const T & x, const Format & f)
+inline std::wstring FormatValWHelper(const T & x, const FormatSpec & f)
 {
 	std::wostringstream o;
 	o.imbue(std::locale::classic());
@@ -155,7 +201,7 @@ inline std::wstring FormatValWHelper(const T & x, const Format & f)
 
 // Parses a useful subset of standard sprintf syntax for specifying floating point formatting.
 template<typename Tchar>
-static inline Format ParseFormatStringFloat(const Tchar * str)
+static inline FormatSpec ParseFormatStringFloat(const Tchar * str)
 {
 	MPT_ASSERT(str);
 	FormatFlags f = FormatFlags();
@@ -163,7 +209,7 @@ static inline Format ParseFormatStringFloat(const Tchar * str)
 	int precision = -1;
 	if(!str)
 	{
-		return Format();
+		return FormatSpec();
 	}
 	const Tchar * p = str;
 	while(*p && *p != Tchar('%'))
@@ -213,65 +259,65 @@ static inline Format ParseFormatStringFloat(const Tchar * str)
 		if(*p == Tchar('E')) f |= mpt::fmt_base::NotaSci | mpt::fmt_base::CaseUpp;
 		++p;
 	}
-	return Format().SetFlags(f).SetWidth(width).SetPrecision(precision);
+	return FormatSpec().SetFlags(f).SetWidth(width).SetPrecision(precision);
 }
 
-Format & Format::ParsePrintf(const char * format)
+FormatSpec & FormatSpec::ParsePrintf(const char * format)
 {
 	*this = ParseFormatStringFloat(format);
 	return *this;
 }
-Format & Format::ParsePrintf(const wchar_t * format)
+FormatSpec & FormatSpec::ParsePrintf(const wchar_t * format)
 {
 	*this = ParseFormatStringFloat(format);
 	return *this;
 }
-Format & Format::ParsePrintf(const std::string & format)
+FormatSpec & FormatSpec::ParsePrintf(const std::string & format)
 {
 	*this = ParseFormatStringFloat(format.c_str());
 	return *this;
 }
-Format & Format::ParsePrintf(const std::wstring & format)
+FormatSpec & FormatSpec::ParsePrintf(const std::wstring & format)
 {
 	*this = ParseFormatStringFloat(format.c_str());
 	return *this;
 }
 
 
-std::string FormatVal(const char & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const wchar_t & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const bool & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const signed char & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const unsigned char & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const signed short & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const unsigned short & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const signed int & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const unsigned int & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const signed long & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const unsigned long & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const signed long long & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const unsigned long long & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const float & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const double & x, const Format & f) { return FormatValHelper(x, f); }
-std::string FormatVal(const long double & x, const Format & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const char & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const wchar_t & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const bool & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const signed char & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const unsigned char & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const signed short & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const unsigned short & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const signed int & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const unsigned int & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const signed long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const unsigned long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const signed long long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const unsigned long long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const float & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const double & x, const FormatSpec & f) { return FormatValHelper(x, f); }
+std::string FormatVal(const long double & x, const FormatSpec & f) { return FormatValHelper(x, f); }
 
 #if MPT_WSTRING_FORMAT
-std::wstring FormatValW(const char & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const wchar_t & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const bool & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const signed char & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const unsigned char & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const signed short & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const unsigned short & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const signed int & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const unsigned int & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const signed long & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const unsigned long & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const signed long long & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const unsigned long long & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const float & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const double & x, const Format & f) { return FormatValWHelper(x, f); }
-std::wstring FormatValW(const long double & x, const Format & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const char & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const bool & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const signed char & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const unsigned char & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const signed short & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const unsigned short & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const signed int & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const unsigned int & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const signed long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const unsigned long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const signed long long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const float & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const double & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
+std::wstring FormatValW(const long double & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
 #endif
 
 
@@ -344,6 +390,7 @@ CString PrintImplTemplate<CString>(const CString & format
 {
 	CString result;
 	const int len = format.GetLength();
+	result.Preallocate(len);
 	for(int pos = 0; pos != len; ++pos)
 	{
 		CString::XCHAR c = format[pos];
@@ -368,10 +415,10 @@ CString PrintImplTemplate<CString>(const CString & format
 				continue;
 			} else if(c != _T('%'))
 			{
-				result += CString(_T('%'));
+				result.AppendChar(_T('%'));
 			}
 		}
-		result += CString(c);
+		result.AppendChar(c);
 	}
 	return result;
 }
diff --git a/common/mptStringFormat.h b/common/mptStringFormat.h
index 84b0175..e45e0cc 100644
--- a/common/mptStringFormat.h
+++ b/common/mptStringFormat.h
@@ -19,9 +19,9 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 // The following section demands a rationale.
-//  1. ToString(), ToWString() an ToUString() mimic the semantics of c++11 std::to_string() and std::to_wstring().
+//  1. mpt::fmt::val(), mpt::wfmt::val() and mpt::ufmt::val() mimic the semantics of c++11 std::to_string() and std::to_wstring().
 //     There is an important difference though. The c++11 versions are specified in terms of sprintf formatting which in turn
-//     depend on the current C locale. This renders these functions unusable in a library context because the current
+//     depends on the current C locale. This renders these functions unusable in a library context because the current
 //     C locale is set by the library-using application and could be anything. There is no way a library can get reliable semantics
 //     out of these functions. It is thus better to just avoid them.
 //     ToString() and ToWString() are based on iostream internally, but the the locale of the stream is forced to std::locale::classic(),
@@ -35,7 +35,7 @@ OPENMPT_NAMESPACE_BEGIN
 //     the same way as '%nd' would do. Appending a '0' to the function name causes zero-filling as print-like '%0nd' would do. Spelling 'HEX'
 //     in upper-case generates upper-case hex digits. If these are not known at compile-time, a more verbose FormatVal(int, format) can be
 //     used.
-//  3. mpt::String::Print(format, ...) provides simplified and type-safe message and localization string formatting.
+//  3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting.
 //     The only specifier allowed is '%' followed by a single digit n. It references to n-th parameter after the format string (1-based).
 //     This mimics the behaviour of QString::arg() in QT4/5 or MFC AfxFormatString2(). C printf-like functions offer similar functionality
 //     with a '%n$TYPE' syntax. In .NET, the syntax is '{n}'. This is useful to support localization strings that can change the parameter
@@ -44,7 +44,7 @@ OPENMPT_NAMESPACE_BEGIN
 //  4. Every function is available for std::string, std::wstring and mpt::ustring. std::string makes no assumption about the encoding, which
 //     basically means, it should work for any 7-bit or 8-bit encoding, including for example ASCII, UTF8 or the current locale encoding.
 //     std::string        std::wstring       mpt::ustring                           CString
-//     mpt::ToString      mpt::ToWString     mpt::ToUString                         mpt::ToStringT<Cstring>
+//     mpt::fmt::val      mpt::wfmt::val     mpt::ufmt::val                         mpt::tfmt::val
 //     mpt::FormatVal     mpt::FormatValW    mpt::FormatValTFunctor<mpt::ustring>() mpt::FormatValTFunctor<Cstring>()
 //     mpt::fmt           mpt::wfmt          mpt::ufmt                              mpt::tfmt
 //     mpt::format        mpt::format        mpt::format                            mpt::format
@@ -55,7 +55,7 @@ OPENMPT_NAMESPACE_BEGIN
 //      - Faster compile times because <sstream> and <locale> (2 very complex headers) are not included everywhere.
 //     Disadvantages:
 //      - Slightly more c++ code is required for delegating work.
-//      - As the header does not use iostreams, custom types need to overload mpt::ToString, mpt::ToWstring and mpt::ToUString instead of
+//      - As the header does not use iostreams, custom types need to overload mpt::String, mpt::ToWstring and mpt::UString instead of
 //        iostream operator << to allow for custom type formatting.
 //      - std::string, std::wstring and mpt::ustring are returned from somewhat deep cascades of helper functions. Where possible, code is
 //        written in such a way that return-value-optimization (RVO) or named-return-value-optimization (NRVO) should be able to eliminate
@@ -66,9 +66,12 @@ namespace mpt
 {
 
 // ToString() converts various built-in types to a well-defined, locale-independent string representation.
-// This is also used as a type-tunnel pattern for mpt::String::Print.
+// This is also used as a type-tunnel pattern for mpt::format.
 // Custom types that need to be converted to strings are encouraged to overload ToString() and ToWString().
 
+// fallback to member function ToString()
+template <typename T> auto ToString(const T & x) -> decltype(x.ToString()) { return x.ToString(); }
+
 static inline std::string ToString(const std::string & x) { return x; }
 static inline std::string ToString(const char * const & x) { return x; }
 MPT_DEPRECATED static inline std::string ToString(const char & x) { return std::string(1, x); } // deprecated to catch potential API mis-use, use std::string(1, x) instead
@@ -98,6 +101,38 @@ std::string ToString(const float & x);
 std::string ToString(const double & x);
 std::string ToString(const long double & x);
 
+// fallback to member function ToUString()
+template <typename T> auto ToUString(const T & x) -> decltype(x.ToUString()) { return x.ToUString(); }
+
+static inline mpt::ustring ToUString(const mpt::ustring & x) { return x; }
+MPT_DEPRECATED mpt::ustring ToUString(const std::string & x); // Unknown encoding.
+MPT_DEPRECATED mpt::ustring ToUString(const char * const & x); // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case.
+MPT_DEPRECATED mpt::ustring ToUString(const char & x); // deprecated to catch potential API mis-use, use std::string(1, x) instead
+#if MPT_WSTRING_FORMAT
+#if MPT_USTRING_MODE_UTF8
+mpt::ustring ToUString(const std::wstring & x);
+#endif
+mpt::ustring ToUString(const wchar_t * const & x);
+MPT_DEPRECATED mpt::ustring ToUString(const wchar_t & x); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
+#endif
+#if defined(_MFC_VER)
+mpt::ustring ToUString(const CString & x);
+#endif
+mpt::ustring ToUString(const bool & x);
+mpt::ustring ToUString(const signed char & x);
+mpt::ustring ToUString(const unsigned char & x);
+mpt::ustring ToUString(const signed short & x);
+mpt::ustring ToUString(const unsigned short & x);
+mpt::ustring ToUString(const signed int & x);
+mpt::ustring ToUString(const unsigned int & x);
+mpt::ustring ToUString(const signed long & x);
+mpt::ustring ToUString(const unsigned long & x);
+mpt::ustring ToUString(const signed long long & x);
+mpt::ustring ToUString(const unsigned long long & x);
+mpt::ustring ToUString(const float & x);
+mpt::ustring ToUString(const double & x);
+mpt::ustring ToUString(const long double & x);
+
 #if MPT_WSTRING_FORMAT
 MPT_DEPRECATED std::wstring ToWString(const std::string & x); // Unknown encoding.
 MPT_DEPRECATED std::wstring ToWString(const char * const & x); // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case.
@@ -127,35 +162,11 @@ std::wstring ToWString(const double & x);
 std::wstring ToWString(const long double & x);
 #endif
 
-#if MPT_USTRING_MODE_UTF8
-template<typename T>
-mpt::ustring ToUString(const T & x)
-{
-	return mpt::ToUnicode(mpt::CharsetUTF8, ToString(x));
-}
-template<>
-inline mpt::ustring ToUString<mpt::ustring>(const mpt::ustring & x)
-{
-	return x;
-}
-#if MPT_WSTRING_FORMAT
-static inline mpt::ustring ToUString(const std::wstring & x) { return mpt::ToUnicode(x); }
-#endif
-#else
-template<typename T>
-mpt::ustring ToUString(const T & x)
-{
-	return ToWString(x);
-}
-#endif
-
 template <typename Tstring> struct ToStringTFunctor {};
 template <> struct ToStringTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x) { return ToString(x); } };
-#if MPT_WSTRING_FORMAT
-template <> struct ToStringTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x) { return ToWString(x); } };
-#endif
-#if MPT_USTRING_MODE_UTF8
 template <> struct ToStringTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x) { return ToUString(x); } };
+#if MPT_WSTRING_FORMAT && MPT_USTRING_MODE_UTF8
+template <> struct ToStringTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x) { return ToWString(x); } };
 #endif
 #if defined(_MFC_VER)
 #ifdef UNICODE
@@ -191,122 +202,124 @@ typedef unsigned int FormatFlags;
 
 STATIC_ASSERT(sizeof(FormatFlags) >= sizeof(fmt_base::FormatFlagsEnum));
 
-class Format;
-
-MPT_DEPRECATED std::string FormatVal(const char & x, const Format & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
-MPT_DEPRECATED std::string FormatVal(const wchar_t & x, const Format & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
-std::string FormatVal(const bool & x, const Format & f);
-std::string FormatVal(const signed char & x, const Format & f);
-std::string FormatVal(const unsigned char & x, const Format & f);
-std::string FormatVal(const signed short & x, const Format & f);
-std::string FormatVal(const unsigned short & x, const Format & f);
-std::string FormatVal(const signed int & x, const Format & f);
-std::string FormatVal(const unsigned int & x, const Format & f);
-std::string FormatVal(const signed long & x, const Format & f);
-std::string FormatVal(const unsigned long & x, const Format & f);
-std::string FormatVal(const signed long long & x, const Format & f);
-std::string FormatVal(const unsigned long long & x, const Format & f);
-std::string FormatVal(const float & x, const Format & f);
-std::string FormatVal(const double & x, const Format & f);
-std::string FormatVal(const long double & x, const Format & f);
+class FormatSpec;
+
+MPT_DEPRECATED std::string FormatVal(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
+MPT_DEPRECATED std::string FormatVal(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
+std::string FormatVal(const bool & x, const FormatSpec & f);
+std::string FormatVal(const signed char & x, const FormatSpec & f);
+std::string FormatVal(const unsigned char & x, const FormatSpec & f);
+std::string FormatVal(const signed short & x, const FormatSpec & f);
+std::string FormatVal(const unsigned short & x, const FormatSpec & f);
+std::string FormatVal(const signed int & x, const FormatSpec & f);
+std::string FormatVal(const unsigned int & x, const FormatSpec & f);
+std::string FormatVal(const signed long & x, const FormatSpec & f);
+std::string FormatVal(const unsigned long & x, const FormatSpec & f);
+std::string FormatVal(const signed long long & x, const FormatSpec & f);
+std::string FormatVal(const unsigned long long & x, const FormatSpec & f);
+std::string FormatVal(const float & x, const FormatSpec & f);
+std::string FormatVal(const double & x, const FormatSpec & f);
+std::string FormatVal(const long double & x, const FormatSpec & f);
 
 #if MPT_WSTRING_FORMAT
-MPT_DEPRECATED std::wstring FormatValW(const char & x, const Format & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
-MPT_DEPRECATED std::wstring FormatValW(const wchar_t & x, const Format & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
-std::wstring FormatValW(const bool & x, const Format & f);
-std::wstring FormatValW(const signed char & x, const Format & f);
-std::wstring FormatValW(const unsigned char & x, const Format & f);
-std::wstring FormatValW(const signed short & x, const Format & f);
-std::wstring FormatValW(const unsigned short & x, const Format & f);
-std::wstring FormatValW(const signed int & x, const Format & f);
-std::wstring FormatValW(const unsigned int & x, const Format & f);
-std::wstring FormatValW(const signed long & x, const Format & f);
-std::wstring FormatValW(const unsigned long & x, const Format & f);
-std::wstring FormatValW(const signed long long & x, const Format & f);
-std::wstring FormatValW(const unsigned long long & x, const Format & f);
-std::wstring FormatValW(const float & x, const Format & f);
-std::wstring FormatValW(const double & x, const Format & f);
-std::wstring FormatValW(const long double & x, const Format & f);
+MPT_DEPRECATED std::wstring FormatValW(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
+MPT_DEPRECATED std::wstring FormatValW(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
+std::wstring FormatValW(const bool & x, const FormatSpec & f);
+std::wstring FormatValW(const signed char & x, const FormatSpec & f);
+std::wstring FormatValW(const unsigned char & x, const FormatSpec & f);
+std::wstring FormatValW(const signed short & x, const FormatSpec & f);
+std::wstring FormatValW(const unsigned short & x, const FormatSpec & f);
+std::wstring FormatValW(const signed int & x, const FormatSpec & f);
+std::wstring FormatValW(const unsigned int & x, const FormatSpec & f);
+std::wstring FormatValW(const signed long & x, const FormatSpec & f);
+std::wstring FormatValW(const unsigned long & x, const FormatSpec & f);
+std::wstring FormatValW(const signed long long & x, const FormatSpec & f);
+std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f);
+std::wstring FormatValW(const float & x, const FormatSpec & f);
+std::wstring FormatValW(const double & x, const FormatSpec & f);
+std::wstring FormatValW(const long double & x, const FormatSpec & f);
 #endif
 
 template <typename Tstring> struct FormatValTFunctor {};
-template <> struct FormatValTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x, const Format & f) { return FormatVal(x, f); } };
-template <> struct FormatValTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x, const Format & f) { return FormatValW(x, f); } };
+template <> struct FormatValTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x, const FormatSpec & f) { return FormatVal(x, f); } };
+#if MPT_WSTRING_FORMAT
+template <> struct FormatValTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x, const FormatSpec & f) { return FormatValW(x, f); } };
+#endif
 #if MPT_USTRING_MODE_UTF8
-template <> struct FormatValTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x, const Format & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatVal(x, f)); } };
+template <> struct FormatValTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatVal(x, f)); } };
 #endif
 #if defined(_MFC_VER)
 #ifdef UNICODE
-template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const Format & f) { return mpt::ToCString(FormatValW(x, f)); } };
+template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } };
 #else
-template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const Format & f) { return mpt::ToCString(mpt::CharsetLocale, FormatVal(x, f)); } };
+template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(mpt::CharsetLocale, FormatVal(x, f)); } };
 #endif
 #endif
 
 
-class Format
+class FormatSpec
 {
 private:
 	FormatFlags flags;
 	std::size_t width;
 	int precision;
 public:
-	Format() : flags(0), width(0), precision(-1) {}
+	FormatSpec() : flags(0), width(0), precision(-1) {}
 	FormatFlags GetFlags() const { return flags; }
 	std::size_t GetWidth() const { return width; }
 	int GetPrecision() const { return precision; }
-	Format & SetFlags(FormatFlags f) { flags = f; return *this; }
-	Format & SetWidth(std::size_t w) { width = w; return *this; }
-	Format & SetPrecision(int p) { precision = p; return *this; }
+	FormatSpec & SetFlags(FormatFlags f) { flags = f; return *this; }
+	FormatSpec & SetWidth(std::size_t w) { width = w; return *this; }
+	FormatSpec & SetPrecision(int p) { precision = p; return *this; }
 public:
 	// short-hand construction
-	explicit Format(FormatFlags f, std::size_t w = 0, int p = -1) : flags(f), width(w), precision(p) {}
-	explicit Format(const char * format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
-	explicit Format(const wchar_t * format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
-	explicit Format(const std::string & format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
-	explicit Format(const std::wstring & format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
+	explicit FormatSpec(FormatFlags f, std::size_t w = 0, int p = -1) : flags(f), width(w), precision(p) {}
+	explicit FormatSpec(const char * format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
+	explicit FormatSpec(const wchar_t * format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
+	explicit FormatSpec(const std::string & format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
+	explicit FormatSpec(const std::wstring & format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
 public:
 	// only for floating point formats
-	Format & ParsePrintf(const char * format);
-	Format & ParsePrintf(const wchar_t * format);
-	Format & ParsePrintf(const std::string & format);
-	Format & ParsePrintf(const std::wstring & format);
+	FormatSpec & ParsePrintf(const char * format);
+	FormatSpec & ParsePrintf(const wchar_t * format);
+	FormatSpec & ParsePrintf(const std::string & format);
+	FormatSpec & ParsePrintf(const std::wstring & format);
 public:
-	Format & BaseDec() { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseDec; return *this; }
-	Format & BaseHex() { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseHex; return *this; }
-	Format & CaseLow() { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseLow; return *this; }
-	Format & CaseUpp() { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseUpp; return *this; }
-	Format & FillOff() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillOff; return *this; }
-	Format & FillSpc() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillSpc; return *this; }
-	Format & FillNul() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillNul; return *this; }
-	Format & NotaNrm() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaNrm; return *this; }
-	Format & NotaFix() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaFix; return *this; }
-	Format & NotaSci() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaSci; return *this; }
-	Format & Width(std::size_t w) { width = w; return *this; }
-	Format & Prec(int p) { precision = p; return *this; }
+	FormatSpec & BaseDec() { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseDec; return *this; }
+	FormatSpec & BaseHex() { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseHex; return *this; }
+	FormatSpec & CaseLow() { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseLow; return *this; }
+	FormatSpec & CaseUpp() { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseUpp; return *this; }
+	FormatSpec & FillOff() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillOff; return *this; }
+	FormatSpec & FillSpc() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillSpc; return *this; }
+	FormatSpec & FillNul() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillNul; return *this; }
+	FormatSpec & NotaNrm() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaNrm; return *this; }
+	FormatSpec & NotaFix() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaFix; return *this; }
+	FormatSpec & NotaSci() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaSci; return *this; }
+	FormatSpec & Width(std::size_t w) { width = w; return *this; }
+	FormatSpec & Prec(int p) { precision = p; return *this; }
 public:
-	Format & Dec() { return BaseDec(); }
-	Format & Hex() { return BaseHex(); }
-	Format & Low() { return CaseLow(); }
-	Format & Upp() { return CaseUpp(); }
-	Format & Off() { return FillOff(); }
-	Format & Spc() { return FillSpc(); }
-	Format & Nul() { return FillNul(); }
-	Format & Nrm() { return NotaNrm(); }
-	Format & Fix() { return NotaFix(); }
-	Format & Sci() { return NotaSci(); }
+	FormatSpec & Dec() { return BaseDec(); }
+	FormatSpec & Hex() { return BaseHex(); }
+	FormatSpec & Low() { return CaseLow(); }
+	FormatSpec & Upp() { return CaseUpp(); }
+	FormatSpec & Off() { return FillOff(); }
+	FormatSpec & Spc() { return FillSpc(); }
+	FormatSpec & Nul() { return FillNul(); }
+	FormatSpec & Nrm() { return NotaNrm(); }
+	FormatSpec & Fix() { return NotaFix(); }
+	FormatSpec & Sci() { return NotaSci(); }
 public:
-	Format & Decimal() { return BaseDec(); }
-	Format & Hexadecimal() { return BaseHex(); }
-	Format & Lower() { return CaseLow(); }
-	Format & Upper() { return CaseUpp(); }
-	Format & FillNone() { return FillOff(); }
-	Format & FillSpace() { return FillSpc(); }
-	Format & FillZero() { return FillNul(); }
-	Format & FloatNormal() { return NotaNrm(); }
-	Format & FloatFixed() { return NotaFix(); }
-	Format & FloatScientific() { return NotaSci(); }
-	Format & Precision(int p) { return Prec(p); }
+	FormatSpec & Decimal() { return BaseDec(); }
+	FormatSpec & Hexadecimal() { return BaseHex(); }
+	FormatSpec & Lower() { return CaseLow(); }
+	FormatSpec & Upper() { return CaseUpp(); }
+	FormatSpec & FillNone() { return FillOff(); }
+	FormatSpec & FillSpace() { return FillSpc(); }
+	FormatSpec & FillZero() { return FillNul(); }
+	FormatSpec & FloatNormal() { return NotaNrm(); }
+	FormatSpec & FloatFixed() { return NotaFix(); }
+	FormatSpec & FloatScientific() { return NotaSci(); }
+	FormatSpec & Precision(int p) { return Prec(p); }
 	template<typename Tstring, typename T>
 	inline Tstring ToStringT(const T & x) const
 	{
@@ -332,111 +345,109 @@ struct fmtT : fmt_base
 {
 
 template<typename T>
+static inline Tstring val(const T& x)
+{
+	return ToStringTFunctor<Tstring>()(x);
+}
+
+template<typename T>
 static inline Tstring dec(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseDec().FillOff());
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff());
 }
 template<int width, typename T>
 static inline Tstring dec(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseDec().FillSpc().Width(width));
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillSpc().Width(width));
 }
 template<int width, typename T>
 static inline Tstring dec0(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseDec().FillNul().Width(width));
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width));
 }
 
 template<typename T>
 static inline Tstring hex(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseHex().CaseLow().FillOff());
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff());
 }
 template<typename T>
 static inline Tstring HEX(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseHex().CaseUpp().FillOff());
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff());
 }
 template<int width, typename T>
 static inline Tstring hex(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseHex().CaseLow().FillSpc().Width(width));
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillSpc().Width(width));
 }
 template<int width, typename T>
 static inline Tstring HEX(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseHex().CaseUpp().FillSpc().Width(width));
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillSpc().Width(width));
 }
 template<int width, typename T>
 static inline Tstring hex0(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseHex().CaseLow().FillNul().Width(width));
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width));
 }
 template<int width, typename T>
 static inline Tstring HEX0(const T& x)
 {
 	STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-	return FormatValTFunctor<Tstring>()(x, Format().BaseHex().CaseUpp().FillNul().Width(width));
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width));
 }
 
 template<typename T>
 static inline Tstring flt(const T& x, std::size_t width = 0, int precision = -1)
 {
-	#if MPT_COMPILER_HAS_TYPE_TRAITS
-		STATIC_ASSERT(std::is_floating_point<T>::value);
-	#endif
+	STATIC_ASSERT(std::is_floating_point<T>::value);
 	if(width == 0)
 	{
-		return FormatValTFunctor<Tstring>()(x, Format().NotaNrm().FillOff().Precision(precision));
+		return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillOff().Precision(precision));
 	} else
 	{
-		return FormatValTFunctor<Tstring>()(x, Format().NotaNrm().FillSpc().Width(width).Precision(precision));
+		return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillSpc().Width(width).Precision(precision));
 	}
 }
 template<typename T>
 static inline Tstring fix(const T& x, std::size_t width = 0, int precision = -1)
 {
-	#if MPT_COMPILER_HAS_TYPE_TRAITS
-		STATIC_ASSERT(std::is_floating_point<T>::value);
-	#endif
+	STATIC_ASSERT(std::is_floating_point<T>::value);
 	if(width == 0)
 	{
-		return FormatValTFunctor<Tstring>()(x, Format().NotaFix().FillOff().Precision(precision));
+		return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillOff().Precision(precision));
 	} else
 	{
-		return FormatValTFunctor<Tstring>()(x, Format().NotaFix().FillSpc().Width(width).Precision(precision));
+		return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillSpc().Width(width).Precision(precision));
 	}
 }
 template<typename T>
 static inline Tstring sci(const T& x, std::size_t width = 0, int precision = -1)
 {
-	#if MPT_COMPILER_HAS_TYPE_TRAITS
-		STATIC_ASSERT(std::is_floating_point<T>::value);
-	#endif
+	STATIC_ASSERT(std::is_floating_point<T>::value);
 	if(width == 0)
 	{
-		return FormatValTFunctor<Tstring>()(x, Format().NotaSci().FillOff().Precision(precision));
+		return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillOff().Precision(precision));
 	} else
 	{
-		return FormatValTFunctor<Tstring>()(x, Format().NotaSci().FillSpc().Width(width).Precision(precision));
+		return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillSpc().Width(width).Precision(precision));
 	}
 }
 
 template <typename T, typename Tformat>
 static inline Tstring f(const Tformat & format, const T& x)
 {
-	#if MPT_COMPILER_HAS_TYPE_TRAITS
-		STATIC_ASSERT(std::is_floating_point<T>::value);
-	#endif
-	return FormatValTFunctor<Tstring>()(x, Format().ParsePrintf(format));
+	STATIC_ASSERT(std::is_floating_point<T>::value);
+	return FormatValTFunctor<Tstring>()(x, FormatSpec().ParsePrintf(format));
 }
 
 }; // struct fmtT
@@ -536,208 +547,6 @@ CString PrintImpl(const CString & format
 
 } // namespace String
 
-namespace String {
-
-template<typename Tformat
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-	);
-}
-
-template<typename Tformat
-	, typename T1
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
-	, typename T3
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-	, const T3& x3
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-		, ToStringTFunctor<Tstring>()(x3)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
-	, typename T3
-	, typename T4
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-	, const T3& x3
-	, const T4& x4
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-		, ToStringTFunctor<Tstring>()(x3)
-		, ToStringTFunctor<Tstring>()(x4)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
-	, typename T3
-	, typename T4
-	, typename T5
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-	, const T3& x3
-	, const T4& x4
-	, const T5& x5
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-		, ToStringTFunctor<Tstring>()(x3)
-		, ToStringTFunctor<Tstring>()(x4)
-		, ToStringTFunctor<Tstring>()(x5)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
-	, typename T3
-	, typename T4
-	, typename T5
-	, typename T6
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-	, const T3& x3
-	, const T4& x4
-	, const T5& x5
-	, const T6& x6
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-		, ToStringTFunctor<Tstring>()(x3)
-		, ToStringTFunctor<Tstring>()(x4)
-		, ToStringTFunctor<Tstring>()(x5)
-		, ToStringTFunctor<Tstring>()(x6)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
-	, typename T3
-	, typename T4
-	, typename T5
-	, typename T6
-	, typename T7
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-	, const T3& x3
-	, const T4& x4
-	, const T5& x5
-	, const T6& x6
-	, const T7& x7
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-		, ToStringTFunctor<Tstring>()(x3)
-		, ToStringTFunctor<Tstring>()(x4)
-		, ToStringTFunctor<Tstring>()(x5)
-		, ToStringTFunctor<Tstring>()(x6)
-		, ToStringTFunctor<Tstring>()(x7)
-	);
-}
-
-template<typename Tformat
-	, typename T1
-	, typename T2
-	, typename T3
-	, typename T4
-	, typename T5
-	, typename T6
-	, typename T7
-	, typename T8
->
-typename mpt::String::detail::to_string_type<Tformat>::type Print(const Tformat & format
-	, const T1& x1
-	, const T2& x2
-	, const T3& x3
-	, const T4& x4
-	, const T5& x5
-	, const T6& x6
-	, const T7& x7
-	, const T8& x8
-)
-{
-	typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
-	return mpt::String::detail::PrintImpl(Tstring(format)
-		, ToStringTFunctor<Tstring>()(x1)
-		, ToStringTFunctor<Tstring>()(x2)
-		, ToStringTFunctor<Tstring>()(x3)
-		, ToStringTFunctor<Tstring>()(x4)
-		, ToStringTFunctor<Tstring>()(x5)
-		, ToStringTFunctor<Tstring>()(x6)
-		, ToStringTFunctor<Tstring>()(x7)
-		, ToStringTFunctor<Tstring>()(x8)
-	);
-}
-
-} // namespace String
-
 template<typename Tformat>
 struct message_formatter
 {
@@ -933,6 +742,25 @@ message_formatter<typename mpt::String::detail::to_string_type<Tformat>::type> f
 	return message_formatter<Tstring>(Tstring(format));
 }
 
+#if MPT_WSTRING_FORMAT
+static inline message_formatter<std::wstring> wformat(const std::wstring &format)
+{
+	return message_formatter<std::wstring>(format);
+}
+#endif
+
+static inline message_formatter<mpt::ustring> uformat(const mpt::ustring &format)
+{
+	return message_formatter<mpt::ustring>(format);
+}
+
+#if defined(_MFC_VER)
+static inline message_formatter<CString> tformat(const CString &format)
+{
+	return message_formatter<CString>(format);
+}
+#endif
+
 } // namespace mpt
 
 
diff --git a/common/mptStringParse.h b/common/mptStringParse.h
index 11bc52e..62307a6 100644
--- a/common/mptStringParse.h
+++ b/common/mptStringParse.h
@@ -78,6 +78,20 @@ template<> inline double ConvertStrTo(const std::wstring &str) { return ConvertS
 template<> inline long double ConvertStrTo(const std::wstring &str) { return ConvertStrToLongDouble(str); }
 #endif
 
+#if defined(_MFC_VER)
+template<typename T>
+inline T ConvertStrTo(const CString &str)
+{
+	#if defined(UNICODE) && MPT_WSTRING_FORMAT
+		return ConvertStrTo<T>(mpt::ToWide(str));
+	#elif defined(UNICODE)
+		return ConvertStrTo<T>(mpt::ToCharset(mpt::CharsetUTF8, str));
+	#else // !UNICODE
+		return ConvertStrTo<T>(mpt::ToCharset(mpt::CharsetLocale, str));
+	#endif // UNICODE
+}
+#endif // _MFC_VER
+
 template<typename T>
 inline T ConvertStrTo(const char *str)
 {
diff --git a/common/mptThread.h b/common/mptThread.h
index 15434e5..499fc17 100644
--- a/common/mptThread.h
+++ b/common/mptThread.h
@@ -15,17 +15,15 @@
 
 #if defined(MPT_QUIRK_NO_CPP_THREAD)
 #define MPT_STD_THREAD 0
-#elif MPT_OS_ANDROID
-#define MPT_STD_THREAD 0
 #elif MPT_COMPILER_GENERIC
 #define MPT_STD_THREAD 1
-#elif MPT_MSVC_AT_LEAST(2012,0)
+#elif MPT_COMPILER_MSVC
 #define MPT_STD_THREAD 1
-#elif MPT_GCC_AT_LEAST(4,4,0) && !MPT_OS_WINDOWS
+#elif MPT_COMPILER_GCC && !MPT_OS_WINDOWS
 #define MPT_STD_THREAD 1
-#elif MPT_CLANG_AT_LEAST(3,2,0) && defined(__GLIBCXX__)
+#elif MPT_COMPILER_CLANG && defined(__GLIBCXX__)
 #define MPT_STD_THREAD 1
-#elif (MPT_OS_MACOSX_OR_IOS || MPT_OS_FREEBSD) && MPT_CLANG_AT_LEAST(3,0,0)
+#elif (MPT_OS_MACOSX_OR_IOS || MPT_OS_FREEBSD) && MPT_COMPILER_CLANG
 #define MPT_STD_THREAD 1
 #elif MPT_CLANG_AT_LEAST(3,6,0) && defined(_LIBCPP_VERSION)
 #define MPT_STD_THREAD 1
@@ -90,8 +88,8 @@ class thread
 
 private:
 
-	thread(const thread &) {} // = delete
-	thread & operator = (const thread &) { return *this; } // = delete
+	thread(const thread &) = delete;
+	thread & operator = (const thread &) = delete;
 
 private:
 
@@ -228,6 +226,37 @@ public:
 		threadHandle = nullptr;
 	}
 
+	void swap(thread & other) noexcept
+	{
+		using std::swap;
+		swap(threadHandle, other.threadHandle);
+		swap(startupDoneEvent, other.startupDoneEvent);
+		swap(functionMode, other.functionMode);
+	}
+
+	friend void swap(thread & a, thread & b) noexcept
+	{
+		a.swap(b);
+	}
+
+	thread(thread && other) noexcept
+		: threadHandle(nullptr)
+		, startupDoneEvent(nullptr)
+		, functionMode(FunctionModeNone)
+	{
+		swap(other);
+	}
+
+	thread & operator=(thread && other) noexcept
+	{
+		if(joinable())
+		{
+			std::terminate();
+		}
+		swap(other);
+		return *this;
+	}
+
 	thread()
 		: threadHandle(nullptr)
 		, startupDoneEvent(nullptr)
@@ -324,31 +353,6 @@ public:
 
 
 
-template<typename T, void (T::*Func)(void)>
-class pointer_to_member_functor {
-private:
-	T *that;
-public:
-	void operator () ()
-	{
-		(that->*Func)();
-	}
-	pointer_to_member_functor(T *that)
-		: that(that)
-	{
-		return;
-	}
-};
-
-// MPT_DELEGATE is a helper to use member functions of classes as thread entry
-//  points.
-// Implementing generic support in the mpt::thread constructor would result
-//  in horribly unreadable template code when not making use of at least some
-//  C++11 features.
-#define MPT_DELEGATE(type, func, inst) mpt::pointer_to_member_functor< type , & type :: func >( inst )
-
-
-
 #if defined(MODPLUG_TRACKER)
 
 #if MPT_OS_WINDOWS
diff --git a/common/mptTime.cpp b/common/mptTime.cpp
index a458e02..8634f5a 100644
--- a/common/mptTime.cpp
+++ b/common/mptTime.cpp
@@ -37,7 +37,6 @@ namespace ANSI
 {
 
 uint64 Now()
-//----------
 {
 	FILETIME filetime;
 	GetSystemTimeAsFileTime(&filetime);
@@ -45,7 +44,6 @@ uint64 Now()
 }
 
 mpt::ustring ToString(uint64 time100ns)
-//-------------------------------------
 {
 	static const std::size_t bufsize = 256;
 
@@ -82,27 +80,23 @@ mpt::ustring ToString(uint64 time100ns)
 #endif // MODPLUG_TRACKER
 
 Unix::Unix()
-//----------
 	: Value(0)
 {
 	return;
 }
 
 Unix::Unix(int64 unixtime)
-//------------------------
 	: Value(unixtime)
 {
 	return;
 }
 
 Unix::operator int64 () const
-//---------------------------
 {
 	return Value;
 }
 
 static int32 ToDaynum(int32 year, int32 month, int32 day)
-//-------------------------------------------------------
 {
 	month = (month + 9) % 12;
 	year = year - (month / 10);
@@ -111,7 +105,6 @@ static int32 ToDaynum(int32 year, int32 month, int32 day)
 }
 
 static void FromDaynum(int32 d, int32 & year, int32 & month, int32 & day)
-//-----------------------------------------------------------------------
 {
 	int64 g = d;
 	int64 y,ddd,mi,mm,dd;
@@ -134,7 +127,6 @@ static void FromDaynum(int32 d, int32 & year, int32 & month, int32 & day)
 }
 
 mpt::Date::Unix Unix::FromUTC(tm timeUtc)
-//---------------------------------------
 {
 	int32 daynum = ToDaynum(timeUtc.tm_year+1900, timeUtc.tm_mon+1, timeUtc.tm_mday);
 	int64 seconds = static_cast<int64>(daynum - ToDaynum(1970,1,1))*24*60*60 + timeUtc.tm_hour*60*60 + timeUtc.tm_min*60 + timeUtc.tm_sec;
@@ -142,7 +134,6 @@ mpt::Date::Unix Unix::FromUTC(tm timeUtc)
 }
 
 tm Unix::AsUTC() const 
-//--------------------
 {
 	int64 tmp = Value;
 	int64 seconds = tmp % 60; tmp /= 60;
@@ -162,7 +153,6 @@ tm Unix::AsUTC() const
 }
 
 mpt::ustring ToShortenedISO8601(tm date)
-//--------------------------------------
 {
 	// We assume date in UTC here.
 	// There are too many differences in supported format specifiers in strftime()
@@ -241,7 +231,7 @@ void MultimediaClock::SetPeriod(uint32 ms)
 	{
 		return;
 	}
-	ms = Clamp<uint32>(ms, caps.wPeriodMin, caps.wPeriodMax);
+	ms = mpt::clamp<uint32>(ms, caps.wPeriodMin, caps.wPeriodMax);
 	if(timeBeginPeriod(ms) != MMSYSERR_NOERROR)
 	{
 		return;
diff --git a/common/mptTypeTraits.h b/common/mptTypeTraits.h
index 1118a88..762f8e4 100644
--- a/common/mptTypeTraits.h
+++ b/common/mptTypeTraits.h
@@ -10,9 +10,7 @@
 
 #pragma once
 
-#if MPT_COMPILER_HAS_TYPE_TRAITS
 #include <type_traits>
-#endif // MPT_COMPILER_HAS_TYPE_TRAITS
 
 
 
@@ -24,32 +22,6 @@ namespace mpt {
 
 
 
-#if MPT_COMPILER_HAS_TYPE_TRAITS
-
-typedef std::true_type true_type;
-typedef std::false_type false_type;
-
-#else // !MPT_COMPILER_HAS_TYPE_TRAITS
-
-struct true_type {
-	typedef true_type type;
-	typedef bool value_type;
-	static const value_type value = true;
-	operator value_type () const { return value; }
-	value_type operator () () const { return value; }
-};
-
-struct false_type {
-	typedef true_type type;
-	typedef bool value_type;
-	static const value_type value = false;
-	operator value_type () const { return value; }
-	value_type operator () () const { return value; }
-};
-
-#endif // MPT_COMPILER_HAS_TYPE_TRAITS
-
-
 template <std::size_t size> struct int_of_size { };
 template <> struct int_of_size<1> { typedef int8  type; };
 template <> struct int_of_size<2> { typedef int16 type; };
@@ -71,106 +43,100 @@ template <> struct uint_of_size<7> { typedef uint64 type; };
 template <> struct uint_of_size<8> { typedef uint64 type; };
 
 
-#if MPT_COMPILER_HAS_TYPE_TRAITS
-
-using std::make_signed;
-using std::make_unsigned;
-
-#else // !MPT_COMPILER_HAS_TYPE_TRAITS
-
-// Simplified version of C++11 std::make_signed and std::make_unsigned:
-//  - we do not require a C++11 <type_traits> header
-//  - no support fr CV-qualifiers
-//  - does not fail for non-integral types
-
-template <typename T> struct make_signed { typedef typename mpt::int_of_size<sizeof(T)>::type type; };
-template <> struct make_signed<char> { typedef signed char type; };
-template <> struct make_signed<signed char> { typedef signed char type; };
-template <> struct make_signed<unsigned char> { typedef signed char type; };
-template <> struct make_signed<signed short> { typedef signed short type; };
-template <> struct make_signed<unsigned short> { typedef signed short type; };
-template <> struct make_signed<signed int> { typedef signed int type; };
-template <> struct make_signed<unsigned int> { typedef signed int type; };
-template <> struct make_signed<signed long> { typedef signed long type; };
-template <> struct make_signed<unsigned long> { typedef signed long type; };
-template <> struct make_signed<signed long long> { typedef signed long long type; };
-template <> struct make_signed<unsigned long long> { typedef signed long long type; };
-
-template <typename T> struct make_unsigned { typedef typename mpt::uint_of_size<sizeof(T)>::type type; };
-template <> struct make_unsigned<char> { typedef unsigned char type; };
-template <> struct make_unsigned<signed char> { typedef unsigned char type; };
-template <> struct make_unsigned<unsigned char> { typedef unsigned char type; };
-template <> struct make_unsigned<signed short> { typedef unsigned short type; };
-template <> struct make_unsigned<unsigned short> { typedef unsigned short type; };
-template <> struct make_unsigned<signed int> { typedef unsigned int type; };
-template <> struct make_unsigned<unsigned int> { typedef unsigned int type; };
-template <> struct make_unsigned<signed long> { typedef unsigned long type; };
-template <> struct make_unsigned<unsigned long> { typedef unsigned long type; };
-template <> struct make_unsigned<signed long long> { typedef unsigned long long type; };
-template <> struct make_unsigned<unsigned long long> { typedef unsigned long long type; };
-
-#endif // MPT_COMPILER_HAS_TYPE_TRAITS
-
-
 // Tell which types are safe for mpt::byte_cast.
 // signed char is actually not allowed to alias into an object representation,
 // which means that, if the actual type is not itself signed char but char or
 // unsigned char instead, dereferencing the signed char pointer is undefined
 // behaviour.
-template <typename T> struct is_byte_castable : public mpt::false_type { };
-template <> struct is_byte_castable<char>                : public mpt::true_type { };
-template <> struct is_byte_castable<unsigned char>       : public mpt::true_type { };
-template <> struct is_byte_castable<const char>          : public mpt::true_type { };
-template <> struct is_byte_castable<const unsigned char> : public mpt::true_type { };
+template <typename T> struct is_byte_castable : public std::false_type { };
+template <> struct is_byte_castable<char>                : public std::true_type { };
+template <> struct is_byte_castable<unsigned char>       : public std::true_type { };
+template <> struct is_byte_castable<const char>          : public std::true_type { };
+template <> struct is_byte_castable<const unsigned char> : public std::true_type { };
 
 
 // Tell which types are safe to binary write into files.
 // By default, no types are safe.
 // When a safe type gets defined,
 // also specialize this template so that IO functions will work.
-template <typename T> struct is_binary_safe : public mpt::false_type { }; 
+template <typename T> struct is_binary_safe : public std::false_type { }; 
 
 // Specialization for byte types.
-template <> struct is_binary_safe<char>  : public mpt::true_type { };
-template <> struct is_binary_safe<uint8> : public mpt::true_type { };
-template <> struct is_binary_safe<int8>  : public mpt::true_type { };
+template <> struct is_binary_safe<char>  : public std::true_type { };
+template <> struct is_binary_safe<uint8> : public std::true_type { };
+template <> struct is_binary_safe<int8>  : public std::true_type { };
+
+// Generic Specialization for arrays.
+template <typename T, std::size_t N> struct is_binary_safe<T[N]> : public is_binary_safe<T> { };
+template <typename T, std::size_t N> struct is_binary_safe<const T[N]> : public is_binary_safe<T> { };
 
 template <typename T>
 struct GetRawBytesFunctor
 {
 	inline const mpt::byte * operator () (const T & v) const
 	{
-		STATIC_ASSERT(mpt::is_binary_safe<T>::value);
+		STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
 		return reinterpret_cast<const mpt::byte *>(&v);
 	}
 	inline mpt::byte * operator () (T & v) const
 	{
-		STATIC_ASSERT(mpt::is_binary_safe<T>::value);
+		STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
 		return reinterpret_cast<mpt::byte *>(&v);
 	}
 };
 
+template <typename T, std::size_t N>
+struct GetRawBytesFunctor<T[N]>
+{
+	inline const mpt::byte * operator () (const T (&v)[N]) const
+	{
+		STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
+		return reinterpret_cast<const mpt::byte *>(v);
+	}
+	inline mpt::byte * operator () (T (&v)[N]) const
+	{
+		STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
+		return reinterpret_cast<mpt::byte *>(v);
+	}
+};
+
+template <typename T, std::size_t N>
+struct GetRawBytesFunctor<const T[N]>
+{
+	inline const mpt::byte * operator () (const T (&v)[N]) const
+	{
+		STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
+		return reinterpret_cast<const mpt::byte *>(v);
+	}
+};
+
 // In order to be able to partially specialize it,
-// GetRawBytes is implemented via a class template.
-// Do not overload or specialize GetRawBytes directly.
+// as_raw_memory is implemented via a class template.
+// Do not overload or specialize as_raw_memory directly.
 // Using a wrapper (by default just around a cast to const mpt::byte *),
 // allows for implementing raw memory access
 // via on-demand generating a cached serialized representation.
-template <typename T> inline const mpt::byte * GetRawBytes(const T & v)
+template <typename T> inline const mpt::byte * as_raw_memory(const T & v)
 {
-	STATIC_ASSERT(mpt::is_binary_safe<T>::value);
+	STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
 	return mpt::GetRawBytesFunctor<T>()(v);
 }
-template <typename T> inline mpt::byte * GetRawBytes(T & v)
+template <typename T> inline mpt::byte * as_raw_memory(T & v)
 {
-	STATIC_ASSERT(mpt::is_binary_safe<T>::value);
+	STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
 	return mpt::GetRawBytesFunctor<T>()(v);
 }
 
-
-
 } // namespace mpt
 
+#define MPT_BINARY_STRUCT(type, size) \
+	MPT_STATIC_ASSERT(sizeof( type ) == (size) ); \
+	MPT_STATIC_ASSERT(alignof( type ) == 1); \
+	MPT_STATIC_ASSERT(std::is_standard_layout< type >::value); \
+	namespace mpt { \
+		template <> struct is_binary_safe< type > : public std::true_type { }; \
+	} \
+/**/
 
 
 OPENMPT_NAMESPACE_END
diff --git a/common/mptUUID.cpp b/common/mptUUID.cpp
index 3294ffe..fa4c9e3 100644
--- a/common/mptUUID.cpp
+++ b/common/mptUUID.cpp
@@ -20,9 +20,9 @@
 #if MPT_OS_WINDOWS
 #include <windows.h>
 #include <rpc.h>
-#if defined(MODPLUG_TRACKER) || !defined(NO_DMO)
+#if defined(MODPLUG_TRACKER) || !defined(NO_DMO) || MPT_OS_WINDOWS_WINRT
 #include <objbase.h>
-#endif // MODPLUG_TRACKER || !NO_DMO
+#endif // MODPLUG_TRACKER || !NO_DMO || MPT_OS_WINDOWS_WINRT
 #endif // MPT_OS_WINDOWS
 
 
@@ -40,136 +40,310 @@ namespace Util
 
 
 std::wstring CLSIDToString(CLSID clsid)
-//-------------------------------------
 {
 	std::wstring str;
 	LPOLESTR tmp = nullptr;
-	::StringFromCLSID(clsid, &tmp);
-	if(tmp)
+	switch(::StringFromCLSID(clsid, &tmp))
+	{
+	case S_OK:
+		break;
+	case E_OUTOFMEMORY:
+		if(tmp)
+		{
+			::CoTaskMemFree(tmp);
+			tmp = nullptr;
+		}
+		MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
+		break;
+	default:
+		if(tmp)
+		{
+			::CoTaskMemFree(tmp);
+			tmp = nullptr;
+		}
+		throw std::logic_error("StringFromCLSID() failed.");
+		break;
+	}
+	if(!tmp)
+	{
+		throw std::logic_error("StringFromCLSID() failed.");
+	}
+	try
 	{
 		str = tmp;
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
 		::CoTaskMemFree(tmp);
 		tmp = nullptr;
+		MPT_UNUSED_VARIABLE(e);
+		MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY();
 	}
+	::CoTaskMemFree(tmp);
+	tmp = nullptr;
 	return str;
 }
 
 
 CLSID StringToCLSID(const std::wstring &str)
-//------------------------------------------
 {
 	CLSID clsid = CLSID();
 	std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
-	if(::CLSIDFromString(&tmp[0], &clsid) != S_OK)
+	switch(::CLSIDFromString(tmp.data(), &clsid))
 	{
-		return CLSID();
+	case NOERROR:
+		// nothing
+		break;
+	case E_INVALIDARG:
+		clsid = CLSID();
+		break;
+	case CO_E_CLASSSTRING:
+		clsid = CLSID();
+		break;
+	case REGDB_E_CLASSNOTREG:
+		clsid = CLSID();
+		break;
+	case REGDB_E_READREGDB:
+		clsid = CLSID();
+		throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB.");
+		break;
+	default:
+		clsid = CLSID();
+		throw std::logic_error("CLSIDFromString() failed.");
+		break;
 	}
 	return clsid;
 }
 
 
 bool VerifyStringToCLSID(const std::wstring &str, CLSID &clsid)
-//-------------------------------------------------------------
 {
+	bool result = false;
+	clsid = CLSID();
 	std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
-	return (::CLSIDFromString(&tmp[0], &clsid) == S_OK);
+	switch(::CLSIDFromString(tmp.data(), &clsid))
+	{
+	case NOERROR:
+		result = true;
+		break;
+	case E_INVALIDARG:
+		result = false;
+		break;
+	case CO_E_CLASSSTRING:
+		result = false;
+		break;
+	case REGDB_E_CLASSNOTREG:
+		result = false;
+		break;
+	case REGDB_E_READREGDB:
+		throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB.");
+		break;
+	default:
+		throw std::logic_error("CLSIDFromString() failed.");
+		break;
+	}
+	return result;
 }
 
 
 bool IsCLSID(const std::wstring &str)
-//-----------------------------------
 {
+	bool result = false;
 	CLSID clsid = CLSID();
 	std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
-	return (::CLSIDFromString(&tmp[0], &clsid) == S_OK);
+	switch(::CLSIDFromString(tmp.data(), &clsid))
+	{
+	case NOERROR:
+		result = true;
+		break;
+	case E_INVALIDARG:
+		result = false;
+		break;
+	case CO_E_CLASSSTRING:
+		result = false;
+		break;
+	case REGDB_E_CLASSNOTREG:
+		result = false;
+		break;
+	case REGDB_E_READREGDB:
+		result = false;
+		throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB.");
+		break;
+	default:
+		result = false;
+		throw std::logic_error("CLSIDFromString() failed.");
+		break;
+	}
+	return result;
 }
 
 
 std::wstring IIDToString(IID iid)
-//-------------------------------
 {
 	std::wstring str;
 	LPOLESTR tmp = nullptr;
-	::StringFromIID(iid, &tmp);
-	if(tmp)
+	switch(::StringFromIID(iid, &tmp))
+	{
+	case S_OK:
+		break;
+	case E_OUTOFMEMORY:
+		if(tmp)
+		{
+			::CoTaskMemFree(tmp);
+			tmp = nullptr;
+		}
+		MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
+		break;
+	default:
+		if(tmp)
+		{
+			::CoTaskMemFree(tmp);
+			tmp = nullptr;
+		}
+		throw std::logic_error("StringFromIID() failed.");
+		break;
+	}
+	if(!tmp)
+	{
+		throw std::logic_error("StringFromIID() failed.");
+	}
+	try
 	{
 		str = tmp;
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
 		::CoTaskMemFree(tmp);
 		tmp = nullptr;
+		MPT_UNUSED_VARIABLE(e);
+		MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY();
 	}
 	return str;
 }
 
 
 IID StringToIID(const std::wstring &str)
-//--------------------------------------
 {
 	IID iid = IID();
 	std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
-	::IIDFromString(&tmp[0], &iid);
+	switch(::IIDFromString(tmp.data(), &iid))
+	{
+	case S_OK:
+		// nothing
+		break;
+	case E_OUTOFMEMORY:
+		iid = IID();
+		MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
+		break;
+	case E_INVALIDARG:
+		iid = IID();
+		break;
+	default:
+		iid = IID();
+		throw std::logic_error("IIDFromString() failed.");
+		break;
+	}
 	return iid;
 }
 
 
 std::wstring GUIDToString(GUID guid)
-//----------------------------------
 {
 	std::vector<OLECHAR> tmp(256);
-	::StringFromGUID2(guid, &tmp[0], static_cast<int>(tmp.size()));
-	return &tmp[0];
+	if(::StringFromGUID2(guid, tmp.data(), static_cast<int>(tmp.size())) <= 0)
+	{
+		throw std::logic_error("StringFromGUID2() failed.");
+	}
+	return tmp.data();
 }
 
 
 GUID StringToGUID(const std::wstring &str)
-//----------------------------------------
 {
 	return StringToIID(str);
 }
 
 
 GUID CreateGUID()
-//---------------
 {
 	GUID guid = GUID();
-	if(::CoCreateGuid(&guid) != S_OK)
+	switch(::CoCreateGuid(&guid))
 	{
-		return GUID();
+	case S_OK:
+		// nothing
+		break;
+	default:
+		guid = GUID();
+		throw std::runtime_error("CoCreateGuid() failed.");
 	}
 	return guid;
 }
 
 
+#if !MPT_OS_WINDOWS_WINRT
+
 UUID StringToUUID(const mpt::ustring &str)
-//----------------------------------------
 {
 	UUID uuid = UUID();
 	std::wstring wstr = mpt::ToWide(str);
 	std::vector<wchar_t> tmp(wstr.c_str(), wstr.c_str() + wstr.length() + 1);
-	if(::UuidFromStringW((RPC_WSTR)(&(tmp[0])), &uuid) != RPC_S_OK)
+	switch(::UuidFromStringW((RPC_WSTR)(&(tmp[0])), &uuid))
 	{
-		return UUID();
+	case RPC_S_OK:
+		// nothing
+		break;
+	case RPC_S_INVALID_STRING_UUID:
+		uuid = UUID();
+		break;
+	default:
+		throw std::logic_error("UuidFromStringW() failed.");
+		break;
 	}
 	return uuid;
 }
 
 
 mpt::ustring UUIDToString(UUID uuid)
-//----------------------------------
 {
 	std::wstring wstr;
 	RPC_WSTR tmp = nullptr;
-	if(::UuidToStringW(&uuid, &tmp) != RPC_S_OK)
+	switch(::UuidToStringW(&uuid, &tmp))
+	{
+	case RPC_S_OK:
+		// nothing
+		break;
+	case RPC_S_OUT_OF_MEMORY:
+		if(tmp)
+		{
+			::RpcStringFreeW(&tmp);
+			tmp = nullptr;
+		}
+		MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
+		break;
+	default:
+		throw std::logic_error("UuidToStringW() failed.");
+		break;
+	}
+	try
 	{
-		return mpt::ustring();
+		std::size_t len = 0;
+		for(len = 0; tmp[len] != 0; ++len)
+		{
+			// nothing
+		}
+		wstr = std::wstring(tmp, tmp + len);
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		::RpcStringFreeW(&tmp);
+		tmp = nullptr;
+		MPT_UNUSED_VARIABLE(e);
+		MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY();
 	}
-	wstr = (wchar_t*)tmp;
-	::RpcStringFreeW(&tmp);
 	return mpt::ToUnicode(wstr);
 }
 
+#endif // !MPT_OS_WINDOWS_WINRT
+
 
 bool IsValid(UUID uuid)
-//---------------------
 {
 	return false
 		|| uuid.Data1 != 0
@@ -237,13 +411,9 @@ mpt::UUID UUIDFromWin32(::UUID uuid)
 	return result;
 }
 
-#if defined(MODPLUG_TRACKER)
+#if defined(MODPLUG_TRACKER) || !defined(NO_DMO)
 
 UUID::UUID(::UUID uuid)
-	: Data1(0)
-	, Data2(0)
-	, Data3(0)
-	, Data4(0)
 {
 	*this = UUIDFromWin32(uuid);
 }
@@ -253,13 +423,36 @@ UUID::operator ::UUID () const
 	return UUIDToWin32(*this);
 }
 
-#endif // MODPLUG_TRACKER
+mpt::UUID UUID::FromGroups(uint32 group1, uint16 group2, uint16 group3, uint16 group4, uint64 group5)
+{
+	MPT_ASSERT((group5 & 0xffff000000000000ull) == 0ull);
+	return mpt::UUID
+		( group1
+		, group2
+		, group3
+		, (static_cast<uint64>(group4) << 48) | group5
+		);
+}
+
+#endif // MODPLUG_TRACKER || !NO_DMO
 
 #endif // MPT_OS_WINDOWS
 
 UUID UUID::Generate()
 {
-	#if MPT_OS_WINDOWS
+	#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+		#if (_WIN32_WINNT >= 0x0602)
+			::GUID guid = ::GUID();
+			HRESULT result = CoCreateGuid(&guid);
+			if(result != S_OK)
+			{
+				return mpt::UUID::RFC4122Random();
+			}
+			return mpt::UUIDFromWin32(guid);
+		#else
+			return mpt::UUID::RFC4122Random();
+		#endif
+	#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
 		::UUID uuid = ::UUID();
 		RPC_STATUS status = ::UuidCreate(&uuid);
 		if(status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY)
@@ -283,7 +476,19 @@ UUID UUID::Generate()
 
 UUID UUID::GenerateLocalUseOnly()
 {
-	#if MPT_OS_WINDOWS
+	#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+		#if (_WIN32_WINNT >= 0x0602)
+			::GUID guid = ::GUID();
+			HRESULT result = CoCreateGuid(&guid);
+			if(result != S_OK)
+			{
+				return mpt::UUID::RFC4122Random();
+			}
+			return mpt::UUIDFromWin32(guid);
+		#else
+			return mpt::UUID::RFC4122Random();
+		#endif
+	#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
 		#if _WIN32_WINNT >= 0x0501
 			// Available since Win2000, but we check for WinXP in order to not use this
 			// function in Win32old builds. It is not available on some non-fully
@@ -398,30 +603,20 @@ void UUID::MakeRFC4122(uint8 version)
 	Data3 |= static_cast<uint16>(Mm) << 8;
 }
 
-void UUID::ConvertEndianness()
-{
-	SwapBytesBE(Data1);
-	SwapBytesBE(Data2);
-	SwapBytesBE(Data3);
-	SwapBytesBE(Data4);
-}
-
 UUID::UUID()
-	: Data1(0)
-	, Data2(0)
-	, Data3(0)
-	, Data4(0)
 {
-	return;
+	Data1 = 0;
+	Data2 = 0;
+	Data3 = 0;
+	Data4 = 0;
 }
 
 UUID::UUID(uint32 Data1, uint16 Data2, uint16 Data3, uint64 Data4)
-	: Data1(Data1)
-	, Data2(Data2)
-	, Data3(Data3)
-	, Data4(Data4)
 {
-	return;
+	this->Data1 = Data1;
+	this->Data2 = Data2;
+	this->Data3 = Data3;
+	this->Data4 = Data4;
 }
 
 bool operator==(const mpt::UUID & a, const mpt::UUID & b)
@@ -434,6 +629,41 @@ bool operator!=(const mpt::UUID & a, const mpt::UUID & b)
 	return (a.Data1 != b.Data1) || (a.Data2 != b.Data2) || (a.Data3 != b.Data3) || (a.Data4 != b.Data4);
 }
 
+UUID UUID::FromString(const std::string &str)
+{
+	std::vector<std::string> segments = mpt::String::Split<std::string>(str, std::string("-"));
+	if(segments.size() != 5)
+	{
+		return UUID();
+	}
+	if(segments[0].length() != 8)
+	{
+		return UUID();
+	}
+	if(segments[1].length() != 4)
+	{
+		return UUID();
+	}
+	if(segments[2].length() != 4)
+	{
+		return UUID();
+	}
+	if(segments[3].length() != 4)
+	{
+		return UUID();
+	}
+	if(segments[4].length() != 12)
+	{
+		return UUID();
+	}
+	UUID result;
+	result.Data1 = mpt::String::Parse::Hex<uint32>(segments[0]);
+	result.Data2 = mpt::String::Parse::Hex<uint16>(segments[1]);
+	result.Data3 = mpt::String::Parse::Hex<uint16>(segments[2]);
+	result.Data4 = mpt::String::Parse::Hex<uint64>(segments[3] + segments[4]);
+	return result;
+}
+
 UUID UUID::FromString(const mpt::ustring &str)
 {
 	std::vector<mpt::ustring> segments = mpt::String::Split<mpt::ustring>(str, MPT_USTRING("-"));
@@ -469,22 +699,57 @@ UUID UUID::FromString(const mpt::ustring &str)
 	return result;
 }
 
+std::string UUID::ToString() const
+{
+	return std::string()
+		+ mpt::fmt::hex0<8>(GetData1())
+		+ std::string("-")
+		+ mpt::fmt::hex0<4>(GetData2())
+		+ std::string("-")
+		+ mpt::fmt::hex0<4>(GetData3())
+		+ std::string("-")
+		+ mpt::fmt::hex0<4>(static_cast<uint16>(GetData4() >> 48))
+		+ std::string("-")
+		+ mpt::fmt::hex0<4>(static_cast<uint16>(GetData4() >> 32))
+		+ mpt::fmt::hex0<8>(static_cast<uint32>(GetData4() >>  0))
+		;
+}
+
 mpt::ustring UUID::ToUString() const
 {
 	return mpt::ustring()
-		+ mpt::ufmt::hex0<8>(Data1)
+		+ mpt::ufmt::hex0<8>(GetData1())
 		+ MPT_USTRING("-")
-		+ mpt::ufmt::hex0<4>(Data2)
+		+ mpt::ufmt::hex0<4>(GetData2())
 		+ MPT_USTRING("-")
-		+ mpt::ufmt::hex0<4>(Data3)
+		+ mpt::ufmt::hex0<4>(GetData3())
 		+ MPT_USTRING("-")
-		+ mpt::ufmt::hex0<4>(static_cast<uint16>(Data4 >> 48))
+		+ mpt::ufmt::hex0<4>(static_cast<uint16>(GetData4() >> 48))
 		+ MPT_USTRING("-")
-		+ mpt::ufmt::hex0<4>(static_cast<uint16>(Data4 >> 32))
-		+ mpt::ufmt::hex0<8>(static_cast<uint32>(Data4 >>  0))
+		+ mpt::ufmt::hex0<4>(static_cast<uint16>(GetData4() >> 32))
+		+ mpt::ufmt::hex0<8>(static_cast<uint32>(GetData4() >>  0))
 		;
 }
 
+UUID::UUID(GUIDms guid)
+{
+	Data1 = guid.Data1.get();
+	Data2 = guid.Data2.get();
+	Data3 = guid.Data3.get();
+	Data4 = guid.Data4.get();
+}
+
+UUID::operator GUIDms() const
+{
+	GUIDms result;
+	result.Data1 = GetData1();
+	result.Data2 = GetData2();
+	result.Data3 = GetData3();
+	result.Data4 = GetData4();
+	return result;
+}
+
+
 } // namespace mpt
 
 
diff --git a/common/mptUUID.h b/common/mptUUID.h
index 8c7ce08..d0b3b36 100644
--- a/common/mptUUID.h
+++ b/common/mptUUID.h
@@ -11,6 +11,8 @@
 #pragma once
 
 
+#include "Endianness.h"
+
 #if MPT_OS_WINDOWS
 #if defined(MODPLUG_TRACKER) || !defined(NO_DMO)
 #include <guiddef.h>
@@ -49,10 +51,12 @@ std::wstring GUIDToString(GUID guid);
 // Create a COM GUID
 GUID CreateGUID();
 
+#if !MPT_OS_WINDOWS_WINRT
 // General UUID<->string conversion.
 // The string must/will be in standard UUID format: 4f9a455d-e7ef-4367-b2f0-0c83a38a5c72
 UUID StringToUUID(const mpt::ustring &str);
 mpt::ustring UUIDToString(UUID uuid);
+#endif // !MPT_OS_WINDOWS_WINRT
 
 // Checks the UUID against the NULL UUID. Returns false if it is NULL, true otherwise.
 bool IsValid(UUID uuid);
@@ -63,15 +67,25 @@ bool IsValid(UUID uuid);
 
 #endif // MPT_OS_WINDOWS
 
+// Microsoft on-disk layout
+struct GUIDms
+{
+	uint32le Data1;
+	uint16le Data2;
+	uint16le Data3;
+	uint64be Data4; // yes, big endian here
+};
+STATIC_ASSERT(sizeof(GUIDms) == 16);
+
 namespace mpt {
 
 struct UUID
 {
 private:
-	uint32 Data1;
-	uint16 Data2;
-	uint16 Data3;
-	uint64 Data4;
+	uint32be Data1;
+	uint16be Data2;
+	uint16be Data3;
+	uint64be Data4;
 public:
 	uint32 GetData1() const;
 	uint16 GetData2() const;
@@ -90,15 +104,18 @@ private:
 	uint8 Nn() const;
 	void MakeRFC4122(uint8 version);
 public:
-	void ConvertEndianness();
-public:
-#if MPT_OS_WINDOWS && defined(MODPLUG_TRACKER)
+#if MPT_OS_WINDOWS && (defined(MODPLUG_TRACKER) || !defined(NO_DMO))
 	explicit UUID(::UUID uuid);
 	operator ::UUID () const;
-#endif // MPT_OS_WINDOWS && MODPLUG_TRACKER
+	static UUID FromGroups(uint32 group1, uint16 group2, uint16 group3, uint16 group4, uint64 group5);
+	#define MPT_UUID_HELPER( prefix , value , suffix ) ( prefix ## value ## suffix )
+	#define MPT_UUID(group1, group2, group3, group4, group5) mpt::UUID::FromGroups(MPT_UUID_HELPER(0x,group1,u), MPT_UUID_HELPER(0x,group2,u), MPT_UUID_HELPER(0x,group3,u), MPT_UUID_HELPER(0x,group4,u), MPT_UUID_HELPER(0x,group5,ull))
+#endif // MPT_OS_WINDOWS && (MODPLUG_TRACKER || !NO_DMO)
 public:
 	UUID();
 	explicit UUID(uint32 Data1, uint16 Data2, uint16 Data3, uint64 Data4);
+	explicit UUID(GUIDms guid);
+	operator GUIDms () const;
 	friend bool operator==(const mpt::UUID & a, const mpt::UUID & b);
 	friend bool operator!=(const mpt::UUID & a, const mpt::UUID & b);
 public:
@@ -112,7 +129,9 @@ public:
 public:
 	// General UUID<->string conversion.
 	// The string must/will be in standard UUID format: 4f9a455d-e7ef-4367-b2f0-0c83a38a5c72
+	static UUID FromString(const std::string &str);
 	static UUID FromString(const mpt::ustring &str);
+	std::string ToString() const;
 	mpt::ustring ToUString() const;
 };
 
diff --git a/common/mptWine.cpp b/common/mptWine.cpp
new file mode 100644
index 0000000..747fd7a
--- /dev/null
+++ b/common/mptWine.cpp
@@ -0,0 +1,766 @@
+/*
+ * mptWine.cpp
+ * -----------
+ * Purpose: Wine stuff.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "mptWine.h"
+
+#include "mptOS.h"
+#include "mptFileIO.h"
+
+#include <deque>
+#include <map>
+
+#if MPT_OS_WINDOWS
+#include <windows.h>
+#endif
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
+
+
+namespace mpt
+{
+namespace Wine
+{
+
+
+
+Context::Context(mpt::Wine::VersionContext versionContext)
+	: m_VersionContext(versionContext)
+	, wine_get_dos_file_name(nullptr)
+	, wine_get_unix_file_name(nullptr)
+{
+	if(!mpt::Windows::IsWine())
+	{
+		throw mpt::Wine::Exception("Wine not detected.");
+	}
+	if(!m_VersionContext.Version().IsValid())
+	{
+		throw mpt::Wine::Exception("Unknown Wine version detected.");
+	}
+	m_Kernel32 = mpt::Library(mpt::LibraryPath::FullPath(MPT_PATHSTRING("kernel32.dll")));
+	if(!m_Kernel32.IsValid())
+	{
+		throw mpt::Wine::Exception("Could not load Wine kernel32.dll.");
+	}
+	if(!m_Kernel32.Bind(wine_get_unix_file_name, "wine_get_unix_file_name"))
+	{
+		throw mpt::Wine::Exception("Could not bind Wine kernel32.dll:wine_get_unix_file_name.");
+	}
+	if(!m_Kernel32.Bind(wine_get_dos_file_name, "wine_get_dos_file_name"))
+	{
+		throw mpt::Wine::Exception("Could not bind Wine kernel32.dll:wine_get_dos_file_name.");
+	}
+	{
+		std::string out;
+		std::string err;
+		try
+		{
+			if(ExecutePosixShellCommand("uname -m", out, err) != 0)
+			{
+				throw mpt::Wine::Exception("Wine 'uname -m' failed.");
+			}
+			if(!err.empty())
+			{
+				throw mpt::Wine::Exception("Wine 'uname -m' failed.");
+			}
+			out = mpt::String::Trim(out, std::string("\r\n"));
+			m_Uname_m = out;
+		} catch(const std::exception &)
+		{
+			m_Uname_m = std::string();
+		}
+	}
+	try
+	{
+		m_HOME = GetPosixEnvVar("HOME");
+	} catch(const std::exception &)
+	{
+		m_HOME = std::string();
+	}
+	try
+	{
+		m_XDG_DATA_HOME = GetPosixEnvVar("XDG_DATA_HOME");
+		if(m_XDG_DATA_HOME.empty())
+		{
+			m_XDG_DATA_HOME = m_HOME + "/.local/share";
+		}
+	} catch(const std::exception &)
+	{
+		m_XDG_DATA_HOME = std::string();
+	}
+	try
+	{
+		m_XDG_CACHE_HOME = GetPosixEnvVar("XDG_CACHE_HOME");
+		if(m_XDG_CACHE_HOME.empty())
+		{
+			m_XDG_CACHE_HOME = m_HOME + "/.cache";
+		}
+	} catch(const std::exception &)
+	{
+		m_XDG_CACHE_HOME = std::string();
+	}
+	try
+	{
+		m_XDG_CONFIG_HOME = GetPosixEnvVar("XDG_CONFIG_HOME");
+		if(m_XDG_CONFIG_HOME.empty())
+		{
+			m_XDG_CONFIG_HOME = m_HOME + "/.config";
+		}
+	} catch(const std::exception &)
+	{
+		m_XDG_CONFIG_HOME = std::string();
+	}
+}
+
+
+std::string Context::PathToPosix(mpt::PathString windowsPath)
+{
+	std::string result;
+	if(windowsPath.empty())
+	{
+		return result;
+	}
+	if(windowsPath.Length() >= 32000)
+	{
+		throw mpt::Wine::Exception("Path too long.");
+	}
+	LPSTR tmp = nullptr;
+	tmp = wine_get_unix_file_name(windowsPath.AsNative().c_str());
+	if(!tmp)
+	{
+		throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_unix_file_name failed.");
+	}
+	result = tmp;
+	HeapFree(GetProcessHeap(), 0, tmp);
+	tmp = nullptr;
+	return result;
+}
+
+mpt::PathString Context::PathToWindows(std::string hostPath)
+{
+	mpt::PathString result;
+	if(hostPath.empty())
+	{
+		return result;
+	}
+	if(hostPath.length() >= 32000)
+	{
+		throw mpt::Wine::Exception("Path too long.");
+	}
+	LPWSTR tmp = nullptr;
+	tmp = wine_get_dos_file_name(hostPath.c_str());
+	if(!tmp)
+	{
+		throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_dos_file_name failed.");
+	}
+	result = mpt::PathString::FromNative(tmp);
+	HeapFree(GetProcessHeap(), 0, tmp);
+	tmp = nullptr;
+	return result;
+}
+
+std::string Context::PathToPosixCanonical(mpt::PathString windowsPath)
+{
+	std::string result;
+	std::string hostPath = PathToPosix(windowsPath);
+	if(hostPath.empty())
+	{
+		return result;
+	}
+	std::string output;
+	std::string error;
+	int exitcode = ExecutePosixShellCommand(std::string() + "readlink -f " + EscapePosixShell(hostPath), output, error);
+	if(!error.empty())
+	{
+		throw mpt::Wine::Exception("Wine readlink failed: " + error);
+	}
+	if(exitcode != 0 && exitcode != 1)
+	{
+		throw mpt::Wine::Exception("Wine readlink failed.");
+	}
+	std::string trimmedOutput = mpt::String::Trim(output, std::string("\r\n"));
+	result = trimmedOutput;
+	return result;
+}
+
+
+static void ExecutePosixCommandProgressDefault(void * /*userdata*/ )
+{
+	::Sleep(10);
+	return;
+}
+
+static ExecuteProgressResult ExecutePosixShellScriptProgressDefault(void * /*userdata*/ )
+{
+	::Sleep(10);
+	return ExecuteProgressContinueWaiting;
+}
+
+
+std::string Context::EscapePosixShell(std::string line)
+{
+	const char escape_chars [] = { '|', '&', ';', '<', '>', '(', ')', '$', '`', '"', '\'', ' ', '\t' };
+	const char maybe_escape_chars [] = { '*', '?', '[', '#', '~', '=', '%' };
+	line = mpt::String::Replace(line, "\\", "\\\\");
+	for(std::size_t i = 0; i < mpt::size(escape_chars); ++i)
+	{
+		line = mpt::String::Replace(line, std::string(1, escape_chars[i]), "\\" + std::string(1, escape_chars[i]));
+	}
+	for(std::size_t i = 0; i < mpt::size(maybe_escape_chars); ++i)
+	{
+		line = mpt::String::Replace(line, std::string(1, maybe_escape_chars[i]), "\\" + std::string(1, maybe_escape_chars[i]));
+	}
+	return line;
+}
+
+
+ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlags> flags, std::map<std::string, std::vector<char> > filetree, std::string title, ExecutePosixCommandProgress progress, ExecutePosixShellScriptProgress progressCancel, void *userdata)
+{
+	// Relevant documentation:
+	// https://stackoverflow.com/questions/6004070/execute-shell-commands-from-program-running-in-wine
+	// https://www.winehq.org/pipermail/wine-bugs/2014-January/374918.html
+	// https://bugs.winehq.org/show_bug.cgi?id=34730
+
+	if(!progress) progress = &ExecutePosixCommandProgressDefault;
+	if(!progressCancel) progressCancel = &ExecutePosixShellScriptProgressDefault;
+
+	if(flags[ExecFlagInteractive]) flags.reset(ExecFlagSilent);
+	if(flags[ExecFlagSplitOutput]) flags.set(ExecFlagSilent);
+
+	std::vector<mpt::PathString> tempfiles;
+
+	progress(userdata);
+
+	mpt::TempDirGuard dirWindowsTemp(mpt::CreateTempFileName());
+	if(dirWindowsTemp.GetDirname().empty())
+	{
+		throw mpt::Wine::Exception("Creating temporary directoy failed.");
+	}
+	std::string dirPosix = PathToPosix(dirWindowsTemp.GetDirname());
+	if(dirPosix.empty())
+	{
+		throw mpt::Wine::Exception("mpt::Wine::ConvertWindowsPathToHost returned empty path.");
+	}
+	const mpt::PathString dirWindows = dirWindowsTemp.GetDirname();
+
+	progress(userdata);
+
+	// write the script to disk
+	mpt::PathString scriptFilenameWindows = dirWindows + MPT_PATHSTRING("script.sh");
+	{
+		mpt::ofstream tempfile(scriptFilenameWindows, std::ios::binary);
+		tempfile << script;
+		tempfile.flush();
+		if(!tempfile)
+		{
+			throw mpt::Wine::Exception("Error writing script.sh.");
+		}
+	}
+	std::string scriptFilenamePosix = PathToPosix(scriptFilenameWindows);
+	if(scriptFilenamePosix.empty())
+	{
+		throw mpt::Wine::Exception("Error converting script.sh path.");
+	}
+
+	progress(userdata);
+
+	// create a wrapper that will call the script and gather result.
+	mpt::PathString wrapperstarterFilenameWindows = dirWindows + MPT_PATHSTRING("wrapperstarter.sh");
+	{
+		mpt::ofstream tempfile(wrapperstarterFilenameWindows, std::ios::binary);
+		std::string wrapperstarterscript;
+		wrapperstarterscript += std::string() + "#!/usr/bin/env sh" + "\n";
+		wrapperstarterscript += std::string() + "exec /usr/bin/env sh " + EscapePosixShell(dirPosix) + "wrapper.sh" + "\n";
+		tempfile << wrapperstarterscript;
+		tempfile.flush();
+		if(!tempfile)
+		{
+			throw mpt::Wine::Exception("Error writing wrapper.sh.");
+		}
+	}
+	mpt::PathString wrapperFilenameWindows = dirWindows + MPT_PATHSTRING("wrapper.sh");
+	std::string cleanupscript;
+	{
+		mpt::ofstream tempfile(wrapperFilenameWindows, std::ios::binary);
+		std::string wrapperscript;
+		if(!flags[ExecFlagSilent])
+		{
+			wrapperscript += std::string() + "printf \"\\033]0;" + title + "\\a\"" + "\n";
+		}
+		wrapperscript += std::string() + "chmod u+x " + EscapePosixShell(scriptFilenamePosix) + "\n";
+		wrapperscript += std::string() + "cd " + EscapePosixShell(dirPosix) + "filetree" + "\n";
+		if(flags[ExecFlagInteractive])
+		{ // no stdout/stderr capturing for interactive scripts
+			wrapperscript += std::string() + EscapePosixShell(scriptFilenamePosix) + "\n";
+			wrapperscript += std::string() + "MPT_RESULT=$?" + "\n";
+			wrapperscript += std::string() + "echo ${MPT_RESULT} > " + EscapePosixShell(dirPosix) + "exit" + "\n";
+		} else if(flags[ExecFlagSplitOutput])
+		{
+			wrapperscript += std::string() + "(" + EscapePosixShell(scriptFilenamePosix) + "; echo $? >&4) 4>" + EscapePosixShell(dirPosix) + "exit 1>" + EscapePosixShell(dirPosix) + "out 2>" + EscapePosixShell(dirPosix) + "err" + "\n";
+		} else
+		{
+			wrapperscript += std::string() + "(" + EscapePosixShell(scriptFilenamePosix) + "; echo $? >&4) 2>&1 4>" + EscapePosixShell(dirPosix) + "exit | tee " + EscapePosixShell(dirPosix) + "out" + "\n";
+		}
+		wrapperscript += std::string() + "echo done > " + EscapePosixShell(dirPosix) + "done" + "\n";
+		cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "done" + "\n";
+		cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "exit" + "\n";
+		if(flags[ExecFlagInteractive])
+		{
+			// nothing
+		} else if(flags[ExecFlagSplitOutput])
+		{
+			cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "out" + "\n";
+			cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "err" + "\n";
+		} else
+		{
+			cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "out" + "\n";
+		}
+		cleanupscript += std::string() + "rm -r " + EscapePosixShell(dirPosix) + "filetree" + "\n";			
+		cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "script.sh" + "\n";			
+		cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "wrapper.sh" + "\n";			
+		cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "wrapperstarter.sh" + "\n";			
+		cleanupscript += std::string() + "rm " + EscapePosixShell(dirPosix) + "terminal.sh" + "\n";			
+		if(flags[ExecFlagAsync])
+		{
+			wrapperscript += cleanupscript;
+			cleanupscript.clear();
+		}
+		tempfile << wrapperscript;
+		tempfile.flush();
+		if(!tempfile)
+		{
+			throw mpt::Wine::Exception("Error writing wrapper.sh.");
+		}
+	}
+
+	progress(userdata);
+
+	::CreateDirectoryW((dirWindows + MPT_PATHSTRING("filetree")).AsNative().c_str(), NULL);
+	for(const auto &file : filetree)
+	{
+		std::vector<mpt::ustring> path = mpt::String::Split<mpt::ustring>(mpt::ToUnicode(mpt::CharsetUTF8, file.first), MPT_USTRING("/"));
+		mpt::PathString combinedPath = dirWindows + MPT_PATHSTRING("filetree") + MPT_PATHSTRING("\\");
+		if(path.size() > 1)
+		{
+			for(std::size_t singlepath = 0; singlepath < path.size() - 1; ++singlepath)
+			{
+				if(path[singlepath].empty())
+				{
+					continue;
+				}
+				combinedPath += mpt::PathString::FromUnicode(path[singlepath]);
+				if(!combinedPath.IsDirectory())
+				{
+					if(::CreateDirectoryW(combinedPath.AsNative().c_str(), NULL) == 0)
+					{
+						throw mpt::Wine::Exception("Error writing filetree.");
+					}
+				}
+				combinedPath += MPT_PATHSTRING("\\");
+			}
+		}
+		try
+		{
+			mpt::LazyFileRef out(dirWindows + MPT_PATHSTRING("filetree") + MPT_PATHSTRING("\\") + mpt::PathString::FromUTF8(mpt::String::Replace(file.first, "/", "\\")));
+			out = file.second;
+		} catch(std::exception &)
+		{
+			throw mpt::Wine::Exception("Error writing filetree.");
+		}
+	}
+
+	progress(userdata);
+
+	// create a wrapper that will find a suitable terminal and run the wrapper script in the terminal window.
+	mpt::PathString terminalWrapperFilenameWindows = dirWindows + MPT_PATHSTRING("terminal.sh");
+	{
+		mpt::ofstream tempfile(terminalWrapperFilenameWindows, std::ios::binary);
+		// NOTE:
+		// Modern terminals detach themselves from the invoking shell if another instance is already present.
+		// This means we cannot rely on terminal invocation being syncronous.
+		std::vector<std::string> terminals;
+		terminals.push_back("x-terminal-emulator");
+		terminals.push_back("konsole");
+		terminals.push_back("mate-terminal");
+		terminals.push_back("xfce4-terminal");
+		terminals.push_back("gnome-terminal");
+		terminals.push_back("uxterm");
+		terminals.push_back("xterm");
+		terminals.push_back("rxvt");
+		std::map<std::string, std::string> terminalLanchers;
+		for(std::size_t i = 0; i < terminals.size(); ++i)
+		{
+			// mate-terminal on Debian 8 cannot execute commands with arguments,
+			// thus we use a separate script that requires no arguments to execute.
+			terminalLanchers[terminals[i]] += std::string() + "if command -v " + terminals[i] + " 2>/dev/null 1>/dev/null ; then" + "\n";
+			terminalLanchers[terminals[i]] += std::string() + " chmod u+x " + EscapePosixShell(dirPosix) + "wrapperstarter.sh" + "\n";
+			terminalLanchers[terminals[i]] += std::string() + " exec `command -v " + terminals[i] + "` -e \"" + EscapePosixShell(dirPosix) + "wrapperstarter.sh\"" + "\n";
+			terminalLanchers[terminals[i]] += std::string() + "fi" + "\n";
+		}
+
+		std::string terminalscript;
+
+		terminalscript += std::string() + "\n";
+
+		for(std::size_t i = 0; i < terminals.size(); ++i)
+		{
+			terminalscript += terminalLanchers[terminals[i]];
+		}
+
+		tempfile << terminalscript;
+		tempfile.flush();
+		if(!tempfile)
+		{
+			return ExecResult::Error();
+		}
+	}
+
+	progress(userdata);
+
+	// build unix command line
+	std::string unixcommand;
+	bool createProcessSuccess = false;
+
+	if(!createProcessSuccess)
+	{
+
+		if(flags[ExecFlagSilent])
+		{
+			unixcommand = "/usr/bin/env sh \"" + EscapePosixShell(dirPosix) + "wrapper.sh\"";
+		} else
+		{
+			unixcommand = "/usr/bin/env sh \"" + EscapePosixShell(dirPosix) + "terminal.sh\"";
+		}
+
+		progress(userdata);
+
+		std::wstring unixcommandW = mpt::ToWide(mpt::CharsetUTF8, unixcommand);
+		std::vector<WCHAR> commandline = std::vector<WCHAR>(unixcommandW.data(), unixcommandW.data() + unixcommandW.length() + 1);
+		std::wstring titleW = mpt::ToWide(mpt::CharsetUTF8, title);
+		std::vector<WCHAR> titleWv = std::vector<WCHAR>(titleW.data(), titleW.data() + titleW.length() + 1);
+		STARTUPINFOW startupInfo;
+		MemsetZero(startupInfo);
+		startupInfo.lpTitle = &titleWv[0];
+		startupInfo.cb = sizeof(startupInfo);
+		PROCESS_INFORMATION processInformation;
+		MemsetZero(processInformation);
+
+		progress(userdata);
+
+		BOOL success = FALSE;
+		if(flags[ExecFlagSilent])
+		{
+			success = CreateProcessW(NULL, &commandline[0], NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &processInformation);
+		} else
+		{
+			success = CreateProcessW(NULL, &commandline[0], NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInformation);
+		}
+
+		progress(userdata);
+
+		createProcessSuccess = (success ? true : false);
+
+		progress(userdata);
+
+		if(success)
+		{
+
+			if(!flags[ExecFlagAsync])
+			{
+				// note: execution is not syncronous with all Wine versions,
+				// we additionally explicitly wait for "done" later
+				while(WaitForSingleObject(processInformation.hProcess, 0) == WAIT_TIMEOUT)
+				{ // wait
+					if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
+					{
+						CloseHandle(processInformation.hThread);
+						CloseHandle(processInformation.hProcess);
+						throw mpt::Wine::Exception("Canceled.");
+					}
+				}
+			}
+
+			progress(userdata);
+
+			CloseHandle(processInformation.hThread);
+			CloseHandle(processInformation.hProcess);
+
+		}
+
+	}
+
+	progress(userdata);
+
+	// Work around Wine being able to execute PIE binaries on Debian 9.
+	// Luckily, /bin/bash is still non-PIE on Debian 9.
+
+	if(!createProcessSuccess)
+	{
+
+		if(flags[ExecFlagSilent]) {
+			unixcommand = "/bin/bash \"" + EscapePosixShell(dirPosix) + "wrapper.sh\"";
+		} else
+		{
+			unixcommand = "/bin/bash \"" + EscapePosixShell(dirPosix) + "terminal.sh\"";
+		}
+
+		progress(userdata);
+
+		std::wstring unixcommandW = mpt::ToWide(mpt::CharsetUTF8, unixcommand);
+		std::vector<WCHAR> commandline = std::vector<WCHAR>(unixcommandW.data(), unixcommandW.data() + unixcommandW.length() + 1);
+		std::wstring titleW = mpt::ToWide(mpt::CharsetUTF8, title);
+		std::vector<WCHAR> titleWv = std::vector<WCHAR>(titleW.data(), titleW.data() + titleW.length() + 1);
+		STARTUPINFOW startupInfo;
+		MemsetZero(startupInfo);
+		startupInfo.lpTitle = &titleWv[0];
+		startupInfo.cb = sizeof(startupInfo);
+		PROCESS_INFORMATION processInformation;
+		MemsetZero(processInformation);
+
+		progress(userdata);
+
+		BOOL success = FALSE;
+		if(flags[ExecFlagSilent])
+		{
+			success = CreateProcessW(NULL, &commandline[0], NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &processInformation);
+		} else
+		{
+			success = CreateProcessW(NULL, &commandline[0], NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInformation);
+		}
+
+		progress(userdata);
+
+		createProcessSuccess = (success ? true : false);
+
+		progress(userdata);
+
+		if(success)
+		{
+
+			if(!flags[ExecFlagAsync])
+			{
+				// note: execution is not syncronous with all Wine versions,
+				// we additionally explicitly wait for "done" later
+				while(WaitForSingleObject(processInformation.hProcess, 0) == WAIT_TIMEOUT)
+				{ // wait
+					if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
+					{
+						CloseHandle(processInformation.hThread);
+						CloseHandle(processInformation.hProcess);
+						throw mpt::Wine::Exception("Canceled.");
+					}
+				}
+			}
+
+			progress(userdata);
+
+			CloseHandle(processInformation.hThread);
+			CloseHandle(processInformation.hProcess);
+
+		}
+
+	}
+
+	progress(userdata);
+
+	if(!createProcessSuccess)
+	{
+		throw mpt::Wine::Exception("CreateProcess failed.");
+	}
+
+	progress(userdata);
+
+	if(flags[ExecFlagAsync])
+	{
+		ExecResult result;
+		result.exitcode = 0;
+		return result;
+	}
+
+	while(!(dirWindows + MPT_PATHSTRING("done")).IsFile())
+	{ // wait
+		if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
+		{
+			throw mpt::Wine::Exception("Canceled.");
+		}
+	}
+
+	progress(userdata);
+
+	int exitCode = 0;
+	{
+		mpt::ifstream exitFile(dirWindows + MPT_PATHSTRING("exit"), std::ios::binary);
+		if(!exitFile)
+		{
+			throw mpt::Wine::Exception("Script .exit file not found.");
+		}
+		std::string exitString;
+		exitFile >> exitString;
+		if(exitString.empty())
+		{
+			throw mpt::Wine::Exception("Script .exit file empty.");
+		}
+		exitCode = ConvertStrTo<int>(exitString);
+	}
+
+	progress(userdata);
+
+	std::string outputString;
+	if(!flags[ExecFlagInteractive])
+	{
+		mpt::ifstream outputFile(dirWindows + MPT_PATHSTRING("out"), std::ios::binary);
+		if(outputFile)
+		{
+			outputFile.seekg(0, std::ios::end);
+			std::streampos outputFileSize = outputFile.tellg();
+			outputFile.seekg(0, std::ios::beg);
+			std::vector<char> outputFileBuf(mpt::saturate_cast<std::size_t>(static_cast<std::streamoff>(outputFileSize)));
+			outputFile.read(&outputFileBuf[0], outputFileBuf.size());
+			outputString = std::string(outputFileBuf.begin(), outputFileBuf.end());
+		}
+	}
+
+	progress(userdata);
+
+	std::string errorString;
+	if(flags[ExecFlagSplitOutput])
+	{
+		mpt::ifstream errorFile(dirWindows + MPT_PATHSTRING("err"), std::ios::binary);
+		if(errorFile)
+		{
+			errorFile.seekg(0, std::ios::end);
+			std::streampos errorFileSize = errorFile.tellg();
+			errorFile.seekg(0, std::ios::beg);
+			std::vector<char> errorFileBuf(mpt::saturate_cast<std::size_t>(static_cast<std::streamoff>(errorFileSize)));
+			errorFile.read(&errorFileBuf[0], errorFileBuf.size());
+			errorString = std::string(errorFileBuf.begin(), errorFileBuf.end());
+		}
+	}
+
+	progress(userdata);
+
+	ExecResult result;
+	result.exitcode = exitCode;
+	result.output = outputString;
+	result.error = errorString;
+
+	std::deque<mpt::PathString> paths;
+	paths.push_back(dirWindows + MPT_PATHSTRING("filetree"));
+	mpt::PathString basePath = (dirWindows + MPT_PATHSTRING("filetree")).EnsureTrailingSlash();
+	while(!paths.empty())
+	{
+		mpt::PathString path = paths.front();
+		paths.pop_front();
+		path.EnsureTrailingSlash();
+		HANDLE hFind = NULL;
+		WIN32_FIND_DATAW wfd;
+		MemsetZero(wfd);
+		hFind = FindFirstFileW((path + MPT_PATHSTRING("*.*")).AsNative().c_str(), &wfd);
+		if(hFind != NULL && hFind != INVALID_HANDLE_VALUE)
+		{
+			do
+			{
+				mpt::PathString filename = mpt::PathString::FromNative(wfd.cFileName);
+				if(filename != MPT_PATHSTRING(".") && filename != MPT_PATHSTRING(".."))
+				{
+					filename = path + filename;
+					filetree[filename.ToUTF8()] = std::vector<char>();
+					if(filename.IsDirectory())
+					{
+						paths.push_back(filename);
+					} else if(filename.IsFile())
+					{
+						try
+						{
+							mpt::LazyFileRef f(filename);
+							std::vector<char> buf = f;
+							mpt::PathString treeFilename = mpt::PathString::FromNative(filename.AsNative().substr(basePath.AsNative().length()));
+							result.filetree[treeFilename.ToUTF8()] = buf;
+						} catch (std::exception &)
+						{
+							// nothing?!
+						}
+					}
+				}
+			} while(FindNextFileW(hFind, &wfd));
+			FindClose(hFind);
+		}
+	}
+
+	mpt::DeleteWholeDirectoryTree(dirWindows);
+
+	return result;
+
+}
+
+
+int Context::ExecutePosixShellCommand(std::string command, std::string & output, std::string & error)
+{
+	std::string script;
+	script += std::string() + "#!/usr/bin/env sh" + "\n";
+	script += std::string() + "exec " + command + "\n";
+	mpt::Wine::ExecResult execResult = ExecutePosixShellScript
+		( script
+		, mpt::Wine::ExecFlagSilent | mpt::Wine::ExecFlagSplitOutput, std::map<std::string, std::vector<char> >()
+		, std::string()
+		, nullptr
+		, nullptr
+		, nullptr
+		);
+	output = execResult.output;
+	error = execResult.error;
+	return execResult.exitcode;
+}
+
+
+std::string Context::GetPosixEnvVar(std::string var, std::string def)
+{
+	// We cannot use std::getenv here because Wine overrides SOME env vars,
+	// in particular, HOME is unset in the Wine environment.
+	// Instead, we just spawn a shell that will catch up a sane environment on
+	// its own.
+	std::string output;
+	std::string error;
+	int exitcode = ExecutePosixShellCommand(std::string() + "echo $" + var, output, error);
+	if(!error.empty())
+	{
+		throw mpt::Wine::Exception("Wine echo $var failed: " + error);
+	}
+	if(exitcode != 0)
+	{
+		throw mpt::Wine::Exception("Wine echo $var failed.");
+	}
+	std::string result = mpt::String::RTrim(output, std::string("\r\n"));
+	if(result.empty())
+	{
+		result = def;
+	}
+	return result;
+}
+
+
+} // namespace Wine
+} // namespace mpt
+
+
+#else // !(MODPLUG_TRACKER && MPT_OS_WINDOWS)
+
+
+MPT_MSVC_WORKAROUND_LNK4221(mptWine)
+
+
+#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
+
+
+OPENMPT_NAMESPACE_END
diff --git a/common/mptWine.h b/common/mptWine.h
new file mode 100644
index 0000000..6bec241
--- /dev/null
+++ b/common/mptWine.h
@@ -0,0 +1,127 @@
+/*
+ * mptWine.h
+ * ---------
+ * Purpose: Wine stuff.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#include "mptOS.h"
+#include "FlagSet.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
+
+
+namespace mpt
+{
+
+namespace Wine
+{
+
+
+class Exception
+ : public std::runtime_error
+{
+public:
+	Exception(const std::string &text)
+	 : std::runtime_error(text)
+	{
+		return;
+	}
+};
+
+
+typedef void (*ExecutePosixCommandProgress)(void *userdata);
+
+enum ExecuteProgressResult
+{
+	ExecuteProgressContinueWaiting = 0,
+	ExecuteProgressAsyncCancel = -1,
+};
+
+typedef ExecuteProgressResult (*ExecutePosixShellScriptProgress)(void *userdata);
+
+
+enum ExecFlags
+{
+	ExecFlagNone           = 0,
+	ExecFlagSilent         = 1<<0, // do not show a terminal window
+	ExecFlagInteractive    = 1<<1, // allow interaction (prevents stdout and stderr capturing and implies !silent)
+	ExecFlagAsync          = 1<<2, // do not wait for the script to finish
+	ExecFlagProgressWindow = 1<<3, // not implemented by mptOS
+	ExecFlagSplitOutput    = 1<<4, // split stdout and stderr (implies silent)
+	ExecFlagsDefault       = ExecFlagNone
+};
+MPT_DECLARE_ENUM(ExecFlags)
+
+struct ExecResult
+{
+	int exitcode;
+	std::string output;
+	std::string error;
+	std::map<std::string, std::vector<char> > filetree;
+	static ExecResult Error()
+	{
+		ExecResult result;
+		result.exitcode = -1;
+		return result;
+	}
+};
+
+
+class Context
+{
+protected:
+	mpt::Wine::VersionContext m_VersionContext;
+	mpt::Library m_Kernel32;
+private:
+	LPWSTR (*CDECL wine_get_dos_file_name)(LPCSTR str);
+	LPSTR (*CDECL wine_get_unix_file_name)(LPCWSTR str);
+protected:
+	std::string m_Uname_m;
+	std::string m_HOME;
+	std::string m_XDG_DATA_HOME;
+	std::string m_XDG_CACHE_HOME;
+	std::string m_XDG_CONFIG_HOME;
+public:
+	Context(mpt::Wine::VersionContext versionContext);
+public:
+	std::string EscapePosixShell(std::string line);
+	std::string PathToPosix(mpt::PathString windowsPath);
+	mpt::PathString PathToWindows(std::string hostPath);
+	ExecResult ExecutePosixShellScript(std::string script, FlagSet<ExecFlags> flags, std::map<std::string, std::vector<char> > filetree, std::string title, ExecutePosixCommandProgress progress, ExecutePosixShellScriptProgress progressCancel, void *userdata);
+	int ExecutePosixShellCommand(std::string command, std::string & output, std::string & error);
+	std::string PathToPosixCanonical(mpt::PathString windowsPath);
+	std::string GetPosixEnvVar(std::string var, std::string def = std::string());
+public:
+	mpt::Wine::VersionContext VersionContext() const { return m_VersionContext; }
+	mpt::Library Kernel32() const { return m_Kernel32; }
+	std::string Uname_m() const { return m_Uname_m; }
+	std::string HOME() const { return m_HOME; }
+	std::string XDG_DATA_HOME() const { return m_XDG_DATA_HOME; }
+	std::string XDG_CACHE_HOME() const { return m_XDG_CACHE_HOME; }
+	std::string XDG_CONFIG_HOME() const { return m_XDG_CONFIG_HOME; }
+};
+
+
+} // namespace Wine
+
+} // namespace mpt
+
+
+#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
+
+
+OPENMPT_NAMESPACE_END
diff --git a/common/serialization_utils.cpp b/common/serialization_utils.cpp
index fee60da..91c7d75 100644
--- a/common/serialization_utils.cpp
+++ b/common/serialization_utils.cpp
@@ -42,7 +42,6 @@ static const uint8 HeaderId_FlagByte = 0;
 static inline bool Testbit(uint8 val, uint8 bitindex) {return ((val & (1 << bitindex)) != 0);}
 
 static inline void Setbit(uint8& val, uint8 bitindex, bool newval)
-//----------------------------------------------------------------
 {
 	if(newval) val |= (1 << bitindex);
 	else val &= ~(1 << bitindex);
@@ -50,7 +49,6 @@ static inline void Setbit(uint8& val, uint8 bitindex, bool newval)
 
 
 bool ID::IsPrintable() const
-//--------------------------
 {
 	for(std::size_t i = 0; i < m_ID.length(); ++i)
 	{
@@ -65,7 +63,6 @@ bool ID::IsPrintable() const
 
 //Format: First bit tells whether the size indicator is 1 or 2 bytes.
 static void WriteAdaptive12String(std::ostream& oStrm, const std::string& str)
-//----------------------------------------------------------------------------
 {
 	uint16 s = static_cast<uint16>(str.size());
 	LimitMax(s, uint16(uint16_max / 2));
@@ -75,7 +72,6 @@ static void WriteAdaptive12String(std::ostream& oStrm, const std::string& str)
 
 
 void WriteItemString(std::ostream& oStrm, const std::string &str)
-//---------------------------------------------------------------
 {
 	uint32 id = static_cast<uint32>(std::min<std::size_t>(str.size(), (uint32_max >> 4))) << 4;
 	id |= 12; // 12 == 1100b
@@ -87,7 +83,6 @@ void WriteItemString(std::ostream& oStrm, const std::string &str)
 
 
 void ReadItemString(std::istream& iStrm, std::string& str, const DataSize)
-//--------------------------------------------------------------------
 {
 	// bits 0,1: Bytes per char type: 1,2,3,4.
 	// bits 2,3: Bytes in size indicator, 1,2,3,4
@@ -118,7 +113,6 @@ void ReadItemString(std::istream& iStrm, std::string& str, const DataSize)
 
 
 mpt::ustring ID::AsString() const
-//-------------------------------
 {
 	if(IsPrintable())
 	{
@@ -128,16 +122,10 @@ mpt::ustring ID::AsString() const
 	{
 		return mpt::ustring();
 	}
-	uint64 val = 0;
-	uint8 bytes[8];
-	std::memset(bytes, 0, 8);
-	for(std::size_t i = 0; i < m_ID.length(); ++i)
-	{
-		bytes[i] = m_ID[i];
-	}
-	std::memcpy(&val, bytes, m_ID.length());
-	val = SwapBytesReturnLE(val);
-	return mpt::ToUString(val);
+	uint64le val;
+	val.set(0);
+	std::memcpy(&val, m_ID.data(), m_ID.length());
+	return mpt::ufmt::val(val);
 }
 
 
@@ -200,29 +188,25 @@ SsbRead::SsbRead(std::istream& iStrm)
 
 
 void SsbWrite::AddWriteNote(const SsbStatus s)
-//--------------------------------------------
 {
 	m_Status |= s;
-	SSB_LOG(mpt::String::Print(MPT_USTRING("%1: 0x%2\n"), strWriteNote, mpt::ufmt::hex(s)));
+	SSB_LOG(mpt::format(MPT_USTRING("%1: 0x%2\n"))(strWriteNote, mpt::ufmt::hex(s)));
 }
 
 void SsbRead::AddReadNote(const SsbStatus s)
-//------------------------------------------
 {
 	m_Status |= s;
-	SSB_LOG(mpt::String::Print(MPT_USTRING("%1: 0x%2\n"), strReadNote, mpt::ufmt::hex(s)));
+	SSB_LOG(mpt::format(MPT_USTRING("%1: 0x%2\n"))(strReadNote, mpt::ufmt::hex(s)));
 }
 
 void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum)
-//-----------------------------------------------------------------------
 {
 	m_Status |= SNT_PROGRESS;
-	SSB_LOG(mpt::String::Print<mpt::ustring>(
-				 tstrReadProgress,
+	SSB_LOG(mpt::format(mpt::ustring(tstrReadProgress))(
 				 nNum,
 				 (pRe && pRe->nIdLength < 30 && m_Idarray.size() > 0) ?  ID(&m_Idarray[pRe->nIdpos], pRe->nIdLength).AsString() : MPT_USTRING(""),
 				 (pRe) ? pRe->rposStart : 0,
-				 (pRe && pRe->nSize != invalidDatasize) ? mpt::ToUString(pRe->nSize) : MPT_USTRING(""),
+				 (pRe && pRe->nSize != invalidDatasize) ? mpt::ufmt::val(pRe->nSize) : MPT_USTRING(""),
 				 MPT_USTRING("")));
 #ifndef SSB_LOGGING
 	MPT_UNREFERENCED_PARAMETER(pRe);
@@ -232,10 +216,9 @@ void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum)
 
 // Called after writing an entry.
 void SsbWrite::AddWriteNote(const ID &id, const NumType nEntryNum, const DataSize nBytecount, const RposType rposStart)
-//---------------------------------------------------------------------------------------------------------------------
 {
 	m_Status |= SNT_PROGRESS;
-	SSB_LOG(mpt::String::Print<mpt::ustring>(tstrWriteProgress, nEntryNum, id.AsString(), rposStart, nBytecount));
+	SSB_LOG(mpt::format(mpt::ustring(tstrWriteProgress))(nEntryNum, id.AsString(), rposStart, nBytecount));
 #ifndef SSB_LOGGING
 	MPT_UNREFERENCED_PARAMETER(id);
 	MPT_UNREFERENCED_PARAMETER(nEntryNum);
@@ -246,7 +229,6 @@ void SsbWrite::AddWriteNote(const ID &id, const NumType nEntryNum, const DataSiz
 
 
 void SsbRead::ResetReadstatus()
-//-------------------------
 {
 	m_Status = SNT_NONE;
 	m_Idarray.reserve(32);
@@ -258,9 +240,8 @@ void SsbWrite::WriteMapItem(const ID &id,
 						const RposType& rposDataStart,
 						const DataSize& nDatasize,
 						const char* pszDesc)
-//----------------------------------------
 {
-	SSB_LOG(mpt::String::Print<mpt::ustring>(tstrMapEntryWrite,
+	SSB_LOG(mpt::format(mpt::ustring(tstrMapEntryWrite))(
 					(id.GetSize() > 0) ? id.AsString() : MPT_USTRING(""),
 					rposDataStart,
 					nDatasize));
@@ -292,7 +273,6 @@ void SsbWrite::WriteMapItem(const ID &id,
 
 
 void SsbWrite::IncrementWriteCounter()
-//-------------------------------
 {
 	m_nCounter++;
 	if (m_nCounter >= (uint16_max >> 2))
@@ -304,11 +284,10 @@ void SsbWrite::IncrementWriteCounter()
 
 
 void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion)
-//-------------------------------------------------------------
 {
 	std::ostream& oStrm = *m_pOstrm;
 
-	SSB_LOG(mpt::String::Print<mpt::ustring>(tstrWriteHeader, id.AsString()));
+	SSB_LOG(mpt::format(mpt::ustring(tstrWriteHeader))(id.AsString()));
 
 	ResetWritestatus();
 
@@ -382,7 +361,6 @@ void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion)
 
 
 SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin)
-//--------------------------------------------------------------------------------------------------
 {
 	if (pE != nullptr)
 		AddReadNote(pE, m_nCounter);
@@ -395,7 +373,7 @@ SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Po
 	}
 	else // Entry not found.
 	{
-		SSB_LOG(mpt::String::Print<mpt::ustring>(tstrNoEntryFound, id.AsString()));
+		SSB_LOG(mpt::format(mpt::ustring(tstrNoEntryFound))(id.AsString()));
 #ifndef SSB_LOGGING
 		MPT_UNREFERENCED_PARAMETER(id);
 #endif
@@ -407,7 +385,6 @@ SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Po
 
 
 void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
-//---------------------------------------------------------------------
 {
 	const Offtype nRawEntrySize = m_pOstrm->tellp() - posBeforeWrite;
 
@@ -440,11 +417,10 @@ void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
 
 
 void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
-//-----------------------------------------------------------
 {
 	std::istream& iStrm = *m_pIstrm;
 
-	SSB_LOG(mpt::String::Print<mpt::ustring>(tstrReadingHeader, id.AsString()));
+	SSB_LOG(mpt::format(mpt::ustring(tstrReadingHeader))(id.AsString()));
 
 	ResetReadstatus();
 
@@ -597,7 +573,6 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
 
 
 void SsbRead::CacheMap()
-//----------------------
 {
 	std::istream& iStrm = *m_pIstrm;
 	if(GetFlag(RwfRwHasMap) || m_nFixedEntrySize > 0)
@@ -607,7 +582,7 @@ void SsbRead::CacheMap()
 		if(iStrm.fail())
 			{ AddReadNote(SNR_BADSTREAM_AFTER_MAPHEADERSEEK); return; }
 
-		SSB_LOG(mpt::String::Print<mpt::ustring>(tstrReadingMap, m_rposMapBegin));
+		SSB_LOG(mpt::format(mpt::ustring(tstrReadingMap))(m_rposMapBegin));
 
 		mapData.resize(m_nReadEntrycount);
 		m_Idarray.reserve(m_nReadEntrycount * 4);
@@ -669,7 +644,7 @@ void SsbRead::CacheMap()
 			}
 		}
 		m_posMapEnd = iStrm.tellg();
-		SSB_LOG(mpt::String::Print<mpt::ustring>(tstrEndOfMap, m_posMapEnd - m_posStart));
+		SSB_LOG(mpt::format(mpt::ustring(tstrEndOfMap))(m_posMapEnd - m_posStart));
 	}
 
 	SetFlag(RwfRMapCached, true);
@@ -689,7 +664,6 @@ void SsbRead::CacheMap()
 
 
 const ReadEntry* SsbRead::Find(const ID &id)
-//------------------------------------------
 {
 	m_pIstrm->clear();
 	if (GetFlag(RwfRMapCached) == false)
@@ -718,14 +692,13 @@ const ReadEntry* SsbRead::Find(const ID &id)
 
 
 void SsbWrite::FinishWrite()
-//---------------------
 {
 	std::ostream& oStrm = *m_pOstrm;
 	const Postype posDataEnd = oStrm.tellp();
 		
 	Postype posMapStart = oStrm.tellp();
 
-	SSB_LOG(mpt::String::Print<mpt::ustring>(tstrWritingMap, posMapStart - m_posStart));
+	SSB_LOG(mpt::format(mpt::ustring(tstrWritingMap))(posMapStart - m_posStart));
 
 	if (GetFlag(RwfRwHasMap)) //Write map
 	{
@@ -753,7 +726,7 @@ void SsbWrite::FinishWrite()
 	// Seek to end.
 	oStrm.seekp(std::max<Postype>(posMapEnd, posDataEnd)); 
 
-	SSB_LOG(mpt::String::Print<mpt::ustring>(tstrEndOfStream, oStrm.tellp() - m_posStart));
+	SSB_LOG(mpt::format(mpt::ustring(tstrEndOfStream))(oStrm.tellp() - m_posStart));
 }
 
 } // namespace srlztn 
diff --git a/common/serialization_utils.h b/common/serialization_utils.h
index 97519b8..0d31c68 100644
--- a/common/serialization_utils.h
+++ b/common/serialization_utils.h
@@ -44,7 +44,7 @@ const DataSize invalidDatasize = DataSize(-1);
 
 enum 
 {
-	SNT_PROGRESS =		0x80000000, // = 1 << 31
+	SNT_PROGRESS =		0x08000000, // = 1 << 27
 	SNT_FAILURE =		0x40000000, // = 1 << 30
 	SNT_NOTE =			0x20000000, // = 1 << 29
 	SNT_WARNING =		0x10000000, // = 1 << 28
@@ -85,7 +85,6 @@ typedef int32 SsbStatus;
 
 
 struct ReadEntry
-//==============
 {
 	ReadEntry() : nIdpos(0), rposStart(0), nSize(invalidDatasize), nIdLength(0) {}
 
@@ -116,14 +115,12 @@ enum Rwf
 
 template<class T>
 inline void Binarywrite(std::ostream& oStrm, const T& data)
-//---------------------------------------------------------
 {
 	mpt::IO::WriteIntLE(oStrm, data);
 }
 
 template<>
 inline void Binarywrite(std::ostream& oStrm, const float& data)
-//-------------------------------------------------------------
 {
 	IEEE754binary32LE tmp = IEEE754binary32LE(data);
 	mpt::IO::Write(oStrm, tmp);
@@ -131,7 +128,6 @@ inline void Binarywrite(std::ostream& oStrm, const float& data)
 
 template<>
 inline void Binarywrite(std::ostream& oStrm, const double& data)
-//--------------------------------------------------------------
 {
 	IEEE754binary64LE tmp = IEEE754binary64LE(data);
 	mpt::IO::Write(oStrm, tmp);
@@ -139,11 +135,8 @@ inline void Binarywrite(std::ostream& oStrm, const double& data)
 
 template <class T>
 inline void WriteItem(std::ostream& oStrm, const T& data)
-//-------------------------------------------------------
 {
-	#if MPT_COMPILER_HAS_TYPE_TRAITS
-		static_assert(std::is_trivial<T>::value == true, "");
-	#endif
+	static_assert(std::is_trivial<T>::value == true, "");
 	Binarywrite(oStrm, data);
 }
 
@@ -155,14 +148,12 @@ inline void WriteItem<std::string>(std::ostream& oStrm, const std::string& str)
 
 template<class T>
 inline void Binaryread(std::istream& iStrm, T& data)
-//--------------------------------------------------
 {
 	mpt::IO::ReadIntLE(iStrm, data);
 }
 
 template<>
 inline void Binaryread(std::istream& iStrm, float& data)
-//------------------------------------------------------
 {
 	IEEE754binary32LE tmp = IEEE754binary32LE(0.0f);
 	mpt::IO::Read(iStrm, tmp);
@@ -171,7 +162,6 @@ inline void Binaryread(std::istream& iStrm, float& data)
 
 template<>
 inline void Binaryread(std::istream& iStrm, double& data)
-//-------------------------------------------------------
 {
 	IEEE754binary64LE tmp = IEEE754binary64LE(0.0);
 	mpt::IO::Read(iStrm, tmp);
@@ -181,14 +171,12 @@ inline void Binaryread(std::istream& iStrm, double& data)
 //Read only given number of bytes to the beginning of data; data bytes are memset to 0 before reading.
 template <class T>
 inline void Binaryread(std::istream& iStrm, T& data, const Offtype bytecount)
-//---------------------------------------------------------------------------
 {
 	mpt::IO::ReadBinaryTruncatedLE(iStrm, data, static_cast<std::size_t>(bytecount));
 }
 
 template <>
 inline void Binaryread<float>(std::istream& iStrm, float& data, const Offtype bytecount)
-//--------------------------------------------------------------------------------------
 {
 	typedef IEEE754binary32LE T;
 	mpt::byte bytes[sizeof(T)];
@@ -201,7 +189,6 @@ inline void Binaryread<float>(std::istream& iStrm, float& data, const Offtype by
 
 template <>
 inline void Binaryread<double>(std::istream& iStrm, double& data, const Offtype bytecount)
-//----------------------------------------------------------------------------------------
 {
 	typedef IEEE754binary64LE T;
 	mpt::byte bytes[sizeof(T)];
@@ -215,11 +202,8 @@ inline void Binaryread<double>(std::istream& iStrm, double& data, const Offtype
 
 template <class T>
 inline void ReadItem(std::istream& iStrm, T& data, const DataSize nSize)
-//----------------------------------------------------------------------
 {
-	#if MPT_COMPILER_HAS_TYPE_TRAITS
-		static_assert(std::is_trivial<T>::value == true, "");
-	#endif
+	static_assert(std::is_trivial<T>::value == true, "");
 	if (nSize == sizeof(T) || nSize == invalidDatasize)
 		Binaryread(iStrm, data);
 	else
@@ -230,7 +214,6 @@ void ReadItemString(std::istream& iStrm, std::string& str, const DataSize);
 
 template <>
 inline void ReadItem<std::string>(std::istream& iStrm, std::string& str, const DataSize nSize)
-//--------------------------------------------------------------------------------------------
 {
 	ReadItemString(iStrm, str, nSize);
 }
@@ -251,12 +234,9 @@ public:
 	static ID FromInt(const T &val)
 	{
 		STATIC_ASSERT(std::numeric_limits<T>::is_integer);
-		char bytes[sizeof(T)];
-		std::memcpy(bytes, &val, sizeof(T));
-		#ifdef MPT_PLATFORM_BIG_ENDIAN
-			std::reverse(bytes, bytes + sizeof(T));
-		#endif
-		return ID(bytes, bytes + sizeof(T));
+		typename mpt::make_le<T>::type valle;
+		valle = val;
+		return ID(std::string(mpt::as_raw_memory(valle), mpt::as_raw_memory(valle) + sizeof(valle)));
 	}
 	bool IsPrintable() const;
 	mpt::ustring AsString() const;
@@ -468,7 +448,6 @@ private:
 
 template <class T, class FuncObj>
 void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func)
-//----------------------------------------------------------------
 {
 	const Postype pos = m_pOstrm->tellp();
 	Func(*m_pOstrm, obj);
@@ -477,7 +456,6 @@ void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func)
 
 template <class T, class FuncObj>
 SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
-//-------------------------------------------------------------------
 {
 	const ReadEntry* pE = Find(id);
 	const Postype pos = m_pIstrm->tellg();
@@ -489,7 +467,6 @@ SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
 
 template <class T, class FuncObj>
 SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func)
-//-----------------------------------------------------------------------------------
 {
 	m_pIstrm->clear();
 	if (iter->rposStart != 0)
@@ -501,7 +478,6 @@ SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj
 
 
 inline SsbRead::IdMatchStatus SsbRead::CompareId(const ReadIterator& iter, const ID &id)
-//--------------------------------------------------------------------------------------
 {
 	if(iter->nIdpos >= m_Idarray.size()) return IdMismatch;
 	return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)) ? IdMatch : IdMismatch;
@@ -509,7 +485,6 @@ inline SsbRead::IdMatchStatus SsbRead::CompareId(const ReadIterator& iter, const
 
 
 inline SsbRead::ReadIterator SsbRead::GetReadBegin()
-//--------------------------------------------------
 {
 	MPT_ASSERT(GetFlag(RwfRMapHasId) && (GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0));
 	if (GetFlag(RwfRMapCached) == false)
@@ -519,7 +494,6 @@ inline SsbRead::ReadIterator SsbRead::GetReadBegin()
 
 
 inline SsbRead::ReadIterator SsbRead::GetReadEnd()
-//------------------------------------------------
 {
 	if (GetFlag(RwfRMapCached) == false)
 		CacheMap();
@@ -528,14 +502,29 @@ inline SsbRead::ReadIterator SsbRead::GetReadEnd()
 
 
 template <class T>
-struct ArrayWriter
-//================
+struct VectorWriter
 {
-	ArrayWriter(size_t nCount) : m_nCount(nCount) {}
-	void operator()(std::ostream& oStrm, const T* pData) {
-		for(std::size_t i=0; i<m_nCount; ++i)
+	VectorWriter(size_t nCount) : m_nCount(nCount) {}
+	void operator()(std::ostream &oStrm, const std::vector<T> &vec)
+	{
+		for(size_t i = 0; i < m_nCount; i++)
+		{
+			Binarywrite(oStrm, vec[i]);
+		}
+	}
+	size_t m_nCount;
+};
+
+template <class T>
+struct VectorReader
+{
+	VectorReader(size_t nCount) : m_nCount(nCount) {}
+	void operator()(std::istream& iStrm, std::vector<T> &vec, const size_t)
+	{
+		vec.resize(m_nCount);
+		for(std::size_t i = 0; i < m_nCount; ++i)
 		{
-			Binarywrite(oStrm, pData[i]);
+			Binaryread(iStrm, vec[i]);
 		}
 	}
 	size_t m_nCount;
@@ -543,10 +532,10 @@ struct ArrayWriter
 
 template <class T>
 struct ArrayReader
-//================
 {
 	ArrayReader(size_t nCount) : m_nCount(nCount) {}
-	void operator()(std::istream& iStrm, T* pData, const size_t) {
+	void operator()(std::istream& iStrm, T* pData, const size_t)
+	{
 		for(std::size_t i=0; i<m_nCount; ++i)
 		{
 			Binaryread(iStrm, pData[i]);
diff --git a/common/stdafx.h b/common/stdafx.h
index 34d6f9a..8cf4b5d 100644
--- a/common/stdafx.h
+++ b/common/stdafx.h
@@ -22,6 +22,7 @@
 
 #if !defined(MPT_BUILD_WINESUPPORT)
 
+#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS	// Do not include support for MFC controls in dialogs (reduces binary bloat; remove this #define if you want to use MFC controls)
 #include <afxwin.h>         // MFC core and standard components
 #include <afxext.h>         // MFC extensions
 #include <afxcmn.h>			// MFC support for Windows Common Controls
@@ -60,11 +61,13 @@ struct IUnknown;
 #include "../common/typedefs.h"
 // <memory>
 // <new>
+// <climits>
+// <cstddef>
 // <cstdint>
 // <stdint.h>
 
 #include "../common/mptTypeTraits.h"
-// <type_traits> // if available
+// <type_traits>
 
 #include "../common/mptString.h"
 // <algorithm>
@@ -110,9 +113,7 @@ struct IUnknown;
 // nonetheless. Pre-include the affected headers here as a future-proof
 // safe-guard and let their own include guards handle the further including by
 // VST SDK.
-#if !((MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2010,0)) || (MPT_COMPILER_GCC && MPT_GCC_BEFORE(4,3,0)))
 #include <cstdint>
-#endif
 #include <stdint.h>
 #include <cstring>
 #include <string.h>
diff --git a/common/typedefs.cpp b/common/typedefs.cpp
index 76521d5..70e9dbb 100644
--- a/common/typedefs.cpp
+++ b/common/typedefs.cpp
@@ -11,9 +11,39 @@
 #include "stdafx.h"
 #include "typedefs.h"
 
+#include "Endianness.h"
+
 
 OPENMPT_NAMESPACE_BEGIN
 
+#if MPT_PLATFORM_ENDIAN_KNOWN
+
 MPT_MSVC_WORKAROUND_LNK4221(typedefs)
 
+#else
+
+int24::int24(int other)
+{
+	MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big()) {
+		bytes[0] = (static_cast<unsigned int>(other)>>16)&0xff;
+		bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff;
+		bytes[2] = (static_cast<unsigned int>(other)>> 0)&0xff;
+	} else {
+		bytes[0] = (static_cast<unsigned int>(other)>> 0)&0xff;
+		bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff;
+		bytes[2] = (static_cast<unsigned int>(other)>>16)&0xff;
+	}
+}
+
+int24::operator int() const
+{
+	MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big()) {
+		return (static_cast<int8>(bytes[0]) * 65536) + (bytes[1] * 256) + bytes[2];
+	} else {
+		return (static_cast<int8>(bytes[2]) * 65536) + (bytes[1] * 256) + bytes[0];
+	}
+}
+
+#endif
+
 OPENMPT_NAMESPACE_END
diff --git a/common/typedefs.h b/common/typedefs.h
index c2ec0ef..bb84ba6 100644
--- a/common/typedefs.h
+++ b/common/typedefs.h
@@ -16,62 +16,60 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 
-// Platform has native IEEE floating point representation.
-// (Currently always assumed)
-#define MPT_PLATFORM_IEEE_FLOAT 1
-
-
-
+// Advanced inline attributes
 #if MPT_COMPILER_MSVC
-
-#if MPT_MSVC_BEFORE(2010,0)
-#define nullptr 0
-#endif
-
-#elif MPT_COMPILER_GCC
-
-#if MPT_GCC_BEFORE(4,6,0)
-#define nullptr 0
-#endif
-
+#define MPT_FORCEINLINE __forceinline
+#define MPT_NOINLINE    __declspec(noinline)
+#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
+#define MPT_FORCEINLINE __attribute__((always_inline)) inline
+#define MPT_NOINLINE    __attribute__((noinline))
+#else
+#define MPT_FORCEINLINE inline
+#define MPT_NOINLINE
 #endif
 
 
 
-//  CountOf macro computes the number of elements in a statically-allocated array.
-#if MPT_COMPILER_MSVC
-	#define CountOf(x) _countof(x)
+// constexpr
+#define MPT_CONSTEXPR11_FUN constexpr MPT_FORCEINLINE
+#define MPT_CONSTEXPR11_VAR constexpr
+#if MPT_CXX_AT_LEAST(14)
+#define MPT_CONSTEXPR14_FUN constexpr MPT_FORCEINLINE
+#define MPT_CONSTEXPR14_VAR constexpr
 #else
-	#define CountOf(x) (sizeof((x))/sizeof((x)[0]))
+#define MPT_CONSTEXPR14_FUN MPT_FORCEINLINE
+#define MPT_CONSTEXPR14_VAR const
 #endif
 
 
 
-#if MPT_COMPILER_MSVC
-#define PACKED __declspec(align(1))
-#define NEEDS_PRAGMA_PACK
-#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
-#if MPT_COMPILER_GCC && MPT_OS_WINDOWS
-// Some versions of mingw64 need this when windows-hosted. Strange.
-#define NEEDS_PRAGMA_PACK
-#endif
-#define PACKED __attribute__((packed)) __attribute__((aligned(1)))
-#else
-#define PACKED alignas(1)
-#endif
+// C++17 std::size
+OPENMPT_NAMESPACE_END
+#include <cstddef>
+OPENMPT_NAMESPACE_BEGIN
+namespace mpt {
+template <typename T>
+MPT_CONSTEXPR11_FUN auto size(const T & v) -> decltype(v.size())
+{
+	return v.size();
+}
+template <typename T, std::size_t N>
+MPT_CONSTEXPR11_FUN std::size_t size(const T(&)[N]) noexcept
+{
+	return N;
+}
+} // namespace mpt
 
 
 
-// Advanced inline attributes
+// MPT_ARRAY_COUNT macro computes the number of elements in a statically-allocated array.
 #if MPT_COMPILER_MSVC
-#define forceinline __forceinline
-#define MPT_NOINLINE __declspec(noinline)
-#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
-#define forceinline __attribute__((always_inline)) inline
-#define MPT_NOINLINE __attribute__((noinline))
+OPENMPT_NAMESPACE_END
+#include <cstdlib>
+OPENMPT_NAMESPACE_BEGIN
+#define MPT_ARRAY_COUNT(x) _countof(x)
 #else
-#define forceinline inline
-#define MPT_NOINLINE
+#define MPT_ARRAY_COUNT(x) (sizeof((x))/sizeof((x)[0]))
 #endif
 
 
@@ -107,151 +105,26 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 
-// Exception type that is used to catch "operator new" exceptions.
-#if defined(_MFC_VER)
-typedef CMemoryException * MPTMemoryException;
-#else
-OPENMPT_NAMESPACE_END
-#include <new>
-OPENMPT_NAMESPACE_BEGIN
-typedef std::bad_alloc & MPTMemoryException;
-#endif
-
-
-
-// For mpt::make_shared<T>, we sacrifice perfect forwarding in order to keep things simple here.
-// Templated for up to 4 parameters. Add more when required.
-
 OPENMPT_NAMESPACE_END
 #include <memory>
+#include <utility>
 OPENMPT_NAMESPACE_BEGIN
 
-#if MPT_COMPILER_GCC && MPT_GCC_BEFORE(4,3,0)
-OPENMPT_NAMESPACE_END
-#include <tr1/memory>
-OPENMPT_NAMESPACE_BEGIN
-#endif
 
-#if (MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2010,0)) || (MPT_COMPILER_GCC && MPT_GCC_BEFORE(4,3,0))
 
-#define MPT_SHARED_PTR std::tr1::shared_ptr
-#define MPT_CONST_POINTER_CAST std::tr1::const_pointer_cast
-#define MPT_STATIC_POINTER_CAST std::tr1::static_pointer_cast
-#define MPT_DYNAMIC_POINTER_CAST std::tr1::dynamic_pointer_cast
+#if MPT_CXX_AT_LEAST(14)
 namespace mpt {
-template <typename T> inline MPT_SHARED_PTR<T> make_shared() { return MPT_SHARED_PTR<T>(new T()); }
-template <typename T, typename T1> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1) { return MPT_SHARED_PTR<T>(new T(x1)); }
-template <typename T, typename T1, typename T2> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1, const T2 &x2) { return MPT_SHARED_PTR<T>(new T(x1, x2)); }
-template <typename T, typename T1, typename T2, typename T3> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1, const T2 &x2, const T3 &x3) { return MPT_SHARED_PTR<T>(new T(x1, x2, x3)); }
-template <typename T, typename T1, typename T2, typename T3, typename T4> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1, const T2 &x2, const T3 &x3, const T4 &x4) { return MPT_SHARED_PTR<T>(new T(x1, x2, x3, x4)); }
+using std::make_unique;
 } // namespace mpt
-
 #else
-
-#define MPT_SHARED_PTR std::shared_ptr
-#define MPT_CONST_POINTER_CAST std::const_pointer_cast
-#define MPT_STATIC_POINTER_CAST std::static_pointer_cast
-#define MPT_DYNAMIC_POINTER_CAST std::dynamic_pointer_cast
-namespace mpt {
-template <typename T> inline MPT_SHARED_PTR<T> make_shared() { return std::make_shared<T>(); }
-template <typename T, typename T1> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1) { return std::make_shared<T>(x1); }
-template <typename T, typename T1, typename T2> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1, const T2 &x2) { return std::make_shared<T>(x1, x2); }
-template <typename T, typename T1, typename T2, typename T3> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1, const T2 &x2, const T3 &x3) { return std::make_shared<T>(x1, x2, x3); }
-template <typename T, typename T1, typename T2, typename T3, typename T4> inline MPT_SHARED_PTR<T> make_shared(const T1 &x1, const T2 &x2, const T3 &x3, const T4 &x4) { return std::make_shared<T>(x1, x2, x3, x4); }
-} // namespace mpt
-
-#endif
-
-// We cannot provide unique_ptr as it does require move semantics.
-// However, we can provide a simple scoped_ptr which is also very useful.
 namespace mpt {
-template<typename T> class scoped_ptr
+template<typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args)
 {
-private:
-	// Copying is not supported.
-	MPT_DEPRECATED scoped_ptr(const scoped_ptr & other) : m_p(other.m_p) {} // = delete
-	// Copying is not supported.
-	MPT_DEPRECATED scoped_ptr & operator=(const scoped_ptr & other) { m_p = other.m_p; return *this; } // = delete
-public:
-	typedef T element_type;
-	class initializer_impl
-	{
-		friend class scoped_ptr<element_type>;
-	private:
-		element_type * m_p;
-	private:
-		inline initializer_impl(const initializer_impl & other) : m_p(other.m_p) {}
-		inline initializer_impl & operator=(const initializer_impl & other) { m_p = other.m_p; return *this; }
-	public:
-		explicit initializer_impl(T * p) : m_p(p) {}
-	public:
-		template <typename Tobj> static inline typename mpt::scoped_ptr<T>::initializer_impl make() { return mpt::scoped_ptr<T>::initializer_impl(new Tobj()); }
-		template <typename Tobj, typename T1> static inline typename mpt::scoped_ptr<T>::initializer_impl make(const T1 &x1) { return mpt::scoped_ptr<T>::initializer_impl(new Tobj(x1)); }
-		template <typename Tobj, typename T1, typename T2> static inline typename mpt::scoped_ptr<T>::initializer_impl make(const T1 &x1, const T2 &x2) { return mpt::scoped_ptr<T>::initializer_impl(new Tobj(x1, x2)); }
-		template <typename Tobj, typename T1, typename T2, typename T3> static inline typename mpt::scoped_ptr<T>::initializer_impl make(const T1 &x1, const T2 &x2, const T3 &x3) { return mpt::scoped_ptr<T>::initializer_impl(new Tobj(x1, x2, x3)); }
-		template <typename Tobj, typename T1, typename T2, typename T3, typename T4> static inline typename mpt::scoped_ptr<T>::initializer_impl make(const T1 &x1, const T2 &x2, const T3 &x3, const T4 &x4) { return mpt::scoped_ptr<T>::initializer_impl(new Tobj(x1, x2, x3, x4)); }
-	};
-	class initializer_impl_result
-	{
-		friend class scoped_ptr<element_type>;
-	private:
-		element_type * m_p;
-	public:
-		inline initializer_impl_result(const initializer_impl_result & other) : m_p(other.m_p) {}
-	private:
-		MPT_DEPRECATED initializer_impl_result & operator=(const initializer_impl_result & other ) { m_p = other.m_p; return *this; } // = delete
-	public:
-		inline initializer_impl_result(const initializer_impl & other) : m_p(other.m_p) {}
-		inline initializer_impl_result & operator=(const initializer_impl & other) { m_p = other.m_p; return *this; }
-	public:
-		explicit initializer_impl_result(T * p) : m_p(p) {}
-	};
-	class initializer
-	{
-		friend class scoped_ptr<element_type>;
-	private:
-		element_type * m_p;
-	private:
-		MPT_DEPRECATED initializer(const initializer & /* other */ ) {} // = delete
-		MPT_DEPRECATED initializer & operator=(const initializer & /* other */ ) {return *this;} // = delete
-	public:
-		inline initializer(const initializer_impl_result & other) : m_p(other.m_p) {}
-		inline initializer & operator=(const initializer_impl_result & other) { m_p = other.m_p; return *this; }
-	public:
-		explicit initializer(T * p) : m_p(p) {}
-	};
-private:
-	element_type * m_p;
-public:
-	// Creates a scoped_ptr without any owned object.
-	scoped_ptr() : m_p(nullptr) {}
-	// Creates a scoped_ptr and assumes ownership of p (if p != nulltr).
-	explicit scoped_ptr(T * p) : m_p(p) {}
-	// Deletes the currently owned object (if any).
-	~scoped_ptr() { if(m_p) { delete m_p; m_p = nullptr; } }
-	// Deletes the currently owned object (if any), and assumes ownership of the passed object p (if any).
-	void reset(T * p = nullptr) { if(m_p) { delete m_p; m_p = nullptr; } m_p = p; }
-	// Returns a reference to the owned object. Behaviour is undefined if there is no owned object.
-	T & operator*() const { return *m_p; }
-	// Returns a pointer to the owned object, or nullptr if there is not any owned object. Ownership is not transferred.
-	T * operator->() const { return m_p; }
-	// Returns a pointer to the owned object, or nullptr if there is not any owned object. Ownership is not transferred.
-	T * get() const { return m_p; }
-	// Give away ownership of the owned object.
-	T * release() { T * ret = m_p; m_p = nullptr; return ret; }
-	// Creates a scoped_ptr and assumes ownership of the passed object init (if any).
-	scoped_ptr (const initializer & init) : m_p(init.m_p) {}
-	// Deletes the currently owned object (if any), and assumes ownership of the passed object init (if any).
-	scoped_ptr & operator=(const initializer & init) { if(m_p) { delete m_p; m_p = nullptr; } m_p = init.m_p; return *this; }
-	// Returns true iff the scoped_ptr currently owns an object (i.e. same as (bool)p).
-	operator bool() const { return m_p ? true : false; }
-};
-template <typename T> inline typename mpt::scoped_ptr<T>::initializer_impl_result make_scoped() { typedef typename mpt::scoped_ptr<T>::initializer_impl init; return init::template make<T>(); }
-template <typename T, typename T1> inline typename mpt::scoped_ptr<T>::initializer_impl_result make_scoped(const T1 &x1) { typedef typename mpt::scoped_ptr<T>::initializer_impl init; return init::template make<T>(x1); }
-template <typename T, typename T1, typename T2> inline typename mpt::scoped_ptr<T>::initializer_impl_result make_scoped(const T1 &x1, const T2 &x2) { typedef typename mpt::scoped_ptr<T>::initializer_impl init; return init::template make<T>(x1, x2); }
-template <typename T, typename T1, typename T2, typename T3> inline typename mpt::scoped_ptr<T>::initializer_impl_result make_scoped(const T1 &x1, const T2 &x2, const T3 &x3) { typedef typename mpt::scoped_ptr<T>::initializer_impl init; return init::template make<T>(x1, x2, x3); }
-template <typename T, typename T1, typename T2, typename T3, typename T4> inline typename mpt::scoped_ptr<T>::initializer_impl_result make_scoped(const T1 &x1, const T2 &x2, const T3 &x3, const T4 &x4) { typedef typename mpt::scoped_ptr<T>::initializer_impl init; return init::template make<T>(x1, x2, x3, x4); }
+	return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
 } // namespace mpt
+#endif
 
 
 
@@ -271,24 +144,12 @@ template <typename T, typename T1, typename T2, typename T3, typename T4> inline
 #endif
 
 #if MPT_COMPILER_GCC
-#if MPT_GCC_AT_LEAST(4,6,0)
 #define MPT_MAYBE_CONSTANT_IF(x) \
   _Pragma("GCC diagnostic push") \
   _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
   if(x) \
   _Pragma("GCC diagnostic pop") \
 /**/
-#elif MPT_GCC_AT_LEAST(4,5,0)
-#define MPT_MAYBE_CONSTANT_IF(x) \
-  _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
-  if(x) \
-/**/
-#elif MPT_GCC_AT_LEAST(4,4,0)
-// GCC 4.4 does not like _Pragma diagnostic inside functions.
-// As GCC 4.4 is one of our major compilers, we do not want a noisy build.
-// Thus, just disable this warning globally. (not required for now)
-//#pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
 #endif
 
 #if MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
@@ -331,6 +192,40 @@ template <typename T, typename T1, typename T2, typename T3, typename T4> inline
 
 
 
+#if MPT_COMPILER_MSVC && defined(UNREFERENCED_PARAMETER)
+#define MPT_UNREFERENCED_PARAMETER(x) UNREFERENCED_PARAMETER(x)
+#else
+#define MPT_UNREFERENCED_PARAMETER(x) (void)(x)
+#endif
+
+#define MPT_UNUSED_VARIABLE(x) MPT_UNREFERENCED_PARAMETER(x)
+
+
+
+// Exception handling helpers, because MFC requires explicit deletion of the exception object,
+// Thus, always call exactly one of MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() or MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e).
+
+#if defined(_MFC_VER)
+
+#define MPT_EXCEPTION_THROW_OUT_OF_MEMORY()   MPT_DO { AfxThrowMemoryException(); } MPT_WHILE_0
+#define MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)  catch ( CMemoryException * e )
+#define MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() MPT_DO { throw; } MPT_WHILE_0
+#define MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e) MPT_DO { if(e) { e->Delete(); e = nullptr; } } MPT_WHILE_0
+
+#else // !_MFC_VER
+
+OPENMPT_NAMESPACE_END
+#include <new>
+OPENMPT_NAMESPACE_BEGIN
+#define MPT_EXCEPTION_THROW_OUT_OF_MEMORY()   MPT_DO { throw std::bad_alloc(); } MPT_WHILE_0
+#define MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)  catch ( const std::bad_alloc & e )
+#define MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() MPT_DO { throw; } MPT_WHILE_0
+#define MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e) MPT_DO { MPT_UNUSED_VARIABLE(e); } MPT_WHILE_0
+
+#endif // _MFC_VER
+
+
+
 // Static code checkers might need to get the knowledge of our assertions transferred to them.
 #define MPT_CHECKER_ASSUME_ASSERTIONS 1
 //#define MPT_CHECKER_ASSUME_ASSERTIONS 0
@@ -347,7 +242,7 @@ template <typename T, typename T1, typename T2, typename T3, typename T4> inline
 
 #if MPT_CHECKER_ASSUME_ASSERTIONS
 #ifdef NDEBUG
-#error "Builds for static analyzers depend on std::asert being enabled, but the current build has #define NDEBUG. This makes no sense."
+#error "Builds for static analyzers depend on std::assert being enabled, but the current build has #define NDEBUG. This makes no sense."
 #endif
 OPENMPT_NAMESPACE_END
 #include <cassert>
@@ -445,16 +340,10 @@ MPT_NOINLINE void AssertHandler(const char *file, int line, const char *function
 #endif // MPT_ASSERT_HANDLER_NEEDED
 
 
+
 // Compile time assert.
-#if (MPT_COMPILER_GCC && MPT_GCC_BEFORE(4,3,0))
-	#define MPT_SA_CONCAT(x, y) x ## y
-	#define MPT_SA_HELPER(x) MPT_SA_CONCAT(OPENMPT_STATIC_ASSERT_, x)
-	#define OPENMPT_STATIC_ASSERT MPT_SA_HELPER(__LINE__)
-	#define static_assert(expr, msg) typedef char OPENMPT_STATIC_ASSERT[(expr)?1:-1]
-#elif (MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2010,0))
-	#define static_assert(expr, msg) typedef char OPENMPT_STATIC_ASSERT[(expr)?1:-1]
-#endif
-#define STATIC_ASSERT(expr) static_assert((expr), "compile time assertion failed: " #expr)
+#define MPT_STATIC_ASSERT(expr) static_assert((expr), "compile time assertion failed: " #expr)
+
 
 
 // Macro for marking intentional fall-throughs in switch statements - can be used for static analysis if supported.
@@ -462,31 +351,22 @@ MPT_NOINLINE void AssertHandler(const char *file, int line, const char *function
 #define MPT_FALLTHROUGH __fallthrough
 #elif MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
 #define MPT_FALLTHROUGH [[clang::fallthrough]]
+#elif defined(__has_cpp_attribute)
+	#if __has_cpp_attribute(fallthrough)
+	#define MPT_FALLTHROUGH [[fallthrough]]
+	#else
+	#define MPT_FALLTHROUGH MPT_DO { } MPT_WHILE_0
+	#endif
 #else
 #define MPT_FALLTHROUGH MPT_DO { } MPT_WHILE_0
 #endif
 
 
 
-#if (MPT_COMPILER_MSVC && MPT_MSVC_BEFORE(2010,0)) || (MPT_COMPILER_GCC && MPT_GCC_BEFORE(4,3,0))
-
-OPENMPT_NAMESPACE_END
-#include "stdint.h"
-OPENMPT_NAMESPACE_BEGIN
-
-typedef int8_t   int8;
-typedef int16_t  int16;
-typedef int32_t  int32;
-typedef int64_t  int64;
-typedef uint8_t  uint8;
-typedef uint16_t uint16;
-typedef uint32_t uint32;
-typedef uint64_t uint64;
-
-#else
-
 OPENMPT_NAMESPACE_END
+#include <climits>
 #include <cstdint>
+#include <stdint.h>
 OPENMPT_NAMESPACE_BEGIN
 
 typedef std::int8_t   int8;
@@ -498,12 +378,6 @@ typedef std::uint16_t uint16;
 typedef std::uint32_t uint32;
 typedef std::uint64_t uint64;
 
-#endif
-
-OPENMPT_NAMESPACE_END
-#include <stdint.h>
-OPENMPT_NAMESPACE_BEGIN
-
 const int8 int8_min     = INT8_MIN;
 const int16 int16_min   = INT16_MIN;
 const int32 int32_min   = INT32_MIN;
@@ -525,6 +399,7 @@ struct int24
 {
 	uint8 bytes[3];
 	int24() { bytes[0] = bytes[1] = bytes[2] = 0; }
+#if MPT_PLATFORM_ENDIAN_KNOWN
 	explicit int24(int other)
 	{
 		#ifdef MPT_PLATFORM_BIG_ENDIAN
@@ -545,47 +420,94 @@ struct int24
 			return (static_cast<int8>(bytes[2]) * 65536) + (bytes[1] * 256) + bytes[0];
 		#endif
 	}
+#else
+	explicit int24(int other);
+	operator int() const;
+#endif
 };
-STATIC_ASSERT(sizeof(int24) == 3);
+MPT_STATIC_ASSERT(sizeof(int24) == 3);
 #define int24_min (0-0x00800000)
 #define int24_max (0+0x007fffff)
 
 
 typedef float float32;
-STATIC_ASSERT(sizeof(float32) == 4);
+MPT_STATIC_ASSERT(sizeof(float32) == 4);
 
 typedef double float64;
-STATIC_ASSERT(sizeof(float64) == 8);
+MPT_STATIC_ASSERT(sizeof(float64) == 8);
 
 
+MPT_STATIC_ASSERT(sizeof(std::uintptr_t) == sizeof(void*));
+
 
 namespace mpt {
 
-STATIC_ASSERT(sizeof(char) == 1);
+MPT_STATIC_ASSERT(CHAR_BIT == 8);
+
+MPT_STATIC_ASSERT(sizeof(char) == 1);
 
 typedef unsigned char byte;
-STATIC_ASSERT(sizeof(mpt::byte) == 1);
+MPT_STATIC_ASSERT(sizeof(mpt::byte) == 1);
 
 } // namespace mpt
 
 
 
-#if MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
-#define MPT_PRINTF_FUNC(formatstringindex,varargsindex) __attribute__((format(printf, formatstringindex, varargsindex)))
-#else
-#define MPT_PRINTF_FUNC(formatstringindex,varargsindex)
-#endif
+#if MPT_COMPILER_MSVC
 
+	#if defined(_M_X64)
+		#define MPT_ARCH_BITS 64
+		#define MPT_ARCH_BITS_32 0
+		#define MPT_ARCH_BITS_64 1
+	#elif defined(_M_IX86)
+		#define MPT_ARCH_BITS 32
+		#define MPT_ARCH_BITS_32 1
+		#define MPT_ARCH_BITS_64 0
+	#endif
 
+#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
 
-#if MPT_COMPILER_MSVC && defined(UNREFERENCED_PARAMETER)
-#define MPT_UNREFERENCED_PARAMETER(x) UNREFERENCED_PARAMETER(x)
+	#if defined(__SIZEOF_POINTER__)
+		#if (__SIZEOF_POINTER__ == 8)
+			#define MPT_ARCH_BITS 64
+			#define MPT_ARCH_BITS_32 0
+			#define MPT_ARCH_BITS_64 1
+		#elif (__SIZEOF_POINTER__ == 4)
+			#define MPT_ARCH_BITS 32
+			#define MPT_ARCH_BITS_32 1
+			#define MPT_ARCH_BITS_64 0
+		#endif
+	#endif
+
+#endif // MPT_COMPILER
+
+// fallback
+
+#if !defined(MPT_ARCH_BITS)
+#include <cstdint>
+#include <stdint.h>
+MPT_STATIC_ASSERT(sizeof(std::uintptr_t) == sizeof(void*));
+#if defined(UINTPTR_MAX)
+	#if (UINTPTR_MAX == 0xffffffffffffffffull)
+		#define MPT_ARCH_BITS 64
+		#define MPT_ARCH_BITS_32 0
+		#define MPT_ARCH_BITS_64 1
+	#elif (UINTPTR_MAX == 0xffffffffu)
+		#define MPT_ARCH_BITS 32
+		#define MPT_ARCH_BITS_32 1
+		#define MPT_ARCH_BITS_64 0
+	#endif
+#endif // UINTPTR_MAX
+#endif // MPT_ARCH_BITS
+
+
+
+#if MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
+#define MPT_PRINTF_FUNC(formatstringindex,varargsindex) __attribute__((format(printf, formatstringindex, varargsindex)))
 #else
-#define MPT_UNREFERENCED_PARAMETER(x) (void)(x)
+#define MPT_PRINTF_FUNC(formatstringindex,varargsindex)
 #endif
 
-#define MPT_UNUSED_VARIABLE(x) MPT_UNREFERENCED_PARAMETER(x)
-
 
 
 #if MPT_COMPILER_MSVC
@@ -609,4 +531,10 @@ STATIC_ASSERT(sizeof(mpt::byte) == 1);
 
 
 
+// legacy
+#define CountOf(x) MPT_ARRAY_COUNT(x)
+#define STATIC_ASSERT(x) MPT_STATIC_ASSERT(x)
+
+
+
 OPENMPT_NAMESPACE_END
diff --git a/common/version.cpp b/common/version.cpp
index b61b495..0639064 100644
--- a/common/version.cpp
+++ b/common/version.cpp
@@ -61,6 +61,23 @@ std::string ToStr(const VersionNum v)
 	}
 }
 
+mpt::ustring ToUString(const VersionNum v)
+{
+	if(v == 0)
+	{
+		// Unknown version
+		return MPT_USTRING("Unknown");
+	} else if((v & 0xFFFF) == 0)
+	{
+		// Only parts of the version number are known (e.g. when reading the version from the IT or S3M file header)
+		return mpt::format(MPT_USTRING("%1.%2"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF));
+	} else
+	{
+		// Full version info available
+		return mpt::format(MPT_USTRING("%1.%2.%3.%4"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF), mpt::ufmt::HEX0<2>((v >> 8) & 0xFF), mpt::ufmt::HEX0<2>((v) & 0xFF));
+	}
+}
+
 VersionNum RemoveBuildNumber(const VersionNum num_)
 {
 	return (num_ & 0xFFFFFF00);
@@ -300,8 +317,6 @@ std::string GetBuildFeaturesString()
 		#endif
 		#if defined(MPT_WITH_MPG123)
 			retval += " +MPG123";
-		#elif defined(MPT_ENABLE_MPG123_DYNBIND)
-			retval += " +MPG123-DYNBIND";
 		#endif
 		#if defined(MPT_WITH_MINIMP3)
 			retval += " +MINIMP3";
@@ -309,7 +324,7 @@ std::string GetBuildFeaturesString()
 		#if defined(MPT_WITH_MEDIAFOUNDATION)
 			retval += " +MF";
 		#endif
-		#if !defined(MPT_WITH_MPG123) && !defined(MPT_ENABLE_MPG123_DYNBIND) && !defined(MPT_WITH_MINIMP3) && !defined(MPT_WITH_MEDIAFOUNDATION)
+		#if !defined(MPT_WITH_MPG123) && !defined(MPT_WITH_MINIMP3) && !defined(MPT_WITH_MEDIAFOUNDATION)
 			retval += " -MP3";
 		#endif
 		#if defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
@@ -321,17 +336,6 @@ std::string GetBuildFeaturesString()
 		#if !(defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)) && !defined(MPT_WITH_STBVORBIS)
 			retval += " -VORBIS";
 		#endif
-		#if defined(MPT_ENABLE_MO3_BUILTIN)
-			retval += " +MO3";
-		#endif
-		#if defined(MPT_WITH_UNMO3)
-			retval += " +UNMO3";
-		#elif defined(MPT_ENABLE_UNMO3_DYNBIND)
-			retval += " +UNMO3-DYNBIND";
-		#endif
-		#if !defined(MPT_WITH_UNMO3) && !defined(MPT_ENABLE_UNMO3_DYNBIND) && !defined(MPT_ENABLE_MO3_BUILTIN)
-			retval += " -MO3";
-		#endif
 		#if !defined(NO_PLUGINS)
 			retval += " +PLUGINS";
 		#else
@@ -342,10 +346,26 @@ std::string GetBuildFeaturesString()
 		#endif
 	#endif
 	#ifdef MODPLUG_TRACKER
-		if(IsForOlderWindows())
-		{
-			retval += " OLDWIN";
-		}
+		#if (MPT_ARCH_BITS == 64)
+			if (true
+				&& (mpt::Windows::Version::GetMinimumKernelLevel() <= mpt::Windows::Version::WinXP64)
+				&& (mpt::Windows::Version::GetMinimumAPILevel() <= mpt::Windows::Version::WinXP64)
+			) {
+				retval += " WIN64OLD";
+			}
+		#elif (MPT_ARCH_BITS == 32)
+			if (true
+				&& (mpt::Windows::Version::GetMinimumKernelLevel() <= mpt::Windows::Version::WinXP)
+				&& (mpt::Windows::Version::GetMinimumAPILevel() <= mpt::Windows::Version::WinXP)
+			) {
+				retval += " WIN32OLD";
+			}
+		#endif
+		#if defined(UNICODE)
+			retval += " UNICODE";
+		#else
+			retval += " ANSI";
+		#endif
 		#ifdef NO_VST
 			retval += " NO_VST";
 		#endif
@@ -406,7 +426,7 @@ static std::string GetRevisionString()
 	{
 		return result;
 	}
-	result = std::string("-r") + mpt::ToString(GetRevision());
+	result = std::string("-r") + mpt::fmt::val(GetRevision());
 	if(HasMixedRevisions())
 	{
 		result += "!";
@@ -422,20 +442,6 @@ static std::string GetRevisionString()
 	return result;
 }
 
-bool IsForOlderWindows()
-{
-	#ifdef MODPLUG_TRACKER
-		return true
-			&& (GetMinimumSSEVersion() <= 0)
-			&& (GetMinimumAVXVersion() <= 0)
-			&& (mpt::Windows::Version::GetMinimumKernelLevel() < mpt::Windows::Version::WinXP)
-			&& (mpt::Windows::Version::GetMinimumAPILevel() < mpt::Windows::Version::WinXP)
-			;
-	#else
-		return false;
-	#endif
-}
-
 mpt::ustring GetDownloadURL()
 {
 	#ifdef MODPLUG_TRACKER
@@ -542,7 +548,7 @@ std::string SourceInfo::GetUrlWithRevision() const
 	{
 		return std::string();
 	}
-	return Url + "@" + mpt::ToString(Revision);
+	return Url + "@" + mpt::fmt::val(Revision);
 }
 
 mpt::ustring GetURL(std::string key)
@@ -623,31 +629,22 @@ mpt::ustring GetFullCreditsString()
 		"http://www.hermannseib.com/english/vsthost.htm\n"
 		"\n"
 #endif
-#if defined(MPT_WITH_UNMO3) || defined(MPT_ENABLE_UNMO3_DYNBIND)
-		"Ian Luck for UNMO3\n"
-		"http://www.un4seen.com/mo3.html\n"
-		"\n"
-#endif
-#ifdef MPT_ENABLE_MO3_BUILTIN
 		"Laurent Cl\xc3\xA9vy for unofficial MO3 documentation and decompression code\n"
 		"https://github.com/lclevy/unmo3\n"
 		"\n"
-#endif
 		"Ben \"GreaseMonkey\" Russell for IT sample compression code\n"
 		"https://github.com/iamgreaser/it2everything/\n"
 		"\n"
-#if MPT_COMPILER_MSVC
-		"Alexander Chemeris for msinttypes\n"
-		"https://github.com/chemeris/msinttypes\n"
+		"Antti S. Lankila for Amiga resampler implementation\n"
+		"https://bel.fi/alankila/modguide/interpolate.txt\n"
 		"\n"
-#endif
 #ifdef MPT_WITH_ZLIB
 		"Jean-loup Gailly and Mark Adler for zlib\n"
 		"http://zlib.net/\n"
 		"\n"
 #endif
 #ifdef MPT_WITH_MINIZ
-		"Rich Geldreich for miniz\n"
+		"Rich Geldreich et al. for miniz\n"
 		"https://github.com/richgel999/miniz\n"
 		"\n"
 #endif
@@ -671,7 +668,7 @@ mpt::ustring GetFullCreditsString()
 		"https://xiph.org/flac/\n"
 		"\n"
 #endif
-#if defined(MPT_WITH_MPG123) || defined(MPT_ENABLE_MPG123_DYNBIND)
+#if defined(MPT_WITH_MPG123)
 		"The mpg123 project for libmpg123\n"
 		"http://mpg123.de/\n"
 		"\n"
@@ -709,6 +706,11 @@ mpt::ustring GetFullCreditsString()
 		"https://opus-codec.org/\n"
 		"\n"
 #endif
+#if defined(MPT_WITH_OPUSENC)
+		"Xiph.Org Foundation, Jean-Marc Valin and contributors for libopusenc\n"
+		"https://git.xiph.org/?p=libopusenc.git;a=summary\n"
+		"\n"
+#endif
 #if defined(MPT_WITH_PICOJSON)
 		"Cybozu Labs Inc. and Kazuho Oku et. al. for picojson\n"
 		"https://github.com/kazuho/picojson\n"
@@ -719,6 +721,12 @@ mpt::ustring GetFullCreditsString()
 		"http://schismtracker.org/\n"
 		"\n"
 #ifdef MODPLUG_TRACKER
+		"Lennart Poettering and David Henningsson for RealtimeKit\n"
+		"http://git.0pointer.net/rtkit.git/\n"
+		"\n"
+		"Gary P. Scavone for RtMidi\n"
+		"https://www.music.mcgill.ca/~gary/rtmidi/\n"
+		"\n"
 		"Alexander Uckun for decimal input field\n"
 		"http://www.codeproject.com/Articles/21257/_\n"
 		"\n"
diff --git a/common/version.h b/common/version.h
index b56b238..305c025 100644
--- a/common/version.h
+++ b/common/version.h
@@ -41,6 +41,7 @@ namespace MptVersion
 
 	// Returns version string from given numerical version value.
 	std::string ToStr(const VersionNum v);
+	mpt::ustring ToUString(const VersionNum v);
 
 	// Return a version without build number (the last number in the version).
 	// The current versioning scheme uses this number only for test builds, and it should be 00 for official builds,
@@ -60,7 +61,7 @@ namespace MptVersion
 		bool IsDirty; // svn working copy is dirty (or false)
 		bool HasMixedRevisions; // svn working copy has mixed revisions (or false)
 		bool IsPackage; // source code originates from a packaged version of the source code
-		std::string Date; // svn date (ór empty string)
+		std::string Date; // svn date (or empty string)
 		SourceInfo() : Url(std::string()), Revision(0), IsDirty(false), HasMixedRevisions(false), IsPackage(false) { }
 	public:
 		std::string GetUrlWithRevision() const; // i.e. "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234" or empty string
@@ -68,9 +69,6 @@ namespace MptVersion
 	};
 	SourceInfo GetSourceInfo();
 
-	// Returns true if the build will run on ancient Windows versions.
-	bool IsForOlderWindows();
-
 	// Returns either the URL to download release builds or the URL to download test builds, depending on the current build.
 	mpt::ustring GetDownloadURL();
 
diff --git a/common/versionNumber.h b/common/versionNumber.h
index 92c02ca..aa484e9 100644
--- a/common/versionNumber.h
+++ b/common/versionNumber.h
@@ -17,9 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 
 //Version definitions. The only thing that needs to be changed when changing version number.
 #define VER_MAJORMAJOR          1
-#define VER_MAJOR               26
-#define VER_MINOR               12
-#define VER_MINORMINOR          01
+#define VER_MAJOR               27
+#define VER_MINOR               01
+#define VER_MINORMINOR          00
 
 //Version string. For example "1.17.02.28"
 #define MPT_VERSION_STR         VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR)
diff --git a/config.h.in b/config.h.in
index b86e66f..a2784e1 100644
--- a/config.h.in
+++ b/config.h.in
@@ -33,13 +33,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
-   */
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
 #undef LT_OBJDIR
 
-/* enable dlopen */
-#undef MPT_ENABLE_DLOPEN
-
 /* is package */
 #undef MPT_PACKAGE
 
diff --git a/configure b/configure
index 18e0272..82e3d6e 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libopenmpt 0.2.8461-autotools.
+# Generated by GNU Autoconf 2.69 for libopenmpt 0.3.1+release.autotools.
 #
 # Report bugs to <https://bugs.openmpt.org/>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='libopenmpt'
 PACKAGE_TARNAME='libopenmpt'
-PACKAGE_VERSION='0.2.8461-autotools'
-PACKAGE_STRING='libopenmpt 0.2.8461-autotools'
+PACKAGE_VERSION='0.3.1+release.autotools'
+PACKAGE_STRING='libopenmpt 0.3.1+release.autotools'
 PACKAGE_BUGREPORT='https://bugs.openmpt.org/'
 PACKAGE_URL='https://lib.openmpt.org/'
 
@@ -635,48 +635,41 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+DX_RULES
+PAPER_SIZE
 DOXYGEN_PAPER_SIZE
-DX_COND_latex_FALSE
-DX_COND_latex_TRUE
-DX_COND_pdf_FALSE
-DX_COND_pdf_TRUE
+GENERATE_LATEX
 DX_PDFLATEX
 DX_FLAG_pdf
-DX_COND_ps_FALSE
-DX_COND_ps_TRUE
 DX_EGREP
 DX_DVIPS
 DX_MAKEINDEX
 DX_LATEX
 DX_FLAG_ps
-DX_COND_html_FALSE
-DX_COND_html_TRUE
 DX_FLAG_html
-DX_COND_chi_FALSE
-DX_COND_chi_TRUE
+GENERATE_CHI
 DX_FLAG_chi
-DX_COND_chm_FALSE
-DX_COND_chm_TRUE
+GENERATE_HTMLHELP
+GENERATE_HTML
+HHC_PATH
 DX_HHC
 DX_FLAG_chm
-DX_COND_xml_FALSE
-DX_COND_xml_TRUE
+GENERATE_XML
 DX_FLAG_xml
-DX_COND_rtf_FALSE
-DX_COND_rtf_TRUE
+GENERATE_RTF
 DX_FLAG_rtf
-DX_COND_man_FALSE
-DX_COND_man_TRUE
+GENERATE_MAN
 DX_FLAG_man
-DX_COND_dot_FALSE
-DX_COND_dot_TRUE
+DOT_PATH
+HAVE_DOT
 DX_DOT
 DX_FLAG_dot
-DX_COND_doc_FALSE
-DX_COND_doc_TRUE
+PERL_PATH
 DX_PERL
 DX_DOXYGEN
 DX_FLAG_doc
+PROJECT
+SRCDIR
 DX_ENV
 DX_DOCDIR
 DX_CONFIG
@@ -712,10 +705,6 @@ ENABLE_OPENMPT123_FALSE
 ENABLE_OPENMPT123_TRUE
 LIBOPENMPT_LIBS_PRIVATE
 LIBOPENMPT_REQUIRES_PRIVATE
-DL_LIBS
-DL_CPPFLAGS
-LTDL_LIBS
-LTDL_CPPFLAGS
 VORBISFILE_LIBS
 VORBISFILE_CFLAGS
 VORBIS_LIBS
@@ -730,6 +719,9 @@ WIN32_CONSOLE_CFLAGS
 WIN32_CONSOLE_CXXFLAGS
 OPENMPT123_WIN32_LIBS
 LIBOPENMPT_WIN32_LIBS
+LIBOPENMPT_LTVER_AGE
+LIBOPENMPT_LTVER_REVISION
+LIBOPENMPT_LTVER_CURRENT
 CXXCPP
 am__fastdepCXX_FALSE
 am__fastdepCXX_TRUE
@@ -741,6 +733,7 @@ PKG_CONFIG_LIBDIR
 PKG_CONFIG_PATH
 PKG_CONFIG
 CPP
+LT_SYS_LIBRARY_PATH
 OTOOL64
 OTOOL
 LIPO
@@ -833,6 +826,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -861,6 +855,7 @@ enable_shared
 enable_static
 with_pic
 enable_fast_install
+with_aix_soname
 with_gnu_ld
 with_sysroot
 enable_libtool_lock
@@ -870,9 +865,6 @@ with_mpg123
 with_ogg
 with_vorbis
 with_vorbisfile
-enable_dlopen
-with_ltdl
-with_dl
 enable_openmpt123
 enable_examples
 enable_tests
@@ -904,6 +896,7 @@ CFLAGS
 LDFLAGS
 LIBS
 CPPFLAGS
+LT_SYS_LIBRARY_PATH
 CPP
 PKG_CONFIG
 PKG_CONFIG_PATH
@@ -975,6 +968,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1227,6 +1221,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1364,7 +1367,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1477,7 +1480,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libopenmpt 0.2.8461-autotools to adapt to many kinds of systems.
+\`configure' configures libopenmpt 0.3.1+release.autotools to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1517,6 +1520,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1547,7 +1551,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libopenmpt 0.2.8461-autotools:";;
+     short | recursive ) echo "Configuration of libopenmpt 0.3.1+release.autotools:";;
    esac
   cat <<\_ACEOF
 
@@ -1567,8 +1571,6 @@ Optional Features:
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --disable-largefile     omit support for large files
-  --enable-dlopen         Enable dynamic loading of 3rd-party libraries using
-                          dlopen or LoadLibray.
   --disable-openmpt123    Disable the openmpt123 command line player.
   --disable-examples      Disable the example programs.
   --disable-tests         Disable the test suite.
@@ -1599,19 +1601,19 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
                           both]
+  --with-aix-soname=aix|svr4|both
+                          shared library versioning (aka "SONAME") variant to
+                          provide on AIX, [default=aix].
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
-  --with-sysroot=DIR Search for dependent libraries within DIR
-                        (or the compiler's sysroot if not specified).
+  --with-sysroot[=DIR]    Search for dependent libraries within DIR (or the
+                          compiler's sysroot if not specified).
   --without-zlib          Disable use of zlib.
   --without-mpg123        Disable use of libmpg123.
   --without-ogg           Disable use of libogg.
   --without-vorbis        Disable use of libvorbis.
   --without-vorbisfile    Disable use of libvorbisfile.
-  --with-ltdl             Enable the use of libtool libltdl for dynamic
-                          loading of third party libraries.
-  --with-dl               Enable the use of libdl for dynamic loading of third
-                          party libraries.
-  --without-pulseaudio    Disable use of libpulse and libpulse-simple.
+  --with-pulseaudio       Enable use of libpulse and libpulse-simple (enabled
+                          by default on Linux).
   --without-portaudio     Disable use of libportaudio.
   --without-portaudiocpp  Disable use of libportaudiocpp.
   --with-sdl2             Enable use of libsdl2.
@@ -1627,6 +1629,8 @@ Some influential environment variables:
   LIBS        libraries to pass to the linker, e.g. -l<library>
   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
+  LT_SYS_LIBRARY_PATH
+              User-defined run-time library search path.
   CPP         C preprocessor
   PKG_CONFIG  path to pkg-config utility
   PKG_CONFIG_PATH
@@ -1742,7 +1746,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libopenmpt configure 0.2.8461-autotools
+libopenmpt configure 0.3.1+release.autotools
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2137,102 +2141,11 @@ fi
   as_fn_set_status $ac_retval
 
 } # ac_fn_cxx_try_link
-
-# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_c_check_header_mongrel ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if eval \${$3+:} false; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_header_compiler=yes
-else
-  ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <$2>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  ac_header_preproc=yes
-else
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
-  yes:no: )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-( $as_echo "## ---------------------------------------- ##
-## Report this to https://bugs.openmpt.org/ ##
-## ---------------------------------------- ##"
-     ) | sed "s/^/$as_me: WARNING:     /" >&2
-    ;;
-esac
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_mongrel
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libopenmpt $as_me 0.2.8461-autotools, which was
+It was created by libopenmpt $as_me 0.3.1+release.autotools, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2617,7 +2530,7 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 ac_config_files="$ac_config_files Makefile libopenmpt/libopenmpt.pc libmodplug/libmodplug.pc Doxyfile"
 
 
-am__api_version='1.14'
+am__api_version='1.15'
 
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
@@ -2809,7 +2722,7 @@ else
 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
 fi
 
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -3103,7 +3016,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='libopenmpt'
- VERSION='0.2.8461-autotools'
+ VERSION='0.3.1+release.autotools'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3137,8 +3050,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 mkdir_p='$(MKDIR_P)'
 
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 # Always define AMTAR for backward compatibility.  Yes, it's still used
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
@@ -4417,8 +4330,8 @@ esac
 
 
 
-macro_version='2.4.2'
-macro_revision='1.3337'
+macro_version='2.4.6'
+macro_revision='2.4.6'
 
 
 
@@ -4432,7 +4345,7 @@ macro_revision='1.3337'
 
 
 
-ltmain="$ac_aux_dir/ltmain.sh"
+ltmain=$ac_aux_dir/ltmain.sh
 
 # Make sure we can run config.sub.
 $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
@@ -4552,7 +4465,7 @@ func_echo_all ()
     $ECHO ""
 }
 
-case "$ECHO" in
+case $ECHO in
   printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
 $as_echo "printf" >&6; } ;;
   print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
@@ -4875,19 +4788,19 @@ test -z "$GREP" && GREP=grep
 
 # Check whether --with-gnu-ld was given.
 if test "${with_gnu_ld+set}" = set; then :
-  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
 else
   with_gnu_ld=no
 fi
 
 ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   # Check if gcc -print-prog-name=ld gives a path.
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
 $as_echo_n "checking for ld used by $CC... " >&6; }
   case $host in
   *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
+    # gcc leaves a trailing carriage return, which upsets mingw
     ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
   *)
     ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -4901,7 +4814,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
       while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
 	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
       done
-      test -z "$LD" && LD="$ac_prog"
+      test -z "$LD" && LD=$ac_prog
       ;;
   "")
     # If it fails, then pretend we aren't using GCC.
@@ -4912,7 +4825,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
     with_gnu_ld=unknown
     ;;
   esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
 $as_echo_n "checking for GNU ld... " >&6; }
 else
@@ -4923,32 +4836,32 @@ if ${lt_cv_path_LD+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$LD"; then
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
   for ac_dir in $PATH; do
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
     test -z "$ac_dir" && ac_dir=.
     if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
+      lt_cv_path_LD=$ac_dir/$ac_prog
       # Check to see if the program is GNU ld.  I'd rather use --version,
       # but apparently some variants of GNU ld only accept -v.
       # Break only if it was the GNU/non-GNU ld that we prefer.
       case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
       *GNU* | *'with BFD'*)
-	test "$with_gnu_ld" != no && break
+	test no != "$with_gnu_ld" && break
 	;;
       *)
-	test "$with_gnu_ld" != yes && break
+	test yes != "$with_gnu_ld" && break
 	;;
       esac
     fi
   done
-  IFS="$lt_save_ifs"
+  IFS=$lt_save_ifs
 else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
 fi
 fi
 
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
 if test -n "$LD"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
 $as_echo "$LD" >&6; }
@@ -4991,33 +4904,38 @@ if ${lt_cv_path_NM+:} false; then :
 else
   if test -n "$NM"; then
   # Let the user override the test.
-  lt_cv_path_NM="$NM"
+  lt_cv_path_NM=$NM
 else
-  lt_nm_to_check="${ac_tool_prefix}nm"
+  lt_nm_to_check=${ac_tool_prefix}nm
   if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
     lt_nm_to_check="$lt_nm_to_check nm"
   fi
   for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
     for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       test -z "$ac_dir" && ac_dir=.
-      tmp_nm="$ac_dir/$lt_tmp_nm"
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
 	# Check to see if the nm accepts a BSD-compat flag.
-	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
 	#   nm: unknown option "B" ignored
 	# Tru64's nm complains that /dev/null is an invalid object file
-	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
-	*/dev/null* | *'Invalid file or object type'*)
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
 	  lt_cv_path_NM="$tmp_nm -B"
-	  break
+	  break 2
 	  ;;
 	*)
 	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
 	  */dev/null*)
 	    lt_cv_path_NM="$tmp_nm -p"
-	    break
+	    break 2
 	    ;;
 	  *)
 	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
@@ -5028,15 +4946,15 @@ else
 	esac
       fi
     done
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
   done
   : ${lt_cv_path_NM=no}
 fi
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
 $as_echo "$lt_cv_path_NM" >&6; }
-if test "$lt_cv_path_NM" != "no"; then
-  NM="$lt_cv_path_NM"
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
 else
   # Didn't find any BSD compatible name lister, look for dumpbin.
   if test -n "$DUMPBIN"; then :
@@ -5142,9 +5060,9 @@ esac
   fi
 fi
 
-    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
     *COFF*)
-      DUMPBIN="$DUMPBIN -symbols"
+      DUMPBIN="$DUMPBIN -symbols -headers"
       ;;
     *)
       DUMPBIN=:
@@ -5152,8 +5070,8 @@ fi
     esac
   fi
 
-  if test "$DUMPBIN" != ":"; then
-    NM="$DUMPBIN"
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
   fi
 fi
 test -z "$NM" && NM=nm
@@ -5204,7 +5122,7 @@ if ${lt_cv_sys_max_cmd_len+:} false; then :
   $as_echo_n "(cached) " >&6
 else
     i=0
-  teststring="ABCD"
+  teststring=ABCD
 
   case $build_os in
   msdosdjgpp*)
@@ -5244,7 +5162,7 @@ else
     lt_cv_sys_max_cmd_len=8192;
     ;;
 
-  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
     # This has been around since 386BSD, at least.  Likely further.
     if test -x /sbin/sysctl; then
       lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -5295,22 +5213,22 @@ else
   *)
     lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
     if test -n "$lt_cv_sys_max_cmd_len" && \
-	test undefined != "$lt_cv_sys_max_cmd_len"; then
+       test undefined != "$lt_cv_sys_max_cmd_len"; then
       lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
       lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
     else
       # Make teststring a little bigger before we do anything with it.
       # a 1K string should be a reasonable start.
-      for i in 1 2 3 4 5 6 7 8 ; do
+      for i in 1 2 3 4 5 6 7 8; do
         teststring=$teststring$teststring
       done
       SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
       # If test is not a shell built-in, we'll probably end up computing a
       # maximum length that is only half of the actual maximum length, but
       # we can't tell.
-      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
 	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
-	      test $i != 17 # 1/2 MB should be enough
+	      test 17 != "$i" # 1/2 MB should be enough
       do
         i=`expr $i + 1`
         teststring=$teststring$teststring
@@ -5328,7 +5246,7 @@ else
 
 fi
 
-if test -n $lt_cv_sys_max_cmd_len ; then
+if test -n "$lt_cv_sys_max_cmd_len"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
 $as_echo "$lt_cv_sys_max_cmd_len" >&6; }
 else
@@ -5346,30 +5264,6 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
 : ${MV="mv -f"}
 : ${RM="rm -f"}
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
-$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
-  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
-      = c,a/b,b/c, \
-    && eval 'test $(( 1 + 1 )) -eq 2 \
-    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
-  && xsi_shell=yes
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
-$as_echo "$xsi_shell" >&6; }
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
-$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
-    >/dev/null 2>&1 \
-  && lt_shell_append=yes
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
-$as_echo "$lt_shell_append" >&6; }
-
-
 if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
   lt_unset=unset
 else
@@ -5492,13 +5386,13 @@ esac
 reload_cmds='$LD$reload_flag -o $output$reload_objs'
 case $host_os in
   cygwin* | mingw* | pw32* | cegcc*)
-    if test "$GCC" != yes; then
+    if test yes != "$GCC"; then
       reload_cmds=false
     fi
     ;;
   darwin*)
-    if test "$GCC" = yes; then
-      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    if test yes = "$GCC"; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
     else
       reload_cmds='$LD$reload_flag -o $output$reload_objs'
     fi
@@ -5626,13 +5520,13 @@ lt_cv_deplibs_check_method='unknown'
 # Need to set the preceding variable on all platforms that support
 # interlibrary dependencies.
 # 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
+# 'unknown' -- same as none, but documents that we really don't know.
 # 'pass_all' -- all dependencies passed with no checks.
 # 'test_compile' -- check by making test program.
 # 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
 
 case $host_os in
 aix[4-9]*)
@@ -5659,8 +5553,7 @@ mingw* | pw32*)
   # Base MSYS/MinGW do not provide the 'file' command needed by
   # func_win32_libid shell function, so use a weaker test based on 'objdump',
   # unless we find 'file', for example because we are cross-compiling.
-  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
-  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+  if ( file / ) >/dev/null 2>&1; then
     lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
     lt_cv_file_magic_cmd='func_win32_libid'
   else
@@ -5756,8 +5649,8 @@ newos6*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
-openbsd*)
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+openbsd* | bitrig*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
     lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
   else
     lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
@@ -5810,6 +5703,9 @@ sysv4 | sysv4.3*)
 tpf*)
   lt_cv_deplibs_check_method=pass_all
   ;;
+os2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
 esac
 
 fi
@@ -5967,8 +5863,8 @@ else
 
 case $host_os in
 cygwin* | mingw* | pw32* | cegcc*)
-  # two different shell functions defined in ltmain.sh
-  # decide which to use based on capabilities of $DLLTOOL
+  # two different shell functions defined in ltmain.sh;
+  # decide which one to use based on capabilities of $DLLTOOL
   case `$DLLTOOL --help 2>&1` in
   *--identify-strict*)
     lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
@@ -5980,7 +5876,7 @@ cygwin* | mingw* | pw32* | cegcc*)
   ;;
 *)
   # fallback: assume linklib IS sharedlib
-  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  lt_cv_sharedlib_from_linklib_cmd=$ECHO
   ;;
 esac
 
@@ -6134,7 +6030,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
-      if test "$ac_status" -eq 0; then
+      if test 0 -eq "$ac_status"; then
 	# Ensure the archiver fails upon bogus file names.
 	rm -f conftest.$ac_objext libconftest.a
 	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
@@ -6142,7 +6038,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
-	if test "$ac_status" -ne 0; then
+	if test 0 -ne "$ac_status"; then
           lt_cv_ar_at_file=@
         fi
       fi
@@ -6155,7 +6051,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
 $as_echo "$lt_cv_ar_at_file" >&6; }
 
-if test "x$lt_cv_ar_at_file" = xno; then
+if test no = "$lt_cv_ar_at_file"; then
   archiver_list_spec=
 else
   archiver_list_spec=$lt_cv_ar_at_file
@@ -6372,7 +6268,7 @@ old_postuninstall_cmds=
 
 if test -n "$RANLIB"; then
   case $host_os in
-  openbsd*)
+  bitrig* | openbsd*)
     old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
     ;;
   *)
@@ -6462,7 +6358,7 @@ cygwin* | mingw* | pw32* | cegcc*)
   symcode='[ABCDGISTW]'
   ;;
 hpux*)
-  if test "$host_cpu" = ia64; then
+  if test ia64 = "$host_cpu"; then
     symcode='[ABCDEGRST]'
   fi
   ;;
@@ -6495,14 +6391,44 @@ case `$NM -V 2>&1` in
   symcode='[ABCDGIRSTW]' ;;
 esac
 
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  # Gets list of data symbols to import.
+  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+  # Adjust the below global symbol transforms to fixup imported variables.
+  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
+  lt_c_name_lib_hook="\
+  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
+  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
+else
+  # Disable hooks by default.
+  lt_cv_sys_global_symbol_to_import=
+  lt_cdecl_hook=
+  lt_c_name_hook=
+  lt_c_name_lib_hook=
+fi
+
 # Transform an extracted symbol line into a proper C declaration.
 # Some systems (esp. on ia64) link data and code symbols differently,
 # so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
 
 # Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
 
 # Handle CRLF in mingw tool chain
 opt_cr=
@@ -6520,21 +6446,24 @@ for ac_symprfx in "" "_"; do
 
   # Write the raw and C identifiers.
   if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-    # Fake it for dumpbin and say T for any non-static function
-    # and D for any global variable.
+    # Fake it for dumpbin and say T for any non-static function,
+    # D for any global variable and I for any imported variable.
     # Also find C++ and __fastcall symbols from MSVC++,
     # which start with @ or ?.
     lt_cv_sys_global_symbol_pipe="$AWK '"\
 "     {last_section=section; section=\$ 3};"\
 "     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
 "     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
 "     \$ 0!~/External *\|/{next};"\
 "     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
 "     {if(hide[section]) next};"\
-"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
-"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
 "     ' prfx=^$ac_symprfx"
   else
     lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
@@ -6582,11 +6511,11 @@ _LT_EOF
 	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
 	  cat <<_LT_EOF > conftest.$ac_ext
 /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
    relocations are performed -- see ld's documentation on pseudo-relocs.  */
 # define LT_DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
 /* This system does not cope well with relocations in const data.  */
 # define LT_DLSYM_CONST
 #else
@@ -6612,7 +6541,7 @@ lt__PROGRAM__LTX_preloaded_symbols[] =
 {
   { "@PROGRAM@", (void *) 0 },
 _LT_EOF
-	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
 	  cat <<\_LT_EOF >> conftest.$ac_ext
   {0, (void *) 0}
 };
@@ -6632,13 +6561,13 @@ _LT_EOF
 	  mv conftest.$ac_objext conftstm.$ac_objext
 	  lt_globsym_save_LIBS=$LIBS
 	  lt_globsym_save_CFLAGS=$CFLAGS
-	  LIBS="conftstm.$ac_objext"
+	  LIBS=conftstm.$ac_objext
 	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
 	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
   (eval $ac_link) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+  test $ac_status = 0; } && test -s conftest$ac_exeext; then
 	    pipe_works=yes
 	  fi
 	  LIBS=$lt_globsym_save_LIBS
@@ -6659,7 +6588,7 @@ _LT_EOF
   rm -rf conftest* conftst*
 
   # Do not use the global_symbol_pipe unless it works.
-  if test "$pipe_works" = yes; then
+  if test yes = "$pipe_works"; then
     break
   else
     lt_cv_sys_global_symbol_pipe=
@@ -6712,6 +6641,16 @@ fi
 
 
 
+
+
+
+
+
+
+
+
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
 $as_echo_n "checking for sysroot... " >&6; }
 
@@ -6724,9 +6663,9 @@ fi
 
 
 lt_sysroot=
-case ${with_sysroot} in #(
+case $with_sysroot in #(
  yes)
-   if test "$GCC" = yes; then
+   if test yes = "$GCC"; then
      lt_sysroot=`$CC --print-sysroot 2>/dev/null`
    fi
    ;; #(
@@ -6736,8 +6675,8 @@ case ${with_sysroot} in #(
  no|'')
    ;; #(
  *)
-   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
-$as_echo "${with_sysroot}" >&6; }
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+$as_echo "$with_sysroot" >&6; }
    as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
    ;;
 esac
@@ -6749,18 +6688,99 @@ $as_echo "${lt_sysroot:-no}" >&6; }
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+$as_echo_n "checking for a working dd... " >&6; }
+if ${ac_cv_path_lt_DD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+if test -z "$lt_DD"; then
+  ac_path_lt_DD_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in dd; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_lt_DD" || continue
+if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi
+      $ac_path_lt_DD_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_lt_DD"; then
+    :
+  fi
+else
+  ac_cv_path_lt_DD=$lt_DD
+fi
+
+rm -f conftest.i conftest2.i conftest.out
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+$as_echo "$ac_cv_path_lt_DD" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+$as_echo_n "checking how to truncate binary pipes... " >&6; }
+if ${lt_cv_truncate_bin+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+$as_echo "$lt_cv_truncate_bin" >&6; }
+
+
+
+
+
+
+
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in $*""; do
+      case $cc_temp in
+        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
 # Check whether --enable-libtool-lock was given.
 if test "${enable_libtool_lock+set}" = set; then :
   enableval=$enable_libtool_lock;
 fi
 
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
 
 # Some flags need to be propagated to the compiler or linker for good
 # libtool support.
 case $host in
 ia64-*-hpux*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set mode
+  # options accordingly.
   echo 'int i;' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
@@ -6769,24 +6789,25 @@ ia64-*-hpux*)
   test $ac_status = 0; }; then
     case `/usr/bin/file conftest.$ac_objext` in
       *ELF-32*)
-	HPUX_IA64_MODE="32"
+	HPUX_IA64_MODE=32
 	;;
       *ELF-64*)
-	HPUX_IA64_MODE="64"
+	HPUX_IA64_MODE=64
 	;;
     esac
   fi
   rm -rf conftest*
   ;;
 *-*-irix6*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
   echo '#line '$LINENO' "configure"' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-    if test "$lt_cv_prog_gnu_ld" = yes; then
+    if test yes = "$lt_cv_prog_gnu_ld"; then
       case `/usr/bin/file conftest.$ac_objext` in
 	*32-bit*)
 	  LD="${LD-ld} -melf32bsmip"
@@ -6815,9 +6836,50 @@ ia64-*-hpux*)
   rm -rf conftest*
   ;;
 
+mips64*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    emul=elf
+    case `/usr/bin/file conftest.$ac_objext` in
+      *32-bit*)
+	emul="${emul}32"
+	;;
+      *64-bit*)
+	emul="${emul}64"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *MSB*)
+	emul="${emul}btsmip"
+	;;
+      *LSB*)
+	emul="${emul}ltsmip"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *N32*)
+	emul="${emul}n32"
+	;;
+    esac
+    LD="${LD-ld} -m $emul"
+  fi
+  rm -rf conftest*
+  ;;
+
 x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
 s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.  Note that the listed cases only cover the
+  # situations where additional linker options are needed (such as when
+  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+  # vice versa); the common cases where no linker options are needed do
+  # not appear in the list.
   echo 'int i;' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
@@ -6840,10 +6902,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 		;;
 	    esac
 	    ;;
-	  powerpc64le-*)
+	  powerpc64le-*linux*)
 	    LD="${LD-ld} -m elf32lppclinux"
 	    ;;
-	  powerpc64-*)
+	  powerpc64-*linux*)
 	    LD="${LD-ld} -m elf32ppclinux"
 	    ;;
 	  s390x-*linux*)
@@ -6862,10 +6924,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 	  x86_64-*linux*)
 	    LD="${LD-ld} -m elf_x86_64"
 	    ;;
-	  powerpcle-*)
+	  powerpcle-*linux*)
 	    LD="${LD-ld} -m elf64lppc"
 	    ;;
-	  powerpc-*)
+	  powerpc-*linux*)
 	    LD="${LD-ld} -m elf64ppc"
 	    ;;
 	  s390*-*linux*|s390*-*tpf*)
@@ -6883,7 +6945,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 
 *-*-sco3.2v5*)
   # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS="$CFLAGS"
+  SAVE_CFLAGS=$CFLAGS
   CFLAGS="$CFLAGS -belf"
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
 $as_echo_n "checking whether the C compiler needs -belf... " >&6; }
@@ -6923,13 +6985,14 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
 $as_echo "$lt_cv_cc_needs_belf" >&6; }
-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+  if test yes != "$lt_cv_cc_needs_belf"; then
     # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS="$SAVE_CFLAGS"
+    CFLAGS=$SAVE_CFLAGS
   fi
   ;;
 *-*solaris*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
   echo 'int i;' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
@@ -6941,7 +7004,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
       case $lt_cv_prog_gnu_ld in
       yes*)
         case $host in
-        i?86-*-solaris*)
+        i?86-*-solaris*|x86_64-*-solaris*)
           LD="${LD-ld} -m elf_x86_64"
           ;;
         sparc*-*-solaris*)
@@ -6950,7 +7013,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
         esac
         # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
         if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
-          LD="${LD-ld}_sol2"
+          LD=${LD-ld}_sol2
         fi
         ;;
       *)
@@ -6966,7 +7029,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
   ;;
 esac
 
-need_locks="$enable_libtool_lock"
+need_locks=$enable_libtool_lock
 
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
@@ -7077,7 +7140,7 @@ else
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
 $as_echo "$lt_cv_path_mainfest_tool" >&6; }
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
+if test yes != "$lt_cv_path_mainfest_tool"; then
   MANIFEST_TOOL=:
 fi
 
@@ -7580,7 +7643,7 @@ if ${lt_cv_apple_cc_single_mod+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_apple_cc_single_mod=no
-      if test -z "${LT_MULTI_MODULE}"; then
+      if test -z "$LT_MULTI_MODULE"; then
 	# By default we will add the -single_module flag. You can override
 	# by either setting the environment variable LT_MULTI_MODULE
 	# non-empty at configure time, or by adding -multi_module to the
@@ -7598,7 +7661,7 @@ else
 	  cat conftest.err >&5
 	# Otherwise, if the output was created with a 0 exit code from
 	# the compiler, it worked.
-	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
 	  lt_cv_apple_cc_single_mod=yes
 	else
 	  cat conftest.err >&5
@@ -7637,7 +7700,7 @@ else
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-	LDFLAGS="$save_LDFLAGS"
+	LDFLAGS=$save_LDFLAGS
 
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
@@ -7666,7 +7729,7 @@ _LT_EOF
       _lt_result=$?
       if test -s conftest.err && $GREP force_load conftest.err; then
 	cat conftest.err >&5
-      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
 	lt_cv_ld_force_load=yes
       else
 	cat conftest.err >&5
@@ -7679,32 +7742,32 @@ fi
 $as_echo "$lt_cv_ld_force_load" >&6; }
     case $host_os in
     rhapsody* | darwin1.[012])
-      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
     darwin1.*)
-      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
     darwin*) # darwin 5.x on
       # if running on 10.5 or later, the deployment target defaults
       # to the OS version, if on x86, and 10.4, the deployment
       # target defaults to 10.4. Don't you love it?
       case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
 	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
-	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-	10.[012]*)
-	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+	10.[012][,.]*)
+	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
 	10.*)
-	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
       esac
     ;;
   esac
-    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+    if test yes = "$lt_cv_apple_cc_single_mod"; then
       _lt_dar_single_mod='$single_module'
     fi
-    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
-      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    if test yes = "$lt_cv_ld_exported_symbols_list"; then
+      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
     else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
     fi
-    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
       _lt_dsymutil='~$DSYMUTIL $lib || :'
     else
       _lt_dsymutil=
@@ -7712,6 +7775,41 @@ $as_echo "$lt_cv_ld_force_load" >&6; }
     ;;
   esac
 
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x$2 in
+    x)
+        ;;
+    *:)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+        ;;
+    x:*)
+        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+        ;;
+    *)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -8015,14 +8113,14 @@ if test "${enable_shared+set}" = set; then :
     *)
       enable_shared=no
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for pkg in $enableval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$pkg" = "X$p"; then
 	  enable_shared=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac
 else
@@ -8046,14 +8144,14 @@ if test "${enable_static+set}" = set; then :
     *)
      enable_static=no
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for pkg in $enableval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$pkg" = "X$p"; then
 	  enable_static=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac
 else
@@ -8077,14 +8175,14 @@ if test "${with_pic+set}" = set; then :
     *)
       pic_mode=default
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for lt_pkg in $withval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$lt_pkg" = "X$lt_p"; then
 	  pic_mode=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac
 else
@@ -8092,8 +8190,6 @@ else
 fi
 
 
-test -z "$pic_mode" && pic_mode=default
-
 
 
 
@@ -8109,14 +8205,14 @@ if test "${enable_fast_install+set}" = set; then :
     *)
       enable_fast_install=no
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for pkg in $enableval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$pkg" = "X$p"; then
 	  enable_fast_install=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac
 else
@@ -8130,11 +8226,63 @@ fi
 
 
 
+  shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[5-9]*,yes)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+
+# Check whether --with-aix-soname was given.
+if test "${with_aix_soname+set}" = set; then :
+  withval=$with_aix_soname; case $withval in
+    aix|svr4|both)
+      ;;
+    *)
+      as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
+      ;;
+    esac
+    lt_cv_with_aix_soname=$with_aix_soname
+else
+  if ${lt_cv_with_aix_soname+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_with_aix_soname=aix
+fi
+
+    with_aix_soname=$lt_cv_with_aix_soname
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+$as_echo "$with_aix_soname" >&6; }
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+*)
+  with_aix_soname=aix
+  ;;
+esac
+
+
+
+
+
+
+
 
 
 
 # This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ltmain"
+LIBTOOL_DEPS=$ltmain
 
 # Always use our own libtool.
 LIBTOOL='$(SHELL) $(top_builddir)/libtool'
@@ -8183,7 +8331,7 @@ test -z "$LN_S" && LN_S="ln -s"
 
 
 
-if test -n "${ZSH_VERSION+set}" ; then
+if test -n "${ZSH_VERSION+set}"; then
    setopt NO_GLOB_SUBST
 fi
 
@@ -8222,7 +8370,7 @@ aix3*)
   # AIX sometimes has problems with the GCC collect2 program.  For some
   # reason, if we set the COLLECT_NAMES environment variable, the problems
   # vanish in a puff of smoke.
-  if test "X${COLLECT_NAMES+set}" != Xset; then
+  if test set != "${COLLECT_NAMES+set}"; then
     COLLECT_NAMES=
     export COLLECT_NAMES
   fi
@@ -8233,14 +8381,14 @@ esac
 ofile=libtool
 can_build_shared=yes
 
-# All known linkers require a `.a' archive for static linking (except MSVC,
+# All known linkers require a '.a' archive for static linking (except MSVC,
 # which needs '.lib').
 libext=a
 
-with_gnu_ld="$lt_cv_prog_gnu_ld"
+with_gnu_ld=$lt_cv_prog_gnu_ld
 
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
+old_CC=$CC
+old_CFLAGS=$CFLAGS
 
 # Set sane defaults for various variables
 test -z "$CC" && CC=cc
@@ -8249,15 +8397,8 @@ test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
 test -z "$LD" && LD=ld
 test -z "$ac_objext" && ac_objext=o
 
-for cc_temp in $compiler""; do
-  case $cc_temp in
-    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
-    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
-    \-*) ;;
-    *) break;;
-  esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
 
 
 # Only perform the check for file, if the check method requires it
@@ -8272,22 +8413,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then :
 else
   case $MAGIC_CMD in
 [\\/*] |  ?:[\\/]*)
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
   ;;
 *)
-  lt_save_MAGIC_CMD="$MAGIC_CMD"
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
   ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
   for ac_dir in $ac_dummy; do
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
     test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/${ac_tool_prefix}file; then
-      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+    if test -f "$ac_dir/${ac_tool_prefix}file"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
       if test -n "$file_magic_test_file"; then
 	case $deplibs_check_method in
 	"file_magic "*)
 	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
 	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
 	    $EGREP "$file_magic_regex" > /dev/null; then
 	    :
@@ -8310,13 +8451,13 @@ _LT_EOF
       break
     fi
   done
-  IFS="$lt_save_ifs"
-  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
   ;;
 esac
 fi
 
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
 if test -n "$MAGIC_CMD"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
 $as_echo "$MAGIC_CMD" >&6; }
@@ -8338,22 +8479,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then :
 else
   case $MAGIC_CMD in
 [\\/*] |  ?:[\\/]*)
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
   ;;
 *)
-  lt_save_MAGIC_CMD="$MAGIC_CMD"
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
   ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
   for ac_dir in $ac_dummy; do
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
     test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/file; then
-      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+    if test -f "$ac_dir/file"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"file"
       if test -n "$file_magic_test_file"; then
 	case $deplibs_check_method in
 	"file_magic "*)
 	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
 	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
 	    $EGREP "$file_magic_regex" > /dev/null; then
 	    :
@@ -8376,13 +8517,13 @@ _LT_EOF
       break
     fi
   done
-  IFS="$lt_save_ifs"
-  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
   ;;
 esac
 fi
 
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
 if test -n "$MAGIC_CMD"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
 $as_echo "$MAGIC_CMD" >&6; }
@@ -8403,7 +8544,7 @@ esac
 
 # Use C for the default configuration in the libtool script
 
-lt_save_CC="$CC"
+lt_save_CC=$CC
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -8465,7 +8606,7 @@ if test -n "$compiler"; then
 
 lt_prog_compiler_no_builtin_flag=
 
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   case $cc_basename in
   nvcc*)
     lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
@@ -8481,7 +8622,7 @@ else
   lt_cv_prog_compiler_rtti_exceptions=no
    ac_outfile=conftest.$ac_objext
    echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   lt_compiler_flag="-fno-rtti -fno-exceptions"  ## exclude from sc_useless_quotes_in_assignment
    # Insert the option either (1) after the last *FLAGS variable, or
    # (2) before a word containing "conftest.", or (3) at the end.
    # Note that $ac_compile itself does not contain backslashes and begins
@@ -8511,7 +8652,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
 
-if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
     lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
 else
     :
@@ -8529,17 +8670,18 @@ lt_prog_compiler_pic=
 lt_prog_compiler_static=
 
 
-  if test "$GCC" = yes; then
+  if test yes = "$GCC"; then
     lt_prog_compiler_wl='-Wl,'
     lt_prog_compiler_static='-static'
 
     case $host_os in
       aix*)
       # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# AIX 5 now supports IA64 processor
 	lt_prog_compiler_static='-Bstatic'
       fi
+      lt_prog_compiler_pic='-fPIC'
       ;;
 
     amigaos*)
@@ -8550,8 +8692,8 @@ lt_prog_compiler_static=
         ;;
       m68k)
             # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
             lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
         ;;
       esac
@@ -8567,6 +8709,11 @@ lt_prog_compiler_static=
       # Although the cygwin gcc ignores -fPIC, still need this for old-style
       # (--disable-auto-import) libraries
       lt_prog_compiler_pic='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static='$wl-static'
+	;;
+      esac
       ;;
 
     darwin* | rhapsody*)
@@ -8637,7 +8784,7 @@ lt_prog_compiler_static=
     case $host_os in
     aix*)
       lt_prog_compiler_wl='-Wl,'
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# AIX 5 now supports IA64 processor
 	lt_prog_compiler_static='-Bstatic'
       else
@@ -8645,10 +8792,29 @@ lt_prog_compiler_static=
       fi
       ;;
 
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      case $cc_basename in
+      nagfor*)
+        # NAG Fortran compiler
+        lt_prog_compiler_wl='-Wl,-Wl,,'
+        lt_prog_compiler_pic='-PIC'
+        lt_prog_compiler_static='-Bstatic'
+        ;;
+      esac
+      ;;
+
     mingw* | cygwin* | pw32* | os2* | cegcc*)
       # This hack is so that the source file can tell whether it is being
       # built for inclusion in a dll (and should export symbols for example).
       lt_prog_compiler_pic='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static='$wl-static'
+	;;
+      esac
       ;;
 
     hpux9* | hpux10* | hpux11*)
@@ -8664,7 +8830,7 @@ lt_prog_compiler_static=
 	;;
       esac
       # Is there a better lt_prog_compiler_static that works with the bundled CC?
-      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      lt_prog_compiler_static='$wl-a ${wl}archive'
       ;;
 
     irix5* | irix6* | nonstopux*)
@@ -8675,7 +8841,7 @@ lt_prog_compiler_static=
 
     linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
       case $cc_basename in
-      # old Intel for x86_64 which still supported -KPIC.
+      # old Intel for x86_64, which still supported -KPIC.
       ecc*)
 	lt_prog_compiler_wl='-Wl,'
 	lt_prog_compiler_pic='-KPIC'
@@ -8700,6 +8866,12 @@ lt_prog_compiler_static=
 	lt_prog_compiler_pic='-PIC'
 	lt_prog_compiler_static='-Bstatic'
 	;;
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+	;;
       pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
         # Portland Group compilers (*not* the Pentium gcc compiler,
 	# which looks to be a dead project)
@@ -8797,7 +8969,7 @@ lt_prog_compiler_static=
       ;;
 
     sysv4*MP*)
-      if test -d /usr/nec ;then
+      if test -d /usr/nec; then
 	lt_prog_compiler_pic='-Kconform_pic'
 	lt_prog_compiler_static='-Bstatic'
       fi
@@ -8826,7 +8998,7 @@ lt_prog_compiler_static=
   fi
 
 case $host_os in
-  # For platforms which do not support PIC, -DPIC is meaningless:
+  # For platforms that do not support PIC, -DPIC is meaningless:
   *djgpp*)
     lt_prog_compiler_pic=
     ;;
@@ -8858,7 +9030,7 @@ else
   lt_cv_prog_compiler_pic_works=no
    ac_outfile=conftest.$ac_objext
    echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"  ## exclude from sc_useless_quotes_in_assignment
    # Insert the option either (1) after the last *FLAGS variable, or
    # (2) before a word containing "conftest.", or (3) at the end.
    # Note that $ac_compile itself does not contain backslashes and begins
@@ -8888,7 +9060,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
 
-if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+if test yes = "$lt_cv_prog_compiler_pic_works"; then
     case $lt_prog_compiler_pic in
      "" | " "*) ;;
      *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
@@ -8920,7 +9092,7 @@ if ${lt_cv_prog_compiler_static_works+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_static_works=no
-   save_LDFLAGS="$LDFLAGS"
+   save_LDFLAGS=$LDFLAGS
    LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
    echo "$lt_simple_link_test_code" > conftest.$ac_ext
    if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -8939,13 +9111,13 @@ else
      fi
    fi
    $RM -r conftest*
-   LDFLAGS="$save_LDFLAGS"
+   LDFLAGS=$save_LDFLAGS
 
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
 $as_echo "$lt_cv_prog_compiler_static_works" >&6; }
 
-if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+if test yes = "$lt_cv_prog_compiler_static_works"; then
     :
 else
     lt_prog_compiler_static=
@@ -9065,8 +9237,8 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; }
 
 
 
-hard_links="nottested"
-if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
   # do not overwrite the value of need_locks provided by the user
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
 $as_echo_n "checking if we can lock with hard links... " >&6; }
@@ -9078,9 +9250,9 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
 $as_echo "$hard_links" >&6; }
-  if test "$hard_links" = no; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
-$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+  if test no = "$hard_links"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
     need_locks=warn
   fi
 else
@@ -9123,9 +9295,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
   # included in the symbol list
   include_expsyms=
   # exclude_expsyms can be an extended regexp of symbols to exclude
-  # it will be wrapped by ` (' and `)$', so one must not match beginning or
-  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-  # as well as any symbol that contains `d'.
+  # it will be wrapped by ' (' and ')$', so one must not match beginning or
+  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+  # as well as any symbol that contains 'd'.
   exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
   # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
   # platforms (ab)use it in PIC code, but their linkers get confused if
@@ -9140,7 +9312,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     # FIXME: the MSVC++ port hasn't been tested in a loooong time
     # When not using gcc, we currently assume that we are using
     # Microsoft Visual C++.
-    if test "$GCC" != yes; then
+    if test yes != "$GCC"; then
       with_gnu_ld=no
     fi
     ;;
@@ -9148,7 +9320,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     # we just hope/assume this is gcc and not c89 (= MSVC++)
     with_gnu_ld=yes
     ;;
-  openbsd*)
+  openbsd* | bitrig*)
     with_gnu_ld=no
     ;;
   linux* | k*bsd*-gnu | gnu*)
@@ -9161,7 +9333,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
   # On some targets, GNU ld is compatible enough with the native linker
   # that we're better off using the native interface for both.
   lt_use_gnu_ld_interface=no
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     case $host_os in
       aix*)
 	# The AIX port of GNU ld has always aspired to compatibility
@@ -9183,24 +9355,24 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     esac
   fi
 
-  if test "$lt_use_gnu_ld_interface" = yes; then
+  if test yes = "$lt_use_gnu_ld_interface"; then
     # If archive_cmds runs LD, not CC, wlarc should be empty
-    wlarc='${wl}'
+    wlarc='$wl'
 
     # Set some defaults for GNU ld with shared library support. These
     # are reset later if shared libraries are not supported. Putting them
     # here allows them to be overridden if necessary.
     runpath_var=LD_RUN_PATH
-    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
-    export_dynamic_flag_spec='${wl}--export-dynamic'
+    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+    export_dynamic_flag_spec='$wl--export-dynamic'
     # ancient GNU ld didn't support --whole-archive et. al.
     if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
-      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
     else
       whole_archive_flag_spec=
     fi
     supports_anon_versioning=no
-    case `$LD -v 2>&1` in
+    case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
       *GNU\ gold*) supports_anon_versioning=yes ;;
       *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
       *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -9213,7 +9385,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
     case $host_os in
     aix[3-9]*)
       # On AIX/PPC, the GNU linker is very broken
-      if test "$host_cpu" != ia64; then
+      if test ia64 != "$host_cpu"; then
 	ld_shlibs=no
 	cat <<_LT_EOF 1>&2
 
@@ -9232,7 +9404,7 @@ _LT_EOF
       case $host_cpu in
       powerpc)
             # see comment about AmigaOS4 .so support
-            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
             archive_expsym_cmds=''
         ;;
       m68k)
@@ -9248,7 +9420,7 @@ _LT_EOF
 	allow_undefined_flag=unsupported
 	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
 	# support --undefined.  This deserves some investigation.  FIXME
-	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
       else
 	ld_shlibs=no
       fi
@@ -9258,7 +9430,7 @@ _LT_EOF
       # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
       # as there is no search path for DLLs.
       hardcode_libdir_flag_spec='-L$libdir'
-      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      export_dynamic_flag_spec='$wl--export-all-symbols'
       allow_undefined_flag=unsupported
       always_export_symbols=no
       enable_shared_with_static_runtimes=yes
@@ -9266,61 +9438,89 @@ _LT_EOF
       exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
 
       if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	# If the export-symbols file already is a .def file (1st line
-	# is EXPORTS), use it as is; otherwise, prepend...
-	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	  cp $export_symbols $output_objdir/$soname.def;
-	else
-	  echo EXPORTS > $output_objdir/$soname.def;
-	  cat $export_symbols >> $output_objdir/$soname.def;
-	fi~
-	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file, use it as
+	# is; otherwise, prepend EXPORTS...
+	archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+          cp $export_symbols $output_objdir/$soname.def;
+        else
+          echo EXPORTS > $output_objdir/$soname.def;
+          cat $export_symbols >> $output_objdir/$soname.def;
+        fi~
+        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
       else
 	ld_shlibs=no
       fi
       ;;
 
     haiku*)
-      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
       link_all_deplibs=yes
       ;;
 
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      shrext_cmds=.dll
+      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
     interix[3-9]*)
       hardcode_direct=no
       hardcode_shlibpath_var=no
-      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
-      export_dynamic_flag_spec='${wl}-E'
+      hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+      export_dynamic_flag_spec='$wl-E'
       # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
       # Instead, shared libraries are loaded at an image base (0x10000000 by
       # default) and relocated if they conflict, which is a slow very memory
       # consuming and fragmenting process.  To avoid this, we pick a random,
       # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
       # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
       ;;
 
     gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
       tmp_diet=no
-      if test "$host_os" = linux-dietlibc; then
+      if test linux-dietlibc = "$host_os"; then
 	case $cc_basename in
 	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
 	esac
       fi
       if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
-	 && test "$tmp_diet" = no
+	 && test no = "$tmp_diet"
       then
 	tmp_addflag=' $pic_flag'
 	tmp_sharedflag='-shared'
 	case $cc_basename,$host_cpu in
         pgcc*)				# Portland Group C compiler
-	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  tmp_addflag=' $pic_flag'
 	  ;;
 	pgf77* | pgf90* | pgf95* | pgfortran*)
 					# Portland Group f77 and f90 compilers
-	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  tmp_addflag=' $pic_flag -Mnomain' ;;
 	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
 	  tmp_addflag=' -i_dynamic' ;;
@@ -9331,42 +9531,47 @@ _LT_EOF
 	lf95*)				# Lahey Fortran 8.1
 	  whole_archive_flag_spec=
 	  tmp_sharedflag='--shared' ;;
+        nagfor*)                        # NAGFOR 5.3
+          tmp_sharedflag='-Wl,-shared' ;;
 	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
 	  tmp_sharedflag='-qmkshrobj'
 	  tmp_addflag= ;;
 	nvcc*)	# Cuda Compiler Driver 2.2
-	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  compiler_needs_object=yes
 	  ;;
 	esac
 	case `$CC -V 2>&1 | sed 5q` in
 	*Sun\ C*)			# Sun C 5.9
-	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  compiler_needs_object=yes
 	  tmp_sharedflag='-G' ;;
 	*Sun\ F*)			# Sun Fortran 8.3
 	  tmp_sharedflag='-G' ;;
 	esac
-	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
 
-        if test "x$supports_anon_versioning" = xyes; then
+        if test yes = "$supports_anon_versioning"; then
           archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
-	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-	    echo "local: *; };" >> $output_objdir/$libname.ver~
-	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+            echo "local: *; };" >> $output_objdir/$libname.ver~
+            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
         fi
 
 	case $cc_basename in
+	tcc*)
+	  export_dynamic_flag_spec='-rdynamic'
+	  ;;
 	xlf* | bgf* | bgxlf* | mpixlf*)
 	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
 	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
-	  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	  hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
 	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
-	  if test "x$supports_anon_versioning" = xyes; then
+	  if test yes = "$supports_anon_versioning"; then
 	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
-	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-	      echo "local: *; };" >> $output_objdir/$libname.ver~
-	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+              echo "local: *; };" >> $output_objdir/$libname.ver~
+              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
 	  fi
 	  ;;
 	esac
@@ -9380,8 +9585,8 @@ _LT_EOF
 	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
 	wlarc=
       else
-	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
       fi
       ;;
 
@@ -9399,8 +9604,8 @@ _LT_EOF
 
 _LT_EOF
       elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
       else
 	ld_shlibs=no
       fi
@@ -9412,7 +9617,7 @@ _LT_EOF
 	ld_shlibs=no
 	cat <<_LT_EOF 1>&2
 
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
 *** reliably create shared libraries on SCO systems.  Therefore, libtool
 *** is disabling shared libraries support.  We urge you to upgrade GNU
 *** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
@@ -9427,9 +9632,9 @@ _LT_EOF
 	  # DT_RUNPATH tag from executables and libraries.  But doing so
 	  # requires that you compile everything twice, which is a pain.
 	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
-	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 	  else
 	    ld_shlibs=no
 	  fi
@@ -9446,15 +9651,15 @@ _LT_EOF
 
     *)
       if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
       else
 	ld_shlibs=no
       fi
       ;;
     esac
 
-    if test "$ld_shlibs" = no; then
+    if test no = "$ld_shlibs"; then
       runpath_var=
       hardcode_libdir_flag_spec=
       export_dynamic_flag_spec=
@@ -9470,7 +9675,7 @@ _LT_EOF
       # Note: this linker hardcodes the directories in LIBPATH if there
       # are no directories specified by -L.
       hardcode_minus_L=yes
-      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
 	# Neither direct hardcoding nor static linking is supported with a
 	# broken collect2.
 	hardcode_direct=unsupported
@@ -9478,34 +9683,57 @@ _LT_EOF
       ;;
 
     aix[4-9]*)
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# On IA64, the linker does run time linking by default, so we don't
 	# have to do anything special.
 	aix_use_runtimelinking=no
 	exp_sym_flag='-Bexport'
-	no_entry_flag=""
+	no_entry_flag=
       else
 	# If we're using GNU nm, then we don't want the "-C" option.
-	# -C means demangle to AIX nm, but means don't demangle with GNU nm
-	# Also, AIX nm treats weak defined symbols like other global
-	# defined symbols, whereas GNU nm marks them as "W".
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
 	# Test if we are trying to use run time linking or normal
 	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
-	# need to do runtime linking.
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname,aix_use_runtimelinking" is:
+	# "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix,yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both,no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
 	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
 	  for ld_flag in $LDFLAGS; do
-	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
 	    aix_use_runtimelinking=yes
 	    break
 	  fi
 	  done
+	  if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
 	  ;;
 	esac
 
@@ -9524,13 +9752,21 @@ _LT_EOF
       hardcode_direct_absolute=yes
       hardcode_libdir_separator=':'
       link_all_deplibs=yes
-      file_list_spec='${wl}-f,'
+      file_list_spec='$wl-f,'
+      case $with_aix_soname,$aix_use_runtimelinking in
+      aix,*) ;; # traditional, no import file
+      svr4,* | *,yes) # use import file
+	# The Import File defines what to hardcode.
+	hardcode_direct=no
+	hardcode_direct_absolute=no
+	;;
+      esac
 
-      if test "$GCC" = yes; then
+      if test yes = "$GCC"; then
 	case $host_os in aix4.[012]|aix4.[012].*)
 	# We only want to do this on AIX 4.2 and lower, the check
 	# below for broken collect2 doesn't work under 4.3+
-	  collect2name=`${CC} -print-prog-name=collect2`
+	  collect2name=`$CC -print-prog-name=collect2`
 	  if test -f "$collect2name" &&
 	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
 	  then
@@ -9549,36 +9785,42 @@ _LT_EOF
 	  ;;
 	esac
 	shared_flag='-shared'
-	if test "$aix_use_runtimelinking" = yes; then
-	  shared_flag="$shared_flag "'${wl}-G'
+	if test yes = "$aix_use_runtimelinking"; then
+	  shared_flag="$shared_flag "'$wl-G'
 	fi
-	link_all_deplibs=no
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
       else
 	# not using gcc
-	if test "$host_cpu" = ia64; then
+	if test ia64 = "$host_cpu"; then
 	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
 	# chokes on -Wl,-G. The following line is correct:
 	  shared_flag='-G'
 	else
-	  if test "$aix_use_runtimelinking" = yes; then
-	    shared_flag='${wl}-G'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag='$wl-G'
 	  else
-	    shared_flag='${wl}-bM:SRE'
+	    shared_flag='$wl-bM:SRE'
 	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
 	fi
       fi
 
-      export_dynamic_flag_spec='${wl}-bexpall'
+      export_dynamic_flag_spec='$wl-bexpall'
       # It seems that -bexpall does not export symbols beginning with
       # underscore (_), so it is better to generate a list of symbols to export.
       always_export_symbols=yes
-      if test "$aix_use_runtimelinking" = yes; then
+      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
 	# Warning - without using the other runtime loading flags (-brtl),
 	# -berok will link without error, but may produce a broken library.
 	allow_undefined_flag='-berok'
         # Determine the default libpath from the value encoded in an
         # empty executable.
-        if test "${lt_cv_aix_libpath+set}" = set; then
+        if test set = "${lt_cv_aix_libpath+set}"; then
   aix_libpath=$lt_cv_aix_libpath
 else
   if ${lt_cv_aix_libpath_+:} false; then :
@@ -9613,7 +9855,7 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
   if test -z "$lt_cv_aix_libpath_"; then
-    lt_cv_aix_libpath_="/usr/lib:/lib"
+    lt_cv_aix_libpath_=/usr/lib:/lib
   fi
 
 fi
@@ -9621,17 +9863,17 @@ fi
   aix_libpath=$lt_cv_aix_libpath_
 fi
 
-        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
-        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
       else
-	if test "$host_cpu" = ia64; then
-	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	if test ia64 = "$host_cpu"; then
+	  hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
 	  allow_undefined_flag="-z nodefs"
-	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
 	else
 	 # Determine the default libpath from the value encoded in an
 	 # empty executable.
-	 if test "${lt_cv_aix_libpath+set}" = set; then
+	 if test set = "${lt_cv_aix_libpath+set}"; then
   aix_libpath=$lt_cv_aix_libpath
 else
   if ${lt_cv_aix_libpath_+:} false; then :
@@ -9666,7 +9908,7 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
   if test -z "$lt_cv_aix_libpath_"; then
-    lt_cv_aix_libpath_="/usr/lib:/lib"
+    lt_cv_aix_libpath_=/usr/lib:/lib
   fi
 
 fi
@@ -9674,21 +9916,33 @@ fi
   aix_libpath=$lt_cv_aix_libpath_
 fi
 
-	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	 hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
 	  # Warning - without using the other run time loading flags,
 	  # -berok will link without error, but may produce a broken library.
-	  no_undefined_flag=' ${wl}-bernotok'
-	  allow_undefined_flag=' ${wl}-berok'
-	  if test "$with_gnu_ld" = yes; then
+	  no_undefined_flag=' $wl-bernotok'
+	  allow_undefined_flag=' $wl-berok'
+	  if test yes = "$with_gnu_ld"; then
 	    # We only use this code for GNU lds that support --whole-archive.
-	    whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
 	  else
 	    # Exported symbols can be pulled into shared objects from archives
 	    whole_archive_flag_spec='$convenience'
 	  fi
 	  archive_cmds_need_lc=yes
-	  # This is similar to how AIX traditionally builds its shared libraries.
-	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	  archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
 	fi
       fi
       ;;
@@ -9697,7 +9951,7 @@ fi
       case $host_cpu in
       powerpc)
             # see comment about AmigaOS4 .so support
-            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
             archive_expsym_cmds=''
         ;;
       m68k)
@@ -9727,16 +9981,17 @@ fi
 	# Tell ltmain to make .lib files, not .a files.
 	libext=lib
 	# Tell ltmain to make .dll files, not .so files.
-	shrext_cmds=".dll"
+	shrext_cmds=.dll
 	# FIXME: Setting linknames here is a bad hack.
-	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-	  else
-	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-	  fi~
-	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-	  linknames='
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+            cp "$export_symbols" "$output_objdir/$soname.def";
+            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+          else
+            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+          fi~
+          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          linknames='
 	# The linker will not automatically build a static lib if we build a DLL.
 	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
 	enable_shared_with_static_runtimes=yes
@@ -9745,18 +10000,18 @@ fi
 	# Don't use ranlib
 	old_postinstall_cmds='chmod 644 $oldlib'
 	postlink_cmds='lt_outputfile="@OUTPUT@"~
-	  lt_tool_outputfile="@TOOL_OUTPUT@"~
-	  case $lt_outputfile in
-	    *.exe|*.EXE) ;;
-	    *)
-	      lt_outputfile="$lt_outputfile.exe"
-	      lt_tool_outputfile="$lt_tool_outputfile.exe"
-	      ;;
-	  esac~
-	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-	    $RM "$lt_outputfile.manifest";
-	  fi'
+          lt_tool_outputfile="@TOOL_OUTPUT@"~
+          case $lt_outputfile in
+            *.exe|*.EXE) ;;
+            *)
+              lt_outputfile=$lt_outputfile.exe
+              lt_tool_outputfile=$lt_tool_outputfile.exe
+              ;;
+          esac~
+          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+            $RM "$lt_outputfile.manifest";
+          fi'
 	;;
       *)
 	# Assume MSVC wrapper
@@ -9765,7 +10020,7 @@ fi
 	# Tell ltmain to make .lib files, not .a files.
 	libext=lib
 	# Tell ltmain to make .dll files, not .so files.
-	shrext_cmds=".dll"
+	shrext_cmds=.dll
 	# FIXME: Setting linknames here is a bad hack.
 	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
 	# The linker will automatically build a .lib file if we build a DLL.
@@ -9784,24 +10039,24 @@ fi
   hardcode_direct=no
   hardcode_automatic=yes
   hardcode_shlibpath_var=unsupported
-  if test "$lt_cv_ld_force_load" = "yes"; then
-    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  if test yes = "$lt_cv_ld_force_load"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
 
   else
     whole_archive_flag_spec=''
   fi
   link_all_deplibs=yes
-  allow_undefined_flag="$_lt_dar_allow_undefined"
+  allow_undefined_flag=$_lt_dar_allow_undefined
   case $cc_basename in
-     ifort*) _lt_dar_can_shared=yes ;;
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
      *) _lt_dar_can_shared=$GCC ;;
   esac
-  if test "$_lt_dar_can_shared" = "yes"; then
+  if test yes = "$_lt_dar_can_shared"; then
     output_verbose_link_cmd=func_echo_all
-    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
-    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
-    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
-    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
 
   else
   ld_shlibs=no
@@ -9843,33 +10098,33 @@ fi
       ;;
 
     hpux9*)
-      if test "$GCC" = yes; then
-	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      if test yes = "$GCC"; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
       else
-	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
       fi
-      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_flag_spec='$wl+b $wl$libdir'
       hardcode_libdir_separator=:
       hardcode_direct=yes
 
       # hardcode_minus_L: Not really in the search PATH,
       # but as the default location of the library.
       hardcode_minus_L=yes
-      export_dynamic_flag_spec='${wl}-E'
+      export_dynamic_flag_spec='$wl-E'
       ;;
 
     hpux10*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
-	archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
       else
 	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
       fi
-      if test "$with_gnu_ld" = no; then
-	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      if test no = "$with_gnu_ld"; then
+	hardcode_libdir_flag_spec='$wl+b $wl$libdir'
 	hardcode_libdir_separator=:
 	hardcode_direct=yes
 	hardcode_direct_absolute=yes
-	export_dynamic_flag_spec='${wl}-E'
+	export_dynamic_flag_spec='$wl-E'
 	# hardcode_minus_L: Not really in the search PATH,
 	# but as the default location of the library.
 	hardcode_minus_L=yes
@@ -9877,25 +10132,25 @@ fi
       ;;
 
     hpux11*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+      if test yes,no = "$GCC,$with_gnu_ld"; then
 	case $host_cpu in
 	hppa*64*)
-	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	ia64*)
-	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	*)
-	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	esac
       else
 	case $host_cpu in
 	hppa*64*)
-	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	ia64*)
-	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	*)
 
@@ -9907,7 +10162,7 @@ if ${lt_cv_prog_compiler__b+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler__b=no
-   save_LDFLAGS="$LDFLAGS"
+   save_LDFLAGS=$LDFLAGS
    LDFLAGS="$LDFLAGS -b"
    echo "$lt_simple_link_test_code" > conftest.$ac_ext
    if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -9926,14 +10181,14 @@ else
      fi
    fi
    $RM -r conftest*
-   LDFLAGS="$save_LDFLAGS"
+   LDFLAGS=$save_LDFLAGS
 
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
 $as_echo "$lt_cv_prog_compiler__b" >&6; }
 
-if test x"$lt_cv_prog_compiler__b" = xyes; then
-    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+if test yes = "$lt_cv_prog_compiler__b"; then
+    archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
 else
     archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
 fi
@@ -9941,8 +10196,8 @@ fi
 	  ;;
 	esac
       fi
-      if test "$with_gnu_ld" = no; then
-	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      if test no = "$with_gnu_ld"; then
+	hardcode_libdir_flag_spec='$wl+b $wl$libdir'
 	hardcode_libdir_separator=:
 
 	case $host_cpu in
@@ -9953,7 +10208,7 @@ fi
 	*)
 	  hardcode_direct=yes
 	  hardcode_direct_absolute=yes
-	  export_dynamic_flag_spec='${wl}-E'
+	  export_dynamic_flag_spec='$wl-E'
 
 	  # hardcode_minus_L: Not really in the search PATH,
 	  # but as the default location of the library.
@@ -9964,8 +10219,8 @@ fi
       ;;
 
     irix5* | irix6* | nonstopux*)
-      if test "$GCC" = yes; then
-	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 	# Try to use the -exported_symbol ld option, if it does not
 	# work, assume that -exports_file does not work either and
 	# implicitly export all symbols.
@@ -9975,8 +10230,8 @@ $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >
 if ${lt_cv_irix_exported_symbol+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  save_LDFLAGS="$LDFLAGS"
-	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+  save_LDFLAGS=$LDFLAGS
+	   LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
 	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 int foo (void) { return 0; }
@@ -9988,24 +10243,35 @@ else
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-           LDFLAGS="$save_LDFLAGS"
+           LDFLAGS=$save_LDFLAGS
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
 $as_echo "$lt_cv_irix_exported_symbol" >&6; }
-	if test "$lt_cv_irix_exported_symbol" = yes; then
-          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	if test yes = "$lt_cv_irix_exported_symbol"; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
 	fi
+	link_all_deplibs=no
       else
-	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
       fi
       archive_cmds_need_lc='no'
-      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
       hardcode_libdir_separator=:
       inherit_rpath=yes
       link_all_deplibs=yes
       ;;
 
+    linux*)
+      case $cc_basename in
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	ld_shlibs=yes
+	archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      esac
+      ;;
+
     netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
@@ -10020,7 +10286,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
     newsos6)
       archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
       hardcode_direct=yes
-      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
       hardcode_libdir_separator=:
       hardcode_shlibpath_var=no
       ;;
@@ -10028,27 +10294,19 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
     *nto* | *qnx*)
       ;;
 
-    openbsd*)
+    openbsd* | bitrig*)
       if test -f /usr/libexec/ld.so; then
 	hardcode_direct=yes
 	hardcode_shlibpath_var=no
 	hardcode_direct_absolute=yes
-	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
 	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
-	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
-	  export_dynamic_flag_spec='${wl}-E'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+	  export_dynamic_flag_spec='$wl-E'
 	else
-	  case $host_os in
-	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
-	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-	     hardcode_libdir_flag_spec='-R$libdir'
-	     ;;
-	   *)
-	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
-	     ;;
-	  esac
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  hardcode_libdir_flag_spec='$wl-rpath,$libdir'
 	fi
       else
 	ld_shlibs=no
@@ -10059,33 +10317,53 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
       hardcode_libdir_flag_spec='-L$libdir'
       hardcode_minus_L=yes
       allow_undefined_flag=unsupported
-      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
-      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      shrext_cmds=.dll
+      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      enable_shared_with_static_runtimes=yes
       ;;
 
     osf3*)
-      if test "$GCC" = yes; then
-	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
-	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      if test yes = "$GCC"; then
+	allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
       else
 	allow_undefined_flag=' -expect_unresolved \*'
-	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
       fi
       archive_cmds_need_lc='no'
-      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
       hardcode_libdir_separator=:
       ;;
 
     osf4* | osf5*)	# as osf3* with the addition of -msym flag
-      if test "$GCC" = yes; then
-	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
-	archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      if test yes = "$GCC"; then
+	allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+	archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
       else
 	allow_undefined_flag=' -expect_unresolved \*'
-	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
 
 	# Both c and cxx compiler support -rpath directly
 	hardcode_libdir_flag_spec='-rpath $libdir'
@@ -10096,24 +10374,24 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
 
     solaris*)
       no_undefined_flag=' -z defs'
-      if test "$GCC" = yes; then
-	wlarc='${wl}'
-	archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes = "$GCC"; then
+	wlarc='$wl'
+	archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
 	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
       else
 	case `$CC -V 2>&1` in
 	*"Compilers 5.0"*)
 	  wlarc=''
-	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
 	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
 	  ;;
 	*)
-	  wlarc='${wl}'
-	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  wlarc='$wl'
+	  archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
 	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
 	  ;;
 	esac
       fi
@@ -10123,11 +10401,11 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
       solaris2.[0-5] | solaris2.[0-5].*) ;;
       *)
 	# The compiler driver will combine and reorder linker options,
-	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but understands '-z linker_flag'.  GCC discards it without '$wl',
 	# but is careful enough not to reorder.
 	# Supported since Solaris 2.6 (maybe 2.5.1?)
-	if test "$GCC" = yes; then
-	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	if test yes = "$GCC"; then
+	  whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
 	else
 	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
 	fi
@@ -10137,10 +10415,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
       ;;
 
     sunos4*)
-      if test "x$host_vendor" = xsequent; then
+      if test sequent = "$host_vendor"; then
 	# Use $CC to link under sequent, because it throws in some extra .o
 	# files that make .init and .fini sections work.
-	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
       else
 	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
       fi
@@ -10189,43 +10467,43 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
       ;;
 
     sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
-      no_undefined_flag='${wl}-z,text'
+      no_undefined_flag='$wl-z,text'
       archive_cmds_need_lc=no
       hardcode_shlibpath_var=no
       runpath_var='LD_RUN_PATH'
 
-      if test "$GCC" = yes; then
-	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       else
-	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       fi
       ;;
 
     sysv5* | sco3.2v5* | sco5v6*)
-      # Note: We can NOT use -z defs as we might desire, because we do not
+      # Note: We CANNOT use -z defs as we might desire, because we do not
       # link with -lc, and that would cause any symbols used from libc to
       # always be unresolved, which means just about no library would
       # ever link correctly.  If we're not using GNU ld we use -z text
       # though, which does catch some bad symbols but isn't as heavy-handed
       # as -z defs.
-      no_undefined_flag='${wl}-z,text'
-      allow_undefined_flag='${wl}-z,nodefs'
+      no_undefined_flag='$wl-z,text'
+      allow_undefined_flag='$wl-z,nodefs'
       archive_cmds_need_lc=no
       hardcode_shlibpath_var=no
-      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_flag_spec='$wl-R,$libdir'
       hardcode_libdir_separator=':'
       link_all_deplibs=yes
-      export_dynamic_flag_spec='${wl}-Bexport'
+      export_dynamic_flag_spec='$wl-Bexport'
       runpath_var='LD_RUN_PATH'
 
-      if test "$GCC" = yes; then
-	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       else
-	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       fi
       ;;
 
@@ -10240,10 +10518,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
       ;;
     esac
 
-    if test x$host_vendor = xsni; then
+    if test sni = "$host_vendor"; then
       case $host in
       sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	export_dynamic_flag_spec='$wl-Blargedynsym'
 	;;
       esac
     fi
@@ -10251,7 +10529,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
 $as_echo "$ld_shlibs" >&6; }
-test "$ld_shlibs" = no && can_build_shared=no
+test no = "$ld_shlibs" && can_build_shared=no
 
 with_gnu_ld=$with_gnu_ld
 
@@ -10277,7 +10555,7 @@ x|xyes)
   # Assume -lc should be added
   archive_cmds_need_lc=yes
 
-  if test "$enable_shared" = yes && test "$GCC" = yes; then
+  if test yes,yes = "$GCC,$enable_shared"; then
     case $archive_cmds in
     *'~'*)
       # FIXME: we may have to deal with multi-command sequences.
@@ -10492,14 +10770,14 @@ esac
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
 $as_echo_n "checking dynamic linker characteristics... " >&6; }
 
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   case $host_os in
-    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
-    *) lt_awk_arg="/^libraries:/" ;;
+    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+    *) lt_awk_arg='/^libraries:/' ;;
   esac
   case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
-    *) lt_sed_strip_eq="s,=/,/,g" ;;
+    mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+    *) lt_sed_strip_eq='s|=/|/|g' ;;
   esac
   lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
   case $lt_search_path_spec in
@@ -10515,28 +10793,35 @@ if test "$GCC" = yes; then
     ;;
   esac
   # Ok, now we have the path, separated by spaces, we can step through it
-  # and add multilib dir if necessary.
+  # and add multilib dir if necessary...
   lt_tmp_lt_search_path_spec=
-  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  # ...but if some path component already ends with the multilib dir we assume
+  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+  case "$lt_multi_os_dir; $lt_search_path_spec " in
+  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+    lt_multi_os_dir=
+    ;;
+  esac
   for lt_sys_path in $lt_search_path_spec; do
-    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
-      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
-    else
+    if test -d "$lt_sys_path$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+    elif test -n "$lt_multi_os_dir"; then
       test -d "$lt_sys_path" && \
 	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
     fi
   done
   lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
-  lt_foo="";
-  lt_count=0;
+BEGIN {RS = " "; FS = "/|\n";} {
+  lt_foo = "";
+  lt_count = 0;
   for (lt_i = NF; lt_i > 0; lt_i--) {
     if ($lt_i != "" && $lt_i != ".") {
       if ($lt_i == "..") {
         lt_count++;
       } else {
         if (lt_count == 0) {
-          lt_foo="/" $lt_i lt_foo;
+          lt_foo = "/" $lt_i lt_foo;
         } else {
           lt_count--;
         }
@@ -10550,7 +10835,7 @@ BEGIN {RS=" "; FS="/|\n";} {
   # for these hosts.
   case $host_os in
     mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
-      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+      $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
   esac
   sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
 else
@@ -10559,7 +10844,7 @@ fi
 library_names_spec=
 libname_spec='lib$name'
 soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
 postinstall_cmds=
 postuninstall_cmds=
 finish_cmds=
@@ -10576,14 +10861,16 @@ hardcode_into_libs=no
 # flags to be left without arguments
 need_version=unknown
 
+
+
 case $host_os in
 aix3*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
   shlibpath_var=LIBPATH
 
   # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='${libname}${release}${shared_ext}$major'
+  soname_spec='$libname$release$shared_ext$major'
   ;;
 
 aix[4-9]*)
@@ -10591,41 +10878,91 @@ aix[4-9]*)
   need_lib_prefix=no
   need_version=no
   hardcode_into_libs=yes
-  if test "$host_cpu" = ia64; then
+  if test ia64 = "$host_cpu"; then
     # AIX 5 supports IA64
-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
     shlibpath_var=LD_LIBRARY_PATH
   else
     # With GCC up to 2.95.x, collect2 would create an import file
     # for dependence libraries.  The import file would start with
-    # the line `#! .'.  This would cause the generated library to
-    # depend on `.', always an invalid library.  This was fixed in
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
     # development snapshots of GCC prior to 3.0.
     case $host_os in
       aix4 | aix4.[01] | aix4.[01].*)
       if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
 	   echo ' yes '
-	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
 	:
       else
 	can_build_shared=no
       fi
       ;;
     esac
-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
     # soname into executable. Probably we can add versioning support to
     # collect2, so additional links can be useful in future.
-    if test "$aix_use_runtimelinking" = yes; then
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
       # If using run time linking (on AIX 4.2 or later) use lib<name>.so
       # instead of lib<name>.a to let people know that these are not
       # typical AIX shared libraries.
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    else
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a(lib.so.V)'
       # We preserve .a as extension for shared libraries through AIX4.2
       # and later when we are not doing run time linking.
-      library_names_spec='${libname}${release}.a $libname.a'
-      soname_spec='${libname}${release}${shared_ext}$major'
-    fi
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
     shlibpath_var=LIBPATH
   fi
   ;;
@@ -10635,18 +10972,18 @@ amigaos*)
   powerpc)
     # Since July 2007 AmigaOS4 officially supports .so libraries.
     # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
     ;;
   m68k)
     library_names_spec='$libname.ixlibrary $libname.a'
     # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
     ;;
   esac
   ;;
 
 beos*)
-  library_names_spec='${libname}${shared_ext}'
+  library_names_spec='$libname$shared_ext'
   dynamic_linker="$host_os ld.so"
   shlibpath_var=LIBRARY_PATH
   ;;
@@ -10654,8 +10991,8 @@ beos*)
 bsdi[45]*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -10667,7 +11004,7 @@ bsdi[45]*)
 
 cygwin* | mingw* | pw32* | cegcc*)
   version_type=windows
-  shrext_cmds=".dll"
+  shrext_cmds=.dll
   need_version=no
   need_lib_prefix=no
 
@@ -10676,8 +11013,8 @@ cygwin* | mingw* | pw32* | cegcc*)
     # gcc
     library_names_spec='$libname.dll.a'
     # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
       dldir=$destdir/`dirname \$dlpath`~
       test -d \$dldir || mkdir -p \$dldir~
       $install_prog $dir/$dlname \$dldir/$dlname~
@@ -10693,17 +11030,17 @@ cygwin* | mingw* | pw32* | cegcc*)
     case $host_os in
     cygwin*)
       # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
 
       sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
       ;;
     mingw* | cegcc*)
       # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
       ;;
     pw32*)
       # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
       ;;
     esac
     dynamic_linker='Win32 ld.exe'
@@ -10712,8 +11049,8 @@ cygwin* | mingw* | pw32* | cegcc*)
   *,cl*)
     # Native MSVC
     libname_spec='$name'
-    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
-    library_names_spec='${libname}.dll.lib'
+    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
 
     case $build_os in
     mingw*)
@@ -10740,7 +11077,7 @@ cygwin* | mingw* | pw32* | cegcc*)
       sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
       ;;
     *)
-      sys_lib_search_path_spec="$LIB"
+      sys_lib_search_path_spec=$LIB
       if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
         # It is most probably a Windows format PATH.
         sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -10753,8 +11090,8 @@ cygwin* | mingw* | pw32* | cegcc*)
     esac
 
     # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
       dldir=$destdir/`dirname \$dlpath`~
       test -d \$dldir || mkdir -p \$dldir~
       $install_prog $dir/$dlname \$dldir/$dlname'
@@ -10767,7 +11104,7 @@ cygwin* | mingw* | pw32* | cegcc*)
 
   *)
     # Assume MSVC wrapper
-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
     dynamic_linker='Win32 ld.exe'
     ;;
   esac
@@ -10780,8 +11117,8 @@ darwin* | rhapsody*)
   version_type=darwin
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
-  soname_spec='${libname}${release}${major}$shared_ext'
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
   shlibpath_overrides_runpath=yes
   shlibpath_var=DYLD_LIBRARY_PATH
   shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
@@ -10794,8 +11131,8 @@ dgux*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   ;;
 
@@ -10813,12 +11150,13 @@ freebsd* | dragonfly*)
   version_type=freebsd-$objformat
   case $version_type in
     freebsd-elf*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
       need_version=no
       need_lib_prefix=no
       ;;
     freebsd-*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
       need_version=yes
       ;;
   esac
@@ -10848,10 +11186,10 @@ haiku*)
   need_lib_prefix=no
   need_version=no
   dynamic_linker="$host_os runtime_loader"
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
+  shlibpath_overrides_runpath=no
   sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
   hardcode_into_libs=yes
   ;;
@@ -10869,14 +11207,15 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.so"
     shlibpath_var=LD_LIBRARY_PATH
     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    if test "X$HPUX_IA64_MODE" = X32; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
       sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
     else
       sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
     fi
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
   hppa*64*)
     shrext_cmds='.sl'
@@ -10884,8 +11223,8 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.sl"
     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
@@ -10894,8 +11233,8 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.sl"
     shlibpath_var=SHLIB_PATH
     shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     ;;
   esac
   # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -10908,8 +11247,8 @@ interix[3-9]*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
@@ -10920,7 +11259,7 @@ irix5* | irix6* | nonstopux*)
   case $host_os in
     nonstopux*) version_type=nonstopux ;;
     *)
-	if test "$lt_cv_prog_gnu_ld" = yes; then
+	if test yes = "$lt_cv_prog_gnu_ld"; then
 		version_type=linux # correct to gnu/linux during the next big refactor
 	else
 		version_type=irix
@@ -10928,8 +11267,8 @@ irix5* | irix6* | nonstopux*)
   esac
   need_lib_prefix=no
   need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
   case $host_os in
   irix5* | nonstopux*)
     libsuff= shlibsuff=
@@ -10948,8 +11287,8 @@ irix5* | irix6* | nonstopux*)
   esac
   shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
   shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
   hardcode_into_libs=yes
   ;;
 
@@ -10958,13 +11297,33 @@ linux*oldld* | linux*aout* | linux*coff*)
   dynamic_linker=no
   ;;
 
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  hardcode_libdir_flag_spec='-L$libdir'
+  ;;
+
 # This must be glibc/ELF.
 linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
@@ -11008,7 +11367,12 @@ fi
   # before this can be enabled.
   hardcode_into_libs=yes
 
-  # Append ld.so.conf contents to the search path
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
   if test -f /etc/ld.so.conf; then
     lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
     sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -11040,12 +11404,12 @@ netbsd*)
   need_lib_prefix=no
   need_version=no
   if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
     finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
     dynamic_linker='NetBSD (a.out) ld.so'
   else
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     dynamic_linker='NetBSD ld.elf_so'
   fi
   shlibpath_var=LD_LIBRARY_PATH
@@ -11055,7 +11419,7 @@ netbsd*)
 
 newsos6)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   ;;
@@ -11064,58 +11428,68 @@ newsos6)
   version_type=qnx
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
   dynamic_linker='ldqnx.so'
   ;;
 
-openbsd*)
+openbsd* | bitrig*)
   version_type=sunos
-  sys_lib_dlsearch_path_spec="/usr/lib"
+  sys_lib_dlsearch_path_spec=/usr/lib
   need_lib_prefix=no
-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
-  case $host_os in
-    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
-    *)				need_version=no  ;;
-  esac
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    case $host_os in
-      openbsd2.[89] | openbsd2.[89].*)
-	shlibpath_overrides_runpath=no
-	;;
-      *)
-	shlibpath_overrides_runpath=yes
-	;;
-      esac
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
   else
-    shlibpath_overrides_runpath=yes
+    need_version=yes
   fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
   ;;
 
 os2*)
   libname_spec='$name'
-  shrext_cmds=".dll"
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
   need_lib_prefix=no
-  library_names_spec='$libname${shared_ext} $libname.a'
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
   dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=LIBPATH
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
   ;;
 
 osf3* | osf4* | osf5*)
   version_type=osf
   need_lib_prefix=no
   need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
   ;;
 
 rdos*)
@@ -11126,8 +11500,8 @@ solaris*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   hardcode_into_libs=yes
@@ -11137,11 +11511,11 @@ solaris*)
 
 sunos4*)
   version_type=sunos
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
   finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     need_lib_prefix=no
   fi
   need_version=yes
@@ -11149,8 +11523,8 @@ sunos4*)
 
 sysv4 | sysv4.3*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   case $host_vendor in
     sni)
@@ -11171,24 +11545,24 @@ sysv4 | sysv4.3*)
   ;;
 
 sysv4*MP*)
-  if test -d /usr/nec ;then
+  if test -d /usr/nec; then
     version_type=linux # correct to gnu/linux during the next big refactor
-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
-    soname_spec='$libname${shared_ext}.$major'
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
     shlibpath_var=LD_LIBRARY_PATH
   fi
   ;;
 
 sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=freebsd-elf
+  version_type=sco
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   hardcode_into_libs=yes
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
   else
     sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -11206,7 +11580,7 @@ tpf*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
@@ -11214,8 +11588,8 @@ tpf*)
 
 uts4*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   ;;
 
@@ -11225,20 +11599,35 @@ uts4*)
 esac
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
 $as_echo "$dynamic_linker" >&6; }
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
 
 variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
-  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
 fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
-  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
 fi
 
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
 
 
 
@@ -11335,15 +11724,15 @@ $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
 hardcode_action=
 if test -n "$hardcode_libdir_flag_spec" ||
    test -n "$runpath_var" ||
-   test "X$hardcode_automatic" = "Xyes" ; then
+   test yes = "$hardcode_automatic"; then
 
   # We can hardcode non-existent directories.
-  if test "$hardcode_direct" != no &&
+  if test no != "$hardcode_direct" &&
      # If the only mechanism to avoid hardcoding is shlibpath_var, we
      # have to relink, otherwise we might link with an installed library
      # when we should be linking with a yet-to-be-installed one
-     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
-     test "$hardcode_minus_L" != no; then
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
+     test no != "$hardcode_minus_L"; then
     # Linking always hardcodes the temporary library directory.
     hardcode_action=relink
   else
@@ -11358,12 +11747,12 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
 $as_echo "$hardcode_action" >&6; }
 
-if test "$hardcode_action" = relink ||
-   test "$inherit_rpath" = yes; then
+if test relink = "$hardcode_action" ||
+   test yes = "$inherit_rpath"; then
   # Fast installation is not supported
   enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
-     test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
   # Fast installation is not necessary
   enable_fast_install=needless
 fi
@@ -11373,7 +11762,7 @@ fi
 
 
 
-  if test "x$enable_dlopen" != xyes; then
+  if test yes != "$enable_dlopen"; then
   enable_dlopen=unknown
   enable_dlopen_self=unknown
   enable_dlopen_self_static=unknown
@@ -11383,23 +11772,23 @@ else
 
   case $host_os in
   beos*)
-    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen=load_add_on
     lt_cv_dlopen_libs=
     lt_cv_dlopen_self=yes
     ;;
 
   mingw* | pw32* | cegcc*)
-    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen=LoadLibrary
     lt_cv_dlopen_libs=
     ;;
 
   cygwin*)
-    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen=dlopen
     lt_cv_dlopen_libs=
     ;;
 
   darwin*)
-  # if libdl is installed we need to link against it
+    # if libdl is installed we need to link against it
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
 $as_echo_n "checking for dlopen in -ldl... " >&6; }
 if ${ac_cv_lib_dl_dlopen+:} false; then :
@@ -11437,10 +11826,10 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
 $as_echo "$ac_cv_lib_dl_dlopen" >&6; }
 if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
-  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
 else
 
-    lt_cv_dlopen="dyld"
+    lt_cv_dlopen=dyld
     lt_cv_dlopen_libs=
     lt_cv_dlopen_self=yes
 
@@ -11448,10 +11837,18 @@ fi
 
     ;;
 
+  tpf*)
+    # Don't try to run any link tests for TPF.  We know it's impossible
+    # because TPF is a cross-compiler, and we know how we open DSOs.
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=no
+    ;;
+
   *)
     ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
 if test "x$ac_cv_func_shl_load" = xyes; then :
-  lt_cv_dlopen="shl_load"
+  lt_cv_dlopen=shl_load
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
 $as_echo_n "checking for shl_load in -ldld... " >&6; }
@@ -11490,11 +11887,11 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
 $as_echo "$ac_cv_lib_dld_shl_load" >&6; }
 if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
-  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+  lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
 else
   ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
 if test "x$ac_cv_func_dlopen" = xyes; then :
-  lt_cv_dlopen="dlopen"
+  lt_cv_dlopen=dlopen
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
 $as_echo_n "checking for dlopen in -ldl... " >&6; }
@@ -11533,7 +11930,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
 $as_echo "$ac_cv_lib_dl_dlopen" >&6; }
 if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
-  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
 $as_echo_n "checking for dlopen in -lsvld... " >&6; }
@@ -11572,7 +11969,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
 $as_echo "$ac_cv_lib_svld_dlopen" >&6; }
 if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
-  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
 $as_echo_n "checking for dld_link in -ldld... " >&6; }
@@ -11611,7 +12008,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
 $as_echo "$ac_cv_lib_dld_dld_link" >&6; }
 if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
-  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+  lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
 fi
 
 
@@ -11632,21 +12029,21 @@ fi
     ;;
   esac
 
-  if test "x$lt_cv_dlopen" != xno; then
-    enable_dlopen=yes
-  else
+  if test no = "$lt_cv_dlopen"; then
     enable_dlopen=no
+  else
+    enable_dlopen=yes
   fi
 
   case $lt_cv_dlopen in
   dlopen)
-    save_CPPFLAGS="$CPPFLAGS"
-    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+    save_CPPFLAGS=$CPPFLAGS
+    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
 
-    save_LDFLAGS="$LDFLAGS"
+    save_LDFLAGS=$LDFLAGS
     wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
 
-    save_LIBS="$LIBS"
+    save_LIBS=$LIBS
     LIBS="$lt_cv_dlopen_libs $LIBS"
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
@@ -11654,7 +12051,7 @@ $as_echo_n "checking whether a program can dlopen itself... " >&6; }
 if ${lt_cv_dlopen_self+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  	  if test "$cross_compiling" = yes; then :
+  	  if test yes = "$cross_compiling"; then :
   lt_cv_dlopen_self=cross
 else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -11701,9 +12098,9 @@ else
 #  endif
 #endif
 
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
    correspondingly for the symbols needed.  */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
 int fnord () __attribute__((visibility("default")));
 #endif
 
@@ -11733,7 +12130,7 @@ _LT_EOF
   (eval $ac_link) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
     (./conftest; exit; ) >&5 2>/dev/null
     lt_status=$?
     case x$lt_status in
@@ -11753,14 +12150,14 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
 $as_echo "$lt_cv_dlopen_self" >&6; }
 
-    if test "x$lt_cv_dlopen_self" = xyes; then
+    if test yes = "$lt_cv_dlopen_self"; then
       wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
 if ${lt_cv_dlopen_self_static+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  	  if test "$cross_compiling" = yes; then :
+  	  if test yes = "$cross_compiling"; then :
   lt_cv_dlopen_self_static=cross
 else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -11807,9 +12204,9 @@ else
 #  endif
 #endif
 
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
    correspondingly for the symbols needed.  */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
 int fnord () __attribute__((visibility("default")));
 #endif
 
@@ -11839,7 +12236,7 @@ _LT_EOF
   (eval $ac_link) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
     (./conftest; exit; ) >&5 2>/dev/null
     lt_status=$?
     case x$lt_status in
@@ -11860,9 +12257,9 @@ fi
 $as_echo "$lt_cv_dlopen_self_static" >&6; }
     fi
 
-    CPPFLAGS="$save_CPPFLAGS"
-    LDFLAGS="$save_LDFLAGS"
-    LIBS="$save_LIBS"
+    CPPFLAGS=$save_CPPFLAGS
+    LDFLAGS=$save_LDFLAGS
+    LIBS=$save_LIBS
     ;;
   esac
 
@@ -11906,7 +12303,7 @@ else
 # FIXME - insert some real tests, host_os isn't really good enough
   case $host_os in
   darwin*)
-    if test -n "$STRIP" ; then
+    if test -n "$STRIP"; then
       striplib="$STRIP -x"
       old_striplib="$STRIP -S"
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
@@ -11934,7 +12331,7 @@ fi
 
 
 
-  # Report which library types will actually be built
+  # Report what library types will actually be built
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
 $as_echo_n "checking if libtool supports shared libraries... " >&6; }
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
@@ -11942,13 +12339,13 @@ $as_echo "$can_build_shared" >&6; }
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
 $as_echo_n "checking whether to build shared libraries... " >&6; }
-  test "$can_build_shared" = "no" && enable_shared=no
+  test no = "$can_build_shared" && enable_shared=no
 
   # On AIX, shared libraries and static libraries use the same namespace, and
   # are all built from PIC.
   case $host_os in
   aix3*)
-    test "$enable_shared" = yes && enable_static=no
+    test yes = "$enable_shared" && enable_static=no
     if test -n "$RANLIB"; then
       archive_cmds="$archive_cmds~\$RANLIB \$lib"
       postinstall_cmds='$RANLIB $lib'
@@ -11956,8 +12353,12 @@ $as_echo_n "checking whether to build shared libraries... " >&6; }
     ;;
 
   aix[4-9]*)
-    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-      test "$enable_shared" = yes && enable_static=no
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+      yes,aix,yes) ;;			# shared object as lib.so file only
+      yes,svr4,*) ;;			# shared object as lib.so archive member only
+      yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+      esac
     fi
     ;;
   esac
@@ -11967,7 +12368,7 @@ $as_echo "$enable_shared" >&6; }
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
 $as_echo_n "checking whether to build static libraries... " >&6; }
   # Make sure either enable_shared or enable_static is yes.
-  test "$enable_shared" = yes || enable_static=yes
+  test yes = "$enable_shared" || enable_static=yes
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
 $as_echo "$enable_static" >&6; }
 
@@ -11981,7 +12382,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
-CC="$lt_save_CC"
+CC=$lt_save_CC
 
 
 
@@ -13443,15 +13844,15 @@ fi
 
 func_stripname_cnf ()
 {
-  case ${2} in
-  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
-  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  case $2 in
+  .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;;
+  *)  func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;;
   esac
 } # func_stripname_cnf
 
-      if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
-    (test "X$CXX" != "Xg++"))) ; then
+      if test -n "$CXX" && ( test no != "$CXX" &&
+    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+    (test g++ != "$CXX"))); then
   ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -13630,7 +14031,7 @@ objext_CXX=$objext
 # the CXX compiler isn't working.  Some variables (like enable_shared)
 # are currently assumed to apply to all compilers on this platform,
 # and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
+if test yes != "$_lt_caught_CXX_error"; then
   # Code to be used in simple compile tests
   lt_simple_compile_test_code="int some_variable = 0;"
 
@@ -13691,46 +14092,39 @@ $RM -r conftest*
   CFLAGS=$CXXFLAGS
   compiler=$CC
   compiler_CXX=$CC
-  for cc_temp in $compiler""; do
-  case $cc_temp in
-    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
-    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
-    \-*) ;;
-    *) break;;
-  esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+  func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
 
 
   if test -n "$compiler"; then
     # We don't want -fno-exception when compiling C++ code, so set the
     # no_builtin_flag separately
-    if test "$GXX" = yes; then
+    if test yes = "$GXX"; then
       lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
     else
       lt_prog_compiler_no_builtin_flag_CXX=
     fi
 
-    if test "$GXX" = yes; then
+    if test yes = "$GXX"; then
       # Set up default GNU C++ configuration
 
 
 
 # Check whether --with-gnu-ld was given.
 if test "${with_gnu_ld+set}" = set; then :
-  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
 else
   with_gnu_ld=no
 fi
 
 ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   # Check if gcc -print-prog-name=ld gives a path.
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
 $as_echo_n "checking for ld used by $CC... " >&6; }
   case $host in
   *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
+    # gcc leaves a trailing carriage return, which upsets mingw
     ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
   *)
     ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -13744,7 +14138,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
       while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
 	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
       done
-      test -z "$LD" && LD="$ac_prog"
+      test -z "$LD" && LD=$ac_prog
       ;;
   "")
     # If it fails, then pretend we aren't using GCC.
@@ -13755,7 +14149,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
     with_gnu_ld=unknown
     ;;
   esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
 $as_echo_n "checking for GNU ld... " >&6; }
 else
@@ -13766,32 +14160,32 @@ if ${lt_cv_path_LD+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   if test -z "$LD"; then
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
   for ac_dir in $PATH; do
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
     test -z "$ac_dir" && ac_dir=.
     if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
+      lt_cv_path_LD=$ac_dir/$ac_prog
       # Check to see if the program is GNU ld.  I'd rather use --version,
       # but apparently some variants of GNU ld only accept -v.
       # Break only if it was the GNU/non-GNU ld that we prefer.
       case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
       *GNU* | *'with BFD'*)
-	test "$with_gnu_ld" != no && break
+	test no != "$with_gnu_ld" && break
 	;;
       *)
-	test "$with_gnu_ld" != yes && break
+	test yes != "$with_gnu_ld" && break
 	;;
       esac
     fi
   done
-  IFS="$lt_save_ifs"
+  IFS=$lt_save_ifs
 else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
 fi
 fi
 
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
 if test -n "$LD"; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
 $as_echo "$LD" >&6; }
@@ -13827,22 +14221,22 @@ with_gnu_ld=$lt_cv_prog_gnu_ld
 
       # Check if GNU C++ uses GNU ld as the underlying linker, since the
       # archiving commands below assume that GNU ld is being used.
-      if test "$with_gnu_ld" = yes; then
-        archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-        archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      if test yes = "$with_gnu_ld"; then
+        archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+        archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 
-        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
-        export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+        export_dynamic_flag_spec_CXX='$wl--export-dynamic'
 
         # If archive_cmds runs LD, not CC, wlarc should be empty
         # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
         #     investigate it a little bit more. (MM)
-        wlarc='${wl}'
+        wlarc='$wl'
 
         # ancient GNU ld didn't support --whole-archive et. al.
         if eval "`$CC -print-prog-name=ld` --help 2>&1" |
 	  $GREP 'no-whole-archive' > /dev/null; then
-          whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+          whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
         else
           whole_archive_flag_spec_CXX=
         fi
@@ -13879,18 +14273,30 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
         ld_shlibs_CXX=no
         ;;
       aix[4-9]*)
-        if test "$host_cpu" = ia64; then
+        if test ia64 = "$host_cpu"; then
           # On IA64, the linker does run time linking by default, so we don't
           # have to do anything special.
           aix_use_runtimelinking=no
           exp_sym_flag='-Bexport'
-          no_entry_flag=""
+          no_entry_flag=
         else
           aix_use_runtimelinking=no
 
           # Test if we are trying to use run time linking or normal
           # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-          # need to do runtime linking.
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname,aix_use_runtimelinking" is:
+          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix,yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
           case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
 	    for ld_flag in $LDFLAGS; do
 	      case $ld_flag in
@@ -13900,6 +14306,13 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
 	        ;;
 	      esac
 	    done
+	    if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
 	    ;;
           esac
 
@@ -13918,13 +14331,21 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
         hardcode_direct_absolute_CXX=yes
         hardcode_libdir_separator_CXX=':'
         link_all_deplibs_CXX=yes
-        file_list_spec_CXX='${wl}-f,'
+        file_list_spec_CXX='$wl-f,'
+        case $with_aix_soname,$aix_use_runtimelinking in
+        aix,*) ;;	# no import file
+        svr4,* | *,yes) # use import file
+          # The Import File defines what to hardcode.
+          hardcode_direct_CXX=no
+          hardcode_direct_absolute_CXX=no
+          ;;
+        esac
 
-        if test "$GXX" = yes; then
+        if test yes = "$GXX"; then
           case $host_os in aix4.[012]|aix4.[012].*)
           # We only want to do this on AIX 4.2 and lower, the check
           # below for broken collect2 doesn't work under 4.3+
-	  collect2name=`${CC} -print-prog-name=collect2`
+	  collect2name=`$CC -print-prog-name=collect2`
 	  if test -f "$collect2name" &&
 	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
 	  then
@@ -13942,36 +14363,44 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
 	  fi
           esac
           shared_flag='-shared'
-	  if test "$aix_use_runtimelinking" = yes; then
-	    shared_flag="$shared_flag "'${wl}-G'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag=$shared_flag' $wl-G'
 	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
         else
           # not using gcc
-          if test "$host_cpu" = ia64; then
+          if test ia64 = "$host_cpu"; then
 	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
 	  # chokes on -Wl,-G. The following line is correct:
 	  shared_flag='-G'
           else
-	    if test "$aix_use_runtimelinking" = yes; then
-	      shared_flag='${wl}-G'
+	    if test yes = "$aix_use_runtimelinking"; then
+	      shared_flag='$wl-G'
 	    else
-	      shared_flag='${wl}-bM:SRE'
+	      shared_flag='$wl-bM:SRE'
 	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
           fi
         fi
 
-        export_dynamic_flag_spec_CXX='${wl}-bexpall'
+        export_dynamic_flag_spec_CXX='$wl-bexpall'
         # It seems that -bexpall does not export symbols beginning with
         # underscore (_), so it is better to generate a list of symbols to
 	# export.
         always_export_symbols_CXX=yes
-        if test "$aix_use_runtimelinking" = yes; then
+	if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
           # Warning - without using the other runtime loading flags (-brtl),
           # -berok will link without error, but may produce a broken library.
-          allow_undefined_flag_CXX='-berok'
+          # The "-G" linker flag allows undefined symbols.
+          no_undefined_flag_CXX='-bernotok'
           # Determine the default libpath from the value encoded in an empty
           # executable.
-          if test "${lt_cv_aix_libpath+set}" = set; then
+          if test set = "${lt_cv_aix_libpath+set}"; then
   aix_libpath=$lt_cv_aix_libpath
 else
   if ${lt_cv_aix_libpath__CXX+:} false; then :
@@ -14006,7 +14435,7 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
   if test -z "$lt_cv_aix_libpath__CXX"; then
-    lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+    lt_cv_aix_libpath__CXX=/usr/lib:/lib
   fi
 
 fi
@@ -14014,18 +14443,18 @@ fi
   aix_libpath=$lt_cv_aix_libpath__CXX
 fi
 
-          hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+          hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
 
-          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
         else
-          if test "$host_cpu" = ia64; then
-	    hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+          if test ia64 = "$host_cpu"; then
+	    hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib'
 	    allow_undefined_flag_CXX="-z nodefs"
-	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
           else
 	    # Determine the default libpath from the value encoded in an
 	    # empty executable.
-	    if test "${lt_cv_aix_libpath+set}" = set; then
+	    if test set = "${lt_cv_aix_libpath+set}"; then
   aix_libpath=$lt_cv_aix_libpath
 else
   if ${lt_cv_aix_libpath__CXX+:} false; then :
@@ -14060,7 +14489,7 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
   if test -z "$lt_cv_aix_libpath__CXX"; then
-    lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+    lt_cv_aix_libpath__CXX=/usr/lib:/lib
   fi
 
 fi
@@ -14068,22 +14497,34 @@ fi
   aix_libpath=$lt_cv_aix_libpath__CXX
 fi
 
-	    hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
 	    # Warning - without using the other run time loading flags,
 	    # -berok will link without error, but may produce a broken library.
-	    no_undefined_flag_CXX=' ${wl}-bernotok'
-	    allow_undefined_flag_CXX=' ${wl}-berok'
-	    if test "$with_gnu_ld" = yes; then
+	    no_undefined_flag_CXX=' $wl-bernotok'
+	    allow_undefined_flag_CXX=' $wl-berok'
+	    if test yes = "$with_gnu_ld"; then
 	      # We only use this code for GNU lds that support --whole-archive.
-	      whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	      whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
 	    else
 	      # Exported symbols can be pulled into shared objects from archives
 	      whole_archive_flag_spec_CXX='$convenience'
 	    fi
 	    archive_cmds_need_lc_CXX=yes
-	    # This is similar to how AIX traditionally builds its shared
-	    # libraries.
-	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	    archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d'
           fi
         fi
         ;;
@@ -14093,7 +14534,7 @@ fi
 	  allow_undefined_flag_CXX=unsupported
 	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
 	  # support --undefined.  This deserves some investigation.  FIXME
-	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
 	else
 	  ld_shlibs_CXX=no
 	fi
@@ -14121,57 +14562,58 @@ fi
 	  # Tell ltmain to make .lib files, not .a files.
 	  libext=lib
 	  # Tell ltmain to make .dll files, not .so files.
-	  shrext_cmds=".dll"
+	  shrext_cmds=.dll
 	  # FIXME: Setting linknames here is a bad hack.
-	  archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-	  archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-	    else
-	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-	    fi~
-	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-	    linknames='
+	  archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	  archive_expsym_cmds_CXX='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+              cp "$export_symbols" "$output_objdir/$soname.def";
+              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+            else
+              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+            fi~
+            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+            linknames='
 	  # The linker will not automatically build a static lib if we build a DLL.
 	  # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true'
 	  enable_shared_with_static_runtimes_CXX=yes
 	  # Don't use ranlib
 	  old_postinstall_cmds_CXX='chmod 644 $oldlib'
 	  postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~
-	    lt_tool_outputfile="@TOOL_OUTPUT@"~
-	    case $lt_outputfile in
-	      *.exe|*.EXE) ;;
-	      *)
-		lt_outputfile="$lt_outputfile.exe"
-		lt_tool_outputfile="$lt_tool_outputfile.exe"
-		;;
-	    esac~
-	    func_to_tool_file "$lt_outputfile"~
-	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-	      $RM "$lt_outputfile.manifest";
-	    fi'
+            lt_tool_outputfile="@TOOL_OUTPUT@"~
+            case $lt_outputfile in
+              *.exe|*.EXE) ;;
+              *)
+                lt_outputfile=$lt_outputfile.exe
+                lt_tool_outputfile=$lt_tool_outputfile.exe
+                ;;
+            esac~
+            func_to_tool_file "$lt_outputfile"~
+            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+              $RM "$lt_outputfile.manifest";
+            fi'
 	  ;;
 	*)
 	  # g++
 	  # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
 	  # as there is no search path for DLLs.
 	  hardcode_libdir_flag_spec_CXX='-L$libdir'
-	  export_dynamic_flag_spec_CXX='${wl}--export-all-symbols'
+	  export_dynamic_flag_spec_CXX='$wl--export-all-symbols'
 	  allow_undefined_flag_CXX=unsupported
 	  always_export_symbols_CXX=no
 	  enable_shared_with_static_runtimes_CXX=yes
 
 	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	    # If the export-symbols file already is a .def file (1st line
-	    # is EXPORTS), use it as is; otherwise, prepend...
-	    archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	      cp $export_symbols $output_objdir/$soname.def;
-	    else
-	      echo EXPORTS > $output_objdir/$soname.def;
-	      cat $export_symbols >> $output_objdir/$soname.def;
-	    fi~
-	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file, use it as
+	    # is; otherwise, prepend EXPORTS...
+	    archive_expsym_cmds_CXX='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+              cp $export_symbols $output_objdir/$soname.def;
+            else
+              echo EXPORTS > $output_objdir/$soname.def;
+              cat $export_symbols >> $output_objdir/$soname.def;
+            fi~
+            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
 	  else
 	    ld_shlibs_CXX=no
 	  fi
@@ -14185,27 +14627,27 @@ fi
   hardcode_direct_CXX=no
   hardcode_automatic_CXX=yes
   hardcode_shlibpath_var_CXX=unsupported
-  if test "$lt_cv_ld_force_load" = "yes"; then
-    whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  if test yes = "$lt_cv_ld_force_load"; then
+    whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
 
   else
     whole_archive_flag_spec_CXX=''
   fi
   link_all_deplibs_CXX=yes
-  allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+  allow_undefined_flag_CXX=$_lt_dar_allow_undefined
   case $cc_basename in
-     ifort*) _lt_dar_can_shared=yes ;;
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
      *) _lt_dar_can_shared=$GCC ;;
   esac
-  if test "$_lt_dar_can_shared" = "yes"; then
+  if test yes = "$_lt_dar_can_shared"; then
     output_verbose_link_cmd=func_echo_all
-    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
-    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
-    archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
-    module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
-       if test "$lt_cv_apple_cc_single_mod" != "yes"; then
-      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
-      archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+       if test yes != "$lt_cv_apple_cc_single_mod"; then
+      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+      archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
     fi
 
   else
@@ -14214,6 +14656,34 @@ fi
 
 	;;
 
+      os2*)
+	hardcode_libdir_flag_spec_CXX='-L$libdir'
+	hardcode_minus_L_CXX=yes
+	allow_undefined_flag_CXX=unsupported
+	shrext_cmds=.dll
+	archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  prefix_cmds="$SED"~
+	  if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	    prefix_cmds="$prefix_cmds -e 1d";
+	  fi~
+	  prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	  cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+	enable_shared_with_static_runtimes_CXX=yes
+	;;
+
       dgux*)
         case $cc_basename in
           ec++*)
@@ -14249,14 +14719,14 @@ fi
         ;;
 
       haiku*)
-        archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
         link_all_deplibs_CXX=yes
         ;;
 
       hpux9*)
-        hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+        hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
         hardcode_libdir_separator_CXX=:
-        export_dynamic_flag_spec_CXX='${wl}-E'
+        export_dynamic_flag_spec_CXX='$wl-E'
         hardcode_direct_CXX=yes
         hardcode_minus_L_CXX=yes # Not in the search PATH,
 				             # but as the default
@@ -14268,7 +14738,7 @@ fi
             ld_shlibs_CXX=no
             ;;
           aCC*)
-            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
             # Commands to make compiler produce verbose output that lists
             # what "hidden" libraries, object files and flags are used when
             # linking a shared library.
@@ -14277,11 +14747,11 @@ fi
             # explicitly linking system object files so we need to strip them
             # from the output so that they don't get included in the library
             # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
             ;;
           *)
-            if test "$GXX" = yes; then
-              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            if test yes = "$GXX"; then
+              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
             else
               # FIXME: insert proper C++ library support
               ld_shlibs_CXX=no
@@ -14291,15 +14761,15 @@ fi
         ;;
 
       hpux10*|hpux11*)
-        if test $with_gnu_ld = no; then
-	  hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+        if test no = "$with_gnu_ld"; then
+	  hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
 	  hardcode_libdir_separator_CXX=:
 
           case $host_cpu in
             hppa*64*|ia64*)
               ;;
             *)
-	      export_dynamic_flag_spec_CXX='${wl}-E'
+	      export_dynamic_flag_spec_CXX='$wl-E'
               ;;
           esac
         fi
@@ -14325,13 +14795,13 @@ fi
           aCC*)
 	    case $host_cpu in
 	      hppa*64*)
-	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	        ;;
 	      ia64*)
-	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	        ;;
 	      *)
-	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	        ;;
 	    esac
 	    # Commands to make compiler produce verbose output that lists
@@ -14342,20 +14812,20 @@ fi
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 	    ;;
           *)
-	    if test "$GXX" = yes; then
-	      if test $with_gnu_ld = no; then
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
 	        case $host_cpu in
 	          hppa*64*)
-	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	            ;;
 	          ia64*)
-	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	            ;;
 	          *)
-	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	            ;;
 	        esac
 	      fi
@@ -14370,22 +14840,22 @@ fi
       interix[3-9]*)
 	hardcode_direct_CXX=no
 	hardcode_shlibpath_var_CXX=no
-	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
-	export_dynamic_flag_spec_CXX='${wl}-E'
+	hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	export_dynamic_flag_spec_CXX='$wl-E'
 	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
 	# Instead, shared libraries are loaded at an image base (0x10000000 by
 	# default) and relocated if they conflict, which is a slow very memory
 	# consuming and fragmenting process.  To avoid this, we pick a random,
 	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
 	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-	archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
 	;;
       irix5* | irix6*)
         case $cc_basename in
           CC*)
 	    # SGI C++
-	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 
 	    # Archives containing C++ object files must be created using
 	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
@@ -14394,17 +14864,17 @@ fi
 	    old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
 	    ;;
           *)
-	    if test "$GXX" = yes; then
-	      if test "$with_gnu_ld" = no; then
-	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 	      else
-	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
 	      fi
 	    fi
 	    link_all_deplibs_CXX=yes
 	    ;;
         esac
-        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
         hardcode_libdir_separator_CXX=:
         inherit_rpath_CXX=yes
         ;;
@@ -14417,8 +14887,8 @@ fi
 	    # KCC will only create a shared library if the output file
 	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
 	    # to its proper name (with version) after linking.
-	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
 	    # Commands to make compiler produce verbose output that lists
 	    # what "hidden" libraries, object files and flags are used when
 	    # linking a shared library.
@@ -14427,10 +14897,10 @@ fi
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 
-	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
-	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
 
 	    # Archives containing C++ object files must be created using
 	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
@@ -14444,59 +14914,59 @@ fi
 	    # earlier do not add the objects themselves.
 	    case `$CC -V 2>&1` in
 	      *"Version 7."*)
-	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 		;;
 	      *)  # Version 8.0 or newer
 	        tmp_idyn=
 	        case $host_cpu in
 		  ia64*) tmp_idyn=' -i_dynamic';;
 		esac
-	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 		;;
 	    esac
 	    archive_cmds_need_lc_CXX=no
-	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
-	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
-	    whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
 	    ;;
           pgCC* | pgcpp*)
             # Portland Group C++ compiler
 	    case `$CC -V` in
 	    *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
 	      prelink_cmds_CXX='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
 	      old_archive_cmds_CXX='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
-		$RANLIB $oldlib'
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+                $RANLIB $oldlib'
 	      archive_cmds_CXX='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
 	      archive_expsym_cmds_CXX='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 	      ;;
 	    *) # Version 6 and above use weak symbols
-	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
-	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 	      ;;
 	    esac
 
-	    hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
-	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
-	    whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	    hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
             ;;
 	  cxx*)
 	    # Compaq C++
-	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
 
 	    runpath_var=LD_RUN_PATH
 	    hardcode_libdir_flag_spec_CXX='-rpath $libdir'
@@ -14510,18 +14980,18 @@ fi
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
 	    ;;
 	  xl* | mpixl* | bgxl*)
 	    # IBM XL 8.0 on PPC, with GNU ld
-	    hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
-	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
-	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    if test "x$supports_anon_versioning" = xyes; then
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    if test yes = "$supports_anon_versioning"; then
 	      archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
-		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-		echo "local: *; };" >> $output_objdir/$libname.ver~
-		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+                echo "local: *; };" >> $output_objdir/$libname.ver~
+                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
 	    fi
 	    ;;
 	  *)
@@ -14529,10 +14999,10 @@ fi
 	    *Sun\ C*)
 	      # Sun C++ 5.9
 	      no_undefined_flag_CXX=' -zdefs'
-	      archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	      archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
 	      hardcode_libdir_flag_spec_CXX='-R$libdir'
-	      whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	      compiler_needs_object_CXX=yes
 
 	      # Not sure whether something based on
@@ -14590,22 +15060,17 @@ fi
         ld_shlibs_CXX=yes
 	;;
 
-      openbsd2*)
-        # C++ shared libraries are fairly broken
-	ld_shlibs_CXX=no
-	;;
-
-      openbsd*)
+      openbsd* | bitrig*)
 	if test -f /usr/libexec/ld.so; then
 	  hardcode_direct_CXX=yes
 	  hardcode_shlibpath_var_CXX=no
 	  hardcode_direct_absolute_CXX=yes
 	  archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-	  hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
-	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
-	    export_dynamic_flag_spec_CXX='${wl}-E'
-	    whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+	    export_dynamic_flag_spec_CXX='$wl-E'
+	    whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
 	  fi
 	  output_verbose_link_cmd=func_echo_all
 	else
@@ -14621,9 +15086,9 @@ fi
 	    # KCC will only create a shared library if the output file
 	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
 	    # to its proper name (with version) after linking.
-	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
 
-	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
 	    hardcode_libdir_separator_CXX=:
 
 	    # Archives containing C++ object files must be created using
@@ -14641,17 +15106,17 @@ fi
           cxx*)
 	    case $host in
 	      osf3*)
-	        allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
-	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	        allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
+	        archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
 		;;
 	      *)
 	        allow_undefined_flag_CXX=' -expect_unresolved \*'
-	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 	        archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
-	          echo "-hidden">> $lib.exp~
-	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
-	          $RM $lib.exp'
+                  echo "-hidden">> $lib.exp~
+                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+                  $RM $lib.exp'
 	        hardcode_libdir_flag_spec_CXX='-rpath $libdir'
 		;;
 	    esac
@@ -14666,21 +15131,21 @@ fi
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 	    ;;
 	  *)
-	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-	      allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
 	      case $host in
 	        osf3*)
-	          archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	          archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 		  ;;
 	        *)
-	          archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	          archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 		  ;;
 	      esac
 
-	      hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	      hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
 	      hardcode_libdir_separator_CXX=:
 
 	      # Commands to make compiler produce verbose output that lists
@@ -14726,9 +15191,9 @@ fi
 	    # Sun C++ 4.2, 5.x and Centerline C++
             archive_cmds_need_lc_CXX=yes
 	    no_undefined_flag_CXX=' -zdefs'
-	    archive_cmds_CXX='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	    archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
 
 	    hardcode_libdir_flag_spec_CXX='-R$libdir'
 	    hardcode_shlibpath_var_CXX=no
@@ -14736,7 +15201,7 @@ fi
 	      solaris2.[0-5] | solaris2.[0-5].*) ;;
 	      *)
 		# The compiler driver will combine and reorder linker options,
-		# but understands `-z linker_flag'.
+		# but understands '-z linker_flag'.
 	        # Supported since Solaris 2.6 (maybe 2.5.1?)
 		whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
 	        ;;
@@ -14753,30 +15218,30 @@ fi
 	    ;;
           gcx*)
 	    # Green Hills C++ Compiler
-	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
 
 	    # The C++ compiler must be used to create the archive.
 	    old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
 	    ;;
           *)
 	    # GNU C++ compiler with Solaris linker
-	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-	      no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      no_undefined_flag_CXX=' $wl-z ${wl}defs'
 	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
-	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
 	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
 
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
 	        # linking a shared library.
 	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
 	      else
-	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
 	        # platform.
-	        archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
 	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
 
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
@@ -14784,11 +15249,11 @@ fi
 	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
 	      fi
 
-	      hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+	      hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir'
 	      case $host_os in
 		solaris2.[0-5] | solaris2.[0-5].*) ;;
 		*)
-		  whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
 		  ;;
 	      esac
 	    fi
@@ -14797,52 +15262,52 @@ fi
         ;;
 
     sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
-      no_undefined_flag_CXX='${wl}-z,text'
+      no_undefined_flag_CXX='$wl-z,text'
       archive_cmds_need_lc_CXX=no
       hardcode_shlibpath_var_CXX=no
       runpath_var='LD_RUN_PATH'
 
       case $cc_basename in
         CC*)
-	  archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	*)
-	  archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
       esac
       ;;
 
       sysv5* | sco3.2v5* | sco5v6*)
-	# Note: We can NOT use -z defs as we might desire, because we do not
+	# Note: We CANNOT use -z defs as we might desire, because we do not
 	# link with -lc, and that would cause any symbols used from libc to
 	# always be unresolved, which means just about no library would
 	# ever link correctly.  If we're not using GNU ld we use -z text
 	# though, which does catch some bad symbols but isn't as heavy-handed
 	# as -z defs.
-	no_undefined_flag_CXX='${wl}-z,text'
-	allow_undefined_flag_CXX='${wl}-z,nodefs'
+	no_undefined_flag_CXX='$wl-z,text'
+	allow_undefined_flag_CXX='$wl-z,nodefs'
 	archive_cmds_need_lc_CXX=no
 	hardcode_shlibpath_var_CXX=no
-	hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+	hardcode_libdir_flag_spec_CXX='$wl-R,$libdir'
 	hardcode_libdir_separator_CXX=':'
 	link_all_deplibs_CXX=yes
-	export_dynamic_flag_spec_CXX='${wl}-Bexport'
+	export_dynamic_flag_spec_CXX='$wl-Bexport'
 	runpath_var='LD_RUN_PATH'
 
 	case $cc_basename in
           CC*)
-	    archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	    old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
-	      '"$old_archive_cmds_CXX"
+              '"$old_archive_cmds_CXX"
 	    reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
-	      '"$reload_cmds_CXX"
+              '"$reload_cmds_CXX"
 	    ;;
 	  *)
-	    archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	    ;;
 	esac
       ;;
@@ -14874,10 +15339,10 @@ fi
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
 $as_echo "$ld_shlibs_CXX" >&6; }
-    test "$ld_shlibs_CXX" = no && can_build_shared=no
+    test no = "$ld_shlibs_CXX" && can_build_shared=no
 
-    GCC_CXX="$GXX"
-    LD_CXX="$LD"
+    GCC_CXX=$GXX
+    LD_CXX=$LD
 
     ## CAVEAT EMPTOR:
     ## There is no encapsulation within the following macros, do not change
@@ -14921,13 +15386,13 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   pre_test_object_deps_done=no
 
   for p in `eval "$output_verbose_link_cmd"`; do
-    case ${prev}${p} in
+    case $prev$p in
 
     -L* | -R* | -l*)
        # Some compilers place space between "-{L,R}" and the path.
        # Remove the space.
-       if test $p = "-L" ||
-          test $p = "-R"; then
+       if test x-L = "$p" ||
+          test x-R = "$p"; then
 	 prev=$p
 	 continue
        fi
@@ -14943,16 +15408,16 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
        case $p in
        =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
        esac
-       if test "$pre_test_object_deps_done" = no; then
-	 case ${prev} in
+       if test no = "$pre_test_object_deps_done"; then
+	 case $prev in
 	 -L | -R)
 	   # Internal compiler library paths should come after those
 	   # provided the user.  The postdeps already come after the
 	   # user supplied libs so there is no need to process them.
 	   if test -z "$compiler_lib_search_path_CXX"; then
-	     compiler_lib_search_path_CXX="${prev}${p}"
+	     compiler_lib_search_path_CXX=$prev$p
 	   else
-	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p"
 	   fi
 	   ;;
 	 # The "-l" case would never come before the object being
@@ -14960,9 +15425,9 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
 	 esac
        else
 	 if test -z "$postdeps_CXX"; then
-	   postdeps_CXX="${prev}${p}"
+	   postdeps_CXX=$prev$p
 	 else
-	   postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+	   postdeps_CXX="${postdeps_CXX} $prev$p"
 	 fi
        fi
        prev=
@@ -14977,15 +15442,15 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
 	 continue
        fi
 
-       if test "$pre_test_object_deps_done" = no; then
+       if test no = "$pre_test_object_deps_done"; then
 	 if test -z "$predep_objects_CXX"; then
-	   predep_objects_CXX="$p"
+	   predep_objects_CXX=$p
 	 else
 	   predep_objects_CXX="$predep_objects_CXX $p"
 	 fi
        else
 	 if test -z "$postdep_objects_CXX"; then
-	   postdep_objects_CXX="$p"
+	   postdep_objects_CXX=$p
 	 else
 	   postdep_objects_CXX="$postdep_objects_CXX $p"
 	 fi
@@ -15015,51 +15480,6 @@ interix[3-9]*)
   postdep_objects_CXX=
   postdeps_CXX=
   ;;
-
-linux*)
-  case `$CC -V 2>&1 | sed 5q` in
-  *Sun\ C*)
-    # Sun C++ 5.9
-
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    if test "$solaris_use_stlport4" != yes; then
-      postdeps_CXX='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
-
-solaris*)
-  case $cc_basename in
-  CC* | sunCC*)
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    # Adding this requires a known-good setup of shared libraries for
-    # Sun compiler versions before 5.6, else PIC objects from an old
-    # archive will be linked into the output, leading to subtle bugs.
-    if test "$solaris_use_stlport4" != yes; then
-      postdeps_CXX='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
 esac
 
 
@@ -15068,7 +15488,7 @@ case " $postdeps_CXX " in
 esac
  compiler_lib_search_dirs_CXX=
 if test -n "${compiler_lib_search_path_CXX}"; then
- compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'`
 fi
 
 
@@ -15107,17 +15527,18 @@ lt_prog_compiler_static_CXX=
 
 
   # C++ specific cases for pic, static, wl, etc.
-  if test "$GXX" = yes; then
+  if test yes = "$GXX"; then
     lt_prog_compiler_wl_CXX='-Wl,'
     lt_prog_compiler_static_CXX='-static'
 
     case $host_os in
     aix*)
       # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# AIX 5 now supports IA64 processor
 	lt_prog_compiler_static_CXX='-Bstatic'
       fi
+      lt_prog_compiler_pic_CXX='-fPIC'
       ;;
 
     amigaos*)
@@ -15128,8 +15549,8 @@ lt_prog_compiler_static_CXX=
         ;;
       m68k)
             # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
             lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
         ;;
       esac
@@ -15144,6 +15565,11 @@ lt_prog_compiler_static_CXX=
       # Although the cygwin gcc ignores -fPIC, still need this for old-style
       # (--disable-auto-import) libraries
       lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static_CXX='$wl-static'
+	;;
+      esac
       ;;
     darwin* | rhapsody*)
       # PIC is the default on this platform
@@ -15193,7 +15619,7 @@ lt_prog_compiler_static_CXX=
     case $host_os in
       aix[4-9]*)
 	# All AIX code is PIC.
-	if test "$host_cpu" = ia64; then
+	if test ia64 = "$host_cpu"; then
 	  # AIX 5 now supports IA64 processor
 	  lt_prog_compiler_static_CXX='-Bstatic'
 	else
@@ -15233,14 +15659,14 @@ lt_prog_compiler_static_CXX=
 	case $cc_basename in
 	  CC*)
 	    lt_prog_compiler_wl_CXX='-Wl,'
-	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
-	    if test "$host_cpu" != ia64; then
+	    lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
+	    if test ia64 != "$host_cpu"; then
 	      lt_prog_compiler_pic_CXX='+Z'
 	    fi
 	    ;;
 	  aCC*)
 	    lt_prog_compiler_wl_CXX='-Wl,'
-	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+	    lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
 	    case $host_cpu in
 	    hppa*64*|ia64*)
 	      # +Z the default
@@ -15277,7 +15703,7 @@ lt_prog_compiler_static_CXX=
 	    lt_prog_compiler_pic_CXX='-fPIC'
 	    ;;
 	  ecpc* )
-	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    # old Intel C++ for x86_64, which still supported -KPIC.
 	    lt_prog_compiler_wl_CXX='-Wl,'
 	    lt_prog_compiler_pic_CXX='-KPIC'
 	    lt_prog_compiler_static_CXX='-static'
@@ -15422,7 +15848,7 @@ lt_prog_compiler_static_CXX=
   fi
 
 case $host_os in
-  # For platforms which do not support PIC, -DPIC is meaningless:
+  # For platforms that do not support PIC, -DPIC is meaningless:
   *djgpp*)
     lt_prog_compiler_pic_CXX=
     ;;
@@ -15454,7 +15880,7 @@ else
   lt_cv_prog_compiler_pic_works_CXX=no
    ac_outfile=conftest.$ac_objext
    echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"  ## exclude from sc_useless_quotes_in_assignment
    # Insert the option either (1) after the last *FLAGS variable, or
    # (2) before a word containing "conftest.", or (3) at the end.
    # Note that $ac_compile itself does not contain backslashes and begins
@@ -15484,7 +15910,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
 $as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
 
-if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then
     case $lt_prog_compiler_pic_CXX in
      "" | " "*) ;;
      *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
@@ -15510,7 +15936,7 @@ if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   lt_cv_prog_compiler_static_works_CXX=no
-   save_LDFLAGS="$LDFLAGS"
+   save_LDFLAGS=$LDFLAGS
    LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
    echo "$lt_simple_link_test_code" > conftest.$ac_ext
    if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -15529,13 +15955,13 @@ else
      fi
    fi
    $RM -r conftest*
-   LDFLAGS="$save_LDFLAGS"
+   LDFLAGS=$save_LDFLAGS
 
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
 $as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
 
-if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then
     :
 else
     lt_prog_compiler_static_CXX=
@@ -15649,8 +16075,8 @@ $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
 
 
 
-hard_links="nottested"
-if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then
   # do not overwrite the value of need_locks provided by the user
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
 $as_echo_n "checking if we can lock with hard links... " >&6; }
@@ -15662,9 +16088,9 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
 $as_echo "$hard_links" >&6; }
-  if test "$hard_links" = no; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
-$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+  if test no = "$hard_links"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
     need_locks=warn
   fi
 else
@@ -15681,17 +16107,21 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
   case $host_os in
   aix[4-9]*)
     # If we're using GNU nm, then we don't want the "-C" option.
-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
-    # Also, AIX nm treats weak defined symbols like other global defined
-    # symbols, whereas GNU nm marks them as "W".
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
     else
-      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
-    export_symbols_cmds_CXX="$ltdll_cmds"
+    export_symbols_cmds_CXX=$ltdll_cmds
     ;;
   cygwin* | mingw* | cegcc*)
     case $cc_basename in
@@ -15714,7 +16144,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
 $as_echo "$ld_shlibs_CXX" >&6; }
-test "$ld_shlibs_CXX" = no && can_build_shared=no
+test no = "$ld_shlibs_CXX" && can_build_shared=no
 
 with_gnu_ld_CXX=$with_gnu_ld
 
@@ -15731,7 +16161,7 @@ x|xyes)
   # Assume -lc should be added
   archive_cmds_need_lc_CXX=yes
 
-  if test "$enable_shared" = yes && test "$GCC" = yes; then
+  if test yes,yes = "$GCC,$enable_shared"; then
     case $archive_cmds_CXX in
     *'~'*)
       # FIXME: we may have to deal with multi-command sequences.
@@ -15859,7 +16289,7 @@ $as_echo_n "checking dynamic linker characteristics... " >&6; }
 library_names_spec=
 libname_spec='lib$name'
 soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
 postinstall_cmds=
 postuninstall_cmds=
 finish_cmds=
@@ -15876,14 +16306,16 @@ hardcode_into_libs=no
 # flags to be left without arguments
 need_version=unknown
 
+
+
 case $host_os in
 aix3*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
   shlibpath_var=LIBPATH
 
   # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='${libname}${release}${shared_ext}$major'
+  soname_spec='$libname$release$shared_ext$major'
   ;;
 
 aix[4-9]*)
@@ -15891,41 +16323,91 @@ aix[4-9]*)
   need_lib_prefix=no
   need_version=no
   hardcode_into_libs=yes
-  if test "$host_cpu" = ia64; then
+  if test ia64 = "$host_cpu"; then
     # AIX 5 supports IA64
-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
     shlibpath_var=LD_LIBRARY_PATH
   else
     # With GCC up to 2.95.x, collect2 would create an import file
     # for dependence libraries.  The import file would start with
-    # the line `#! .'.  This would cause the generated library to
-    # depend on `.', always an invalid library.  This was fixed in
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
     # development snapshots of GCC prior to 3.0.
     case $host_os in
       aix4 | aix4.[01] | aix4.[01].*)
       if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
 	   echo ' yes '
-	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
 	:
       else
 	can_build_shared=no
       fi
       ;;
     esac
-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
     # soname into executable. Probably we can add versioning support to
     # collect2, so additional links can be useful in future.
-    if test "$aix_use_runtimelinking" = yes; then
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
       # If using run time linking (on AIX 4.2 or later) use lib<name>.so
       # instead of lib<name>.a to let people know that these are not
       # typical AIX shared libraries.
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    else
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a(lib.so.V)'
       # We preserve .a as extension for shared libraries through AIX4.2
       # and later when we are not doing run time linking.
-      library_names_spec='${libname}${release}.a $libname.a'
-      soname_spec='${libname}${release}${shared_ext}$major'
-    fi
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
     shlibpath_var=LIBPATH
   fi
   ;;
@@ -15935,18 +16417,18 @@ amigaos*)
   powerpc)
     # Since July 2007 AmigaOS4 officially supports .so libraries.
     # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
     ;;
   m68k)
     library_names_spec='$libname.ixlibrary $libname.a'
     # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
     ;;
   esac
   ;;
 
 beos*)
-  library_names_spec='${libname}${shared_ext}'
+  library_names_spec='$libname$shared_ext'
   dynamic_linker="$host_os ld.so"
   shlibpath_var=LIBRARY_PATH
   ;;
@@ -15954,8 +16436,8 @@ beos*)
 bsdi[45]*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -15967,7 +16449,7 @@ bsdi[45]*)
 
 cygwin* | mingw* | pw32* | cegcc*)
   version_type=windows
-  shrext_cmds=".dll"
+  shrext_cmds=.dll
   need_version=no
   need_lib_prefix=no
 
@@ -15976,8 +16458,8 @@ cygwin* | mingw* | pw32* | cegcc*)
     # gcc
     library_names_spec='$libname.dll.a'
     # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
       dldir=$destdir/`dirname \$dlpath`~
       test -d \$dldir || mkdir -p \$dldir~
       $install_prog $dir/$dlname \$dldir/$dlname~
@@ -15993,16 +16475,16 @@ cygwin* | mingw* | pw32* | cegcc*)
     case $host_os in
     cygwin*)
       # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
 
       ;;
     mingw* | cegcc*)
       # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
       ;;
     pw32*)
       # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
       ;;
     esac
     dynamic_linker='Win32 ld.exe'
@@ -16011,8 +16493,8 @@ cygwin* | mingw* | pw32* | cegcc*)
   *,cl*)
     # Native MSVC
     libname_spec='$name'
-    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
-    library_names_spec='${libname}.dll.lib'
+    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
 
     case $build_os in
     mingw*)
@@ -16039,7 +16521,7 @@ cygwin* | mingw* | pw32* | cegcc*)
       sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
       ;;
     *)
-      sys_lib_search_path_spec="$LIB"
+      sys_lib_search_path_spec=$LIB
       if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
         # It is most probably a Windows format PATH.
         sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -16052,8 +16534,8 @@ cygwin* | mingw* | pw32* | cegcc*)
     esac
 
     # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
       dldir=$destdir/`dirname \$dlpath`~
       test -d \$dldir || mkdir -p \$dldir~
       $install_prog $dir/$dlname \$dldir/$dlname'
@@ -16066,7 +16548,7 @@ cygwin* | mingw* | pw32* | cegcc*)
 
   *)
     # Assume MSVC wrapper
-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
     dynamic_linker='Win32 ld.exe'
     ;;
   esac
@@ -16079,8 +16561,8 @@ darwin* | rhapsody*)
   version_type=darwin
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
-  soname_spec='${libname}${release}${major}$shared_ext'
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
   shlibpath_overrides_runpath=yes
   shlibpath_var=DYLD_LIBRARY_PATH
   shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
@@ -16092,8 +16574,8 @@ dgux*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   ;;
 
@@ -16111,12 +16593,13 @@ freebsd* | dragonfly*)
   version_type=freebsd-$objformat
   case $version_type in
     freebsd-elf*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
       need_version=no
       need_lib_prefix=no
       ;;
     freebsd-*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
       need_version=yes
       ;;
   esac
@@ -16146,10 +16629,10 @@ haiku*)
   need_lib_prefix=no
   need_version=no
   dynamic_linker="$host_os runtime_loader"
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
+  shlibpath_overrides_runpath=no
   sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
   hardcode_into_libs=yes
   ;;
@@ -16167,14 +16650,15 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.so"
     shlibpath_var=LD_LIBRARY_PATH
     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    if test "X$HPUX_IA64_MODE" = X32; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
       sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
     else
       sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
     fi
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
   hppa*64*)
     shrext_cmds='.sl'
@@ -16182,8 +16666,8 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.sl"
     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
@@ -16192,8 +16676,8 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.sl"
     shlibpath_var=SHLIB_PATH
     shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     ;;
   esac
   # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -16206,8 +16690,8 @@ interix[3-9]*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
@@ -16218,7 +16702,7 @@ irix5* | irix6* | nonstopux*)
   case $host_os in
     nonstopux*) version_type=nonstopux ;;
     *)
-	if test "$lt_cv_prog_gnu_ld" = yes; then
+	if test yes = "$lt_cv_prog_gnu_ld"; then
 		version_type=linux # correct to gnu/linux during the next big refactor
 	else
 		version_type=irix
@@ -16226,8 +16710,8 @@ irix5* | irix6* | nonstopux*)
   esac
   need_lib_prefix=no
   need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
   case $host_os in
   irix5* | nonstopux*)
     libsuff= shlibsuff=
@@ -16246,8 +16730,8 @@ irix5* | irix6* | nonstopux*)
   esac
   shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
   shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
   hardcode_into_libs=yes
   ;;
 
@@ -16256,13 +16740,33 @@ linux*oldld* | linux*aout* | linux*coff*)
   dynamic_linker=no
   ;;
 
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  hardcode_libdir_flag_spec_CXX='-L$libdir'
+  ;;
+
 # This must be glibc/ELF.
 linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
@@ -16306,7 +16810,12 @@ fi
   # before this can be enabled.
   hardcode_into_libs=yes
 
-  # Append ld.so.conf contents to the search path
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
   if test -f /etc/ld.so.conf; then
     lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
     sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -16338,12 +16847,12 @@ netbsd*)
   need_lib_prefix=no
   need_version=no
   if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
     finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
     dynamic_linker='NetBSD (a.out) ld.so'
   else
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     dynamic_linker='NetBSD ld.elf_so'
   fi
   shlibpath_var=LD_LIBRARY_PATH
@@ -16353,7 +16862,7 @@ netbsd*)
 
 newsos6)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   ;;
@@ -16362,58 +16871,68 @@ newsos6)
   version_type=qnx
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
   dynamic_linker='ldqnx.so'
   ;;
 
-openbsd*)
+openbsd* | bitrig*)
   version_type=sunos
-  sys_lib_dlsearch_path_spec="/usr/lib"
+  sys_lib_dlsearch_path_spec=/usr/lib
   need_lib_prefix=no
-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
-  case $host_os in
-    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
-    *)				need_version=no  ;;
-  esac
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    case $host_os in
-      openbsd2.[89] | openbsd2.[89].*)
-	shlibpath_overrides_runpath=no
-	;;
-      *)
-	shlibpath_overrides_runpath=yes
-	;;
-      esac
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
   else
-    shlibpath_overrides_runpath=yes
+    need_version=yes
   fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
   ;;
 
 os2*)
   libname_spec='$name'
-  shrext_cmds=".dll"
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
   need_lib_prefix=no
-  library_names_spec='$libname${shared_ext} $libname.a'
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
   dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=LIBPATH
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
   ;;
 
 osf3* | osf4* | osf5*)
   version_type=osf
   need_lib_prefix=no
   need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
   ;;
 
 rdos*)
@@ -16424,8 +16943,8 @@ solaris*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   hardcode_into_libs=yes
@@ -16435,11 +16954,11 @@ solaris*)
 
 sunos4*)
   version_type=sunos
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
   finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     need_lib_prefix=no
   fi
   need_version=yes
@@ -16447,8 +16966,8 @@ sunos4*)
 
 sysv4 | sysv4.3*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   case $host_vendor in
     sni)
@@ -16469,24 +16988,24 @@ sysv4 | sysv4.3*)
   ;;
 
 sysv4*MP*)
-  if test -d /usr/nec ;then
+  if test -d /usr/nec; then
     version_type=linux # correct to gnu/linux during the next big refactor
-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
-    soname_spec='$libname${shared_ext}.$major'
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
     shlibpath_var=LD_LIBRARY_PATH
   fi
   ;;
 
 sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=freebsd-elf
+  version_type=sco
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   hardcode_into_libs=yes
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
   else
     sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -16504,7 +17023,7 @@ tpf*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
@@ -16512,8 +17031,8 @@ tpf*)
 
 uts4*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   ;;
 
@@ -16523,20 +17042,32 @@ uts4*)
 esac
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
 $as_echo "$dynamic_linker" >&6; }
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
 
 variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
-  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
 fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
-  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
 fi
 
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
 
 
 
@@ -16579,15 +17110,15 @@ $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
 hardcode_action_CXX=
 if test -n "$hardcode_libdir_flag_spec_CXX" ||
    test -n "$runpath_var_CXX" ||
-   test "X$hardcode_automatic_CXX" = "Xyes" ; then
+   test yes = "$hardcode_automatic_CXX"; then
 
   # We can hardcode non-existent directories.
-  if test "$hardcode_direct_CXX" != no &&
+  if test no != "$hardcode_direct_CXX" &&
      # If the only mechanism to avoid hardcoding is shlibpath_var, we
      # have to relink, otherwise we might link with an installed library
      # when we should be linking with a yet-to-be-installed one
-     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
-     test "$hardcode_minus_L_CXX" != no; then
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" &&
+     test no != "$hardcode_minus_L_CXX"; then
     # Linking always hardcodes the temporary library directory.
     hardcode_action_CXX=relink
   else
@@ -16602,12 +17133,12 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
 $as_echo "$hardcode_action_CXX" >&6; }
 
-if test "$hardcode_action_CXX" = relink ||
-   test "$inherit_rpath_CXX" = yes; then
+if test relink = "$hardcode_action_CXX" ||
+   test yes = "$inherit_rpath_CXX"; then
   # Fast installation is not supported
   enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
-     test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
   # Fast installation is not necessary
   enable_fast_install=needless
 fi
@@ -16630,7 +17161,7 @@ fi
   lt_cv_path_LD=$lt_save_path_LD
   lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
   lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
+fi # test yes != "$_lt_caught_CXX_error"
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -16641,14 +17172,21 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
+LIBOPENMPT_LTVER_CURRENT=1
+LIBOPENMPT_LTVER_REVISION=1
+LIBOPENMPT_LTVER_AGE=1
+
 
-$as_echo "#define MPT_SVNURL \"https://source.openmpt.org/svn/openmpt/branches/OpenMPT-1.26\"" >>confdefs.h
 
 
-$as_echo "#define MPT_SVNVERSION \"8461\"" >>confdefs.h
 
+$as_echo "#define MPT_SVNURL \"https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.3.1\"" >>confdefs.h
 
-$as_echo "#define MPT_SVNDATE \"2017-07-07T12:47:24.457926Z\"" >>confdefs.h
+
+$as_echo "#define MPT_SVNVERSION \"9016\"" >>confdefs.h
+
+
+$as_echo "#define MPT_SVNDATE \"2017-09-28T06:05:55.172831Z\"" >>confdefs.h
 
 
 $as_echo "#define MPT_PACKAGE true" >>confdefs.h
@@ -16790,12 +17328,12 @@ if test -n "$MPG123_CFLAGS"; then
     pkg_cv_MPG123_CFLAGS="$MPG123_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmpg123\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libmpg123") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmpg123 >= 1.13.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libmpg123 >= 1.13.0") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_MPG123_CFLAGS=`$PKG_CONFIG --cflags "libmpg123" 2>/dev/null`
+  pkg_cv_MPG123_CFLAGS=`$PKG_CONFIG --cflags "libmpg123 >= 1.13.0" 2>/dev/null`
 		      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -16807,12 +17345,12 @@ if test -n "$MPG123_LIBS"; then
     pkg_cv_MPG123_LIBS="$MPG123_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmpg123\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libmpg123") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmpg123 >= 1.13.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libmpg123 >= 1.13.0") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_MPG123_LIBS=`$PKG_CONFIG --libs "libmpg123" 2>/dev/null`
+  pkg_cv_MPG123_LIBS=`$PKG_CONFIG --libs "libmpg123 >= 1.13.0" 2>/dev/null`
 		      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -16833,9 +17371,9 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-	        MPG123_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libmpg123" 2>&1`
+	        MPG123_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libmpg123 >= 1.13.0" 2>&1`
         else
-	        MPG123_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libmpg123" 2>&1`
+	        MPG123_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libmpg123 >= 1.13.0" 2>&1`
         fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$MPG123_PKG_ERRORS" >&5
@@ -17131,281 +17669,168 @@ fi
 
 fi
 
-# Check whether --enable-dlopen was given.
-if test "${enable_dlopen+set}" = set; then :
-  enableval=$enable_dlopen;
-fi
-
-if test "x$enable-dlopen" = "xyes"; then :
-
-
-$as_echo "#define MPT_ENABLE_DLOPEN /**/" >>confdefs.h
 
+LIBOPENMPT_REQUIRES_PRIVATE="$ZLIB_PKG $MPG123_PKG $OGG_PKG $VORBIS_PKG $VORBISFILE_PKG"
+LIBOPENMPT_LIBS_PRIVATE=""
 
 
-fi
 
-# Optional libopenmpt dependency: libltdl
 
-# Check whether --with-ltdl was given.
-if test "${with_ltdl+set}" = set; then :
-  withval=$with_ltdl;
+# openmpt123
+# Check whether --enable-openmpt123 was given.
+if test "${enable_openmpt123+set}" = set; then :
+  enableval=$enable_openmpt123;
 fi
 
-if test "x$with_ltdl" = "xyes"; then :
-
-  ac_fn_c_check_header_mongrel "$LINENO" "ltdl.h" "ac_cv_header_ltdl_h" "$ac_includes_default"
-if test "x$ac_cv_header_ltdl_h" = xyes; then :
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lt_dlinit in -lltdl" >&5
-$as_echo_n "checking for lt_dlinit in -lltdl... " >&6; }
-if ${ac_cv_lib_ltdl_lt_dlinit+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lltdl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char lt_dlinit ();
-int
-main ()
-{
-return lt_dlinit ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_ltdl_lt_dlinit=yes
+ if test "x$enable_openmpt123" != "xno"; then
+  ENABLE_OPENMPT123_TRUE=
+  ENABLE_OPENMPT123_FALSE='#'
 else
-  ac_cv_lib_ltdl_lt_dlinit=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+  ENABLE_OPENMPT123_TRUE='#'
+  ENABLE_OPENMPT123_FALSE=
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ltdl_lt_dlinit" >&5
-$as_echo "$ac_cv_lib_ltdl_lt_dlinit" >&6; }
-if test "x$ac_cv_lib_ltdl_lt_dlinit" = xyes; then :
 
-      have_ltdl=1
-
-else
-
-      have_ltdl=0
 
 
+# examples
+# Check whether --enable-examples was given.
+if test "${enable_examples+set}" = set; then :
+  enableval=$enable_examples;
 fi
 
-
+ if test "x$enable_examples" != "xno"; then
+  ENABLE_EXAMPLES_TRUE=
+  ENABLE_EXAMPLES_FALSE='#'
 else
-
-    have_ltdl=0
-
-
+  ENABLE_EXAMPLES_TRUE='#'
+  ENABLE_EXAMPLES_FALSE=
 fi
 
 
-  if test "x$have_ltdl" = "x0"; then :
-
-    as_fn_error $? "Unable to find libltdl." "$LINENO" 5
-
 
+# tests
+# Check whether --enable-tests was given.
+if test "${enable_tests+set}" = set; then :
+  enableval=$enable_tests;
 fi
 
+ if test "x$enable_tests" != "xno"; then
+  ENABLE_TESTS_TRUE=
+  ENABLE_TESTS_FALSE='#'
 else
-
-  have_ltdl=0
-
-
+  ENABLE_TESTS_TRUE='#'
+  ENABLE_TESTS_FALSE=
 fi
-if test "x$have_ltdl" = "x1"; then :
 
-  LTDL_CPPFLAGS=-DMPT_WITH_LTDL
-  LTDL_LIBS=-lltdl
-
-else
 
-  LTDL_CPPFLAGS=
-  LTDL_LIBS=
 
+# Optional openmpt123 dependency
 
+# Check whether --with-pulseaudio was given.
+if test "${with_pulseaudio+set}" = set; then :
+  withval=$with_pulseaudio;
 fi
 
+if test "x$enable_openmpt123" != "xno"; then :
 
+case $host_os in
+ linux*)
+if test "x$with_pulseaudio" != "xno"; then :
 
-# Optional libopenmpt dependency: libdl
-
-# Check whether --with-dl was given.
-if test "${with_dl+set}" = set; then :
-  withval=$with_dl;
-fi
 
-if test "x$with_dl" = "xyes"; then :
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
-$as_echo_n "checking for library containing dlopen... " >&6; }
-if ${ac_cv_search_dlopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' dl dld; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_dlopen=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_dlopen+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_dlopen+:} false; then :
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PULSEAUDIO" >&5
+$as_echo_n "checking for PULSEAUDIO... " >&6; }
 
+if test -n "$PULSEAUDIO_CFLAGS"; then
+    pkg_cv_PULSEAUDIO_CFLAGS="$PULSEAUDIO_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse libpulse-simple\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libpulse libpulse-simple") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PULSEAUDIO_CFLAGS=`$PKG_CONFIG --cflags "libpulse libpulse-simple" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
 else
-  ac_cv_search_dlopen=no
+  pkg_failed=yes
 fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
+ else
+    pkg_failed=untried
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
-$as_echo "$ac_cv_search_dlopen" >&6; }
-ac_res=$ac_cv_search_dlopen
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-    have_dl=1
-
+if test -n "$PULSEAUDIO_LIBS"; then
+    pkg_cv_PULSEAUDIO_LIBS="$PULSEAUDIO_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpulse libpulse-simple\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libpulse libpulse-simple") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_PULSEAUDIO_LIBS=`$PKG_CONFIG --libs "libpulse libpulse-simple" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
 else
-
-    have_dl=0
-
-
+  pkg_failed=yes
 fi
-
-  if test "x$have_dl" = "x0"; then :
-
-    as_fn_error $? "Unable to find libdl." "$LINENO" 5
-
-
+ else
+    pkg_failed=untried
 fi
 
-else
-
-  have_dl=0
 
 
-fi
-if test "x$have_dl" = "x1"; then :
-
-  DL_CPPFLAGS=-DMPT_WITH_DL
-  DL_LIBS=
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-
-  DL_CPPFLAGS=
-  DL_LIBS=
-
-
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+	        PULSEAUDIO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libpulse libpulse-simple" 2>&1`
+        else
+	        PULSEAUDIO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libpulse libpulse-simple" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$PULSEAUDIO_PKG_ERRORS" >&5
 
 
+    have_pulseaudio=0
+    as_fn_error $? "Unable to find libpulse and/or libpulse-simple." "$LINENO" 5
 
 
-LIBOPENMPT_REQUIRES_PRIVATE="$ZLIB_PKG $MPG123_PKG $OGG_PKG $VORBIS_PKG $VORBISFILE_PKG"
-LIBOPENMPT_LIBS_PRIVATE="$LTDL_LIBS $DL_LIBS"
-
-
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
+    have_pulseaudio=0
+    as_fn_error $? "Unable to find libpulse and/or libpulse-simple." "$LINENO" 5
 
-# openmpt123
-# Check whether --enable-openmpt123 was given.
-if test "${enable_openmpt123+set}" = set; then :
-  enableval=$enable_openmpt123;
-fi
 
- if test "x$enable_openmpt123" != "xno"; then
-  ENABLE_OPENMPT123_TRUE=
-  ENABLE_OPENMPT123_FALSE='#'
 else
-  ENABLE_OPENMPT123_TRUE='#'
-  ENABLE_OPENMPT123_FALSE=
-fi
-
-
-
-# examples
-# Check whether --enable-examples was given.
-if test "${enable_examples+set}" = set; then :
-  enableval=$enable_examples;
-fi
+	PULSEAUDIO_CFLAGS=$pkg_cv_PULSEAUDIO_CFLAGS
+	PULSEAUDIO_LIBS=$pkg_cv_PULSEAUDIO_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 
- if test "x$enable_examples" != "xno"; then
-  ENABLE_EXAMPLES_TRUE=
-  ENABLE_EXAMPLES_FALSE='#'
-else
-  ENABLE_EXAMPLES_TRUE='#'
-  ENABLE_EXAMPLES_FALSE=
-fi
+    have_pulseaudio=1
 
+$as_echo "#define MPT_WITH_PULSEAUDIO /**/" >>confdefs.h
 
 
-# tests
-# Check whether --enable-tests was given.
-if test "${enable_tests+set}" = set; then :
-  enableval=$enable_tests;
 fi
 
- if test "x$enable_tests" != "xno"; then
-  ENABLE_TESTS_TRUE=
-  ENABLE_TESTS_FALSE='#'
 else
-  ENABLE_TESTS_TRUE='#'
-  ENABLE_TESTS_FALSE=
-fi
-
 
+  have_pulseaudio=0
 
-# Optional openmpt123 dependency
 
-# Check whether --with-pulseaudio was given.
-if test "${with_pulseaudio+set}" = set; then :
-  withval=$with_pulseaudio;
 fi
-
-if test "x$enable_openmpt123" != "xno"; then :
-
-if test "x$with_pulseaudio" != "xno"; then :
+ ;;
+ *)
+if test "x$with_pulseaudio" = "xyes"; then :
 
 
 pkg_failed=no
@@ -17498,6 +17923,8 @@ else
 
 
 fi
+ ;;
+esac
 
 else
   have_pulseaudio=0
@@ -18392,7 +18819,7 @@ esac
 #AC_LANG_POP([C])
 
 # We need basic C++11 support (implementing C++03TR2 features in namespace std::)
-    ax_cxx_compile_cxx11_required=false
+      ax_cxx_compile_cxx11_required=false
   ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -18407,84 +18834,604 @@ else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
-  template <typename T>
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ax_cv_cxx_compile_cxx11=yes
+else
+  ax_cv_cxx_compile_cxx11=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
+$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+
+
+    if test x$ac_success = xno; then
+                for switch in -std=c++11 -std=c++0x +std=c++11 "-h std=c++11"; do
+      cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
     struct check
     {
-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
     };
 
-    struct Base {
-    virtual void f() {}
-    };
-    struct Child : public Base {
-    virtual void f() override {}
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
     };
 
-    typedef check<check<bool>> right_angle_brackets;
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
 
-    int a;
-    decltype(a) b;
+  }
 
-    typedef check<int> check_type;
-    check_type c;
-    check_type&& cr = static_cast<check_type&&>(c);
+  namespace test_lambdas
+  {
 
-    auto d = a;
-    auto l = [](){};
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
 
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
-  ax_cv_cxx_compile_cxx11=yes
-else
-  ax_cv_cxx_compile_cxx11=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
-$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
-  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
-    ac_success=yes
-  fi
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
 
+  }
 
+  namespace test_variadic_templates
+  {
 
-    if test x$ac_success = xno; then
-    for switch in -std=c++11 -std=c++0x; do
-      cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
-      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
-$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
-if eval \${$cachevar+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_save_CXXFLAGS="$CXXFLAGS"
-         CXXFLAGS="$CXXFLAGS $switch"
-         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
+    template <int...>
+    struct sum;
 
-  template <typename T>
-    struct check
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
     {
-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+      static constexpr auto value = N0 + sum<N1toN...>::value;
     };
 
-    struct Base {
-    virtual void f() {}
-    };
-    struct Child : public Base {
-    virtual void f() override {}
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
     };
 
-    typedef check<check<bool>> right_angle_brackets;
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
 
-    int a;
-    decltype(a) b;
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
 
-    typedef check<int> check_type;
-    check_type c;
-    check_type&& cr = static_cast<check_type&&>(c);
 
-    auto d = a;
-    auto l = [](){};
 
 _ACEOF
 if ac_fn_cxx_try_compile "$LINENO"; then :
@@ -18493,13 +19440,16 @@ else
   eval $cachevar=no
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-         CXXFLAGS="$ac_save_CXXFLAGS"
+         CXX="$ac_save_CXX"
 fi
 eval ac_res=\$$cachevar
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
       if eval test x\$$cachevar = xyes; then
-        CXXFLAGS="$CXXFLAGS $switch"
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
         ac_success=yes
         break
       fi
@@ -18515,21 +19465,19 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
     if test x$ac_success = xno; then
       as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
     fi
-  else
-    if test x$ac_success = xno; then
-      HAVE_CXX11=0
-      { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX11=0
+    { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
 $as_echo "$as_me: No compiler with C++11 support was found" >&6;}
-    else
-      HAVE_CXX11=1
+  else
+    HAVE_CXX11=1
 
 $as_echo "#define HAVE_CXX11 1" >>confdefs.h
 
-    fi
-
-
   fi
 
+
 ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -18567,7 +19515,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___std_cpp0x" >&5
 $as_echo "$ax_cv_check_cxxflags___std_cpp0x" >&6; }
-if test x"$ax_cv_check_cxxflags___std_cpp0x" = xyes; then :
+if test "x$ax_cv_check_cxxflags___std_cpp0x" = xyes; then :
   CXXFLAGS="$CXXFLAGS -std=c++0x"
 else
   :
@@ -18616,7 +19564,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cflags___fvisibility_hidden" >&5
 $as_echo "$ax_cv_check_cflags___fvisibility_hidden" >&6; }
-if test x"$ax_cv_check_cflags___fvisibility_hidden" = xyes; then :
+if test "x$ax_cv_check_cflags___fvisibility_hidden" = xyes; then :
   CFLAGS="$CFLAGS -fvisibility=hidden"
 else
   :
@@ -18663,26 +19611,36 @@ $as_echo "$ac_cv_cflags_warn_all" >&6; }
 case ".$ac_cv_cflags_warn_all" in
      .ok|.ok,*)  ;;
    .|.no|.no,*)  ;;
-   *) if ${CFLAGS+:} false; then :
-  case " $CFLAGS " in
-    *" $ac_cv_cflags_warn_all "*)
-      { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS already contains \$ac_cv_cflags_warn_all"; } >&5
+   *)
+if ${CFLAGS+:} false; then :
+
+  case " $CFLAGS " in #(
+  *" $ac_cv_cflags_warn_all "*) :
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS already contains \$ac_cv_cflags_warn_all"; } >&5
   (: CFLAGS already contains $ac_cv_cflags_warn_all) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-      ;;
-    *)
-      { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS \$ac_cv_cflags_warn_all\""; } >&5
-  (: CFLAGS="$CFLAGS $ac_cv_cflags_warn_all") 2>&5
+  test $ac_status = 0; } ;; #(
+  *) :
+
+     as_fn_append CFLAGS " $ac_cv_cflags_warn_all"
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS\""; } >&5
+  (: CFLAGS="$CFLAGS") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
-      CFLAGS="$CFLAGS $ac_cv_cflags_warn_all"
-      ;;
-   esac
+     ;;
+esac
+
 else
-  CFLAGS="$ac_cv_cflags_warn_all"
+
+  CFLAGS=$ac_cv_cflags_warn_all
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS\""; } >&5
+  (: CFLAGS="$CFLAGS") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+
 fi
  ;;
 esac
@@ -18736,7 +19694,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___fvisibility_hidden" >&5
 $as_echo "$ax_cv_check_cxxflags___fvisibility_hidden" >&6; }
-if test x"$ax_cv_check_cxxflags___fvisibility_hidden" = xyes; then :
+if test "x$ax_cv_check_cxxflags___fvisibility_hidden" = xyes; then :
   CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
 else
   :
@@ -18783,26 +19741,36 @@ $as_echo "$ac_cv_cxxflags_warn_all" >&6; }
 case ".$ac_cv_cxxflags_warn_all" in
      .ok|.ok,*)  ;;
    .|.no|.no,*)  ;;
-   *) if ${CXXFLAGS+:} false; then :
-  case " $CXXFLAGS " in
-    *" $ac_cv_cxxflags_warn_all "*)
-      { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS already contains \$ac_cv_cxxflags_warn_all"; } >&5
+   *)
+if ${CXXFLAGS+:} false; then :
+
+  case " $CXXFLAGS " in #(
+  *" $ac_cv_cxxflags_warn_all "*) :
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS already contains \$ac_cv_cxxflags_warn_all"; } >&5
   (: CXXFLAGS already contains $ac_cv_cxxflags_warn_all) 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-      ;;
-    *)
-      { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS \$ac_cv_cxxflags_warn_all\""; } >&5
-  (: CXXFLAGS="$CXXFLAGS $ac_cv_cxxflags_warn_all") 2>&5
+  test $ac_status = 0; } ;; #(
+  *) :
+
+     as_fn_append CXXFLAGS " $ac_cv_cxxflags_warn_all"
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5
+  (: CXXFLAGS="$CXXFLAGS") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
-      CXXFLAGS="$CXXFLAGS $ac_cv_cxxflags_warn_all"
-      ;;
-   esac
+     ;;
+esac
+
 else
-  CXXFLAGS="$ac_cv_cxxflags_warn_all"
+
+  CXXFLAGS=$ac_cv_cxxflags_warn_all
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: : CXXFLAGS=\"\$CXXFLAGS\""; } >&5
+  (: CXXFLAGS="$CXXFLAGS") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+
 fi
  ;;
 esac
@@ -18868,17 +19836,17 @@ fi
 # Files:
 DX_PROJECT=libopenmpt
 
-DX_CONFIG=Doxyfile
+DX_CONFIG='Doxyfile'
 
-DX_DOCDIR=doxygen-doc
+DX_DOCDIR='doxygen-doc'
 
 
 # Environment variables used inside doxygen.cfg:
 DX_ENV="$DX_ENV SRCDIR='$srcdir'"
+SRCDIR=$srcdir
 
 DX_ENV="$DX_ENV PROJECT='$DX_PROJECT'"
-
-DX_ENV="$DX_ENV DOCDIR='$DX_DOCDIR'"
+PROJECT=$DX_PROJECT
 
 DX_ENV="$DX_ENV VERSION='$PACKAGE_VERSION'"
 
@@ -19129,16 +20097,9 @@ fi
 
     :
 fi
- if test "$DX_FLAG_doc" = 1; then
-  DX_COND_doc_TRUE=
-  DX_COND_doc_FALSE='#'
-else
-  DX_COND_doc_TRUE='#'
-  DX_COND_doc_FALSE=
-fi
-
 if test "$DX_FLAG_doc" = 1; then
     DX_ENV="$DX_ENV PERL_PATH='$DX_PERL'"
+PERL_PATH=$DX_PERL
 
     :
 else
@@ -19293,22 +20254,17 @@ fi
 
     :
 fi
- if test "$DX_FLAG_dot" = 1; then
-  DX_COND_dot_TRUE=
-  DX_COND_dot_FALSE='#'
-else
-  DX_COND_dot_TRUE='#'
-  DX_COND_dot_FALSE=
-fi
-
 if test "$DX_FLAG_dot" = 1; then
     DX_ENV="$DX_ENV HAVE_DOT='YES'"
+HAVE_DOT=YES
 
              DX_ENV="$DX_ENV DOT_PATH='`expr ".$DX_DOT" : '\(\.\)[^/]*$' \| "x$DX_DOT" : 'x\(.*\)/[^/]*$'`'"
+DOT_PATH=`expr ".$DX_DOT" : '\(\.\)[^/]*$' \| "x$DX_DOT" : 'x\(.*\)/[^/]*$'`
 
     :
 else
     DX_ENV="$DX_ENV HAVE_DOT='NO'"
+HAVE_DOT=NO
 
     :
 fi
@@ -19355,20 +20311,14 @@ if test "$DX_FLAG_man" = 1; then
 
     :
 fi
- if test "$DX_FLAG_man" = 1; then
-  DX_COND_man_TRUE=
-  DX_COND_man_FALSE='#'
-else
-  DX_COND_man_TRUE='#'
-  DX_COND_man_FALSE=
-fi
-
 if test "$DX_FLAG_man" = 1; then
     DX_ENV="$DX_ENV GENERATE_MAN='YES'"
+GENERATE_MAN=YES
 
     :
 else
     DX_ENV="$DX_ENV GENERATE_MAN='NO'"
+GENERATE_MAN=NO
 
     :
 fi
@@ -19415,20 +20365,14 @@ if test "$DX_FLAG_rtf" = 1; then
 
     :
 fi
- if test "$DX_FLAG_rtf" = 1; then
-  DX_COND_rtf_TRUE=
-  DX_COND_rtf_FALSE='#'
-else
-  DX_COND_rtf_TRUE='#'
-  DX_COND_rtf_FALSE=
-fi
-
 if test "$DX_FLAG_rtf" = 1; then
     DX_ENV="$DX_ENV GENERATE_RTF='YES'"
+GENERATE_RTF=YES
 
     :
 else
     DX_ENV="$DX_ENV GENERATE_RTF='NO'"
+GENERATE_RTF=NO
 
     :
 fi
@@ -19475,20 +20419,14 @@ if test "$DX_FLAG_xml" = 1; then
 
     :
 fi
- if test "$DX_FLAG_xml" = 1; then
-  DX_COND_xml_TRUE=
-  DX_COND_xml_FALSE='#'
-else
-  DX_COND_xml_TRUE='#'
-  DX_COND_xml_FALSE=
-fi
-
 if test "$DX_FLAG_xml" = 1; then
     DX_ENV="$DX_ENV GENERATE_XML='YES'"
+GENERATE_XML=YES
 
     :
 else
     DX_ENV="$DX_ENV GENERATE_XML='NO'"
+GENERATE_XML=NO
 
     :
 fi
@@ -19640,24 +20578,20 @@ fi
 
     :
 fi
- if test "$DX_FLAG_chm" = 1; then
-  DX_COND_chm_TRUE=
-  DX_COND_chm_FALSE='#'
-else
-  DX_COND_chm_TRUE='#'
-  DX_COND_chm_FALSE=
-fi
-
 if test "$DX_FLAG_chm" = 1; then
     DX_ENV="$DX_ENV HHC_PATH='$DX_HHC'"
+HHC_PATH=$DX_HHC
 
              DX_ENV="$DX_ENV GENERATE_HTML='YES'"
+GENERATE_HTML=YES
 
              DX_ENV="$DX_ENV GENERATE_HTMLHELP='YES'"
+GENERATE_HTMLHELP=YES
 
     :
 else
     DX_ENV="$DX_ENV GENERATE_HTMLHELP='NO'"
+GENERATE_HTMLHELP=NO
 
     :
 fi
@@ -19704,20 +20638,14 @@ if test "$DX_FLAG_chi" = 1; then
 
     :
 fi
- if test "$DX_FLAG_chi" = 1; then
-  DX_COND_chi_TRUE=
-  DX_COND_chi_FALSE='#'
-else
-  DX_COND_chi_TRUE='#'
-  DX_COND_chi_FALSE=
-fi
-
 if test "$DX_FLAG_chi" = 1; then
     DX_ENV="$DX_ENV GENERATE_CHI='YES'"
+GENERATE_CHI=YES
 
     :
 else
     DX_ENV="$DX_ENV GENERATE_CHI='NO'"
+GENERATE_CHI=NO
 
     :
 fi
@@ -19770,20 +20698,14 @@ if test "$DX_FLAG_html" = 1; then
 
     :
 fi
- if test "$DX_FLAG_html" = 1; then
-  DX_COND_html_TRUE=
-  DX_COND_html_FALSE='#'
-else
-  DX_COND_html_TRUE='#'
-  DX_COND_html_FALSE=
-fi
-
 if test "$DX_FLAG_html" = 1; then
     DX_ENV="$DX_ENV GENERATE_HTML='YES'"
+GENERATE_HTML=YES
 
     :
 else
     test "$DX_FLAG_chm" = 1 || DX_ENV="$DX_ENV GENERATE_HTML='NO'"
+GENERATE_HTML=NO
 
     :
 fi
@@ -20253,14 +21175,6 @@ fi
 
     :
 fi
- if test "$DX_FLAG_ps" = 1; then
-  DX_COND_ps_TRUE=
-  DX_COND_ps_FALSE='#'
-else
-  DX_COND_ps_TRUE='#'
-  DX_COND_ps_FALSE=
-fi
-
 if test "$DX_FLAG_ps" = 1; then
 
     :
@@ -20628,14 +21542,6 @@ fi
 
     :
 fi
- if test "$DX_FLAG_pdf" = 1; then
-  DX_COND_pdf_TRUE=
-  DX_COND_pdf_FALSE='#'
-else
-  DX_COND_pdf_TRUE='#'
-  DX_COND_pdf_FALSE=
-fi
-
 if test "$DX_FLAG_pdf" = 1; then
 
     :
@@ -20646,19 +21552,13 @@ fi
 
 
 # LaTeX generation for PS and/or PDF:
- if test "$DX_FLAG_ps" = 1 || test "$DX_FLAG_pdf" = 1; then
-  DX_COND_latex_TRUE=
-  DX_COND_latex_FALSE='#'
-else
-  DX_COND_latex_TRUE='#'
-  DX_COND_latex_FALSE=
-fi
-
 if test "$DX_FLAG_ps" = 1 || test "$DX_FLAG_pdf" = 1; then
     DX_ENV="$DX_ENV GENERATE_LATEX='YES'"
+GENERATE_LATEX=YES
 
 else
     DX_ENV="$DX_ENV GENERATE_LATEX='NO'"
+GENERATE_LATEX=NO
 
 fi
 
@@ -20672,6 +21572,7 @@ case "$DOXYGEN_PAPER_SIZE" in
 ;; #(
 a4wide|a4|letter|legal|executive)
     DX_ENV="$DX_ENV PAPER_SIZE='$DOXYGEN_PAPER_SIZE'"
+PAPER_SIZE=$DOXYGEN_PAPER_SIZE
 
 ;; #(
 *)
@@ -20679,6 +21580,203 @@ a4wide|a4|letter|legal|executive)
 ;;
 esac
 
+# Rules:
+if test $DX_FLAG_html -eq 1; then :
+  DX_SNIPPET_html="## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+DX_CLEAN_HTML = \$(DX_DOCDIR)/html\\
+                \$(DX_DOCDIR)/html
+
+"
+else
+  DX_SNIPPET_html=""
+fi
+if test $DX_FLAG_chi -eq 1; then :
+  DX_SNIPPET_chi="
+DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi\\
+               \$(DX_DOCDIR)/\$(PACKAGE).chi"
+else
+  DX_SNIPPET_chi=""
+fi
+if test $DX_FLAG_chm -eq 1; then :
+  DX_SNIPPET_chm="## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+DX_CLEAN_CHM = \$(DX_DOCDIR)/chm\\
+               \$(DX_DOCDIR)/chm\
+${DX_SNIPPET_chi}
+
+"
+else
+  DX_SNIPPET_chm=""
+fi
+if test $DX_FLAG_man -eq 1; then :
+  DX_SNIPPET_man="## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+DX_CLEAN_MAN = \$(DX_DOCDIR)/man\\
+               \$(DX_DOCDIR)/man
+
+"
+else
+  DX_SNIPPET_man=""
+fi
+if test $DX_FLAG_rtf -eq 1; then :
+  DX_SNIPPET_rtf="## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf\\
+               \$(DX_DOCDIR)/rtf
+
+"
+else
+  DX_SNIPPET_rtf=""
+fi
+if test $DX_FLAG_xml -eq 1; then :
+  DX_SNIPPET_xml="## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+DX_CLEAN_XML = \$(DX_DOCDIR)/xml\\
+               \$(DX_DOCDIR)/xml
+
+"
+else
+  DX_SNIPPET_xml=""
+fi
+if test $DX_FLAG_ps -eq 1; then :
+  DX_SNIPPET_ps="## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps\\
+              \$(DX_DOCDIR)/\$(PACKAGE).ps
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: \$(DX_CLEAN_PS)
+
+\$(DX_DOCDIR)/\$(PACKAGE).ps: \$(DX_DOCDIR)/\$(PACKAGE).tag
+	\$(DX_V_LATEX)cd \$(DX_DOCDIR)/latex; \\
+	rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+	\$(DX_LATEX) refman.tex; \\
+	\$(DX_MAKEINDEX) refman.idx; \\
+	\$(DX_LATEX) refman.tex; \\
+	countdown=5; \\
+	while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+	                  refman.log > /dev/null 2>&1 \\
+	   && test \$\$countdown -gt 0; do \\
+	    \$(DX_LATEX) refman.tex; \\
+            countdown=\`expr \$\$countdown - 1\`; \\
+	done; \\
+	\$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
+
+"
+else
+  DX_SNIPPET_ps=""
+fi
+if test $DX_FLAG_pdf -eq 1; then :
+  DX_SNIPPET_pdf="## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf\\
+               \$(DX_DOCDIR)/\$(PACKAGE).pdf
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: \$(DX_CLEAN_PDF)
+
+\$(DX_DOCDIR)/\$(PACKAGE).pdf: \$(DX_DOCDIR)/\$(PACKAGE).tag
+	\$(DX_V_LATEX)cd \$(DX_DOCDIR)/latex; \\
+	rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+	\$(DX_PDFLATEX) refman.tex; \\
+	\$(DX_MAKEINDEX) refman.idx; \\
+	\$(DX_PDFLATEX) refman.tex; \\
+	countdown=5; \\
+	while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+	                  refman.log > /dev/null 2>&1 \\
+	   && test \$\$countdown -gt 0; do \\
+	    \$(DX_PDFLATEX) refman.tex; \\
+	    countdown=\`expr \$\$countdown - 1\`; \\
+	done; \\
+	mv refman.pdf ../\$(PACKAGE).pdf
+
+"
+else
+  DX_SNIPPET_pdf=""
+fi
+if test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1; then :
+  DX_SNIPPET_latex="## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
+_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_LATEX_0 = @echo \"  LATEX \" \$@;
+
+DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex\\
+                 \$(DX_DOCDIR)/latex
+
+"
+else
+  DX_SNIPPET_latex=""
+fi
+
+if test $DX_FLAG_doc -eq 1; then :
+  DX_SNIPPET_doc="## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+${DX_SNIPPET_html}\
+${DX_SNIPPET_chm}\
+${DX_SNIPPET_man}\
+${DX_SNIPPET_rtf}\
+${DX_SNIPPET_xml}\
+${DX_SNIPPET_ps}\
+${DX_SNIPPET_pdf}\
+${DX_SNIPPET_latex}\
+DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
+_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_DXGEN_0 = @echo \"  DXGEN \" \$<;
+
+.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+doxygen-run: \$(DX_DOCDIR)/\$(PACKAGE).tag
+
+doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+\$(DX_DOCDIR)/\$(PACKAGE).tag: \$(DX_CONFIG) \$(pkginclude_HEADERS)
+	\$(A""M_V_at)rm -rf \$(DX_DOCDIR)
+	\$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR) \$(DX_DOXYGEN) \$(DX_CONFIG)
+	\$(A""M_V_at)echo Timestamp >\$@
+
+DX_CLEANFILES = \\
+	\$(DX_DOCDIR)/doxygen_sqlite3.db \\
+	\$(DX_DOCDIR)/\$(PACKAGE).tag \\
+	-r \\
+	\$(DX_CLEAN_HTML) \\
+	\$(DX_CLEAN_CHM) \\
+	\$(DX_CLEAN_CHI) \\
+	\$(DX_CLEAN_MAN) \\
+	\$(DX_CLEAN_RTF) \\
+	\$(DX_CLEAN_XML) \\
+	\$(DX_CLEAN_PS) \\
+	\$(DX_CLEAN_PDF) \\
+	\$(DX_CLEAN_LATEX)"
+else
+  DX_SNIPPET_doc=""
+fi
+DX_RULES="${DX_SNIPPET_doc}"
+
+
 #For debugging:
 #echo DX_FLAG_doc=$DX_FLAG_doc
 #echo DX_FLAG_dot=$DX_FLAG_dot
@@ -20862,50 +21960,6 @@ if test -z "${ENABLE_LIBMODPLUG_TRUE}" && test -z "${ENABLE_LIBMODPLUG_FALSE}";
   as_fn_error $? "conditional \"ENABLE_LIBMODPLUG\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${DX_COND_doc_TRUE}" && test -z "${DX_COND_doc_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_doc\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_dot_TRUE}" && test -z "${DX_COND_dot_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_dot\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_man_TRUE}" && test -z "${DX_COND_man_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_man\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_rtf_TRUE}" && test -z "${DX_COND_rtf_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_rtf\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_xml_TRUE}" && test -z "${DX_COND_xml_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_xml\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_chm_TRUE}" && test -z "${DX_COND_chm_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_chm\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_chi_TRUE}" && test -z "${DX_COND_chi_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_chi\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_html_TRUE}" && test -z "${DX_COND_html_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_html\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_ps_TRUE}" && test -z "${DX_COND_ps_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_ps\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_pdf_TRUE}" && test -z "${DX_COND_pdf_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_pdf\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${DX_COND_latex_TRUE}" && test -z "${DX_COND_latex_FALSE}"; then
-  as_fn_error $? "conditional \"DX_COND_latex\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
 
 : "${CONFIG_STATUS=./config.status}"
 ac_write_fail=0
@@ -21303,7 +22357,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libopenmpt $as_me 0.2.8461-autotools, which was
+This file was extended by libopenmpt $as_me 0.3.1+release.autotools, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -21370,7 +22424,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libopenmpt config.status 0.2.8461-autotools
+libopenmpt config.status 0.3.1+release.autotools
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -21505,6 +22559,7 @@ enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
 enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
 pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
 enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
 SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
 ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
 PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
@@ -21554,10 +22609,13 @@ compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
 GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
 lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
 lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
 lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
 lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
 nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
 lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
 objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
 MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
 lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
@@ -21622,7 +22680,8 @@ finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
 finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
 hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
 sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
-sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
+configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
 hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
 enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
 enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
@@ -21727,9 +22786,12 @@ CFLAGS \
 compiler \
 lt_cv_sys_global_symbol_pipe \
 lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_import \
 lt_cv_sys_global_symbol_to_c_name_address \
 lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_cv_nm_interface \
 nm_file_list_spec \
+lt_cv_truncate_bin \
 lt_prog_compiler_no_builtin_flag \
 lt_prog_compiler_pic \
 lt_prog_compiler_wl \
@@ -21795,7 +22857,7 @@ postdeps_CXX \
 compiler_lib_search_path_CXX; do
     case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[\\\\\\\`\\"\\\$]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -21822,7 +22884,8 @@ postinstall_cmds \
 postuninstall_cmds \
 finish_cmds \
 sys_lib_search_path_spec \
-sys_lib_dlsearch_path_spec \
+configure_time_dlsearch_path \
+configure_time_lt_sys_library_path \
 reload_cmds_CXX \
 old_archive_cmds_CXX \
 old_archive_from_new_cmds_CXX \
@@ -21836,7 +22899,7 @@ prelink_cmds_CXX \
 postlink_cmds_CXX; do
     case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[\\\\\\\`\\"\\\$]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -21845,19 +22908,16 @@ postlink_cmds_CXX; do
 done
 
 ac_aux_dir='$ac_aux_dir'
-xsi_shell='$xsi_shell'
-lt_shell_append='$lt_shell_append'
 
-# See if we are running on zsh, and set the options which allow our
+# See if we are running on zsh, and set the options that allow our
 # commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
+if test -n "\${ZSH_VERSION+set}"; then
    setopt NO_GLOB_SUBST
 fi
 
 
     PACKAGE='$PACKAGE'
     VERSION='$VERSION'
-    TIMESTAMP='$TIMESTAMP'
     RM='$RM'
     ofile='$ofile'
 
@@ -22571,55 +23631,52 @@ $as_echo X"$file" |
  ;;
     "libtool":C)
 
-    # See if we are running on zsh, and set the options which allow our
+    # See if we are running on zsh, and set the options that allow our
     # commands through without removal of \ escapes.
-    if test -n "${ZSH_VERSION+set}" ; then
+    if test -n "${ZSH_VERSION+set}"; then
       setopt NO_GLOB_SUBST
     fi
 
-    cfgfile="${ofile}T"
+    cfgfile=${ofile}T
     trap "$RM \"$cfgfile\"; exit 1" 1 2 15
     $RM "$cfgfile"
 
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# Generated automatically by $as_me ($PACKAGE) $VERSION
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
 #
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-#                 Foundation, Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-#   This file is part of GNU Libtool.
-#
-# GNU Libtool is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the  same
+# distribution terms that you use for the rest of that program.
 #
-# GNU Libtool is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING.  If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 # The names of the tagged configurations supported by this script.
-available_tags="CXX "
+available_tags='CXX '
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
 
 # ### BEGIN LIBTOOL CONFIG
 
@@ -22639,6 +23696,9 @@ pic_mode=$pic_mode
 # Whether or not to optimize for fast installation.
 fast_install=$enable_fast_install
 
+# Shared archive member basename,for filename based shared library versioning on AIX.
+shared_archive_member_spec=$shared_archive_member_spec
+
 # Shell to use when invoking shell scripts.
 SHELL=$lt_SHELL
 
@@ -22756,18 +23816,27 @@ global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
 # Transform the output of nm in a proper C declaration.
 global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
 
+# Transform the output of nm into a list of symbols to manually relocate.
+global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
+
 # Transform the output of nm in a C name address pair.
 global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
 
 # Transform the output of nm in a C name address pair when lib prefix is needed.
 global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
 
+# The name lister interface.
+nm_interface=$lt_lt_cv_nm_interface
+
 # Specify filename containing input files for \$NM.
 nm_file_list_spec=$lt_nm_file_list_spec
 
-# The root where to search for dependent libraries,and in which our libraries should be installed.
+# The root where to search for dependent libraries,and where our libraries should be installed.
 lt_sysroot=$lt_sysroot
 
+# Command to truncate a binary pipe.
+lt_truncate_bin=$lt_lt_cv_truncate_bin
+
 # The name of the directory that contains temporary libtool files.
 objdir=$objdir
 
@@ -22858,8 +23927,11 @@ hardcode_into_libs=$hardcode_into_libs
 # Compile-time system search path for libraries.
 sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
 
-# Run-time system search path for libraries.
-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+# Detected run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
+
+# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
+configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
 
 # Whether dlopen is supported.
 dlopen_support=$enable_dlopen
@@ -22952,13 +24024,13 @@ hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
 # Whether we need a single "-rpath" flag with a separated argument.
 hardcode_libdir_separator=$lt_hardcode_libdir_separator
 
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
 # DIR into the resulting binary.
 hardcode_direct=$hardcode_direct
 
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
 # DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
 # library is relocated.
 hardcode_direct_absolute=$hardcode_direct_absolute
 
@@ -23024,13 +24096,72 @@ compiler_lib_search_path=$lt_compiler_lib_search_path
 
 _LT_EOF
 
+    cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x$2 in
+    x)
+        ;;
+    *:)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+        ;;
+    x:*)
+        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+        ;;
+    *)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+
+
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in $*""; do
+      case $cc_temp in
+        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
   case $host_os in
   aix3*)
     cat <<\_LT_EOF >> "$cfgfile"
 # AIX sometimes has problems with the GCC collect2 program.  For some
 # reason, if we set the COLLECT_NAMES environment variable, the problems
 # vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
+if test set != "${COLLECT_NAMES+set}"; then
   COLLECT_NAMES=
   export COLLECT_NAMES
 fi
@@ -23039,7 +24170,7 @@ _LT_EOF
   esac
 
 
-ltmain="$ac_aux_dir/ltmain.sh"
+ltmain=$ac_aux_dir/ltmain.sh
 
 
   # We use sed instead of cat because bash on DJGPP gets confused if
@@ -23049,165 +24180,6 @@ ltmain="$ac_aux_dir/ltmain.sh"
   sed '$q' "$ltmain" >> "$cfgfile" \
      || (rm -f "$cfgfile"; exit 1)
 
-  if test x"$xsi_shell" = xyes; then
-  sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
-func_dirname ()\
-{\
-\    case ${1} in\
-\      */*) func_dirname_result="${1%/*}${2}" ;;\
-\      *  ) func_dirname_result="${3}" ;;\
-\    esac\
-} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_basename ()$/,/^} # func_basename /c\
-func_basename ()\
-{\
-\    func_basename_result="${1##*/}"\
-} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
-func_dirname_and_basename ()\
-{\
-\    case ${1} in\
-\      */*) func_dirname_result="${1%/*}${2}" ;;\
-\      *  ) func_dirname_result="${3}" ;;\
-\    esac\
-\    func_basename_result="${1##*/}"\
-} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
-func_stripname ()\
-{\
-\    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
-\    # positional parameters, so assign one to ordinary parameter first.\
-\    func_stripname_result=${3}\
-\    func_stripname_result=${func_stripname_result#"${1}"}\
-\    func_stripname_result=${func_stripname_result%"${2}"}\
-} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
-func_split_long_opt ()\
-{\
-\    func_split_long_opt_name=${1%%=*}\
-\    func_split_long_opt_arg=${1#*=}\
-} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
-func_split_short_opt ()\
-{\
-\    func_split_short_opt_arg=${1#??}\
-\    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
-} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
-func_lo2o ()\
-{\
-\    case ${1} in\
-\      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
-\      *)    func_lo2o_result=${1} ;;\
-\    esac\
-} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_xform ()$/,/^} # func_xform /c\
-func_xform ()\
-{\
-    func_xform_result=${1%.*}.lo\
-} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_arith ()$/,/^} # func_arith /c\
-func_arith ()\
-{\
-    func_arith_result=$(( $* ))\
-} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_len ()$/,/^} # func_len /c\
-func_len ()\
-{\
-    func_len_result=${#1}\
-} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-fi
-
-if test x"$lt_shell_append" = xyes; then
-  sed -e '/^func_append ()$/,/^} # func_append /c\
-func_append ()\
-{\
-    eval "${1}+=\\${2}"\
-} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
-func_append_quoted ()\
-{\
-\    func_quote_for_eval "${2}"\
-\    eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
-} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
-  # Save a `func_append' function call where possible by direct use of '+='
-  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-else
-  # Save a `func_append' function call even when '+=' is not available
-  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
-$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
-fi
-
-
    mv -f "$cfgfile" "$ofile" ||
     (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
   chmod +x "$ofile"
@@ -23294,13 +24266,13 @@ hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
 # Whether we need a single "-rpath" flag with a separated argument.
 hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
 
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
 # DIR into the resulting binary.
 hardcode_direct=$hardcode_direct_CXX
 
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
 # DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
 # library is relocated.
 hardcode_direct_absolute=$hardcode_direct_absolute_CXX
 
diff --git a/configure.ac b/configure.ac
index 1575db5..ea14de3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([libopenmpt], [0.2.8461-autotools], [https://bugs.openmpt.org/], [libopenmpt], [https://lib.openmpt.org/])
+AC_INIT([libopenmpt], [0.3.1+release.autotools], [https://bugs.openmpt.org/], [libopenmpt], [https://lib.openmpt.org/])
 AC_PREREQ([2.68])
 
 AC_CONFIG_MACRO_DIR([m4])
@@ -20,9 +20,16 @@ AM_PROG_CC_C_O
 AC_PROG_CXX
 AC_PROG_INSTALL
 
-AC_DEFINE([MPT_SVNURL], ["https://source.openmpt.org/svn/openmpt/branches/OpenMPT-1.26"], [svn version])
-AC_DEFINE([MPT_SVNVERSION], ["8461"], [svn version])
-AC_DEFINE([MPT_SVNDATE], ["2017-07-07T12:47:24.457926Z"], [svn date])
+LIBOPENMPT_LTVER_CURRENT=1
+LIBOPENMPT_LTVER_REVISION=1
+LIBOPENMPT_LTVER_AGE=1
+AC_SUBST([LIBOPENMPT_LTVER_CURRENT])
+AC_SUBST([LIBOPENMPT_LTVER_REVISION])
+AC_SUBST([LIBOPENMPT_LTVER_AGE])
+
+AC_DEFINE([MPT_SVNURL], ["https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.3.1"], [svn version])
+AC_DEFINE([MPT_SVNVERSION], ["9016"], [svn version])
+AC_DEFINE([MPT_SVNDATE], ["2017-09-28T06:05:55.172831Z"], [svn date])
 AC_DEFINE([MPT_PACKAGE], [true], [is package])
 
 
@@ -70,7 +77,7 @@ MPG123_PKG=
 AC_ARG_WITH([mpg123], AS_HELP_STRING([--without-mpg123], [Disable use of libmpg123.]))
 AS_IF([test "x$with_mpg123" != "xno"],
  [
-  PKG_CHECK_MODULES([MPG123], [libmpg123],
+  PKG_CHECK_MODULES([MPG123], [libmpg123 >= 1.13.0],
    [
     MPG123_PKG=libmpg123
     AC_DEFINE([MPT_WITH_MPG123], [], [with mpg123])
@@ -117,93 +124,9 @@ AS_IF([test "x$with_vorbisfile" != "xno"],
  ]
 )
 
-AC_ARG_ENABLE([dlopen], AS_HELP_STRING([--enable-dlopen], [Enable dynamic loading of 3rd-party libraries using dlopen or LoadLibray.]))
-AS_IF([test "x$enable-dlopen" = "xyes"],
- [
-  AC_DEFINE([MPT_ENABLE_DLOPEN], [], [enable dlopen])
- ]
-)
-  
-# Optional libopenmpt dependency: libltdl
-AC_ARG_WITH([ltdl], AS_HELP_STRING([--with-ltdl], [Enable the use of libtool libltdl for dynamic loading of third party libraries.]))
-AS_IF([test "x$with_ltdl" = "xyes"],
- [
-  AC_CHECK_HEADER([ltdl.h],
-   [
-    AC_CHECK_LIB([ltdl], [lt_dlinit],
-     [
-      have_ltdl=1
-     ],
-     [
-      have_ltdl=0
-     ]
-    )
-   ],
-   [
-    have_ltdl=0
-   ]
-  )
-  AS_IF([test "x$have_ltdl" = "x0"],
-   [
-    AC_MSG_ERROR([Unable to find libltdl.])
-   ]
-  )
- ],
- [
-  have_ltdl=0
- ]
-)
-AS_IF([test "x$have_ltdl" = "x1"],
- [
-  LTDL_CPPFLAGS=-DMPT_WITH_LTDL
-  LTDL_LIBS=-lltdl
- ],
- [
-  LTDL_CPPFLAGS=
-  LTDL_LIBS=
- ]
-)
-AC_SUBST([LTDL_CPPFLAGS])
-AC_SUBST([LTDL_LIBS])
-
-# Optional libopenmpt dependency: libdl
-AC_ARG_WITH([dl], AS_HELP_STRING([--with-dl], [Enable the use of libdl for dynamic loading of third party libraries.]))
-AS_IF([test "x$with_dl" = "xyes"],
- [
-  AC_SEARCH_LIBS([dlopen], [dl dld],
-   [
-    have_dl=1
-   ],
-   [
-    have_dl=0
-   ]
-  )
-  AS_IF([test "x$have_dl" = "x0"],
-   [
-    AC_MSG_ERROR([Unable to find libdl.])
-   ]
-  )
- ],
- [
-  have_dl=0
- ]
-)
-AS_IF([test "x$have_dl" = "x1"],
- [
-  DL_CPPFLAGS=-DMPT_WITH_DL
-  DL_LIBS=  
- ],
- [
-  DL_CPPFLAGS=
-  DL_LIBS=
- ]
-)
-AC_SUBST([DL_CPPFLAGS])
-AC_SUBST([DL_LIBS])
-
 
 LIBOPENMPT_REQUIRES_PRIVATE="$ZLIB_PKG $MPG123_PKG $OGG_PKG $VORBIS_PKG $VORBISFILE_PKG"
-LIBOPENMPT_LIBS_PRIVATE="$LTDL_LIBS $DL_LIBS"
+LIBOPENMPT_LIBS_PRIVATE=""
 AC_SUBST([LIBOPENMPT_REQUIRES_PRIVATE])
 AC_SUBST([LIBOPENMPT_LIBS_PRIVATE])
 
@@ -224,8 +147,10 @@ AM_CONDITIONAL([ENABLE_TESTS], [test "x$enable_tests" != "xno"])
 
 
 # Optional openmpt123 dependency
-AC_ARG_WITH([pulseaudio], AS_HELP_STRING([--without-pulseaudio], [Disable use of libpulse and libpulse-simple.]))
+AC_ARG_WITH([pulseaudio], AS_HELP_STRING([--with-pulseaudio], [Enable use of libpulse and libpulse-simple (enabled by default on Linux).]))
 AS_IF([test "x$enable_openmpt123" != "xno"],[
+case $host_os in
+ linux*)
 AS_IF([test "x$with_pulseaudio" != "xno"],
  [
   PKG_CHECK_MODULES([PULSEAUDIO], [libpulse libpulse-simple],
@@ -243,6 +168,27 @@ AS_IF([test "x$with_pulseaudio" != "xno"],
   have_pulseaudio=0
  ]
 )
+ ;;
+ *)
+AS_IF([test "x$with_pulseaudio" = "xyes"],
+ [
+  PKG_CHECK_MODULES([PULSEAUDIO], [libpulse libpulse-simple],
+   [
+    have_pulseaudio=1
+    AC_DEFINE([MPT_WITH_PULSEAUDIO], [], [with libpulseaudio])
+   ],
+   [
+    have_pulseaudio=0
+    AC_MSG_ERROR([Unable to find libpulse and/or libpulse-simple.])
+   ]
+  )
+ ],
+ [
+  have_pulseaudio=0
+ ]
+)
+ ;;
+esac
 ],[have_pulseaudio=0])
 
 # Optional openmpt123 and examples dependency
diff --git a/examples/libopenmpt_example_c.c b/examples/libopenmpt_example_c.c
index f49d603..550f2d0 100644
--- a/examples/libopenmpt_example_c.c
+++ b/examples/libopenmpt_example_c.c
@@ -31,9 +31,42 @@ static int16_t * const buffers[2] = { left, right };
 
 static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
 	(void)userdata;
-
 	if ( message ) {
-		fprintf( stderr, "%s\n", message );
+		fprintf( stderr, "openmpt: %s\n", message );
+	}
+}
+
+static int libopenmpt_example_errfunc( int error, void * userdata ) {
+	(void)userdata;
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_DEFAULT & ~OPENMPT_ERROR_FUNC_RESULT_LOG;
+}
+
+static void libopenmpt_example_print_error( const char * func_name, int mod_err, const char * mod_err_str ) {
+	if ( !func_name ) {
+		func_name = "unknown function";
+	}
+	if ( mod_err == OPENMPT_ERROR_OUT_OF_MEMORY ) {
+		mod_err_str = openmpt_error_string( mod_err );
+		if ( !mod_err_str ) {
+			fprintf( stderr, "Error: %s\n", "OPENMPT_ERROR_OUT_OF_MEMORY" );
+		} else {
+			fprintf( stderr, "Error: %s\n", mod_err_str );
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
+	} else {
+		if ( !mod_err_str ) {
+			mod_err_str = openmpt_error_string( mod_err );
+			if ( !mod_err_str ) {
+				fprintf( stderr, "Error: %s failed.\n", func_name );
+			} else {
+				fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
+			}
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
+		fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
 	}
 }
 
@@ -46,6 +79,8 @@ int main( int argc, char * argv[] ) {
 	int result = 0;
 	FILE * file = 0;
 	openmpt_module * mod = 0;
+	int mod_err = OPENMPT_ERROR_OK;
+	const char * mod_err_str = NULL;
 	size_t count = 0;
 	PaError pa_error = paNoError;
 	int pa_initialized = 0;
@@ -74,11 +109,14 @@ int main( int argc, char * argv[] ) {
 		goto fail;
 	}
 
-	mod = openmpt_module_create( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, NULL );
+	mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
 	if ( !mod ) {
-		fprintf( stderr, "Error: %s\n", "openmpt_module_create() failed." );
+		libopenmpt_example_print_error( "openmpt_module_create2()", mod_err, mod_err_str );
+		openmpt_free_string( mod_err_str );
+		mod_err_str = NULL;
 		goto fail;
 	}
+	openmpt_module_set_error_func( mod, NULL, NULL );
 
 	pa_error = Pa_Initialize();
 	if ( pa_error != paNoError ) {
@@ -105,7 +143,15 @@ int main( int argc, char * argv[] ) {
 
 	while ( 1 ) {
 
+		openmpt_module_error_clear( mod );
 		count = openmpt_module_read_stereo( mod, SAMPLERATE, BUFFERSIZE, left, right );
+		mod_err = openmpt_module_error_get_last( mod );
+		mod_err_str = openmpt_module_error_get_last_message( mod );
+		if ( mod_err != OPENMPT_ERROR_OK ) {
+			libopenmpt_example_print_error( "openmpt_module_read_stereo()", mod_err, mod_err_str );
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
 		if ( count == 0 ) {
 			break;
 		}
diff --git a/examples/libopenmpt_example_c_mem.c b/examples/libopenmpt_example_c_mem.c
index 2eb09be..6a40575 100644
--- a/examples/libopenmpt_example_c_mem.c
+++ b/examples/libopenmpt_example_c_mem.c
@@ -30,9 +30,42 @@ static int16_t * const buffers[2] = { left, right };
 
 static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
 	(void)userdata;
-
 	if ( message ) {
-		fprintf( stderr, "%s\n", message );
+		fprintf( stderr, "openmpt: %s\n", message );
+	}
+}
+
+static int libopenmpt_example_errfunc( int error, void * userdata ) {
+	(void)userdata;
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_DEFAULT & ~OPENMPT_ERROR_FUNC_RESULT_LOG;
+}
+
+static void libopenmpt_example_print_error( const char * func_name, int mod_err, const char * mod_err_str ) {
+	if ( !func_name ) {
+		func_name = "unknown function";
+	}
+	if ( mod_err == OPENMPT_ERROR_OUT_OF_MEMORY ) {
+		mod_err_str = openmpt_error_string( mod_err );
+		if ( !mod_err_str ) {
+			fprintf( stderr, "Error: %s\n", "OPENMPT_ERROR_OUT_OF_MEMORY" );
+		} else {
+			fprintf( stderr, "Error: %s\n", mod_err_str );
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
+	} else {
+		if ( !mod_err_str ) {
+			mod_err_str = openmpt_error_string( mod_err );
+			if ( !mod_err_str ) {
+				fprintf( stderr, "Error: %s failed.\n", func_name );
+			} else {
+				fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
+			}
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
+		fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
 	}
 }
 
@@ -137,6 +170,8 @@ int main( int argc, char * argv[] ) {
 	int result = 0;
 	blob_t * blob = 0;
 	openmpt_module * mod = 0;
+	int mod_err = OPENMPT_ERROR_OK;
+	const char * mod_err_str = NULL;
 	size_t count = 0;
 	PaError pa_error = paNoError;
 	int pa_initialized = 0;
@@ -164,9 +199,11 @@ int main( int argc, char * argv[] ) {
 		goto fail;
 	}
 
-	mod = openmpt_module_create_from_memory( blob->data, blob->size, &libopenmpt_example_logfunc, NULL, NULL );
+	mod = openmpt_module_create_from_memory2( blob->data, blob->size, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
 	if ( !mod ) {
-		fprintf( stderr, "Error: %s\n", "openmpt_module_from_memory() failed." );
+		libopenmpt_example_print_error( "openmpt_module_create_from_memory2()", mod_err, mod_err_str );
+		openmpt_free_string( mod_err_str );
+		mod_err_str = NULL;
 		goto fail;
 	}
 
@@ -195,7 +232,15 @@ int main( int argc, char * argv[] ) {
 
 	while ( 1 ) {
 
+		openmpt_module_error_clear( mod );
 		count = openmpt_module_read_stereo( mod, SAMPLERATE, BUFFERSIZE, left, right );
+		mod_err = openmpt_module_error_get_last( mod );
+		mod_err_str = openmpt_module_error_get_last_message( mod );
+		if ( mod_err != OPENMPT_ERROR_OK ) {
+			libopenmpt_example_print_error( "openmpt_module_read_stereo()", mod_err, mod_err_str );
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
 		if ( count == 0 ) {
 			break;
 		}
diff --git a/examples/libopenmpt_example_c_probe.c b/examples/libopenmpt_example_c_probe.c
index 2a0925f..e4fbabc 100644
--- a/examples/libopenmpt_example_c_probe.c
+++ b/examples/libopenmpt_example_c_probe.c
@@ -8,26 +8,16 @@
  */
 
 /*
- * Usage: libopenmpt_example_c_probe SOMEMODULE
- * Returns 0 on successful probing.
- * Returns 1 on failed probing.
+ * Usage: libopenmpt_example_c_probe SOMEMODULE ...
+ * Returns 0 on successful probing for all files.
+ * Returns 1 on failed probing for 1 or more files.
  * Returns 2 on error.
  */
 
 #define LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY 1
 #define LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT  2
 
-#define LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS 1
-#define LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX    2
-
-#define LIBOPENMPT_EXAMPLE_PROBE_STYLE  LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS
-/* #define LIBOPENMPT_EXAMPLE_PROBE_STYLE  LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX */
-
 #define LIBOPENMPT_EXAMPLE_PROBE_RESULT LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY
-/* #define LIBOPENMPT_EXAMPLE_PROBE_RESULT LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY */
-
-/* Use something between 1024 and 65536. 4096 is a sane default. */
-#define LIBOPENMPT_EXAMPLE_PROBE_PREFIX_BYTES (4096)
 
 #include <memory.h>
 #include <stdint.h>
@@ -36,183 +26,7 @@
 #include <string.h>
 
 #include <libopenmpt/libopenmpt.h>
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS )
 #include <libopenmpt/libopenmpt_stream_callbacks_file.h>
-#endif
-
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-
-typedef struct libopenmpt_example_stream_prefix_probe {
-	const void * prefix_data;
-	int64_t prefix_size;
-	int64_t file_size;
-	int64_t file_pos;
-	int overflow;
-} libopenmpt_example_stream_prefix_probe;
-
-static size_t libopenmpt_example_stream_read_func_prefix_probe( void * stream, void * dst, size_t bytes ) {
-	libopenmpt_example_stream_prefix_probe * s = (libopenmpt_example_stream_prefix_probe*)stream;
-	int64_t offset = bytes;
-	int64_t begpos = s->file_pos;
-	int64_t endpos = s->file_pos;
-	size_t valid_bytes = 0;
-	endpos = (uint64_t)endpos + (uint64_t)offset;
-	if ( ( offset > 0 ) && !( (uint64_t)endpos > (uint64_t)begpos ) ) {
-		/* integer wrapped */
-		return 0;
-	}
-	if ( bytes == 0 ) {
-		return 0;
-	}
-	if ( begpos >= s->file_size ) {
-		return 0;
-	}
-	if ( endpos > s->file_size ) {
-		/* clip to eof */
-		bytes = bytes - (size_t)( endpos - s->file_size );
-		endpos = endpos - ( endpos - s->file_size );
-	}
-	memset( dst, 0, bytes );
-	if ( begpos >= s->prefix_size ) {
-		s->overflow = 1;
-		valid_bytes = 0;
-	} else if ( endpos > s->prefix_size ) {
-		s->overflow = 1;
-		valid_bytes = bytes - (size_t)( endpos - s->prefix_size );
-	} else {
-		valid_bytes = bytes;
-	}
-	memcpy( dst, (const char*)s->prefix_data + s->file_pos, valid_bytes );
-	s->file_pos = s->file_pos + bytes;
-	return bytes;
-}
-
-static int libopenmpt_example_stream_seek_func_prefix_probe( void * stream, int64_t offset, int whence ) {
-	libopenmpt_example_stream_prefix_probe * s = (libopenmpt_example_stream_prefix_probe*)stream;
-	int result = -1;
-	switch ( whence ) {
-		case OPENMPT_STREAM_SEEK_SET:
-			if ( offset < 0 ) {
-				return -1;
-			}
-			if ( offset > s->file_size ) {
-				return -1;
-			}
-			s->file_pos = offset;
-			result = 0;
-			break;
-		case OPENMPT_STREAM_SEEK_CUR:
-			do {
-				int64_t oldpos = s->file_pos;
-				int64_t pos = s->file_pos;
-				pos = (uint64_t)pos + (uint64_t)offset;
-				if ( ( offset > 0 ) && !( (uint64_t)pos > (uint64_t)oldpos ) ) {
-					/* integer wrapped */
-					return -1;
-				}
-				if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) {
-					/* integer wrapped */
-					return -1;
-				}
-				s->file_pos = pos;
-			} while(0);
-			result = 0;
-			break;
-		case OPENMPT_STREAM_SEEK_END:
-			if ( offset > 0 ) {
-				return -1;
-			}
-			do {
-				int64_t oldpos = s->file_pos;
-				int64_t pos = s->file_pos;
-				pos = s->file_size;
-				pos = (uint64_t)pos + (uint64_t)offset;
-				if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) {
-					/* integer wrapped */
-					return -1;
-				}
-				s->file_pos = pos;
-			} while(0);
-			result = 0;
-			break;
-	}
-	return result;
-}
-
-static int64_t libopenmpt_example_stream_tell_func_prefix_probe( void * stream ) {
-	libopenmpt_example_stream_prefix_probe * s = (libopenmpt_example_stream_prefix_probe*)stream;
-	return s->file_pos;
-}
-
-static double libopenmpt_example_could_open_probability_prefix( const void * prefix_data, size_t prefix_size_, int64_t file_size, double effort, openmpt_log_func logfunc, void * user ) {
-	double ret = 0.0;
-	int64_t prefix_size = prefix_size_;
-	openmpt_stream_callbacks openmpt_stream_callbacks_prefix_probe;
-	libopenmpt_example_stream_prefix_probe stream;
-	memset( &openmpt_stream_callbacks_prefix_probe, 0, sizeof( openmpt_stream_callbacks ) );
-	memset( &stream, 0, sizeof( libopenmpt_example_stream_prefix_probe ) );
-	if ( !prefix_data ) {
-		return 0.0;
-	}
-	if ( prefix_size < 0 ) {
-		return 0.0;
-	}
-	if ( file_size < 0 ) {
-		return 0.0;
-	}
-	if ( prefix_size > file_size ) {
-		prefix_size = file_size;
-	}
-	openmpt_stream_callbacks_prefix_probe.read = &libopenmpt_example_stream_read_func_prefix_probe;
-	openmpt_stream_callbacks_prefix_probe.seek = &libopenmpt_example_stream_seek_func_prefix_probe;
-	openmpt_stream_callbacks_prefix_probe.tell = &libopenmpt_example_stream_tell_func_prefix_probe;
-	stream.prefix_data = prefix_data;
-	stream.prefix_size = prefix_size;
-	stream.file_size = file_size;
-	stream.file_pos = 0;
-	stream.overflow = 0;
-	ret = openmpt_could_open_propability( openmpt_stream_callbacks_prefix_probe, &stream, effort, logfunc, user );
-	if ( stream.overflow ) {
-		ret = 0.5;
-	}
-	return ret;
-}
-
-#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY )
-
-static int libopenmpt_example_probe_file_header_prefix( const void * prefix_data, size_t prefix_size, int64_t file_size, openmpt_log_func logfunc, void * user ) {
-	double ret = libopenmpt_example_could_open_probability_prefix( prefix_data, prefix_size, file_size, 0.25, logfunc, user );
-	if ( ret >= 0.5 ) {
-		return 1;
-	}
-	if ( ret < 0.25 ) {
-		return 0;
-	}
-	return 1;
-}
-
-#endif
-
-#endif
-
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS )
-
-#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY )
-
-static int libopenmpt_example_probe_file_header( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * user ) {
-	double ret = openmpt_could_open_propability( stream_callbacks, stream, 0.25, logfunc, user );
-	if ( ret >= 0.5 ) {
-		return 1;
-	}
-	if ( ret < 0.25 ) {
-		return 0;
-	}
-	return 1;
-}
-
-#endif
-
-#endif
 
 static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
 	(void)userdata;
@@ -222,40 +36,36 @@ static void libopenmpt_example_logfunc( const char * message, void * userdata )
 	}
 }
 
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-
-typedef struct blob_t {
-	size_t size;
-	void * data;
-} blob_t;
-
-static void free_blob( blob_t * blob ) {
-	if ( blob ) {
-		if ( blob->data ) {
-			free( blob->data );
-			blob->data = 0;
-		}
-		blob->size = 0;
-		free( blob );
-	}
-}
-
 #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
-static blob_t * load_file( const wchar_t * filename ) {
+static int probe_file( const wchar_t * filename ) {
 #else
-static blob_t * load_file( const char * filename ) {
+static int probe_file( const char * filename ) {
 #endif
-	blob_t * result = 0;
 
-	blob_t * blob = 0;
-	FILE * file = 0;
-	long tell_result = 0;
+	int result = 0;
+	int mod_err = OPENMPT_ERROR_OK;
+	FILE * file = NULL;
 
-	blob = malloc( sizeof( blob_t ) );
-	if ( !blob ) {
+#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY )
+	int result_binary = 0;
+	int probe_file_header_result = OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE;
+	const char * probe_file_header_result_str = NULL;
+#endif
+#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT )
+	double probability = 0.0;
+#endif
+
+#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
+	if ( wcslen( filename ) == 0 ) {
+		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_probe SOMEMODULE'." );
+		goto fail;
+	}
+#else
+	if ( strlen( filename ) == 0 ) {
+		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_probe SOMEMODULE'." );
 		goto fail;
 	}
-	memset( blob, 0, sizeof( blob_t ) );
+#endif
 
 #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
 	file = _wfopen( filename, L"rb" );
@@ -263,51 +73,72 @@ static blob_t * load_file( const char * filename ) {
 	file = fopen( filename, "rb" );
 #endif
 	if ( !file ) {
+		fprintf( stderr, "Error: %s\n", "fopen() failed." );
 		goto fail;
 	}
 
-	if ( fseek( file, 0, SEEK_END ) != 0 ) {
-		goto fail;
-	}
-
-	tell_result = ftell( file );
-	if ( tell_result < 0 ) {
-		goto fail;
-	}
-	if ( (unsigned long)tell_result > SIZE_MAX ) {
-		goto fail;
-	}
-	blob->size = (size_t)tell_result;
-
-	if ( fseek( file, 0, SEEK_SET ) != 0 ) {
-		goto fail;
-	}
-
-	blob->data = malloc( blob->size );
-	if ( !blob->data ) {
-		goto fail;
-	}
-	memset( blob->data, 0, blob->size );
-
-	if ( fread( blob->data, 1, blob->size, file ) != blob->size ) {
-		goto fail;
-	}
+	#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY )
+		probe_file_header_result = openmpt_probe_file_header_from_stream( OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &openmpt_error_func_default, NULL, &mod_err, NULL );
+		probe_file_header_result_str = NULL;
+		result_binary = 0;
+		switch ( probe_file_header_result ) {
+			case OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS:
+				probe_file_header_result_str = "Success     ";
+				result_binary = 1;
+				break;
+			case OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE:
+				probe_file_header_result_str = "Failure     ";
+				result_binary = 0;
+				break;
+			case OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA:
+				probe_file_header_result_str = "WantMoreData";
+				result_binary = 0;
+				break;
+			case OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR:
+				result_binary = 0;
+				fprintf( stderr, "Error: %s\n", "openmpt_probe_file_header() failed." );
+				goto fail;
+				break;
+			default:
+				result_binary = 0;
+				fprintf( stderr, "Error: %s\n", "openmpt_probe_file_header() failed." );
+				goto fail;
+				break;
+		}
+#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
+		fprintf( stdout, "%s - %ls\n", probe_file_header_result_str, filename );
+#else
+		fprintf( stdout, "%s - %s\n", probe_file_header_result_str, filename );
+#endif
+		if ( result_binary ) {
+			result = 0;
+		} else {
+			result = 1;
+		}
+	#elif ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT )
+		probability = openmpt_could_open_probability2( openmpt_stream_get_file_callbacks(), file, 0.25, &libopenmpt_example_logfunc, NULL, &openmpt_error_func_default, NULL, &mod_err, NULL );
+#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
+		fprintf( stdout, "%s: %f - %ls\n", "Result", probability, filename );
+#else
+		fprintf( stdout, "%s: %f - %s\n", "Result", probability, filename );
+#endif
+		if ( probability >= 0.5 ) {
+			result = 0;
+		} else {
+			result = 1;
+		}
+	#else
+		#error "LIBOPENMPT_EXAMPLE_PROBE_RESULT is wrong"
+	#endif
 
-	result = blob;
-	blob = 0;
 	goto cleanup;
 
 fail:
 
-	result = 0;
+	result = 2;
 
 cleanup:
 
-	if ( blob ) {
-		free_blob( blob );
-		blob = 0;
-	}
-
 	if ( file ) {
 		fclose( file );
 		file = 0;
@@ -316,145 +147,35 @@ cleanup:
 	return result;
 }
 
-#endif
-
 #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
 int wmain( int argc, wchar_t * argv[] ) {
 #else
 int main( int argc, char * argv[] ) {
 #endif
 
-	int result = 0;
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-	blob_t * blob = 0;
-#elif ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS )
-	FILE * file = NULL;
-#endif
-
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-	size_t prefix_size = LIBOPENMPT_EXAMPLE_PROBE_PREFIX_BYTES;
-#endif
-#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT )
-	double probability = 0.0;
-#endif
+	int global_result = 0;
 
-	if ( argc != 2 ) {
-		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_probe SOMEMODULE'." );
+	if ( argc <= 1 ) {
+		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_probe SOMEMODULE ...'." );
 		goto fail;
 	}
 
-#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
-	if ( wcslen( argv[1] ) == 0 ) {
-		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_probe SOMEMODULE'." );
-		goto fail;
-	}
-#else
-	if ( strlen( argv[1] ) == 0 ) {
-		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c_probe SOMEMODULE'." );
-		goto fail;
-	}
-#endif
-
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-	blob = load_file( argv[1] );
-	if ( !blob ) {
-		fprintf( stderr, "Error: %s\n", "load_file() failed." );
-		goto fail;
-	}
-#elif ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS )
-#if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) )
-	if ( wcslen( argv[1] ) == 0 ) {
-		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c SOMEMODULE'." );
-		goto fail;
-	}
-	file = _wfopen( argv[1], L"rb" );
-#else
-	if ( strlen( argv[1] ) == 0 ) {
-		fprintf( stderr, "Error: %s\n", "Wrong invocation. Use 'libopenmpt_example_c SOMEMODULE'." );
-		goto fail;
-	}
-	file = fopen( argv[1], "rb" );
-#endif
-	if ( !file ) {
-		fprintf( stderr, "Error: %s\n", "fopen() failed." );
-		goto fail;
-	}
-#endif
-
-	#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-
-		if ( prefix_size > blob->size ) {
-			prefix_size = blob->size;
+	for ( int i = 1; i < argc; ++i ) {
+		int result = probe_file( argv[i] );
+		if ( result > global_result ) {
+			global_result = result;
 		}
-		#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY )
-			if ( libopenmpt_example_probe_file_header_prefix( blob->data, prefix_size, blob->size, &libopenmpt_example_logfunc, NULL ) <= 0 ) {
-				fprintf( stdout, "%s\n", "Failure." );
-				result = 1;
-				goto cleanup;
-			} else {
-				fprintf( stdout, "%s\n", "Success." );
-				result = 0; 
-			}
-		#elif ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT )
-			probability = libopenmpt_example_could_open_probability_prefix( blob->data, prefix_size, blob->size, 0.25, &libopenmpt_example_logfunc, NULL );
-			fprintf( stdout, "%s: %f\n", "Result", probability );
-			if ( probability >= 0.5 ) {
-				result = 0;
-			} else {
-				result = 1;
-			}
-		#else
-			#error "LIBOPENMPT_EXAMPLE_PROBE_RESULT is wrong"
-		#endif
-
-	#elif ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS )
-
-		#if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY )
-			if ( libopenmpt_example_probe_file_header( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL ) <= 0 ) {
-				fprintf( stdout, "%s\n", "Failure." );
-				result = 1;
-				goto cleanup;
-			} else {
-				fprintf( stdout, "%s\n", "Success." );
-				result = 0; 
-			}
-		#elif ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT )
-			probability = openmpt_could_open_propability( openmpt_stream_get_file_callbacks(), file, 0.25, &libopenmpt_example_logfunc, NULL );
-			fprintf( stdout, "%s: %f\n", "Result", probability );
-			if ( probability >= 0.5 ) {
-				result = 0;
-			} else {
-				result = 1;
-			}
-		#else
-			#error "LIBOPENMPT_EXAMPLE_PROBE_RESULT is wrong"
-		#endif
-
-	#else
-		#error "LIBOPENMPT_EXAMPLE_PROBE_STYLE is wrong"
-	#endif
+	}
 
 	goto cleanup;
 
 fail:
 
-	result = 2;
+	global_result = 2;
 
 cleanup:
 
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_PREFIX )
-	if ( blob ) {
-		free_blob( blob );
-		blob = 0;
-	}
-#endif
+	return global_result;
 
-#if ( LIBOPENMPT_EXAMPLE_PROBE_STYLE == LIBOPENMPT_EXAMPLE_PROBE_STYLE_CALLBACKS )
-	if ( file ) {
-		fclose( file );
-		file = 0;
-	}
-#endif
-
-	return result;
 }
+
diff --git a/examples/libopenmpt_example_c_stdout.c b/examples/libopenmpt_example_c_stdout.c
index 37f11a9..1488737 100644
--- a/examples/libopenmpt_example_c_stdout.c
+++ b/examples/libopenmpt_example_c_stdout.c
@@ -28,9 +28,42 @@
 
 static void libopenmpt_example_logfunc( const char * message, void * userdata ) {
 	(void)userdata;
-
 	if ( message ) {
-		fprintf( stderr, "%s\n", message );
+		fprintf( stderr, "openmpt: %s\n", message );
+	}
+}
+
+static int libopenmpt_example_errfunc( int error, void * userdata ) {
+	(void)userdata;
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_DEFAULT & ~OPENMPT_ERROR_FUNC_RESULT_LOG;
+}
+
+static void libopenmpt_example_print_error( const char * func_name, int mod_err, const char * mod_err_str ) {
+	if ( !func_name ) {
+		func_name = "unknown function";
+	}
+	if ( mod_err == OPENMPT_ERROR_OUT_OF_MEMORY ) {
+		mod_err_str = openmpt_error_string( mod_err );
+		if ( !mod_err_str ) {
+			fprintf( stderr, "Error: %s\n", "OPENMPT_ERROR_OUT_OF_MEMORY" );
+		} else {
+			fprintf( stderr, "Error: %s\n", mod_err_str );
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
+	} else {
+		if ( !mod_err_str ) {
+			mod_err_str = openmpt_error_string( mod_err );
+			if ( !mod_err_str ) {
+				fprintf( stderr, "Error: %s failed.\n", func_name );
+			} else {
+				fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
+			}
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
+		fprintf( stderr, "Error: %s failed: %s\n", func_name, mod_err_str );
 	}
 }
 
@@ -61,6 +94,8 @@ int main( int argc, char * argv[] ) {
 	int result = 0;
 	FILE * file = 0;
 	openmpt_module * mod = 0;
+	int mod_err = OPENMPT_ERROR_OK;
+	const char * mod_err_str = NULL;
 	size_t count = 0;
 	size_t written = 0;
 
@@ -87,15 +122,25 @@ int main( int argc, char * argv[] ) {
 		goto fail;
 	}
 
-	mod = openmpt_module_create( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, NULL );
+	mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL );
 	if ( !mod ) {
-		fprintf( stderr, "Error: %s\n", "openmpt_module_create() failed." );
+		libopenmpt_example_print_error( "openmpt_module_create2()", mod_err, mod_err_str );
+		openmpt_free_string( mod_err_str );
+		mod_err_str = NULL;
 		goto fail;
 	}
 
 	while ( 1 ) {
 
+		openmpt_module_error_clear( mod );
 		count = openmpt_module_read_interleaved_stereo( mod, SAMPLERATE, BUFFERSIZE, buffer );
+		mod_err = openmpt_module_error_get_last( mod );
+		mod_err_str = openmpt_module_error_get_last_message( mod );
+		if ( mod_err != OPENMPT_ERROR_OK ) {
+			libopenmpt_example_print_error( "openmpt_module_read_interleaved_stereo()", mod_err, mod_err_str );
+			openmpt_free_string( mod_err_str );
+			mod_err_str = NULL;
+		}
 		if ( count == 0 ) {
 			break;
 		}
diff --git a/examples/libopenmpt_example_c_unsafe.c b/examples/libopenmpt_example_c_unsafe.c
index e8009b7..0419ac3 100644
--- a/examples/libopenmpt_example_c_unsafe.c
+++ b/examples/libopenmpt_example_c_unsafe.c
@@ -45,7 +45,7 @@ int main( int argc, char * argv[] ) {
 #else
 	file = fopen( argv[1], "rb" );
 #endif
-	mod = openmpt_module_create( openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL );
+	mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
 	fclose( file );
 	Pa_Initialize();
 	Pa_OpenDefaultStream( &stream, 0, 2, paInt16 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL );
diff --git a/examples/libopenmpt_example_cxx.cpp b/examples/libopenmpt_example_cxx.cpp
index 552499a..f3564ce 100644
--- a/examples/libopenmpt_example_cxx.cpp
+++ b/examples/libopenmpt_example_cxx.cpp
@@ -14,6 +14,7 @@
 #include <exception>
 #include <fstream>
 #include <iostream>
+#include <new>
 #include <stdexcept>
 #include <vector>
 
@@ -66,6 +67,8 @@ int main( int argc, char * argv[] ) {
 			}
 		}
 		stream.stop();
+	} catch ( const std::bad_alloc & ) {
+		std::cerr << "Error: " << std::string( "out of memory" ) << std::endl;
 	} catch ( const std::exception & e ) {
 		std::cerr << "Error: " << std::string( e.what() ? e.what() : "unknown error" ) << std::endl;
 		return 1;
diff --git a/libopenmpt/bindings/freebasic/libopenmpt.bi b/libopenmpt/bindings/freebasic/libopenmpt.bi
index f057bf4..aa9c2ae 100644
--- a/libopenmpt/bindings/freebasic/libopenmpt.bi
+++ b/libopenmpt/bindings/freebasic/libopenmpt.bi
@@ -22,6 +22,15 @@
   failure and 1 on success.
   - Functions that return integer values signal error condition by returning
   an invalid value (-1 in most cases, 0 in some cases).
+  - All functions that work on an openmpt_module object will call an
+  openmpt_error_func and depending on the value returned by this function log
+  the error code and/xor/or store it inside the openmpt_module object. Stored
+  error codes can be accessed with the openmpt_module_error_get_last() and
+  openmpt_module_error_get_last_message(). Stored errors will not get cleared
+  automatically and should be reset with openmpt_module_error_clear().
+  - Some functions not directly related to an openmpt_module object take an
+  explicit openmpt_error_func error function callback and a pointer to an int
+  and behave analog to the functions working on an openmpt_module object.
 
   \section libopenmpt_freebasic_strings Strings
 
@@ -64,7 +73,7 @@
 
   \section libopenmpt_freebasic_threads libopenmpt in multi-threaded environments
 
-  - libopenmpt is tread-aware.
+  - libopenmpt is thread-aware.
   - Individual libopenmpt objects are not thread-safe.
   - libopenmpt itself does not spawn any user-visible threads but may spawn
   threads for internal use.
@@ -82,14 +91,16 @@ Extern "C"
 
 '* API version of this header file
 Const OPENMPT_API_VERSION_MAJOR = 0
-Const OPENMPT_API_VERSION_MINOR = 2
-Const OPENMPT_API_VERSION = (OPENMPT_API_VERSION_MAJOR Shl 24) Or (OPENMPT_API_VERSION_MINOR Shl 16)
-#Define OPENMPT_API_VERSION_STRING (OPENMPT_API_VERSION_MAJOR & "." & OPENMPT_API_VERSION_MINOR)
+Const OPENMPT_API_VERSION_MINOR = 3
+Const OPENMPT_API_VERSION_PATCH = 0
+Const OPENMPT_API_VERSION = (OPENMPT_API_VERSION_MAJOR Shl 24) Or (OPENMPT_API_VERSION_MINOR Shl 16) Or (OPENMPT_API_VERSION_PATCH Shl 0)
+#Define OPENMPT_API_VERSION_STRING (OPENMPT_API_VERSION_MAJOR & "." & OPENMPT_API_VERSION_MINOR & "." & OPENMPT_API_VERSION_PATCH)
 
 /'* \brief Get the libopenmpt version number
 
   Returns the libopenmpt version number.
-  \return The value represents (major Shl 24 + minor << Shr 16 + revision).
+  \return The value represents (major Shl 24 + minor Shl 16 + patch Shl 0).
+  \remarks libopenmpt < 0.3.0-pre used the following scheme: (major Shl 24 + minor Shl 16 + revision).
   \remarks Check the HiWord of the return value against OPENMPT_API_VERSION to ensure that the correct library version is loaded.
 '/
 Declare Function openmpt_get_library_version() As ULong
@@ -127,10 +138,15 @@ Declare Sub openmpt_free_string(ByVal Str As Const ZString Ptr)
   \param key Key to query.
         Possible keys are:
          -  "library_version": verbose library version string
+         -  "library_version_is_release": "1" if the version is an officially released version                              
          -  "library_features": verbose library features string
          -  "core_version": verbose OpenMPT core version string
          -  "source_url": original source code URL
          -  "source_date": original source code date
+         -  "source_revision": original source code revision
+         -  "source_is_modified": "1" if the original source has been modified
+         -  "source_has_mixed_revisions": "1" if the original source has been compiled from different various revision
+         -  "source_is_package": "1" if the original source has been obtained from a source pacakge instead of source code version control
          -  "build": information about the current build (e.g. the build date or compiler used)
          -  "build_compiler": information about the compiler used to build libopenmpt
          -  "credits": all contributors
@@ -173,6 +189,7 @@ Const OPENMPT_STREAM_SEEK_END = 2
   \param bytes Number of bytes to read.
   \return Number of bytes actually read and written to dst.
   \retval 0 End of stream or error.
+  \remarks Short reads are allowed as long as they return at least 1 byte if EOF is not reached.
 '/
 Type openmpt_stream_read_func As Function(ByVal stream As Any Ptr, ByVal dst As Any Ptr, ByVal bytes As UInteger) As UInteger
 
@@ -185,6 +202,7 @@ Type openmpt_stream_read_func As Function(ByVal stream As Any Ptr, ByVal dst As
   \return Returns 0 on success.
   \retval 0 Success.
   \retval -1 Failure. Position does not get updated.
+  \remarks libopenmpt will not try to seek beyond the file size, thus it is not important whether you allow for virtual positioning after the file end, or return an error in that case. The position equal to the file size needs to be seekable to.
 '/
 Type openmpt_stream_seek_func As Function(ByVal stream As Any Ptr, ByVal offset As LongInt, ByVal whence As Long) As Long
 
@@ -224,7 +242,7 @@ End Type
 /'* \brief Logging function
 
   \param message UTF-8 encoded log message.
-  \param user User context that was passed to openmpt_module_create(), openmpt_module_create_from_memory() or openmpt_could_open_propability().
+  \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2().
 '/
 Type openmpt_log_func As Sub(ByVal message As Const ZString Ptr, ByVal user As Any Ptr)
 
@@ -240,19 +258,304 @@ Declare Sub openmpt_log_func_default(ByVal message As Const ZString Ptr, ByVal u
 '/
 Declare Sub openmpt_log_func_silent(ByVal message As Const ZString Ptr, ByVal user As Any Ptr)
 
+'* No error. \since 0.3.0
+Const OPENMPT_ERROR_OK = 0
+
+'* Lowest value libopenmpt will use for any of its own error codes. \since 0.3.0
+Const OPENMPT_ERROR_BASE = 256
+
+'* Unknown internal error. \since 0.3.0
+Const OPENMPT_ERROR_UNKNOWN = OPENMPT_ERROR_BASE + 1
+
+'* Unknown internal C++ exception. \since 0.3.0
+Const OPENMPT_ERROR_EXCEPTION = OPENMPT_ERROR_BASE + 11
+
+'* Out of memory. \since 0.3.0
+Const OPENMPT_ERROR_OUT_OF_MEMORY = OPENMPT_ERROR_BASE + 21
+
+'* Runtime error. \since 0.3.0
+Const OPENMPT_ERROR_RUNTIME = OPENMPT_ERROR_BASE + 30
+'* Range error. \since 0.3.0
+Const OPENMPT_ERROR_RANGE = OPENMPT_ERROR_BASE + 31
+'* Arithmetic overflow. \since 0.3.0
+Const OPENMPT_ERROR_OVERFLOW = OPENMPT_ERROR_BASE + 32
+'* Arithmetic underflow. \since 0.3.0
+Const OPENMPT_ERROR_UNDERFLOW = OPENMPT_ERROR_BASE + 33
+
+'* Logic error. \since 0.3.0
+Const OPENMPT_ERROR_LOGIC = OPENMPT_ERROR_BASE + 40
+'* Value domain error. \since 0.3.0
+Const OPENMPT_ERROR_DOMAIN = OPENMPT_ERROR_BASE + 41
+'* Maximum supported size exceeded. \since 0.3.0
+Const OPENMPT_ERROR_LENGTH = OPENMPT_ERROR_BASE + 42
+'* Argument out of range. \since 0.3.0
+Const OPENMPT_ERROR_OUT_OF_RANGE = OPENMPT_ERROR_BASE + 43
+'* Invalid argument. \since 0.3.0
+Const OPENMPT_ERROR_INVALID_ARGUMENT = OPENMPT_ERROR_BASE + 44
+
+'* General libopenmpt error. \since 0.3.0
+Const OPENMPT_ERROR_GENERAL = OPENMPT_ERROR_BASE + 101
+'* openmpt_module Ptr is invalid. \since 0.3.0
+Const OPENMPT_ERROR_INVALID_MODULE_POINTER = OPENMPT_ERROR_BASE + 102
+'* NULL pointer argument. \since 0.3.0
+Const OPENMPT_ERROR_ARGUMENT_NULL_POINTER = OPENMPT_ERROR_BASE + 103
+
+/'* \brief Check whether the error is transient
+
+  Checks whether an error code represents a transient error which may not occur again in a later try if for example memory has been freed up after an out-of-memory error.
+  \param errorcode Error code.
+  \retval 0 Error is not transient.
+  \retval 1 Error is transient.
+  \sa OPENMPT_ERROR_OUT_OF_MEMORY
+  \since 0.3.0
+'/
+Declare Function openmpt_error_is_transient(ByVal errorcode As Long) As Long
+
+/'* \brief Convert error code to text
+
+  Converts an error code into a text string describing the error.
+  \param errorcode Error code.
+  \return Allocated string describing the error.
+  \retval NULL Not enough memory to allocate the string.
+  \since 0.3.0
+  \remarks Use openmpt_error_string to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_error_string_ Alias "openmpt_error_string" (ByVal errorcode As Long) As Const ZString Ptr
+
+'* Do not log or store the error. \since 0.3.0
+Const OPENMPT_ERROR_FUNC_RESULT_NONE = 0
+'* Log the error. \since 0.3.0
+Const OPENMPT_ERROR_FUNC_RESULT_LOG = 1
+'* Store the error. \since 0.3.0
+Const OPENMPT_ERROR_FUNC_RESULT_STORE = 2
+'* Log and store the error. \since 0.3.0
+Const OPENMPT_ERROR_FUNC_RESULT_DEFAULT = OPENMPT_ERROR_FUNC_RESULT_LOG Or OPENMPT_ERROR_FUNC_RESULT_STORE
+
+/'* \brief Error function
+
+  \param errorcode Error code.
+  \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2().
+  \return Mask of OPENMPT_ERROR_FUNC_RESULT_LOG and OPENMPT_ERROR_FUNC_RESULT_STORE.
+  \retval OPENMPT_ERROR_FUNC_RESULT_NONE Do not log or store the error.
+  \retval OPENMPT_ERROR_FUNC_RESULT_LOG Log the error.
+  \retval OPENMPT_ERROR_FUNC_RESULT_STORE Store the error.
+  \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Log and store the error.
+  \sa OPENMPT_ERROR_FUNC_RESULT_NONE
+  \sa OPENMPT_ERROR_FUNC_RESULT_LOG
+  \sa OPENMPT_ERROR_FUNC_RESULT_STORE
+  \sa OPENMPT_ERROR_FUNC_RESULT_DEFAULT
+  \sa openmpt_error_func_default
+  \sa openmpt_error_func_log
+  \sa openmpt_error_func_store
+  \sa openmpt_error_func_ignore
+  \sa openmpt_error_func_errno
+  \since 0.3.0
+'/
+Type openmpt_error_func As Function(ByVal errorcode As Long, ByVal user As Any Ptr) As Long
+
+/'* \brief Default error function
+
+  Causes all errors to be logged and stored.
+  \param errorcode Error code.
+  \param user Ignored.
+  \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Always.
+  \since 0.3.0
+'/
+Declare Function openmpt_error_func_default(ByVal errorcode As Long, ByVal User As Any Ptr) As Long
+
+/'* \brief Log error function
+
+  Causes all errors to be logged.
+  \param errorcode Error code.
+  \param user Ignored.
+  \retval OPENMPT_ERROR_FUNC_RESULT_LOG Always.
+  \since 0.3.0
+'/
+Declare Function openmpt_error_func_log(ByVal errorcode As Long, ByVal user As Any Ptr) As Long
+
+/'* \brief Store error function
+
+  Causes all errors to be stored.
+  \param errorcode Error code.
+  \param user Ignored.
+  \retval OPENMPT_ERROR_FUNC_RESULT_STORE Always.
+  \since 0.3.0
+'/
+Declare Function openmpt_error_func_store(ByVal errorcode As Long, ByVal user As Any Ptr) As Long
+
+/'* \brief Ignore error function
+
+  Causes all errors to be neither logged nor stored.
+  \param errorcode Error code.
+  \param user Ignored.
+  \retval OPENMPT_ERROR_FUNC_RESULT_NONE Always.
+  \since 0.3.0
+'/
+Declare Function openmpt_error_func_ignore(ByVal errorcode As Long, ByVal user As Any Ptr) As Long
+
+/'* \brief Errno error function
+
+  Causes all errors to be stored in the pointer passed in as user.
+  \param errorcode Error code.
+  \param user Pointer to an int as generated by openmpt_error_func_errno_userdata.
+  \retval OPENMPT_ERROR_FUNC_RESULT_NONE user is not NULL.
+  \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT user is NULL.
+  \since 0.3.0
+'/
+Declare Function openmpt_error_func_errno(ByVal errorcode As Long, ByVal user As Any Ptr) As Long
+
+/'* \brief User pointer for openmpt_error_func_errno
+
+  Provides a suitable user pointer argument for openmpt_error_func_errno.
+  \param errorcode Pointer to an integer value to be used as output by openmpt_error_func_errno.
+  \retval Cast(Any Ptr, errorcode).
+  \since 0.3.0
+'/
+Declare Function openmpt_error_func_errno_userdata(ByVal errorcode As Long Ptr) As Any Ptr
+
 /'* \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it
 
   \param stream_callbacks Input stream callback operations.
   \param stream Input stream to scan.
   \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file.
-  \param logfunc Logging function where warning and errors are written.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
   \param user Logging function user context.
   \return Probability between 0.0 and 1.0.
-  \remarks openmpt_could_open_propability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
-  \remarks openmpt_could_open_propability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_propability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_propability() returned 0.5.
+  \remarks openmpt_could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
+  \remarks openmpt_could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5.
   \sa openmpt_stream_callbacks
+  \deprecated Please use openmpt_module_could_open_probability2().
+  \since 0.3.0
 '/
-Declare Function openmpt_could_open_propability(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal effort As Double, ByVal logfunc As openmpt_log_func, ByVal user As Any Ptr) As Double
+Declare Function openmpt_could_open_probability(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal effort As Double, ByVal logfunc As openmpt_log_func, ByVal user As Any Ptr) As Double
+
+/'* \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it
+
+  \param stream_callbacks Input stream callback operations.
+  \param stream Input stream to scan.
+  \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context.
+  \param errorcode Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+  \return Probability between 0.0 and 1.0.
+  \remarks openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() provide a simpler and faster interface that fits almost all use cases better. It is recommended to use openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() instead of openmpt_could_open_probability().
+  \remarks openmpt_could_open_probability2() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
+  \remarks openmpt_could_open_probability2() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5.
+  \sa openmpt_stream_callbacks
+  \sa openmpt_probe_file_header
+  \sa openmpt_probe_file_header_without_filesize
+  \since 0.3.0
+'/
+Declare Function openmpt_could_open_probability2(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal effort As Double, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal errorcode As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Double
+
+/'* \brief Get recommended header size for successfull format probing
+
+  \sa openmpt_probe_file_header()
+  \sa openmpt_probe_file_header_without_filesize()
+  \since 0.3.0
+'/
+Declare Function openmpt_probe_file_header_get_recommended_size() As UInteger
+
+'* Probe for module formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES = 1
+'* Probe for module-specific container formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS = 2
+
+'* Probe for the default set of formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT = OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES or OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS
+'* Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE = 0
+
+'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS = 1
+'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE = 0
+'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA = -1
+'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0
+Const OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR = -255
+
+/'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+
+  \param flags Ored mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT.
+  \param data Beginning of the file data.
+  \param size Size of the beginning of the file data.
+  \param filesize Full size of the file data on disk.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param error Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+  \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. 
+  \remarks openmpt_could_open_probability2() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred.
+  \sa openmpt_probe_file_header_get_recommended_size()
+  \sa openmpt_probe_file_header_without_filesize()
+  \sa openmpt_probe_file_header_from_stream()
+  \sa openmpt_could_open_probability2()
+  \since 0.3.0
+'/
+Declare Function openmpt_probe_file_header(ByVal flags As ULongInt, ByVal Data As Const Any Ptr, ByVal size As UInteger, ByVal filesize As ULongInt, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Long
+
+/'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+
+  \param flags Ored mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT.
+  \param data Beginning of the file data.
+  \param size Size of the beginning of the file data.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param error Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+  \remarks It is recommended to use openmpt_prove_file_header() and provide the acutal file's size as a parameter if at all possible. libopenmpt can provide more accurate answers if the filesize is known.
+  \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. 
+  \remarks openmpt_could_open_probability2() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred.
+  \sa openmpt_probe_file_header_get_recommended_size()
+  \sa openmpt_probe_file_header()
+  \sa openmpt_probe_file_header_from_stream()
+  \sa openmpt_could_open_probability2()
+  \since 0.3.0
+'/
+Declare Function openmpt_probe_file_header_without_filesize(ByVal flags As ULongInt, ByVal Data As Const Any Ptr, ByVal size As UInteger, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Long
+
+/'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+
+  \param flags Ored mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT.
+  \param stream_callbacks Input stream callback operations.
+  \param stream Input stream to scan.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param error Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+  \remarks The stream is left in an unspecified state when this function returns.
+  \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. 
+  \remarks openmpt_could_open_probability2() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided.
+  \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred.
+  \sa openmpt_probe_file_header_get_recommended_size()
+  \sa openmpt_probe_file_header()
+  \sa openmpt_probe_file_header_without_filesize()
+  \sa openmpt_could_open_probability2()
+  \since 0.3.0
+'/
+Declare Function openmpt_probe_file_header_from_stream(ByVal flags As ULongInt, ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr) As Long
+
 
 '* \brief Opaque type representing a libopenmpt module
 Type openmpt_module
@@ -279,6 +582,24 @@ Declare Function openmpt_module_create(ByVal stream_callbacks As openmpt_stream_
 
 /'* \brief Construct an openmpt_module
 
+  \param stream_callbacks Input stream callback operations.
+  \param stream Input stream to load the module from.
+  \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. May be NULL.
+  \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context.
+  \param errorcode Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+  \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+  \return A pointer to the constructed openmpt_module, or NULL on failure.
+  \remarks The input data can be discarded after an openmpt_module has been constructed successfully.
+  \sa openmpt_stream_callbacks
+  \since 0.3.0
+'/
+Declare Function openmpt_module_create2(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, ByVal logfunc As openmpt_log_func = 0, ByVal loguser As Any Ptr = 0, ByVal errfunc As openmpt_error_func = 0, ByVal erruser As Any Ptr = 0, ByVal errorcode As Long Ptr = 0, ByVal error_message As Const ZString Ptr Ptr = 0, ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
+
+/'* \brief Construct an openmpt_module
+
   \param filedata Data to load the module from.
   \param filesize Amount of data available.
   \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
@@ -289,12 +610,94 @@ Declare Function openmpt_module_create(ByVal stream_callbacks As openmpt_stream_
 '/
 Declare Function openmpt_module_create_from_memory(ByVal filedata As Const Any Ptr, ByVal filesize As UInteger, ByVal logfunc As openmpt_log_func = 0, ByVal user As Any Ptr = 0, ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
 
+/'* \brief Construct an openmpt_module
+
+  \param filedata Data to load the module from.
+  \param filesize Amount of data available.
+  \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
+  \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context.
+  \param errorcode Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+  \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+  \return A pointer to the constructed openmpt_module, or NULL on failure.
+  \remarks The input data can be discarded after an openmpt_module has been constructed successfully.
+  \since 0.3.0
+'/
+Declare Function openmpt_module_create_from_memory2(ByVal filedata As Const Any Ptr, ByVal filesize As UInteger, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr, ByVal errorcode As Long Ptr, ByVal error_message As Const ZString Ptr Ptr, ByVal ctls As Const openmpt_module_initial_ctl Ptr) As openmpt_module Ptr
+
 /'* \brief Unload a previously created openmpt_module from memory.
 
   \param module The module to unload.
 '/
 Declare Sub openmpt_module_destroy(ByVal module As openmpt_module Ptr)
 
+/'* \brief Set logging function.
+
+  Set the logging function of an already constructed openmpt_module.
+  \param module The module handle to work on.
+  \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
+  \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+  \since 0.3.0
+'/
+Declare Sub openmpt_module_set_log_func(ByVal module As openmpt_module Ptr, ByVal logfunc As openmpt_log_func, ByVal loguser As Any Ptr)
+
+/'* \brief Set error function.
+
+  Set the error function of an already constructed openmpt_module.
+  \param module The module handle to work on.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context.
+  \since 0.3.0
+'/
+Declare Sub openmpt_module_set_error_func(ByVal module As openmpt_module Ptr, ByVal errfunc As openmpt_error_func, ByVal erruser As Any Ptr)
+
+/'* \brief Get last error.
+
+  Return the error currently stored in an openmpt_module. The stored error is not cleared.
+  \param module The module handle to work on.
+  \return The error currently stored.
+  \sa openmpt_module_error_get_last_message
+  \sa openmpt_module_error_set_last
+  \sa openmpt_module_error_clear
+  \since 0.3.0
+'/
+Declare Function openmpt_module_error_get_last(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get last error message.
+
+  Return the error message currently stored in an openmpt_module. The stored error is not cleared.
+  \param module The module handle to work on.
+  \return The error message currently stored.
+  \sa openmpt_module_error_set_last
+  \sa openmpt_module_error_clear
+  \since 0.3.0
+  \remarks Use openmpt_module_error_get_last_message to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_error_get_last_message_ Alias "openmpt_module_error_get_last_message" (ByVal module As openmpt_module Ptr) As Const ZString Ptr
+
+/'* \brief Set last error.
+
+  Set the error currently stored in an openmpt_module.
+  \param module The module handle to work on.
+  \param errorcode Error to be stored.
+  \sa openmpt_module_error_get_last
+  \sa openmpt_module_error_clear
+  \since 0.3.0
+'/
+Declare Sub openmpt_module_error_set_last(ByVal module As openmpt_module Ptr, ByVal errorcode As Long)
+
+/'* \brief Clear last error.
+
+  Set the error currently stored in an openmpt_module to OPPENMPT_ERROR_OK.
+  \param module The module handle to work on.
+  \sa openmpt_module_error_get_last
+  \sa openmpt_module_error_set_last
+  \since 0.3.0
+'/
+Declare Sub openmpt_module_error_clear(ByVal module As openmpt_module Ptr)
+
 /'* \brief Master Gain
 
   The related value represents a relative gain in milliBel.\n
@@ -351,11 +754,20 @@ Const OPENMPT_MODULE_COMMAND_PARAMETER = 5
   \param module The module handle to work on.
   \param subsong Index of the sub-song. -1 plays all sub-songs consecutively.
   \return 1 on success, 0 on failure.
-  \sa openmpt_module_get_num_subsongs, openmpt_module_get_subsong_names
+  \sa openmpt_module_get_num_subsongs, openmpt_module_get_selected_subsong, openmpt_module_get_subsong_name
   \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt_module_select_subsong() at all.
 '/
 Declare Function openmpt_module_select_subsong(ByVal module As openmpt_module Ptr, ByVal subsong As Long) As Long
 
+/'* \brief Get currently selected sub-song from a multi-song module
+
+  \param module The module handle to work on.
+  \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index.
+  \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_subsong_name
+  \since 0.3.0
+'/
+Declare Function openmpt_module_get_selected_subsong(ByVal module As openmpt_module Ptr) As Long
+
 /'* \brief Set Repeat Count
 
   \param module The module handle to work on.
@@ -725,7 +1137,7 @@ Declare Function openmpt_module_get_current_channel_vu_rear_right(ByVal module A
 
   \param module The module handle to work on.
   \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them).
-  \sa openmpt_module_get_subsong_names, openmpt_module_select_subsong
+  \sa openmpt_module_get_subsong_name, openmpt_module_select_subsong, openmpt_module_get_selected_subsong
 '/
 Declare Function openmpt_module_get_num_subsongs(ByVal module As openmpt_module Ptr) As Long
 
@@ -770,7 +1182,7 @@ Declare Function openmpt_module_get_num_samples(ByVal module As openmpt_module P
   \param module The module handle to work on.
   \param index The sub-song whose name should be retrieved
   \return The sub-song name.
-  \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong
+  \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_selected_subsong
   \remarks Use openmpt_module_get_subsong_name to automatically handle the lifetime of the returned pointer.
 '/
 Declare Function openmpt_module_get_subsong_name_ Alias "openmpt_module_get_subsong_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr
@@ -930,6 +1342,7 @@ Declare Function openmpt_module_highlight_pattern_row_channel_ Alias "openmpt_mo
            - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong.
            - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo.
            - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch.
+           - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. 
            - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are:
                      - 0: No dithering.
                      - 1: Default mode. Chosen by OpenMPT code, might change.
@@ -954,6 +1367,7 @@ Declare Function openmpt_module_ctl_get_ Alias "openmpt_module_ctl_get" (ByVal m
   \param module The module handle to work on.
   \param ctl The ctl key whose value should be set.
   \param value The value that should be set.
+  \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized.
   \sa openmpt_module_get_ctls
 '/
 Declare Function openmpt_module_ctl_set(ByVal module As openmpt_module Ptr, ByVal ctl As Const ZString Ptr, ByVal value As Const ZString Ptr) As Long
@@ -1009,42 +1423,97 @@ End Function
 /'* \brief Construct an openmpt_module
 
   \param file The FreeBASIC file handle to load from.
-  \param logfunc Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance.
-  \param user User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context. Used to pass any user-defined data associated with this module to the error function.
+  \param errorcode Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
   \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
   \return A pointer to the constructed openmpt_module, or NULL on failure.
   \remarks The file handle can be closed after an openmpt_module has been constructed successfully.
+  \sa openmpt_module_create2
+'/
+Function openmpt_module_create_from_fbhandle2(_
+		ByVal file As Integer,_
+		ByVal logfunc As openmpt_log_func = 0,_
+		ByVal loguser As Any Ptr = 0,_
+		ByVal errfunc As openmpt_error_func = 0,_
+		ByVal erruser As Any Ptr = 0,_
+		ByVal errorcode As Long Ptr = 0,_
+		ByVal error_message As Const ZString Ptr Ptr = 0,_
+		ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
+	Return openmpt_module_create2(openmpt_stream_get_file_callbacks(), Cast(FILE Ptr, FileAttr(file, fbFileAttrHandle)), logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls)
+End Function
+
+/'* \brief Construct an openmpt_module
+
+  \param file The FreeBASIC file handle to load from.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+  \return A pointer to the constructed openmpt_module, or NULL on failure.
+  \remarks The file handle can be closed after an openmpt_module has been constructed successfully.
+  \deprecated Please use openmpt_module_create_from_fbhandle2().
+  \sa openmpt_module_create2
 '/
 Function openmpt_module_create_from_fbhandle(_
 		ByVal file As Integer,_
 		ByVal logfunc As openmpt_log_func = 0,_
-		ByVal user As Any Ptr = 0,_
+		ByVal loguser As Any Ptr = 0,_
 		ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
-	Return openmpt_module_create(openmpt_stream_get_file_callbacks(), Cast(FILE Ptr, FileAttr(file, fbFileAttrHandle)), logfunc, user, ctls)
+	Return openmpt_module_create_from_fbhandle2(file, logfunc, loguser, 0, 0, 0, 0, ctls)
 End Function
 
 /'* \brief Construct an openmpt_module
 
   \param filename The file to load from.
-  \param logfunc Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance.
-  \param user User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param errfunc Error function to define error behaviour. May be NULL.
+  \param erruser Error function user context. Used to pass any user-defined data associated with this module to the error function.
+  \param errorcode Pointer to an integer where an error may get stored. May be NULL.
+  \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
   \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
   \return A pointer to the constructed openmpt_module, or NULL on failure.
+  \sa openmpt_module_create2
 '/
-Function openmpt_module_create_from_filename(_
+Function openmpt_module_create_from_filename2(_
 		ByRef filename As String,_
 		ByVal logfunc As openmpt_log_func = 0,_
-		ByVal user As Any Ptr = 0,_
+		ByVal loguser As Any Ptr = 0,_
+		ByVal errfunc As openmpt_error_func = 0,_
+		ByVal erruser As Any Ptr = 0,_
+		ByVal errorcode As Long Ptr = 0,_
+		ByVal error_message As Const ZString Ptr Ptr = 0,_
 		ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
 	Var file = fopen(filename, "rb")
 	Var retval = CPtr(openmpt_module Ptr, 0)
 	If(file <> 0) Then
-		retval = openmpt_module_create(openmpt_stream_get_file_callbacks(), file, logfunc, user, ctls)
+		retval = openmpt_module_create2(openmpt_stream_get_file_callbacks(), file, logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls)
 		fclose(file)
 	EndIf
 	Return retval
 End Function
 
+/'* \brief Construct an openmpt_module
+
+  \param filename The file to load from.
+  \param logfunc Logging function where warning and errors are written. May be NULL.
+  \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+  \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+  \return A pointer to the constructed openmpt_module, or NULL on failure.
+  \deprecated Please use openmpt_module_create_from_filename2().
+  \sa openmpt_module_create2
+'/
+Function openmpt_module_create_from_filename(_
+		ByRef filename As String,_
+		ByVal logfunc As openmpt_log_func = 0,_
+		ByVal loguser As Any Ptr = 0,_
+		ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
+	Return openmpt_module_create_from_filename2(filename, logfunc, loguser, 0, 0, 0, 0, ctls)
+End Function
+
 '* String handling for wrapping and freeing ZStrings returned by libopenmpt
 Function openmpt_get_zstring(sz As Const ZString Ptr) As String
 	If(sz = 0) Then Return ""
@@ -1058,6 +1527,16 @@ Function openmpt_get_string(ByVal key As Const ZString Ptr) As String
 	Return openmpt_get_zstring(openmpt_get_string_(key))
 End Function
 
+'* \sa openmpt_error_string_
+Function openmpt_error_string (ByVal errorcode As Long) As String
+	Return openmpt_get_zstring(openmpt_error_string_(errorcode))
+End Function
+
+'* \sa openmpt_module_error_get_last_message_
+Function openmpt_module_error_get_last_message (ByVal module As openmpt_module Ptr) As String
+	Return openmpt_get_zstring(openmpt_module_error_get_last_message_(module))
+End Function
+
 '* \sa openmpt_module_get_metadata_keys_
 Function openmpt_module_get_metadata_keys(ByVal module As openmpt_module Ptr) As String
 	Return openmpt_get_zstring(openmpt_module_get_metadata_keys_(module))
diff --git a/libopenmpt/dox/changelog.md b/libopenmpt/dox/changelog.md
index 0d2648a..037a480 100644
--- a/libopenmpt/dox/changelog.md
+++ b/libopenmpt/dox/changelog.md
@@ -5,92 +5,151 @@ Changelog {#changelog}
 For fully detailed change log, please see the source repository directly. This
 is just a high-level summary.
 
-### libopenmpt 0.2-beta26 (2017-07-07)
-
- *  [**Bug**] Possible crashes with malformed PLM and PSM files.
- *  [**Bug**] mktime() and localtime() were used for song date parsing.
-    These functions are not guaranteed to be thread-safe by the standard.
-    Furthermore, some standard library implementations are buggy and may cause
-    the program to abort in out-of-memory situations. These functions are now no
-    longer used.
-
- *  Loops shorter than four sample points at the end of a sample could cause the
-    sample data before the loop to become corrupted.
-
-### libopenmpt 0.2-beta25 (2017-07-02)
-
- *  PT36: Enable VBlank timing as specified in file and read song comment.
- *  M15: Loosen heuristics to allow a few more semi-damaged files to play.
- *  MT2: If there were instruments with both sample and plugin assignments,
-    sample data was not read correctly.
-
-### libopenmpt 0.2-beta24 (2017-05-22)
-
+### libopenmpt 0.3.1 (2017-09-28)
+
+ *  [**Bug**] Windows: libopenmpt resource did not compile for release versions.
+
+### libopenmpt 0.3.0 (2017-09-27, not released)
+
+ *  [**New**] New error handling functionality in the C API, which in particular
+    allows distinguishing potentially transient out-of-memory errors from parse
+    errors during module loading. 
+ *  [**New**] New API `openmpt::module::get_selected_subsong()` (C++) and
+    `openmpt_module_get_selected_subsong()` (C).
+ *  [**New**] Faster file header probing API `openmpt::probe_file_header()` and
+    `openmpt::probe_file_header_get_recommended_size` (C++), and
+    `openmpt_probe_file_header()`,
+    `openmpt_probe_file_header_without_filesize()`,
+    `openmpt_probe_file_header_from_stream()` and
+    `openmpt_probe_file_header_get_recommended_size()` (C).
+ *  [**New**] New API `openmpt::could_open_probability()` (C++) and
+    `openmpt_could_open_probability()` (C). This fixes a spelling error in the
+    old 0.2 API.
+ *  [**New**] openmpt123: openmpt123 can now open M3U, M3U8, M3UEXT, M3U8EXT and
+    PLSv2 playlists via the `--playlist` option.
+ *  [**New**] openmpt123: openmpt123 now supports very fast file header probing
+    via the `--probe` option.
+ *  [**New**] Libopenmpt now supports building for Windows 10 Universal (Windows
+    Store 8.2) APIs with MSVC, and also for the older Windows Runtime APIs with
+    MinGW-w64.
+ *  [**New**] New API header `libopenmpt_ext.h` which implements the libopenmpt
+    extension APIs also for the C interface.
+ *  [**New**] The Reverb effect (S99 in S3M/IT/MPTM, and X99 in XM) is now
+    implemented in libopenmpt.
+ *  [**New**] For Amiga modules, a new resampler based on the Amiga's sound
+    characteristics has been added. It can be activated by passing the
+    `render.resampler.emulate_amiga` ctl with a value of `1`. Non-Amiga modules
+    are not affected by this, and setting the ctl overrides the resampler choice
+    specified by `OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH` or
+    `openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH`. Support for the MOD
+    command E0x (Set LED Filter) is also available when the Amiga resampler is
+    enabled. 
+
+ *  [**Change**] libopenmpt versioning changed and follows the more conventional
+    major.minor.patch as well as the recommendations of the
+    [SemVer](http://semver.org/) scheme now. In addition to the SemVer
+    requirements, pre-1.0.0 versions will also honor API and ABI stability in
+    libopenmpt (i.e. libopenmpt ignores SemVer Clause 4). 
+ *  [**Change**] The output directories of the MSVC build system were changed to
+    `bin/vs2015-shared/x86-64-win7/` (and similar) layout which allows building
+    in the same tree with different compiler versions without overwriting other
+    outputs.
+ *  [**Change**] The emscripten build now exports libopenmpt as 'libopenmpt'
+    instead of the default 'Module'.
+ *  [**Change**] Android: The build system changed. The various Android.mk files
+    have been merged into a single one which can be controlled using command
+    line options.
+ *  [**Change**] The `Makefile` build system now passes `std=c++11` to the
+    compiler by default. Older compilers may still work if you pass
+    `STDCXX=c++0x` to the `make` invocation.
+ *  [**Change**] The `Makefile` option `ANCIENT=1` is gone.
+ *  [**Change**] The optional dependencies on `libltdl` or `libdl` are gone.
+    They are no longer needed for any functionality.
+
+ *  [**Regression**] Compiling client code using the C++ API now requires a
+    compiler running in C++11 mode.
+ *  [**Regression**] Support for GCC 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7 has been
+    removed.
+ *  [**Regression**] Support for Clang 3.0, 3.1, 3.2, 3.3 has been removed.
+ *  [**Regression**] Support for Emscripten versions older than 1.31.0 has been
+    removed.
+ *  [**Regression**] Support for Android NDK versions older than 11 has been
+    removed.
+ *  [**Regression**] Visual Studio 2008, 2010, 2012, 2013 support has been
+    removed.
+ *  [**Regression**] Dynamic run-time loading of libmpg123 is no longer
+    supported. Libmpg123 must be linked at link-time now.
+ *  [**Regression**] xmp-openmpt: xmp-openmpt now requires XMPlay 3.8 or later
+    and compiling xmp-openmpt requires an appropriate XMPlay SDK with
+    `XMPIN_FACE` >= `4`.
+ *  [**Regression**] Support for libmpg123 older than 1.13.0 has been removed.
+ *  [**Regression**] Un4seen unmo3 support has been removed.
+
+ *  [**Bug**] C++ API: `openmpt::exception` did not define copy and move
+    constructors or copy and move assignment operators in libopenmpt 0.2. The
+    compiler-generated ones were not adequate though. libopenmpt 0.3 adds the
+    appropriate special member functions. This adds the respective symbol names
+    to the exported ABI, which, depending on the compiler, might or might not
+    have been there in libopenmpt 0.2. The possibly resulting possible ODR
+    violation only affects cases that did crash in the libopenmpt 0.2 API anyway
+    due to memory double-free, and does not cause any further problems in
+    practice for all known platforms and compilers.
+ *  [**Bug**] The C API could crash instead of failing gracefully in
+    out-of-memory situations.
+ *  [**Bug**] The test suite could fail on MacOSX or FreeBSD in non-fatal ways
+    when no locale was active.
+ *  [**Bug**] `libopenmpt_stream_callbacks_fd.h` and
+    `libopenmpt_stream_callbacks_file.h` were missing in Windows development
+    packages.
+ *  [**Bug**] libopenmpt on Windows did not properly guard against current
+    working directory DLL injection attacks.
  *  [**Bug**] localtime() was used to determine the version of Schism Tracker
     used to save IT and S3M files. This function is not guaranteed to be
     thread-safe by the standard and is now no longer used.
- *  [**Bug**] Compilation with GCC 4.1 was broken since 0.2-beta20.5.
-
- *  Improvements to seeking: Channel panning was not always updated from
-    instruments / samples when seeking, and out-of-range global volume was not
-    applied correctly in some formats.
- *  Work-around for reading MIDI macros and plugin settings in some malformed IT
-    files written by old UNMO3 versions.
- *  Improve tracker detection in IT format.
-
-### libopenmpt 0.2-beta23 (2017-04-23)
-
- *  [**Change**] The libmpg123 binary download script on Windows now downloads
-    libmpg123 1.24.0.
- *  [**Change**] MSVC builds of libopenmpt will now only load known DMO plugins.
-
- *  [**Bug**] foo_openmpt: Interpolation filter and volume ramping settings were
-    confused in previous versions. This version resets both to the defaults.
-
- *  Add support for "WUZAMOD!" magic bytes in STM files and allow some slightly
-    malformed STM files to load which were previously rejected (putup10.stm,
-    putup11.stm) while tightening some other heuristics.
- *  Tighten heuristics for rejecting invalid SoundTracker files.
- *  Detect whether "hidden" patterns in the order list of SoundTracker modules
-    should be taken into account or not. Fixes wolf1.mod, wolf3.mod and
-    jean_baudlot_-_bad_dudes_vs_dragonninja-dragonf.mod.
- *  MO3: Clear MIDI macros for files that were originally saved with
-    Impulse Tracker 1.0 and Scream Tracker prior to version 3.20.
-
-### libopenmpt 0.2-beta22 (2017-03-11)
-
+ *  [**Bug**] Possible crashes with malformed IT, ITP, AMS, MDL, MED, MPTM, PSM
+    and Startrekker files.
+ *  [**Bug**] Possible hangs with malformed DBM, MPTM and PSM files.
+ *  [**Bug**] Possible hangs with malformed files containing cyclic plugin
+    routings.
+ *  [**Bug**] Excessive loading times with malformed ITP / truncated AMS files.
+ *  [**Bug**] Plugins did not work correctly when changing the sample rate
+    between two render calls.
  *  [**Bug**] Possible NULL-pointer dereference read during obscure
     out-of-memory situations while handling exceptions in the C API.
  *  [**Bug**] libmodplug: `libmodplug.pc` was wrong.
  *  [**Bug**] Cross-compiling libopenmpt with autotools for Windows now properly
     sets `-municode` and `-mconsole` as well as all required Windows system
     libraries.
- *  [**Bug**] Excessive loading times with malformed ITP / truncated AMS files.
- *  [**Bug**] libopenmpt on Windows did not properly guard against current
-    working directory DLL injection attacks.
-
- *  [**Change**] The `Makefile` and Autotools build system got new options
-    `USE_DLOPEN` and `--enable-dlopen` respectively which are required to be set
-    in order to load 3rd-party libraries dynamically. Additionally, the defaults
-    for detecting libdl and libltdl now also default to off with autotools. This
-    change has been made in order to make the default configuration as secure as
-    possible. Both build systems default to dependencies that facilitate native
-    MO3 decoding internally anyway, thus there is actually no practical
-    disadvantage with the new default settings at all.
- *  [**Change**] Un4seen unmo3 support is now completely disabled by default in
-    all configurations and build systems.
-
- *  [**Regression**] In order to securely load libmpg123, the Windows binary
-    packages only support the precise libmpg123 binary that is downloaded by the
-    `download_mpg123.vbs` script. Other binaries might also work, but this has
-    neither been tested nor is officially supported from now on.
-
- *  Autotools build system now has options `--disable-openmpt123`,
-    `--disable-tests` and `--disable-examples` which may be desireable when
-    cross-compiling.
- *  Windows binary packages now include a script `download_mpg123.vbs` which
-    downloads libmpg123 and copies it to the appropriate directories relative
-    to the uncompressed binary archive.
+ *  [**Bug**] foo_openmpt: Interpolation filter and volume ramping settings were
+    confused in previous versions. This version resets both to the defaults.
+ *  [**Bug**] libmodplug: The CSoundFile::Read function in the emulated
+    libmodplug C++ API returned the wrong value, causing qmmp (and possibly
+    other software) to crash.
+
+ *  Support for SoundTracker Pro II (STP) and Digital Tracker (DTM) modules.
+ *  Increased accuracy of the sample position and sample rate to drift less when
+    playing very long samples.
+ *  Various playback improvements for IT and XM files.
+ *  Channel frequency could wrap around after some excessive portamento / down
+    in some formats since libopenmpt 0.2-beta17.
+ *  Playback improvements for S3M files made with Impulse Tracker and
+    Schism Tracker.
+ *  ParamEq plugin emulation didn't do anything at full gain (+15dB).
+ *  All standard DMO effects are now also emulated on non-Windows and non-MSVC
+    systems.
+ *  Added `libopenmpt_stream_callbacks_buffer.h` which adds
+    `openmpt_stream_callbacks` support for in-memory buffers, possibly even only
+    using a truncated prefix view into a bigger file which is useful for
+    probing.
+ *  Avoid enabling some ProTracker-specific quirks for MOD files most likely
+    created with ScreamTracker 3.
+ *  Tremolo effect only had half the intended strength in MOD files.
+ *  Pattern loops ending on the last row a pattern were not executed correctly
+    in S3M files.
+ *  Work-around for reading MIDI macros and plugin settings in some malformed IT
+    files written by old UNMO3 versions.
+ *  Improve tracker detection in IT format.
+ *  Playback fixes for 8-channel MED files
  *  Do not set note volume to 0 on out-of-range offset in XM files.
  *  Better import of some slide commands in SFX files.
  *  Sample 15 in "Crew Generation" by Necros requires short loops at the
@@ -99,74 +158,41 @@ is just a high-level summary.
     sanitization behaviour based on the module channel count.
  *  Both normal and percentage offset in PLM files were handled as percentage
     offset.
+ *  MT2 files with instruments that had both sample and plugin assignments were
+    not read correctly.
+ *  Some valid FAR files were rejected erroneously.
+ *  Support for VBlank timing flag and comment field in PT36 files.
+ *  Improved accuracy of vibrato command in DIGI / DBM files.
+ *  STM: Add support for "WUZAMOD!" magic bytes and allow some slightly
+    malformed STM files to load which were previously rejected.
+ *  Detect whether "hidden" patterns in the order list of SoundTracker modules
+    should be taken into account or not.
+ *  Tighten heuristics for rejecting invalid 669, M15, MOD and ICE files and
+    loosen them in other places to allow some valid MOD files to load.
+ *  Improvements to seeking: Channel panning was not always updated from
+    instruments / samples when seeking, and out-of-range global volume was not
+    applied correctly in some formats.
  *  seek.sync_samples=1 did not apply PTM reverse offset effect and the volume
     slide part of combined volume slide + vibrato commands.
-
-### libopenmpt 0.2-beta21 (skipped)
-
- *  Version 0.2-beta21 has been skipped in order to avoid confusion with libtool
-    version of libopenmpt 0.3.0-pre.0 and 0.3.0-pre.1 development versions.
-
-### libopenmpt 0.2-beta20.5 (2017-02-05)
-
- *  [**Bug**] libmodplug: C++ API did not build with MSVC2008 in 0.2-beta20.4.
-
-### libopenmpt 0.2-beta20.4 (2017-02-05, not released)
-
- *  [**Bug**] Possible hangs with malformed files containing cyclic plugin
-    routings.
-
- *  libmodplug: Added all missing C++ API symbols that are accessible via the
-    public libmodplug header file.
- *  Channel frequency could wrap around after some excessive portamento / down
-    in some formats since libopenmpt 0.2-beta17.
- *  Playback improvements for S3M files made with Impulse Tracker and
-    Schism Tracker.
-
-### libopenmpt 0.2-beta20.3 (2016-11-20)
-
- *  [**Bug**] Possible crashes with malformed ITP and MED files.
-
- *  Pattern loops ending on the last row a pattern were not executed correctly
-    in S3M files.
- *  Playback fixes for 8-channel MED files
- *  Tremolo on quiet notes was broken in 0.2-beta20.2.
-
-### libopenmpt 0.2-beta20.2 (2016-10-22)
-
- *  [**Bug**] The C API could crash instead of failing gracefully in
-    out-of-memory situations.
- *  [**Bug**] `libopenmpt_stream_callbacks_fd.h` and
-    `libopenmpt_stream_callbacks_file.h` were missing in Windows development
-    packages.
- *  [**Bug**] Plugins did not work correctly when changing the sample rate
-    between two render calls.
- *  [**Bug**] Possible crashes with malformed IT, AMS, MDL, MED, MPTM, PSM and
-    Startrekker files.
- *  [**Bug**] Possible hangs with malformed DBM, MPTM and PSM files.
-
- *  ParamEq plugin emulation didn't do anything at full gain (+15dB).
- *  Avoid enabling some ProTracker-specific quirks for MOD files most likely
-    created with ScreamTracker 3.
- *  Tremolo effect only had half the intended strength in MOD files.
- *  openmpt123: Improved section layout in man page.
-
-### libopenmpt 0.2-beta20.1 (2016-09-03)
-
- *  [**Bug**] The test suite could fail on MacOSX or FreeBSD in non-fatal ways
-    when no locale was active.
- *  [**Bug**] Possible crashes with malformed IT, MED, MPTM, PSM and Startrekker 
-    files.
-
+ *  If the order list was longer than 256 items and there was a pattern break
+    effect without a position jump on the last pattern of the sequence, it did
+    not jump to the correct restart order.
  *  `Makefile` has now explicit support for FreeBSD with no special option or
     configuration required.
+ *  openmpt123: Improved section layout in man page.
+ *  libmodplug: Added all missing C++ API symbols that are accessible via the
+    public libmodplug header file.
+ *  Autotools build system now has options `--disable-openmpt123`,
+    `--disable-tests` and `--disable-examples` which may be desireable when
+    cross-compiling.
+ *  Windows binary packages now ship with libmpg123 included.
 
 ### libopenmpt 0.2-beta20 (2016-08-07)
 
  *  [**Bug**] PSM loader was broken on big-endian platforms since forever.
- *  [**Bug**] load.skip_samples ctl did not work for PSM16 modules.
+ *  [**Bug**] `load.skip_samples` ctl did not work for PSM16 modules.
 
- *  There is a new `"subsong"` ctl, which can return the currently selected
+ *  There is a new `subsong` ctl, which can return the currently selected
     subsong.
  *  More accurate ProTracker arpeggio wrap-around emulation.
  *  More accurate sample tuning in PSM16 files.
diff --git a/libopenmpt/dox/dependencies.md b/libopenmpt/dox/dependencies.md
index 7042ac2..d689562 100644
--- a/libopenmpt/dox/dependencies.md
+++ b/libopenmpt/dox/dependencies.md
@@ -9,22 +9,47 @@ Dependencies
 ### libopenmpt
 
  *  Supported compilers for building libopenmpt:
-     *  **Microsoft Visual Studio 2008** or higher
-     *  **GCC 4.3** or higher (4.1 to 4.2 are partially supported)
-     *  **Clang 3.0** or higher
-     *  **MinGW-W64 4.6** or higher
-     *  **emscripten 1.21** or higher
+     *  **Microsoft Visual Studio 2015** or higher
+     *  **GCC 4.8** or higher
+     *  **Clang 3.4** or higher
+     *  **MinGW-W64 4.8** or higher
+     *  **emscripten 1.31** or higher
+     *  any other **C++11 compliant** compiler (full standard compliant mode is
+        known to work with GCC >= 5.1 and Clang >= 3.5)
+        
+        libopenmpt makes the following assumptions about the C++ implementation
+        used for building:
+         *  `CHAR_BIT == 8` (enforced by static_assert)
+         *  `sizeof(char) == 1` (enforced by static_assert)
+         *  existence of `std::uintptr_t` (enforced by static_assert)
+         *  `sizeof(float) == 4` (enforced by static_assert)
+         *  `sizeof(double) == 8` (enforced by static_assert)
+         *  if `__BYTE_ORDER__` is provided by the compiler and
+            `__STDC_IEC_559__ == 1`, the endianness of integers is the same as
+            the endianness of floats (implicitly assumed)
+         *  `wchar_t` encoding is either UTF-16 or UTF-32 (implicitly assumed)
+         *  representation of basic source character set is ASCII (implicitly
+            assumed)
+         *  representation of basic source character set is identical in char
+            and `wchar_t` (implicitly assumed)
+        
+        libopenmpt does not rely on any specific implementation defined or
+        undefined behaviour (if it does, that's a bug in libopenmpt). In
+        particular:
+         *  `char` can be `signed` or `unsigned`
+         *  shifting signed values is implementation defined
+         *  `float` and `double` can be non-IEEE754
+
  *  Required compilers to use libopenmpt:
      *  Any **C89** / **C99** / **C11** compatible compiler should work with
         the C API as long as a **C99** compatible **stdint.h** is available.
-     *  Any **C++98** / **C++03** / **C++11** / **C++14** / **C++1z** compatible
-        compiler should work with the C++ API. **C++98** and **C++03** compilers
-        require a **C99** compatible **stdint.h** to be available.
+     *  Any **C++11** / **C++14** / **C++17** compatible compiler should work
+        with the C++ API.
  *  **J2B** support requires an inflate (deflate decompression) implementation:
      *  **zlib**
      *  **miniz** can be used internally if no zlib is available.
  *  Built-in **MO3** support requires:
-     *  **libmpg123**
+     *  **libmpg123 >= 1.13.0**
      *  **libogg**
      *  **libvorbis**
      *  **libvorbisfile**
@@ -43,12 +68,12 @@ Dependencies
 
 ### openmpt123
 
- *  Supported compilers for building openmpt:
-     *  **Microsoft Visual Studio 2008** or higher
-     *  **GCC 4.3** or higher (4.1 to 4.2 are partially supported)
-     *  **Clang 3.0** or higher
-     *  **MinGW-W64 4.6** or higher
-     *  any **C++11 compliant** compiler should also work
+ *  Supported compilers for building openmpt123:
+     *  **Microsoft Visual Studio 2015** or higher
+     *  **GCC 4.8** or higher
+     *  **Clang 3.4** or higher
+     *  **MinGW-W64 4.8** or higher
+     *  any **C++11 compliant** compiler
  *  Live sound output requires one of:
      *  **PulseAudio**
      *  **SDL 2**
@@ -78,10 +103,3 @@ Optional dependencies
      *  raw PCM has no external dependencies
  *  **help2man** is required to build the documentation.
 
-
-Deprecated features
--------------------
- *  To be removed 2018-01-01: **MO3** support via libunmo3 requires:
-     *  closed-source **libunmo3** from un4seen
-     *  **libltdl** from libtool on Unix-like platforms or **libdl**
-
diff --git a/libopenmpt/dox/packaging.md b/libopenmpt/dox/packaging.md
index e302bd2..458dd38 100644
--- a/libopenmpt/dox/packaging.md
+++ b/libopenmpt/dox/packaging.md
@@ -8,6 +8,14 @@ Packaging
 
 ### Packaging recommendations for distribution package maintainers
 
+ *  libopenmpt (since 0.3) uses SemVer versioning. See
+    [semver.org](http://semver.org/). Clause 4 is ignored for libopenmpt, which
+    means that libopenmpt will also provide API/ABI compatbility semantics for
+    pre-1.0.0 versions as required by SemVer only for post-1.0.0 versions. The
+    SemVer versioning scheme is incompatible with Debian/Ubuntu package
+    versions, however it can easily be processed to be compatible by replacing
+    '-' (hyphen) with '~' (tilde). It is recommended that you use this exact
+    transformation if required.
  *  Use the autotools source package.
  *  Use the default set of dependencies required by the autotools package.
  *  Run the test suite in your build process.
diff --git a/libopenmpt/dox/quickstart.md b/libopenmpt/dox/quickstart.md
index 488e296..2b2b418 100644
--- a/libopenmpt/dox/quickstart.md
+++ b/libopenmpt/dox/quickstart.md
@@ -5,21 +5,19 @@ Quick Start {#quickstart}
 
 ### Autotools-based
 
- 1. Grab a `libopenmpt-autotools.VERSION.tar.gz` tarball.
+ 1. Grab a `libopenmpt-VERSION.autotools.tar.gz` tarball.
  2. Get dependencies:
-     -  **gcc >= 4.3** or **clang >= 3.0**
+     -  **gcc >= 4.8** or **clang >= 3.4**
      -  **pkg-config >= 0.24**
      -  **zlib**
      -  **libogg**, **libvorbis**, **libvorbisfile**
-     -  **libmpg123**
+     -  **libmpg123 >= 1.13.0**
      -  **doxygen >= 1.8**
      -  **libpulse**, **libpulse-simple** (required only by openmpt123)
      -  **portaudio-v19** (required only by openmpt123)
      -  **libFLAC** (required only by openmpt123)
      -  **libsndfile** (required only by openmpt123)
  3. *Optional*:
-     -  **libltdl**
-     -  **libdl**
      -  **libSDL >= 1.2.x** (required only by openmpt123)
  4. Run:
     
@@ -31,12 +29,12 @@ Quick Start {#quickstart}
 ### Windows
 
  1. Get dependencies:
-     -  **Microsoft Visual Studio 2010**
+     -  **Microsoft Visual Studio >= 2015**
  2. *Optionally* get dependencies:
      -  **Winamp SDK**
      -  **XMPlay SDK**
  3. Checkout `https://source.openmpt.org/svn/openmpt/trunk/OpenMPT/` .
- 4. Open `build\vs2010\openmpt123.sln` or `build\vs2010\libopenmpt.sln` or `build\vs2010\xmp-openmpt.sln` or `build\vs2010\in_openmpt.sln` or `build\vs2010\foo_openmpt.sln` in *Microsoft Visual Studio 2010*.
+ 4. Open `build\vs2015\openmpt123.sln` or `build\vs2015\libopenmpt.sln` or `build\vs2015\xmp-openmpt.sln` or `build\vs2015\in_openmpt.sln` or `build\vs2015\foo_openmpt.sln` in *Microsoft Visual Studio 2015*.
  5. Select appropriate configuration and build. Binaries are generated in `bin\`
  6. Drag a module onto `openmpt123.exe` or copy the player plugin DLLs (`in_openmpt.dll`, `xmp-openmpt.dll` or `foo_openmpt.dll`) into the respective player directory.
 
@@ -44,18 +42,16 @@ Quick Start {#quickstart}
 
  1. Get dependencies:
      -  **GNU make**
-     -  **gcc >= 4.3** or **clang >= 3.0**
+     -  **gcc >= 4.8** or **clang >= 3.4**
      -  **pkg-config**
      -  **zlib**
      -  **libogg**, **libvorbis**, **libvorbisfile**
-     -  **libmpg123**
+     -  **libmpg123 >= 1.13.0**
      -  **libpulse**, **libpulse-simple** (required only by openmpt123)
      -  **portaudio-v19** (required only by openmpt123)
      -  **libFLAC** (required only by openmpt123)
      -  **libsndfile** (required only by openmpt123)
  2. *Optional*:
-     -  **libltdl**
-     -  **libdl**
      -  **libSDL >= 1.2.x** (required only by openmpt123)
      -  **doxygen >= 1.8**
      -  **help2man**
diff --git a/libopenmpt/dox/tests.md b/libopenmpt/dox/tests.md
index 16f7138..5b1c959 100644
--- a/libopenmpt/dox/tests.md
+++ b/libopenmpt/dox/tests.md
@@ -25,7 +25,7 @@ and run
 As the build system retains no state between make invocations, you have to
 provide your make options on every make invocation.
 
-### Autotools-based build system
+#### Autotools-based build system
 
     ./configure
     make check
diff --git a/libopenmpt/libopenmpt.h b/libopenmpt/libopenmpt.h
index 8217da5..84104d7 100644
--- a/libopenmpt/libopenmpt.h
+++ b/libopenmpt/libopenmpt.h
@@ -26,6 +26,15 @@
  * failure, a NULL pointer is returned.
  * - Functions that return integer values signal error condition by returning
  * an invalid value (-1 in most cases, 0 in some cases).
+ * - All functions that work on an openmpt_module object will call an
+ * openmpt_error_func and depending on the value returned by this function log
+ * the error code and/xor/or store it inside the openmpt_module object. Stored
+ * error codes can be accessed with the openmpt_module_error_get_last() and
+ * openmpt_module_error_get_last_message(). Stored errors will not get cleared
+ * automatically and should be reset with openmpt_module_error_clear().
+ * - Some functions not directly related to an openmpt_module object take an
+ * explicit openmpt_error_func error function callback and a pointer to an int
+ * and behave analog to the functions working on an openmpt_module object.
  *
  * \section libopenmpt_c_strings Strings
  *
@@ -51,7 +60,7 @@
  * caller.
  * - openmpt_module_create() with a seekable stream will load the module via
  * callbacks to the stream interface. libopenmpt will not implement an
- * additional buffering layer in this case whih means the callbacks are assumed
+ * additional buffering layer in this case which means the callbacks are assumed
  * to be performant even with small i/o sizes.
  * - openmpt_module_create() with an unseekable stream will load the module via
  * callbacks to the stream interface. libopempt will make an internal copy as
@@ -66,7 +75,7 @@
  * | openmpt_module_create() with unseekable stream | <p style="background-color:yellow">medium</p> | <p style="background-color:red"   >high  </p> |
  *
  * In all cases, the data or stream passed to the create function is no longer
- * needed after the the openmpt_module has been created and can be freed by the
+ * needed after the openmpt_module has been created and can be freed by the
  * caller.
  *
  * \section libopenmpt_c_outputformat Output Format
@@ -93,7 +102,7 @@
  *
  * \section libopenmpt_c_threads libopenmpt in multi-threaded environments
  *
- * - libopenmpt is tread-aware.
+ * - libopenmpt is thread-aware.
  * - Individual libopenmpt objects are not thread-safe.
  * - libopenmpt itself does not spawn any user-visible threads but may spawn
  * threads for internal use.
@@ -136,7 +145,8 @@ extern "C" {
 /*! \brief Get the libopenmpt version number
  *
  * Returns the libopenmpt version number.
- * \return The value represents (major << 24 + minor << 16 + revision).
+ * \return The value represents (major << 24 + minor << 16 + patch << 0).
+ * \remarks libopenmpt < 0.3.0-pre used the following scheme: (major << 24 + minor << 16 + revision).
  */
 LIBOPENMPT_API uint32_t openmpt_get_library_version(void);
 
@@ -173,10 +183,15 @@ LIBOPENMPT_API void openmpt_free_string( const char * str );
  * \param key Key to query.
  *       Possible keys are:
  *        -  "library_version": verbose library version string
+ *        -  "library_version_is_release": "1" if the version is an officially released version
  *        -  "library_features": verbose library features string
  *        -  "core_version": verbose OpenMPT core version string
  *        -  "source_url": original source code URL
  *        -  "source_date": original source code date
+ *        -  "source_revision": original source code revision
+ *        -  "source_is_modified": "1" if the original source has been modified
+ *        -  "source_has_mixed_revisions": "1" if the original source has been compiled from different various revision
+ *        -  "source_is_package": "1" if the original source has been obtained from a source pacakge instead of source code version control
  *        -  "build": information about the current build (e.g. the build date or compiler used)
  *        -  "build_compiler": information about the compiler used to build libopenmpt
  *        -  "credits": all contributors
@@ -217,6 +232,7 @@ LIBOPENMPT_API int openmpt_is_extension_supported( const char * extension );
  * \param bytes Number of bytes to read.
  * \return Number of bytes actually read and written to dst.
  * \retval 0 End of stream or error.
+ * \remarks Short reads are allowed as long as they return at least 1 byte if EOF is not reached.
  */
 typedef size_t (*openmpt_stream_read_func)( void * stream, void * dst, size_t bytes );
 
@@ -229,6 +245,7 @@ typedef size_t (*openmpt_stream_read_func)( void * stream, void * dst, size_t by
  * \return Returns 0 on success.
  * \retval 0 Success.
  * \retval -1 Failure. Position does not get updated.
+ * \remarks libopenmpt will not try to seek beyond the file size, thus it is not important whether you allow for virtual positioning after the file end, or return an error in that case. The position equal to the file size needs to be seekable to.
  */
 typedef int (*openmpt_stream_seek_func)( void * stream, int64_t offset, int whence );
 
@@ -272,7 +289,7 @@ typedef struct openmpt_stream_callbacks {
 /*! \brief Logging function
  *
  * \param message UTF-8 encoded log message.
- * \param user User context that was passed to openmpt_module_create(), openmpt_module_create_from_memory() or openmpt_could_open_propability().
+ * \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2().
  */
 typedef void (*openmpt_log_func)( const char * message, void * user );
 
@@ -288,20 +305,320 @@ LIBOPENMPT_API void openmpt_log_func_default( const char * message, void * user
  */
 LIBOPENMPT_API void openmpt_log_func_silent( const char * message, void * user );
 
+/*! No error. \since 0.3.0 */
+#define OPENMPT_ERROR_OK                     0
+
+/*! Lowest value libopenmpt will use for any of its own error codes. \since 0.3.0 */
+#define OPENMPT_ERROR_BASE                   256
+
+/*! Unknown internal error. \since 0.3.0 */
+#define OPENMPT_ERROR_UNKNOWN                ( OPENMPT_ERROR_BASE +   1 )
+
+/*! Unknown internal C++ exception. \since 0.3.0 */
+#define OPENMPT_ERROR_EXCEPTION              ( OPENMPT_ERROR_BASE +  11 )
+
+/*! Out of memory. \since 0.3.0 */
+#define OPENMPT_ERROR_OUT_OF_MEMORY          ( OPENMPT_ERROR_BASE +  21 )
+
+/*! Runtime error. \since 0.3.0 */
+#define OPENMPT_ERROR_RUNTIME                ( OPENMPT_ERROR_BASE +  30 )
+/*! Range error. \since 0.3.0 */
+#define OPENMPT_ERROR_RANGE                  ( OPENMPT_ERROR_BASE +  31 )
+/*! Arithmetic overflow. \since 0.3.0 */
+#define OPENMPT_ERROR_OVERFLOW               ( OPENMPT_ERROR_BASE +  32 )
+/*! Arithmetic underflow. \since 0.3.0 */
+#define OPENMPT_ERROR_UNDERFLOW              ( OPENMPT_ERROR_BASE +  33 )
+
+/*! Logic error. \since 0.3.0 */
+#define OPENMPT_ERROR_LOGIC                  ( OPENMPT_ERROR_BASE +  40 )
+/*! Value domain error. \since 0.3.0 */
+#define OPENMPT_ERROR_DOMAIN                 ( OPENMPT_ERROR_BASE +  41 )
+/*! Maximum supported size exceeded. \since 0.3.0 */
+#define OPENMPT_ERROR_LENGTH                 ( OPENMPT_ERROR_BASE +  42 )
+/*! Argument out of range. \since 0.3.0 */
+#define OPENMPT_ERROR_OUT_OF_RANGE           ( OPENMPT_ERROR_BASE +  43 )
+/*! Invalid argument. \since 0.3.0 */
+#define OPENMPT_ERROR_INVALID_ARGUMENT       ( OPENMPT_ERROR_BASE +  44 )
+
+/*! General libopenmpt error. \since 0.3.0 */
+#define OPENMPT_ERROR_GENERAL                ( OPENMPT_ERROR_BASE + 101 )
+/*! openmpt_module * is invalid. \since 0.3.0 */
+#define OPENMPT_ERROR_INVALID_MODULE_POINTER ( OPENMPT_ERROR_BASE + 102 )
+/*! NULL pointer argument. \since 0.3.0 */
+#define OPENMPT_ERROR_ARGUMENT_NULL_POINTER  ( OPENMPT_ERROR_BASE + 103 )
+
+/*! \brief Check whether the error is transient
+ *
+ * Checks whether an error code represents a transient error which may not occur again in a later try if for example memory has been freed up after an out-of-memory error.
+ * \param error Error code.
+ * \retval 0 Error is not transient.
+ * \retval 1 Error is transient.
+ * \sa OPENMPT_ERROR_OUT_OF_MEMORY
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_error_is_transient( int error );
+
+/*! \brief Convert error code to text
+ *
+ * Converts an error code into a text string describing the error.
+ * \param error Error code.
+ * \return Allocated string describing the error.
+ * \retval NULL Not enough memory to allocate the string.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API const char * openmpt_error_string( int error );
+
+/*! Do not log or store the error. \since 0.3.0 */
+#define OPENMPT_ERROR_FUNC_RESULT_NONE    0
+/*! Log the error. \since 0.3.0 */
+#define OPENMPT_ERROR_FUNC_RESULT_LOG     ( 1 << 0 )
+/*! Store the error. \since 0.3.0 */
+#define OPENMPT_ERROR_FUNC_RESULT_STORE   ( 1 << 1 )
+/*! Log and store the error. \since 0.3.0 */
+#define OPENMPT_ERROR_FUNC_RESULT_DEFAULT ( OPENMPT_ERROR_FUNC_RESULT_LOG | OPENMPT_ERROR_FUNC_RESULT_STORE )
+
+/*! \brief Error function
+ *
+ * \param error Error code.
+ * \param user User context that was passed to openmpt_module_create2(), openmpt_module_create_from_memory2() or openmpt_could_open_probability2().
+ * \return Mask of OPENMPT_ERROR_FUNC_RESULT_LOG and OPENMPT_ERROR_FUNC_RESULT_STORE.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_NONE Do not log or store the error.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_LOG Log the error.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_STORE Store the error.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Log and store the error.
+ * \sa OPENMPT_ERROR_FUNC_RESULT_NONE
+ * \sa OPENMPT_ERROR_FUNC_RESULT_LOG
+ * \sa OPENMPT_ERROR_FUNC_RESULT_STORE
+ * \sa OPENMPT_ERROR_FUNC_RESULT_DEFAULT
+ * \sa openmpt_error_func_default
+ * \sa openmpt_error_func_log
+ * \sa openmpt_error_func_store
+ * \sa openmpt_error_func_ignore
+ * \sa openmpt_error_func_errno
+ * \since 0.3.0
+ */
+typedef int (*openmpt_error_func)( int error, void * user );
+
+/*! \brief Default error function
+ *
+ * Causes all errors to be logged and stored.
+ * \param error Error code.
+ * \param user Ignored.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT Always.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_error_func_default( int error, void * user );
+
+/*! \brief Log error function
+ *
+ * Causes all errors to be logged.
+ * \param error Error code.
+ * \param user Ignored.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_LOG Always.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_error_func_log( int error, void * user );
+
+/*! \brief Store error function
+ *
+ * Causes all errors to be stored.
+ * \param error Error code.
+ * \param user Ignored.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_STORE Always.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_error_func_store( int error, void * user );
+
+/*! \brief Ignore error function
+ *
+ * Causes all errors to be neither logged nor stored.
+ * \param error Error code.
+ * \param user Ignored.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_NONE Always.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_error_func_ignore( int error, void * user );
+
+/*! \brief Errno error function
+ *
+ * Causes all errors to be stored in the pointer passed in as user.
+ * \param error Error code.
+ * \param user Pointer to an int as generated by openmpt_error_func_errno_userdata.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_NONE user is not NULL.
+ * \retval OPENMPT_ERROR_FUNC_RESULT_DEFAULT user is NULL.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_error_func_errno( int error, void * user );
+
+/*! \brief User pointer for openmpt_error_func_errno
+ *
+ * Provides a suitable user pointer argument for openmpt_error_func_errno.
+ * \param error Pointer to an integer value to be used as output by openmpt_error_func_errno.
+ * \retval (void*)error.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API void * openmpt_error_func_errno_userdata( int * error );
+
 /*! \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it
  *
  * \param stream_callbacks Input stream callback operations.
  * \param stream Input stream to scan.
  * \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file.
- * \param logfunc Logging function where warning and errors are written.
- * \param user Logging function user context.
+ * \param logfunc Logging function where warning and errors are written. May be NULL.
+ * \param user Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
  * \return Probability between 0.0 and 1.0.
- * \remarks openmpt_could_open_propability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
- * \remarks openmpt_could_open_propability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_propability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_propability() returned 0.5. \include libopenmpt_example_c_probe.c
+ * \remarks openmpt_could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
+ * \remarks openmpt_could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5.
  * \sa \ref libopenmpt_c_fileio
  * \sa openmpt_stream_callbacks
+ * \deprecated Please use openmpt_module_could_open_probability2().
+ * \since 0.3.0
  */
-LIBOPENMPT_API double openmpt_could_open_propability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * user );
+LIBOPENMPT_API LIBOPENMPT_DEPRECATED double openmpt_could_open_probability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * user );
+
+/*! \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it
+ *
+ * \param stream_callbacks Input stream callback operations.
+ * \param stream Input stream to scan.
+ * \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file.
+ * \param logfunc Logging function where warning and errors are written. May be NULL.
+ * \param user Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \return Probability between 0.0 and 1.0.
+ * \remarks openmpt_could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
+ * \remarks openmpt_could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability() returned 0.5.
+ * \sa \ref libopenmpt_c_fileio
+ * \sa openmpt_stream_callbacks
+ * \deprecated Please use openmpt_module_could_open_probability2().
+ */
+LIBOPENMPT_API LIBOPENMPT_DEPRECATED double openmpt_could_open_propability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * user );
+
+/*! \brief Roughly scan the input stream to find out whether libopenmpt might be able to open it
+ *
+ * \param stream_callbacks Input stream callback operations.
+ * \param stream Input stream to scan.
+ * \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file.
+ * \param logfunc Logging function where warning and errors are written. May be NULL.
+ * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \return Probability between 0.0 and 1.0.
+ * \remarks openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() provide a simpler and faster interface that fits almost all use cases better. It is recommended to use openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize() instead of openmpt_could_open_probability().
+ * \remarks openmpt_could_open_probability2() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
+ * \remarks openmpt_could_open_probability2() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your callback functions whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt_could_open_probability2() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt_could_open_probability2() returned 0.5. \include libopenmpt_example_c_probe.c
+ * \sa \ref libopenmpt_c_fileio
+ * \sa openmpt_stream_callbacks
+ * \sa openmpt_probe_file_header
+ * \sa openmpt_probe_file_header_without_filesize
+ * \since 0.3.0
+ */
+LIBOPENMPT_API double openmpt_could_open_probability2( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message );
+
+/*! \brief Get recommended header size for successfull format probing
+ *
+ * \sa openmpt_probe_file_header()
+ * \sa openmpt_probe_file_header_without_filesize()
+ * \since 0.3.0
+ */
+LIBOPENMPT_API size_t openmpt_probe_file_header_get_recommended_size(void);
+
+/*! Probe for module formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES    0x1ul
+/*! Probe for module-specific container formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS 0x2ul
+
+/*! Probe for the default set of formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT    ( OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES | OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS )
+/*! Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE       0x0ul
+
+/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS      1
+/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE      0
+/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA (-1)
+/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */
+#define OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR        (-255)
+
+/*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+ *
+ * \param flags Ored mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT.
+ * \param data Beginning of the file data.
+ * \param size Size of the beginning of the file data.
+ * \param filesize Full size of the file data on disk.
+ * \param logfunc Logging function where warning and errors are written. May be NULL.
+ * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. 
+ * \remarks openmpt_could_open_probability2() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred.
+ * \sa openmpt_probe_file_header_get_recommended_size()
+ * \sa openmpt_probe_file_header_without_filesize()
+ * \sa openmpt_probe_file_header_from_stream()
+ * \sa openmpt_could_open_probability2()
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_probe_file_header( uint64_t flags, const void * data, size_t size, uint64_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message );
+/*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+ *
+ * \param flags Ored mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT.
+ * \param data Beginning of the file data.
+ * \param size Size of the beginning of the file data.
+ * \param logfunc Logging function where warning and errors are written. May be NULL.
+ * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \remarks It is recommended to use openmpt_prove_file_header() and provide the acutal file's size as a parameter if at all possible. libopenmpt can provide more accurate answers if the filesize is known.
+ * \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. 
+ * \remarks openmpt_could_open_probability2() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred.
+ * \sa openmpt_probe_file_header_get_recommended_size()
+ * \sa openmpt_probe_file_header()
+ * \sa openmpt_probe_file_header_from_stream()
+ * \sa openmpt_could_open_probability2()
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_probe_file_header_without_filesize( uint64_t flags, const void * data, size_t size, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message );
+
+/*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+ *
+ * \param flags Ored mask of OPENMPT_PROBE_FILE_HEADER_FLAGS_MODULES and OPENMPT_PROBE_FILE_HEADER_FLAGS_CONTAINERS, or OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT.
+ * \param stream_callbacks Input stream callback operations.
+ * \param stream Input stream to scan.
+ * \param logfunc Logging function where warning and errors are written. May be NULL.
+ * \param loguser Logging function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \remarks The stream is left in an unspecified state when this function returns.
+ * \remarks It is recommended to provide openmpt_probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. 
+ * \remarks openmpt_could_open_probability2() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt_probe_file_header() though, if possible.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS The file will most likely be supported by libopenmpt.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE The file is not supported by libopenmpt.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA An answer could not be determined with the amount of data provided.
+ * \retval OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR An internal error occurred.
+ * \sa openmpt_probe_file_header_get_recommended_size()
+ * \sa openmpt_probe_file_header()
+ * \sa openmpt_probe_file_header_without_filesize()
+ * \sa openmpt_could_open_probability2()
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_probe_file_header_from_stream( uint64_t flags, openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message );
+
 
 /*! \brief Opaque type representing a libopenmpt module
  */
@@ -316,28 +633,67 @@ typedef struct openmpt_module_initial_ctl {
  *
  * \param stream_callbacks Input stream callback operations.
  * \param stream Input stream to load the module from.
- * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
- * \param user User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. May be NULL.
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
  * \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
  * \return A pointer to the constructed openmpt_module, or NULL on failure.
  * \remarks The input data can be discarded after an openmpt_module has been constructed successfully.
  * \sa openmpt_stream_callbacks
  * \sa \ref libopenmpt_c_fileio
+ * \deprecated Please use openmpt_module_create2().
+ */
+LIBOPENMPT_API LIBOPENMPT_DEPRECATED openmpt_module * openmpt_module_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, const openmpt_module_initial_ctl * ctls );
+
+/*! \brief Construct an openmpt_module
+ *
+ * \param stream_callbacks Input stream callback operations.
+ * \param stream Input stream to load the module from.
+ * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module. May be NULL.
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+ * \return A pointer to the constructed openmpt_module, or NULL on failure.
+ * \remarks The input data can be discarded after an openmpt_module has been constructed successfully.
+ * \sa openmpt_stream_callbacks
+ * \sa \ref libopenmpt_c_fileio
+ * \since 0.3.0
+ */
+LIBOPENMPT_API openmpt_module * openmpt_module_create2( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls );
+
+/*! \brief Construct an openmpt_module
+ *
+ * \param filedata Data to load the module from.
+ * \param filesize Amount of data available.
+ * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+ * \return A pointer to the constructed openmpt_module, or NULL on failure.
+ * \remarks The input data can be discarded after an openmpt_module has been constructed successfully.
+ * \sa \ref libopenmpt_c_fileio
+ * \deprecated Please use openmpt_module_create_from_memory2().
  */
-LIBOPENMPT_API openmpt_module * openmpt_module_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * user, const openmpt_module_initial_ctl * ctls );
+LIBOPENMPT_API LIBOPENMPT_DEPRECATED openmpt_module * openmpt_module_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, const openmpt_module_initial_ctl * ctls );
 
 /*! \brief Construct an openmpt_module
  *
  * \param filedata Data to load the module from.
  * \param filesize Amount of data available.
  * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
- * \param user User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
  * \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
  * \return A pointer to the constructed openmpt_module, or NULL on failure.
  * \remarks The input data can be discarded after an openmpt_module has been constructed successfully.
  * \sa \ref libopenmpt_c_fileio
+ * \since 0.3.0
  */
-LIBOPENMPT_API openmpt_module * openmpt_module_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * user, const openmpt_module_initial_ctl * ctls );
+LIBOPENMPT_API openmpt_module * openmpt_module_create_from_memory2( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls );
 
 /*! \brief Unload a previously created openmpt_module from memory.
  *
@@ -345,6 +701,70 @@ LIBOPENMPT_API openmpt_module * openmpt_module_create_from_memory( const void *
  */
 LIBOPENMPT_API void openmpt_module_destroy( openmpt_module * mod );
 
+/*! \brief Set logging function.
+ *
+ * Set the logging function of an already constructed openmpt_module.
+ * \param mod The module handle to work on.
+ * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module.
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \since 0.3.0
+ */
+LIBOPENMPT_API void openmpt_module_set_log_func( openmpt_module * mod, openmpt_log_func logfunc, void * loguser );
+
+/*! \brief Set error function.
+ *
+ * Set the error function of an already constructed openmpt_module.
+ * \param mod The module handle to work on.
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API void openmpt_module_set_error_func( openmpt_module * mod, openmpt_error_func errfunc, void * erruser );
+
+/*! \brief Get last error.
+ *
+ * Return the error currently stored in an openmpt_module. The stored error is not cleared.
+ * \param mod The module handle to work on.
+ * \return The error currently stored.
+ * \sa openmpt_module_error_get_last_message
+ * \sa openmpt_module_error_set_last
+ * \sa openmpt_module_error_clear
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_module_error_get_last( openmpt_module * mod );
+
+/*! \brief Get last error message.
+ *
+ * Return the error message currently stored in an openmpt_module. The stored error is not cleared.
+ * \param mod The module handle to work on.
+ * \return The error message currently stored.
+ * \sa openmpt_module_error_set_last
+ * \sa openmpt_module_error_clear
+ * \since 0.3.0
+ */
+LIBOPENMPT_API const char * openmpt_module_error_get_last_message( openmpt_module * mod );
+
+/*! \brief Set last error.
+ *
+ * Set the error currently stored in an openmpt_module.
+ * \param mod The module handle to work on.
+ * \param error Error to be stored.
+ * \sa openmpt_module_error_get_last
+ * \sa openmpt_module_error_clear
+ * \since 0.3.0
+ */
+LIBOPENMPT_API void openmpt_module_error_set_last( openmpt_module * mod, int error );
+
+/*! \brief Clear last error.
+ *
+ * Set the error currently stored in an openmpt_module to OPPENMPT_ERROR_OK.
+ * \param mod The module handle to work on.
+ * \sa openmpt_module_error_get_last
+ * \sa openmpt_module_error_set_last
+ * \since 0.3.0
+ */
+LIBOPENMPT_API void openmpt_module_error_clear( openmpt_module * mod );
+
 /*! \brief Master Gain
  *
  * The related value represents a relative gain in milliBel.\n
@@ -401,10 +821,18 @@ LIBOPENMPT_API void openmpt_module_destroy( openmpt_module * mod );
  * \param mod The module handle to work on.
  * \param subsong Index of the sub-song. -1 plays all sub-songs consecutively.
  * \return 1 on success, 0 on failure.
- * \sa openmpt_module_get_num_subsongs, openmpt_module_get_subsong_names
+ * \sa openmpt_module_get_num_subsongs, openmpt_module_get_selected_subsong, openmpt_module_get_subsong_name
  * \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt_module_select_subsong() at all.
  */
 LIBOPENMPT_API int openmpt_module_select_subsong( openmpt_module * mod, int32_t subsong );
+/*! \brief Get currently selected sub-song from a multi-song module
+ *
+ * \param mod The module handle to work on.
+ * \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index.
+ * \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_subsong_name
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_selected_subsong( openmpt_module * mod );
 /*! \brief Set Repeat Count
  *
  * \param mod The module handle to work on.
@@ -750,7 +1178,7 @@ LIBOPENMPT_API float openmpt_module_get_current_channel_vu_rear_right( openmpt_m
  *
  * \param mod The module handle to work on.
  * \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them).
- * \sa openmpt_module_get_subsong_names, openmpt_module_select_subsong
+ * \sa openmpt_module_get_subsong_name, openmpt_module_select_subsong, openmpt_module_get_selected_subsong
  */
 LIBOPENMPT_API int32_t openmpt_module_get_num_subsongs( openmpt_module * mod );
 /*! \brief Get the number of pattern channels
@@ -790,7 +1218,7 @@ LIBOPENMPT_API int32_t openmpt_module_get_num_samples( openmpt_module * mod );
  * \param mod The module handle to work on.
  * \param index The sub-song whose name should be retrieved
  * \return The sub-song name.
- * \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong
+ * \sa openmpt_module_get_num_subsongs, openmpt_module_select_subsong, openmpt_module_get_selected_subsong
  */
 LIBOPENMPT_API const char * openmpt_module_get_subsong_name( openmpt_module * mod, int32_t index );
 /*! \brief Get a channel name
@@ -932,6 +1360,7 @@ LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel( openmp
  *          - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong.
  *          - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo.
  *          - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch.
+ *          - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. 
  *          - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are:
  *                    - 0: No dithering.
  *                    - 1: Default mode. Chosen by OpenMPT code, might change.
@@ -952,6 +1381,7 @@ LIBOPENMPT_API const char * openmpt_module_ctl_get( openmpt_module * mod, const
  * \param mod The module handle to work on.
  * \param ctl The ctl key whose value should be set.
  * \param value The value that should be set.
+ * \return 1 if successful, 0 in case the value is not sensible (e.g. negative tempo factor) or the ctl is not recognized.
  * \sa openmpt_module_get_ctls
  */
 LIBOPENMPT_API int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value );
diff --git a/libopenmpt/libopenmpt.hpp b/libopenmpt/libopenmpt.hpp
index 37a5f4d..e2bd8d2 100644
--- a/libopenmpt/libopenmpt.hpp
+++ b/libopenmpt/libopenmpt.hpp
@@ -19,24 +19,7 @@
 #include <string>
 #include <vector>
 
-#ifndef LIBOPENMPT_QUIRK_NO_CSTDINT
 #include <cstdint>
-#else
-#include <stdint.h>
-namespace openmpt {
-namespace std {
-typedef ::int8_t   int8_t;
-typedef ::int16_t  int16_t;
-typedef ::int32_t  int32_t;
-typedef ::int64_t  int64_t;
-typedef ::uint8_t  uint8_t; 
-typedef ::uint16_t uint16_t; 
-typedef ::uint32_t uint32_t;
-typedef ::uint64_t uint64_t;
-using namespace ::std;
-}
-}
-#endif
 
 /*!
  * \page libopenmpt_cpp_overview C++ API
@@ -112,7 +95,7 @@ using namespace ::std;
  *
  * \section libopenmpt_cpp_threads libopenmpt in multi-threaded environments
  *
- * - libopenmpt is tread-aware.
+ * - libopenmpt is thread-aware.
  * - Individual libopenmpt objects are not thread-safe.
  * - libopenmpt itself does not spawn any user-visible threads but may spawn
  * threads for internal use.
@@ -148,19 +131,36 @@ using namespace ::std;
 
 namespace openmpt {
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4275)
+#endif
+//! libopenmpt exception base class
+/*!
+  Base class used for all exceptions that are thrown by libopenmpt itself. Libopenmpt may additionally throw any exception thrown by the standard library which are all derived from std::exception.
+  \sa \ref libopenmpt_cpp_error
+*/
 class LIBOPENMPT_CXX_API exception : public std::exception {
 private:
 	char * text;
 public:
-	exception( const std::string & text ) LIBOPENMPT_NOEXCEPT;
-	virtual ~exception() LIBOPENMPT_NOEXCEPT;
-	virtual const char * what() const LIBOPENMPT_NOEXCEPT;
+	exception( const std::string & text ) noexcept;
+	exception( const exception & other ) noexcept;
+	exception( exception && other ) noexcept;
+	exception & operator = ( const exception & other ) noexcept;
+	exception & operator = ( exception && other ) noexcept;
+	virtual ~exception() noexcept;
+	virtual const char * what() const noexcept;
 }; // class exception
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
 
 //! Get the libopenmpt version number
 /*!
   Returns the libopenmpt version number.
-  \return The value represents (major << 24 + minor << 16 + revision).
+  \return The value represents (major << 24 + minor << 16 + patch << 0).
+  \remarks libopenmpt < 0.3.0-pre used the following scheme: (major << 24 + minor << 16 + revision).
 */
 LIBOPENMPT_CXX_API std::uint32_t get_library_version();
 
@@ -193,10 +193,19 @@ LIBOPENMPT_DEPRECATED static const char license          LIBOPENMPT_ATTR_DEPRECA
   \param key Key to query.
          Possible keys are:
           -  "library_version": verbose library version string
+          -  "library_version_major": libopenmpt major version number
+          -  "library_version_minor": libopenmpt minor version number
+          -  "library_version_patch": libopenmpt patch version number
+          -  "library_version_prerel": libopenmpt pre-release version string
+          -  "library_version_is_release": "1" if the version is an officially released version
           -  "library_features": verbose library features string
           -  "core_version": verbose OpenMPT core version string
           -  "source_url": original source code URL
           -  "source_date": original source code date
+          -  "source_revision": original source code revision
+          -  "source_is_modified": "1" if the original source has been modified
+          -  "source_has_mixed_revisions": "1" if the original source has been compiled from different various revision
+          -  "source_is_package": "1" if the original source has been obtained from a source pacakge instead of source code version control
           -  "build": information about the current build (e.g. the build date or compiler used)
           -  "build_compiler": information about the compiler used to build libopenmpt
           -  "credits": all contributors
@@ -231,11 +240,95 @@ LIBOPENMPT_CXX_API bool is_extension_supported( const std::string & extension );
   \param effort Effort to make when validating stream. Effort 0.0 does not even look at stream at all and effort 1.0 completely loads the file from stream. A lower effort requires less data to be loaded but only gives a rough estimate answer. Use an effort of 0.25 to only verify the header data of the module file.
   \param log Log where warning and errors are written.
   \return Probability between 0.0 and 1.0.
-  \remarks openmpt::could_open_propability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
-  \remarks openmpt::could_open_propability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your std::istream implementation whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt::could_open_propability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt::could_open_propability() returned 0.5.
+  \remarks openmpt::probe_file_header() provides a simpler and faster interface that fits almost all use cases better. It is recommended to use openmpt::probe_file_header() instead of openmpt::could_open_probability().
+  \remarks openmpt::could_open_probability() can return any value between 0.0 and 1.0. Only 0.0 and 1.0 are definitive answers, all values in between are just estimates. In general, any return value >0.0 means that you should try loading the file, and any value below 1.0 means that loading may fail. If you want a threshold above which you can be reasonably sure that libopenmpt will be able to load the file, use >=0.5. If you see the need for a threshold below which you could reasonably outright reject a file, use <0.25 (Note: Such a threshold for rejecting on the lower end is not recommended, but may be required for better integration into some other framework's probe scoring.).
+  \remarks openmpt::could_open_probability() expects the complete file data to be eventually available to it, even if it is asked to just parse the header. Verification will be unreliable (both false positives and false negatives), if you pretend that the file is just some few bytes of initial data threshold in size. In order to really just access the first bytes of a file, check in your std::istream implementation whether data or seeking is requested beyond your initial data threshold, and in that case, return an error. openmpt::could_open_probability() will treat this as any other I/O error and return 0.0. You must not expect the correct result in this case. You instead must remember that it asked for more data than you currently want to provide to it and treat this situation as if openmpt::could_open_probability() returned 0.5.
   \sa \ref libopenmpt_c_fileio
+  \sa openmpt::probe_file_header()
+  \since 0.3.0
+*/
+LIBOPENMPT_CXX_API double could_open_probability( std::istream & stream, double effort = 1.0, std::ostream & log = std::clog );
+
+//! Roughly scan the input stream to find out whether libopenmpt might be able to open it
+/*!
+  \deprecated Please use openmpt::module::could_open_probability().
+*/
+LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API LIBOPENMPT_DEPRECATED double could_open_propability( std::istream & stream, double effort = 1.0, std::ostream & log = std::clog );
+
+//! Get recommended header size for successfull format probing
+/*!
+  \sa openmpt::probe_file_header()
+  \since 0.3.0
+*/
+LIBOPENMPT_CXX_API std::size_t probe_file_header_get_recommended_size();
+
+//! Probe for module formats in openmpt::probe_file_header(). \since 0.3.0
+static const std::uint64_t probe_file_header_flags_modules    = 0x1ul;
+
+//! Probe for module-specific container formats in openmpt::probe_file_header(). \since 0.3.0
+static const std::uint64_t probe_file_header_flags_containers = 0x2ul;
+
+//! Probe for the default set of formats in openmpt::probe_file_header(). \since 0.3.0
+static const std::uint64_t probe_file_header_flags_default    = probe_file_header_flags_modules | probe_file_header_flags_containers;
+
+//! Probe for no formats in openmpt::probe_file_header(). \since 0.3.0
+static const std::uint64_t probe_file_header_flags_none       = 0x0ul;
+
+//! Possible return values for openmpt::probe_file_header(). \since 0.3.0
+enum probe_file_header_result {
+	probe_file_header_result_success      =  1,
+	probe_file_header_result_failure      =  0,
+	probe_file_header_result_wantmoredata = -1
+};
+
+//! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+/*!
+  \param flags Ored mask of openmpt::probe_file_header_flags_modules and openmpt::probe_file_header_flags_containers, or openmpt::probe_file_header_flags_default.
+  \param data Beginning of the file data.
+  \param size Size of the beginning of the file data.
+  \param filesize Full size of the file data on disk.
+  \remarks It is recommended to provide openmpt::probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size and filesize to the file's size. 
+  \remarks openmpt::could_open_probability() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible.
+  \retval probe_file_header_result_success The file will most likely be supported by libopenmpt.
+  \retval probe_file_header_result_failure The file is not supported by libopenmpt.
+  \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided.
+  \sa openmpt::probe_file_header_get_recommended_size()
+  \sa openmpt::could_open_probability()
+  \since 0.3.0
 */
-LIBOPENMPT_CXX_API double could_open_propability( std::istream & stream, double effort = 1.0, std::ostream & log = std::clog );
+LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize );
+
+//! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+/*!
+  \param flags Ored mask of openmpt::probe_file_header_flags_modules and openmpt::probe_file_header_flags_containers, or openmpt::probe_file_header_flags_default.
+  \param data Beginning of the file data.
+  \param size Size of the beginning of the file data.
+  \remarks It is recommended to use the overload of this function that also takes the filesize as parameter if at all possile. libopenmpt can provide more accurate answers if the filesize is known.
+  \remarks It is recommended to provide openmpt::probe_file_header_get_recommended_size() bytes of data for data and size. If the file is smaller, only provide the filesize amount and set size to the file's size. 
+  \remarks openmpt::could_open_probability() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible.
+  \retval probe_file_header_result_success The file will most likely be supported by libopenmpt.
+  \retval probe_file_header_result_failure The file is not supported by libopenmpt.
+  \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided.
+  \sa openmpt::probe_file_header_get_recommended_size()
+  \sa openmpt::could_open_probability()
+  \since 0.3.0
+*/
+LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size );
+
+//! Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it
+/*!
+  \param flags Ored mask of openmpt::probe_file_header_flags_modules and openmpt::probe_file_header_flags_containers, or openmpt::probe_file_header_flags_default.
+  \param stream Input stream to scan.
+  \remarks stream is left in an unspecified state when this function returns.
+  \remarks openmpt::could_open_probability() provides a more elaborate interace that might be require for special use cases. It is recommended to use openmpt::probe_file_header() though, if possible.
+  \retval probe_file_header_result_success The file will most likely be supported by libopenmpt.
+  \retval probe_file_header_result_failure The file is not supported by libopenmpt.
+  \retval probe_file_header_result_wantmoredata An answer could not be determined with the amount of data provided.
+  \sa openmpt::probe_file_header_get_recommended_size()
+  \sa openmpt::could_open_probability()
+  \since 0.3.0
+*/
+LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, std::istream & stream );
 
 class module_impl;
 
@@ -399,10 +492,17 @@ public:
 	/*!
 	  \param subsong Index of the sub-song. -1 plays all sub-songs consecutively.
 	  \throws openmpt::exception Throws an exception derived from openmpt::exception if sub-song is not in range [-1,openmpt::module::get_num_subsongs()[
-	  \sa openmpt::module::get_num_subsongs, openmpt::module::get_subsong_names
+	  \sa openmpt::module::get_num_subsongs, openmpt::module::get_selected_subsong, openmpt::module::get_subsong_names
 	  \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt::module::select_subsong() at all.
 	*/
 	void select_subsong( std::int32_t subsong );
+	//! Get currently selected sub-song from a multi-song module
+	/*!
+	  \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index.
+	  \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong, openmpt::module::get_subsong_names
+	  \since 0.3.0
+	*/
+	std::int32_t get_selected_subsong() const;
 	//! Set Repeat Count
 	/*!
 	  \param repeat_count Repeat Count
@@ -709,7 +809,7 @@ public:
 	//! Get the number of sub-songs
 	/*!
 	  \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them).
-	  \sa openmpt::module::get_subsong_names, openmpt::module::select_subsong
+	  \sa openmpt::module::get_subsong_names, openmpt::module::select_subsong, openmpt::module::get_selected_subsong
 	*/
 	std::int32_t get_num_subsongs() const;
 	//! Get the number of pattern channels
@@ -742,7 +842,7 @@ public:
 	//! Get a list of sub-song names
 	/*!
 	  \return All sub-song names.
-	  \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong
+	  \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong, openmpt::module::get_selected_subsong
 	*/
 	std::vector<std::string> get_subsong_names() const;
 	//! Get a list of channel names
@@ -868,6 +968,7 @@ public:
 	           - subsong: The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong.
 	           - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo.
 	           - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch.
+	           - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting. 
 	           - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt::module::read. Supported values are:
 	                     - 0: No dithering.
 	                     - 1: Default mode. Chosen by OpenMPT code, might change.
@@ -889,6 +990,7 @@ public:
 	/*!
 	  \param ctl The ctl key whose value should be set.
 	  \param value The value that should be set.
+	  \throws openmpt::exception Throws an exception derived from openmpt::exception in case the value is not sensible (e.g. negative tempo factor) or under the circumstances outlined in openmpt::module::get_ctls.
 	  \sa openmpt::module::get_ctls
 	*/
 	void ctl_set( const std::string & ctl, const std::string & value );
diff --git a/libopenmpt/libopenmpt_c.cpp b/libopenmpt/libopenmpt_c.cpp
index 3f82e6c..c001d3d 100644
--- a/libopenmpt/libopenmpt_c.cpp
+++ b/libopenmpt/libopenmpt_c.cpp
@@ -11,10 +11,13 @@
 
 #include "libopenmpt_internal.h"
 #include "libopenmpt.h"
+#include "libopenmpt_ext.h"
 
 #include "libopenmpt_impl.hpp"
+#include "libopenmpt_ext_impl.hpp"
 
 #include <limits>
+#include <new>
 #include <stdexcept>
 
 #include <cmath>
@@ -31,7 +34,7 @@
 namespace openmpt {
 
 static const char * strdup( const char * src ) {
-	char * dst = (char*)std::malloc( std::strlen( src ) + 1 );
+	char * dst = (char*)std::calloc( std::strlen( src ) + 1, sizeof( char ) );
 	if ( !dst ) {
 		return NULL;
 	}
@@ -59,6 +62,34 @@ public:
 	}
 }; // class logfunc_logger
 
+namespace interface {
+
+class invalid_module_pointer : public openmpt::exception {
+public:
+	invalid_module_pointer() throw()
+		: openmpt::exception("module * not valid")
+	{
+		return;
+	}
+	virtual ~invalid_module_pointer() throw() {
+		return;
+	}
+};
+
+class argument_null_pointer : public openmpt::exception {
+public:
+	argument_null_pointer() throw()
+		: openmpt::exception("argument null pointer")
+	{
+		return;
+	}
+	virtual ~argument_null_pointer() throw() {
+		return;
+	}
+};
+
+} // namespace interface
+
 static std::string format_exception( const char * const function ) {
 	std::string err;
 	try {
@@ -83,42 +114,148 @@ static std::string format_exception( const char * const function ) {
 	return err;
 }
 
+static void error_message_from_exception( const char * * error_message, const std::exception & e ) {
+	if ( error_message ) {
+		const char * what = e.what();
+		*error_message = ( what ? openmpt::strdup( what ) : openmpt::strdup( "" ) );
+	}
+}
+
+static int error_from_exception( const char * * error_message ) {
+	int error = 0;
+	if ( error_message ) {
+		if ( *error_message ) {
+			openmpt_free_string( *error_message );
+			*error_message = NULL;
+		}
+	}
+	try {
+		throw;
+
+	} catch ( const std::bad_alloc & e ) {
+		error = OPENMPT_ERROR_OUT_OF_MEMORY;
+		error_message_from_exception( error_message, e );
+
+	} catch ( const openmpt::interface::invalid_module_pointer & e ) {
+		error = OPENMPT_ERROR_INVALID_MODULE_POINTER;
+		error_message_from_exception( error_message, e );
+	} catch ( const openmpt::interface::argument_null_pointer & e ) {
+		error = OPENMPT_ERROR_ARGUMENT_NULL_POINTER;
+		error_message_from_exception( error_message, e );
+	} catch ( const openmpt::exception & e ) {
+		error = OPENMPT_ERROR_GENERAL;
+		error_message_from_exception( error_message, e );
+
+	} catch ( const std::invalid_argument & e ) {
+		error = OPENMPT_ERROR_INVALID_ARGUMENT;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::out_of_range & e ) {
+		error = OPENMPT_ERROR_OUT_OF_RANGE;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::length_error & e ) {
+		error = OPENMPT_ERROR_LENGTH;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::domain_error & e ) {
+		error = OPENMPT_ERROR_DOMAIN;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::logic_error & e ) {
+		error = OPENMPT_ERROR_LOGIC;
+		error_message_from_exception( error_message, e );
+
+	} catch ( const std::underflow_error & e ) {
+		error = OPENMPT_ERROR_UNDERFLOW;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::overflow_error & e ) {
+		error = OPENMPT_ERROR_OVERFLOW;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::range_error & e ) {
+		error = OPENMPT_ERROR_RANGE;
+		error_message_from_exception( error_message, e );
+	} catch ( const std::runtime_error & e ) {
+		error = OPENMPT_ERROR_RUNTIME;
+		error_message_from_exception( error_message, e );
+
+	} catch ( const std::exception & e ) {
+		error = OPENMPT_ERROR_EXCEPTION;
+		error_message_from_exception( error_message, e );
+
+	} catch ( ... ) {
+		error = OPENMPT_ERROR_UNKNOWN;
+
+	}
+	return error;
+}
+
 } // namespace openmpt
 
 extern "C" {
 
 struct openmpt_module {
 	openmpt_log_func logfunc;
-	void * user;
+	void * loguser;
+	openmpt_error_func errfunc;
+	void * erruser;
+	int error;
+	const char * error_message;
 	openmpt::module_impl * impl;
 };
 
+struct openmpt_module_ext {
+	openmpt_module mod;
+	openmpt::module_ext_impl * impl;
+};
+
 } // extern "C"
 
 namespace openmpt {
 
-static void do_report_exception( const char * const function, openmpt_log_func const logfunc = 0, void * const user = 0, openmpt::module_impl * const impl = 0 ) {
-	try {
-		const std::string message = format_exception( function );
-		if ( impl ) {
-			impl->PushToCSoundFileLog( message );
-		} else if ( logfunc ) {
-			logfunc( message.c_str(), user );
-		} else {
-			openmpt_log_func_default( message.c_str(), NULL );
+static void do_report_exception( const char * const function, openmpt_log_func const logfunc = 0, void * const loguser = 0, openmpt_error_func errfunc = 0, void * const erruser = 0, openmpt::module_impl * const impl = 0, openmpt_module * const mod = 0, int * const err = 0, const char * * err_msg = 0 ) {
+	int error = OPENMPT_ERROR_OK;
+	const char * error_message = NULL;
+	int error_func_result = OPENMPT_ERROR_FUNC_RESULT_DEFAULT;
+	if ( errfunc || mod || err || err_msg ) {
+		error = error_from_exception( mod ? &error_message : NULL );
+	}
+	if ( errfunc ) {
+		error_func_result = errfunc( error, erruser );
+	}
+	if ( mod && ( error_func_result & OPENMPT_ERROR_FUNC_RESULT_STORE ) ) {
+		mod->error = error;
+		mod->error_message = ( error_message ? openmpt::strdup( error_message ) : openmpt::strdup( "" ) );
+	}
+	if ( err ) {
+		*err = error;
+	}
+	if ( err_msg ) {
+		*err_msg = ( error_message ? openmpt::strdup( error_message ) : openmpt::strdup( "" ) );
+	}
+	if ( error_message ) {
+		openmpt_free_string( error_message );
+		error_message = NULL;
+	}
+	if ( error_func_result & OPENMPT_ERROR_FUNC_RESULT_LOG ) {
+		try {
+			const std::string message = format_exception( function );
+			if ( impl ) {
+				impl->PushToCSoundFileLog( message );
+			} else if ( logfunc ) {
+				logfunc( message.c_str(), loguser );
+			} else {
+				openmpt_log_func_default( message.c_str(), NULL );
+			}
+		} catch ( ... ) {
+			fprintf( stderr, "openmpt: %s:%i: UNKNOWN INTERNAL ERROR in error handling: function='%s', logfunc=%p, loguser=%p, errfunc=%p, erruser=%p, impl=%p\n", __FILE__, static_cast<int>( __LINE__ ), function ? function : "", logfunc, loguser, errfunc, erruser, impl );
+			fflush( stderr );
 		}
-	} catch ( ... ) {
-		fprintf( stderr, "openmpt: %s:%i: UNKNOWN INTERNAL ERROR in error handling: function='%s', logfunc=%p, user=%p, impl=%p\n", __FILE__, static_cast<int>( __LINE__ ), function ? function : "", logfunc, user, impl );
-		fflush( stderr );
 	}
 }
 
-static void report_exception( const char * const function, openmpt_module * mod = 0 ) {
-	do_report_exception( function, mod ? mod->logfunc : 0, mod ? mod->user : 0, mod ? mod->impl : 0 );
+static void report_exception( const char * const function, openmpt_module * mod = 0, int * error = 0, const char * * error_message = 0 ) {
+	do_report_exception( function, mod ? mod->logfunc : NULL, mod ? mod->loguser : NULL, mod ? mod->errfunc : NULL, mod ? mod->erruser : NULL, mod ? mod->impl : 0, mod ? mod : NULL, error ? error : NULL, error_message ? error_message : NULL );
 }
 
-static void report_exception( const char * const function, openmpt_log_func const logfunc, void * const user ) {
-	do_report_exception( function, logfunc, user );
+static void report_exception( const char * const function, openmpt_log_func const logfunc, void * const loguser, openmpt_error_func errfunc, void * const erruser, int * error, const char * * error_message ) {
+	do_report_exception( function, logfunc, loguser, errfunc, erruser, 0, 0, error, error_message );
 }
 
 namespace interface {
@@ -126,14 +263,14 @@ namespace interface {
 template < typename T >
 void check_soundfile( T * mod ) {
 	if ( !mod ) {
-		throw openmpt::exception("module * not valid");
+		throw openmpt::interface::invalid_module_pointer();
 	}
 }
 
 template < typename T >
 void check_pointer( T * p ) {
 	if ( !p ) {
-		throw openmpt::exception("null pointer");
+		throw openmpt::interface::argument_null_pointer();
 	}
 }
 
@@ -219,32 +356,176 @@ void openmpt_log_func_default( const char * message, void * /*user*/ ) {
 	fflush( stderr );
 }
 
-void openmpt_log_func_silent( const char * /*message*/, void * /*user*/ ) {
+void openmpt_log_func_silent( const char * /*message*/ , void * /*user*/ ) {
 	return;
 }
 
-double openmpt_could_open_propability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * user ) {
+int openmpt_error_is_transient( int error ) {
+	int result = 0;
+	switch ( error ) {
+		case OPENMPT_ERROR_OUT_OF_MEMORY:
+			result = 1;
+			break;
+		default:
+			result = 0;
+			break;
+	}
+	return result;
+}
+
+const char * openmpt_error_string( int error ) {
+	const char * text = "unkown error";
+	switch ( error ) {
+		case OPENMPT_ERROR_OK:                
+			text = "";
+			break;
+		case OPENMPT_ERROR_UNKNOWN:
+			text = "unknown internal error";
+			break;
+		case OPENMPT_ERROR_EXCEPTION:
+			text = "unknown exception ";
+			break;
+		case OPENMPT_ERROR_OUT_OF_MEMORY:
+			text = "out of memory";
+			break;
+		case OPENMPT_ERROR_RUNTIME:
+			text = "runtime error";
+			break;
+		case OPENMPT_ERROR_RANGE:
+			text = "range error";
+			break;
+		case OPENMPT_ERROR_OVERFLOW:
+			text = "arithmetic overflow";
+			break;
+		case OPENMPT_ERROR_UNDERFLOW:
+			text = "arithmetic underflow";
+			break;
+		case OPENMPT_ERROR_LOGIC:
+			text = "logic error";
+			break;
+		case OPENMPT_ERROR_DOMAIN:
+			text = "value domain error";
+			break;
+		case OPENMPT_ERROR_LENGTH:
+			text = "maximum supported size exceeded";
+			break;
+		case OPENMPT_ERROR_OUT_OF_RANGE:
+			text = "argument out of range";
+			break;
+		case OPENMPT_ERROR_INVALID_ARGUMENT:
+			text = "invalid argument";
+			break;
+		case OPENMPT_ERROR_GENERAL:
+			text = "libopenmpt error";
+			break;
+	}
+	return openmpt::strdup( text );
+}
+
+int openmpt_error_func_default( int error, void * /* user */ ) {
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_DEFAULT;
+}
+
+int openmpt_error_func_log( int error, void * /* user */ ) {
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_LOG;
+}
+
+int openmpt_error_func_store( int error, void * /* user */ ) {
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_STORE;
+}
+
+int openmpt_error_func_ignore( int error, void * /* user */ ) {
+	(void)error;
+	return OPENMPT_ERROR_FUNC_RESULT_NONE;
+}
+
+int openmpt_error_func_errno( int error, void * user ) {
+	int * e = (int *)user;
+	if ( !e ) {
+		return OPENMPT_ERROR_FUNC_RESULT_DEFAULT;
+	}
+	*e = error;
+	return OPENMPT_ERROR_FUNC_RESULT_NONE;
+}
+
+void * openmpt_error_func_errno_userdata( int * error ) {
+	return (void *)error;
+}
+
+double openmpt_could_open_probability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser ) {
+	return openmpt_could_open_probability2( stream_callbacks, stream, effort, logfunc, loguser, NULL, NULL, NULL, NULL );
+}
+double openmpt_could_open_propability( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser ) {
+	return openmpt_could_open_probability2( stream_callbacks, stream, effort, logfunc, loguser, NULL, NULL, NULL, NULL );
+}
+
+double openmpt_could_open_probability2( openmpt_stream_callbacks stream_callbacks, void * stream, double effort, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) {
 	try {
 		openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell };
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-		return openmpt::module_impl::could_open_propability( istream, effort, std::tr1::shared_ptr<openmpt::logfunc_logger>( new openmpt::logfunc_logger( logfunc ? logfunc : openmpt_log_func_default, user ) ) );
-#else
-		return openmpt::module_impl::could_open_propability( istream, effort, std::make_shared<openmpt::logfunc_logger>( logfunc ? logfunc : openmpt_log_func_default, user ) );
-#endif
+		return openmpt::module_impl::could_open_probability( istream, effort, openmpt::helper::make_unique<openmpt::logfunc_logger>( logfunc ? logfunc : openmpt_log_func_default, loguser ) );
 	} catch ( ... ) {
-		openmpt::report_exception( __FUNCTION__, logfunc, user );
+		openmpt::report_exception( __FUNCTION__, logfunc, loguser, errfunc, erruser, error, error_message );
 	}
 	return 0.0;
 }
 
+size_t openmpt_probe_file_header_get_recommended_size(void) {
+	try {
+		return openmpt::module_impl::probe_file_header_get_recommended_size();
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__ );
+	}
+	return 0;
+}
+
+int openmpt_probe_file_header( uint64_t flags, const void * data, size_t size, uint64_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) {
+	try {
+		return openmpt::module_impl::probe_file_header( flags, data, size, filesize );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, logfunc, loguser, errfunc, erruser, error, error_message );
+	}
+	return OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR;
+}
+
+int openmpt_probe_file_header_without_filesize( uint64_t flags, const void * data, size_t size, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) {
+	try {
+		return openmpt::module_impl::probe_file_header( flags, data, size );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, logfunc, loguser, errfunc, erruser, error, error_message );
+	}
+	return OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR;
+}
+
+int openmpt_probe_file_header_from_stream( uint64_t flags, openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message ) {
+	try {
+		openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell };
+		return openmpt::module_impl::probe_file_header( flags, istream );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, logfunc, loguser, errfunc, erruser, error, error_message );
+	}
+	return OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR;
+}
+
 openmpt_module * openmpt_module_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * user, const openmpt_module_initial_ctl * ctls ) {
+	return openmpt_module_create2( stream_callbacks, stream, logfunc, user, NULL, NULL, NULL, NULL, ctls );
+}
+
+openmpt_module * openmpt_module_create2( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) {
 	try {
-		openmpt_module * mod = (openmpt_module*)std::malloc( sizeof( openmpt_module ) );
+		openmpt_module * mod = (openmpt_module*)std::calloc( 1, sizeof( openmpt_module ) );
 		if ( !mod ) {
 			throw std::bad_alloc();
 		}
+		std::memset( mod, 0, sizeof( openmpt_module ) );
 		mod->logfunc = logfunc ? logfunc : openmpt_log_func_default;
-		mod->user = user;
+		mod->loguser = loguser;
+		mod->errfunc = errfunc ? errfunc : NULL;
+		mod->erruser = erruser;
+		mod->error = OPENMPT_ERROR_OK;
+		mod->error_message = NULL;
 		mod->impl = 0;
 		try {
 			std::map< std::string, std::string > ctls_map;
@@ -258,33 +539,42 @@ openmpt_module * openmpt_module_create( openmpt_stream_callbacks stream_callback
 				}
 			}
 			openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell };
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-			mod->impl = new openmpt::module_impl( istream, std::tr1::shared_ptr<openmpt::logfunc_logger>( new openmpt::logfunc_logger( mod->logfunc, mod->user ) ), ctls_map );
-#else
-			mod->impl = new openmpt::module_impl( istream, std::make_shared<openmpt::logfunc_logger>( mod->logfunc, mod->user ), ctls_map );
-#endif
+			mod->impl = new openmpt::module_impl( istream, openmpt::helper::make_unique<openmpt::logfunc_logger>( mod->logfunc, mod->loguser ), ctls_map );
 			return mod;
 		} catch ( ... ) {
-			openmpt::report_exception( __FUNCTION__, mod );
+			openmpt::report_exception( __FUNCTION__, mod, error, error_message );
 		}
 		delete mod->impl;
 		mod->impl = 0;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
 		std::free( (void*)mod );
 		mod = NULL;
 	} catch ( ... ) {
-		openmpt::report_exception( __FUNCTION__ );
+		openmpt::report_exception( __FUNCTION__, 0, error, error_message );
 	}
 	return NULL;
 }
 
 openmpt_module * openmpt_module_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * user, const openmpt_module_initial_ctl * ctls ) {
+	return openmpt_module_create_from_memory2( filedata, filesize, logfunc, user, NULL, NULL, NULL, NULL, ctls );
+}
+
+openmpt_module * openmpt_module_create_from_memory2( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) {
 	try {
-		openmpt_module * mod = (openmpt_module*)std::malloc( sizeof( openmpt_module ) );
+		openmpt_module * mod = (openmpt_module*)std::calloc( 1, sizeof( openmpt_module ) );
 		if ( !mod ) {
 			throw std::bad_alloc();
 		}
+		std::memset( mod, 0, sizeof( openmpt_module ) );
 		mod->logfunc = logfunc ? logfunc : openmpt_log_func_default;
-		mod->user = user;
+		mod->loguser = loguser;
+		mod->errfunc = errfunc ? errfunc : NULL;
+		mod->erruser = erruser;
+		mod->error = OPENMPT_ERROR_OK;
+		mod->error_message = NULL;
 		mod->impl = 0;
 		try {
 			std::map< std::string, std::string > ctls_map;
@@ -297,21 +587,21 @@ openmpt_module * openmpt_module_create_from_memory( const void * filedata, size_
 					}
 				}
 			}
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-			mod->impl = new openmpt::module_impl( filedata, filesize, std::tr1::shared_ptr<openmpt::logfunc_logger>( new openmpt::logfunc_logger( mod->logfunc, mod->user ) ), ctls_map );
-#else
-			mod->impl = new openmpt::module_impl( filedata, filesize, std::make_shared<openmpt::logfunc_logger>( mod->logfunc, mod->user ), ctls_map );
-#endif
+			mod->impl = new openmpt::module_impl( filedata, filesize, openmpt::helper::make_unique<openmpt::logfunc_logger>( mod->logfunc, mod->loguser ), ctls_map );
 			return mod;
 		} catch ( ... ) {
-			openmpt::report_exception( __FUNCTION__, mod );
+			openmpt::report_exception( __FUNCTION__, mod, error, error_message );
 		}
 		delete mod->impl;
 		mod->impl = 0;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
 		std::free( (void*)mod );
 		mod = NULL;
 	} catch ( ... ) {
-		openmpt::report_exception( __FUNCTION__ );
+		openmpt::report_exception( __FUNCTION__, 0, error, error_message );
 	}
 	return NULL;
 }
@@ -321,6 +611,10 @@ void openmpt_module_destroy( openmpt_module * mod ) {
 		openmpt::interface::check_soundfile( mod );
 		delete mod->impl;
 		mod->impl = 0;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
 		std::free( (void*)mod );
 		mod = NULL;
 		return;
@@ -330,6 +624,81 @@ void openmpt_module_destroy( openmpt_module * mod ) {
 	return;
 }
 
+void openmpt_module_set_log_func( openmpt_module * mod, openmpt_log_func logfunc, void * loguser ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		mod->logfunc = logfunc ? logfunc : openmpt_log_func_default;
+		mod->loguser = loguser;
+		return;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return;
+}
+
+void openmpt_module_set_error_func( openmpt_module * mod, openmpt_error_func errfunc, void * erruser ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		mod->errfunc = errfunc ? errfunc : NULL;
+		mod->erruser = erruser;
+		mod->error = OPENMPT_ERROR_OK;
+		return;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return;
+}
+
+int openmpt_module_error_get_last( openmpt_module * mod ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		return mod->error;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return -1;
+}
+
+const char * openmpt_module_error_get_last_message( openmpt_module * mod ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		return mod->error_message ? openmpt::strdup( mod->error_message ) : openmpt::strdup( "" );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return NULL;
+}
+
+void openmpt_module_error_set_last( openmpt_module * mod, int error ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		mod->error = error;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
+		return;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return;
+}
+
+void openmpt_module_error_clear( openmpt_module * mod ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		mod->error = OPENMPT_ERROR_OK;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
+		return;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return;
+}
+
 int openmpt_module_select_subsong( openmpt_module * mod, int32_t subsong ) {
 	try {
 		openmpt::interface::check_soundfile( mod );
@@ -341,6 +710,16 @@ int openmpt_module_select_subsong( openmpt_module * mod, int32_t subsong ) {
 	return 0;
 }
 
+int32_t openmpt_module_get_selected_subsong( openmpt_module * mod ) {
+	try {
+		openmpt::interface::check_soundfile( mod );
+		return mod->impl->get_selected_subsong();
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod );
+	}
+	return -1;
+}
+
 int openmpt_module_set_repeat_count( openmpt_module * mod, int32_t repeat_count ) {
 	try {
 		openmpt::interface::check_soundfile( mod );
@@ -912,6 +1291,376 @@ int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char *
 	return 0;
 }
 
+
+openmpt_module_ext * openmpt_module_ext_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) {
+	try {
+		openmpt_module_ext * mod_ext = (openmpt_module_ext*)std::calloc( 1, sizeof( openmpt_module_ext ) );
+		if ( !mod_ext ) {
+			throw std::bad_alloc();
+		}
+		std::memset( mod_ext, 0, sizeof( openmpt_module_ext ) );
+		openmpt_module * mod = &mod_ext->mod;
+		std::memset( mod, 0, sizeof( openmpt_module ) );
+		mod_ext->impl = 0;
+		mod->logfunc = logfunc ? logfunc : openmpt_log_func_default;
+		mod->loguser = loguser;
+		mod->errfunc = errfunc ? errfunc : NULL;
+		mod->erruser = erruser;
+		mod->error = OPENMPT_ERROR_OK;
+		mod->error_message = NULL;
+		mod->impl = 0;
+		try {
+			std::map< std::string, std::string > ctls_map;
+			if ( ctls ) {
+				for ( const openmpt_module_initial_ctl * it = ctls; it->ctl; ++it ) {
+					if ( it->value ) {
+						ctls_map[ it->ctl ] = it->value;
+					} else {
+						ctls_map.erase( it->ctl );
+					}
+				}
+			}
+			openmpt::callback_stream_wrapper istream = { stream, stream_callbacks.read, stream_callbacks.seek, stream_callbacks.tell };
+			mod_ext->impl = new openmpt::module_ext_impl( istream, openmpt::helper::make_unique<openmpt::logfunc_logger>( mod->logfunc, mod->loguser ), ctls_map );
+			mod->impl = mod_ext->impl;
+			return mod_ext;
+		} catch ( ... ) {
+			openmpt::report_exception( __FUNCTION__, mod, error, error_message );
+		}
+		delete mod_ext->impl;
+		mod_ext->impl = 0;
+		mod->impl = 0;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
+		std::free( (void*)mod_ext );
+		mod_ext = NULL;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, 0, error, error_message );
+	}
+	return NULL;
+}
+
+openmpt_module_ext * openmpt_module_ext_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls ) {
+	try {
+		openmpt_module_ext * mod_ext = (openmpt_module_ext*)std::calloc( 1, sizeof( openmpt_module_ext ) );
+		if ( !mod_ext ) {
+			throw std::bad_alloc();
+		}
+		std::memset( mod_ext, 0, sizeof( openmpt_module_ext ) );
+		openmpt_module * mod = &mod_ext->mod;
+		std::memset( mod, 0, sizeof( openmpt_module ) );
+		mod_ext->impl = 0;
+		mod->logfunc = logfunc ? logfunc : openmpt_log_func_default;
+		mod->loguser = loguser;
+		mod->errfunc = errfunc ? errfunc : NULL;
+		mod->erruser = erruser;
+		mod->error = OPENMPT_ERROR_OK;
+		mod->error_message = NULL;
+		mod->impl = 0;
+		try {
+			std::map< std::string, std::string > ctls_map;
+			if ( ctls ) {
+				for ( const openmpt_module_initial_ctl * it = ctls; it->ctl; ++it ) {
+					if ( it->value ) {
+						ctls_map[ it->ctl ] = it->value;
+					} else {
+						ctls_map.erase( it->ctl );
+					}
+				}
+			}
+			mod_ext->impl = new openmpt::module_ext_impl( filedata, filesize, openmpt::helper::make_unique<openmpt::logfunc_logger>( mod->logfunc, mod->loguser ), ctls_map );
+			mod->impl = mod_ext->impl;
+			return mod_ext;
+		} catch ( ... ) {
+			openmpt::report_exception( __FUNCTION__, mod, error, error_message );
+		}
+		delete mod_ext->impl;
+		mod_ext->impl = 0;
+		mod->impl = 0;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
+		std::free( (void*)mod_ext );
+		mod_ext = NULL;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, 0, error, error_message );
+	}
+	return NULL;
+}
+
+void openmpt_module_ext_destroy( openmpt_module_ext * mod_ext ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		openmpt_module * mod = &mod_ext->mod;
+		mod->impl = 0;
+		delete mod_ext->impl;
+		mod_ext->impl = 0;
+		if ( mod->error_message ) {
+			openmpt_free_string( mod->error_message );
+			mod->error_message = NULL;
+		}
+		std::free( (void*)mod_ext );
+		mod_ext = NULL;
+		return;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return;
+}
+
+openmpt_module * openmpt_module_ext_get_module( openmpt_module_ext * mod_ext ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		openmpt_module * mod = &mod_ext->mod;
+		return mod;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return NULL;
+}
+
+
+
+static int get_pattern_row_channel_volume_effect_type( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_pattern_row_channel_volume_effect_type( pattern, row, channel );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return -1;
+}
+static int get_pattern_row_channel_effect_type( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_pattern_row_channel_effect_type( pattern, row, channel );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return -1;
+}
+
+
+
+int set_current_speed( openmpt_module_ext * mod_ext, int32_t speed ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_current_speed( speed );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+int set_current_tempo( openmpt_module_ext * mod_ext, int32_t tempo ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_current_tempo( tempo );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+int set_tempo_factor( openmpt_module_ext * mod_ext, double factor ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_tempo_factor( factor );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+double get_tempo_factor( openmpt_module_ext * mod_ext ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_tempo_factor();
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0.0;
+}
+int set_pitch_factor( openmpt_module_ext * mod_ext, double factor ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_pitch_factor( factor );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+double get_pitch_factor( openmpt_module_ext * mod_ext ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_pitch_factor();
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0.0;
+}
+int set_global_volume( openmpt_module_ext * mod_ext, double volume ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_global_volume( volume );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+double get_global_volume( openmpt_module_ext * mod_ext ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_global_volume();
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0.0;
+}
+int set_channel_volume( openmpt_module_ext * mod_ext, int32_t channel, double volume ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_channel_volume( channel, volume );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+double get_channel_volume( openmpt_module_ext * mod_ext, int32_t channel ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_channel_volume( channel );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0.0;
+}
+int set_channel_mute_status( openmpt_module_ext * mod_ext, int32_t channel, int mute ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_channel_mute_status( channel, mute ? true : false );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+int get_channel_mute_status( openmpt_module_ext * mod_ext, int32_t channel ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_channel_mute_status( channel ) ? 1 : 0;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return -1;
+}
+int set_instrument_mute_status( openmpt_module_ext * mod_ext, int32_t instrument, int mute ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->set_instrument_mute_status( instrument, mute ? true : false );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+int get_instrument_mute_status( openmpt_module_ext * mod_ext, int32_t instrument ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->get_instrument_mute_status( instrument ) ? 1 : 0;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return -1;
+}
+int32_t play_note( openmpt_module_ext * mod_ext, int32_t instrument, int32_t note, double volume, double panning ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		return mod_ext->impl->play_note( instrument, note, volume, panning );
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return -1;
+}
+int stop_note( openmpt_module_ext * mod_ext, int32_t channel ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		mod_ext->impl->stop_note( channel );
+		return 1;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+
+
+
+/* add stuff here */
+
+
+
+int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * interface_id, void * interface, size_t interface_size ) {
+	try {
+		openmpt::interface::check_soundfile( mod_ext );
+		openmpt::interface::check_pointer( interface_id );
+		openmpt::interface::check_pointer( interface );
+		std::memset( interface, 0, interface_size );
+		int result = 0;
+		if ( !strcmp( interface_id, "" ) ) {
+			result = 0;
+
+
+
+		} else if ( !strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS ) && ( interface_size == sizeof( openmpt_module_ext_interface_pattern_vis ) ) ) {
+			openmpt_module_ext_interface_pattern_vis * i = static_cast< openmpt_module_ext_interface_pattern_vis * >( interface );
+			i->get_pattern_row_channel_volume_effect_type = &get_pattern_row_channel_volume_effect_type;
+			i->get_pattern_row_channel_effect_type = &get_pattern_row_channel_effect_type;
+			result = 1;
+
+
+
+		} else if ( !strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive ) ) ) {
+			openmpt_module_ext_interface_interactive * i = static_cast< openmpt_module_ext_interface_interactive * >( interface );
+			i->set_current_speed = &set_current_speed;
+			i->set_current_tempo = &set_current_tempo;
+			i->set_tempo_factor = &set_tempo_factor;
+			i->get_tempo_factor = &get_tempo_factor;
+			i->set_pitch_factor = &set_pitch_factor;
+			i->get_pitch_factor = &get_pitch_factor;
+			i->set_global_volume = &set_global_volume;
+			i->get_global_volume = &get_global_volume;
+			i->set_channel_volume = &set_channel_volume;
+			i->get_channel_volume = &get_channel_volume;
+			i->set_channel_mute_status = &set_channel_mute_status;
+			i->get_channel_mute_status = &get_channel_mute_status;
+			i->set_instrument_mute_status = &set_instrument_mute_status;
+			i->get_instrument_mute_status = &get_instrument_mute_status;
+			i->play_note = &play_note;
+			i->stop_note = &stop_note;
+			result = 1;
+
+
+
+/* add stuff here */
+
+
+
+		} else {
+			result = 0;
+		}
+		return result;
+	} catch ( ... ) {
+		openmpt::report_exception( __FUNCTION__, mod_ext ? &mod_ext->mod : NULL );
+	}
+	return 0;
+}
+
 } // extern "C"
 
 #endif // NO_LIBOPENMPT_C
diff --git a/libopenmpt/libopenmpt_config.h b/libopenmpt/libopenmpt_config.h
index e379e37..9d1a3c9 100644
--- a/libopenmpt/libopenmpt_config.h
+++ b/libopenmpt/libopenmpt_config.h
@@ -22,6 +22,35 @@
 #define LIBOPENMPT_CXX_API
 #undef LIBOPENMPT_CXX_API
 
+/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_buffer.h exists. */
+#define LIBOPENMPT_STREAM_CALLBACKS_BUFFER
+
+/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_fd.h exists.
+ * \since 0.3
+ * \remarks
+ *   Use the following to check for availability:
+ *   \code
+ *   #include <libopenmpt/libopenmpt.h>
+ *   #if defined(LIBOPENMPT_STREAM_CALLBACKS_FD) || ((OPENMPT_API_VERSION_MAJOR == 0) && ((OPENMPT_API_VERSION_MINOR == 2) || (OPENMPT_API_VERSION_MINOR == 1)))
+ *   #include <libopenmpt/libopenmpt_stream_callbacks_fd.h>
+ *   #endif
+ *   \endcode
+ */
+#define LIBOPENMPT_STREAM_CALLBACKS_FD
+
+/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file.h exists.
+ * \since 0.3
+ * \remarks
+ *   Use the following to check for availability:
+ *   \code
+ *   #include <libopenmpt/libopenmpt.h>
+ *   #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE) || ((OPENMPT_API_VERSION_MAJOR == 0) && ((OPENMPT_API_VERSION_MINOR == 2) || (OPENMPT_API_VERSION_MINOR == 1))
+ *   #include <libopenmpt/libopenmpt_stream_callbacks_file.h>
+ *   #endif
+ *   \endcode
+ */
+#define LIBOPENMPT_STREAM_CALLBACKS_FILE
+
 #if defined(__DOXYGEN__)
 
 #define LIBOPENMPT_API_HELPER_EXPORT
@@ -135,52 +164,14 @@ LIBOPENMPT_DEPRECATED static const int LIBOPENMPT_DEPRECATED_STRING_CONSTANT = 0
 
 #ifdef __cplusplus
 
-#ifndef LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT
-/* handle known broken compilers here by defining LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT appropriately */
-/* Note: We force the known compilers to C++11 here in order to retain compatibility with libopenmpt <= 0.2.661-beta18. */
-#if defined(__clang__)
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT 201103L
-#elif defined(_MSC_VER)
-#if (_MSC_VER >= 1600)
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT 201103L
-#else
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT 199711L
-#endif
-#elif defined(__GNUC__)
-#if (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1 < 40300)
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT 199711L
-#else
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT 201103L
-#endif
-#endif
-#endif
-
 #ifndef LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED
 /* handle known broken compilers here by defining LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED appropriately */
 #endif
 
-#ifndef LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT
-/* handle known broken compilers here by defining LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT appropriately */
-#endif
-
 #if defined(LIBOPENMPT_ASSUME_CPLUSPLUS)
-#ifndef LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT LIBOPENMPT_ASSUME_CPLUSPLUS
-#endif
 #ifndef LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED
 #define LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED LIBOPENMPT_ASSUME_CPLUSPLUS
 #endif
-#ifndef LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT
-#define LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT LIBOPENMPT_ASSUME_CPLUSPLUS
-#endif
-#endif
-
-#if defined(LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT)
-#if (LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT < 201103L)
-#define LIBOPENMPT_QUIRK_NO_CSTDINT
-#endif
-#elif (__cplusplus < 201103L)
-#define LIBOPENMPT_QUIRK_NO_CSTDINT
 #endif
 
 #if !defined(LIBOPENMPT_NO_DEPRECATE)
@@ -205,18 +196,6 @@ LIBOPENMPT_DEPRECATED static const int LIBOPENMPT_DEPRECATED_STRING_CONSTANT = 0
 #define LIBOPENMPT_ATTR_DEPRECATED
 #endif
 
-#if defined(LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT)
-#if (LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT >= 201103L)
-#define LIBOPENMPT_NOEXCEPT noexcept
-#else
-#define LIBOPENMPT_NOEXCEPT throw()
-#endif
-#elif (__cplusplus >= 201103L)
-#define LIBOPENMPT_NOEXCEPT noexcept
-#else
-#define LIBOPENMPT_NOEXCEPT throw()
-#endif
-
 #endif
 
 
diff --git a/libopenmpt/libopenmpt_cxx.cpp b/libopenmpt/libopenmpt_cxx.cpp
index 1d2a25f..a6ad8a7 100644
--- a/libopenmpt/libopenmpt_cxx.cpp
+++ b/libopenmpt/libopenmpt_cxx.cpp
@@ -11,17 +11,20 @@
 
 #include "libopenmpt_internal.h"
 #include "libopenmpt.hpp"
+#include "libopenmpt_ext.hpp"
 
 #include "libopenmpt_impl.hpp"
+#include "libopenmpt_ext_impl.hpp"
 
 #include <algorithm>
+#include <stdexcept>
 
 #include <cstdlib>
 #include <cstring>
 
 namespace openmpt {
 
-exception::exception( const std::string & text_ ) LIBOPENMPT_NOEXCEPT
+exception::exception( const std::string & text_ ) noexcept
 	: std::exception()
 	, text(0)
 {
@@ -31,18 +34,66 @@ exception::exception( const std::string & text_ ) LIBOPENMPT_NOEXCEPT
 	}
 }
 
-exception::~exception() LIBOPENMPT_NOEXCEPT {
+exception::exception( const exception & other ) noexcept
+	: std::exception()
+	, text(0)
+{
+	const char * const text_ = ( other.what() ? other.what() : "" );
+	text = static_cast<char*>( std::malloc( std::strlen( text_ ) + 1 ) );
+	if ( text ) {
+		std::memcpy( text, text_, std::strlen( text_ ) + 1 );
+	}
+}
+
+exception::exception( exception && other ) noexcept
+	: std::exception()
+	, text(0)
+{
+	text = std::move( other.text );
+	other.text = 0;
+}
+
+exception & exception::operator = ( const exception & other ) noexcept {
+	if ( this == &other ) {
+		return *this;
+	}
+	if ( text ) {
+		std::free( text );
+		text = 0;
+	}
+	const char * const text_ = ( other.what() ? other.what() : "" );
+	text = static_cast<char*>( std::malloc( std::strlen( text_ ) + 1 ) );
+	if ( text ) {
+		std::memcpy( text, text_, std::strlen( text_ ) + 1 );
+	}
+	return *this;
+}
+
+exception & exception::operator = ( exception && other ) noexcept {
+	if ( this == &other ) {
+		return *this;
+	}
+	if ( text ) {
+		std::free( text );
+		text = 0;
+	}
+	text = std::move( other.text );
+	other.text = 0;
+	return *this;
+}
+
+exception::~exception() noexcept {
 	if ( text ) {
 		std::free( text );
 		text = 0;
 	}
 }
 
-const char * exception::what() const LIBOPENMPT_NOEXCEPT {
+const char * exception::what() const noexcept {
 	if ( text ) {
 		return text;
 	} else {
-		return "unknown openmpt exception";
+		return "out of memory";
 	}
 }
 
@@ -76,13 +127,30 @@ bool is_extension_supported( const std::string & extension ) {
 	return openmpt::module_impl::is_extension_supported( extension );
 }
 
+double could_open_probability( std::istream & stream, double effort, std::ostream & log ) {
+	return openmpt::module_impl::could_open_probability( stream, effort, openmpt::helper::make_unique<std_ostream_log>( log ) );
+}
 double could_open_propability( std::istream & stream, double effort, std::ostream & log ) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	return openmpt::module_impl::could_open_propability( stream, effort, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ) );
-#else
-	return openmpt::module_impl::could_open_propability( stream, effort, std::make_shared<std_ostream_log>( log ) );
-#endif
+	return openmpt::module_impl::could_open_probability( stream, effort, openmpt::helper::make_unique<std_ostream_log>( log ) );
+}
+
+std::size_t probe_file_header_get_recommended_size() {
+	return openmpt::module_impl::probe_file_header_get_recommended_size();
+}
+int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize ) {
+	return openmpt::module_impl::probe_file_header( flags, data, size, filesize );
+}
+int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size ) {
+	return openmpt::module_impl::probe_file_header( flags, data, size );
 }
+int probe_file_header( std::uint64_t flags, std::istream & stream ) {
+	return openmpt::module_impl::probe_file_header( flags, stream );
+}
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4702) // unreachable code
+#endif // _MSC_VER
 
 module::module( const module & ) {
 	throw exception("openmpt::module is non-copyable");
@@ -92,6 +160,10 @@ void module::operator = ( const module & ) {
 	throw exception("openmpt::module is non-copyable");
 }
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif // _MSC_VER
+
 module::module() : impl(0) {
 	return;
 }
@@ -101,67 +173,35 @@ void module::set_impl( module_impl * i ) {
 }
 
 module::module( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( stream, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( stream, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( stream, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const std::vector<std::uint8_t> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( data, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( data, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( data, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const std::uint8_t * beg, const std::uint8_t * end, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( beg, end - beg, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( beg, end - beg, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( beg, end - beg, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const std::uint8_t * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( data, size, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( data, size, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( data, size, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const std::vector<char> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( data, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( data, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( data, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const char * beg, const char * end, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( beg, end - beg, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( beg, end - beg, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( beg, end - beg, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( data, size, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( data, size, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( data, size, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::module( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	impl = new module_impl( data, size, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls );
-#else
-	impl = new module_impl( data, size, std::make_shared<std_ostream_log>( log ), ctls );
-#endif
+	impl = new module_impl( data, size, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
 }
 
 module::~module() {
@@ -172,6 +212,9 @@ module::~module() {
 void module::select_subsong( std::int32_t subsong ) {
 	impl->select_subsong( subsong );
 }
+std::int32_t module::get_selected_subsong() const {
+	return impl->get_selected_subsong();
+}
 
 void module::set_repeat_count( std::int32_t repeat_count ) {
 	impl->set_repeat_count( repeat_count );
@@ -348,6 +391,46 @@ void module::ctl_set( const std::string & ctl, const std::string & value ) {
 	impl->ctl_set( ctl, value );
 }
 
+module_ext::module_ext( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
+	ext_impl = new module_ext_impl( stream, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+	set_impl( ext_impl );
+}
+module_ext::module_ext( const std::vector<char> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
+	ext_impl = new module_ext_impl( data, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+	set_impl( ext_impl );
+}
+module_ext::module_ext( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
+	ext_impl = new module_ext_impl( data, size, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+	set_impl( ext_impl );
+}
+module_ext::module_ext( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
+	ext_impl = new module_ext_impl( data, size, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+	set_impl( ext_impl );
+}
+module_ext::~module_ext() {
+	set_impl( 0 );
+	delete ext_impl;
+	ext_impl = 0;
+}
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4702) // unreachable code
+#endif // _MSC_VER
+module_ext::module_ext( const module_ext & other ) : module(other) {
+	throw std::runtime_error("openmpt::module_ext is non-copyable");
+}
+void module_ext::operator = ( const module_ext & ) {
+	throw std::runtime_error("openmpt::module_ext is non-copyable");
+}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif // _MSC_VER
+
+void * module_ext::get_interface( const std::string & interface_id ) {
+	return ext_impl->get_interface( interface_id );
+}
+
 } // namespace openmpt
 
 #endif // NO_LIBOPENMPT_CXX
diff --git a/libopenmpt/libopenmpt_ext.h b/libopenmpt/libopenmpt_ext.h
new file mode 100644
index 0000000..62df271
--- /dev/null
+++ b/libopenmpt/libopenmpt_ext.h
@@ -0,0 +1,297 @@
+/*
+ * libopenmpt_ext.h
+ * ----------------
+ * Purpose: libopenmpt public c interface for libopenmpt extensions
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_EXT_H
+#define LIBOPENMPT_EXT_H
+
+#include "libopenmpt_config.h"
+#include "libopenmpt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! \brief Opaque type representing a libopenmpt extension module
+ */
+typedef struct openmpt_module_ext openmpt_module_ext;
+
+/*! \brief Construct an openmpt_module_ext
+ *
+ * \param stream_callbacks Input stream callback operations.
+ * \param stream Input stream to load the module from.
+ * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module_ext. May be NULL.
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+ * \return A pointer to the constructed openmpt_module_ext, or NULL on failure.
+ * \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully.
+ * \sa openmpt_stream_callbacks
+ * \sa \ref libopenmpt_c_fileio
+ * \since 0.3.0
+ */
+LIBOPENMPT_API openmpt_module_ext * openmpt_module_ext_create( openmpt_stream_callbacks stream_callbacks, void * stream, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls );
+
+/*! \brief Construct an openmpt_module_ext
+ *
+ * \param filedata Data to load the module from.
+ * \param filesize Amount of data available.
+ * \param logfunc Logging function where warning and errors are written. The logging function may be called throughout the lifetime of openmpt_module_ext.
+ * \param loguser User-defined data associated with this module. This value will be passed to the logging callback function (logfunc)
+ * \param errfunc Error function to define error behaviour. May be NULL.
+ * \param erruser Error function user context. Used to pass any user-defined data associated with this module to the logging function.
+ * \param error Pointer to an integer where an error may get stored. May be NULL.
+ * \param error_message Pointer to a string pointer where an error message may get stored. May be NULL.
+ * \param ctls A map of initial ctl values, see openmpt_module_get_ctls.
+ * \return A pointer to the constructed openmpt_module_ext, or NULL on failure.
+ * \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully.
+ * \sa \ref libopenmpt_c_fileio
+ * \since 0.3.0
+ */
+LIBOPENMPT_API openmpt_module_ext * openmpt_module_ext_create_from_memory( const void * filedata, size_t filesize, openmpt_log_func logfunc, void * loguser, openmpt_error_func errfunc, void * erruser, int * error, const char * * error_message, const openmpt_module_initial_ctl * ctls );
+
+/*! \brief Unload a previously created openmpt_module_ext from memory.
+ *
+ * \param mod The module to unload.
+ */
+LIBOPENMPT_API void openmpt_module_ext_destroy( openmpt_module_ext * mod_ext );
+
+/*! \brief Retrieve the openmpt_module handle from an openmpt_module_ext handle.
+ *
+ * \param mod_ext The extension module handle to convert
+ * \return An equivalent openmpt_module handle to pass to standard libopenmpt functions 
+ * \since 0.3.0
+ */
+LIBOPENMPT_API openmpt_module * openmpt_module_ext_get_module( openmpt_module_ext * mod_ext );
+
+/*! Retrieve a libopenmpt extension.
+ *
+ * \param mod_ext The module handle to work on.
+ * \param interface_id The name of the extension interface to retrieve (e.g. LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS).
+ * \param interface Appropriate structure of interface function pointers which is to be filled by this function (e.g. a pointer to a openmpt_module_ext_interface_pattern_vis structure).
+ * \param interface_size Size of the interface's structure of function pointers (e.g. sizeof(openmpt_module_ext_interface_pattern_vis)).
+ * \return 1 on success, 0 if the interface was not found.
+ * \since 0.3.0
+ */
+LIBOPENMPT_API int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * interface_id, void * interface, size_t interface_size );
+
+
+
+#ifndef LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS
+#define LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS "pattern_vis"
+#endif
+
+/*! Pattern command type */
+#define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_UNKNOWN 0
+#define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GENERAL 1
+#define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GLOBAL  2
+#define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_VOLUME  3
+#define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PANNING 4
+#define OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PITCH   5
+
+typedef struct openmpt_module_ext_interface_pattern_vis {
+	/*! Get pattern command type for pattern highlighting
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param pattern The pattern whose data should be retrieved.
+	 * \param row The row from which the data should be retrieved.
+	 * \param channel The channel from which the data should be retrieved.
+	 * \return The command type in the effect column at the given pattern position (see OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_*)
+	 * \sa openmpt_module_ext_interface_pattern_vis::get_pattern_row_channel_volume_effect_type
+	 */
+	int ( * get_pattern_row_channel_volume_effect_type ) ( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel );
+
+	/*! Get pattern command type for pattern highlighting
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param pattern The pattern whose data should be retrieved.
+	 * \param row The row from which the data should be retrieved.
+	 * \param channel The channel from which the data should be retrieved.
+	 * \return The command type in the effect column at the given pattern position (see OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_*)
+	 * \sa openmpt_module_ext_interface_pattern_vis::get_pattern_row_channel_volume_effect_type
+	 */
+	int ( * get_pattern_row_channel_effect_type ) ( openmpt_module_ext * mod_ext, int32_t pattern, int32_t row, int32_t channel );
+} openmpt_module_ext_interface_pattern_vis;
+
+
+
+#ifndef LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE
+#define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE "interactive"
+#endif
+
+typedef struct openmpt_module_ext_interface_interactive {
+	/*! Set the current ticks per row (speed)
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param speed The new tick count in range [1, 65535].
+	 * \return 1 on success, 0 on failure.
+	 * \remarks The tick count may be reset by pattern commands at any time.
+	 * \sa openmpt_module_get_current_speed
+	 */
+	int ( * set_current_speed ) ( openmpt_module_ext * mod_ext, int32_t speed );
+
+	/*! Set the current module tempo
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module.
+	 * \return 1 on success, 0 on failure.
+	 * \remarks The tempo may be reset by pattern commands at any time. Use openmpt_module_ext_interface_interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands.
+	 * \sa openmpt_module_get_current_tempo
+	 */
+	int ( * set_current_tempo ) ( openmpt_module_ext * mod_ext, int32_t tempo );
+
+	/*! Set the current module tempo factor without affecting playback pitch
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param factor The new tempo factor in range ]0.0, 4.0] - 1.0 means unmodified tempo.
+	 * \return 1 on success, 0 on failure.
+	 * \remarks Modifying the tempo without applying the same pitch factor using openmpt_module_ext_interface_interactive::set_pitch_factor may cause rhythmic samples (e.g. drum loops) to go out of sync.
+	 * \sa openmpt_module_ext_interface_interactive::get_tempo_factor
+	 */
+	int ( * set_tempo_factor ) ( openmpt_module_ext * mod_ext, double factor );
+
+	/*! Gets the current module tempo factor
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \return The current tempo factor.
+	 * \sa openmpt_module_ext_interface_interactive::set_tempo_factor
+	 */
+	double ( * get_tempo_factor ) ( openmpt_module_ext * mod_ext );
+
+	/*! Set the current module pitch factor without affecting playback speed
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param factor The new pitch factor in range ]0.0, 4.0] - 1.0 means unmodified pitch.
+	 * \return 1 on success, 0 on failure.
+	 * \remarks Modifying the pitch without applying the the same tempo factor using openmpt_module_ext_interface_interactive::set_tempo_factor may cause rhythmic samples (e.g. drum loops) to go out of sync.
+	 * \remarks To shift the pich by `n` semitones, the parameter can be calculated as follows: `pow( 2.0, n / 12.0 )`
+	 * \sa openmpt_module_ext_interface_interactive::get_pitch_factor
+	 */
+	int ( * set_pitch_factor ) ( openmpt_module_ext * mod_ext, double factor );
+
+	/*! Gets the current module pitch factor
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \return The current pitch factor.
+	 * \sa openmpt_module_ext_interface_interactive::set_pitch_factor
+	*/
+	double ( * get_pitch_factor ) ( openmpt_module_ext * mod_ext );
+
+	/*! Set the current global volume
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param volume The new global volume in range [0.0, 1.0]
+	 * \return 1 on success, 0 on failure.
+	 * \remarks The global volume may be reset by pattern commands at any time. Use openmpt_module_set_render_param to apply a global overall volume factor that is independent of pattern commands.
+	 * \sa openmpt_module_ext_interface_interactive::get_global_volume
+	 */
+	int ( * set_global_volume ) ( openmpt_module_ext * mod_ext, double volume );
+
+	/*! Get the current global volume
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \return The current global volume in range [0.0, 1.0]
+	 * \sa openmpt_module_ext_interface_interactive::set_global_volume
+	 */
+	double ( * get_global_volume ) ( openmpt_module_ext * mod_ext );
+
+	/*! Set the current channel volume for a channel
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param channel The channel whose volume should be set, in range [0, openmpt_module_get_num_channels()[
+	 * \param volume The new channel volume in range [0.0, 1.0]
+	 * \return 1 on success, 0 on failure (channel out of range).
+	 * \remarks The channel volume may be reset by pattern commands at any time.
+	 * \sa openmpt_module_ext_interface_interactive::get_channel_volume
+	 */
+	int ( * set_channel_volume ) ( openmpt_module_ext * mod_ext, int32_t channel, double volume );
+
+	/*! Get the current channel volume for a channel
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param channel The channel whose volume should be retrieved, in range [0, openmpt_module_get_num_channels()[
+	 * \return The current channel volume in range [0.0, 1.0]
+	 * \sa openmpt_module_ext_interface_interactive::set_channel_volume
+	 */
+	double ( * get_channel_volume ) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+	/*! Set the current mute status for a channel
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param channel The channel whose mute status should be set, in range [0, openmpt_module_get_num_channels()[
+	 * \param mute The new mute status. true is muted, false is unmuted.
+	 * \return 1 on success, 0 on failure (channel out of range).
+	 * \sa openmpt_module_ext_interface_interactive::get_channel_mute_status
+	 */
+	int ( * set_channel_mute_status ) ( openmpt_module_ext * mod_ext, int32_t channel, int mute );
+
+	/*! Get the current mute status for a channel
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param channel The channel whose mute status should be retrieved, in range [0, openmpt_module_get_num_channels()[
+	 * \return The current channel mute status. 1 is muted, 0 is unmuted, -1 means the instrument was out of range
+	 * \sa openmpt_module_ext_interface_interactive::set_channel_mute_status
+	 */
+	int ( * get_channel_mute_status ) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+	/*! Set the current mute status for an instrument
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param instrument The instrument whose mute status should be set, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[
+	 * \param mute The new mute status. true is muted, false is unmuted.
+	 * \return 1 on success, 0 on failure (instrument out of range).
+	 * \sa openmpt_module_ext_interface_interactive::get_instrument_mute_status
+	 */
+	int ( * set_instrument_mute_status ) ( openmpt_module_ext * mod_ext, int32_t instrument, int mute );
+
+	/*! Get the current mute status for an instrument
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param instrument The instrument whose mute status should be retrieved, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[
+	 * \return The current instrument mute status. 1 is muted, 0 is unmuted, -1 means the instrument was out of range
+	 * \sa openmpt_module_ext_interface_interactive::set_instrument_mute_status
+	 */
+	int ( * get_instrument_mute_status ) ( openmpt_module_ext * mod_ext, int32_t instrument );
+
+	/*! Play a note using the specified instrument
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param instrument The instrument that should be played, in range [0, openmpt_module_get_num_instruments()[ if openmpt_module_get_num_instruments is not 0, otherwise in [0, openmpt_module_get_num_samples()[
+	 * \param note The note to play, in rage [0, 119]. 60 is the middle C.
+	 * \param volume The volume at which the note should be triggered, in range [0.0, 1.0]
+	 * \param panning The panning position at which the note should be triggered, in range [-1.0, 1.0], 0.0 is center.
+	 * \return The channel on which the note is played. This can pe be passed to openmpt_module_ext_interface_interactive::stop_note to stop the note. -1 means that no channel could be allocated and the note is not played.
+	 * \sa openmpt_module_ext_interface_interactive::stop_note
+	 */
+	int32_t ( * play_note ) ( openmpt_module_ext * mod_ext, int32_t instrument, int32_t note, double volume, double panning );
+
+	/*! Stop the note playing on the specified channel
+	 *
+	 * \param mod_ext The module handle to work on.
+	 * \param channel The channel on which the note should be stopped.
+	 * \return 1 on success, 0 on failure (channel out of range).
+	 * \sa openmpt_module_ext_interface_interactive::play_note
+	 */
+	int ( * stop_note ) ( openmpt_module_ext * mod_ext, int32_t channel );
+} openmpt_module_ext_interface_interactive;
+
+
+
+/* add stuff here */
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBOPENMPT_EXT_H */
+
diff --git a/libopenmpt/libopenmpt_ext.hpp b/libopenmpt/libopenmpt_ext.hpp
index f9b7d73..686eaee 100644
--- a/libopenmpt/libopenmpt_ext.hpp
+++ b/libopenmpt/libopenmpt_ext.hpp
@@ -1,8 +1,8 @@
 /*
  * libopenmpt_ext.hpp
  * ------------------
- * Purpose: libopenmpt public c++ interface for extending libopenmpt
- * Notes  : The API defined in this file is currently not considered stable yet. Do NOT ship in distributions yet to avoid applications relying on API/ABI compatibility.
+ * Purpose: libopenmpt public c++ interface for libopenmpt extensions
+ * Notes  :
  * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  */
@@ -13,32 +13,10 @@
 #include "libopenmpt_config.h"
 #include "libopenmpt.hpp"
 
-#if !defined(LIBOPENMPT_EXT_IS_EXPERIMENTAL)
-
-#error "libopenmpt_ext is still completely experimental. The ABIs and APIs WILL change. Use at your own risk, and use only internally for now. You have to #define LIBOPENMPT_EXT_IS_EXPERIMENTAL to use it."
-
-#else // LIBOPENMPT_EXT_IS_EXPERIMENTAL
-
 /*!
  * \page libopenmpt_ext_cpp_overview libopenmpt_ext C++ API
  *
- * \section libopenmpt-ext-cpp-experimental libopenmpt_ext is experimental
- *
- * libopenmpt_ext is currently experimental and still subject to change without
- * further notice.
- * 
- * Only a C++ interface is provided.
- *
- * libopenmpt_ext is included in all builds by default.
- *
- * You need to `#define LIBOPENMPT_EXT_IS_EXPERIMENTAL` before including
- * `libopenmpt_ext.hpp` in order to acknowledge the experimental state and
- * potentially unstable API and ABI.
- *
- * When relying on libopenmpt_ext, it is currently recommended to either, bundle
- * a copy of libopenmpt with your project and link it statically, or,
- * explicitely state a dependency on a particular libopenmpt version, in order
- * to get the exact required API semantics in libopenmpt_ext.
+ * libopenmpt_ext is now included in all builds by default.
  *
  * \section libopenmpt-ext-cpp-detailed Detailed documentation
  *
@@ -77,8 +55,16 @@ public:
 	/*! Example: Retrieving the interactive extension to change the tempo of a module:
 	  \code{.cpp}
 	  openmpt::module_ext *mod = new openmpt::module_ext( stream );
-	  openmpt::ext::interactive *interactive = static_cast<openmpt::ext::interactive *>( self->mod->get_interface( openmpt::ext::interactive_id ) );
-	  interactive->set_tempo_factor( 2.0 ); // play module at double speed
+	  #ifdef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE
+	    openmpt::ext::interactive *interactive = static_cast<openmpt::ext::interactive *>( self->mod->get_interface( openmpt::ext::interactive_id ) );
+	    if ( interactive ) {
+	      interactive->set_tempo_factor( 2.0 ); // play module at double speed
+	    } else {
+	      // interface not available
+	    }
+	  #else
+	    // interfae not available
+	  #endif
 	  \endcode
 	  \param interface_id The name of the extension interface to retrieve.
 	  \return The interface object. This may be a nullptr if the extension was not found.
@@ -89,26 +75,28 @@ public:
 
 namespace ext {
 
-#define LIBOPENMPT_DECLARE_EXT_INTERFACE(name) \
+#define LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(name) \
 	static const char name ## _id [] = # name ; \
 	class name; \
 /**/
 
-#define LIBOPENMPT_EXT_INTERFACE(name) \
+#define LIBOPENMPT_EXT_CXX_INTERFACE(name) \
 	protected: \
 		name () {} \
-		virtual ~ name() {} \
+		virtual ~ name () {} \
 	public: \
 /**/
 
 
+#ifndef LIBOPENMPT_EXT_INTERFACE_PATTERN_VIS
 #define LIBOPENMPT_EXT_INTERFACE_PATTERN_VIS
+#endif
 
-LIBOPENMPT_DECLARE_EXT_INTERFACE(pattern_vis)
+LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(pattern_vis)
 
 class pattern_vis {
 
-	LIBOPENMPT_EXT_INTERFACE(pattern_vis)
+	LIBOPENMPT_EXT_CXX_INTERFACE(pattern_vis)
 
 	//! Pattern command type
 	enum effect_type {
@@ -145,13 +133,15 @@ class pattern_vis {
 }; // class pattern_vis
 
 
+#ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE
 #define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE
+#endif
 
-LIBOPENMPT_DECLARE_EXT_INTERFACE(interactive)
+LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive)
 
 class interactive {
 
-	LIBOPENMPT_EXT_INTERFACE(interactive)
+	LIBOPENMPT_EXT_CXX_INTERFACE(interactive)
 
 	//! Set the current ticks per row (speed)
 	/*!
@@ -191,7 +181,7 @@ class interactive {
 	/*!
 	  \param factor The new pitch factor in range ]0.0, 4.0] - 1.0 means unmodified pitch.
 	  \throws openmpt::exception Throws an exception derived from openmpt::exception if the factor is outside the specified range.
-	  \remarks Modifying the pitch without applying the the same tempo factor openmpt::ext::interactive::set_tempo_factor may cause rhythmic samples (e.g. drum loops) to go out of sync.
+	  \remarks Modifying the pitch without applying the the same tempo factor using openmpt::ext::interactive::set_tempo_factor may cause rhythmic samples (e.g. drum loops) to go out of sync.
 	  \remarks To shift the pich by `n` semitones, the parameter can be calculated as follows: `pow( 2.0, n / 12.0 )`
 	  \sa openmpt::ext::interactive::get_pitch_factor
 	*/
@@ -208,7 +198,7 @@ class interactive {
 	/*!
 	  \param volume The new global volume in range [0.0, 1.0]
 	  \throws openmpt::exception Throws an exception derived from openmpt::exception if the volume is outside the specified range.
-	  \remarks The global volume may be reset by pattern commands at any time. Use openmpt::module:set_render_param to apply a global overall volume factor that is independent of pattern commands.
+	  \remarks The global volume may be reset by pattern commands at any time. Use openmpt::module::set_render_param to apply a global overall volume factor that is independent of pattern commands.
 	  \sa openmpt::ext::interactive::get_global_volume
 	*/
 	virtual void set_global_volume( double volume ) = 0;
@@ -269,7 +259,7 @@ class interactive {
 	//! Get the current mute status for an instrument
 	/*!
 	  \param instrument The instrument whose mute status should be retrieved, in range [0, openmpt::module::get_num_instruments()[ if openmpt::module::get_num_instruments is not 0, otherwise in [0, openmpt::module::get_num_samples()[
-	  \return The current channel mute status. true is muted, false is unmuted.
+	  \return The current instrument mute status. true is muted, false is unmuted.
 	  \throws openmpt::exception Throws an exception derived from openmpt::exception if the instrument is outside the specified range.
 	  \sa openmpt::ext::interactive::set_instrument_mute_status
 	*/
@@ -302,8 +292,8 @@ class interactive {
 
 
 
-#undef LIBOPENMPT_DECLARE_EXT_INTERFACE
-#undef LIBOPENMPT_EXT_INTERFACE
+#undef LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE
+#undef LIBOPENMPT_EXT_CXX_INTERFACE
 
 } // namespace ext
 
@@ -313,6 +303,4 @@ class interactive {
   @}
 */
 
-#endif // LIBOPENMPT_EXT_IS_EXPERIMENTAL
-
 #endif // LIBOPENMPT_EXT_HPP
diff --git a/libopenmpt/libopenmpt_ext.cpp b/libopenmpt/libopenmpt_ext_impl.cpp
similarity index 57%
rename from libopenmpt/libopenmpt_ext.cpp
rename to libopenmpt/libopenmpt_ext_impl.cpp
index ec29f97..30e4d24 100644
--- a/libopenmpt/libopenmpt_ext.cpp
+++ b/libopenmpt/libopenmpt_ext_impl.cpp
@@ -1,79 +1,52 @@
+/*
+ * libopenmpt_ext_impl.cpp
+ * -----------------------
+ * Purpose: libopenmpt extensions - implementation
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
 
 #include "common/stdafx.h"
 
-#define LIBOPENMPT_EXT_IS_EXPERIMENTAL
-
 #include "libopenmpt_internal.h"
 #include "libopenmpt_ext.hpp"
-#include "libopenmpt_impl.hpp"
+
+#include "libopenmpt_ext_impl.hpp"
 
 #include <stdexcept>
 
 #include "soundlib/Sndfile.h"
 
-#if defined(_MSC_VER)
-#pragma warning(disable:4702) // unreachable code
-#endif
-
 using namespace OpenMPT;
 
-#ifndef NO_LIBOPENMPT_CXX
-
 namespace openmpt {
 
-class module_ext_impl
-	: public module_impl
-	, public ext::pattern_vis
-	, public ext::interactive
-
-
-
-	/* add stuff here */
-
-
-
-{
-public:
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	module_ext_impl( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( stream, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls ) {
-#else
-	module_ext_impl( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( stream, std::make_shared<std_ostream_log>( log ), ctls ) {
-#endif
+	module_ext_impl::module_ext_impl( callback_stream_wrapper stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( stream, std::move(log), ctls ) {
 		ctor();
 	}
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	module_ext_impl( const std::vector<char> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls ) {
-#else
-	module_ext_impl( const std::vector<char> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::make_shared<std_ostream_log>( log ), ctls ) {
-#endif
+	module_ext_impl::module_ext_impl( std::istream & stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( stream, std::move(log), ctls ) {
 		ctor();
 	}
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	module_ext_impl( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls ) {
-#else
-	module_ext_impl( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::make_shared<std_ostream_log>( log ), ctls ) {
-#endif
+	module_ext_impl::module_ext_impl( const std::vector<std::uint8_t> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::move(log), ctls ) {
 		ctor();
 	}
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-	module_ext_impl( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::tr1::shared_ptr<std_ostream_log>( new std_ostream_log( log ) ), ctls ) {
-#else
-	module_ext_impl( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::make_shared<std_ostream_log>( log ), ctls ) {
-#endif
+	module_ext_impl::module_ext_impl( const std::vector<char> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( data, std::move(log), ctls ) {
+		ctor();
+	}
+	module_ext_impl::module_ext_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) {
+		ctor();
+	}
+	module_ext_impl::module_ext_impl( const char * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) {
+		ctor();
+	}
+	module_ext_impl::module_ext_impl( const void * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : module_impl( data, size, std::move(log), ctls ) {
 		ctor();
 	}
-
-private:
-
-
-
-	/* add stuff here */
-
 
 
-private:
 
-	void ctor() {
+	void module_ext_impl::ctor() {
 
 
 
@@ -83,9 +56,9 @@ private:
 
 	}
 
-public:
 
-	~module_ext_impl() {
+
+	module_ext_impl::~module_ext_impl() {
 
 
 
@@ -95,9 +68,9 @@ public:
 
 	}
 
-public:
 
-	void * get_interface( const std::string & interface_id ) {
+
+	void * module_ext_impl::get_interface( const std::string & interface_id ) {
 		if ( interface_id.empty() ) {
 			return 0;
 		} else if ( interface_id == ext::pattern_vis_id ) {
@@ -118,7 +91,7 @@ public:
 
 	// pattern_vis
 
-	virtual effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const {
+	module_ext_impl::effect_type module_ext_impl::get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const {
 		std::uint8_t byte = get_pattern_row_channel_command( pattern, row, channel, module::command_volumeffect );
 		switch ( ModCommand::GetVolumeEffectType( byte ) ) {
 			case EFFECT_TYPE_NORMAL : return effect_general; break;
@@ -130,7 +103,7 @@ public:
 		}
 	}
 
-	virtual effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const {
+	module_ext_impl::effect_type module_ext_impl::get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const {
 		std::uint8_t byte = get_pattern_row_channel_command( pattern, row, channel, module::command_effect );
 		switch ( ModCommand::GetEffectType( byte ) ) {
 			case EFFECT_TYPE_NORMAL : return effect_general; break;
@@ -144,21 +117,21 @@ public:
 
 	// interactive
 
-	virtual void set_current_speed( std::int32_t speed ) {
+	void module_ext_impl::set_current_speed( std::int32_t speed ) {
 		if ( speed < 1 || speed > 65535 ) {
 			throw openmpt::exception("invalid tick count");
 		}
 		m_sndFile->m_PlayState.m_nMusicSpeed = speed;
 	}
 
-	virtual void set_current_tempo( std::int32_t tempo ) {
+	void module_ext_impl::set_current_tempo( std::int32_t tempo ) {
 		if ( tempo < 32 || tempo > 512 ) {
 			throw openmpt::exception("invalid tempo");
 		}
 		m_sndFile->m_PlayState.m_nMusicTempo.Set( tempo );
 	}
 
-	virtual void set_tempo_factor( double factor ) {
+	void module_ext_impl::set_tempo_factor( double factor ) {
 		if ( factor <= 0.0 || factor > 4.0 ) {
 			throw openmpt::exception("invalid tempo factor");
 		}
@@ -166,11 +139,11 @@ public:
 		m_sndFile->RecalculateSamplesPerTick();
 	}
 
-	virtual double get_tempo_factor( ) const {
+	double module_ext_impl::get_tempo_factor( ) const {
 		return 65536.0 / m_sndFile->m_nTempoFactor;
 	}
 
-	virtual void set_pitch_factor( double factor ) {
+	void module_ext_impl::set_pitch_factor( double factor ) {
 		if ( factor <= 0.0 || factor > 4.0 ) {
 			throw openmpt::exception("invalid pitch factor");
 		}
@@ -178,22 +151,22 @@ public:
 		m_sndFile->RecalculateSamplesPerTick();
 	}
 
-	virtual double get_pitch_factor( ) const {
+	double module_ext_impl::get_pitch_factor( ) const {
 		return m_sndFile->m_nFreqFactor / 65536.0;
 	}
 
-	virtual void set_global_volume( double volume ) {
+	void module_ext_impl::set_global_volume( double volume ) {
 		if ( volume < 0.0 || volume > 1.0 ) {
 			throw openmpt::exception("invalid global volume");
 		}
 		m_sndFile->m_PlayState.m_nGlobalVolume = Util::Round<uint32_t>( volume * MAX_GLOBAL_VOLUME );
 	}
 
-	virtual double get_global_volume( ) const {
+	double module_ext_impl::get_global_volume( ) const {
 		return m_sndFile->m_PlayState.m_nGlobalVolume / static_cast<double>( MAX_GLOBAL_VOLUME );
 	}
 	
-	virtual void set_channel_volume( std::int32_t channel, double volume ) {
+	void module_ext_impl::set_channel_volume( std::int32_t channel, double volume ) {
 		if ( channel < 0 || channel >= get_num_channels() ) {
 			throw openmpt::exception("invalid channel");
 		}
@@ -203,14 +176,14 @@ public:
 		m_sndFile->m_PlayState.Chn[channel].nGlobalVol = Util::Round<std::int32_t>(volume * 64.0);
 	}
 
-	virtual double get_channel_volume( std::int32_t channel ) const {
+	double module_ext_impl::get_channel_volume( std::int32_t channel ) const {
 		if ( channel < 0 || channel >= get_num_channels() ) {
 			throw openmpt::exception("invalid channel");
 		}
 		return m_sndFile->m_PlayState.Chn[channel].nGlobalVol / 64.0;
 	}
 
-	virtual void set_channel_mute_status( std::int32_t channel, bool mute ) {
+	void module_ext_impl::set_channel_mute_status( std::int32_t channel, bool mute ) {
 		if ( channel < 0 || channel >= get_num_channels() ) {
 			throw openmpt::exception("invalid channel");
 		}
@@ -227,14 +200,14 @@ public:
 		}
 	}
 
-	virtual bool get_channel_mute_status( std::int32_t channel ) const {
+	bool module_ext_impl::get_channel_mute_status( std::int32_t channel ) const {
 		if ( channel < 0 || channel >= get_num_channels() ) {
 			throw openmpt::exception("invalid channel");
 		}
 		return m_sndFile->m_PlayState.Chn[channel].dwFlags[CHN_MUTE];
 	}
 	
-	virtual void set_instrument_mute_status( std::int32_t instrument, bool mute ) {
+	void module_ext_impl::set_instrument_mute_status( std::int32_t instrument, bool mute ) {
 		const bool instrument_mode = get_num_instruments() != 0;
 		const int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
 		if ( instrument < 0 || instrument >= max_instrument ) {
@@ -249,7 +222,7 @@ public:
 		}
 	}
 
-	virtual bool get_instrument_mute_status( std::int32_t instrument ) const {
+	bool module_ext_impl::get_instrument_mute_status( std::int32_t instrument ) const {
 		const bool instrument_mode = get_num_instruments() != 0;
 		const int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
 		if ( instrument < 0 || instrument >= max_instrument ) {
@@ -265,7 +238,7 @@ public:
 		}
 	}
 
-	virtual std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) {
+	std::int32_t module_ext_impl::play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) {
 		const bool instrument_mode = get_num_instruments() != 0;
 		const int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
 		if ( instrument < 0 || instrument >= max_instrument ) {
@@ -305,7 +278,7 @@ public:
 		return free_channel;
 	}
 
-	virtual void stop_note( std::int32_t channel ) {
+	void module_ext_impl::stop_note( std::int32_t channel ) {
 		if ( channel < 0 || channel >= MAX_CHANNELS ) {
 			throw openmpt::exception("invalid channel");
 		}
@@ -319,40 +292,5 @@ public:
 
 
 
-}; // class module_ext_impl
-
-module_ext::module_ext( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
-	ext_impl = new module_ext_impl( stream, log, ctls );
-	set_impl( ext_impl );
-}
-module_ext::module_ext( const std::vector<char> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
-	ext_impl = new module_ext_impl( data, log, ctls );
-	set_impl( ext_impl );
-}
-module_ext::module_ext( const char * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
-	ext_impl = new module_ext_impl( data, size, log, ctls );
-	set_impl( ext_impl );
-}
-module_ext::module_ext( const void * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : ext_impl(0) {
-	ext_impl = new module_ext_impl( data, size, log, ctls );
-	set_impl( ext_impl );
-}
-module_ext::~module_ext() {
-	set_impl( 0 );
-	delete ext_impl;
-	ext_impl = 0;
-}
-module_ext::module_ext( const module_ext & other ) : module(other) {
-	throw std::runtime_error("openmpt::module_ext is non-copyable");
-}
-void module_ext::operator = ( const module_ext & ) {
-	throw std::runtime_error("openmpt::module_ext is non-copyable");
-}
-
-void * module_ext::get_interface( const std::string & interface_id ) {
-	return ext_impl->get_interface( interface_id );
-}
-
 } // namespace openmpt
 
-#endif // NO_LIBOPENMPT_CXX
diff --git a/libopenmpt/libopenmpt_ext_impl.hpp b/libopenmpt/libopenmpt_ext_impl.hpp
new file mode 100644
index 0000000..c407ddf
--- /dev/null
+++ b/libopenmpt/libopenmpt_ext_impl.hpp
@@ -0,0 +1,112 @@
+/*
+ * libopenmpt_ext_impl.hpp
+ * -----------------------
+ * Purpose: libopenmpt extensions - implementation header
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_EXT_IMPL_HPP
+#define LIBOPENMPT_EXT_IMPL_HPP
+
+#include "libopenmpt_internal.h"
+#include "libopenmpt_impl.hpp"
+#include "libopenmpt_ext.hpp"
+
+using namespace OpenMPT;
+
+namespace openmpt {
+
+class module_ext_impl
+	: public module_impl
+	, public ext::pattern_vis
+	, public ext::interactive
+
+
+
+	/* add stuff here */
+
+
+
+{
+public:
+	module_ext_impl( callback_stream_wrapper stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_ext_impl( std::istream & stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_ext_impl( const std::vector<std::uint8_t> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_ext_impl( const std::vector<char> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_ext_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_ext_impl( const char * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_ext_impl( const void * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+
+private:
+
+
+
+	/* add stuff here */
+
+
+
+private:
+
+	void ctor();
+
+public:
+
+	~module_ext_impl();
+
+public:
+
+	void * get_interface( const std::string & interface_id );
+
+	// pattern_vis
+
+	virtual effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const;
+
+	virtual effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const;
+
+	// interactive
+
+	virtual void set_current_speed( std::int32_t speed );
+
+	virtual void set_current_tempo( std::int32_t tempo );
+
+	virtual void set_tempo_factor( double factor );
+
+	virtual double get_tempo_factor( ) const;
+
+	virtual void set_pitch_factor( double factor );
+
+	virtual double get_pitch_factor( ) const;
+
+	virtual void set_global_volume( double volume );
+
+	virtual double get_global_volume( ) const;
+	
+	virtual void set_channel_volume( std::int32_t channel, double volume );
+
+	virtual double get_channel_volume( std::int32_t channel ) const;
+
+	virtual void set_channel_mute_status( std::int32_t channel, bool mute );
+
+	virtual bool get_channel_mute_status( std::int32_t channel ) const;
+	
+	virtual void set_instrument_mute_status( std::int32_t instrument, bool mute );
+
+	virtual bool get_instrument_mute_status( std::int32_t instrument ) const;
+
+	virtual std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning );
+
+	virtual void stop_note( std::int32_t channel );
+
+
+	/* add stuff here */
+
+
+
+}; // class module_ext_impl
+
+} // namespace openmpt
+
+#endif // LIBOPENMPT_EXT_IMPL_HPP
+
diff --git a/libopenmpt/libopenmpt_impl.cpp b/libopenmpt/libopenmpt_impl.cpp
index 8aba11c..adf2182 100644
--- a/libopenmpt/libopenmpt_impl.cpp
+++ b/libopenmpt/libopenmpt_impl.cpp
@@ -36,8 +36,28 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if MPT_COMPILER_MSVC || MPT_COMPILER_MSVCCLANGC2
+#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+#if defined(_WIN32_WINNT)
+#if (_WIN32_WINNT < 0x0602)
+#if MPT_COMPILER_MSVC
+#pragma message("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define _WIN32_WINNT 0x0602.")
+#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
+#warning "Warning: libopenmpt for WinRT is built with reduced functionality. Please #define _WIN32_WINNT 0x0602."
+#else
+// There is no portable way to display a warning.
+// Try to provoke a warning with an unused variable.
+static int Warning_libopenmpt_for_WinRT_is_built_with_reduced_functionality_Please_define_WIN32_WINNT_0x0602;
+#endif
+#endif // _WIN32_WINNT
+#endif // _WIN32_WINNT
+#endif // MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+
+#if defined(MPT_BUILD_MSVC)
+#if MPT_OS_WINDOWS_WINRT
+#pragma comment(lib, "ole32.lib")
+#else
 #pragma comment(lib, "rpcrt4.lib")
+#endif
 #if defined(MPT_WITH_MEDIAFOUNDATION)
 #pragma comment(lib, "mf.lib")
 #pragma comment(lib, "mfplat.lib")
@@ -49,9 +69,9 @@ OPENMPT_NAMESPACE_BEGIN
 #pragma comment(lib, "dmoguids.lib")
 #pragma comment(lib, "strmiids.lib")
 #endif // !NO_DMO
-#endif // MPT_COMPILER_MSVC || MPT_COMPILER_MSVCCLANGC2
+#endif // MPT_BUILD_MSVC
 
-#if MPT_MUTEX_NONE && !MPT_OS_EMSCRIPTEN
+#if MPT_PLATFORM_MULTITHREADED && MPT_MUTEX_NONE
 #if MPT_COMPILER_MSVC
 #pragma message("Warning: libopenmpt built in non thread-safe mode because mutexes are not supported by the C++ standard library available.")
 #elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
@@ -63,10 +83,23 @@ static int Warning_libopenmpt_built_in_non_thread_safe_mode_because_mutexes_are_
 #endif
 #endif // MPT_MUTEX_NONE
 
+#if 0
+#if (!MPT_COMPILER_HAS_CONSTEXPR11)
+#if MPT_COMPILER_MSVC
+#pragma message("Warning: libopenmpt is built with a compiler not supporting constexpr. Referring to libopenmpt from global initializers will result in undefined behaviour.")
+#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
+#warning "Warning: libopenmpt is built with a compiler not supporting constexpr. Referring to libopenmpt from global initializers will result in undefined behaviour.")
+#else
+// There is no portable way to display a warning.
+// Try to provoke a warning with an unused variable.
+static int Warning_libopenmpt_is_built_with_a_compiler_not_supporting_constexpr_Referring_to_libopenmpt_from_global_initializers_will_result_in_undefined_behaviour;
+#endif
+#endif // "MPT_COMPILER_HAS_CONSTEXPR11
+#endif 
+
 #if defined(MPT_ASSERT_HANDLER_NEEDED) && !defined(ENABLE_TESTS)
 
 MPT_NOINLINE void AssertHandler(const char *file, int line, const char *function, const char *expr, const char *msg)
-//------------------------------------------------------------------------------------------------------------------
 {
 	if(msg)
 	{
@@ -95,8 +128,7 @@ namespace openmpt {
 namespace version {
 
 std::uint32_t get_library_version() {
-	const MptVersion::SourceInfo sourceInfo = MptVersion::GetSourceInfo();
-	return OPENMPT_API_VERSION | ( sourceInfo.Revision & 0xffff );
+	return OPENMPT_API_VERSION;
 }
 
 std::uint32_t get_core_version() {
@@ -106,30 +138,29 @@ std::uint32_t get_core_version() {
 static std::string get_library_version_string() {
 	std::string str;
 	const MptVersion::SourceInfo sourceInfo = MptVersion::GetSourceInfo();
-	std::uint32_t version = get_library_version();
-	if ( ( version & 0xffff ) == 0 ) {
-		str += mpt::ToString((version>>24) & 0xff);
-		str += ".";
-		str += mpt::ToString((version>>16) & 0xff);
-	} else {
-		str += mpt::ToString((version>>24) & 0xff);
-		str += ".";
-		str += mpt::ToString((version>>16) & 0xff);
-		str += ".";
-		str += mpt::ToString((version>>0) & 0xffff);
+	str += mpt::fmt::val(OPENMPT_API_VERSION_MAJOR);
+	str += ".";
+	str += mpt::fmt::val(OPENMPT_API_VERSION_MINOR);
+	str += ".";
+	str += mpt::fmt::val(OPENMPT_API_VERSION_PATCH);
+	if ( std::string(OPENMPT_API_VERSION_PREREL).length() > 0 ) {
+		str += OPENMPT_API_VERSION_PREREL;
+	}
+	std::vector<std::string> fields;
+	if ( sourceInfo.Revision ) {
+		fields.push_back( "r" + mpt::fmt::val( sourceInfo.Revision ) );
 	}
 	if ( sourceInfo.IsDirty ) {
-		str += ".2-modified";
-		if ( sourceInfo.IsPackage ) {
-			str += "-pkg";
-		}
+		fields.push_back( "modified" );
 	} else if ( sourceInfo.HasMixedRevisions ) {
-		str += ".1-modified";
-		if ( sourceInfo.IsPackage ) {
-			str += "-pkg";
-		}
-	} else if ( sourceInfo.IsPackage ) {
-		str += ".0-pkg";
+		fields.push_back( "mixed" );
+	}
+	if ( sourceInfo.IsPackage ) {
+		fields.push_back( "pkg" );
+	}
+	if ( !fields.empty() ) {
+		str += "+";
+		str += mpt::String::Combine( fields, std::string(".") );
 	}
 	return str;
 }
@@ -150,6 +181,11 @@ static std::string get_source_date_string() {
 	return MptVersion::GetSourceInfo().Date;
 }
 
+static std::string get_source_revision_string() {
+	const MptVersion::SourceInfo sourceInfo = MptVersion::GetSourceInfo();
+	return sourceInfo.Revision ? mpt::fmt::val(sourceInfo.Revision) : std::string();
+}
+
 static std::string get_build_string() {
 	return MptVersion::GetBuildDateString();
 }
@@ -187,6 +223,16 @@ std::string get_string( const std::string & key ) {
 		return std::string();
 	} else if ( key == "library_version" ) {
 		return get_library_version_string();
+	} else if ( key == "library_version_major" ) {
+		return mpt::fmt::val(OPENMPT_API_VERSION_MAJOR);
+	} else if ( key == "library_version_minor" ) {
+		return mpt::fmt::val(OPENMPT_API_VERSION_MINOR);
+	} else if ( key == "library_version_patch" ) {
+		return mpt::fmt::val(OPENMPT_API_VERSION_PATCH);
+	} else if ( key == "library_version_prerel" ) {
+		return mpt::fmt::val(OPENMPT_API_VERSION_PREREL);
+	} else if ( key == "library_version_is_release" ) {
+		return ( std::string(OPENMPT_API_VERSION_PREREL).length() == 0 ) ? "1" : "0";
 	} else if ( key == "library_features" ) {
 		return get_library_features_string();
 	} else if ( key == "core_version" ) {
@@ -195,6 +241,14 @@ std::string get_string( const std::string & key ) {
 		return get_source_url_string();
 	} else if ( key == "source_date" ) {
 		return get_source_date_string();
+	} else if ( key == "source_revision" ) {
+		return get_source_revision_string();
+	} else if ( key == "source_is_modified" ) {
+		return MptVersion::GetSourceInfo().IsDirty ? "1" : "0";
+	} else if ( key == "source_has_mixed_revision" ) {
+		return MptVersion::GetSourceInfo().HasMixedRevisions ? "1" : "0";
+	} else if ( key == "source_is_package" ) {
+		return MptVersion::GetSourceInfo().IsPackage ? "1" : "0";
 	} else if ( key == "build" ) {
 		return get_build_string();
 	} else if ( key == "build_compiler" ) {
@@ -239,17 +293,9 @@ void std_ostream_log::log( const std::string & message ) const {
 
 class log_forwarder : public ILog {
 private:
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<log_interface> destination;
-#else
-	std::shared_ptr<log_interface> destination;
-#endif
+	log_interface & destination;
 public:
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	log_forwarder( LIBOPENMPT_SHARED_PTR<log_interface> dest ) : destination(dest) {
-#else
-	log_forwarder( std::shared_ptr<log_interface> dest ) : destination(dest) {
-#endif
+	log_forwarder( log_interface & dest ) : destination(dest) {
 		return;
 	}
 	virtual ~log_forwarder() {
@@ -257,7 +303,7 @@ public:
 	}
 private:
 	void AddToLog( LogLevel level, const mpt::ustring & text ) const {
-		destination->log( mpt::ToCharset( mpt::CharsetUTF8, LogLevelToString( level ) + MPT_USTRING(": ") + text ) );
+		destination.log( mpt::ToCharset( mpt::CharsetUTF8, LogLevelToString( level ) + MPT_USTRING(": ") + text ) );
 	}
 }; // class log_forwarder
 
@@ -355,7 +401,7 @@ static void mixersettings_to_ramping( int & ramping, const MixerSettings & setti
 }
 
 std::string module_impl::mod_string_to_utf8( const std::string & encoded ) const {
-	return mpt::ToCharset( mpt::CharsetUTF8, m_sndFile->GetCharset(), encoded );
+	return mpt::ToCharset( mpt::CharsetUTF8, m_sndFile->GetCharsetInternal(), encoded );
 }
 void module_impl::apply_mixer_settings( std::int32_t samplerate, int channels ) {
 	bool samplerate_changed = static_cast<std::int32_t>( m_sndFile->m_MixerSettings.gdwMixingFreq ) != samplerate;
@@ -399,22 +445,10 @@ bool module_impl::has_subsongs_inited() const {
 	return !m_subsongs.empty();
 }
 void module_impl::ctor( const std::map< std::string, std::string > & ctls ) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	m_sndFile = LIBOPENMPT_SHARED_PTR<CSoundFile>(new CSoundFile());
-#else
-	m_sndFile = std::unique_ptr<CSoundFile>(new CSoundFile());
-#endif
+	m_sndFile = mpt::make_unique<CSoundFile>();
 	m_loaded = false;
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	m_Dither = LIBOPENMPT_SHARED_PTR<Dither>(new Dither(mpt::global_prng()));
-#else
-	m_Dither = std::unique_ptr<Dither>(new Dither(mpt::global_prng()));
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	m_LogForwarder = LIBOPENMPT_SHARED_PTR<log_forwarder>(new log_forwarder(m_Log));
-#else
-	m_LogForwarder = std::unique_ptr<log_forwarder>(new log_forwarder(m_Log));
-#endif
+	m_Dither = mpt::make_unique<Dither>(mpt::global_prng());
+	m_LogForwarder = mpt::make_unique<log_forwarder>( *m_Log );
 	m_sndFile->SetCustomLog( m_LogForwarder.get() );
 	m_current_subsong = 0;
 	m_currentPositionSeconds = 0.0;
@@ -441,7 +475,7 @@ void module_impl::load( const FileReader & file, const std::map< std::string, st
 			load_flags &= ~CSoundFile::loadPatternData;
 		}
 		if ( m_ctl_load_skip_plugins ) {
-			load_flags &= ~CSoundFile::loadPluginData;
+			load_flags &= ~(CSoundFile::loadPluginData | CSoundFile::loadPluginInstance);
 		}
 		if ( !m_sndFile->Create( file, static_cast<CSoundFile::ModLoadingFlags>( load_flags ) ) ) {
 			throw openmpt::exception("error loading file");
@@ -542,144 +576,274 @@ std::vector<std::string> module_impl::get_supported_extensions() {
 	std::copy( extensions.begin(), extensions.end(), std::back_insert_iterator<std::vector<std::string> >( retval ) );
 	return retval;
 }
+bool module_impl::is_extension_supported( const char * extension ) {
+	return CSoundFile::IsExtensionSupported( extension );
+}
 bool module_impl::is_extension_supported( const std::string & extension ) {
-	std::vector<std::string> extensions = get_supported_extensions();
-	std::string lowercase_ext = extension;
-	std::transform( lowercase_ext.begin(), lowercase_ext.end(), lowercase_ext.begin(), tolower );
-	return std::find( extensions.begin(), extensions.end(), lowercase_ext ) != extensions.end();
+	return CSoundFile::IsExtensionSupported( extension.c_str() );
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-double module_impl::could_open_propability( const OpenMPT::FileReader & file, double effort, LIBOPENMPT_SHARED_PTR<log_interface> log ) {
-#else
-double module_impl::could_open_propability( const OpenMPT::FileReader & file, double effort, std::shared_ptr<log_interface> log ) {
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<CSoundFile> sndFile( new CSoundFile() );
-#else
-	std::unique_ptr<CSoundFile> sndFile( new CSoundFile() );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<log_forwarder> logForwarder( new log_forwarder( log ) );
-#else
-	std::unique_ptr<log_forwarder> logForwarder( new log_forwarder( log ) );
-#endif
-	sndFile->SetCustomLog( logForwarder.get() );
-
+double module_impl::could_open_probability( const OpenMPT::FileReader & file, double effort, std::unique_ptr<log_interface> log ) {
 	try {
-
 		if ( effort >= 0.8 ) {
+			std::unique_ptr<CSoundFile> sndFile = mpt::make_unique<CSoundFile>();
+			std::unique_ptr<log_forwarder> logForwarder = mpt::make_unique<log_forwarder>( *log );
+			sndFile->SetCustomLog( logForwarder.get() );
 			if ( !sndFile->Create( file, CSoundFile::loadCompleteModule ) ) {
 				return 0.0;
 			}
 			sndFile->Destroy();
 			return 1.0;
 		} else if ( effort >= 0.6 ) {
+			std::unique_ptr<CSoundFile> sndFile = mpt::make_unique<CSoundFile>();
+			std::unique_ptr<log_forwarder> logForwarder = mpt::make_unique<log_forwarder>( *log );
+			sndFile->SetCustomLog( logForwarder.get() );
 			if ( !sndFile->Create( file, CSoundFile::loadNoPatternOrPluginData ) ) {
 				return 0.0;
 			}
 			sndFile->Destroy();
 			return 0.8;
 		} else if ( effort >= 0.2 ) {
+			std::unique_ptr<CSoundFile> sndFile = mpt::make_unique<CSoundFile>();
+			std::unique_ptr<log_forwarder> logForwarder = mpt::make_unique<log_forwarder>( *log );
+			sndFile->SetCustomLog( logForwarder.get() );
 			if ( !sndFile->Create( file, CSoundFile::onlyVerifyHeader ) ) {
 				return 0.0;
 			}
 			sndFile->Destroy();
 			return 0.6;
+		} else if ( effort >= 0.1 ) {
+			FileReader::PinnedRawDataView view = file.GetPinnedRawDataView( probe_file_header_get_recommended_size() );
+			int probe_file_header_result = probe_file_header( probe_file_header_flags_default, view.data(), view.size(), file.GetLength() );
+			double result = 0.0;
+			switch ( probe_file_header_result ) {
+				case probe_file_header_result_success:
+					result = 0.6;
+					break;
+				case probe_file_header_result_failure:
+					result = 0.0;
+					break;
+				case probe_file_header_result_wantmoredata:
+					result = 0.3;
+					break;
+				default:
+					throw openmpt::exception("");
+					break;
+			}
+			return result;
 		} else {
 			return 0.2;
 		}
-
 	} catch ( ... ) {
 		return 0.0;
 	}
-
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-double module_impl::could_open_propability( callback_stream_wrapper stream, double effort, LIBOPENMPT_SHARED_PTR<log_interface> log ) {
-#else
-double module_impl::could_open_propability( callback_stream_wrapper stream, double effort, std::shared_ptr<log_interface> log ) {
-#endif
+double module_impl::could_open_probability( callback_stream_wrapper stream, double effort, std::unique_ptr<log_interface> log ) {
 	CallbackStream fstream;
 	fstream.stream = stream.stream;
 	fstream.read = stream.read;
 	fstream.seek = stream.seek;
 	fstream.tell = stream.tell;
-	return could_open_propability( FileReader( fstream ), effort, log );
+	return could_open_probability( make_FileReader( fstream ), effort, std::move(log) );
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-double module_impl::could_open_propability( std::istream & stream, double effort, LIBOPENMPT_SHARED_PTR<log_interface> log ) {
-#else
-double module_impl::could_open_propability( std::istream & stream, double effort, std::shared_ptr<log_interface> log ) {
-#endif
-	return could_open_propability( FileReader( &stream ), effort, log );
+double module_impl::could_open_probability( std::istream & stream, double effort, std::unique_ptr<log_interface> log ) {
+	return could_open_probability( make_FileReader( &stream ), effort, std::move(log) );
 }
 
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( callback_stream_wrapper stream, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( callback_stream_wrapper stream, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+std::size_t module_impl::probe_file_header_get_recommended_size() {
+	return CSoundFile::ProbeRecommendedSize;
+}
+int module_impl::probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize ) {
+	int result = 0;
+	switch ( CSoundFile::Probe( static_cast<CSoundFile::ProbeFlags>( flags ), mpt::span<const mpt::byte>( mpt::byte_cast<const mpt::byte*>( data ), size ), &filesize ) ) {
+		case CSoundFile::ProbeSuccess:
+			result = probe_file_header_result_success;
+			break;
+		case CSoundFile::ProbeFailure:
+			result = probe_file_header_result_failure;
+			break;
+		case CSoundFile::ProbeWantMoreData:
+			result = probe_file_header_result_wantmoredata;
+			break;
+		default:
+			throw exception("internal error");
+			break;
+	}
+	return result;
+}
+int module_impl::probe_file_header( std::uint64_t flags, const void * data, std::size_t size, std::uint64_t filesize ) {
+	int result = 0;
+	switch ( CSoundFile::Probe( static_cast<CSoundFile::ProbeFlags>( flags ), mpt::span<const mpt::byte>( mpt::void_cast<const mpt::byte*>( data ), size ), &filesize ) ) {
+		case CSoundFile::ProbeSuccess:
+			result = probe_file_header_result_success;
+			break;
+		case CSoundFile::ProbeFailure:
+			result = probe_file_header_result_failure;
+			break;
+		case CSoundFile::ProbeWantMoreData:
+			result = probe_file_header_result_wantmoredata;
+			break;
+		default:
+			throw exception("internal error");
+			break;
+	}
+	return result;
+}
+int module_impl::probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size ) {
+	int result = 0;
+	switch ( CSoundFile::Probe( static_cast<CSoundFile::ProbeFlags>( flags ), mpt::span<const mpt::byte>( mpt::byte_cast<const mpt::byte*>( data ), size ), nullptr ) ) {
+		case CSoundFile::ProbeSuccess:
+			result = probe_file_header_result_success;
+			break;
+		case CSoundFile::ProbeFailure:
+			result = probe_file_header_result_failure;
+			break;
+		case CSoundFile::ProbeWantMoreData:
+			result = probe_file_header_result_wantmoredata;
+			break;
+		default:
+			throw exception("internal error");
+			break;
+	}
+	return result;
+}
+int module_impl::probe_file_header( std::uint64_t flags, const void * data, std::size_t size ) {
+	int result = 0;
+	switch ( CSoundFile::Probe( static_cast<CSoundFile::ProbeFlags>( flags ), mpt::span<const mpt::byte>( mpt::void_cast<const mpt::byte*>( data ), size ), nullptr ) ) {
+		case CSoundFile::ProbeSuccess:
+			result = probe_file_header_result_success;
+			break;
+		case CSoundFile::ProbeFailure:
+			result = probe_file_header_result_failure;
+			break;
+		case CSoundFile::ProbeWantMoreData:
+			result = probe_file_header_result_wantmoredata;
+			break;
+		default:
+			throw exception("internal error");
+			break;
+	}
+	return result;
+}
+int module_impl::probe_file_header( std::uint64_t flags, std::istream & stream ) {
+	int result = 0;
+	char buffer[ PROBE_RECOMMENDED_SIZE ];
+	MemsetZero( buffer );
+	std::size_t size_read = 0;
+	std::size_t size_toread = CSoundFile::ProbeRecommendedSize;
+	if ( stream.bad() ) {
+		throw exception("error reading stream");
+	}
+	const bool seekable = FileDataContainerStdStreamSeekable::IsSeekable( &stream );
+	const uint64 filesize = ( seekable ? FileDataContainerStdStreamSeekable::GetLength( &stream ) : 0 );
+	while ( ( size_toread > 0 ) && stream ) {
+		stream.read( buffer + size_read, size_toread );
+		if ( stream.bad() ) {
+			throw exception("error reading stream");
+		} else if ( stream.eof() ) {
+			// normal
+		} else if ( stream.fail() ) {
+			throw exception("error reading stream");
+		} else {
+			// normal
+		}
+		std::size_t read_count = static_cast<std::size_t>( stream.gcount() );
+		size_read += read_count;
+		size_toread -= read_count;
+	}
+	switch ( CSoundFile::Probe( static_cast<CSoundFile::ProbeFlags>( flags ), mpt::span<const mpt::byte>( mpt::byte_cast<const mpt::byte*>( buffer ), size_read ), seekable ? &filesize : nullptr ) ) {
+		case CSoundFile::ProbeSuccess:
+			result = probe_file_header_result_success;
+			break;
+		case CSoundFile::ProbeFailure:
+			result = probe_file_header_result_failure;
+			break;
+		case CSoundFile::ProbeWantMoreData:
+			result = probe_file_header_result_wantmoredata;
+			break;
+		default:
+			throw exception("internal error");
+			break;
+	}
+	return result;
+}
+int module_impl::probe_file_header( std::uint64_t flags, callback_stream_wrapper stream ) {
+	int result = 0;
+	char buffer[ PROBE_RECOMMENDED_SIZE ];
+	MemsetZero( buffer );
+	std::size_t size_read = 0;
+	std::size_t size_toread = CSoundFile::ProbeRecommendedSize;
+	if ( !stream.read ) {
+		throw exception("error reading stream");
+	}
+	CallbackStream fstream;
+	fstream.stream = stream.stream;
+	fstream.read = stream.read;
+	fstream.seek = stream.seek;
+	fstream.tell = stream.tell;
+	const bool seekable = FileDataContainerCallbackStreamSeekable::IsSeekable( fstream );
+	const uint64 filesize = ( seekable ? FileDataContainerCallbackStreamSeekable::GetLength( fstream ) : 0 );
+	while ( size_toread > 0 ) {
+		std::size_t read_count = stream.read( stream.stream, buffer + size_read, size_toread );
+		size_read += read_count;
+		size_toread -= read_count;
+		if ( read_count == 0 ) { // eof
+			break;
+		}
+	}
+	switch ( CSoundFile::Probe( static_cast<CSoundFile::ProbeFlags>( flags ), mpt::span<const mpt::byte>( mpt::byte_cast<const mpt::byte*>( buffer ), size_read ), seekable ? &filesize : nullptr ) ) {
+		case CSoundFile::ProbeSuccess:
+			result = probe_file_header_result_success;
+			break;
+		case CSoundFile::ProbeFailure:
+			result = probe_file_header_result_failure;
+			break;
+		case CSoundFile::ProbeWantMoreData:
+			result = probe_file_header_result_wantmoredata;
+			break;
+		default:
+			throw exception("internal error");
+			break;
+	}
+	return result;
+}
+module_impl::module_impl( callback_stream_wrapper stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
 	CallbackStream fstream;
 	fstream.stream = stream.stream;
 	fstream.read = stream.read;
 	fstream.seek = stream.seek;
 	fstream.tell = stream.tell;
-	load( FileReader( fstream ), ctls );
+	load( make_FileReader( fstream ), ctls );
 	apply_libopenmpt_defaults();
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( std::istream & stream, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( std::istream & stream, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+module_impl::module_impl( std::istream & stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
-	load( FileReader( &stream ), ctls );
+	load( make_FileReader( &stream ), ctls );
 	apply_libopenmpt_defaults();
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( const std::vector<std::uint8_t> & data, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( const std::vector<std::uint8_t> & data, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+module_impl::module_impl( const std::vector<std::uint8_t> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
-	load( FileReader( mpt::as_span( data ) ), ctls );
+	load( make_FileReader( mpt::as_span( data ) ), ctls );
 	apply_libopenmpt_defaults();
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( const std::vector<char> & data, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( const std::vector<char> & data, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+module_impl::module_impl( const std::vector<char> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
-	load( FileReader( mpt::byte_cast< mpt::span< const mpt::byte > >( mpt::as_span( data ) ) ), ctls );
+	load( make_FileReader( mpt::byte_cast< mpt::span< const mpt::byte > >( mpt::as_span( data ) ) ), ctls );
 	apply_libopenmpt_defaults();
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( const std::uint8_t * data, std::size_t size, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( const std::uint8_t * data, std::size_t size, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+module_impl::module_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
-	load( FileReader( mpt::as_span( data, size ) ), ctls );
+	load( make_FileReader( mpt::as_span( data, size ) ), ctls );
 	apply_libopenmpt_defaults();
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( const char * data, std::size_t size, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( const char * data, std::size_t size, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+module_impl::module_impl( const char * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
-	load( FileReader( mpt::byte_cast< mpt::span< const mpt::byte > >( mpt::as_span( data, size ) ) ), ctls );
+	load( make_FileReader( mpt::byte_cast< mpt::span< const mpt::byte > >( mpt::as_span( data, size ) ) ), ctls );
 	apply_libopenmpt_defaults();
 }
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-module_impl::module_impl( const void * data, std::size_t size, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#else
-module_impl::module_impl( const void * data, std::size_t size, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(log) {
-#endif
+module_impl::module_impl( const void * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
 	ctor( ctls );
-	load( FileReader( mpt::as_span( mpt::void_cast< const mpt::byte * >( data ), size ) ), ctls );
+	load( make_FileReader( mpt::as_span( mpt::void_cast< const mpt::byte * >( data ), size ) ), ctls );
 	apply_libopenmpt_defaults();
 }
 module_impl::~module_impl() {
@@ -721,7 +885,7 @@ void module_impl::set_render_param( int param, std::int32_t value ) {
 			}
 		} break;
 		case module::RENDER_INTERPOLATIONFILTER_LENGTH: {
-			CResamplerSettings newsettings;
+			CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings;
 			newsettings.SrcMode = filterlength_to_resamplingmode( value );
 			if ( newsettings != m_sndFile->m_Resampler.m_Settings ) {
 				m_sndFile->SetResamplerSettings( newsettings );
@@ -831,11 +995,7 @@ std::size_t module_impl::read_interleaved_quad( std::int32_t samplerate, std::si
 
 
 double module_impl::get_duration_seconds() const {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<subsongs_type> subsongs_temp = has_subsongs_inited() ? LIBOPENMPT_SHARED_PTR<subsongs_type>() : LIBOPENMPT_SHARED_PTR<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#else
-	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : std::unique_ptr<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#endif
+	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : mpt::make_unique<subsongs_type>( get_subsongs() );
 	const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp;
 	if ( m_current_subsong == all_subsongs ) {
 		// Play all subsongs consecutively.
@@ -848,11 +1008,7 @@ double module_impl::get_duration_seconds() const {
 	return subsongs[m_current_subsong].duration;
 }
 void module_impl::select_subsong( std::int32_t subsong ) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<subsongs_type> subsongs_temp = has_subsongs_inited() ? LIBOPENMPT_SHARED_PTR<subsongs_type>() : LIBOPENMPT_SHARED_PTR<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#else
-	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : std::unique_ptr<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#endif
+	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : mpt::make_unique<subsongs_type>( get_subsongs() );
 	const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp;
 	if ( subsong != all_subsongs && ( subsong < 0 || subsong >= static_cast<std::int32_t>( subsongs.size() ) ) ) {
 		throw openmpt::exception("invalid subsong");
@@ -866,6 +1022,9 @@ void module_impl::select_subsong( std::int32_t subsong ) {
 	set_position_order_row( subsongs[subsong].start_order, subsongs[subsong].start_row );
 	m_currentPositionSeconds = 0.0;
 }
+std::int32_t module_impl::get_selected_subsong() const {
+	return m_current_subsong;
+}
 void module_impl::set_repeat_count( std::int32_t repeat_count ) {
 	m_sndFile->SetRepeatCount( repeat_count );
 }
@@ -876,11 +1035,7 @@ double module_impl::get_position_seconds() const {
 	return m_currentPositionSeconds;
 }
 double module_impl::set_position_seconds( double seconds ) {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<subsongs_type> subsongs_temp = has_subsongs_inited() ? LIBOPENMPT_SHARED_PTR<subsongs_type>() : LIBOPENMPT_SHARED_PTR<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#else
-	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : std::unique_ptr<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#endif
+	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : mpt::make_unique<subsongs_type>( get_subsongs() );
 	const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp;
 	const subsong_data * subsong = 0;
 	double base_seconds = 0.0;
@@ -906,10 +1061,10 @@ double module_impl::set_position_seconds( double seconds ) {
 	return m_currentPositionSeconds;
 }
 double module_impl::set_position_order_row( std::int32_t order, std::int32_t row ) {
-	if ( order < 0 || order >= m_sndFile->Order.GetLengthTailTrimmed() ) {
+	if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) {
 		return m_currentPositionSeconds;
 	}
-	PATTERNINDEX pattern = m_sndFile->Order[order];
+	PATTERNINDEX pattern = m_sndFile->Order()[order];
 	if ( m_sndFile->Patterns.IsValidIndex( pattern ) ) {
 		if ( row < 0 || row >= static_cast<std::int32_t>( m_sndFile->Patterns[pattern].GetNumRows() ) ) {
 			return m_currentPositionSeconds;
@@ -940,15 +1095,15 @@ std::vector<std::string> module_impl::get_metadata_keys() const {
 }
 std::string module_impl::get_metadata( const std::string & key ) const {
 	if ( key == std::string("type") ) {
-		return CSoundFile::ModTypeToString( m_sndFile->GetType() );
+		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModTypeToString( m_sndFile->GetType() ) );
 	} else if ( key == std::string("type_long") ) {
-		return CSoundFile::ModTypeToTracker( m_sndFile->GetType() );
+		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModTypeToTracker( m_sndFile->GetType() ) );
 	} else if ( key == std::string("container") ) {
-		return CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() );
+		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() ) );
 	} else if ( key == std::string("container_long") ) {
-		return CSoundFile::ModContainerTypeToTracker( m_sndFile->GetContainerType() );
+		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModContainerTypeToTracker( m_sndFile->GetContainerType() ) );
 	} else if ( key == std::string("tracker") ) {
-		return m_sndFile->m_madeWithTracker;
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_madeWithTracker );
 	} else if ( key == std::string("artist") ) {
 		return mpt::ToCharset( mpt::CharsetUTF8, m_sndFile->m_songArtist );
 	} else if ( key == std::string("title") ) {
@@ -1021,10 +1176,10 @@ std::int32_t module_impl::get_current_order() const {
 }
 std::int32_t module_impl::get_current_pattern() const {
 	std::int32_t order = m_sndFile->GetCurrentOrder();
-	if ( order < 0 || order >= m_sndFile->Order.GetLengthTailTrimmed() ) {
+	if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) {
 		return m_sndFile->GetCurrentPattern();
 	}
-	std::int32_t pattern = m_sndFile->Order[order];
+	std::int32_t pattern = m_sndFile->Order()[order];
 	if ( !m_sndFile->Patterns.IsValidIndex( static_cast<PATTERNINDEX>( pattern ) ) ) {
 		return -1;
 	}
@@ -1071,11 +1226,7 @@ float module_impl::get_current_channel_vu_rear_right( std::int32_t channel ) con
 }
 
 std::int32_t module_impl::get_num_subsongs() const {
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<subsongs_type> subsongs_temp = has_subsongs_inited() ? LIBOPENMPT_SHARED_PTR<subsongs_type>() : LIBOPENMPT_SHARED_PTR<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#else
-	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : std::unique_ptr<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#endif
+	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : mpt::make_unique<subsongs_type>( get_subsongs() );
 	const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp;
 	return static_cast<std::int32_t>( subsongs.size() );
 }
@@ -1083,7 +1234,7 @@ std::int32_t module_impl::get_num_channels() const {
 	return m_sndFile->GetNumChannels();
 }
 std::int32_t module_impl::get_num_orders() const {
-	return m_sndFile->Order.GetLengthTailTrimmed();
+	return m_sndFile->Order().GetLengthTailTrimmed();
 }
 std::int32_t module_impl::get_num_patterns() const {
 	return m_sndFile->Patterns.GetNumPatterns();
@@ -1097,14 +1248,10 @@ std::int32_t module_impl::get_num_samples() const {
 
 std::vector<std::string> module_impl::get_subsong_names() const {
 	std::vector<std::string> retval;
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<subsongs_type> subsongs_temp = has_subsongs_inited() ? LIBOPENMPT_SHARED_PTR<subsongs_type>() : LIBOPENMPT_SHARED_PTR<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#else
-	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : std::unique_ptr<subsongs_type>( new subsongs_type( get_subsongs() ) );
-#endif
+	std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ?  std::unique_ptr<subsongs_type>() : mpt::make_unique<subsongs_type>( get_subsongs() );
 	const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp;
 	for ( std::size_t i = 0; i < subsongs.size(); ++i ) {
-		retval.push_back( mod_string_to_utf8( m_sndFile->Order.GetSequence( static_cast<SEQUENCEINDEX>( subsongs[i].sequence ) ).GetName() ) );
+		retval.push_back( mod_string_to_utf8( m_sndFile->Order( static_cast<SEQUENCEINDEX>( subsongs[i].sequence ) ).GetName() ) );
 	}
 	return retval;
 }
@@ -1117,10 +1264,10 @@ std::vector<std::string> module_impl::get_channel_names() const {
 }
 std::vector<std::string> module_impl::get_order_names() const {
 	std::vector<std::string> retval;
-	for ( ORDERINDEX i = 0; i < m_sndFile->Order.GetLengthTailTrimmed(); ++i ) {
-		PATTERNINDEX pat = m_sndFile->Order[i];
+	for ( ORDERINDEX i = 0; i < m_sndFile->Order().GetLengthTailTrimmed(); ++i ) {
+		PATTERNINDEX pat = m_sndFile->Order()[i];
 		if ( m_sndFile->Patterns.IsValidIndex( pat ) ) {
-			retval.push_back( mod_string_to_utf8( m_sndFile->Patterns[ m_sndFile->Order[i] ].GetName() ) );
+			retval.push_back( mod_string_to_utf8( m_sndFile->Patterns[ m_sndFile->Order()[i] ].GetName() ) );
 		} else {
 			if ( pat == m_sndFile->Order.GetIgnoreIndex() ) {
 				retval.push_back( "+++ skip" );
@@ -1156,10 +1303,10 @@ std::vector<std::string> module_impl::get_sample_names() const {
 }
 
 std::int32_t module_impl::get_order_pattern( std::int32_t o ) const {
-	if ( o < 0 || o >= m_sndFile->Order.GetLengthTailTrimmed() ) {
+	if ( o < 0 || o >= m_sndFile->Order().GetLengthTailTrimmed() ) {
 		return -1;
 	}
-	return m_sndFile->Order[o];
+	return m_sndFile->Order()[o];
 }
 std::int32_t module_impl::get_pattern_num_rows( std::int32_t p ) const {
 	if ( !IsInRange( p, std::numeric_limits<PATTERNINDEX>::min(), std::numeric_limits<PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<PATTERNINDEX>( p ) ) ) {
@@ -1169,26 +1316,27 @@ std::int32_t module_impl::get_pattern_num_rows( std::int32_t p ) const {
 }
 
 std::uint8_t module_impl::get_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const {
-	CHANNELINDEX numchannels = m_sndFile->GetNumChannels();
 	if ( !IsInRange( p, std::numeric_limits<PATTERNINDEX>::min(), std::numeric_limits<PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<PATTERNINDEX>( p ) ) ) {
 		return 0;
 	}
-	if ( r < 0 || r >= static_cast<std::int32_t>( m_sndFile->Patterns[p].GetNumRows() ) ) {
+	const CPattern &pattern = m_sndFile->Patterns[p];
+	if ( r < 0 || r >= static_cast<std::int32_t>( pattern.GetNumRows() ) ) {
 		return 0;
 	}
-	if ( c < 0 || c >= numchannels ) {
+	if ( c < 0 || c >= m_sndFile->GetNumChannels() ) {
 		return 0;
 	}
 	if ( cmd < module::command_note || cmd > module::command_parameter ) {
 		return 0;
 	}
+	const ModCommand & cell = *pattern.GetpModCommand( static_cast<ROWINDEX>( r ), static_cast<CHANNELINDEX>( c ) );
 	switch ( cmd ) {
-		case module::command_note: return m_sndFile->Patterns[p][r*numchannels+c].note; break;
-		case module::command_instrument: return m_sndFile->Patterns[p][r*numchannels+c].instr; break;
-		case module::command_volumeffect: return m_sndFile->Patterns[p][r*numchannels+c].volcmd; break;
-		case module::command_effect: return m_sndFile->Patterns[p][r*numchannels+c].command; break;
-		case module::command_volume: return m_sndFile->Patterns[p][r*numchannels+c].vol; break;
-		case module::command_parameter: return m_sndFile->Patterns[p][r*numchannels+c].param; break;
+		case module::command_note: return cell.note; break;
+		case module::command_instrument: return cell.instr; break;
+		case module::command_volumeffect: return cell.volcmd; break;
+		case module::command_effect: return cell.command; break;
+		case module::command_volume: return cell.vol; break;
+		case module::command_parameter: return cell.param; break;
 	}
 	return 0;
 }
@@ -1210,20 +1358,20 @@ f : generic effect column parameter
 */
 
 std::pair< std::string, std::string > module_impl::format_and_highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const {
-	CHANNELINDEX numchannels = m_sndFile->GetNumChannels();
 	if ( !IsInRange( p, std::numeric_limits<PATTERNINDEX>::min(), std::numeric_limits<PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<PATTERNINDEX>( p ) ) ) {
 		return std::make_pair( std::string(), std::string() );
 	}
-	if ( r < 0 || r >= static_cast<std::int32_t>( m_sndFile->Patterns[p].GetNumRows() ) ) {
+	const CPattern &pattern = m_sndFile->Patterns[p];
+	if ( r < 0 || r >= static_cast<std::int32_t>( pattern.GetNumRows() ) ) {
 		return std::make_pair( std::string(), std::string() );
 	}
-	if ( c < 0 || c >= numchannels ) {
+	if ( c < 0 || c >= m_sndFile->GetNumChannels() ) {
 		return std::make_pair( std::string(), std::string() );
 	}
 	if ( cmd < module::command_note || cmd > module::command_parameter ) {
 		return std::make_pair( std::string(), std::string() );
 	}
-	const ModCommand & cell = m_sndFile->Patterns[p][r*numchannels+c];
+	const ModCommand & cell = *pattern.GetpModCommand( static_cast<ROWINDEX>( r ), static_cast<CHANNELINDEX>( c ) );
 	switch ( cmd ) {
 		case module::command_note:
 			return std::make_pair(
@@ -1280,20 +1428,20 @@ std::string module_impl::highlight_pattern_row_channel_command( std::int32_t p,
 std::pair< std::string, std::string > module_impl::format_and_highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const {
 	std::string text = pad ? std::string( width, ' ' ) : std::string();
 	std::string high = pad ? std::string( width, ' ' ) : std::string();
-	const CHANNELINDEX numchannels = m_sndFile->GetNumChannels();
 	if ( !IsInRange( p, std::numeric_limits<PATTERNINDEX>::min(), std::numeric_limits<PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<PATTERNINDEX>( p ) ) ) {
 		return std::make_pair( text, high );
 	}
-	if ( r < 0 || r >= static_cast<std::int32_t>( m_sndFile->Patterns[p].GetNumRows() ) ) {
+	const CPattern &pattern = m_sndFile->Patterns[p];
+	if ( r < 0 || r >= static_cast<std::int32_t>( pattern.GetNumRows() ) ) {
 		return std::make_pair( text, high );
 	}
-	if ( c < 0 || c >= numchannels ) {
+	if ( c < 0 || c >= m_sndFile->GetNumChannels() ) {
 		return std::make_pair( text, high );
 	}
 	//  0000000001111
 	//  1234567890123
 	// "NNN IIvVV EFF"
-	const ModCommand cell = m_sndFile->Patterns[p][r*numchannels+c];
+	const ModCommand & cell = *pattern.GetpModCommand( static_cast<ROWINDEX>( r ), static_cast<CHANNELINDEX>( c ) );
 	text.clear();
 	high.clear();
 	text += ( cell.IsNote() || cell.IsSpecialNote() ) ? m_sndFile->GetNoteName( cell.note, cell.instr ) : std::string("...");
@@ -1343,16 +1491,17 @@ std::vector<std::string> module_impl::get_ctls() const {
 	retval.push_back( "subsong" );
 	retval.push_back( "play.tempo_factor" );
 	retval.push_back( "play.pitch_factor" );
+	retval.push_back( "render.resampler.emulate_amiga" );
 	retval.push_back( "dither" );
 	return retval;
 }
 std::string module_impl::ctl_get( std::string ctl, bool throw_if_unknown ) const {
 	if ( !ctl.empty() ) {
-		std::string rightmost = ctl.substr( ctl.length() - 1, 1 );
-		if ( rightmost == "!" || rightmost == "?" ) {
-			if ( rightmost == "!" ) {
+		char rightmost = ctl.back();
+		if ( rightmost == '!' || rightmost == '?' ) {
+			if ( rightmost == '!' ) {
 				throw_if_unknown = true;
-			} else if ( rightmost == "?" ) {
+			} else if ( rightmost == '?' ) {
 				throw_if_unknown = false;
 			}
 			ctl = ctl.substr( 0, ctl.length() - 1 );
@@ -1361,29 +1510,31 @@ std::string module_impl::ctl_get( std::string ctl, bool throw_if_unknown ) const
 	if ( ctl == "" ) {
 		throw openmpt::exception("empty ctl");
 	} else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) {
-		return mpt::ToString( m_ctl_load_skip_samples );
+		return mpt::fmt::val( m_ctl_load_skip_samples );
 	} else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) {
-		return mpt::ToString( m_ctl_load_skip_patterns );
+		return mpt::fmt::val( m_ctl_load_skip_patterns );
 	} else if ( ctl == "load.skip_plugins" ) {
-		return mpt::ToString( m_ctl_load_skip_plugins );
+		return mpt::fmt::val( m_ctl_load_skip_plugins );
 	} else if ( ctl == "load.skip_subsongs_init" ) {
-		return mpt::ToString( m_ctl_load_skip_subsongs_init );
+		return mpt::fmt::val( m_ctl_load_skip_subsongs_init );
 	} else if ( ctl == "seek.sync_samples" ) {
-		return mpt::ToString( m_ctl_seek_sync_samples );
+		return mpt::fmt::val( m_ctl_seek_sync_samples );
 	} else if ( ctl == "subsong" ) {
-		return mpt::ToString( m_current_subsong );
+		return mpt::fmt::val( get_selected_subsong() );
 	} else if ( ctl == "play.tempo_factor" ) {
 		if ( !is_loaded() ) {
 			return "1.0";
 		}
-		return mpt::ToString( 65536.0 / m_sndFile->m_nTempoFactor );
+		return mpt::fmt::val( 65536.0 / m_sndFile->m_nTempoFactor );
 	} else if ( ctl == "play.pitch_factor" ) {
 		if ( !is_loaded() ) {
 			return "1.0";
 		}
-		return mpt::ToString( m_sndFile->m_nFreqFactor / 65536.0 );
+		return mpt::fmt::val( m_sndFile->m_nFreqFactor / 65536.0 );
+	} else if ( ctl == "render.resampler.emulate_amiga" ) {
+		return mpt::fmt::val( m_sndFile->m_Resampler.m_Settings.emulateAmiga );
 	} else if ( ctl == "dither" ) {
-		return mpt::ToString( static_cast<int>( m_Dither->GetMode() ) );
+		return mpt::fmt::val( static_cast<int>( m_Dither->GetMode() ) );
 	} else {
 		if ( throw_if_unknown ) {
 			throw openmpt::exception("unknown ctl: " + ctl);
@@ -1394,11 +1545,11 @@ std::string module_impl::ctl_get( std::string ctl, bool throw_if_unknown ) const
 }
 void module_impl::ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown ) {
 	if ( !ctl.empty() ) {
-		std::string rightmost = ctl.substr( ctl.length() - 1, 1 );
-		if ( rightmost == "!" || rightmost == "?" ) {
-			if ( rightmost == "!" ) {
+		char rightmost = ctl.back();
+		if ( rightmost == '!' || rightmost == '?' ) {
+			if ( rightmost == '!' ) {
 				throw_if_unknown = true;
-			} else if ( rightmost == "?" ) {
+			} else if ( rightmost == '?' ) {
 				throw_if_unknown = false;
 			}
 			ctl = ctl.substr( 0, ctl.length() - 1 );
@@ -1438,8 +1589,18 @@ void module_impl::ctl_set( std::string ctl, const std::string & value, bool thro
 		}
 		m_sndFile->m_nFreqFactor = Util::Round<uint32_t>( 65536.0 * factor );
 		m_sndFile->RecalculateSamplesPerTick();
+	} else if ( ctl == "render.resampler.emulate_amiga" ) {
+		CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings;
+		newsettings.emulateAmiga = ConvertStrTo<bool>( value );
+		if ( newsettings != m_sndFile->m_Resampler.m_Settings ) {
+			m_sndFile->SetResamplerSettings( newsettings );
+		}
 	} else if ( ctl == "dither" ) {
-		m_Dither->SetMode( static_cast<DitherMode>( ConvertStrTo<int>( value ) ) );
+		int dither = ConvertStrTo<int>( value );
+		if ( dither < 0 || dither >= NumDitherModes ) {
+			dither = DitherDefault;
+		}
+		m_Dither->SetMode( static_cast<DitherMode>( dither ) );
 	} else {
 		if ( throw_if_unknown ) {
 			throw openmpt::exception("unknown ctl: " + ctl + " := " + value);
diff --git a/libopenmpt/libopenmpt_impl.hpp b/libopenmpt/libopenmpt_impl.hpp
index ae0bcc9..0cf6569 100644
--- a/libopenmpt/libopenmpt_impl.hpp
+++ b/libopenmpt/libopenmpt_impl.hpp
@@ -14,11 +14,6 @@
 #include "libopenmpt.hpp"
 
 #include <iosfwd>
-#ifdef LIBOPENMPT_ANCIENT_COMPILER
-#if defined(__GNUC__)
-#include <tr1/memory>
-#endif
-#endif
 #include <memory>
 
 #if defined(_MSC_VER)
@@ -28,7 +23,13 @@
 
 // forward declarations
 namespace OpenMPT {
+class FileReaderTraitsStdStream;
+typedef FileReaderTraitsStdStream FileReaderTraitsDefault;
+namespace detail {
+template <typename Tbase>
 class FileReader;
+} // namespace detail
+typedef detail::FileReader<FileReaderTraitsDefault> FileReader;
 class CSoundFile;
 class Dither;
 } // namespace OpenMPT
@@ -80,29 +81,13 @@ protected:
 	}; // struct subsong_data
 	typedef std::vector<subsong_data> subsongs_type;
 	static const std::int32_t all_subsongs = -1;
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<log_interface> m_Log;
-#else
-	std::shared_ptr<log_interface> m_Log;
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<log_forwarder> m_LogForwarder;
-#else
+	std::unique_ptr<log_interface> m_Log;
 	std::unique_ptr<log_forwarder> m_LogForwarder;
-#endif
 	std::int32_t m_current_subsong;
 	double m_currentPositionSeconds;
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<OpenMPT::CSoundFile> m_sndFile;
-#else
 	std::unique_ptr<OpenMPT::CSoundFile> m_sndFile;
-#endif
 	bool m_loaded;
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	LIBOPENMPT_SHARED_PTR<OpenMPT::Dither> m_Dither;
-#else
 	std::unique_ptr<OpenMPT::Dither> m_Dither;
-#endif
 	subsongs_type m_subsongs;
 	float m_Gain;
 	bool m_ctl_load_skip_samples;
@@ -130,62 +115,31 @@ protected:
 	std::size_t read_interleaved_wrapper( std::size_t count, std::size_t channels, float * interleaved );
 	std::pair< std::string, std::string > format_and_highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int command ) const;
 	std::pair< std::string, std::string > format_and_highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const;
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	static double could_open_propability( const OpenMPT::FileReader & file, double effort, LIBOPENMPT_SHARED_PTR<log_interface> log );
-#else
-	static double could_open_propability( const OpenMPT::FileReader & file, double effort, std::shared_ptr<log_interface> log );
-#endif
+	static double could_open_probability( const OpenMPT::FileReader & file, double effort, std::unique_ptr<log_interface> log );
 public:
 	static std::vector<std::string> get_supported_extensions();
+	static bool is_extension_supported( const char * extension );
 	static bool is_extension_supported( const std::string & extension );
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	static double could_open_propability( callback_stream_wrapper stream, double effort, LIBOPENMPT_SHARED_PTR<log_interface> log );
-#else
-	static double could_open_propability( callback_stream_wrapper stream, double effort, std::shared_ptr<log_interface> log );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	static double could_open_propability( std::istream & stream, double effort, LIBOPENMPT_SHARED_PTR<log_interface> log );
-#else
-	static double could_open_propability( std::istream & stream, double effort, std::shared_ptr<log_interface> log );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( callback_stream_wrapper stream, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( callback_stream_wrapper stream, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( std::istream & stream, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( std::istream & stream, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( const std::vector<std::uint8_t> & data, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( const std::vector<std::uint8_t> & data, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( const std::vector<char> & data, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( const std::vector<char> & data, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( const std::uint8_t * data, std::size_t size, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( const std::uint8_t * data, std::size_t size, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( const char * data, std::size_t size, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( const char * data, std::size_t size, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
-#ifdef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-	module_impl( const void * data, std::size_t size, LIBOPENMPT_SHARED_PTR<log_interface> log, const std::map< std::string, std::string > & ctls );
-#else
-	module_impl( const void * data, std::size_t size, std::shared_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
-#endif
+	static double could_open_probability( callback_stream_wrapper stream, double effort, std::unique_ptr<log_interface> log );
+	static double could_open_probability( std::istream & stream, double effort, std::unique_ptr<log_interface> log );
+	static std::size_t probe_file_header_get_recommended_size();
+	static int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size, std::uint64_t filesize );
+	static int probe_file_header( std::uint64_t flags, const void * data, std::size_t size, std::uint64_t filesize );
+	static int probe_file_header( std::uint64_t flags, const std::uint8_t * data, std::size_t size );
+	static int probe_file_header( std::uint64_t flags, const void * data, std::size_t size );
+	static int probe_file_header( std::uint64_t flags, std::istream & stream );
+	static int probe_file_header( std::uint64_t flags, callback_stream_wrapper stream );
+	module_impl( callback_stream_wrapper stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_impl( std::istream & stream, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_impl( const std::vector<std::uint8_t> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_impl( const std::vector<char> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_impl( const std::uint8_t * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_impl( const char * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
+	module_impl( const void * data, std::size_t size, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls );
 	~module_impl();
 public:
 	void select_subsong( std::int32_t subsong );
+	std::int32_t get_selected_subsong() const;
 	void set_repeat_count( std::int32_t repeat_count );
 	std::int32_t get_repeat_count() const;
 	double get_duration_seconds() const;
@@ -241,6 +195,14 @@ public:
 	void ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown = true );
 }; // class module_impl
 
+namespace helper {
+
+template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {
+	return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+} // namespace helper
+
 } // namespace openmpt
 
 #if defined(_MSC_VER)
diff --git a/libopenmpt/libopenmpt_internal.h b/libopenmpt/libopenmpt_internal.h
index ce8e925..6765898 100644
--- a/libopenmpt/libopenmpt_internal.h
+++ b/libopenmpt/libopenmpt_internal.h
@@ -33,51 +33,4 @@
 #endif
 
 
-#if defined(_MSC_VER)
-#if (_MSC_VER >= 1500) && (_MSC_VER < 1600)
-#ifndef LIBOPENMPT_ANCIENT_COMPILER
-#define LIBOPENMPT_ANCIENT_COMPILER
-#endif
-#ifndef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-#define LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-#define LIBOPENMPT_SHARED_PTR std::tr1::shared_ptr
-#endif
-#endif
-#endif
-
-#if defined(__GNUC__) && !defined(__clang__)
-#if (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1 < 40300)
-#ifndef LIBOPENMPT_ANCIENT_COMPILER
-#define LIBOPENMPT_ANCIENT_COMPILER
-#endif
-#ifndef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-#define LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-#define LIBOPENMPT_SHARED_PTR std::tr1::shared_ptr
-#endif
-#elif (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1 < 40400)
-#ifndef LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-#define LIBOPENMPT_ANCIENT_COMPILER_SHARED_PTR
-#define LIBOPENMPT_SHARED_PTR std::shared_ptr 
-#endif
-#endif
-#endif
-
-
-#ifdef __cplusplus
-#ifdef LIBOPENMPT_QUIRK_NO_CSTDINT
-#include <stdint.h>
-namespace std {
-typedef ::int8_t   int8_t;
-typedef ::int16_t  int16_t;
-typedef ::int32_t  int32_t;
-typedef ::int64_t  int64_t;
-typedef ::uint8_t  uint8_t; 
-typedef ::uint16_t uint16_t; 
-typedef ::uint32_t uint32_t;
-typedef ::uint64_t uint64_t;
-}
-#endif
-#endif
-
-
-#endif // LIBOPENMPT_INTERNAL_H
+#endif /* LIBOPENMPT_INTERNAL_H */
diff --git a/libopenmpt/libopenmpt_modplug.c b/libopenmpt/libopenmpt_modplug.c
index 2423722..e427b79 100644
--- a/libopenmpt/libopenmpt_modplug.c
+++ b/libopenmpt/libopenmpt_modplug.c
@@ -129,7 +129,7 @@ LIBOPENMPT_MODPLUG_API ModPlugFile* ModPlug_Load(const void* data, int size)
 	if(!file) return NULL;
 	memset(file,0,sizeof(ModPlugFile));
 	memcpy(&file->settings,&globalsettings,sizeof(ModPlug_Settings));
-	file->mod = openmpt_module_create_from_memory(data,size,NULL,NULL,NULL);
+	file->mod = openmpt_module_create_from_memory2(data,size,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
 	if(!file->mod){
 		free(file);
 		return NULL;
diff --git a/libopenmpt/libopenmpt_modplug_cpp.cpp b/libopenmpt/libopenmpt_modplug_cpp.cpp
index b5bb080..48878b7 100644
--- a/libopenmpt/libopenmpt_modplug_cpp.cpp
+++ b/libopenmpt/libopenmpt_modplug_cpp.cpp
@@ -95,6 +95,13 @@ static openmpt::module * get_self( const CSoundFile * that ) {
 
 #define mod ( get_self( this ) )
 
+#define update_state() \
+	if ( mod ) m_nCurrentPattern = mod->get_current_order(); \
+	if ( mod ) m_nPattern = mod->get_current_pattern(); \
+	if ( mod ) m_nMusicSpeed = mod->get_current_speed(); \
+	if ( mod ) m_nMusicTempo = mod->get_current_tempo(); \
+/**/
+
 UINT CSoundFile::m_nXBassDepth = 0;
 UINT CSoundFile::m_nXBassRange = 0;
 UINT CSoundFile::m_nReverbDepth = 0;
@@ -246,6 +253,7 @@ BOOL CSoundFile::Create( LPCBYTE lpStream, DWORD dwMemLength ) {
 		m_nChannels = mod->get_num_channels();
 		m_nMasterVolume = 128;
 		m_nSamples = mod->get_num_samples();
+		update_state();
 		return TRUE;
 	} catch ( ... ) {
 		Destroy();
@@ -267,8 +275,8 @@ UINT CSoundFile::GetNumChannels() const {
 	return mod->get_num_channels();
 }
 
-static int vol128_To_millibel( unsigned int vol ) {
-	return static_cast<int>( 2000.0 * std::log10( static_cast<int>( vol ) / 128.0 ) );
+static std::int32_t vol128_To_millibel( unsigned int vol ) {
+	return static_cast<std::int32_t>( 2000.0 * std::log10( static_cast<int>( vol ) / 128.0 ) );
 }
 
 BOOL CSoundFile::SetMasterVolume( UINT vol, BOOL bAdjustAGC ) {
@@ -292,26 +300,41 @@ UINT CSoundFile::GetNumInstruments() const {
 void CSoundFile::SetCurrentOrder( UINT nOrder ) {
 	mpcpplog();
 	mod->set_position_order_row( nOrder, 0 );
+	update_state();
 }
 
 UINT CSoundFile::GetSampleName( UINT nSample, LPSTR s ) const {
-	UNUSED(nSample);
 	mpcpplog();
 	if ( !s ) {
 		return 0;
 	}
-	// todo
-	return 0;
+	char buf[32];
+	std::memset( buf, 0, 32 );
+	if ( mod ) {
+		std::vector<std::string> names = mod->get_sample_names();
+		if ( 1 <= nSample && nSample <= names.size() ) {
+			std::strncpy( buf, names[ nSample - 1 ].c_str(), 31 );
+		}
+	}
+	std::memcpy( s, buf, 32 );
+	return static_cast<UINT>( std::strlen( buf ) );
 }
 
 UINT CSoundFile::GetInstrumentName( UINT nInstr, LPSTR s ) const {
-	UNUSED(nInstr);
 	mpcpplog();
 	if ( !s ) {
 		return 0;
 	}
-	// todo
-	return 0;
+	char buf[32];
+	std::memset( buf, 0, 32 );
+	if ( mod ) {
+		std::vector<std::string> names = mod->get_instrument_names();
+		if ( 1 <= nInstr && nInstr <= names.size() ) {
+			std::strncpy( buf, names[ nInstr - 1 ].c_str(), 31 );
+		}
+	}
+	std::memcpy( s, buf, 32 );
+	return static_cast<UINT>( std::strlen( buf ) );
 }
 
 void CSoundFile::LoopPattern( int nPat, int nRow ) {
@@ -635,6 +658,7 @@ UINT CSoundFile::GetRawSongComments( LPSTR s, UINT cbsize, UINT linesize ) {
 void CSoundFile::SetCurrentPos( UINT nPos ) {
 	mpcpplog();
 	if ( mod ) mod->set_position_seconds( nPos );
+	update_state();
 }
 
 UINT CSoundFile::GetCurrentPos() const {
@@ -734,7 +758,8 @@ UINT CSoundFile::Read( LPVOID lpBuffer, UINT cbBuffer ) {
 			dst[sample] = tmpbuf[sample] << (32-16-1-MIXING_ATTENUATION);
 		}
 	}
-	return static_cast<UINT>( frames_rendered * get_frame_size() );
+	update_state();
+	return static_cast<UINT>( frames_rendered );
 }
 
 
diff --git a/libopenmpt/libopenmpt_stream_callbacks_buffer.h b/libopenmpt/libopenmpt_stream_callbacks_buffer.h
new file mode 100644
index 0000000..8111cfd
--- /dev/null
+++ b/libopenmpt/libopenmpt_stream_callbacks_buffer.h
@@ -0,0 +1,179 @@
+/*
+ * libopenmpt_stream_callbacks_buffer.h
+ * ------------------------------------
+ * Purpose: libopenmpt public c interface
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H
+#define LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H
+
+#include "libopenmpt.h"
+
+/* The use of this header requires:
+
+#include <libopenmpt/libopenmpt.h>
+#if defined( LIBOPENMPT_STREAM_CALLBACKS_BUFFER )
+#include <libopenmpt/libopenmpt_stream_callbacks_buffer.h>
+#else
+#error "libopenmpt too old."
+#endif
+
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct openmpt_stream_buffer {
+	const void * file_data; /* or prefix data IFF prefix_size < file_size */
+	int64_t file_size;
+	int64_t file_pos;
+	int64_t prefix_size;
+	int overflow;
+} openmpt_stream_buffer;
+
+static size_t openmpt_stream_buffer_read_func( void * stream, void * dst, size_t bytes ) {
+	openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream;
+	int64_t offset = 0;
+	int64_t begpos = 0;
+	int64_t endpos = 0;
+	size_t valid_bytes = 0;
+	if ( !s ) {
+		return 0;
+	}
+	offset = bytes;
+	begpos = s->file_pos;
+	endpos = s->file_pos;
+	valid_bytes = 0;
+	endpos = (uint64_t)endpos + (uint64_t)offset;
+	if ( ( offset > 0 ) && !( (uint64_t)endpos > (uint64_t)begpos ) ) {
+		/* integer wrapped */
+		return 0;
+	}
+	if ( bytes == 0 ) {
+		return 0;
+	}
+	if ( begpos >= s->file_size ) {
+		return 0;
+	}
+	if ( endpos > s->file_size ) {
+		/* clip to eof */
+		bytes = bytes - (size_t)( endpos - s->file_size );
+		endpos = endpos - ( endpos - s->file_size );
+	}
+	memset( dst, 0, bytes );
+	if ( begpos >= s->prefix_size ) {
+		s->overflow = 1;
+		valid_bytes = 0;
+	} else if ( endpos > s->prefix_size ) {
+		s->overflow = 1;
+		valid_bytes = bytes - (size_t)( endpos - s->prefix_size );
+	} else {
+		valid_bytes = bytes;
+	}
+	memcpy( dst, (const char*)s->file_data + s->file_pos, valid_bytes );
+	s->file_pos = s->file_pos + bytes;
+	return bytes;
+}
+
+static int openmpt_stream_buffer_seek_func( void * stream, int64_t offset, int whence ) {
+	openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream;
+	int result = -1;
+	if ( !s ) {
+		return -1;
+	}
+	switch ( whence ) {
+		case OPENMPT_STREAM_SEEK_SET:
+			if ( offset < 0 ) {
+				return -1;
+			}
+			if ( offset > s->file_size ) {
+				return -1;
+			}
+			s->file_pos = offset;
+			result = 0;
+			break;
+		case OPENMPT_STREAM_SEEK_CUR:
+			do {
+				int64_t oldpos = s->file_pos;
+				int64_t pos = s->file_pos;
+				pos = (uint64_t)pos + (uint64_t)offset;
+				if ( ( offset > 0 ) && !( (uint64_t)pos > (uint64_t)oldpos ) ) {
+					/* integer wrapped */
+					return -1;
+				}
+				if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) {
+					/* integer wrapped */
+					return -1;
+				}
+				s->file_pos = pos;
+			} while(0);
+			result = 0;
+			break;
+		case OPENMPT_STREAM_SEEK_END:
+			if ( offset > 0 ) {
+				return -1;
+			}
+			do {
+				int64_t oldpos = s->file_pos;
+				int64_t pos = s->file_pos;
+				pos = s->file_size;
+				pos = (uint64_t)pos + (uint64_t)offset;
+				if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) {
+					/* integer wrapped */
+					return -1;
+				}
+				s->file_pos = pos;
+			} while(0);
+			result = 0;
+			break;
+	}
+	return result;
+}
+
+static int64_t openmpt_stream_buffer_tell_func( void * stream ) {
+	openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream;
+	if ( !s ) {
+		return -1;
+	}
+	return s->file_pos;
+}
+
+static void openmpt_stream_buffer_init( openmpt_stream_buffer * buffer, const void * file_data, int64_t file_size ) {
+	memset( buffer, 0, sizeof( openmpt_stream_buffer ) );
+	buffer->file_data = file_data;
+	buffer->file_size = file_size;
+	buffer->file_pos = 0;
+	buffer->prefix_size = file_size;
+	buffer->overflow = 0;
+}
+
+#define openmpt_stream_buffer_init_prefix_only( buffer_, prefix_data_, prefix_size_, file_size_ ) do { \
+	openmpt_stream_buffer_init( (buffer_), (prefix_data_), (file_size_) ); \
+	(buffer_)->prefix_size = (prefix_size_); \
+} while(0)
+
+#define openmpt_stream_buffer_overflowed( buffer_ ) ( (buffer_)->overflow )
+
+static openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks(void) {
+	openmpt_stream_callbacks retval;
+	memset( &retval, 0, sizeof( openmpt_stream_callbacks ) );
+	retval.read = openmpt_stream_buffer_read_func;
+	retval.seek = openmpt_stream_buffer_seek_func;
+	retval.tell = openmpt_stream_buffer_tell_func;
+	return retval;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H */
+
diff --git a/libopenmpt/libopenmpt_version.h b/libopenmpt/libopenmpt_version.h
index 7d4fac9..78c630e 100644
--- a/libopenmpt/libopenmpt_version.h
+++ b/libopenmpt/libopenmpt_version.h
@@ -17,14 +17,56 @@
 /*! \brief libopenmpt major version number */
 #define OPENMPT_API_VERSION_MAJOR 0
 /*! \brief libopenmpt minor version number */
-#define OPENMPT_API_VERSION_MINOR 2
+#define OPENMPT_API_VERSION_MINOR 3
+/*! \brief libopenmpt patch version number */
+#define OPENMPT_API_VERSION_PATCH 1
+/*! \brief libopenmpt pre-release tag */
+#define OPENMPT_API_VERSION_PREREL ""
+/*! \brief libopenmpt pre-release flag */
+#define OPENMPT_API_VERSION_IS_PREREL 0
+
+/*! \brief libopenmpt version number as a single integer value
+ *  \since 0.3
+ *  \remarks Use the following shim if you need to support earlier libopenmpt versions:
+ *           \code
+ *           #include <libopenmpt/libopenmpt_version.h>
+ *           #if !defined(OPENMPT_API_VERSION_MAKE)
+ *           #define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0))
+ *           #endif
+ *           \endcode
+ */
+#define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0))
 
 /*! \brief libopenmpt API version number */
-#define OPENMPT_API_VERSION ((OPENMPT_API_VERSION_MAJOR<<24)|(OPENMPT_API_VERSION_MINOR<<16))
+#define OPENMPT_API_VERSION OPENMPT_API_VERSION_MAKE(OPENMPT_API_VERSION_MAJOR, OPENMPT_API_VERSION_MINOR, OPENMPT_API_VERSION_PATCH)
+
+/*! \brief Check whether the libopenmpt API is at least the provided version
+ *  \since 0.3
+ *  \remarks Use the following shim if you need to support earlier libopenmpt versions:
+ *           \code
+ *           #include <libopenmpt/libopenmpt_version.h>
+ *           #if !defined(OPENMPT_API_VERSION_AT_LEAST)
+ *           #define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch)))
+ *           #endif
+ *           \endcode
+ */
+#define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch)))
+
+/*! \brief Check whether the libopenmpt API is before the provided version
+ *  \since 0.3
+ *  \remarks Use the following shim if you need to support earlier libopenmpt versions:
+ *           \code
+ *           #include <libopenmpt/libopenmpt_version.h>
+ *           #if !defined(OPENMPT_API_VERSION_BEFORE)
+ *           #define OPENMPT_API_VERSION_BEFORE(major, minor, patch) (OPENMPT_API_VERSION < OPENMPT_API_VERSION_MAKE((major), (minor), (patch)))
+ *           #endif
+ *           \endcode
+ */
+#define OPENMPT_API_VERSION_BEFORE(major, minor, patch) (OPENMPT_API_VERSION < OPENMPT_API_VERSION_MAKE((major), (minor), (patch)))
 
 #define OPENMPT_API_VERSION_HELPER_STRINGIZE(x) #x
 #define OPENMPT_API_VERSION_STRINGIZE(x) OPENMPT_API_VERSION_HELPER_STRINGIZE(x)
-#define OPENMPT_API_VERSION_STRING OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_MAJOR) "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_MINOR)
+#define OPENMPT_API_VERSION_STRING OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_MAJOR) "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_MINOR) "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_PATCH) OPENMPT_API_VERSION_PREREL
 
 /*!
   @}
diff --git a/libopenmpt/libopenmpt_version.mk b/libopenmpt/libopenmpt_version.mk
new file mode 100644
index 0000000..bbd79be
--- /dev/null
+++ b/libopenmpt/libopenmpt_version.mk
@@ -0,0 +1,8 @@
+LIBOPENMPT_VERSION_MAJOR=0
+LIBOPENMPT_VERSION_MINOR=3
+LIBOPENMPT_VERSION_PATCH=1
+LIBOPENMPT_VERSION_PREREL=
+
+LIBOPENMPT_LTVER_CURRENT=1
+LIBOPENMPT_LTVER_REVISION=1
+LIBOPENMPT_LTVER_AGE=1
diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4
index 1d38b76..08f2e07 100644
--- a/m4/ax_append_flag.m4
+++ b/m4/ax_append_flag.m4
@@ -49,21 +49,23 @@
 #   modified version of the Autoconf Macro, you may extend this special
 #   exception to the GPL to apply to your modified version as well.
 
-#serial 2
+#serial 6
 
 AC_DEFUN([AX_APPEND_FLAG],
-[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
-AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
-AS_VAR_SET_IF(FLAGS,
-  [case " AS_VAR_GET(FLAGS) " in
-    *" $1 "*)
-      AC_RUN_LOG([: FLAGS already contains $1])
-      ;;
-    *)
-      AC_RUN_LOG([: FLAGS="$FLAGS $1"])
-      AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
-      ;;
-   esac],
-  [AS_VAR_SET(FLAGS,["$1"])])
+[dnl
+AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
+AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
+AS_VAR_SET_IF(FLAGS,[
+  AS_CASE([" AS_VAR_GET(FLAGS) "],
+    [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
+    [
+     AS_VAR_APPEND(FLAGS,[" $1"])
+     AC_RUN_LOG([: FLAGS="$FLAGS"])
+    ])
+  ],
+  [
+  AS_VAR_SET(FLAGS,[$1])
+  AC_RUN_LOG([: FLAGS="$FLAGS"])
+  ])
 AS_VAR_POPDEF([FLAGS])dnl
 ])dnl AX_APPEND_FLAG
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
index 51df0c0..ca36397 100644
--- a/m4/ax_check_compile_flag.m4
+++ b/m4/ax_check_compile_flag.m4
@@ -55,10 +55,10 @@
 #   modified version of the Autoconf Macro, you may extend this special
 #   exception to the GPL to apply to your modified version as well.
 
-#serial 3
+#serial 4
 
 AC_DEFUN([AX_CHECK_COMPILE_FLAG],
-[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
 AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
 AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
   ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
@@ -67,7 +67,7 @@ AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
     [AS_VAR_SET(CACHEVAR,[yes])],
     [AS_VAR_SET(CACHEVAR,[no])])
   _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
-AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
+AS_VAR_IF(CACHEVAR,yes,
   [m4_default([$2], :)],
   [m4_default([$3], :)])
 AS_VAR_POPDEF([CACHEVAR])dnl
diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000..2c18e49
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,562 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXX and
+#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
+#   or '14' (for the C++14 standard).
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz at redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw at panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr at ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov at google.com>
+#   Copyright (c) 2015 Paul Norman <penorman at mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz at klammler.eu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 4
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [],
+        [$1], [14], [],
+        [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+  ax_cv_cxx_compile_cxx$1,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+    [ax_cv_cxx_compile_cxx$1=yes],
+    [ax_cv_cxx_compile_cxx$1=no])])
+  if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=gnu++$1 -std=gnu++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX$1=0
+    AC_MSG_NOTICE([No compiler with C++$1 support was found])
+  else
+    HAVE_CXX$1=1
+    AC_DEFINE(HAVE_CXX$1,1,
+              [define if the compiler supports basic C++$1 syntax])
+  fi
+  AC_SUBST(HAVE_CXX$1)
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_seperators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4
index 163a4c6..0aadeaf 100644
--- a/m4/ax_cxx_compile_stdcxx_11.m4
+++ b/m4/ax_cxx_compile_stdcxx_11.m4
@@ -4,139 +4,36 @@
 #
 # SYNOPSIS
 #
-#   AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
 #
 # DESCRIPTION
 #
 #   Check for baseline language coverage in the compiler for the C++11
-#   standard; if necessary, add switches to CXXFLAGS to enable support.
+#   standard; if necessary, add switches to CXX and CXXCPP to enable
+#   support.
 #
-#   The first argument, if specified, indicates whether you insist on an
-#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
-#   -std=c++11).  If neither is specified, you get whatever works, with
-#   preference for an extended mode.
-#
-#   The second argument, if specified 'mandatory' or if left unspecified,
-#   indicates that baseline C++11 support is required and that the macro
-#   should error out if no mode with that support is found.  If specified
-#   'optional', then configuration proceeds regardless, after defining
-#   HAVE_CXX11 if and only if a supporting mode is found.
+#   This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
+#   macro with the version set to C++11.  The two optional arguments are
+#   forwarded literally as the second and third argument respectively.
+#   Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
+#   more information.  If you want to use this macro, you also need to
+#   download the ax_cxx_compile_stdcxx.m4 file.
 #
 # LICENSE
 #
 #   Copyright (c) 2008 Benjamin Kosnik <bkoz at redhat.com>
 #   Copyright (c) 2012 Zack Weinberg <zackw at panix.com>
 #   Copyright (c) 2013 Roy Stogner <roystgnr at ices.utexas.edu>
-#   Copyright (c) 2014 Alexey Sokolov <sokolov at google.com>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov at google.com>
+#   Copyright (c) 2015 Paul Norman <penorman at mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz at klammler.eu>
 #
 #   Copying and distribution of this file, with or without modification, are
 #   permitted in any medium without royalty provided the copyright notice
 #   and this notice are preserved. This file is offered as-is, without any
 #   warranty.
 
-#serial 4
-
-m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
-  template <typename T>
-    struct check
-    {
-      static_assert(sizeof(int) <= sizeof(T), "not big enough");
-    };
-
-    struct Base {
-    virtual void f() {}
-    };
-    struct Child : public Base {
-    virtual void f() override {}
-    };
-
-    typedef check<check<bool>> right_angle_brackets;
-
-    int a;
-    decltype(a) b;
-
-    typedef check<int> check_type;
-    check_type c;
-    check_type&& cr = static_cast<check_type&&>(c);
-
-    auto d = a;
-    auto l = [](){};
-]])
-
-AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
-  m4_if([$1], [], [],
-        [$1], [ext], [],
-        [$1], [noext], [],
-        [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
-  m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
-        [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
-        [$2], [optional], [ax_cxx_compile_cxx11_required=false],
-        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
-  AC_LANG_PUSH([C++])dnl
-  ac_success=no
-  AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
-  ax_cv_cxx_compile_cxx11,
-  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
-    [ax_cv_cxx_compile_cxx11=yes],
-    [ax_cv_cxx_compile_cxx11=no])])
-  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
-    ac_success=yes
-  fi
-
-  m4_if([$1], [noext], [], [dnl
-  if test x$ac_success = xno; then
-    for switch in -std=gnu++11 -std=gnu++0x; do
-      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
-      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
-                     $cachevar,
-        [ac_save_CXXFLAGS="$CXXFLAGS"
-         CXXFLAGS="$CXXFLAGS $switch"
-         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
-          [eval $cachevar=yes],
-          [eval $cachevar=no])
-         CXXFLAGS="$ac_save_CXXFLAGS"])
-      if eval test x\$$cachevar = xyes; then
-        CXXFLAGS="$CXXFLAGS $switch"
-        ac_success=yes
-        break
-      fi
-    done
-  fi])
-
-  m4_if([$1], [ext], [], [dnl
-  if test x$ac_success = xno; then
-    for switch in -std=c++11 -std=c++0x; do
-      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
-      AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
-                     $cachevar,
-        [ac_save_CXXFLAGS="$CXXFLAGS"
-         CXXFLAGS="$CXXFLAGS $switch"
-         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
-          [eval $cachevar=yes],
-          [eval $cachevar=no])
-         CXXFLAGS="$ac_save_CXXFLAGS"])
-      if eval test x\$$cachevar = xyes; then
-        CXXFLAGS="$CXXFLAGS $switch"
-        ac_success=yes
-        break
-      fi
-    done
-  fi])
-  AC_LANG_POP([C++])
-  if test x$ax_cxx_compile_cxx11_required = xtrue; then
-    if test x$ac_success = xno; then
-      AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
-    fi
-  else
-    if test x$ac_success = xno; then
-      HAVE_CXX11=0
-      AC_MSG_NOTICE([No compiler with C++11 support was found])
-    else
-      HAVE_CXX11=1
-      AC_DEFINE(HAVE_CXX11,1,
-                [define if the compiler supports basic C++11 syntax])
-    fi
+#serial 17
 
-    AC_SUBST(HAVE_CXX11)
-  fi
-])
+AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])
diff --git a/m4/ax_prog_doxygen.m4 b/m4/ax_prog_doxygen.m4
index 44b22b0..e92c9e4 100644
--- a/m4/ax_prog_doxygen.m4
+++ b/m4/ax_prog_doxygen.m4
@@ -4,7 +4,7 @@
 #
 # SYNOPSIS
 #
-#   DX_INIT_DOXYGEN(PROJECT-NAME, DOXYFILE-PATH, [OUTPUT-DIR])
+#   DX_INIT_DOXYGEN(PROJECT-NAME, [DOXYFILE-PATH], [OUTPUT-DIR], ...)
 #   DX_DOXYGEN_FEATURE(ON|OFF)
 #   DX_DOT_FEATURE(ON|OFF)
 #   DX_HTML_FEATURE(ON|OFF)
@@ -45,14 +45,19 @@
 #   Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
 #   with the following parameters: a one-word name for the project for use
 #   as a filename base etc., an optional configuration file name (the
-#   default is 'Doxyfile', the same as Doxygen's default), and an optional
-#   output directory name (the default is 'doxygen-doc').
+#   default is '$(srcdir)/Doxyfile', the same as Doxygen's default), and an
+#   optional output directory name (the default is 'doxygen-doc'). To run
+#   doxygen multiple times for different configuration files and output
+#   directories provide more parameters: the second, forth, sixth, etc
+#   parameter are configuration file names and the third, fifth, seventh,
+#   etc parameter are output directories. No checking is done to catch
+#   duplicates.
 #
 #   Automake Support
 #
-#   The following is a template aminclude.am file for use with Automake.
-#   Make targets and variables values are controlled by the various
-#   DX_COND_* conditionals set by autoconf.
+#   The DX_RULES substitution can be used to add all needed rules to the
+#   Makefile. Note that this is a substitution without being a variable:
+#   only the @DX_RULES@ syntax will work.
 #
 #   The provided targets are:
 #
@@ -61,9 +66,7 @@
 #     doxygen-run: Run doxygen, which will generate some of the
 #                  documentation (HTML, CHM, CHI, MAN, RTF, XML)
 #                  but will not do the post processing required
-#                  for the rest of it (PS, PDF, and some MAN).
-#
-#     doxygen-man: Rename some doxygen generated man pages.
+#                  for the rest of it (PS, PDF).
 #
 #     doxygen-ps:  Generate doxygen PostScript documentation.
 #
@@ -84,177 +87,17 @@
 #
 #   Then add this variable to MOSTLYCLEANFILES.
 #
-#     ----- begin aminclude.am -------------------------------------
-#
-#     ## --------------------------------- ##
-#     ## Format-independent Doxygen rules. ##
-#     ## --------------------------------- ##
-#
-#     if DX_COND_doc
-#
-#     ## ------------------------------- ##
-#     ## Rules specific for HTML output. ##
-#     ## ------------------------------- ##
-#
-#     if DX_COND_html
-#
-#     DX_CLEAN_HTML = @DX_DOCDIR@/html
-#
-#     endif DX_COND_html
-#
-#     ## ------------------------------ ##
-#     ## Rules specific for CHM output. ##
-#     ## ------------------------------ ##
-#
-#     if DX_COND_chm
-#
-#     DX_CLEAN_CHM = @DX_DOCDIR@/chm
-#
-#     if DX_COND_chi
-#
-#     DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE at .chi
-#
-#     endif DX_COND_chi
-#
-#     endif DX_COND_chm
-#
-#     ## ------------------------------ ##
-#     ## Rules specific for MAN output. ##
-#     ## ------------------------------ ##
-#
-#     if DX_COND_man
-#
-#     DX_CLEAN_MAN = @DX_DOCDIR@/man
-#
-#     endif DX_COND_man
-#
-#     ## ------------------------------ ##
-#     ## Rules specific for RTF output. ##
-#     ## ------------------------------ ##
-#
-#     if DX_COND_rtf
-#
-#     DX_CLEAN_RTF = @DX_DOCDIR@/rtf
-#
-#     endif DX_COND_rtf
-#
-#     ## ------------------------------ ##
-#     ## Rules specific for XML output. ##
-#     ## ------------------------------ ##
-#
-#     if DX_COND_xml
-#
-#     DX_CLEAN_XML = @DX_DOCDIR@/xml
-#
-#     endif DX_COND_xml
-#
-#     ## ----------------------------- ##
-#     ## Rules specific for PS output. ##
-#     ## ----------------------------- ##
-#
-#     if DX_COND_ps
-#
-#     DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE at .ps
-#
-#     DX_PS_GOAL = doxygen-ps
-#
-#     doxygen-ps: @DX_DOCDIR@/@PACKAGE at .ps
-#
-#     @DX_DOCDIR@/@PACKAGE at .ps: @DX_DOCDIR@/@PACKAGE at .tag
-#         cd @DX_DOCDIR@/latex; \
-#         rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
-#         $(DX_LATEX) refman.tex; \
-#         $(MAKEINDEX_PATH) refman.idx; \
-#         $(DX_LATEX) refman.tex; \
-#         countdown=5; \
-#         while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
-#                           refman.log > /dev/null 2>&1 \
-#            && test $$countdown -gt 0; do \
-#             $(DX_LATEX) refman.tex; \
-#             countdown=`expr $$countdown - 1`; \
-#         done; \
-#         $(DX_DVIPS) -o ../@PACKAGE at .ps refman.dvi
-#
-#     endif DX_COND_ps
-#
-#     ## ------------------------------ ##
-#     ## Rules specific for PDF output. ##
-#     ## ------------------------------ ##
-#
-#     if DX_COND_pdf
-#
-#     DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE at .pdf
-#
-#     DX_PDF_GOAL = doxygen-pdf
-#
-#     doxygen-pdf: @DX_DOCDIR@/@PACKAGE at .pdf
-#
-#     @DX_DOCDIR@/@PACKAGE at .pdf: @DX_DOCDIR@/@PACKAGE at .tag
-#         cd @DX_DOCDIR@/latex; \
-#         rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
-#         $(DX_PDFLATEX) refman.tex; \
-#         $(DX_MAKEINDEX) refman.idx; \
-#         $(DX_PDFLATEX) refman.tex; \
-#         countdown=5; \
-#         while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
-#                           refman.log > /dev/null 2>&1 \
-#            && test $$countdown -gt 0; do \
-#             $(DX_PDFLATEX) refman.tex; \
-#             countdown=`expr $$countdown - 1`; \
-#         done; \
-#         mv refman.pdf ../@PACKAGE at .pdf
-#
-#     endif DX_COND_pdf
-#
-#     ## ------------------------------------------------- ##
-#     ## Rules specific for LaTeX (shared for PS and PDF). ##
-#     ## ------------------------------------------------- ##
-#
-#     if DX_COND_latex
-#
-#     DX_CLEAN_LATEX = @DX_DOCDIR@/latex
-#
-#     endif DX_COND_latex
-#
-#     .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)
-#
-#     .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
-#
-#     doxygen-run: @DX_DOCDIR@/@PACKAGE at .tag
-#
-#     doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
-#
-#     @DX_DOCDIR@/@PACKAGE at .tag: $(DX_CONFIG) $(pkginclude_HEADERS)
-#         rm -rf @DX_DOCDIR@
-#         $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)
-#
-#     DX_CLEANFILES = \
-#         @DX_DOCDIR@/@PACKAGE at .tag \
-#         -r \
-#         $(DX_CLEAN_HTML) \
-#         $(DX_CLEAN_CHM) \
-#         $(DX_CLEAN_CHI) \
-#         $(DX_CLEAN_MAN) \
-#         $(DX_CLEAN_RTF) \
-#         $(DX_CLEAN_XML) \
-#         $(DX_CLEAN_PS) \
-#         $(DX_CLEAN_PDF) \
-#         $(DX_CLEAN_LATEX)
-#
-#     endif DX_COND_doc
-#
-#     ----- end aminclude.am ---------------------------------------
-#
 # LICENSE
 #
 #   Copyright (c) 2009 Oren Ben-Kiki <oren at ben-kiki.org>
+#   Copyright (c) 2015 Olaf Mandel <olaf at mandel.name>
 #
 #   Copying and distribution of this file, with or without modification, are
 #   permitted in any medium without royalty provided the copyright notice
 #   and this notice are preserved. This file is offered as-is, without any
 #   warranty.
 
-#serial 12
+#serial 20
 
 ## ----------##
 ## Defaults. ##
@@ -278,8 +121,14 @@ AC_DEFUN([DX_FEATURE_ps],   ON)
 
 # DX_ENV_APPEND(VARIABLE, VALUE)
 # ------------------------------
-# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen.
-AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])])
+# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen and add it
+# as a substitution (but not a Makefile variable). The substitution
+# is skipped if the variable name is VERSION.
+AC_DEFUN([DX_ENV_APPEND],
+[AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])dnl
+m4_if([$1], [VERSION], [], [AC_SUBST([$1], [$2])dnl
+AM_SUBST_NOTMAKE([$1])])dnl
+])
 
 # DX_DIRNAME_EXPR
 # ---------------
@@ -364,7 +213,6 @@ if DX_TEST_FEATURE([$1]); then
     $5
     :
 fi
-AM_CONDITIONAL(DX_COND_$1, DX_TEST_FEATURE([$1]))
 if DX_TEST_FEATURE([$1]); then
     $6
     :
@@ -392,21 +240,34 @@ AC_DEFUN([DX_XML_FEATURE],     [AC_DEFUN([DX_FEATURE_xml],  [$1])])
 AC_DEFUN([DX_PDF_FEATURE],     [AC_DEFUN([DX_FEATURE_pdf],  [$1])])
 AC_DEFUN([DX_PS_FEATURE],      [AC_DEFUN([DX_FEATURE_ps],   [$1])])
 
-# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])
-# ---------------------------------------------------------
+# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR], ...)
+# --------------------------------------------------------------
 # PROJECT also serves as the base name for the documentation files.
-# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc".
+# The default CONFIG-FILE is "$(srcdir)/Doxyfile" and OUTPUT-DOC-DIR is
+# "doxygen-doc".
+# More arguments are interpreted as interleaved CONFIG-FILE and
+# OUTPUT-DOC-DIR values.
 AC_DEFUN([DX_INIT_DOXYGEN], [
 
 # Files:
 AC_SUBST([DX_PROJECT], [$1])
-AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])
-AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])
+AC_SUBST([DX_CONFIG], ['ifelse([$2], [], [$(srcdir)/Doxyfile], [$2])'])
+AC_SUBST([DX_DOCDIR], ['ifelse([$3], [], [doxygen-doc], [$3])'])
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 4, m4_count($@), 2,
+      [AC_SUBST([DX_CONFIG]m4_eval(DX_i[/2]),
+                'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+                                          [$(srcdir)/Doxyfile])')])])dnl
+m4_if(m4_eval(3 < m4_count($@)), 1, [m4_for([DX_i], 5, m4_count($@,), 2,
+      [AC_SUBST([DX_DOCDIR]m4_eval([(]DX_i[-1)/2]),
+                'm4_default_nblank_quoted(m4_argn(DX_i, $@),
+                                          [doxygen-doc])')])])dnl
+m4_define([DX_loop], m4_dquote(m4_if(m4_eval(3 < m4_count($@)), 1,
+          [m4_for([DX_i], 4, m4_count($@), 2, [, m4_eval(DX_i[/2])])],
+          [])))dnl
 
 # Environment variables used inside doxygen.cfg:
 DX_ENV_APPEND(SRCDIR, $srcdir)
 DX_ENV_APPEND(PROJECT, $DX_PROJECT)
-DX_ENV_APPEND(DOCDIR, $DX_DOCDIR)
 DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
 
 # Doxygen itself:
@@ -494,7 +355,6 @@ DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
              DX_REQUIRE_PROG([DX_EGREP], egrep)])
 
 # LaTeX generation for PS and/or PDF:
-AM_CONDITIONAL(DX_COND_latex, DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf))
 if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
     DX_ENV_APPEND(GENERATE_LATEX, YES)
 else
@@ -517,6 +377,200 @@ a4wide|a4|letter|legal|executive)
 ;;
 esac
 
+# Rules:
+AS_IF([[test $DX_FLAG_html -eq 1]],
+[[DX_SNIPPET_html="## ------------------------------- ##
+## Rules specific for HTML output. ##
+## ------------------------------- ##
+
+DX_CLEAN_HTML = \$(DX_DOCDIR)/html]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+                \$(DX_DOCDIR]DX_i[)/html]])[
+
+"]],
+[[DX_SNIPPET_html=""]])
+AS_IF([[test $DX_FLAG_chi -eq 1]],
+[[DX_SNIPPET_chi="
+DX_CLEAN_CHI = \$(DX_DOCDIR)/\$(PACKAGE).chi]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).chi]])["]],
+[[DX_SNIPPET_chi=""]])
+AS_IF([[test $DX_FLAG_chm -eq 1]],
+[[DX_SNIPPET_chm="## ------------------------------ ##
+## Rules specific for CHM output. ##
+## ------------------------------ ##
+
+DX_CLEAN_CHM = \$(DX_DOCDIR)/chm]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/chm]])[\
+${DX_SNIPPET_chi}
+
+"]],
+[[DX_SNIPPET_chm=""]])
+AS_IF([[test $DX_FLAG_man -eq 1]],
+[[DX_SNIPPET_man="## ------------------------------ ##
+## Rules specific for MAN output. ##
+## ------------------------------ ##
+
+DX_CLEAN_MAN = \$(DX_DOCDIR)/man]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/man]])[
+
+"]],
+[[DX_SNIPPET_man=""]])
+AS_IF([[test $DX_FLAG_rtf -eq 1]],
+[[DX_SNIPPET_rtf="## ------------------------------ ##
+## Rules specific for RTF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_RTF = \$(DX_DOCDIR)/rtf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/rtf]])[
+
+"]],
+[[DX_SNIPPET_rtf=""]])
+AS_IF([[test $DX_FLAG_xml -eq 1]],
+[[DX_SNIPPET_xml="## ------------------------------ ##
+## Rules specific for XML output. ##
+## ------------------------------ ##
+
+DX_CLEAN_XML = \$(DX_DOCDIR)/xml]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/xml]])[
+
+"]],
+[[DX_SNIPPET_xml=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1]],
+[[DX_SNIPPET_ps="## ----------------------------- ##
+## Rules specific for PS output. ##
+## ----------------------------- ##
+
+DX_CLEAN_PS = \$(DX_DOCDIR)/\$(PACKAGE).ps]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+              \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps]])[
+
+DX_PS_GOAL = doxygen-ps
+
+doxygen-ps: \$(DX_CLEAN_PS)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).ps: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+	\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+	rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+	\$(DX_LATEX) refman.tex; \\
+	\$(DX_MAKEINDEX) refman.idx; \\
+	\$(DX_LATEX) refman.tex; \\
+	countdown=5; \\
+	while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+	                  refman.log > /dev/null 2>&1 \\
+	   && test \$\$countdown -gt 0; do \\
+	    \$(DX_LATEX) refman.tex; \\
+            countdown=\`expr \$\$countdown - 1\`; \\
+	done; \\
+	\$(DX_DVIPS) -o ../\$(PACKAGE).ps refman.dvi
+
+]])["]],
+[[DX_SNIPPET_ps=""]])
+AS_IF([[test $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_pdf="## ------------------------------ ##
+## Rules specific for PDF output. ##
+## ------------------------------ ##
+
+DX_CLEAN_PDF = \$(DX_DOCDIR)/\$(PACKAGE).pdf]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+               \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf]])[
+
+DX_PDF_GOAL = doxygen-pdf
+
+doxygen-pdf: \$(DX_CLEAN_PDF)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).pdf: \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag
+	\$(DX_V_LATEX)cd \$(DX_DOCDIR]DX_i[)/latex; \\
+	rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \\
+	\$(DX_PDFLATEX) refman.tex; \\
+	\$(DX_MAKEINDEX) refman.idx; \\
+	\$(DX_PDFLATEX) refman.tex; \\
+	countdown=5; \\
+	while \$(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \\
+	                  refman.log > /dev/null 2>&1 \\
+	   && test \$\$countdown -gt 0; do \\
+	    \$(DX_PDFLATEX) refman.tex; \\
+	    countdown=\`expr \$\$countdown - 1\`; \\
+	done; \\
+	mv refman.pdf ../\$(PACKAGE).pdf
+
+]])["]],
+[[DX_SNIPPET_pdf=""]])
+AS_IF([[test $DX_FLAG_ps -eq 1 -o $DX_FLAG_pdf -eq 1]],
+[[DX_SNIPPET_latex="## ------------------------------------------------- ##
+## Rules specific for LaTeX (shared for PS and PDF). ##
+## ------------------------------------------------- ##
+
+DX_V_LATEX = \$(_DX_v_LATEX_\$(V))
+_DX_v_LATEX_ = \$(_DX_v_LATEX_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_LATEX_0 = @echo \"  LATEX \" \$][@;
+
+DX_CLEAN_LATEX = \$(DX_DOCDIR)/latex]dnl
+m4_foreach([DX_i], [m4_shift(DX_loop)], [[\\
+                 \$(DX_DOCDIR]DX_i[)/latex]])[
+
+"]],
+[[DX_SNIPPET_latex=""]])
+
+AS_IF([[test $DX_FLAG_doc -eq 1]],
+[[DX_SNIPPET_doc="## --------------------------------- ##
+## Format-independent Doxygen rules. ##
+## --------------------------------- ##
+
+${DX_SNIPPET_html}\
+${DX_SNIPPET_chm}\
+${DX_SNIPPET_man}\
+${DX_SNIPPET_rtf}\
+${DX_SNIPPET_xml}\
+${DX_SNIPPET_ps}\
+${DX_SNIPPET_pdf}\
+${DX_SNIPPET_latex}\
+DX_V_DXGEN = \$(_DX_v_DXGEN_\$(V))
+_DX_v_DXGEN_ = \$(_DX_v_DXGEN_\$(AM_DEFAULT_VERBOSITY))
+_DX_v_DXGEN_0 = @echo \"  DXGEN \" \$<;
+
+.PHONY: doxygen-run doxygen-doc \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+.INTERMEDIATE: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+doxygen-run:]m4_foreach([DX_i], [DX_loop],
+                         [[ \$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag]])[
+
+doxygen-doc: doxygen-run \$(DX_PS_GOAL) \$(DX_PDF_GOAL)
+
+]m4_foreach([DX_i], [DX_loop],
+[[\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag: \$(DX_CONFIG]DX_i[) \$(pkginclude_HEADERS)
+	\$(A""M_V_at)rm -rf \$(DX_DOCDIR]DX_i[)
+	\$(DX_V_DXGEN)\$(DX_ENV) DOCDIR=\$(DX_DOCDIR]DX_i[) \$(DX_DOXYGEN) \$(DX_CONFIG]DX_i[)
+	\$(A""M_V_at)echo Timestamp >\$][@
+
+]])dnl
+[DX_CLEANFILES = \\]
+m4_foreach([DX_i], [DX_loop],
+[[	\$(DX_DOCDIR]DX_i[)/doxygen_sqlite3.db \\
+	\$(DX_DOCDIR]DX_i[)/\$(PACKAGE).tag \\
+]])dnl
+[	-r \\
+	\$(DX_CLEAN_HTML) \\
+	\$(DX_CLEAN_CHM) \\
+	\$(DX_CLEAN_CHI) \\
+	\$(DX_CLEAN_MAN) \\
+	\$(DX_CLEAN_RTF) \\
+	\$(DX_CLEAN_XML) \\
+	\$(DX_CLEAN_PS) \\
+	\$(DX_CLEAN_PDF) \\
+	\$(DX_CLEAN_LATEX)"]],
+[[DX_SNIPPET_doc=""]])
+AC_SUBST([DX_RULES],
+["${DX_SNIPPET_doc}"])dnl
+AM_SUBST_NOTMAKE([DX_RULES])
+
 #For debugging:
 #echo DX_FLAG_doc=$DX_FLAG_doc
 #echo DX_FLAG_dot=$DX_FLAG_dot
diff --git a/m4/libtool.m4 b/m4/libtool.m4
index d7c043f..ee80844 100644
--- a/m4/libtool.m4
+++ b/m4/libtool.m4
@@ -1,8 +1,6 @@
 # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
 #
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-#                 Foundation, Inc.
+#   Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 # This file is free software; the Free Software Foundation gives
@@ -10,36 +8,30 @@
 # modifications, as long as this notice is preserved.
 
 m4_define([_LT_COPYING], [dnl
-#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-#                 Foundation, Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-#   This file is part of GNU Libtool.
-#
-# GNU Libtool is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
 #
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the  same
+# distribution terms that you use for the rest of that program.
 #
-# GNU Libtool is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING.  If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ])
 
-# serial 57 LT_INIT
+# serial 58 LT_INIT
 
 
 # LT_PREREQ(VERSION)
@@ -67,7 +59,7 @@ esac
 # LT_INIT([OPTIONS])
 # ------------------
 AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
 AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
 AC_BEFORE([$0], [LT_LANG])dnl
 AC_BEFORE([$0], [LT_OUTPUT])dnl
@@ -91,7 +83,7 @@ dnl Parse OPTIONS
 _LT_SET_OPTIONS([$0], [$1])
 
 # This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ltmain"
+LIBTOOL_DEPS=$ltmain
 
 # Always use our own libtool.
 LIBTOOL='$(SHELL) $(top_builddir)/libtool'
@@ -111,26 +103,43 @@ dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
 dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
 
 
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in @S|@*""; do
+      case $cc_temp in
+        compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+        distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
 # _LT_CC_BASENAME(CC)
 # -------------------
-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
 m4_defun([_LT_CC_BASENAME],
-[for cc_temp in $1""; do
-  case $cc_temp in
-    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
-    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
-    \-*) ;;
-    *) break;;
-  esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
 ])
 
 
 # _LT_FILEUTILS_DEFAULTS
 # ----------------------
 # It is okay to use these file commands and assume they have been set
-# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
 m4_defun([_LT_FILEUTILS_DEFAULTS],
 [: ${CP="cp -f"}
 : ${MV="mv -f"}
@@ -177,15 +186,16 @@ m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
 m4_require([_LT_CMD_OLD_ARCHIVE])dnl
 m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
 m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
 
 _LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options which allow our
+# See if we are running on zsh, and set the options that allow our
 # commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
+if test -n "\${ZSH_VERSION+set}"; then
    setopt NO_GLOB_SUBST
 fi
 ])
-if test -n "${ZSH_VERSION+set}" ; then
+if test -n "${ZSH_VERSION+set}"; then
    setopt NO_GLOB_SUBST
 fi
 
@@ -198,7 +208,7 @@ aix3*)
   # AIX sometimes has problems with the GCC collect2 program.  For some
   # reason, if we set the COLLECT_NAMES environment variable, the problems
   # vanish in a puff of smoke.
-  if test "X${COLLECT_NAMES+set}" != Xset; then
+  if test set != "${COLLECT_NAMES+set}"; then
     COLLECT_NAMES=
     export COLLECT_NAMES
   fi
@@ -209,14 +219,14 @@ esac
 ofile=libtool
 can_build_shared=yes
 
-# All known linkers require a `.a' archive for static linking (except MSVC,
+# All known linkers require a '.a' archive for static linking (except MSVC,
 # which needs '.lib').
 libext=a
 
-with_gnu_ld="$lt_cv_prog_gnu_ld"
+with_gnu_ld=$lt_cv_prog_gnu_ld
 
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
+old_CC=$CC
+old_CFLAGS=$CFLAGS
 
 # Set sane defaults for various variables
 test -z "$CC" && CC=cc
@@ -269,14 +279,14 @@ no_glob_subst='s/\*/\\\*/g'
 
 # _LT_PROG_LTMAIN
 # ---------------
-# Note that this code is called both from `configure', and `config.status'
+# Note that this code is called both from 'configure', and 'config.status'
 # now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
-# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
 # so we pass a copy along to make sure it has a sensible value anyway.
 m4_defun([_LT_PROG_LTMAIN],
 [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
 _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
-ltmain="$ac_aux_dir/ltmain.sh"
+ltmain=$ac_aux_dir/ltmain.sh
 ])# _LT_PROG_LTMAIN
 
 
@@ -286,7 +296,7 @@ ltmain="$ac_aux_dir/ltmain.sh"
 
 # So that we can recreate a full libtool script including additional
 # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the `libtool'
+# in macros and then make a single call at the end using the 'libtool'
 # label.
 
 
@@ -421,8 +431,8 @@ m4_define([_lt_decl_all_varnames],
 
 # _LT_CONFIG_STATUS_DECLARE([VARNAME])
 # ------------------------------------
-# Quote a variable value, and forward it to `config.status' so that its
-# declaration there will have the same value as in `configure'.  VARNAME
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'.  VARNAME
 # must have a single quote delimited value for this to work.
 m4_define([_LT_CONFIG_STATUS_DECLARE],
 [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
@@ -446,7 +456,7 @@ m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
 # Output comment and list of tags supported by the script
 m4_defun([_LT_LIBTOOL_TAGS],
 [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags="_LT_TAGS"dnl
+available_tags='_LT_TAGS'dnl
 ])
 
 
@@ -474,7 +484,7 @@ m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
 # _LT_LIBTOOL_CONFIG_VARS
 # -----------------------
 # Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
 # script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
 # section) are produced by _LT_LIBTOOL_TAG_VARS.
 m4_defun([_LT_LIBTOOL_CONFIG_VARS],
@@ -500,8 +510,8 @@ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
 # Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
 # variables for single and double quote escaping we saved from calls
 # to _LT_DECL, we can put quote escaped variables declarations
-# into `config.status', and then the shell code to quote escape them in
-# for loops in `config.status'.  Finally, any additional code accumulated
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'.  Finally, any additional code accumulated
 # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
 m4_defun([_LT_CONFIG_COMMANDS],
 [AC_PROVIDE_IFELSE([LT_OUTPUT],
@@ -547,7 +557,7 @@ for var in lt_decl_all_varnames([[ \
 ]], lt_decl_quote_varnames); do
     case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -560,7 +570,7 @@ for var in lt_decl_all_varnames([[ \
 ]], lt_decl_dquote_varnames); do
     case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
       ;;
     *)
       eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -576,7 +586,7 @@ _LT_OUTPUT_LIBTOOL_INIT
 # Generate a child script FILE with all initialization necessary to
 # reuse the environment learned by the parent script, and make the
 # file executable.  If COMMENT is supplied, it is inserted after the
-# `#!' sequence but before initialization text begins.  After this
+# '#!' sequence but before initialization text begins.  After this
 # macro, additional text can be appended to FILE to form the body of
 # the child script.  The macro ends with non-zero status if the
 # file could not be fully written (such as if the disk is full).
@@ -598,7 +608,7 @@ AS_SHELL_SANITIZE
 _AS_PREPARE
 exec AS_MESSAGE_FD>&1
 _ASEOF
-test $lt_write_fail = 0 && chmod +x $1[]dnl
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
 m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
 
 # LT_OUTPUT
@@ -621,7 +631,7 @@ exec AS_MESSAGE_LOG_FD>>config.log
 } >&AS_MESSAGE_LOG_FD
 
 lt_cl_help="\
-\`$as_me' creates a local libtool stub from the current configuration,
+'$as_me' creates a local libtool stub from the current configuration,
 for use in further configure time tests before the real libtool is
 generated.
 
@@ -643,7 +653,7 @@ Copyright (C) 2011 Free Software Foundation, Inc.
 This config.lt script is free software; the Free Software Foundation
 gives unlimited permision to copy, distribute and modify it."
 
-while test $[#] != 0
+while test 0 != $[#]
 do
   case $[1] in
     --version | --v* | -V )
@@ -656,10 +666,10 @@ do
       lt_cl_silent=: ;;
 
     -*) AC_MSG_ERROR([unrecognized option: $[1]
-Try \`$[0] --help' for more information.]) ;;
+Try '$[0] --help' for more information.]) ;;
 
     *) AC_MSG_ERROR([unrecognized argument: $[1]
-Try \`$[0] --help' for more information.]) ;;
+Try '$[0] --help' for more information.]) ;;
   esac
   shift
 done
@@ -685,7 +695,7 @@ chmod +x "$CONFIG_LT"
 # open by configure.  Here we exec the FD to /dev/null, effectively closing
 # config.log, so it can be properly (re)opened and appended to by config.lt.
 lt_cl_success=:
-test "$silent" = yes &&
+test yes = "$silent" &&
   lt_config_lt_args="$lt_config_lt_args --quiet"
 exec AS_MESSAGE_LOG_FD>/dev/null
 $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
@@ -705,27 +715,30 @@ m4_defun([_LT_CONFIG],
 _LT_CONFIG_SAVE_COMMANDS([
   m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
   m4_if(_LT_TAG, [C], [
-    # See if we are running on zsh, and set the options which allow our
+    # See if we are running on zsh, and set the options that allow our
     # commands through without removal of \ escapes.
-    if test -n "${ZSH_VERSION+set}" ; then
+    if test -n "${ZSH_VERSION+set}"; then
       setopt NO_GLOB_SUBST
     fi
 
-    cfgfile="${ofile}T"
+    cfgfile=${ofile}T
     trap "$RM \"$cfgfile\"; exit 1" 1 2 15
     $RM "$cfgfile"
 
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# Generated automatically by $as_me ($PACKAGE) $VERSION
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
 _LT_COPYING
 _LT_LIBTOOL_TAGS
 
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
 # ### BEGIN LIBTOOL CONFIG
 _LT_LIBTOOL_CONFIG_VARS
 _LT_LIBTOOL_TAG_VARS
@@ -733,13 +746,24 @@ _LT_LIBTOOL_TAG_VARS
 
 _LT_EOF
 
+    cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
   case $host_os in
   aix3*)
     cat <<\_LT_EOF >> "$cfgfile"
 # AIX sometimes has problems with the GCC collect2 program.  For some
 # reason, if we set the COLLECT_NAMES environment variable, the problems
 # vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
+if test set != "${COLLECT_NAMES+set}"; then
   COLLECT_NAMES=
   export COLLECT_NAMES
 fi
@@ -756,8 +780,6 @@ _LT_EOF
   sed '$q' "$ltmain" >> "$cfgfile" \
      || (rm -f "$cfgfile"; exit 1)
 
-  _LT_PROG_REPLACE_SHELLFNS
-
    mv -f "$cfgfile" "$ofile" ||
     (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
   chmod +x "$ofile"
@@ -775,7 +797,6 @@ _LT_EOF
 [m4_if([$1], [], [
     PACKAGE='$PACKAGE'
     VERSION='$VERSION'
-    TIMESTAMP='$TIMESTAMP'
     RM='$RM'
     ofile='$ofile'], [])
 ])dnl /_LT_CONFIG_SAVE_COMMANDS
@@ -974,7 +995,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
 
     AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
       [lt_cv_apple_cc_single_mod=no
-      if test -z "${LT_MULTI_MODULE}"; then
+      if test -z "$LT_MULTI_MODULE"; then
 	# By default we will add the -single_module flag. You can override
 	# by either setting the environment variable LT_MULTI_MODULE
 	# non-empty at configure time, or by adding -multi_module to the
@@ -992,7 +1013,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
 	  cat conftest.err >&AS_MESSAGE_LOG_FD
 	# Otherwise, if the output was created with a 0 exit code from
 	# the compiler, it worked.
-	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
 	  lt_cv_apple_cc_single_mod=yes
 	else
 	  cat conftest.err >&AS_MESSAGE_LOG_FD
@@ -1010,7 +1031,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
       AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
 	[lt_cv_ld_exported_symbols_list=yes],
 	[lt_cv_ld_exported_symbols_list=no])
-	LDFLAGS="$save_LDFLAGS"
+	LDFLAGS=$save_LDFLAGS
     ])
 
     AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
@@ -1032,7 +1053,7 @@ _LT_EOF
       _lt_result=$?
       if test -s conftest.err && $GREP force_load conftest.err; then
 	cat conftest.err >&AS_MESSAGE_LOG_FD
-      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
 	lt_cv_ld_force_load=yes
       else
 	cat conftest.err >&AS_MESSAGE_LOG_FD
@@ -1042,32 +1063,32 @@ _LT_EOF
     ])
     case $host_os in
     rhapsody* | darwin1.[[012]])
-      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
     darwin1.*)
-      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
     darwin*) # darwin 5.x on
       # if running on 10.5 or later, the deployment target defaults
       # to the OS version, if on x86, and 10.4, the deployment
       # target defaults to 10.4. Don't you love it?
       case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
 	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
-	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-	10.[[012]]*)
-	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]][[,.]]*)
+	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
 	10.*)
-	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
       esac
     ;;
   esac
-    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+    if test yes = "$lt_cv_apple_cc_single_mod"; then
       _lt_dar_single_mod='$single_module'
     fi
-    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
-      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    if test yes = "$lt_cv_ld_exported_symbols_list"; then
+      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
     else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
     fi
-    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
       _lt_dsymutil='~$DSYMUTIL $lib || :'
     else
       _lt_dsymutil=
@@ -1087,29 +1108,29 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
   _LT_TAGVAR(hardcode_direct, $1)=no
   _LT_TAGVAR(hardcode_automatic, $1)=yes
   _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  if test "$lt_cv_ld_force_load" = "yes"; then
-    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  if test yes = "$lt_cv_ld_force_load"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
     m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
                   [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
   else
     _LT_TAGVAR(whole_archive_flag_spec, $1)=''
   fi
   _LT_TAGVAR(link_all_deplibs, $1)=yes
-  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
   case $cc_basename in
-     ifort*) _lt_dar_can_shared=yes ;;
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
      *) _lt_dar_can_shared=$GCC ;;
   esac
-  if test "$_lt_dar_can_shared" = "yes"; then
+  if test yes = "$_lt_dar_can_shared"; then
     output_verbose_link_cmd=func_echo_all
-    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
-    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
-    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
-    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
     m4_if([$1], [CXX],
-[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
-      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
-      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+[   if test yes != "$lt_cv_apple_cc_single_mod"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
     fi
 ],[])
   else
@@ -1129,7 +1150,7 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
 # Allow to override them for all tags through lt_cv_aix_libpath.
 m4_defun([_LT_SYS_MODULE_PATH_AIX],
 [m4_require([_LT_DECL_SED])dnl
-if test "${lt_cv_aix_libpath+set}" = set; then
+if test set = "${lt_cv_aix_libpath+set}"; then
   aix_libpath=$lt_cv_aix_libpath
 else
   AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
@@ -1147,7 +1168,7 @@ else
     _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
   fi],[])
   if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
   fi
   ])
   aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
@@ -1167,8 +1188,8 @@ m4_define([_LT_SHELL_INIT],
 # -----------------------
 # Find how we can fake an echo command that does not interpret backslash.
 # In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script which will find a shell with a builtin
-# printf (which we can use as an echo command).
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
 m4_defun([_LT_PROG_ECHO_BACKSLASH],
 [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
 ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
@@ -1196,10 +1217,10 @@ fi
 # Invoke $ECHO with all args, space-separated.
 func_echo_all ()
 {
-    $ECHO "$*" 
+    $ECHO "$*"
 }
 
-case "$ECHO" in
+case $ECHO in
   printf*) AC_MSG_RESULT([printf]) ;;
   print*) AC_MSG_RESULT([print -r]) ;;
   *) AC_MSG_RESULT([cat]) ;;
@@ -1225,16 +1246,17 @@ _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
 AC_DEFUN([_LT_WITH_SYSROOT],
 [AC_MSG_CHECKING([for sysroot])
 AC_ARG_WITH([sysroot],
-[  --with-sysroot[=DIR] Search for dependent libraries within DIR
-                        (or the compiler's sysroot if not specified).],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+  [Search for dependent libraries within DIR (or the compiler's sysroot
+   if not specified).])],
 [], [with_sysroot=no])
 
 dnl lt_sysroot will always be passed unquoted.  We quote it here
 dnl in case the user passed a directory name.
 lt_sysroot=
-case ${with_sysroot} in #(
+case $with_sysroot in #(
  yes)
-   if test "$GCC" = yes; then
+   if test yes = "$GCC"; then
      lt_sysroot=`$CC --print-sysroot 2>/dev/null`
    fi
    ;; #(
@@ -1244,14 +1266,14 @@ case ${with_sysroot} in #(
  no|'')
    ;; #(
  *)
-   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_RESULT([$with_sysroot])
    AC_MSG_ERROR([The sysroot must be an absolute path.])
    ;;
 esac
 
  AC_MSG_RESULT([${lt_sysroot:-no}])
 _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and in which our libraries should be installed.])])
+[dependent libraries, and where our libraries should be installed.])])
 
 # _LT_ENABLE_LOCK
 # ---------------
@@ -1259,31 +1281,33 @@ m4_defun([_LT_ENABLE_LOCK],
 [AC_ARG_ENABLE([libtool-lock],
   [AS_HELP_STRING([--disable-libtool-lock],
     [avoid locking (might break parallel builds)])])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
 
 # Some flags need to be propagated to the compiler or linker for good
 # libtool support.
 case $host in
 ia64-*-hpux*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set mode
+  # options accordingly.
   echo 'int i;' > conftest.$ac_ext
   if AC_TRY_EVAL(ac_compile); then
     case `/usr/bin/file conftest.$ac_objext` in
       *ELF-32*)
-	HPUX_IA64_MODE="32"
+	HPUX_IA64_MODE=32
 	;;
       *ELF-64*)
-	HPUX_IA64_MODE="64"
+	HPUX_IA64_MODE=64
 	;;
     esac
   fi
   rm -rf conftest*
   ;;
 *-*-irix6*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
   echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
   if AC_TRY_EVAL(ac_compile); then
-    if test "$lt_cv_prog_gnu_ld" = yes; then
+    if test yes = "$lt_cv_prog_gnu_ld"; then
       case `/usr/bin/file conftest.$ac_objext` in
 	*32-bit*)
 	  LD="${LD-ld} -melf32bsmip"
@@ -1312,9 +1336,46 @@ ia64-*-hpux*)
   rm -rf conftest*
   ;;
 
+mips64*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    emul=elf
+    case `/usr/bin/file conftest.$ac_objext` in
+      *32-bit*)
+	emul="${emul}32"
+	;;
+      *64-bit*)
+	emul="${emul}64"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *MSB*)
+	emul="${emul}btsmip"
+	;;
+      *LSB*)
+	emul="${emul}ltsmip"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *N32*)
+	emul="${emul}n32"
+	;;
+    esac
+    LD="${LD-ld} -m $emul"
+  fi
+  rm -rf conftest*
+  ;;
+
 x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
 s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.  Note that the listed cases only cover the
+  # situations where additional linker options are needed (such as when
+  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+  # vice versa); the common cases where no linker options are needed do
+  # not appear in the list.
   echo 'int i;' > conftest.$ac_ext
   if AC_TRY_EVAL(ac_compile); then
     case `/usr/bin/file conftest.o` in
@@ -1333,10 +1394,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 		;;
 	    esac
 	    ;;
-	  powerpc64le-*)
+	  powerpc64le-*linux*)
 	    LD="${LD-ld} -m elf32lppclinux"
 	    ;;
-	  powerpc64-*)
+	  powerpc64-*linux*)
 	    LD="${LD-ld} -m elf32ppclinux"
 	    ;;
 	  s390x-*linux*)
@@ -1355,10 +1416,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 	  x86_64-*linux*)
 	    LD="${LD-ld} -m elf_x86_64"
 	    ;;
-	  powerpcle-*)
+	  powerpcle-*linux*)
 	    LD="${LD-ld} -m elf64lppc"
 	    ;;
-	  powerpc-*)
+	  powerpc-*linux*)
 	    LD="${LD-ld} -m elf64ppc"
 	    ;;
 	  s390*-*linux*|s390*-*tpf*)
@@ -1376,19 +1437,20 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 
 *-*-sco3.2v5*)
   # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS="$CFLAGS"
+  SAVE_CFLAGS=$CFLAGS
   CFLAGS="$CFLAGS -belf"
   AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
     [AC_LANG_PUSH(C)
      AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
      AC_LANG_POP])
-  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+  if test yes != "$lt_cv_cc_needs_belf"; then
     # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS="$SAVE_CFLAGS"
+    CFLAGS=$SAVE_CFLAGS
   fi
   ;;
 *-*solaris*)
-  # Find out which ABI we are using.
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
   echo 'int i;' > conftest.$ac_ext
   if AC_TRY_EVAL(ac_compile); then
     case `/usr/bin/file conftest.o` in
@@ -1396,7 +1458,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
       case $lt_cv_prog_gnu_ld in
       yes*)
         case $host in
-        i?86-*-solaris*)
+        i?86-*-solaris*|x86_64-*-solaris*)
           LD="${LD-ld} -m elf_x86_64"
           ;;
         sparc*-*-solaris*)
@@ -1405,7 +1467,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
         esac
         # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
         if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
-          LD="${LD-ld}_sol2"
+          LD=${LD-ld}_sol2
         fi
         ;;
       *)
@@ -1421,7 +1483,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
   ;;
 esac
 
-need_locks="$enable_libtool_lock"
+need_locks=$enable_libtool_lock
 ])# _LT_ENABLE_LOCK
 
 
@@ -1440,11 +1502,11 @@ AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
      [echo conftest.$ac_objext > conftest.lst
       lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
       AC_TRY_EVAL([lt_ar_try])
-      if test "$ac_status" -eq 0; then
+      if test 0 -eq "$ac_status"; then
 	# Ensure the archiver fails upon bogus file names.
 	rm -f conftest.$ac_objext libconftest.a
 	AC_TRY_EVAL([lt_ar_try])
-	if test "$ac_status" -ne 0; then
+	if test 0 -ne "$ac_status"; then
           lt_cv_ar_at_file=@
         fi
       fi
@@ -1452,7 +1514,7 @@ AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
      ])
   ])
 
-if test "x$lt_cv_ar_at_file" = xno; then
+if test no = "$lt_cv_ar_at_file"; then
   archiver_list_spec=
 else
   archiver_list_spec=$lt_cv_ar_at_file
@@ -1483,7 +1545,7 @@ old_postuninstall_cmds=
 
 if test -n "$RANLIB"; then
   case $host_os in
-  openbsd*)
+  bitrig* | openbsd*)
     old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
     ;;
   *)
@@ -1519,7 +1581,7 @@ AC_CACHE_CHECK([$1], [$2],
   [$2=no
    m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
    echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$3"
+   lt_compiler_flag="$3"  ## exclude from sc_useless_quotes_in_assignment
    # Insert the option either (1) after the last *FLAGS variable, or
    # (2) before a word containing "conftest.", or (3) at the end.
    # Note that $ac_compile itself does not contain backslashes and begins
@@ -1546,7 +1608,7 @@ AC_CACHE_CHECK([$1], [$2],
    $RM conftest*
 ])
 
-if test x"[$]$2" = xyes; then
+if test yes = "[$]$2"; then
     m4_if([$5], , :, [$5])
 else
     m4_if([$6], , :, [$6])
@@ -1568,7 +1630,7 @@ AC_DEFUN([_LT_LINKER_OPTION],
 m4_require([_LT_DECL_SED])dnl
 AC_CACHE_CHECK([$1], [$2],
   [$2=no
-   save_LDFLAGS="$LDFLAGS"
+   save_LDFLAGS=$LDFLAGS
    LDFLAGS="$LDFLAGS $3"
    echo "$lt_simple_link_test_code" > conftest.$ac_ext
    if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -1587,10 +1649,10 @@ AC_CACHE_CHECK([$1], [$2],
      fi
    fi
    $RM -r conftest*
-   LDFLAGS="$save_LDFLAGS"
+   LDFLAGS=$save_LDFLAGS
 ])
 
-if test x"[$]$2" = xyes; then
+if test yes = "[$]$2"; then
     m4_if([$4], , :, [$4])
 else
     m4_if([$5], , :, [$5])
@@ -1611,7 +1673,7 @@ AC_DEFUN([LT_CMD_MAX_LEN],
 AC_MSG_CHECKING([the maximum length of command line arguments])
 AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
   i=0
-  teststring="ABCD"
+  teststring=ABCD
 
   case $build_os in
   msdosdjgpp*)
@@ -1651,7 +1713,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
     lt_cv_sys_max_cmd_len=8192;
     ;;
 
-  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
     # This has been around since 386BSD, at least.  Likely further.
     if test -x /sbin/sysctl; then
       lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -1702,22 +1764,22 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
   *)
     lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
     if test -n "$lt_cv_sys_max_cmd_len" && \
-	test undefined != "$lt_cv_sys_max_cmd_len"; then
+       test undefined != "$lt_cv_sys_max_cmd_len"; then
       lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
       lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
     else
       # Make teststring a little bigger before we do anything with it.
       # a 1K string should be a reasonable start.
-      for i in 1 2 3 4 5 6 7 8 ; do
+      for i in 1 2 3 4 5 6 7 8; do
         teststring=$teststring$teststring
       done
       SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
       # If test is not a shell built-in, we'll probably end up computing a
       # maximum length that is only half of the actual maximum length, but
       # we can't tell.
-      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
 	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
-	      test $i != 17 # 1/2 MB should be enough
+	      test 17 != "$i" # 1/2 MB should be enough
       do
         i=`expr $i + 1`
         teststring=$teststring$teststring
@@ -1733,7 +1795,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
     ;;
   esac
 ])
-if test -n $lt_cv_sys_max_cmd_len ; then
+if test -n "$lt_cv_sys_max_cmd_len"; then
   AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
 else
   AC_MSG_RESULT(none)
@@ -1761,7 +1823,7 @@ m4_defun([_LT_HEADER_DLFCN],
 # ----------------------------------------------------------------
 m4_defun([_LT_TRY_DLOPEN_SELF],
 [m4_require([_LT_HEADER_DLFCN])dnl
-if test "$cross_compiling" = yes; then :
+if test yes = "$cross_compiling"; then :
   [$4]
 else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -1808,9 +1870,9 @@ else
 #  endif
 #endif
 
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
    correspondingly for the symbols needed.  */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
 int fnord () __attribute__((visibility("default")));
 #endif
 
@@ -1836,7 +1898,7 @@ int main ()
   return status;
 }]
 _LT_EOF
-  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+  if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
     (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
     lt_status=$?
     case x$lt_status in
@@ -1857,7 +1919,7 @@ rm -fr conftest*
 # ------------------
 AC_DEFUN([LT_SYS_DLOPEN_SELF],
 [m4_require([_LT_HEADER_DLFCN])dnl
-if test "x$enable_dlopen" != xyes; then
+if test yes != "$enable_dlopen"; then
   enable_dlopen=unknown
   enable_dlopen_self=unknown
   enable_dlopen_self_static=unknown
@@ -1867,44 +1929,52 @@ else
 
   case $host_os in
   beos*)
-    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen=load_add_on
     lt_cv_dlopen_libs=
     lt_cv_dlopen_self=yes
     ;;
 
   mingw* | pw32* | cegcc*)
-    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen=LoadLibrary
     lt_cv_dlopen_libs=
     ;;
 
   cygwin*)
-    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen=dlopen
     lt_cv_dlopen_libs=
     ;;
 
   darwin*)
-  # if libdl is installed we need to link against it
+    # if libdl is installed we need to link against it
     AC_CHECK_LIB([dl], [dlopen],
-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
-    lt_cv_dlopen="dyld"
+		[lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+    lt_cv_dlopen=dyld
     lt_cv_dlopen_libs=
     lt_cv_dlopen_self=yes
     ])
     ;;
 
+  tpf*)
+    # Don't try to run any link tests for TPF.  We know it's impossible
+    # because TPF is a cross-compiler, and we know how we open DSOs.
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=no
+    ;;
+
   *)
     AC_CHECK_FUNC([shl_load],
-	  [lt_cv_dlopen="shl_load"],
+	  [lt_cv_dlopen=shl_load],
       [AC_CHECK_LIB([dld], [shl_load],
-	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	    [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
 	[AC_CHECK_FUNC([dlopen],
-	      [lt_cv_dlopen="dlopen"],
+	      [lt_cv_dlopen=dlopen],
 	  [AC_CHECK_LIB([dl], [dlopen],
-		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+		[lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
 	    [AC_CHECK_LIB([svld], [dlopen],
-		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+		  [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
 	      [AC_CHECK_LIB([dld], [dld_link],
-		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+		    [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
 	      ])
 	    ])
 	  ])
@@ -1913,21 +1983,21 @@ else
     ;;
   esac
 
-  if test "x$lt_cv_dlopen" != xno; then
-    enable_dlopen=yes
-  else
+  if test no = "$lt_cv_dlopen"; then
     enable_dlopen=no
+  else
+    enable_dlopen=yes
   fi
 
   case $lt_cv_dlopen in
   dlopen)
-    save_CPPFLAGS="$CPPFLAGS"
-    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+    save_CPPFLAGS=$CPPFLAGS
+    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
 
-    save_LDFLAGS="$LDFLAGS"
+    save_LDFLAGS=$LDFLAGS
     wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
 
-    save_LIBS="$LIBS"
+    save_LIBS=$LIBS
     LIBS="$lt_cv_dlopen_libs $LIBS"
 
     AC_CACHE_CHECK([whether a program can dlopen itself],
@@ -1937,7 +2007,7 @@ else
 	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
     ])
 
-    if test "x$lt_cv_dlopen_self" = xyes; then
+    if test yes = "$lt_cv_dlopen_self"; then
       wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
       AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
 	  lt_cv_dlopen_self_static, [dnl
@@ -1947,9 +2017,9 @@ else
       ])
     fi
 
-    CPPFLAGS="$save_CPPFLAGS"
-    LDFLAGS="$save_LDFLAGS"
-    LIBS="$save_LIBS"
+    CPPFLAGS=$save_CPPFLAGS
+    LDFLAGS=$save_LDFLAGS
+    LIBS=$save_LIBS
     ;;
   esac
 
@@ -2041,8 +2111,8 @@ m4_defun([_LT_COMPILER_FILE_LOCKS],
 m4_require([_LT_FILEUTILS_DEFAULTS])dnl
 _LT_COMPILER_C_O([$1])
 
-hard_links="nottested"
-if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
   # do not overwrite the value of need_locks provided by the user
   AC_MSG_CHECKING([if we can lock with hard links])
   hard_links=yes
@@ -2052,8 +2122,8 @@ if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" !=
   ln conftest.a conftest.b 2>&5 || hard_links=no
   ln conftest.a conftest.b 2>/dev/null && hard_links=no
   AC_MSG_RESULT([$hard_links])
-  if test "$hard_links" = no; then
-    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+  if test no = "$hard_links"; then
+    AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
     need_locks=warn
   fi
 else
@@ -2080,8 +2150,8 @@ objdir=$lt_cv_objdir
 _LT_DECL([], [objdir], [0],
          [The name of the directory that contains temporary libtool files])dnl
 m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
-  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+  [Define to the sub-directory where libtool stores uninstalled libraries.])
 ])# _LT_CHECK_OBJDIR
 
 
@@ -2093,15 +2163,15 @@ m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
 _LT_TAGVAR(hardcode_action, $1)=
 if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
    test -n "$_LT_TAGVAR(runpath_var, $1)" ||
-   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+   test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
 
   # We can hardcode non-existent directories.
-  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+  if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
      # If the only mechanism to avoid hardcoding is shlibpath_var, we
      # have to relink, otherwise we might link with an installed library
      # when we should be linking with a yet-to-be-installed one
-     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
-     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+     test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
     # Linking always hardcodes the temporary library directory.
     _LT_TAGVAR(hardcode_action, $1)=relink
   else
@@ -2115,12 +2185,12 @@ else
 fi
 AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
 
-if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
-   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+   test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
   # Fast installation is not supported
   enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
-     test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
   # Fast installation is not necessary
   enable_fast_install=needless
 fi
@@ -2144,7 +2214,7 @@ else
 # FIXME - insert some real tests, host_os isn't really good enough
   case $host_os in
   darwin*)
-    if test -n "$STRIP" ; then
+    if test -n "$STRIP"; then
       striplib="$STRIP -x"
       old_striplib="$STRIP -S"
       AC_MSG_RESULT([yes])
@@ -2162,6 +2232,47 @@ _LT_DECL([], [striplib], [1])
 ])# _LT_CMD_STRIPLIB
 
 
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x at S|@2 in
+    x)
+        ;;
+    *:)
+        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+        ;;
+    x:*)
+        eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+        ;;
+    *)
+        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
 # _LT_SYS_DYNAMIC_LINKER([TAG])
 # -----------------------------
 # PORTME Fill in your ld.so characteristics
@@ -2172,17 +2283,18 @@ m4_require([_LT_FILEUTILS_DEFAULTS])dnl
 m4_require([_LT_DECL_OBJDUMP])dnl
 m4_require([_LT_DECL_SED])dnl
 m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
 AC_MSG_CHECKING([dynamic linker characteristics])
 m4_if([$1],
 	[], [
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   case $host_os in
-    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
-    *) lt_awk_arg="/^libraries:/" ;;
+    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+    *) lt_awk_arg='/^libraries:/' ;;
   esac
   case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
-    *) lt_sed_strip_eq="s,=/,/,g" ;;
+    mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+    *) lt_sed_strip_eq='s|=/|/|g' ;;
   esac
   lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
   case $lt_search_path_spec in
@@ -2198,28 +2310,35 @@ if test "$GCC" = yes; then
     ;;
   esac
   # Ok, now we have the path, separated by spaces, we can step through it
-  # and add multilib dir if necessary.
+  # and add multilib dir if necessary...
   lt_tmp_lt_search_path_spec=
-  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  # ...but if some path component already ends with the multilib dir we assume
+  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+  case "$lt_multi_os_dir; $lt_search_path_spec " in
+  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+    lt_multi_os_dir=
+    ;;
+  esac
   for lt_sys_path in $lt_search_path_spec; do
-    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
-      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
-    else
+    if test -d "$lt_sys_path$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+    elif test -n "$lt_multi_os_dir"; then
       test -d "$lt_sys_path" && \
 	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
     fi
   done
   lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
-  lt_foo="";
-  lt_count=0;
+BEGIN {RS = " "; FS = "/|\n";} {
+  lt_foo = "";
+  lt_count = 0;
   for (lt_i = NF; lt_i > 0; lt_i--) {
     if ($lt_i != "" && $lt_i != ".") {
       if ($lt_i == "..") {
         lt_count++;
       } else {
         if (lt_count == 0) {
-          lt_foo="/" $lt_i lt_foo;
+          lt_foo = "/" $lt_i lt_foo;
         } else {
           lt_count--;
         }
@@ -2233,7 +2352,7 @@ BEGIN {RS=" "; FS="/|\n";} {
   # for these hosts.
   case $host_os in
     mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
-      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+      $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
   esac
   sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
 else
@@ -2242,7 +2361,7 @@ fi])
 library_names_spec=
 libname_spec='lib$name'
 soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
 postinstall_cmds=
 postuninstall_cmds=
 finish_cmds=
@@ -2259,14 +2378,17 @@ hardcode_into_libs=no
 # flags to be left without arguments
 need_version=unknown
 
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
 case $host_os in
 aix3*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
   shlibpath_var=LIBPATH
 
   # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='${libname}${release}${shared_ext}$major'
+  soname_spec='$libname$release$shared_ext$major'
   ;;
 
 aix[[4-9]]*)
@@ -2274,41 +2396,91 @@ aix[[4-9]]*)
   need_lib_prefix=no
   need_version=no
   hardcode_into_libs=yes
-  if test "$host_cpu" = ia64; then
+  if test ia64 = "$host_cpu"; then
     # AIX 5 supports IA64
-    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
     shlibpath_var=LD_LIBRARY_PATH
   else
     # With GCC up to 2.95.x, collect2 would create an import file
     # for dependence libraries.  The import file would start with
-    # the line `#! .'.  This would cause the generated library to
-    # depend on `.', always an invalid library.  This was fixed in
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
     # development snapshots of GCC prior to 3.0.
     case $host_os in
       aix4 | aix4.[[01]] | aix4.[[01]].*)
       if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
 	   echo ' yes '
-	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
 	:
       else
 	can_build_shared=no
       fi
       ;;
     esac
-    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
     # soname into executable. Probably we can add versioning support to
     # collect2, so additional links can be useful in future.
-    if test "$aix_use_runtimelinking" = yes; then
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
       # If using run time linking (on AIX 4.2 or later) use lib<name>.so
       # instead of lib<name>.a to let people know that these are not
       # typical AIX shared libraries.
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    else
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a[(]lib.so.V[)]'
       # We preserve .a as extension for shared libraries through AIX4.2
       # and later when we are not doing run time linking.
-      library_names_spec='${libname}${release}.a $libname.a'
-      soname_spec='${libname}${release}${shared_ext}$major'
-    fi
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
     shlibpath_var=LIBPATH
   fi
   ;;
@@ -2318,18 +2490,18 @@ amigaos*)
   powerpc)
     # Since July 2007 AmigaOS4 officially supports .so libraries.
     # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
     ;;
   m68k)
     library_names_spec='$libname.ixlibrary $libname.a'
     # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
     ;;
   esac
   ;;
 
 beos*)
-  library_names_spec='${libname}${shared_ext}'
+  library_names_spec='$libname$shared_ext'
   dynamic_linker="$host_os ld.so"
   shlibpath_var=LIBRARY_PATH
   ;;
@@ -2337,8 +2509,8 @@ beos*)
 bsdi[[45]]*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -2350,7 +2522,7 @@ bsdi[[45]]*)
 
 cygwin* | mingw* | pw32* | cegcc*)
   version_type=windows
-  shrext_cmds=".dll"
+  shrext_cmds=.dll
   need_version=no
   need_lib_prefix=no
 
@@ -2359,8 +2531,8 @@ cygwin* | mingw* | pw32* | cegcc*)
     # gcc
     library_names_spec='$libname.dll.a'
     # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
       dldir=$destdir/`dirname \$dlpath`~
       test -d \$dldir || mkdir -p \$dldir~
       $install_prog $dir/$dlname \$dldir/$dlname~
@@ -2376,17 +2548,17 @@ cygwin* | mingw* | pw32* | cegcc*)
     case $host_os in
     cygwin*)
       # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
 m4_if([$1], [],[
       sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
       ;;
     mingw* | cegcc*)
       # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
       ;;
     pw32*)
       # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
       ;;
     esac
     dynamic_linker='Win32 ld.exe'
@@ -2395,8 +2567,8 @@ m4_if([$1], [],[
   *,cl*)
     # Native MSVC
     libname_spec='$name'
-    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
-    library_names_spec='${libname}.dll.lib'
+    soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
 
     case $build_os in
     mingw*)
@@ -2423,7 +2595,7 @@ m4_if([$1], [],[
       sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
       ;;
     *)
-      sys_lib_search_path_spec="$LIB"
+      sys_lib_search_path_spec=$LIB
       if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
         # It is most probably a Windows format PATH.
         sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -2436,8 +2608,8 @@ m4_if([$1], [],[
     esac
 
     # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \${file}`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
       dldir=$destdir/`dirname \$dlpath`~
       test -d \$dldir || mkdir -p \$dldir~
       $install_prog $dir/$dlname \$dldir/$dlname'
@@ -2450,7 +2622,7 @@ m4_if([$1], [],[
 
   *)
     # Assume MSVC wrapper
-    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
     dynamic_linker='Win32 ld.exe'
     ;;
   esac
@@ -2463,8 +2635,8 @@ darwin* | rhapsody*)
   version_type=darwin
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
-  soname_spec='${libname}${release}${major}$shared_ext'
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
   shlibpath_overrides_runpath=yes
   shlibpath_var=DYLD_LIBRARY_PATH
   shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
@@ -2477,8 +2649,8 @@ dgux*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   ;;
 
@@ -2496,12 +2668,13 @@ freebsd* | dragonfly*)
   version_type=freebsd-$objformat
   case $version_type in
     freebsd-elf*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
       need_version=no
       need_lib_prefix=no
       ;;
     freebsd-*)
-      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
       need_version=yes
       ;;
   esac
@@ -2531,10 +2704,10 @@ haiku*)
   need_lib_prefix=no
   need_version=no
   dynamic_linker="$host_os runtime_loader"
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
+  shlibpath_overrides_runpath=no
   sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
   hardcode_into_libs=yes
   ;;
@@ -2552,14 +2725,15 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.so"
     shlibpath_var=LD_LIBRARY_PATH
     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
-    if test "X$HPUX_IA64_MODE" = X32; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
       sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
     else
       sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
     fi
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
   hppa*64*)
     shrext_cmds='.sl'
@@ -2567,8 +2741,8 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.sl"
     shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
     shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
     sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
     ;;
@@ -2577,8 +2751,8 @@ hpux9* | hpux10* | hpux11*)
     dynamic_linker="$host_os dld.sl"
     shlibpath_var=SHLIB_PATH
     shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     ;;
   esac
   # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -2591,8 +2765,8 @@ interix[[3-9]]*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
@@ -2603,7 +2777,7 @@ irix5* | irix6* | nonstopux*)
   case $host_os in
     nonstopux*) version_type=nonstopux ;;
     *)
-	if test "$lt_cv_prog_gnu_ld" = yes; then
+	if test yes = "$lt_cv_prog_gnu_ld"; then
 		version_type=linux # correct to gnu/linux during the next big refactor
 	else
 		version_type=irix
@@ -2611,8 +2785,8 @@ irix5* | irix6* | nonstopux*)
   esac
   need_lib_prefix=no
   need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
   case $host_os in
   irix5* | nonstopux*)
     libsuff= shlibsuff=
@@ -2631,8 +2805,8 @@ irix5* | irix6* | nonstopux*)
   esac
   shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
   shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
-  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
   hardcode_into_libs=yes
   ;;
 
@@ -2641,13 +2815,33 @@ linux*oldld* | linux*aout* | linux*coff*)
   dynamic_linker=no
   ;;
 
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+  ;;
+
 # This must be glibc/ELF.
 linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
@@ -2672,7 +2866,12 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   # before this can be enabled.
   hardcode_into_libs=yes
 
-  # Append ld.so.conf contents to the search path
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
   if test -f /etc/ld.so.conf; then
     lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
     sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -2704,12 +2903,12 @@ netbsd*)
   need_lib_prefix=no
   need_version=no
   if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
     finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
     dynamic_linker='NetBSD (a.out) ld.so'
   else
-    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-    soname_spec='${libname}${release}${shared_ext}$major'
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
     dynamic_linker='NetBSD ld.elf_so'
   fi
   shlibpath_var=LD_LIBRARY_PATH
@@ -2719,7 +2918,7 @@ netbsd*)
 
 newsos6)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   ;;
@@ -2728,58 +2927,68 @@ newsos6)
   version_type=qnx
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
   dynamic_linker='ldqnx.so'
   ;;
 
-openbsd*)
+openbsd* | bitrig*)
   version_type=sunos
-  sys_lib_dlsearch_path_spec="/usr/lib"
+  sys_lib_dlsearch_path_spec=/usr/lib
   need_lib_prefix=no
-  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
-  case $host_os in
-    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
-    *)				need_version=no  ;;
-  esac
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-    case $host_os in
-      openbsd2.[[89]] | openbsd2.[[89]].*)
-	shlibpath_overrides_runpath=no
-	;;
-      *)
-	shlibpath_overrides_runpath=yes
-	;;
-      esac
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
   else
-    shlibpath_overrides_runpath=yes
+    need_version=yes
   fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
   ;;
 
 os2*)
   libname_spec='$name'
-  shrext_cmds=".dll"
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
   need_lib_prefix=no
-  library_names_spec='$libname${shared_ext} $libname.a'
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
   dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=LIBPATH
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
   ;;
 
 osf3* | osf4* | osf5*)
   version_type=osf
   need_lib_prefix=no
   need_version=no
-  soname_spec='${libname}${release}${shared_ext}$major'
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
   ;;
 
 rdos*)
@@ -2790,8 +2999,8 @@ solaris*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   hardcode_into_libs=yes
@@ -2801,11 +3010,11 @@ solaris*)
 
 sunos4*)
   version_type=sunos
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
   finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     need_lib_prefix=no
   fi
   need_version=yes
@@ -2813,8 +3022,8 @@ sunos4*)
 
 sysv4 | sysv4.3*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   case $host_vendor in
     sni)
@@ -2835,24 +3044,24 @@ sysv4 | sysv4.3*)
   ;;
 
 sysv4*MP*)
-  if test -d /usr/nec ;then
+  if test -d /usr/nec; then
     version_type=linux # correct to gnu/linux during the next big refactor
-    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
-    soname_spec='$libname${shared_ext}.$major'
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
     shlibpath_var=LD_LIBRARY_PATH
   fi
   ;;
 
 sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=freebsd-elf
+  version_type=sco
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=yes
   hardcode_into_libs=yes
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
   else
     sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -2870,7 +3079,7 @@ tpf*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
   shlibpath_var=LD_LIBRARY_PATH
   shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
@@ -2878,8 +3087,8 @@ tpf*)
 
 uts4*)
   version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
   shlibpath_var=LD_LIBRARY_PATH
   ;;
 
@@ -2888,20 +3097,30 @@ uts4*)
   ;;
 esac
 AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
 
 variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
 fi
 
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
-  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
 fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
-  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
 fi
 
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
 _LT_DECL([], [variables_saved_for_relink], [1],
     [Variables whose values should be saved in libtool wrapper scripts and
     restored at link time])
@@ -2934,39 +3153,41 @@ _LT_DECL([], [hardcode_into_libs], [0],
     [Whether we should hardcode library paths into libraries])
 _LT_DECL([], [sys_lib_search_path_spec], [2],
     [Compile-time system search path for libraries])
-_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
-    [Run-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+    [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+    [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
 ])# _LT_SYS_DYNAMIC_LINKER
 
 
 # _LT_PATH_TOOL_PREFIX(TOOL)
 # --------------------------
-# find a file program which can recognize shared library
+# find a file program that can recognize shared library
 AC_DEFUN([_LT_PATH_TOOL_PREFIX],
 [m4_require([_LT_DECL_EGREP])dnl
 AC_MSG_CHECKING([for $1])
 AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
 [case $MAGIC_CMD in
 [[\\/*] |  ?:[\\/]*])
-  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
   ;;
 *)
-  lt_save_MAGIC_CMD="$MAGIC_CMD"
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
 dnl $ac_dummy forces splitting on constant user-supplied paths.
 dnl POSIX.2 word splitting is done only on the output of word expansions,
 dnl not every word.  This closes a longstanding sh security hole.
   ac_dummy="m4_if([$2], , $PATH, [$2])"
   for ac_dir in $ac_dummy; do
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
     test -z "$ac_dir" && ac_dir=.
-    if test -f $ac_dir/$1; then
-      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+    if test -f "$ac_dir/$1"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
       if test -n "$file_magic_test_file"; then
 	case $deplibs_check_method in
 	"file_magic "*)
 	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
 	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
 	    $EGREP "$file_magic_regex" > /dev/null; then
 	    :
@@ -2989,11 +3210,11 @@ _LT_EOF
       break
     fi
   done
-  IFS="$lt_save_ifs"
-  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
   ;;
 esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
 if test -n "$MAGIC_CMD"; then
   AC_MSG_RESULT($MAGIC_CMD)
 else
@@ -3011,7 +3232,7 @@ dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
 
 # _LT_PATH_MAGIC
 # --------------
-# find a file program which can recognize a shared library
+# find a file program that can recognize a shared library
 m4_defun([_LT_PATH_MAGIC],
 [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
 if test -z "$lt_cv_path_MAGIC_CMD"; then
@@ -3038,16 +3259,16 @@ m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
 AC_ARG_WITH([gnu-ld],
     [AS_HELP_STRING([--with-gnu-ld],
 	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
-    [test "$withval" = no || with_gnu_ld=yes],
+    [test no = "$withval" || with_gnu_ld=yes],
     [with_gnu_ld=no])dnl
 
 ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   # Check if gcc -print-prog-name=ld gives a path.
   AC_MSG_CHECKING([for ld used by $CC])
   case $host in
   *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
+    # gcc leaves a trailing carriage return, which upsets mingw
     ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
   *)
     ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -3061,7 +3282,7 @@ if test "$GCC" = yes; then
       while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
 	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
       done
-      test -z "$LD" && LD="$ac_prog"
+      test -z "$LD" && LD=$ac_prog
       ;;
   "")
     # If it fails, then pretend we aren't using GCC.
@@ -3072,37 +3293,37 @@ if test "$GCC" = yes; then
     with_gnu_ld=unknown
     ;;
   esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
   AC_MSG_CHECKING([for GNU ld])
 else
   AC_MSG_CHECKING([for non-GNU ld])
 fi
 AC_CACHE_VAL(lt_cv_path_LD,
 [if test -z "$LD"; then
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
   for ac_dir in $PATH; do
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
     test -z "$ac_dir" && ac_dir=.
     if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
+      lt_cv_path_LD=$ac_dir/$ac_prog
       # Check to see if the program is GNU ld.  I'd rather use --version,
       # but apparently some variants of GNU ld only accept -v.
       # Break only if it was the GNU/non-GNU ld that we prefer.
       case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
       *GNU* | *'with BFD'*)
-	test "$with_gnu_ld" != no && break
+	test no != "$with_gnu_ld" && break
 	;;
       *)
-	test "$with_gnu_ld" != yes && break
+	test yes != "$with_gnu_ld" && break
 	;;
       esac
     fi
   done
-  IFS="$lt_save_ifs"
+  IFS=$lt_save_ifs
 else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
 fi])
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
 if test -n "$LD"; then
   AC_MSG_RESULT($LD)
 else
@@ -3156,13 +3377,13 @@ esac
 reload_cmds='$LD$reload_flag -o $output$reload_objs'
 case $host_os in
   cygwin* | mingw* | pw32* | cegcc*)
-    if test "$GCC" != yes; then
+    if test yes != "$GCC"; then
       reload_cmds=false
     fi
     ;;
   darwin*)
-    if test "$GCC" = yes; then
-      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    if test yes = "$GCC"; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
     else
       reload_cmds='$LD$reload_flag -o $output$reload_objs'
     fi
@@ -3173,6 +3394,43 @@ _LT_TAGDECL([], [reload_cmds], [2])dnl
 ])# _LT_CMD_RELOAD
 
 
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+  [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
 # _LT_CHECK_MAGIC_METHOD
 # ----------------------
 # how to check for library dependencies
@@ -3188,13 +3446,13 @@ lt_cv_deplibs_check_method='unknown'
 # Need to set the preceding variable on all platforms that support
 # interlibrary dependencies.
 # 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
+# 'unknown' -- same as none, but documents that we really don't know.
 # 'pass_all' -- all dependencies passed with no checks.
 # 'test_compile' -- check by making test program.
 # 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
 
 case $host_os in
 aix[[4-9]]*)
@@ -3221,8 +3479,7 @@ mingw* | pw32*)
   # Base MSYS/MinGW do not provide the 'file' command needed by
   # func_win32_libid shell function, so use a weaker test based on 'objdump',
   # unless we find 'file', for example because we are cross-compiling.
-  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
-  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+  if ( file / ) >/dev/null 2>&1; then
     lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
     lt_cv_file_magic_cmd='func_win32_libid'
   else
@@ -3318,8 +3575,8 @@ newos6*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
-openbsd*)
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+openbsd* | bitrig*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
     lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
   else
     lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
@@ -3372,6 +3629,9 @@ sysv4 | sysv4.3*)
 tpf*)
   lt_cv_deplibs_check_method=pass_all
   ;;
+os2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
 esac
 ])
 
@@ -3412,33 +3672,38 @@ AC_DEFUN([LT_PATH_NM],
 AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
 [if test -n "$NM"; then
   # Let the user override the test.
-  lt_cv_path_NM="$NM"
+  lt_cv_path_NM=$NM
 else
-  lt_nm_to_check="${ac_tool_prefix}nm"
+  lt_nm_to_check=${ac_tool_prefix}nm
   if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
     lt_nm_to_check="$lt_nm_to_check nm"
   fi
   for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
     for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       test -z "$ac_dir" && ac_dir=.
-      tmp_nm="$ac_dir/$lt_tmp_nm"
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
 	# Check to see if the nm accepts a BSD-compat flag.
-	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
 	#   nm: unknown option "B" ignored
 	# Tru64's nm complains that /dev/null is an invalid object file
-	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
-	*/dev/null* | *'Invalid file or object type'*)
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
 	  lt_cv_path_NM="$tmp_nm -B"
-	  break
+	  break 2
 	  ;;
 	*)
 	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
 	  */dev/null*)
 	    lt_cv_path_NM="$tmp_nm -p"
-	    break
+	    break 2
 	    ;;
 	  *)
 	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
@@ -3449,21 +3714,21 @@ else
 	esac
       fi
     done
-    IFS="$lt_save_ifs"
+    IFS=$lt_save_ifs
   done
   : ${lt_cv_path_NM=no}
 fi])
-if test "$lt_cv_path_NM" != "no"; then
-  NM="$lt_cv_path_NM"
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
 else
   # Didn't find any BSD compatible name lister, look for dumpbin.
   if test -n "$DUMPBIN"; then :
     # Let the user override the test.
   else
     AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
-    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
     *COFF*)
-      DUMPBIN="$DUMPBIN -symbols"
+      DUMPBIN="$DUMPBIN -symbols -headers"
       ;;
     *)
       DUMPBIN=:
@@ -3471,8 +3736,8 @@ else
     esac
   fi
   AC_SUBST([DUMPBIN])
-  if test "$DUMPBIN" != ":"; then
-    NM="$DUMPBIN"
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
   fi
 fi
 test -z "$NM" && NM=nm
@@ -3518,8 +3783,8 @@ lt_cv_sharedlib_from_linklib_cmd,
 
 case $host_os in
 cygwin* | mingw* | pw32* | cegcc*)
-  # two different shell functions defined in ltmain.sh
-  # decide which to use based on capabilities of $DLLTOOL
+  # two different shell functions defined in ltmain.sh;
+  # decide which one to use based on capabilities of $DLLTOOL
   case `$DLLTOOL --help 2>&1` in
   *--identify-strict*)
     lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
@@ -3531,7 +3796,7 @@ cygwin* | mingw* | pw32* | cegcc*)
   ;;
 *)
   # fallback: assume linklib IS sharedlib
-  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  lt_cv_sharedlib_from_linklib_cmd=$ECHO
   ;;
 esac
 ])
@@ -3558,13 +3823,28 @@ AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool
     lt_cv_path_mainfest_tool=yes
   fi
   rm -f conftest*])
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
+if test yes != "$lt_cv_path_mainfest_tool"; then
   MANIFEST_TOOL=:
 fi
 _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
 ])# _LT_PATH_MANIFEST_TOOL
 
 
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+  test DEF = "`$SED -n dnl
+    -e '\''s/^[[	 ]]*//'\'' dnl Strip leading whitespace
+    -e '\''/^\(;.*\)*$/d'\'' dnl      Delete empty lines and comments
+    -e '\''s/^\(EXPORTS\|LIBRARY\)\([[	 ]].*\)*$/DEF/p'\'' dnl
+    -e q dnl                          Only consider the first "real" line
+    $1`" dnl
+])# _LT_DLL_DEF_P
+
+
 # LT_LIB_M
 # --------
 # check for math library
@@ -3576,11 +3856,11 @@ case $host in
   # These system don't have libm, or don't need it
   ;;
 *-ncr-sysv4.3*)
-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
   AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
   ;;
 *)
-  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  AC_CHECK_LIB(m, cos, LIBM=-lm)
   ;;
 esac
 AC_SUBST([LIBM])
@@ -3599,7 +3879,7 @@ m4_defun([_LT_COMPILER_NO_RTTI],
 
 _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
 
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
   case $cc_basename in
   nvcc*)
     _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
@@ -3651,7 +3931,7 @@ cygwin* | mingw* | pw32* | cegcc*)
   symcode='[[ABCDGISTW]]'
   ;;
 hpux*)
-  if test "$host_cpu" = ia64; then
+  if test ia64 = "$host_cpu"; then
     symcode='[[ABCDEGRST]]'
   fi
   ;;
@@ -3684,14 +3964,44 @@ case `$NM -V 2>&1` in
   symcode='[[ABCDGIRSTW]]' ;;
 esac
 
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  # Gets list of data symbols to import.
+  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+  # Adjust the below global symbol transforms to fixup imported variables.
+  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
+  lt_c_name_lib_hook="\
+  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
+  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
+else
+  # Disable hooks by default.
+  lt_cv_sys_global_symbol_to_import=
+  lt_cdecl_hook=
+  lt_c_name_hook=
+  lt_c_name_lib_hook=
+fi
+
 # Transform an extracted symbol line into a proper C declaration.
 # Some systems (esp. on ia64) link data and code symbols differently,
 # so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
 
 # Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
 
 # Handle CRLF in mingw tool chain
 opt_cr=
@@ -3709,21 +4019,24 @@ for ac_symprfx in "" "_"; do
 
   # Write the raw and C identifiers.
   if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-    # Fake it for dumpbin and say T for any non-static function
-    # and D for any global variable.
+    # Fake it for dumpbin and say T for any non-static function,
+    # D for any global variable and I for any imported variable.
     # Also find C++ and __fastcall symbols from MSVC++,
     # which start with @ or ?.
     lt_cv_sys_global_symbol_pipe="$AWK ['"\
 "     {last_section=section; section=\$ 3};"\
 "     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
 "     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
 "     \$ 0!~/External *\|/{next};"\
 "     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
 "     {if(hide[section]) next};"\
-"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
-"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
 "     ' prfx=^$ac_symprfx]"
   else
     lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
@@ -3763,11 +4076,11 @@ _LT_EOF
 	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
 	  cat <<_LT_EOF > conftest.$ac_ext
 /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
    relocations are performed -- see ld's documentation on pseudo-relocs.  */
 # define LT@&t at _DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
 /* This system does not cope well with relocations in const data.  */
 # define LT@&t at _DLSYM_CONST
 #else
@@ -3793,7 +4106,7 @@ lt__PROGRAM__LTX_preloaded_symbols[[]] =
 {
   { "@PROGRAM@", (void *) 0 },
 _LT_EOF
-	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
 	  cat <<\_LT_EOF >> conftest.$ac_ext
   {0, (void *) 0}
 };
@@ -3813,9 +4126,9 @@ _LT_EOF
 	  mv conftest.$ac_objext conftstm.$ac_objext
 	  lt_globsym_save_LIBS=$LIBS
 	  lt_globsym_save_CFLAGS=$CFLAGS
-	  LIBS="conftstm.$ac_objext"
+	  LIBS=conftstm.$ac_objext
 	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
-	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	  if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
 	    pipe_works=yes
 	  fi
 	  LIBS=$lt_globsym_save_LIBS
@@ -3836,7 +4149,7 @@ _LT_EOF
   rm -rf conftest* conftst*
 
   # Do not use the global_symbol_pipe unless it works.
-  if test "$pipe_works" = yes; then
+  if test yes = "$pipe_works"; then
     break
   else
     lt_cv_sys_global_symbol_pipe=
@@ -3863,12 +4176,16 @@ _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
     [Take the output of nm and produce a listing of raw symbols and C names])
 _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
     [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+    [Transform the output of nm into a list of symbols to manually relocate])
 _LT_DECL([global_symbol_to_c_name_address],
     [lt_cv_sys_global_symbol_to_c_name_address], [1],
     [Transform the output of nm in a C name address pair])
 _LT_DECL([global_symbol_to_c_name_address_lib_prefix],
     [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
     [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+    [The name lister interface])
 _LT_DECL([], [nm_file_list_spec], [1],
     [Specify filename containing input files for $NM])
 ]) # _LT_CMD_GLOBAL_SYMBOLS
@@ -3884,17 +4201,18 @@ _LT_TAGVAR(lt_prog_compiler_static, $1)=
 
 m4_if([$1], [CXX], [
   # C++ specific cases for pic, static, wl, etc.
-  if test "$GXX" = yes; then
+  if test yes = "$GXX"; then
     _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
     _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
 
     case $host_os in
     aix*)
       # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# AIX 5 now supports IA64 processor
 	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
       fi
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
       ;;
 
     amigaos*)
@@ -3905,8 +4223,8 @@ m4_if([$1], [CXX], [
         ;;
       m68k)
             # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
             _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
         ;;
       esac
@@ -3922,6 +4240,11 @@ m4_if([$1], [CXX], [
       # (--disable-auto-import) libraries
       m4_if([$1], [GCJ], [],
 	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
       ;;
     darwin* | rhapsody*)
       # PIC is the default on this platform
@@ -3971,7 +4294,7 @@ m4_if([$1], [CXX], [
     case $host_os in
       aix[[4-9]]*)
 	# All AIX code is PIC.
-	if test "$host_cpu" = ia64; then
+	if test ia64 = "$host_cpu"; then
 	  # AIX 5 now supports IA64 processor
 	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
 	else
@@ -4012,14 +4335,14 @@ m4_if([$1], [CXX], [
 	case $cc_basename in
 	  CC*)
 	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
-	    if test "$host_cpu" != ia64; then
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+	    if test ia64 != "$host_cpu"; then
 	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
 	    fi
 	    ;;
 	  aCC*)
 	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
 	    case $host_cpu in
 	    hppa*64*|ia64*)
 	      # +Z the default
@@ -4056,7 +4379,7 @@ m4_if([$1], [CXX], [
 	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
 	    ;;
 	  ecpc* )
-	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    # old Intel C++ for x86_64, which still supported -KPIC.
 	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
 	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
 	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
@@ -4201,17 +4524,18 @@ m4_if([$1], [CXX], [
   fi
 ],
 [
-  if test "$GCC" = yes; then
+  if test yes = "$GCC"; then
     _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
     _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
 
     case $host_os in
       aix*)
       # All AIX code is PIC.
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# AIX 5 now supports IA64 processor
 	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
       fi
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
       ;;
 
     amigaos*)
@@ -4222,8 +4546,8 @@ m4_if([$1], [CXX], [
         ;;
       m68k)
             # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the `-m68020' flag to GCC prevents building anything better,
-            # like `-m68040'.
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
             _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
         ;;
       esac
@@ -4240,6 +4564,11 @@ m4_if([$1], [CXX], [
       # (--disable-auto-import) libraries
       m4_if([$1], [GCJ], [],
 	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
       ;;
 
     darwin* | rhapsody*)
@@ -4310,7 +4639,7 @@ m4_if([$1], [CXX], [
     case $host_os in
     aix*)
       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# AIX 5 now supports IA64 processor
 	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
       else
@@ -4318,11 +4647,30 @@ m4_if([$1], [CXX], [
       fi
       ;;
 
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      case $cc_basename in
+      nagfor*)
+        # NAG Fortran compiler
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      esac
+      ;;
+
     mingw* | cygwin* | pw32* | os2* | cegcc*)
       # This hack is so that the source file can tell whether it is being
       # built for inclusion in a dll (and should export symbols for example).
       m4_if([$1], [GCJ], [],
 	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
       ;;
 
     hpux9* | hpux10* | hpux11*)
@@ -4338,7 +4686,7 @@ m4_if([$1], [CXX], [
 	;;
       esac
       # Is there a better lt_prog_compiler_static that works with the bundled CC?
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
       ;;
 
     irix5* | irix6* | nonstopux*)
@@ -4349,7 +4697,7 @@ m4_if([$1], [CXX], [
 
     linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
       case $cc_basename in
-      # old Intel for x86_64 which still supported -KPIC.
+      # old Intel for x86_64, which still supported -KPIC.
       ecc*)
 	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
 	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
@@ -4374,6 +4722,12 @@ m4_if([$1], [CXX], [
 	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
 	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
 	;;
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	;;
       pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
         # Portland Group compilers (*not* the Pentium gcc compiler,
 	# which looks to be a dead project)
@@ -4471,7 +4825,7 @@ m4_if([$1], [CXX], [
       ;;
 
     sysv4*MP*)
-      if test -d /usr/nec ;then
+      if test -d /usr/nec; then
 	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
 	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
       fi
@@ -4500,7 +4854,7 @@ m4_if([$1], [CXX], [
   fi
 ])
 case $host_os in
-  # For platforms which do not support PIC, -DPIC is meaningless:
+  # For platforms that do not support PIC, -DPIC is meaningless:
   *djgpp*)
     _LT_TAGVAR(lt_prog_compiler_pic, $1)=
     ;;
@@ -4566,17 +4920,21 @@ m4_if([$1], [CXX], [
   case $host_os in
   aix[[4-9]]*)
     # If we're using GNU nm, then we don't want the "-C" option.
-    # -C means demangle to AIX nm, but means don't demangle with GNU nm
-    # Also, AIX nm treats weak defined symbols like other global defined
-    # symbols, whereas GNU nm marks them as "W".
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
     else
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
-    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
     ;;
   cygwin* | mingw* | cegcc*)
     case $cc_basename in
@@ -4625,9 +4983,9 @@ m4_if([$1], [CXX], [
   # included in the symbol list
   _LT_TAGVAR(include_expsyms, $1)=
   # exclude_expsyms can be an extended regexp of symbols to exclude
-  # it will be wrapped by ` (' and `)$', so one must not match beginning or
-  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-  # as well as any symbol that contains `d'.
+  # it will be wrapped by ' (' and ')$', so one must not match beginning or
+  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+  # as well as any symbol that contains 'd'.
   _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
   # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
   # platforms (ab)use it in PIC code, but their linkers get confused if
@@ -4643,7 +5001,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
     # FIXME: the MSVC++ port hasn't been tested in a loooong time
     # When not using gcc, we currently assume that we are using
     # Microsoft Visual C++.
-    if test "$GCC" != yes; then
+    if test yes != "$GCC"; then
       with_gnu_ld=no
     fi
     ;;
@@ -4651,7 +5009,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
     # we just hope/assume this is gcc and not c89 (= MSVC++)
     with_gnu_ld=yes
     ;;
-  openbsd*)
+  openbsd* | bitrig*)
     with_gnu_ld=no
     ;;
   linux* | k*bsd*-gnu | gnu*)
@@ -4664,7 +5022,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
   # On some targets, GNU ld is compatible enough with the native linker
   # that we're better off using the native interface for both.
   lt_use_gnu_ld_interface=no
-  if test "$with_gnu_ld" = yes; then
+  if test yes = "$with_gnu_ld"; then
     case $host_os in
       aix*)
 	# The AIX port of GNU ld has always aspired to compatibility
@@ -4686,24 +5044,24 @@ dnl Note also adjust exclude_expsyms for C++ above.
     esac
   fi
 
-  if test "$lt_use_gnu_ld_interface" = yes; then
+  if test yes = "$lt_use_gnu_ld_interface"; then
     # If archive_cmds runs LD, not CC, wlarc should be empty
-    wlarc='${wl}'
+    wlarc='$wl'
 
     # Set some defaults for GNU ld with shared library support. These
     # are reset later if shared libraries are not supported. Putting them
     # here allows them to be overridden if necessary.
     runpath_var=LD_RUN_PATH
-    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
     # ancient GNU ld didn't support --whole-archive et. al.
     if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
-      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
     else
       _LT_TAGVAR(whole_archive_flag_spec, $1)=
     fi
     supports_anon_versioning=no
-    case `$LD -v 2>&1` in
+    case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
       *GNU\ gold*) supports_anon_versioning=yes ;;
       *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
       *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -4716,7 +5074,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
     case $host_os in
     aix[[3-9]]*)
       # On AIX/PPC, the GNU linker is very broken
-      if test "$host_cpu" != ia64; then
+      if test ia64 != "$host_cpu"; then
 	_LT_TAGVAR(ld_shlibs, $1)=no
 	cat <<_LT_EOF 1>&2
 
@@ -4735,7 +5093,7 @@ _LT_EOF
       case $host_cpu in
       powerpc)
             # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
             _LT_TAGVAR(archive_expsym_cmds, $1)=''
         ;;
       m68k)
@@ -4751,7 +5109,7 @@ _LT_EOF
 	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
 	# support --undefined.  This deserves some investigation.  FIXME
-	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
       else
 	_LT_TAGVAR(ld_shlibs, $1)=no
       fi
@@ -4761,7 +5119,7 @@ _LT_EOF
       # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
       # as there is no search path for DLLs.
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
       _LT_TAGVAR(always_export_symbols, $1)=no
       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -4769,61 +5127,89 @@ _LT_EOF
       _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
 
       if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	# If the export-symbols file already is a .def file (1st line
-	# is EXPORTS), use it as is; otherwise, prepend...
-	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	  cp $export_symbols $output_objdir/$soname.def;
-	else
-	  echo EXPORTS > $output_objdir/$soname.def;
-	  cat $export_symbols >> $output_objdir/$soname.def;
-	fi~
-	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file, use it as
+	# is; otherwise, prepend EXPORTS...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+          cp $export_symbols $output_objdir/$soname.def;
+        else
+          echo EXPORTS > $output_objdir/$soname.def;
+          cat $export_symbols >> $output_objdir/$soname.def;
+        fi~
+        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
       else
 	_LT_TAGVAR(ld_shlibs, $1)=no
       fi
       ;;
 
     haiku*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
       _LT_TAGVAR(link_all_deplibs, $1)=yes
       ;;
 
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      shrext_cmds=.dll
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
     interix[[3-9]]*)
       _LT_TAGVAR(hardcode_direct, $1)=no
       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
       # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
       # Instead, shared libraries are loaded at an image base (0x10000000 by
       # default) and relocated if they conflict, which is a slow very memory
       # consuming and fragmenting process.  To avoid this, we pick a random,
       # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
       # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
       ;;
 
     gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
       tmp_diet=no
-      if test "$host_os" = linux-dietlibc; then
+      if test linux-dietlibc = "$host_os"; then
 	case $cc_basename in
 	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
 	esac
       fi
       if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
-	 && test "$tmp_diet" = no
+	 && test no = "$tmp_diet"
       then
 	tmp_addflag=' $pic_flag'
 	tmp_sharedflag='-shared'
 	case $cc_basename,$host_cpu in
         pgcc*)				# Portland Group C compiler
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  tmp_addflag=' $pic_flag'
 	  ;;
 	pgf77* | pgf90* | pgf95* | pgfortran*)
 					# Portland Group f77 and f90 compilers
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  tmp_addflag=' $pic_flag -Mnomain' ;;
 	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
 	  tmp_addflag=' -i_dynamic' ;;
@@ -4834,42 +5220,47 @@ _LT_EOF
 	lf95*)				# Lahey Fortran 8.1
 	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
 	  tmp_sharedflag='--shared' ;;
+        nagfor*)                        # NAGFOR 5.3
+          tmp_sharedflag='-Wl,-shared' ;;
 	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
 	  tmp_sharedflag='-qmkshrobj'
 	  tmp_addflag= ;;
 	nvcc*)	# Cuda Compiler Driver 2.2
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  _LT_TAGVAR(compiler_needs_object, $1)=yes
 	  ;;
 	esac
 	case `$CC -V 2>&1 | sed 5q` in
 	*Sun\ C*)			# Sun C 5.9
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	  _LT_TAGVAR(compiler_needs_object, $1)=yes
 	  tmp_sharedflag='-G' ;;
 	*Sun\ F*)			# Sun Fortran 8.3
 	  tmp_sharedflag='-G' ;;
 	esac
-	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
 
-        if test "x$supports_anon_versioning" = xyes; then
+        if test yes = "$supports_anon_versioning"; then
           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-	    echo "local: *; };" >> $output_objdir/$libname.ver~
-	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+            echo "local: *; };" >> $output_objdir/$libname.ver~
+            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
         fi
 
 	case $cc_basename in
+	tcc*)
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+	  ;;
 	xlf* | bgf* | bgxlf* | mpixlf*)
 	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
 	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
 	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
-	  if test "x$supports_anon_versioning" = xyes; then
+	  if test yes = "$supports_anon_versioning"; then
 	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-	      echo "local: *; };" >> $output_objdir/$libname.ver~
-	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+              echo "local: *; };" >> $output_objdir/$libname.ver~
+              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
 	  fi
 	  ;;
 	esac
@@ -4883,8 +5274,8 @@ _LT_EOF
 	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
 	wlarc=
       else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
       fi
       ;;
 
@@ -4902,8 +5293,8 @@ _LT_EOF
 
 _LT_EOF
       elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
       else
 	_LT_TAGVAR(ld_shlibs, $1)=no
       fi
@@ -4915,7 +5306,7 @@ _LT_EOF
 	_LT_TAGVAR(ld_shlibs, $1)=no
 	cat <<_LT_EOF 1>&2
 
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
 *** reliably create shared libraries on SCO systems.  Therefore, libtool
 *** is disabling shared libraries support.  We urge you to upgrade GNU
 *** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
@@ -4930,9 +5321,9 @@ _LT_EOF
 	  # DT_RUNPATH tag from executables and libraries.  But doing so
 	  # requires that you compile everything twice, which is a pain.
 	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 	  else
 	    _LT_TAGVAR(ld_shlibs, $1)=no
 	  fi
@@ -4949,15 +5340,15 @@ _LT_EOF
 
     *)
       if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
       else
 	_LT_TAGVAR(ld_shlibs, $1)=no
       fi
       ;;
     esac
 
-    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+    if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
       runpath_var=
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
       _LT_TAGVAR(export_dynamic_flag_spec, $1)=
@@ -4973,7 +5364,7 @@ _LT_EOF
       # Note: this linker hardcodes the directories in LIBPATH if there
       # are no directories specified by -L.
       _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
 	# Neither direct hardcoding nor static linking is supported with a
 	# broken collect2.
 	_LT_TAGVAR(hardcode_direct, $1)=unsupported
@@ -4981,34 +5372,57 @@ _LT_EOF
       ;;
 
     aix[[4-9]]*)
-      if test "$host_cpu" = ia64; then
+      if test ia64 = "$host_cpu"; then
 	# On IA64, the linker does run time linking by default, so we don't
 	# have to do anything special.
 	aix_use_runtimelinking=no
 	exp_sym_flag='-Bexport'
-	no_entry_flag=""
+	no_entry_flag=
       else
 	# If we're using GNU nm, then we don't want the "-C" option.
-	# -C means demangle to AIX nm, but means don't demangle with GNU nm
-	# Also, AIX nm treats weak defined symbols like other global
-	# defined symbols, whereas GNU nm marks them as "W".
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
 	else
-	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	  _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
 	# Test if we are trying to use run time linking or normal
 	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
-	# need to do runtime linking.
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname,aix_use_runtimelinking" is:
+	# "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix,yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both,no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
 	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
 	  for ld_flag in $LDFLAGS; do
-	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
 	    aix_use_runtimelinking=yes
 	    break
 	  fi
 	  done
+	  if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
 	  ;;
 	esac
 
@@ -5027,13 +5441,21 @@ _LT_EOF
       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
       _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+      _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+      case $with_aix_soname,$aix_use_runtimelinking in
+      aix,*) ;; # traditional, no import file
+      svr4,* | *,yes) # use import file
+	# The Import File defines what to hardcode.
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+	;;
+      esac
 
-      if test "$GCC" = yes; then
+      if test yes = "$GCC"; then
 	case $host_os in aix4.[[012]]|aix4.[[012]].*)
 	# We only want to do this on AIX 4.2 and lower, the check
 	# below for broken collect2 doesn't work under 4.3+
-	  collect2name=`${CC} -print-prog-name=collect2`
+	  collect2name=`$CC -print-prog-name=collect2`
 	  if test -f "$collect2name" &&
 	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
 	  then
@@ -5052,62 +5474,80 @@ _LT_EOF
 	  ;;
 	esac
 	shared_flag='-shared'
-	if test "$aix_use_runtimelinking" = yes; then
-	  shared_flag="$shared_flag "'${wl}-G'
+	if test yes = "$aix_use_runtimelinking"; then
+	  shared_flag="$shared_flag "'$wl-G'
 	fi
-	_LT_TAGVAR(link_all_deplibs, $1)=no
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
       else
 	# not using gcc
-	if test "$host_cpu" = ia64; then
+	if test ia64 = "$host_cpu"; then
 	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
 	# chokes on -Wl,-G. The following line is correct:
 	  shared_flag='-G'
 	else
-	  if test "$aix_use_runtimelinking" = yes; then
-	    shared_flag='${wl}-G'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag='$wl-G'
 	  else
-	    shared_flag='${wl}-bM:SRE'
+	    shared_flag='$wl-bM:SRE'
 	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
 	fi
       fi
 
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
       # It seems that -bexpall does not export symbols beginning with
       # underscore (_), so it is better to generate a list of symbols to export.
       _LT_TAGVAR(always_export_symbols, $1)=yes
-      if test "$aix_use_runtimelinking" = yes; then
+      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
 	# Warning - without using the other runtime loading flags (-brtl),
 	# -berok will link without error, but may produce a broken library.
 	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
         # Determine the default libpath from the value encoded in an
         # empty executable.
         _LT_SYS_MODULE_PATH_AIX([$1])
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
       else
-	if test "$host_cpu" = ia64; then
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	if test ia64 = "$host_cpu"; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
 	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
 	else
 	 # Determine the default libpath from the value encoded in an
 	 # empty executable.
 	 _LT_SYS_MODULE_PATH_AIX([$1])
-	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
 	  # Warning - without using the other run time loading flags,
 	  # -berok will link without error, but may produce a broken library.
-	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
-	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-	  if test "$with_gnu_ld" = yes; then
+	  _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+	  if test yes = "$with_gnu_ld"; then
 	    # We only use this code for GNU lds that support --whole-archive.
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
 	  else
 	    # Exported symbols can be pulled into shared objects from archives
 	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
 	  fi
 	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	  # This is similar to how AIX traditionally builds its shared libraries.
-	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
 	fi
       fi
       ;;
@@ -5116,7 +5556,7 @@ _LT_EOF
       case $host_cpu in
       powerpc)
             # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
             _LT_TAGVAR(archive_expsym_cmds, $1)=''
         ;;
       m68k)
@@ -5146,16 +5586,17 @@ _LT_EOF
 	# Tell ltmain to make .lib files, not .a files.
 	libext=lib
 	# Tell ltmain to make .dll files, not .so files.
-	shrext_cmds=".dll"
+	shrext_cmds=.dll
 	# FIXME: Setting linknames here is a bad hack.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-	  else
-	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-	  fi~
-	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-	  linknames='
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+            cp "$export_symbols" "$output_objdir/$soname.def";
+            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+          else
+            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+          fi~
+          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          linknames='
 	# The linker will not automatically build a static lib if we build a DLL.
 	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
 	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -5164,18 +5605,18 @@ _LT_EOF
 	# Don't use ranlib
 	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
 	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-	  lt_tool_outputfile="@TOOL_OUTPUT@"~
-	  case $lt_outputfile in
-	    *.exe|*.EXE) ;;
-	    *)
-	      lt_outputfile="$lt_outputfile.exe"
-	      lt_tool_outputfile="$lt_tool_outputfile.exe"
-	      ;;
-	  esac~
-	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-	    $RM "$lt_outputfile.manifest";
-	  fi'
+          lt_tool_outputfile="@TOOL_OUTPUT@"~
+          case $lt_outputfile in
+            *.exe|*.EXE) ;;
+            *)
+              lt_outputfile=$lt_outputfile.exe
+              lt_tool_outputfile=$lt_tool_outputfile.exe
+              ;;
+          esac~
+          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+            $RM "$lt_outputfile.manifest";
+          fi'
 	;;
       *)
 	# Assume MSVC wrapper
@@ -5184,7 +5625,7 @@ _LT_EOF
 	# Tell ltmain to make .lib files, not .a files.
 	libext=lib
 	# Tell ltmain to make .dll files, not .so files.
-	shrext_cmds=".dll"
+	shrext_cmds=.dll
 	# FIXME: Setting linknames here is a bad hack.
 	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
 	# The linker will automatically build a .lib file if we build a DLL.
@@ -5234,33 +5675,33 @@ _LT_EOF
       ;;
 
     hpux9*)
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
       else
-	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
       fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
       _LT_TAGVAR(hardcode_direct, $1)=yes
 
       # hardcode_minus_L: Not really in the search PATH,
       # but as the default location of the library.
       _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
       ;;
 
     hpux10*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
       else
 	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
       fi
-      if test "$with_gnu_ld" = no; then
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      if test no = "$with_gnu_ld"; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
 	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
 	_LT_TAGVAR(hardcode_direct, $1)=yes
 	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
 	# hardcode_minus_L: Not really in the search PATH,
 	# but as the default location of the library.
 	_LT_TAGVAR(hardcode_minus_L, $1)=yes
@@ -5268,25 +5709,25 @@ _LT_EOF
       ;;
 
     hpux11*)
-      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+      if test yes,no = "$GCC,$with_gnu_ld"; then
 	case $host_cpu in
 	hppa*64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	ia64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	esac
       else
 	case $host_cpu in
 	hppa*64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	ia64*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	*)
 	m4_if($1, [], [
@@ -5294,14 +5735,14 @@ _LT_EOF
 	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
 	  _LT_LINKER_OPTION([if $CC understands -b],
 	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
-	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
 	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
-	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
 	  ;;
 	esac
       fi
-      if test "$with_gnu_ld" = no; then
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      if test no = "$with_gnu_ld"; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
 	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
 
 	case $host_cpu in
@@ -5312,7 +5753,7 @@ _LT_EOF
 	*)
 	  _LT_TAGVAR(hardcode_direct, $1)=yes
 	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
 
 	  # hardcode_minus_L: Not really in the search PATH,
 	  # but as the default location of the library.
@@ -5323,16 +5764,16 @@ _LT_EOF
       ;;
 
     irix5* | irix6* | nonstopux*)
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 	# Try to use the -exported_symbol ld option, if it does not
 	# work, assume that -exports_file does not work either and
 	# implicitly export all symbols.
 	# This should be the same for all languages, so no per-tag cache variable.
 	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
 	  [lt_cv_irix_exported_symbol],
-	  [save_LDFLAGS="$LDFLAGS"
-	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	  [save_LDFLAGS=$LDFLAGS
+	   LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
 	   AC_LINK_IFELSE(
 	     [AC_LANG_SOURCE(
 	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
@@ -5345,21 +5786,32 @@ _LT_EOF
       end]])])],
 	      [lt_cv_irix_exported_symbol=yes],
 	      [lt_cv_irix_exported_symbol=no])
-           LDFLAGS="$save_LDFLAGS"])
-	if test "$lt_cv_irix_exported_symbol" = yes; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+           LDFLAGS=$save_LDFLAGS])
+	if test yes = "$lt_cv_irix_exported_symbol"; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
 	fi
+	_LT_TAGVAR(link_all_deplibs, $1)=no
       else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
       fi
       _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
       _LT_TAGVAR(inherit_rpath, $1)=yes
       _LT_TAGVAR(link_all_deplibs, $1)=yes
       ;;
 
+    linux*)
+      case $cc_basename in
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      esac
+      ;;
+
     netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
@@ -5374,7 +5826,7 @@ _LT_EOF
     newsos6)
       _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
       _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
       ;;
@@ -5382,27 +5834,19 @@ _LT_EOF
     *nto* | *qnx*)
       ;;
 
-    openbsd*)
+    openbsd* | bitrig*)
       if test -f /usr/libexec/ld.so; then
 	_LT_TAGVAR(hardcode_direct, $1)=yes
 	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
 	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
 	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
 	else
-	  case $host_os in
-	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
-	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-	     ;;
-	   *)
-	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	     ;;
-	  esac
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
 	fi
       else
 	_LT_TAGVAR(ld_shlibs, $1)=no
@@ -5413,33 +5857,53 @@ _LT_EOF
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
       _LT_TAGVAR(hardcode_minus_L, $1)=yes
       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
-      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      shrext_cmds=.dll
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
       ;;
 
     osf3*)
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
       else
 	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
       fi
       _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
       ;;
 
     osf4* | osf5*)	# as osf3* with the addition of -msym flag
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
       else
 	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
 
 	# Both c and cxx compiler support -rpath directly
 	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -5450,24 +5914,24 @@ _LT_EOF
 
     solaris*)
       _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
-      if test "$GCC" = yes; then
-	wlarc='${wl}'
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes = "$GCC"; then
+	wlarc='$wl'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
 	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
       else
 	case `$CC -V 2>&1` in
 	*"Compilers 5.0"*)
 	  wlarc=''
-	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
 	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
 	  ;;
 	*)
-	  wlarc='${wl}'
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  wlarc='$wl'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
 	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
 	  ;;
 	esac
       fi
@@ -5477,11 +5941,11 @@ _LT_EOF
       solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
       *)
 	# The compiler driver will combine and reorder linker options,
-	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but understands '-z linker_flag'.  GCC discards it without '$wl',
 	# but is careful enough not to reorder.
 	# Supported since Solaris 2.6 (maybe 2.5.1?)
-	if test "$GCC" = yes; then
-	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	if test yes = "$GCC"; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
 	else
 	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
 	fi
@@ -5491,10 +5955,10 @@ _LT_EOF
       ;;
 
     sunos4*)
-      if test "x$host_vendor" = xsequent; then
+      if test sequent = "$host_vendor"; then
 	# Use $CC to link under sequent, because it throws in some extra .o
 	# files that make .init and .fini sections work.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
       else
 	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
       fi
@@ -5543,43 +6007,43 @@ _LT_EOF
       ;;
 
     sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
       runpath_var='LD_RUN_PATH'
 
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       fi
       ;;
 
     sysv5* | sco3.2v5* | sco5v6*)
-      # Note: We can NOT use -z defs as we might desire, because we do not
+      # Note: We CANNOT use -z defs as we might desire, because we do not
       # link with -lc, and that would cause any symbols used from libc to
       # always be unresolved, which means just about no library would
       # ever link correctly.  If we're not using GNU ld we use -z text
       # though, which does catch some bad symbols but isn't as heavy-handed
       # as -z defs.
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
       _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
       runpath_var='LD_RUN_PATH'
 
-      if test "$GCC" = yes; then
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       else
-	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
       fi
       ;;
 
@@ -5594,17 +6058,17 @@ _LT_EOF
       ;;
     esac
 
-    if test x$host_vendor = xsni; then
+    if test sni = "$host_vendor"; then
       case $host in
       sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
 	;;
       esac
     fi
   fi
 ])
 AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
 
 _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
 
@@ -5621,7 +6085,7 @@ x|xyes)
   # Assume -lc should be added
   _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
 
-  if test "$enable_shared" = yes && test "$GCC" = yes; then
+  if test yes,yes = "$GCC,$enable_shared"; then
     case $_LT_TAGVAR(archive_cmds, $1) in
     *'~'*)
       # FIXME: we may have to deal with multi-command sequences.
@@ -5701,12 +6165,12 @@ _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
 _LT_TAGDECL([], [hardcode_libdir_separator], [1],
     [Whether we need a single "-rpath" flag with a separated argument])
 _LT_TAGDECL([], [hardcode_direct], [0],
-    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
     DIR into the resulting binary])
 _LT_TAGDECL([], [hardcode_direct_absolute], [0],
-    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
     DIR into the resulting binary and the resulting library dependency is
-    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    "absolute", i.e impossible to change by setting $shlibpath_var if the
     library is relocated])
 _LT_TAGDECL([], [hardcode_minus_L], [0],
     [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
@@ -5747,10 +6211,10 @@ dnl    [Compiler flag to generate thread safe objects])
 # ------------------------
 # Ensure that the configuration variables for a C compiler are suitably
 # defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
+# the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_C_CONFIG],
 [m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC="$CC"
+lt_save_CC=$CC
 AC_LANG_PUSH(C)
 
 # Source file extension for C test sources.
@@ -5790,18 +6254,18 @@ if test -n "$compiler"; then
   LT_SYS_DLOPEN_SELF
   _LT_CMD_STRIPLIB
 
-  # Report which library types will actually be built
+  # Report what library types will actually be built
   AC_MSG_CHECKING([if libtool supports shared libraries])
   AC_MSG_RESULT([$can_build_shared])
 
   AC_MSG_CHECKING([whether to build shared libraries])
-  test "$can_build_shared" = "no" && enable_shared=no
+  test no = "$can_build_shared" && enable_shared=no
 
   # On AIX, shared libraries and static libraries use the same namespace, and
   # are all built from PIC.
   case $host_os in
   aix3*)
-    test "$enable_shared" = yes && enable_static=no
+    test yes = "$enable_shared" && enable_static=no
     if test -n "$RANLIB"; then
       archive_cmds="$archive_cmds~\$RANLIB \$lib"
       postinstall_cmds='$RANLIB $lib'
@@ -5809,8 +6273,12 @@ if test -n "$compiler"; then
     ;;
 
   aix[[4-9]]*)
-    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-      test "$enable_shared" = yes && enable_static=no
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+      yes,aix,yes) ;;			# shared object as lib.so file only
+      yes,svr4,*) ;;			# shared object as lib.so archive member only
+      yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+      esac
     fi
     ;;
   esac
@@ -5818,13 +6286,13 @@ if test -n "$compiler"; then
 
   AC_MSG_CHECKING([whether to build static libraries])
   # Make sure either enable_shared or enable_static is yes.
-  test "$enable_shared" = yes || enable_static=yes
+  test yes = "$enable_shared" || enable_static=yes
   AC_MSG_RESULT([$enable_static])
 
   _LT_CONFIG($1)
 fi
 AC_LANG_POP
-CC="$lt_save_CC"
+CC=$lt_save_CC
 ])# _LT_LANG_C_CONFIG
 
 
@@ -5832,14 +6300,14 @@ CC="$lt_save_CC"
 # --------------------------
 # Ensure that the configuration variables for a C++ compiler are suitably
 # defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
+# the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_CXX_CONFIG],
 [m4_require([_LT_FILEUTILS_DEFAULTS])dnl
 m4_require([_LT_DECL_EGREP])dnl
 m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
-    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
-    (test "X$CXX" != "Xg++"))) ; then
+if test -n "$CXX" && ( test no != "$CXX" &&
+    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+    (test g++ != "$CXX"))); then
   AC_PROG_CXXCPP
 else
   _lt_caught_CXX_error=yes
@@ -5881,7 +6349,7 @@ _LT_TAGVAR(objext, $1)=$objext
 # the CXX compiler isn't working.  Some variables (like enable_shared)
 # are currently assumed to apply to all compilers on this platform,
 # and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
+if test yes != "$_lt_caught_CXX_error"; then
   # Code to be used in simple compile tests
   lt_simple_compile_test_code="int some_variable = 0;"
 
@@ -5923,35 +6391,35 @@ if test "$_lt_caught_CXX_error" != yes; then
   if test -n "$compiler"; then
     # We don't want -fno-exception when compiling C++ code, so set the
     # no_builtin_flag separately
-    if test "$GXX" = yes; then
+    if test yes = "$GXX"; then
       _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
     else
       _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
     fi
 
-    if test "$GXX" = yes; then
+    if test yes = "$GXX"; then
       # Set up default GNU C++ configuration
 
       LT_PATH_LD
 
       # Check if GNU C++ uses GNU ld as the underlying linker, since the
       # archiving commands below assume that GNU ld is being used.
-      if test "$with_gnu_ld" = yes; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      if test yes = "$with_gnu_ld"; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
 
         # If archive_cmds runs LD, not CC, wlarc should be empty
         # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
         #     investigate it a little bit more. (MM)
-        wlarc='${wl}'
+        wlarc='$wl'
 
         # ancient GNU ld didn't support --whole-archive et. al.
         if eval "`$CC -print-prog-name=ld` --help 2>&1" |
 	  $GREP 'no-whole-archive' > /dev/null; then
-          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
         else
           _LT_TAGVAR(whole_archive_flag_spec, $1)=
         fi
@@ -5987,18 +6455,30 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_TAGVAR(ld_shlibs, $1)=no
         ;;
       aix[[4-9]]*)
-        if test "$host_cpu" = ia64; then
+        if test ia64 = "$host_cpu"; then
           # On IA64, the linker does run time linking by default, so we don't
           # have to do anything special.
           aix_use_runtimelinking=no
           exp_sym_flag='-Bexport'
-          no_entry_flag=""
+          no_entry_flag=
         else
           aix_use_runtimelinking=no
 
           # Test if we are trying to use run time linking or normal
           # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-          # need to do runtime linking.
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname,aix_use_runtimelinking" is:
+          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix,yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
           case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
 	    for ld_flag in $LDFLAGS; do
 	      case $ld_flag in
@@ -6008,6 +6488,13 @@ if test "$_lt_caught_CXX_error" != yes; then
 	        ;;
 	      esac
 	    done
+	    if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
 	    ;;
           esac
 
@@ -6026,13 +6513,21 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
         _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
         _LT_TAGVAR(link_all_deplibs, $1)=yes
-        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+        _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+        case $with_aix_soname,$aix_use_runtimelinking in
+        aix,*) ;;	# no import file
+        svr4,* | *,yes) # use import file
+          # The Import File defines what to hardcode.
+          _LT_TAGVAR(hardcode_direct, $1)=no
+          _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+          ;;
+        esac
 
-        if test "$GXX" = yes; then
+        if test yes = "$GXX"; then
           case $host_os in aix4.[[012]]|aix4.[[012]].*)
           # We only want to do this on AIX 4.2 and lower, the check
           # below for broken collect2 doesn't work under 4.3+
-	  collect2name=`${CC} -print-prog-name=collect2`
+	  collect2name=`$CC -print-prog-name=collect2`
 	  if test -f "$collect2name" &&
 	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
 	  then
@@ -6050,64 +6545,84 @@ if test "$_lt_caught_CXX_error" != yes; then
 	  fi
           esac
           shared_flag='-shared'
-	  if test "$aix_use_runtimelinking" = yes; then
-	    shared_flag="$shared_flag "'${wl}-G'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag=$shared_flag' $wl-G'
 	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
         else
           # not using gcc
-          if test "$host_cpu" = ia64; then
+          if test ia64 = "$host_cpu"; then
 	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
 	  # chokes on -Wl,-G. The following line is correct:
 	  shared_flag='-G'
           else
-	    if test "$aix_use_runtimelinking" = yes; then
-	      shared_flag='${wl}-G'
+	    if test yes = "$aix_use_runtimelinking"; then
+	      shared_flag='$wl-G'
 	    else
-	      shared_flag='${wl}-bM:SRE'
+	      shared_flag='$wl-bM:SRE'
 	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
           fi
         fi
 
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
         # It seems that -bexpall does not export symbols beginning with
         # underscore (_), so it is better to generate a list of symbols to
 	# export.
         _LT_TAGVAR(always_export_symbols, $1)=yes
-        if test "$aix_use_runtimelinking" = yes; then
+	if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
           # Warning - without using the other runtime loading flags (-brtl),
           # -berok will link without error, but may produce a broken library.
-          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # The "-G" linker flag allows undefined symbols.
+          _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
           # Determine the default libpath from the value encoded in an empty
           # executable.
           _LT_SYS_MODULE_PATH_AIX([$1])
-          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
 
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
         else
-          if test "$host_cpu" = ia64; then
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+          if test ia64 = "$host_cpu"; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
 	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
           else
 	    # Determine the default libpath from the value encoded in an
 	    # empty executable.
 	    _LT_SYS_MODULE_PATH_AIX([$1])
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
 	    # Warning - without using the other run time loading flags,
 	    # -berok will link without error, but may produce a broken library.
-	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
-	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
-	    if test "$with_gnu_ld" = yes; then
+	    _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+	    if test yes = "$with_gnu_ld"; then
 	      # We only use this code for GNU lds that support --whole-archive.
-	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
 	    else
 	      # Exported symbols can be pulled into shared objects from archives
 	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
 	    fi
 	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-	    # This is similar to how AIX traditionally builds its shared
-	    # libraries.
-	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
           fi
         fi
         ;;
@@ -6117,7 +6632,7 @@ if test "$_lt_caught_CXX_error" != yes; then
 	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
 	  # support --undefined.  This deserves some investigation.  FIXME
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
 	else
 	  _LT_TAGVAR(ld_shlibs, $1)=no
 	fi
@@ -6145,57 +6660,58 @@ if test "$_lt_caught_CXX_error" != yes; then
 	  # Tell ltmain to make .lib files, not .a files.
 	  libext=lib
 	  # Tell ltmain to make .dll files, not .so files.
-	  shrext_cmds=".dll"
+	  shrext_cmds=.dll
 	  # FIXME: Setting linknames here is a bad hack.
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
-	    else
-	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
-	    fi~
-	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-	    linknames='
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+              cp "$export_symbols" "$output_objdir/$soname.def";
+              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+            else
+              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+            fi~
+            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+            linknames='
 	  # The linker will not automatically build a static lib if we build a DLL.
 	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
 	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
 	  # Don't use ranlib
 	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
 	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-	    lt_tool_outputfile="@TOOL_OUTPUT@"~
-	    case $lt_outputfile in
-	      *.exe|*.EXE) ;;
-	      *)
-		lt_outputfile="$lt_outputfile.exe"
-		lt_tool_outputfile="$lt_tool_outputfile.exe"
-		;;
-	    esac~
-	    func_to_tool_file "$lt_outputfile"~
-	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
-	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-	      $RM "$lt_outputfile.manifest";
-	    fi'
+            lt_tool_outputfile="@TOOL_OUTPUT@"~
+            case $lt_outputfile in
+              *.exe|*.EXE) ;;
+              *)
+                lt_outputfile=$lt_outputfile.exe
+                lt_tool_outputfile=$lt_tool_outputfile.exe
+                ;;
+            esac~
+            func_to_tool_file "$lt_outputfile"~
+            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+              $RM "$lt_outputfile.manifest";
+            fi'
 	  ;;
 	*)
 	  # g++
 	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
 	  # as there is no search path for DLLs.
 	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
 	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	  _LT_TAGVAR(always_export_symbols, $1)=no
 	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
 
 	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-	    # If the export-symbols file already is a .def file (1st line
-	    # is EXPORTS), use it as is; otherwise, prepend...
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
-	      cp $export_symbols $output_objdir/$soname.def;
-	    else
-	      echo EXPORTS > $output_objdir/$soname.def;
-	      cat $export_symbols >> $output_objdir/$soname.def;
-	    fi~
-	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file, use it as
+	    # is; otherwise, prepend EXPORTS...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+              cp $export_symbols $output_objdir/$soname.def;
+            else
+              echo EXPORTS > $output_objdir/$soname.def;
+              cat $export_symbols >> $output_objdir/$soname.def;
+            fi~
+            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
 	  else
 	    _LT_TAGVAR(ld_shlibs, $1)=no
 	  fi
@@ -6206,6 +6722,34 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_DARWIN_LINKER_FEATURES($1)
 	;;
 
+      os2*)
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	shrext_cmds=.dll
+	_LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  prefix_cmds="$SED"~
+	  if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	    prefix_cmds="$prefix_cmds -e 1d";
+	  fi~
+	  prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	  cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+
       dgux*)
         case $cc_basename in
           ec++*)
@@ -6241,14 +6785,14 @@ if test "$_lt_caught_CXX_error" != yes; then
         ;;
 
       haiku*)
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
         _LT_TAGVAR(link_all_deplibs, $1)=yes
         ;;
 
       hpux9*)
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
         _LT_TAGVAR(hardcode_direct, $1)=yes
         _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
 				             # but as the default
@@ -6260,7 +6804,7 @@ if test "$_lt_caught_CXX_error" != yes; then
             _LT_TAGVAR(ld_shlibs, $1)=no
             ;;
           aCC*)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
             # Commands to make compiler produce verbose output that lists
             # what "hidden" libraries, object files and flags are used when
             # linking a shared library.
@@ -6269,11 +6813,11 @@ if test "$_lt_caught_CXX_error" != yes; then
             # explicitly linking system object files so we need to strip them
             # from the output so that they don't get included in the library
             # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
             ;;
           *)
-            if test "$GXX" = yes; then
-              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            if test yes = "$GXX"; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
             else
               # FIXME: insert proper C++ library support
               _LT_TAGVAR(ld_shlibs, $1)=no
@@ -6283,15 +6827,15 @@ if test "$_lt_caught_CXX_error" != yes; then
         ;;
 
       hpux10*|hpux11*)
-        if test $with_gnu_ld = no; then
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        if test no = "$with_gnu_ld"; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
 	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
 
           case $host_cpu in
             hppa*64*|ia64*)
               ;;
             *)
-	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
               ;;
           esac
         fi
@@ -6317,13 +6861,13 @@ if test "$_lt_caught_CXX_error" != yes; then
           aCC*)
 	    case $host_cpu in
 	      hppa*64*)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	        ;;
 	      ia64*)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	        ;;
 	      *)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	        ;;
 	    esac
 	    # Commands to make compiler produce verbose output that lists
@@ -6334,20 +6878,20 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 	    ;;
           *)
-	    if test "$GXX" = yes; then
-	      if test $with_gnu_ld = no; then
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
 	        case $host_cpu in
 	          hppa*64*)
-	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	            ;;
 	          ia64*)
-	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	            ;;
 	          *)
-	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	            ;;
 	        esac
 	      fi
@@ -6362,22 +6906,22 @@ if test "$_lt_caught_CXX_error" != yes; then
       interix[[3-9]]*)
 	_LT_TAGVAR(hardcode_direct, $1)=no
 	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
 	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
 	# Instead, shared libraries are loaded at an image base (0x10000000 by
 	# default) and relocated if they conflict, which is a slow very memory
 	# consuming and fragmenting process.  To avoid this, we pick a random,
 	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
 	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
 	;;
       irix5* | irix6*)
         case $cc_basename in
           CC*)
 	    # SGI C++
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 
 	    # Archives containing C++ object files must be created using
 	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
@@ -6386,17 +6930,17 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
 	    ;;
           *)
-	    if test "$GXX" = yes; then
-	      if test "$with_gnu_ld" = no; then
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 	      else
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
 	      fi
 	    fi
 	    _LT_TAGVAR(link_all_deplibs, $1)=yes
 	    ;;
         esac
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
         _LT_TAGVAR(inherit_rpath, $1)=yes
         ;;
@@ -6409,8 +6953,8 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # KCC will only create a shared library if the output file
 	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
 	    # to its proper name (with version) after linking.
-	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
 	    # Commands to make compiler produce verbose output that lists
 	    # what "hidden" libraries, object files and flags are used when
 	    # linking a shared library.
@@ -6419,10 +6963,10 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
 
 	    # Archives containing C++ object files must be created using
 	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
@@ -6436,59 +6980,59 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # earlier do not add the objects themselves.
 	    case `$CC -V 2>&1` in
 	      *"Version 7."*)
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 		;;
 	      *)  # Version 8.0 or newer
 	        tmp_idyn=
 	        case $host_cpu in
 		  ia64*) tmp_idyn=' -i_dynamic';;
 		esac
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 		;;
 	    esac
 	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
 	    ;;
           pgCC* | pgcpp*)
             # Portland Group C++ compiler
 	    case `$CC -V` in
 	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
 	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
 	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
-		$RANLIB $oldlib'
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+                $RANLIB $oldlib'
 	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
 	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
-		rm -rf $tpldir~
-		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 	      ;;
 	    *) # Version 6 and above use weak symbols
-	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
-	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
 	      ;;
 	    esac
 
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
             ;;
 	  cxx*)
 	    # Compaq C++
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
 
 	    runpath_var=LD_RUN_PATH
 	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -6502,18 +7046,18 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
 	    ;;
 	  xl* | mpixl* | bgxl*)
 	    # IBM XL 8.0 on PPC, with GNU ld
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
-	    if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    if test yes = "$supports_anon_versioning"; then
 	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-		echo "local: *; };" >> $output_objdir/$libname.ver~
-		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+                echo "local: *; };" >> $output_objdir/$libname.ver~
+                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
 	    fi
 	    ;;
 	  *)
@@ -6521,10 +7065,10 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    *Sun\ C*)
 	      # Sun C++ 5.9
 	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
 	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
 	      _LT_TAGVAR(compiler_needs_object, $1)=yes
 
 	      # Not sure whether something based on
@@ -6582,22 +7126,17 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_TAGVAR(ld_shlibs, $1)=yes
 	;;
 
-      openbsd2*)
-        # C++ shared libraries are fairly broken
-	_LT_TAGVAR(ld_shlibs, $1)=no
-	;;
-
-      openbsd*)
+      openbsd* | bitrig*)
 	if test -f /usr/libexec/ld.so; then
 	  _LT_TAGVAR(hardcode_direct, $1)=yes
 	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
 	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
 	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
-	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
-	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
-	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
 	  fi
 	  output_verbose_link_cmd=func_echo_all
 	else
@@ -6613,9 +7152,9 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # KCC will only create a shared library if the output file
 	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
 	    # to its proper name (with version) after linking.
-	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
 
-	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
 	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
 
 	    # Archives containing C++ object files must be created using
@@ -6633,17 +7172,17 @@ if test "$_lt_caught_CXX_error" != yes; then
           cxx*)
 	    case $host in
 	      osf3*)
-	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
-	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
 		;;
 	      *)
 	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
-	          echo "-hidden">> $lib.exp~
-	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
-	          $RM $lib.exp'
+                  echo "-hidden">> $lib.exp~
+                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+                  $RM $lib.exp'
 	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
 		;;
 	    esac
@@ -6658,21 +7197,21 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 	    ;;
 	  *)
-	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
 	      case $host in
 	        osf3*)
-	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 		  ;;
 	        *)
-	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
 		  ;;
 	      esac
 
-	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
 	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
 
 	      # Commands to make compiler produce verbose output that lists
@@ -6718,9 +7257,9 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    # Sun C++ 4.2, 5.x and Centerline C++
             _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
 	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
 	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
 
 	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
 	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
@@ -6728,7 +7267,7 @@ if test "$_lt_caught_CXX_error" != yes; then
 	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
 	      *)
 		# The compiler driver will combine and reorder linker options,
-		# but understands `-z linker_flag'.
+		# but understands '-z linker_flag'.
 	        # Supported since Solaris 2.6 (maybe 2.5.1?)
 		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
 	        ;;
@@ -6745,30 +7284,30 @@ if test "$_lt_caught_CXX_error" != yes; then
 	    ;;
           gcx*)
 	    # Green Hills C++ Compiler
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
 
 	    # The C++ compiler must be used to create the archive.
 	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
 	    ;;
           *)
 	    # GNU C++ compiler with Solaris linker
-	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
-	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
 	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
 	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
 
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
 	        # linking a shared library.
 	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
 	      else
-	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
 	        # platform.
-	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
 	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
 
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
@@ -6776,11 +7315,11 @@ if test "$_lt_caught_CXX_error" != yes; then
 	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
 	      fi
 
-	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
 	      case $host_os in
 		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
 		*)
-		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
 		  ;;
 	      esac
 	    fi
@@ -6789,52 +7328,52 @@ if test "$_lt_caught_CXX_error" != yes; then
         ;;
 
     sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
       runpath_var='LD_RUN_PATH'
 
       case $cc_basename in
         CC*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
 	*)
-	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	  ;;
       esac
       ;;
 
       sysv5* | sco3.2v5* | sco5v6*)
-	# Note: We can NOT use -z defs as we might desire, because we do not
+	# Note: We CANNOT use -z defs as we might desire, because we do not
 	# link with -lc, and that would cause any symbols used from libc to
 	# always be unresolved, which means just about no library would
 	# ever link correctly.  If we're not using GNU ld we use -z text
 	# though, which does catch some bad symbols but isn't as heavy-handed
 	# as -z defs.
-	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
-	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
 	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
 	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
 	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
 	_LT_TAGVAR(link_all_deplibs, $1)=yes
-	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
 	runpath_var='LD_RUN_PATH'
 
 	case $cc_basename in
           CC*)
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
-	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
+              '"$_LT_TAGVAR(old_archive_cmds, $1)"
 	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
-	      '"$_LT_TAGVAR(reload_cmds, $1)"
+              '"$_LT_TAGVAR(reload_cmds, $1)"
 	    ;;
 	  *)
-	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
 	    ;;
 	esac
       ;;
@@ -6865,10 +7404,10 @@ if test "$_lt_caught_CXX_error" != yes; then
     esac
 
     AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+    test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
 
-    _LT_TAGVAR(GCC, $1)="$GXX"
-    _LT_TAGVAR(LD, $1)="$LD"
+    _LT_TAGVAR(GCC, $1)=$GXX
+    _LT_TAGVAR(LD, $1)=$LD
 
     ## CAVEAT EMPTOR:
     ## There is no encapsulation within the following macros, do not change
@@ -6895,7 +7434,7 @@ if test "$_lt_caught_CXX_error" != yes; then
   lt_cv_path_LD=$lt_save_path_LD
   lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
   lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
+fi # test yes != "$_lt_caught_CXX_error"
 
 AC_LANG_POP
 ])# _LT_LANG_CXX_CONFIG
@@ -6917,13 +7456,14 @@ AC_REQUIRE([_LT_DECL_SED])
 AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
 func_stripname_cnf ()
 {
-  case ${2} in
-  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
-  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  case @S|@2 in
+  .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+  *)  func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
   esac
 } # func_stripname_cnf
 ])# _LT_FUNC_STRIPNAME_CNF
 
+
 # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
 # ---------------------------------
 # Figure out "hidden" library dependencies from verbose
@@ -7007,13 +7547,13 @@ if AC_TRY_EVAL(ac_compile); then
   pre_test_object_deps_done=no
 
   for p in `eval "$output_verbose_link_cmd"`; do
-    case ${prev}${p} in
+    case $prev$p in
 
     -L* | -R* | -l*)
        # Some compilers place space between "-{L,R}" and the path.
        # Remove the space.
-       if test $p = "-L" ||
-          test $p = "-R"; then
+       if test x-L = "$p" ||
+          test x-R = "$p"; then
 	 prev=$p
 	 continue
        fi
@@ -7029,16 +7569,16 @@ if AC_TRY_EVAL(ac_compile); then
        case $p in
        =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
        esac
-       if test "$pre_test_object_deps_done" = no; then
-	 case ${prev} in
+       if test no = "$pre_test_object_deps_done"; then
+	 case $prev in
 	 -L | -R)
 	   # Internal compiler library paths should come after those
 	   # provided the user.  The postdeps already come after the
 	   # user supplied libs so there is no need to process them.
 	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
-	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	     _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
 	   else
-	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
 	   fi
 	   ;;
 	 # The "-l" case would never come before the object being
@@ -7046,9 +7586,9 @@ if AC_TRY_EVAL(ac_compile); then
 	 esac
        else
 	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
-	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	   _LT_TAGVAR(postdeps, $1)=$prev$p
 	 else
-	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
 	 fi
        fi
        prev=
@@ -7063,15 +7603,15 @@ if AC_TRY_EVAL(ac_compile); then
 	 continue
        fi
 
-       if test "$pre_test_object_deps_done" = no; then
+       if test no = "$pre_test_object_deps_done"; then
 	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
-	   _LT_TAGVAR(predep_objects, $1)="$p"
+	   _LT_TAGVAR(predep_objects, $1)=$p
 	 else
 	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
 	 fi
        else
 	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
-	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	   _LT_TAGVAR(postdep_objects, $1)=$p
 	 else
 	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
 	 fi
@@ -7102,51 +7642,6 @@ interix[[3-9]]*)
   _LT_TAGVAR(postdep_objects,$1)=
   _LT_TAGVAR(postdeps,$1)=
   ;;
-
-linux*)
-  case `$CC -V 2>&1 | sed 5q` in
-  *Sun\ C*)
-    # Sun C++ 5.9
-
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    if test "$solaris_use_stlport4" != yes; then
-      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
-
-solaris*)
-  case $cc_basename in
-  CC* | sunCC*)
-    # The more standards-conforming stlport4 library is
-    # incompatible with the Cstd library. Avoid specifying
-    # it if it's in CXXFLAGS. Ignore libCrun as
-    # -library=stlport4 depends on it.
-    case " $CXX $CXXFLAGS " in
-    *" -library=stlport4 "*)
-      solaris_use_stlport4=yes
-      ;;
-    esac
-
-    # Adding this requires a known-good setup of shared libraries for
-    # Sun compiler versions before 5.6, else PIC objects from an old
-    # archive will be linked into the output, leading to subtle bugs.
-    if test "$solaris_use_stlport4" != yes; then
-      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
-    fi
-    ;;
-  esac
-  ;;
 esac
 ])
 
@@ -7155,7 +7650,7 @@ case " $_LT_TAGVAR(postdeps, $1) " in
 esac
  _LT_TAGVAR(compiler_lib_search_dirs, $1)=
 if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
 fi
 _LT_TAGDECL([], [compiler_lib_search_dirs], [1],
     [The directories searched by this compiler when creating a shared library])
@@ -7175,10 +7670,10 @@ _LT_TAGDECL([], [compiler_lib_search_path], [1],
 # --------------------------
 # Ensure that the configuration variables for a Fortran 77 compiler are
 # suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_F77_CONFIG],
 [AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test "X$F77" = "Xno"; then
+if test -z "$F77" || test no = "$F77"; then
   _lt_disable_F77=yes
 fi
 
@@ -7215,7 +7710,7 @@ _LT_TAGVAR(objext, $1)=$objext
 # the F77 compiler isn't working.  Some variables (like enable_shared)
 # are currently assumed to apply to all compilers on this platform,
 # and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_F77" != yes; then
+if test yes != "$_lt_disable_F77"; then
   # Code to be used in simple compile tests
   lt_simple_compile_test_code="\
       subroutine t
@@ -7237,7 +7732,7 @@ if test "$_lt_disable_F77" != yes; then
   _LT_LINKER_BOILERPLATE
 
   # Allow CC to be a program name with arguments.
-  lt_save_CC="$CC"
+  lt_save_CC=$CC
   lt_save_GCC=$GCC
   lt_save_CFLAGS=$CFLAGS
   CC=${F77-"f77"}
@@ -7251,21 +7746,25 @@ if test "$_lt_disable_F77" != yes; then
     AC_MSG_RESULT([$can_build_shared])
 
     AC_MSG_CHECKING([whether to build shared libraries])
-    test "$can_build_shared" = "no" && enable_shared=no
+    test no = "$can_build_shared" && enable_shared=no
 
     # On AIX, shared libraries and static libraries use the same namespace, and
     # are all built from PIC.
     case $host_os in
       aix3*)
-        test "$enable_shared" = yes && enable_static=no
+        test yes = "$enable_shared" && enable_static=no
         if test -n "$RANLIB"; then
           archive_cmds="$archive_cmds~\$RANLIB \$lib"
           postinstall_cmds='$RANLIB $lib'
         fi
         ;;
       aix[[4-9]]*)
-	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-	  test "$enable_shared" = yes && enable_static=no
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+	  yes,aix,yes) ;;		# shared object as lib.so file only
+	  yes,svr4,*) ;;		# shared object as lib.so archive member only
+	  yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+	  esac
 	fi
         ;;
     esac
@@ -7273,11 +7772,11 @@ if test "$_lt_disable_F77" != yes; then
 
     AC_MSG_CHECKING([whether to build static libraries])
     # Make sure either enable_shared or enable_static is yes.
-    test "$enable_shared" = yes || enable_static=yes
+    test yes = "$enable_shared" || enable_static=yes
     AC_MSG_RESULT([$enable_static])
 
-    _LT_TAGVAR(GCC, $1)="$G77"
-    _LT_TAGVAR(LD, $1)="$LD"
+    _LT_TAGVAR(GCC, $1)=$G77
+    _LT_TAGVAR(LD, $1)=$LD
 
     ## CAVEAT EMPTOR:
     ## There is no encapsulation within the following macros, do not change
@@ -7294,9 +7793,9 @@ if test "$_lt_disable_F77" != yes; then
   fi # test -n "$compiler"
 
   GCC=$lt_save_GCC
-  CC="$lt_save_CC"
-  CFLAGS="$lt_save_CFLAGS"
-fi # test "$_lt_disable_F77" != yes
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
 
 AC_LANG_POP
 ])# _LT_LANG_F77_CONFIG
@@ -7306,11 +7805,11 @@ AC_LANG_POP
 # -------------------------
 # Ensure that the configuration variables for a Fortran compiler are
 # suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_FC_CONFIG],
 [AC_LANG_PUSH(Fortran)
 
-if test -z "$FC" || test "X$FC" = "Xno"; then
+if test -z "$FC" || test no = "$FC"; then
   _lt_disable_FC=yes
 fi
 
@@ -7347,7 +7846,7 @@ _LT_TAGVAR(objext, $1)=$objext
 # the FC compiler isn't working.  Some variables (like enable_shared)
 # are currently assumed to apply to all compilers on this platform,
 # and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_FC" != yes; then
+if test yes != "$_lt_disable_FC"; then
   # Code to be used in simple compile tests
   lt_simple_compile_test_code="\
       subroutine t
@@ -7369,7 +7868,7 @@ if test "$_lt_disable_FC" != yes; then
   _LT_LINKER_BOILERPLATE
 
   # Allow CC to be a program name with arguments.
-  lt_save_CC="$CC"
+  lt_save_CC=$CC
   lt_save_GCC=$GCC
   lt_save_CFLAGS=$CFLAGS
   CC=${FC-"f95"}
@@ -7385,21 +7884,25 @@ if test "$_lt_disable_FC" != yes; then
     AC_MSG_RESULT([$can_build_shared])
 
     AC_MSG_CHECKING([whether to build shared libraries])
-    test "$can_build_shared" = "no" && enable_shared=no
+    test no = "$can_build_shared" && enable_shared=no
 
     # On AIX, shared libraries and static libraries use the same namespace, and
     # are all built from PIC.
     case $host_os in
       aix3*)
-        test "$enable_shared" = yes && enable_static=no
+        test yes = "$enable_shared" && enable_static=no
         if test -n "$RANLIB"; then
           archive_cmds="$archive_cmds~\$RANLIB \$lib"
           postinstall_cmds='$RANLIB $lib'
         fi
         ;;
       aix[[4-9]]*)
-	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
-	  test "$enable_shared" = yes && enable_static=no
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+	  yes,aix,yes) ;;		# shared object as lib.so file only
+	  yes,svr4,*) ;;		# shared object as lib.so archive member only
+	  yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+	  esac
 	fi
         ;;
     esac
@@ -7407,11 +7910,11 @@ if test "$_lt_disable_FC" != yes; then
 
     AC_MSG_CHECKING([whether to build static libraries])
     # Make sure either enable_shared or enable_static is yes.
-    test "$enable_shared" = yes || enable_static=yes
+    test yes = "$enable_shared" || enable_static=yes
     AC_MSG_RESULT([$enable_static])
 
-    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
-    _LT_TAGVAR(LD, $1)="$LD"
+    _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+    _LT_TAGVAR(LD, $1)=$LD
 
     ## CAVEAT EMPTOR:
     ## There is no encapsulation within the following macros, do not change
@@ -7431,7 +7934,7 @@ if test "$_lt_disable_FC" != yes; then
   GCC=$lt_save_GCC
   CC=$lt_save_CC
   CFLAGS=$lt_save_CFLAGS
-fi # test "$_lt_disable_FC" != yes
+fi # test yes != "$_lt_disable_FC"
 
 AC_LANG_POP
 ])# _LT_LANG_FC_CONFIG
@@ -7441,7 +7944,7 @@ AC_LANG_POP
 # --------------------------
 # Ensure that the configuration variables for the GNU Java Compiler compiler
 # are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_GCJ_CONFIG],
 [AC_REQUIRE([LT_PROG_GCJ])dnl
 AC_LANG_SAVE
@@ -7475,7 +7978,7 @@ CC=${GCJ-"gcj"}
 CFLAGS=$GCJFLAGS
 compiler=$CC
 _LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
+_LT_TAGVAR(LD, $1)=$LD
 _LT_CC_BASENAME([$compiler])
 
 # GCJ did not exist at the time GCC didn't implicitly link libc in.
@@ -7512,7 +8015,7 @@ CFLAGS=$lt_save_CFLAGS
 # --------------------------
 # Ensure that the configuration variables for the GNU Go compiler
 # are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_GO_CONFIG],
 [AC_REQUIRE([LT_PROG_GO])dnl
 AC_LANG_SAVE
@@ -7546,7 +8049,7 @@ CC=${GOC-"gccgo"}
 CFLAGS=$GOFLAGS
 compiler=$CC
 _LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
+_LT_TAGVAR(LD, $1)=$LD
 _LT_CC_BASENAME([$compiler])
 
 # Go did not exist at the time GCC didn't implicitly link libc in.
@@ -7583,7 +8086,7 @@ CFLAGS=$lt_save_CFLAGS
 # -------------------------
 # Ensure that the configuration variables for the Windows resource compiler
 # are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
 m4_defun([_LT_LANG_RC_CONFIG],
 [AC_REQUIRE([LT_PROG_RC])dnl
 AC_LANG_SAVE
@@ -7599,7 +8102,7 @@ _LT_TAGVAR(objext, $1)=$objext
 lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
 
 # Code to be used in simple link tests
-lt_simple_link_test_code="$lt_simple_compile_test_code"
+lt_simple_link_test_code=$lt_simple_compile_test_code
 
 # ltmain only uses $CC for tagged configurations so make sure $CC is set.
 _LT_TAG_COMPILER
@@ -7609,7 +8112,7 @@ _LT_COMPILER_BOILERPLATE
 _LT_LINKER_BOILERPLATE
 
 # Allow CC to be a program name with arguments.
-lt_save_CC="$CC"
+lt_save_CC=$CC
 lt_save_CFLAGS=$CFLAGS
 lt_save_GCC=$GCC
 GCC=
@@ -7638,7 +8141,7 @@ AC_DEFUN([LT_PROG_GCJ],
 [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
   [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
     [AC_CHECK_TOOL(GCJ, gcj,)
-      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
       AC_SUBST(GCJFLAGS)])])[]dnl
 ])
 
@@ -7749,7 +8252,7 @@ lt_ac_count=0
 # Add /usr/xpg4/bin/sed as it is typically found on Solaris
 # along with /bin/sed that truncates output.
 for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
-  test ! -f $lt_ac_sed && continue
+  test ! -f "$lt_ac_sed" && continue
   cat /dev/null > conftest.in
   lt_ac_count=0
   echo $ECHO_N "0123456789$ECHO_C" >conftest.in
@@ -7766,9 +8269,9 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
     $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
     cmp -s conftest.out conftest.nl || break
     # 10000 chars as input seems more than enough
-    test $lt_ac_count -gt 10 && break
+    test 10 -lt "$lt_ac_count" && break
     lt_ac_count=`expr $lt_ac_count + 1`
-    if test $lt_ac_count -gt $lt_ac_max; then
+    if test "$lt_ac_count" -gt "$lt_ac_max"; then
       lt_ac_max=$lt_ac_count
       lt_cv_path_SED=$lt_ac_sed
     fi
@@ -7792,27 +8295,7 @@ dnl AC_DEFUN([LT_AC_PROG_SED], [])
 # Find out whether the shell is Bourne or XSI compatible,
 # or has some other useful features.
 m4_defun([_LT_CHECK_SHELL_FEATURES],
-[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
-  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
-      = c,a/b,b/c, \
-    && eval 'test $(( 1 + 1 )) -eq 2 \
-    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
-  && xsi_shell=yes
-AC_MSG_RESULT([$xsi_shell])
-_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
-
-AC_MSG_CHECKING([whether the shell understands "+="])
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
-    >/dev/null 2>&1 \
-  && lt_shell_append=yes
-AC_MSG_RESULT([$lt_shell_append])
-_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
   lt_unset=unset
 else
   lt_unset=false
@@ -7836,102 +8319,9 @@ _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
 ])# _LT_CHECK_SHELL_FEATURES
 
 
-# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
-# ------------------------------------------------------
-# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
-# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
-m4_defun([_LT_PROG_FUNCTION_REPLACE],
-[dnl {
-sed -e '/^$1 ()$/,/^} # $1 /c\
-$1 ()\
-{\
-m4_bpatsubsts([$2], [$], [\\], [^\([	 ]\)], [\\\1])
-} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
-  && mv -f "$cfgfile.tmp" "$cfgfile" \
-    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-])
-
-
-# _LT_PROG_REPLACE_SHELLFNS
-# -------------------------
-# Replace existing portable implementations of several shell functions with
-# equivalent extended shell implementations where those features are available..
-m4_defun([_LT_PROG_REPLACE_SHELLFNS],
-[if test x"$xsi_shell" = xyes; then
-  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
-    case ${1} in
-      */*) func_dirname_result="${1%/*}${2}" ;;
-      *  ) func_dirname_result="${3}" ;;
-    esac])
-
-  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
-    func_basename_result="${1##*/}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
-    case ${1} in
-      */*) func_dirname_result="${1%/*}${2}" ;;
-      *  ) func_dirname_result="${3}" ;;
-    esac
-    func_basename_result="${1##*/}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
-    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
-    # positional parameters, so assign one to ordinary parameter first.
-    func_stripname_result=${3}
-    func_stripname_result=${func_stripname_result#"${1}"}
-    func_stripname_result=${func_stripname_result%"${2}"}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
-    func_split_long_opt_name=${1%%=*}
-    func_split_long_opt_arg=${1#*=}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
-    func_split_short_opt_arg=${1#??}
-    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
-
-  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
-    case ${1} in
-      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
-      *)    func_lo2o_result=${1} ;;
-    esac])
-
-  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
-
-  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
-
-  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
-fi
-
-if test x"$lt_shell_append" = xyes; then
-  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
-
-  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
-    func_quote_for_eval "${2}"
-dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
-    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
-
-  # Save a `func_append' function call where possible by direct use of '+='
-  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-else
-  # Save a `func_append' function call even when '+=' is not available
-  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
-    && mv -f "$cfgfile.tmp" "$cfgfile" \
-      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-  test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
-  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
-fi
-])
-
 # _LT_PATH_CONVERSION_FUNCTIONS
 # -----------------------------
-# Determine which file name conversion functions should be used by
+# Determine what file name conversion functions should be used by
 # func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
 # for certain cross-compile configurations and native mingw.
 m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
index 5d9acd8..94b0829 100644
--- a/m4/ltoptions.m4
+++ b/m4/ltoptions.m4
@@ -1,14 +1,14 @@
 # Helper functions for option handling.                    -*- Autoconf -*-
 #
-#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
-#   Inc.
+#   Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+#   Foundation, Inc.
 #   Written by Gary V. Vaughan, 2004
 #
 # This file is free software; the Free Software Foundation gives
 # unlimited permission to copy and/or distribute it, with or without
 # modifications, as long as this notice is preserved.
 
-# serial 7 ltoptions.m4
+# serial 8 ltoptions.m4
 
 # This is to help aclocal find these macros, as it can't see m4_define.
 AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
@@ -29,7 +29,7 @@ m4_define([_LT_SET_OPTION],
 [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
 m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
         _LT_MANGLE_DEFUN([$1], [$2]),
-    [m4_warning([Unknown $1 option `$2'])])[]dnl
+    [m4_warning([Unknown $1 option '$2'])])[]dnl
 ])
 
 
@@ -75,13 +75,15 @@ m4_if([$1],[LT_INIT],[
   dnl
   dnl If no reference was made to various pairs of opposing options, then
   dnl we run the default mode handler for the pair.  For example, if neither
-  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
   dnl archives by default:
   _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
   _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
   _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
   _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
-  		   [_LT_ENABLE_FAST_INSTALL])
+		   [_LT_ENABLE_FAST_INSTALL])
+  _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+		   [_LT_WITH_AIX_SONAME([aix])])
   ])
 ])# _LT_SET_OPTIONS
 
@@ -112,7 +114,7 @@ AU_DEFUN([AC_LIBTOOL_DLOPEN],
 [_LT_SET_OPTION([LT_INIT], [dlopen])
 AC_DIAGNOSE([obsolete],
 [$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `dlopen' option into LT_INIT's first parameter.])
+put the 'dlopen' option into LT_INIT's first parameter.])
 ])
 
 dnl aclocal-1.4 backwards compatibility:
@@ -148,7 +150,7 @@ AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
 _LT_SET_OPTION([LT_INIT], [win32-dll])
 AC_DIAGNOSE([obsolete],
 [$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `win32-dll' option into LT_INIT's first parameter.])
+put the 'win32-dll' option into LT_INIT's first parameter.])
 ])
 
 dnl aclocal-1.4 backwards compatibility:
@@ -157,9 +159,9 @@ dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
 
 # _LT_ENABLE_SHARED([DEFAULT])
 # ----------------------------
-# implement the --enable-shared flag, and supports the `shared' and
-# `disable-shared' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
 m4_define([_LT_ENABLE_SHARED],
 [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
 AC_ARG_ENABLE([shared],
@@ -172,14 +174,14 @@ AC_ARG_ENABLE([shared],
     *)
       enable_shared=no
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for pkg in $enableval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$pkg" = "X$p"; then
 	  enable_shared=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac],
     [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
@@ -211,9 +213,9 @@ dnl AC_DEFUN([AM_DISABLE_SHARED], [])
 
 # _LT_ENABLE_STATIC([DEFAULT])
 # ----------------------------
-# implement the --enable-static flag, and support the `static' and
-# `disable-static' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
 m4_define([_LT_ENABLE_STATIC],
 [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
 AC_ARG_ENABLE([static],
@@ -226,14 +228,14 @@ AC_ARG_ENABLE([static],
     *)
      enable_static=no
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for pkg in $enableval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$pkg" = "X$p"; then
 	  enable_static=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac],
     [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
@@ -265,9 +267,9 @@ dnl AC_DEFUN([AM_DISABLE_STATIC], [])
 
 # _LT_ENABLE_FAST_INSTALL([DEFAULT])
 # ----------------------------------
-# implement the --enable-fast-install flag, and support the `fast-install'
-# and `disable-fast-install' LT_INIT options.
-# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
 m4_define([_LT_ENABLE_FAST_INSTALL],
 [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
 AC_ARG_ENABLE([fast-install],
@@ -280,14 +282,14 @@ AC_ARG_ENABLE([fast-install],
     *)
       enable_fast_install=no
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for pkg in $enableval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$pkg" = "X$p"; then
 	  enable_fast_install=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac],
     [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
@@ -304,14 +306,14 @@ AU_DEFUN([AC_ENABLE_FAST_INSTALL],
 [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
 AC_DIAGNOSE([obsolete],
 [$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `fast-install' option into LT_INIT's first parameter.])
+the 'fast-install' option into LT_INIT's first parameter.])
 ])
 
 AU_DEFUN([AC_DISABLE_FAST_INSTALL],
 [_LT_SET_OPTION([LT_INIT], [disable-fast-install])
 AC_DIAGNOSE([obsolete],
 [$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `disable-fast-install' option into LT_INIT's first parameter.])
+the 'disable-fast-install' option into LT_INIT's first parameter.])
 ])
 
 dnl aclocal-1.4 backwards compatibility:
@@ -319,11 +321,64 @@ dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
 dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
 
 
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'.  If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+  AC_MSG_CHECKING([which variant of shared library versioning to provide])
+  AC_ARG_WITH([aix-soname],
+    [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+      [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+    [case $withval in
+    aix|svr4|both)
+      ;;
+    *)
+      AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+      ;;
+    esac
+    lt_cv_with_aix_soname=$with_aix_soname],
+    [AC_CACHE_VAL([lt_cv_with_aix_soname],
+      [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+    with_aix_soname=$lt_cv_with_aix_soname])
+  AC_MSG_RESULT([$with_aix_soname])
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+*)
+  with_aix_soname=aix
+  ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+    [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
 # _LT_WITH_PIC([MODE])
 # --------------------
-# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
 # LT_INIT options.
-# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+# MODE is either 'yes' or 'no'.  If omitted, it defaults to 'both'.
 m4_define([_LT_WITH_PIC],
 [AC_ARG_WITH([pic],
     [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
@@ -334,19 +389,17 @@ m4_define([_LT_WITH_PIC],
     *)
       pic_mode=default
       # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
       for lt_pkg in $withval; do
-	IFS="$lt_save_ifs"
+	IFS=$lt_save_ifs
 	if test "X$lt_pkg" = "X$lt_p"; then
 	  pic_mode=yes
 	fi
       done
-      IFS="$lt_save_ifs"
+      IFS=$lt_save_ifs
       ;;
     esac],
-    [pic_mode=default])
-
-test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+    [pic_mode=m4_default([$1], [default])])
 
 _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
 ])# _LT_WITH_PIC
@@ -359,7 +412,7 @@ AU_DEFUN([AC_LIBTOOL_PICMODE],
 [_LT_SET_OPTION([LT_INIT], [pic-only])
 AC_DIAGNOSE([obsolete],
 [$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `pic-only' option into LT_INIT's first parameter.])
+put the 'pic-only' option into LT_INIT's first parameter.])
 ])
 
 dnl aclocal-1.4 backwards compatibility:
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
index 9000a05..48bc934 100644
--- a/m4/ltsugar.m4
+++ b/m4/ltsugar.m4
@@ -1,6 +1,7 @@
 # ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
 #
-# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
 # Written by Gary V. Vaughan, 2004
 #
 # This file is free software; the Free Software Foundation gives
@@ -33,7 +34,7 @@ m4_define([_lt_join],
 # ------------
 # Manipulate m4 lists.
 # These macros are necessary as long as will still need to support
-# Autoconf-2.59 which quotes differently.
+# Autoconf-2.59, which quotes differently.
 m4_define([lt_car], [[$1]])
 m4_define([lt_cdr],
 [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
@@ -44,7 +45,7 @@ m4_define([lt_unquote], $1)
 
 # lt_append(MACRO-NAME, STRING, [SEPARATOR])
 # ------------------------------------------
-# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
 # Note that neither SEPARATOR nor STRING are expanded; they are appended
 # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
 # No SEPARATOR is output if MACRO-NAME was previously undefined (different
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
index 07a8602..fa04b52 100644
--- a/m4/ltversion.m4
+++ b/m4/ltversion.m4
@@ -1,6 +1,6 @@
 # ltversion.m4 -- version numbers			-*- Autoconf -*-
 #
-#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
 #   Written by Scott James Remnant, 2004
 #
 # This file is free software; the Free Software Foundation gives
@@ -9,15 +9,15 @@
 
 # @configure_input@
 
-# serial 3337 ltversion.m4
+# serial 4179 ltversion.m4
 # This file is part of GNU Libtool
 
-m4_define([LT_PACKAGE_VERSION], [2.4.2])
-m4_define([LT_PACKAGE_REVISION], [1.3337])
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
 
 AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.2'
-macro_revision='1.3337'
+[macro_version='2.4.6'
+macro_revision='2.4.6'
 _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
 _LT_DECL(, macro_revision, 0)
 ])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
index c573da9..c6b26f8 100644
--- a/m4/lt~obsolete.m4
+++ b/m4/lt~obsolete.m4
@@ -1,6 +1,7 @@
 # lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
 #
-#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+#   Foundation, Inc.
 #   Written by Scott James Remnant, 2004.
 #
 # This file is free software; the Free Software Foundation gives
@@ -11,7 +12,7 @@
 
 # These exist entirely to fool aclocal when bootstrapping libtool.
 #
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
 # which have later been changed to m4_define as they aren't part of the
 # exported API, or moved to Autoconf or Automake where they belong.
 #
@@ -25,7 +26,7 @@
 # included after everything else.  This provides aclocal with the
 # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
 # because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
 #
 # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
 # Yes, that means every name once taken will need to remain here until
diff --git a/m4/pkg.m4 b/m4/pkg.m4
index c5b26b5..4688002 100644
--- a/m4/pkg.m4
+++ b/m4/pkg.m4
@@ -1,29 +1,60 @@
-# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
-# serial 1 (pkg-config-0.24)
-# 
-# Copyright © 2004 Scott James Remnant <scott at netsplit.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
+dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29)
+dnl
+dnl Copyright © 2004 Scott James Remnant <scott at netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists at gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
 AC_DEFUN([PKG_PROG_PKG_CONFIG],
 [m4_pattern_forbid([^_?PKG_[A-Z_]+$])
 m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
@@ -45,18 +76,19 @@ if test -n "$PKG_CONFIG"; then
 		PKG_CONFIG=""
 	fi
 fi[]dnl
-])# PKG_PROG_PKG_CONFIG
-
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists.  Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-# only at the first occurence in configure.ac, so if the first place
-# it's called might be skipped (such as if it is within an "if", you
-# have to call PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
 AC_DEFUN([PKG_CHECK_EXISTS],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 if test -n "$PKG_CONFIG" && \
@@ -66,8 +98,10 @@ m4_ifvaln([$3], [else
   $3])dnl
 fi])
 
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
 m4_define([_PKG_CONFIG],
 [if test -n "$$1"; then
     pkg_cv_[]$1="$$1"
@@ -79,10 +113,11 @@ m4_define([_PKG_CONFIG],
  else
     pkg_failed=untried
 fi[]dnl
-])# _PKG_CONFIG
+])dnl _PKG_CONFIG
 
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
 AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -90,19 +125,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
 else
         _pkg_short_errors_supported=no
 fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
-
-
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
 AC_DEFUN([PKG_CHECK_MODULES],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
@@ -156,16 +189,40 @@ else
         AC_MSG_RESULT([yes])
 	$3
 fi[]dnl
-])# PKG_CHECK_MODULES
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
 
 
-# PKG_INSTALLDIR(DIRECTORY)
-# -------------------------
-# Substitutes the variable pkgconfigdir as the location where a module
-# should install pkg-config .pc files. By default the directory is
-# $libdir/pkgconfig, but the default can be changed by passing
-# DIRECTORY. The user can override through the --with-pkgconfigdir
-# parameter.
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
 AC_DEFUN([PKG_INSTALLDIR],
 [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
 m4_pushdef([pkg_description],
@@ -176,16 +233,18 @@ AC_ARG_WITH([pkgconfigdir],
 AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
 m4_popdef([pkg_default])
 m4_popdef([pkg_description])
-]) dnl PKG_INSTALLDIR
+])dnl PKG_INSTALLDIR
 
 
-# PKG_NOARCH_INSTALLDIR(DIRECTORY)
-# -------------------------
-# Substitutes the variable noarch_pkgconfigdir as the location where a
-# module should install arch-independent pkg-config .pc files. By
-# default the directory is $datadir/pkgconfig, but the default can be
-# changed by passing DIRECTORY. The user can override through the
-# --with-noarch-pkgconfigdir parameter.
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
 AC_DEFUN([PKG_NOARCH_INSTALLDIR],
 [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
 m4_pushdef([pkg_description],
@@ -196,13 +255,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
 AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
 m4_popdef([pkg_default])
 m4_popdef([pkg_description])
-]) dnl PKG_NOARCH_INSTALLDIR
+])dnl PKG_NOARCH_INSTALLDIR
 
 
-# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
-# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-# -------------------------------------------
-# Retrieves the value of the pkg-config variable for the given module.
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
 AC_DEFUN([PKG_CHECK_VAR],
 [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
 AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
@@ -211,4 +272,4 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
 AS_VAR_COPY([$1], [pkg_cv_][$1])
 
 AS_VAR_IF([$1], [""], [$5], [$4])dnl
-])# PKG_CHECK_VAR
+])dnl PKG_CHECK_VAR
diff --git a/man/openmpt123.1 b/man/openmpt123.1
index 33d8115..fc52a95 100644
--- a/man/openmpt123.1
+++ b/man/openmpt123.1
@@ -1,5 +1,5 @@
-.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.46.4.
-.TH OPENMPT123 "1" "July 2017" "openmpt123 v0.2" "User Commands"
+.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.47.4.
+.TH OPENMPT123 "1" "September 2017" "openmpt123 v0.3.1" "User Commands"
 .SH NAME
 openmpt123 - command line module music player based on libopenmpt
 .SH SYNOPSIS
@@ -36,6 +36,9 @@ Show elaborate contributors list
 \fB\-\-license\fR
 Show license
 .TP
+\fB\-\-probe\fR
+Probe each file whether it is a supported file format
+.TP
 \fB\-\-info\fR
 Display information about each file
 .TP
@@ -105,6 +108,9 @@ Set pitch factor f [default: 1]
 \fB\-\-dither\fR n
 Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: 1]
 .TP
+\fB\-\-playlist\fR file
+Load playlist from file
+.TP
 \fB\-\-[no\-]randomize\fR
 Randomize playlist [default: 0]
 .TP
diff --git a/src/openmpt123/openmpt123.cpp b/openmpt123/openmpt123.cpp
similarity index 85%
rename from src/openmpt123/openmpt123.cpp
rename to openmpt123/openmpt123.cpp
index c979d22..529079f 100644
--- a/src/openmpt123/openmpt123.cpp
+++ b/openmpt123/openmpt123.cpp
@@ -53,9 +53,7 @@ static const char * const license =
 #include <vector>
 
 #include <cmath>
-#if !defined(OPENMPT123_ANCIENT_COMPILER_STDINT)
 #include <cstdint>
-#endif
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -174,11 +172,7 @@ public:
 		: impl(0)
 	{
 		if ( !flags.force_overwrite ) {
-#if defined(OPENMPT123_ANCIENT_COMPILER_FSTREAM)
-			std::ifstream testfile( filename.c_str(), std::ios::binary );
-#else
 			std::ifstream testfile( filename, std::ios::binary );
-#endif
 			if ( testfile ) {
 				throw exception( "file already exists" );
 			}
@@ -307,17 +301,99 @@ static std::string replace( std::string str, const std::string & oldstr, const s
 	return str;
 }
 
-#if defined( WIN32 )
-static const char path_sep = '\\';
+static bool begins_with( const std::string & str, const std::string & match ) {
+	return ( str.find( match ) == 0 );
+}
+
+static bool ends_with( const std::string & str, const std::string & match ) {
+	return ( str.rfind( match ) == ( str.length() - match.length() ) );
+}
+
+static std::string trim_left(std::string str, const std::string &whitespace = std::string()) {
+	std::string::size_type pos = str.find_first_not_of(whitespace);
+	if(pos != std::string::npos) {
+		str.erase(str.begin(), str.begin() + pos);
+	} else if(pos == std::string::npos && str.length() > 0 && str.find_last_of(whitespace) == str.length() - 1) {
+		return std::string();
+	}
+	return str;
+}
+
+static std::string trim_right(std::string str, const std::string &whitespace = std::string()) {
+	std::string::size_type pos = str.find_last_not_of(whitespace);
+	if(pos != std::string::npos) {
+		str.erase(str.begin() + pos + 1, str.end());
+	} else if(pos == std::string::npos && str.length() > 0 && str.find_first_of(whitespace) == 0) {
+		return std::string();
+	}
+	return str;
+}
+
+static std::string trim(std::string str, const std::string &whitespace = std::string()) {
+	return trim_right(trim_left(str, whitespace), whitespace);
+}
+
+static std::string trim_eol( const std::string & str ) {
+	return trim( str, "\r\n" );
+}
+
+static std::string default_path_separator() {
+#if defined(WIN32)
+	return "\\";
 #else
-static const char path_sep = '/';
+	return "/";
 #endif
+}
+
+static std::string path_separators() {
+#if defined(WIN32)
+	return "\\/";
+#else
+	return "/";
+#endif
+}
+
+static bool is_path_separator( char c ) {
+#if defined(WIN32)
+	return ( c == '\\' ) || ( c == '/' );
+#else
+	return c == '/';
+#endif
+}
+
+static std::string get_basepath( std::string filename ) {
+	std::string::size_type pos = filename.find_last_of( path_separators() );
+	if ( pos == std::string::npos ) {
+		return std::string();
+	}
+	return filename.substr( 0, pos ) + default_path_separator();
+}
+
+static bool is_absolute( std::string filename ) {
+#if defined(WIN32)
+	if ( begins_with( filename, "\\\\?\\UNC\\" ) ) {
+		return true;
+	}
+	if ( begins_with( filename, "\\\\?\\" ) ) {
+		return true;
+	}
+	if ( begins_with( filename, "\\\\" ) ) {
+		return true; // UNC
+	}
+	if ( begins_with( filename, "//" ) ) {
+		return true; // UNC
+	}
+	return ( filename.length() ) >= 3 && ( filename[1] == ':' ) && is_path_separator( filename[2] );
+#else
+	return ( filename.length() >= 1 ) && is_path_separator( filename[0] );
+#endif
+}
 
 static std::string get_filename( const std::string & filepath ) {
-	if ( filepath.find_last_of( std::string(1,path_sep) ) == std::string::npos ) {
+	if ( filepath.find_last_of( path_separators() ) == std::string::npos ) {
 		return filepath;
 	}
-	return filepath.substr( filepath.find_last_of( std::string(1,path_sep) ) + 1 );
+	return filepath.substr( filepath.find_last_of( path_separators() ) + 1 );
 }
 
 static std::string prepend_lines( std::string str, const std::string & prefix ) {
@@ -372,6 +448,36 @@ static void show_info( std::ostream & log, bool verbose ) {
 	}
 	log << "  libopenmpt source..: " << openmpt::string::get( "source_url" ) << std::endl;
 	log << "  libopenmpt date....: " << openmpt::string::get( "source_date" ) << std::endl;
+	log << "  libopenmpt srcinfo.: ";
+	{
+		std::vector<std::string> fields;
+		if ( openmpt::string::get( "source_is_package" ) == "1" ) {
+			fields.push_back( "package" );
+		}
+		if ( openmpt::string::get( "source_is_release" ) == "1" ) {
+			fields.push_back( "release" );
+		}
+		if ( ( !openmpt::string::get( "source_revision" ).empty() ) && ( openmpt::string::get( "source_revision" ) != "0" ) ) {
+			std::string field = "rev" + openmpt::string::get( "source_revision" );
+			if ( openmpt::string::get( "source_has_mixed_revisions" ) == "1" ) {
+				field += "+mixed";
+			}
+			if ( openmpt::string::get( "source_is_modified" ) == "1" ) {
+				field += "+modified";
+			}
+			fields.push_back( field );
+		}
+		bool first = true;
+		for ( std::vector<std::string>::const_iterator it = fields.begin(); it != fields.end(); ++it ) {
+			if ( first ) {
+				first = false;
+			} else {
+				log << ", ";
+			}
+			log << (*it);
+		}
+	}
+	log << std::endl;
 	log << "  libopenmpt compiler: " << openmpt::string::get( "build_compiler" ) << std::endl;
 	log << "  libopenmpt features: " << openmpt::string::get( "library_features" ) << std::endl;
 #ifdef MPT_WITH_SDL2
@@ -494,6 +600,7 @@ static void show_help( textout & log, bool with_info = true, bool longhelp = fal
 		log << "     --credits              Show elaborate contributors list" << std::endl;
 		log << "     --license              Show license" << std::endl;
 		log << std::endl;
+		log << "     --probe                Probe each file whether it is a supported file format" << std::endl;
 		log << "     --info                 Display information about each file" << std::endl;
 		log << "     --ui                   Interactively play each file" << std::endl;
 		log << "     --batch                Play each file" << std::endl;
@@ -529,6 +636,7 @@ static void show_help( textout & log, bool with_info = true, bool longhelp = fal
 		log << "     --pitch f              Set pitch factor f [default: " << pitch_flag_to_double( commandlineflags().pitch ) << "]" << std::endl;
 		log << "     --dither n             Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: " << commandlineflags().dither << "]" << std::endl;
 		log << std::endl;
+		log << "     --playlist file        Load playlist from file" << std::endl;
 		log << "     --[no-]randomize       Randomize playlist [default: " << commandlineflags().randomize << "]" << std::endl;
 		log << "     --[no-]shuffle         Shuffle through playlist [default: " << commandlineflags().shuffle << "]" << std::endl;
 		log << "     --[no-]restart         Restart playlist when finished [default: " << commandlineflags().restart << "]" << std::endl;
@@ -938,17 +1046,10 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto
 	std::vector<Tsample> rear_left( bufsize );
 	std::vector<Tsample> rear_right( bufsize );
 	std::vector<Tsample*> buffers( 4 ) ;
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-	buffers[0] = &left[0];
-	buffers[1] = &right[0];
-	buffers[2] = &rear_left[0];
-	buffers[3] = &rear_right[0];
-#else
 	buffers[0] = left.data();
 	buffers[1] = right.data();
 	buffers[2] = rear_left.data();
 	buffers[3] = rear_right.data();
-#endif
 	buffers.resize( flags.channels );
 	
 	meter_type meter;
@@ -1063,15 +1164,9 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto
 		std::size_t count = 0;
 
 		switch ( flags.channels ) {
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-			case 1: count = mod.read( flags.samplerate, bufsize, &left[0] ); break;
-			case 2: count = mod.read( flags.samplerate, bufsize, &left[0], &right[0] ); break;
-			case 4: count = mod.read( flags.samplerate, bufsize, &left[0], &right[0], &rear_left[0], &rear_right[0] ); break;
-#else
 			case 1: count = mod.read( flags.samplerate, bufsize, left.data() ); break;
 			case 2: count = mod.read( flags.samplerate, bufsize, left.data(), right.data() ); break;
 			case 4: count = mod.read( flags.samplerate, bufsize, left.data(), right.data(), rear_left.data(), rear_right.data() ); break;
-#endif
 		}
 		
 		char cpu_str[64] = "";
@@ -1088,11 +1183,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto
 		}
 
 		if ( flags.show_meters ) {
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-			update_meter( meter, flags, count, &buffers[0] );
-#else
 			update_meter( meter, flags, count, buffers.data() );
-#endif
 		}
 
 		if ( count > 0 ) {
@@ -1343,12 +1434,64 @@ static void show_fields( textout & log, const std::vector<field> & fields ) {
 	}
 }
 
+static void probe_mod_file( commandlineflags & flags, const std::string & filename, std::uint64_t filesize, std::istream & data_stream, textout & log ) {
+
+	log.writeout();
+
+	std::vector<field> fields;
+
+	if ( flags.filenames.size() > 1 ) {
+		set_field( fields, "Playlist" ).ostream() << flags.playlist_index + 1 << "/" << flags.filenames.size();
+		set_field( fields, "Prev/Next" ).ostream()
+		    << "'"
+		    << ( flags.playlist_index > 0 ? get_filename( flags.filenames[ flags.playlist_index - 1 ] ) : std::string() )
+		    << "'"
+		    << " / "
+		    << "['" << get_filename( filename ) << "']"
+		    << " / "
+		    << "'"
+		    << ( flags.playlist_index + 1 < flags.filenames.size() ? get_filename( flags.filenames[ flags.playlist_index + 1 ] ) : std::string() )
+		    << "'"
+		   ;
+	}
+	if ( flags.verbose ) {
+		set_field( fields, "Path" ).ostream() << filename;
+	}
+	if ( flags.show_details ) {
+		set_field( fields, "Filename" ).ostream() << get_filename( filename );
+		set_field( fields, "Size" ).ostream() << bytes_to_string( filesize );
+	}
+	
+	int probe_result = openmpt::probe_file_header( openmpt::probe_file_header_flags_default, data_stream );
+	std::string probe_result_string;
+	switch ( probe_result ) {
+		case openmpt::probe_file_header_result_success:
+			probe_result_string = "Success";
+			break;
+		case openmpt::probe_file_header_result_failure:
+			probe_result_string = "Failure";
+			break;
+		case openmpt::probe_file_header_result_wantmoredata:
+			probe_result_string = "Insufficient Data";
+			break;
+		default:
+			probe_result_string = "Internal Error";
+			break;
+	}
+	set_field( fields, "Probe" ).ostream() << probe_result_string;
+
+	show_fields( log, fields );
+
+	log.writeout();
+
+}
+
 template < typename Tmod >
 void render_mod_file( commandlineflags & flags, const std::string & filename, std::uint64_t filesize, Tmod & mod, textout & log, write_buffers_interface & audio_stream ) {
 
 	log.writeout();
 
-	if ( flags.mode != ModeInfo ) {
+	if ( flags.mode != ModeProbe && flags.mode != ModeInfo ) {
 		mod.set_repeat_count( flags.repeatcount );
 		apply_mod_settings( flags, mod );
 	}
@@ -1421,7 +1564,7 @@ void render_mod_file( commandlineflags & flags, const std::string & filename, st
 		audio_stream.write_updated_metadata( get_metadata( mod ) );
 	}
 
-	if ( flags.mode == ModeInfo ) {
+	if ( flags.mode == ModeProbe || flags.mode == ModeInfo ) {
 		return;
 	}
 
@@ -1449,7 +1592,7 @@ void render_mod_file( commandlineflags & flags, const std::string & filename, st
 
 }
 
-static void render_file( commandlineflags & flags, const std::string & filename, textout & log, write_buffers_interface & audio_stream ) {
+static void probe_file( commandlineflags & flags, const std::string & filename, textout & log ) {
 
 	log.writeout();
 
@@ -1483,20 +1626,88 @@ static void render_file( commandlineflags & flags, const std::string & filename,
 				file_stream.str( data );
 				filesize = data.length();
 			#elif defined(_MSC_VER) && defined(UNICODE)
-#if defined(OPENMPT123_ANCIENT_COMPILER_FSTREAM)
-				file_stream.open( utf8_to_wstring( filename ).c_str(), std::ios::binary );
-#else
 				file_stream.open( utf8_to_wstring( filename ), std::ios::binary );
-#endif
 				file_stream.seekg( 0, std::ios::end );
 				filesize = file_stream.tellg();
 				file_stream.seekg( 0, std::ios::beg );
 			#else
-#if defined(OPENMPT123_ANCIENT_COMPILER_FSTREAM)
-				file_stream.open( filename.c_str(), std::ios::binary );
-#else
 				file_stream.open( filename, std::ios::binary );
+				file_stream.seekg( 0, std::ios::end );
+				filesize = file_stream.tellg();
+				file_stream.seekg( 0, std::ios::beg );
+			#endif
+		}
+		std::istream & data_stream = use_stdin ? std::cin : file_stream;
+		if ( data_stream.fail() ) {
+			throw exception( "file open error" );
+		}
+		
+		probe_mod_file( flags, filename, filesize, data_stream, log );
+
+	} catch ( silent_exit_exception & ) {
+		throw;
+	} catch ( std::exception & e ) {
+		if ( !silentlog.str().empty() ) {
+			log << "errors probing '" << filename << "': " << silentlog.str() << std::endl;
+		} else {
+			log << "errors probing '" << filename << "'" << std::endl;
+		}
+		log << "error probing '" << filename << "': " << e.what() << std::endl;
+	} catch ( ... ) {
+		if ( !silentlog.str().empty() ) {
+			log << "errors probing '" << filename << "': " << silentlog.str() << std::endl;
+		} else {
+			log << "errors probing '" << filename << "'" << std::endl;
+		}
+		log << "unknown error probing '" << filename << "'" << std::endl;
+	}
+
+	log << std::endl;
+
+	log.writeout();
+
+}
+
+static void render_file( commandlineflags & flags, const std::string & filename, textout & log, write_buffers_interface & audio_stream ) {
+
+	log.writeout();
+
+	std::ostringstream silentlog;
+
+	try {
+
+#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
+		std::istringstream file_stream;
+#else
+		std::ifstream file_stream;
 #endif
+		std::uint64_t filesize = 0;
+		bool use_stdin = ( filename == "-" );
+		if ( !use_stdin ) {
+			#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
+				// Only MSVC has std::ifstream::ifstream(std::wstring).
+				// Fake it for other compilers using _wfopen().
+				std::string data;
+				FILE * f = _wfopen( utf8_to_wstring( filename ).c_str(), L"rb" );
+				if ( f ) {
+					while ( !feof( f ) ) {
+						static const std::size_t BUFFER_SIZE = 4096;
+						char buffer[BUFFER_SIZE];
+						size_t data_read = fread( buffer, 1, BUFFER_SIZE, f );
+						std::copy( buffer, buffer + data_read, std::back_inserter( data ) );
+					}
+					fclose( f );
+					f = NULL;
+				}
+				file_stream.str( data );
+				filesize = data.length();
+			#elif defined(_MSC_VER) && defined(UNICODE)
+				file_stream.open( utf8_to_wstring( filename ), std::ios::binary );
+				file_stream.seekg( 0, std::ios::end );
+				filesize = file_stream.tellg();
+				file_stream.seekg( 0, std::ios::beg );
+			#else
+				file_stream.open( filename, std::ios::binary );
 				file_stream.seekg( 0, std::ios::end );
 				filesize = file_stream.tellg();
 				file_stream.seekg( 0, std::ios::beg );
@@ -1620,6 +1831,126 @@ static void render_files( commandlineflags & flags, textout & log, write_buffers
 }
 
 
+static bool parse_playlist( commandlineflags & flags, std::string filename, std::ostream & log ) {
+	log.flush();
+	bool is_playlist = false;
+	bool m3u8 = false;
+	if ( ends_with( filename, ".m3u") || ends_with( filename, ".m3U") || ends_with( filename, ".M3u") || ends_with( filename, ".M3U") ) {
+		is_playlist = true;
+	}
+	if ( ends_with( filename, ".m3u8") || ends_with( filename, ".m3U8") || ends_with( filename, ".M3u8") || ends_with( filename, ".M3U8") ) {
+		is_playlist = true;
+		m3u8 = true;
+	}
+	if ( ends_with( filename, ".pls") || ends_with( filename, ".plS") || ends_with( filename, ".pLs") || ends_with( filename, ".pLS") || ends_with( filename, ".Pls")  || ends_with( filename, ".PlS")  || ends_with( filename, ".PLs")  || ends_with( filename, ".PLS") ) {
+		is_playlist = true;
+	}
+	std::string basepath = get_basepath( filename );
+	try {
+#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
+		std::istringstream file_stream;
+#else
+		std::ifstream file_stream;
+#endif
+		#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER)
+			// Only MSVC has std::ifstream::ifstream(std::wstring).
+			// Fake it for other compilers using _wfopen().
+			std::string data;
+			FILE * f = _wfopen( utf8_to_wstring( filename ).c_str(), L"rb" );
+			if ( f ) {
+				while ( !feof( f ) ) {
+					static const std::size_t BUFFER_SIZE = 4096;
+					char buffer[BUFFER_SIZE];
+					size_t data_read = fread( buffer, 1, BUFFER_SIZE, f );
+					std::copy( buffer, buffer + data_read, std::back_inserter( data ) );
+				}
+				fclose( f );
+				f = NULL;
+			}
+			file_stream.str( data );
+		#elif defined(_MSC_VER) && defined(UNICODE)
+			file_stream.open( utf8_to_wstring( filename ), std::ios::binary );
+		#else
+			file_stream.open( filename, std::ios::binary );
+		#endif
+		std::string line;
+		bool first = true;
+		bool extm3u = false;
+		bool pls = false;
+		while ( std::getline( file_stream, line ) ) {
+			std::string newfile;
+			line = trim_eol( line );
+			if ( first ) {
+				first = false;
+				if ( line == "#EXTM3U" ) {
+					extm3u = true;
+					continue;
+				} else if ( line == "[playlist]" ) {
+					pls = true;
+				}
+			}
+			if ( line.empty() ) {
+				continue;
+			}
+			if ( pls ) {
+				if ( begins_with( line, "File" ) ) {
+					if ( line.find( "=" ) != std::string::npos ) {
+						flags.filenames.push_back( line.substr( line.find( "=" ) + 1 ) );
+					}
+				} else if ( begins_with( line, "Title" ) ) {
+					continue;
+				} else if ( begins_with( line, "Length" ) ) {
+					continue;
+				} else if ( begins_with( line, "NumberOfEntries" ) ) {
+					continue;
+				} else if ( begins_with( line, "Version" ) ) {
+					continue;
+				} else {
+					continue;
+				}
+			} else if ( extm3u ) {
+				if ( begins_with( line, "#EXTINF" ) ) {
+					continue;
+				} else if ( begins_with( line, "#" ) ) {
+					continue;
+				}
+				if ( m3u8 ) {
+					newfile = line;
+				} else {
+#if defined(WIN32)
+					newfile = wstring_to_utf8( locale_to_wstring( line ) );
+#else
+					newfile = line;
+#endif
+				}
+			} else {
+				if ( m3u8 ) {
+					newfile = line;
+				} else {
+#if defined(WIN32)
+					newfile = wstring_to_utf8( locale_to_wstring( line ) );
+#else
+					newfile = line;
+#endif
+				}
+			}
+			if ( !newfile.empty() ) {
+				if ( !is_absolute( newfile ) ) {
+					newfile = basepath + newfile;
+				}
+				flags.filenames.push_back( newfile );
+			}
+		}
+	} catch ( std::exception & e ) {
+		log << "error loading '" << filename << "': " << e.what() << std::endl;
+	} catch ( ... ) {
+		log << "unknown error loading '" << filename << "'" << std::endl;
+	}
+	log.flush();
+	return is_playlist;
+}
+
+
 static commandlineflags parse_openmpt123( const std::vector<std::string> & args, std::ostream & log ) {
 
 	log.flush();
@@ -1667,6 +1998,8 @@ static commandlineflags parse_openmpt123( const std::vector<std::string> & args,
 				throw show_credits_exception();
 			} else if ( arg == "--license" ) {
 				throw show_license_exception();
+			} else if ( arg == "--probe" ) {
+				flags.mode = ModeProbe;
 			} else if ( arg == "--info" ) {
 				flags.mode = ModeInfo;
 			} else if ( arg == "--ui" ) {
@@ -1830,6 +2163,9 @@ static commandlineflags parse_openmpt123( const std::vector<std::string> & args,
 				std::istringstream istr( nextarg );
 				istr >> flags.dither;
 				++i;
+			} else if ( arg == "--playlist" && nextarg != "" ) {
+				parse_playlist( flags, nextarg, log );
+				++i;
 			} else if ( arg == "--randomize" ) {
 				flags.randomize = true;
 			} else if ( arg == "--no-randomize" ) {
@@ -2056,6 +2392,12 @@ static int main( int argc, char * argv [] ) {
 		std::srand( static_cast<unsigned int>( std::time( NULL ) ) );
 
 		switch ( flags.mode ) {
+			case ModeProbe: {
+				for ( std::vector<std::string>::iterator filename = flags.filenames.begin(); filename != flags.filenames.end(); ++filename ) {
+					probe_file( flags, *filename, log );
+					flags.playlist_index++;
+				}
+			} break;
 			case ModeInfo: {
 				void_audio_stream dummy;
 				render_files( flags, log, dummy );
diff --git a/src/openmpt123/openmpt123.hpp b/openmpt123/openmpt123.hpp
similarity index 93%
rename from src/openmpt123/openmpt123.hpp
rename to openmpt123/openmpt123.hpp
index 7e3a870..edb6553 100644
--- a/src/openmpt123/openmpt123.hpp
+++ b/openmpt123/openmpt123.hpp
@@ -52,6 +52,26 @@ std::wstring utf8_to_wstring( const std::string & utf8_string ) {
 	return &unicode_buf[0];
 }
 
+std::string wstring_to_locale( const std::wstring & unicode_string ) {
+	int required_size = WideCharToMultiByte( CP_ACP, 0, unicode_string.c_str(), -1, NULL, 0, NULL, NULL );
+	if ( required_size <= 0 ) {
+		return std::string();
+	}
+	std::vector<char> locale_buf( required_size );
+	WideCharToMultiByte( CP_ACP, 0, unicode_string.c_str(), -1, &locale_buf[0], required_size, NULL, NULL );
+	return &locale_buf[0];
+}
+
+std::wstring locale_to_wstring( const std::string & locale_string ) {
+	int required_size = MultiByteToWideChar( CP_ACP, 0, locale_string.c_str(), -1, NULL, 0 );
+	if ( required_size <= 0 ) {
+		return std::wstring();
+	}
+	std::vector<wchar_t> unicode_buf( required_size );
+	MultiByteToWideChar( CP_ACP, 0, locale_string.data(), -1, &unicode_buf[0], required_size );
+	return &unicode_buf[0];
+}
+
 #endif // WIN32
 
 #if defined(MPT_NEEDS_THREADS)
@@ -216,6 +236,7 @@ bool IsTerminal( int fd );
 
 enum Mode {
 	ModeNone,
+	ModeProbe,
 	ModeInfo,
 	ModeUI,
 	ModeBatch,
@@ -225,6 +246,7 @@ enum Mode {
 static inline std::string mode_to_string( Mode mode ) {
 	switch ( mode ) {
 		case ModeNone:   return "none"; break;
+		case ModeProbe:  return "probe"; break;
 		case ModeInfo:   return "info"; break;
 		case ModeUI:     return "ui"; break;
 		case ModeBatch:  return "batch"; break;
@@ -418,6 +440,13 @@ struct commandlineflags {
 			case ModeNone:
 				throw args_error_exception();
 			break;
+			case ModeProbe:
+				show_ui = false;
+				show_progress = false;
+				show_meters = false;
+				show_channel_meters = false;
+				show_pattern = false;
+			break;
 			case ModeInfo:
 				show_ui = false;
 				show_progress = false;
diff --git a/src/openmpt123/openmpt123_config.hpp b/openmpt123/openmpt123_config.hpp
similarity index 58%
rename from src/openmpt123/openmpt123_config.hpp
rename to openmpt123/openmpt123_config.hpp
index 2985711..fc76f0f 100644
--- a/src/openmpt123/openmpt123_config.hpp
+++ b/openmpt123/openmpt123_config.hpp
@@ -44,6 +44,10 @@
 
 #pragma warning( disable : 4996 ) // 'foo': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _foo. See online help for details.
 
+#endif // _MSC_VER
+
+#if defined(MPT_BUILD_MSVC)
+
 #define MPT_WITH_FLAC
 #define MPT_WITH_PORTAUDIO
 
@@ -51,7 +55,7 @@
 #define FLAC__NO_DLL
 #endif
 
-#endif // _MSC_VER
+#endif // MPT_BUILD_MSVC
 
 #if defined(MPT_WITH_SDL)
 #ifndef MPT_NEEDS_THREADS
@@ -59,37 +63,6 @@
 #endif
 #endif
 
-#define OPENMPT123_VERSION_STRING "0.2"
-
-#if defined(_MSC_VER)
-#if (_MSC_VER >= 1500) && (_MSC_VER < 1600)
-#define OPENMPT123_ANCIENT_COMPILER_STDINT
-#define OPENMPT123_ANCIENT_COMPILER_FSTREAM
-#define OPENMPT123_ANCIENT_COMPILER_VECTOR
-#endif
-#endif
-
-#if defined(__GNUC__) && !defined(__clang__)
-#if (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1 < 40300)
-#define OPENMPT123_ANCIENT_COMPILER_STDINT
-#endif
-#if (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__*1 < 40400)
-#define OPENMPT123_ANCIENT_COMPILER_FSTREAM
-#endif
-#endif
-
-#ifdef OPENMPT123_ANCIENT_COMPILER_STDINT
-#include <stdint.h>
-namespace std {
-typedef int8_t   int8_t;
-typedef int16_t  int16_t;
-typedef int32_t  int32_t;
-typedef int64_t  int64_t;
-typedef uint8_t  uint8_t;
-typedef uint16_t uint16_t;
-typedef uint32_t uint32_t;
-typedef uint64_t uint64_t;
-}
-#endif
+#define OPENMPT123_VERSION_STRING OPENMPT_API_VERSION_STRING
 
 #endif // OPENMPT123_CONFIG_HPP
diff --git a/src/openmpt123/openmpt123_flac.hpp b/openmpt123/openmpt123_flac.hpp
similarity index 93%
rename from src/openmpt123/openmpt123_flac.hpp
rename to openmpt123/openmpt123_flac.hpp
index 42e2bf9..037931c 100644
--- a/src/openmpt123/openmpt123_flac.hpp
+++ b/openmpt123/openmpt123_flac.hpp
@@ -111,11 +111,7 @@ public:
 				interleaved_buffer.push_back( out );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		FLAC__stream_encoder_process_interleaved( encoder, &interleaved_buffer[0], static_cast<unsigned int>( frames ) );
-#else
 		FLAC__stream_encoder_process_interleaved( encoder, interleaved_buffer.data(), static_cast<unsigned int>( frames ) );
-#endif
 	}
 	void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) {
 		if ( !called_init ) {
@@ -128,11 +124,7 @@ public:
 				interleaved_buffer.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		FLAC__stream_encoder_process_interleaved( encoder, &interleaved_buffer[0], static_cast<unsigned int>( frames ) );
-#else
 		FLAC__stream_encoder_process_interleaved( encoder, interleaved_buffer.data(), static_cast<unsigned int>( frames ) );
-#endif
 	}
 };
 
diff --git a/src/openmpt123/openmpt123_mmio.hpp b/openmpt123/openmpt123_mmio.hpp
similarity index 100%
rename from src/openmpt123/openmpt123_mmio.hpp
rename to openmpt123/openmpt123_mmio.hpp
diff --git a/src/openmpt123/openmpt123_portaudio.hpp b/openmpt123/openmpt123_portaudio.hpp
similarity index 96%
rename from src/openmpt123/openmpt123_portaudio.hpp
rename to openmpt123/openmpt123_portaudio.hpp
index 114adaa..e15e2f2 100644
--- a/src/openmpt123/openmpt123_portaudio.hpp
+++ b/openmpt123/openmpt123_portaudio.hpp
@@ -197,11 +197,7 @@ private:
 	void write_frames( std::vector<Tsample*> buffers, std::size_t frames ) {
 		while ( frames > 0 ) {
 			unsigned long chunk_frames = static_cast<unsigned long>( std::min<std::size_t>( frames, std::numeric_limits<unsigned long>::max() ) );
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-			check_portaudio_error( Pa_WriteStream( stream, &buffers[0], chunk_frames ) );
-#else
 			check_portaudio_error( Pa_WriteStream( stream, buffers.data(), chunk_frames ) );
-#endif
 			for ( std::size_t channel = 0; channel < channels; ++channel ) {
 				buffers[channel] += chunk_frames;
 			}
@@ -217,11 +213,7 @@ public:
 					sampleBufFloat.push_back( buffers[channel][frame] );
 				}
 			}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-			write_frames( &sampleBufFloat[0], frames );
-#else
 			write_frames( sampleBufFloat.data(), frames );
-#endif
 		} else {
 			write_frames( buffers, frames );
 		}
@@ -234,11 +226,7 @@ public:
 					sampleBufInt.push_back( buffers[channel][frame] );
 				}
 			}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-			write_frames( &sampleBufInt[0], frames );
-#else
 			write_frames( sampleBufInt.data(), frames );
-#endif
 		} else {
 			write_frames( buffers, frames );
 		}
diff --git a/src/openmpt123/openmpt123_pulseaudio.hpp b/openmpt123/openmpt123_pulseaudio.hpp
similarity index 95%
rename from src/openmpt123/openmpt123_pulseaudio.hpp
rename to openmpt123/openmpt123_pulseaudio.hpp
index be999b6..f6d7cba 100644
--- a/src/openmpt123/openmpt123_pulseaudio.hpp
+++ b/openmpt123/openmpt123_pulseaudio.hpp
@@ -124,11 +124,7 @@ public:
 				sampleBufFloat.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		write_frames( &sampleBufFloat[0], frames );
-#else
 		write_frames( sampleBufFloat.data(), frames );
-#endif
 	}
 	void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) {
 		sampleBufInt.clear();
@@ -137,11 +133,7 @@ public:
 				sampleBufInt.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		write_frames( &sampleBufInt[0], frames );
-#else
 		write_frames( sampleBufInt.data(), frames );
-#endif
 	}
 	bool unpause() {
 		return true;
diff --git a/src/openmpt123/openmpt123_raw.hpp b/openmpt123/openmpt123_raw.hpp
similarity index 83%
rename from src/openmpt123/openmpt123_raw.hpp
rename to openmpt123/openmpt123_raw.hpp
index ff85b72..25b2e25 100644
--- a/src/openmpt123/openmpt123_raw.hpp
+++ b/openmpt123/openmpt123_raw.hpp
@@ -40,11 +40,7 @@ public:
 				interleaved_float_buffer.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		file.write( reinterpret_cast<const char *>( &interleaved_float_buffer[0] ), frames * buffers.size() * sizeof( float ) );
-#else
 		file.write( reinterpret_cast<const char *>( interleaved_float_buffer.data() ), frames * buffers.size() * sizeof( float ) );
-#endif
 	}
 	void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) {
 		interleaved_int_buffer.clear();
@@ -53,11 +49,7 @@ public:
 				interleaved_int_buffer.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		file.write( reinterpret_cast<const char *>( &interleaved_int_buffer[0] ), frames * buffers.size() * sizeof( std::int16_t ) );
-#else
 		file.write( reinterpret_cast<const char *>( interleaved_int_buffer.data() ), frames * buffers.size() * sizeof( std::int16_t ) );
-#endif
 	}
 };
 
diff --git a/src/openmpt123/openmpt123_sdl.hpp b/openmpt123/openmpt123_sdl.hpp
similarity index 100%
rename from src/openmpt123/openmpt123_sdl.hpp
rename to openmpt123/openmpt123_sdl.hpp
diff --git a/src/openmpt123/openmpt123_sdl2.hpp b/openmpt123/openmpt123_sdl2.hpp
similarity index 100%
rename from src/openmpt123/openmpt123_sdl2.hpp
rename to openmpt123/openmpt123_sdl2.hpp
diff --git a/src/openmpt123/openmpt123_sndfile.hpp b/openmpt123/openmpt123_sndfile.hpp
similarity index 100%
rename from src/openmpt123/openmpt123_sndfile.hpp
rename to openmpt123/openmpt123_sndfile.hpp
diff --git a/src/openmpt123/openmpt123_stdout.hpp b/openmpt123/openmpt123_stdout.hpp
similarity index 80%
rename from src/openmpt123/openmpt123_stdout.hpp
rename to openmpt123/openmpt123_stdout.hpp
index d840706..6b18198 100644
--- a/src/openmpt123/openmpt123_stdout.hpp
+++ b/openmpt123/openmpt123_stdout.hpp
@@ -31,11 +31,7 @@ public:
 				interleaved_float_buffer.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		std::cout.write( reinterpret_cast<const char *>( &interleaved_float_buffer[0] ), interleaved_float_buffer.size() * sizeof( float ) );
-#else
 		std::cout.write( reinterpret_cast<const char *>( interleaved_float_buffer.data() ), interleaved_float_buffer.size() * sizeof( float ) );
-#endif
 	}
 	void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) {
 		interleaved_int_buffer.clear();
@@ -44,11 +40,7 @@ public:
 				interleaved_int_buffer.push_back( buffers[channel][frame] );
 			}
 		}
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-		std::cout.write( reinterpret_cast<const char *>( &interleaved_int_buffer[0] ), interleaved_int_buffer.size() * sizeof( std::int16_t ) );
-#else
 		std::cout.write( reinterpret_cast<const char *>( interleaved_int_buffer.data() ), interleaved_int_buffer.size() * sizeof( std::int16_t ) );
-#endif
 	}
 };
 
diff --git a/src/openmpt123/openmpt123_waveout.hpp b/openmpt123/openmpt123_waveout.hpp
similarity index 98%
rename from src/openmpt123/openmpt123_waveout.hpp
rename to openmpt123/openmpt123_waveout.hpp
index 184792c..9a245fc 100644
--- a/src/openmpt123/openmpt123_waveout.hpp
+++ b/openmpt123/openmpt123_waveout.hpp
@@ -76,11 +76,7 @@ public:
 		for ( std::size_t i = 0; i < num_chunks; ++i ) {
 			wavebuffers[i].resize( bytes_per_chunk );
 			waveheaders[i] = WAVEHDR();
-#if defined(OPENMPT123_ANCIENT_COMPILER_VECTOR)
-			waveheaders[i].lpData = &wavebuffers[i][0];
-#else
 			waveheaders[i].lpData = wavebuffers[i].data();
-#endif
 			waveheaders[i].dwBufferLength = static_cast<DWORD>( wavebuffers[i].size() );
 			waveheaders[i].dwFlags = 0;
 			waveOutPrepareHeader( waveout, &waveheaders[i], sizeof( WAVEHDR ) );
diff --git a/soundbase/SampleFormat.h b/soundbase/SampleFormat.h
new file mode 100644
index 0000000..29d13b0
--- /dev/null
+++ b/soundbase/SampleFormat.h
@@ -0,0 +1,93 @@
+/*
+ * SampleFormat.h
+ * ---------------
+ * Purpose: Utility enum and funcion to describe sample formats.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+enum SampleFormatEnum
+{
+	SampleFormatUnsigned8 =  8,       // do not change value (for compatibility with old configuration settings)
+	SampleFormatInt16     = 16,       // do not change value (for compatibility with old configuration settings)
+	SampleFormatInt24     = 24,       // do not change value (for compatibility with old configuration settings)
+	SampleFormatInt32     = 32,       // do not change value (for compatibility with old configuration settings)
+	SampleFormatFloat32   = 32 + 128, // do not change value (for compatibility with old configuration settings)
+	SampleFormatInvalid   =  0
+};
+
+template<typename Tsample> struct SampleFormatTraits;
+template<> struct SampleFormatTraits<uint8>     { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatUnsigned8; };
+template<> struct SampleFormatTraits<int16>     { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatInt16;     };
+template<> struct SampleFormatTraits<int24>     { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatInt24;     };
+template<> struct SampleFormatTraits<int32>     { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatInt32;     };
+template<> struct SampleFormatTraits<float>     { static MPT_CONSTEXPR11_VAR SampleFormatEnum sampleFormat = SampleFormatFloat32;   };
+
+template<SampleFormatEnum sampleFormat> struct SampleFormatToType;
+template<> struct SampleFormatToType<SampleFormatUnsigned8> { typedef uint8     type; };
+template<> struct SampleFormatToType<SampleFormatInt16>     { typedef int16     type; };
+template<> struct SampleFormatToType<SampleFormatInt24>     { typedef int24     type; };
+template<> struct SampleFormatToType<SampleFormatInt32>     { typedef int32     type; };
+template<> struct SampleFormatToType<SampleFormatFloat32>   { typedef float     type; };
+
+
+struct SampleFormat
+{
+	SampleFormatEnum value;
+	MPT_CONSTEXPR11_FUN SampleFormat(SampleFormatEnum v = SampleFormatInvalid) : value(v) { }
+	MPT_CONSTEXPR11_FUN bool operator == (SampleFormat other) const { return value == other.value; }
+	MPT_CONSTEXPR11_FUN bool operator != (SampleFormat other) const { return value != other.value; }
+	MPT_CONSTEXPR11_FUN bool operator == (SampleFormatEnum other) const { return value == other; }
+	MPT_CONSTEXPR11_FUN bool operator != (SampleFormatEnum other) const { return value != other; }
+	MPT_CONSTEXPR11_FUN operator SampleFormatEnum () const
+	{
+		return value;
+	}
+	MPT_CONSTEXPR11_FUN bool IsValid() const
+	{
+		return value != SampleFormatInvalid;
+	}
+	MPT_CONSTEXPR11_FUN bool IsUnsigned() const
+	{
+		return IsValid() && (value == SampleFormatUnsigned8);
+	}
+	MPT_CONSTEXPR11_FUN bool IsFloat() const
+	{
+		return IsValid() && (value == SampleFormatFloat32);
+	}
+	MPT_CONSTEXPR11_FUN bool IsInt() const
+	{
+		return IsValid() && (value != SampleFormatFloat32);
+	}
+	MPT_CONSTEXPR11_FUN uint8 GetBitsPerSample() const
+	{
+		return
+			!IsValid() ? 0 :
+			(value == SampleFormatUnsigned8) ?  8 :
+			(value == SampleFormatInt16)     ? 16 :
+			(value == SampleFormatInt24)     ? 24 :
+			(value == SampleFormatInt32)     ? 32 :
+			(value == SampleFormatFloat32)   ? 32 :
+			0;
+	}
+
+	// backward compatibility, conversion to/from integers
+	MPT_CONSTEXPR11_FUN operator int () const { return value; }
+	MPT_CONSTEXPR11_FUN SampleFormat(int v) : value(SampleFormatEnum(v)) { }
+	MPT_CONSTEXPR11_FUN operator long () const { return value; }
+	MPT_CONSTEXPR11_FUN SampleFormat(long v) : value(SampleFormatEnum(v)) { }
+	MPT_CONSTEXPR11_FUN operator unsigned int () const { return value; }
+	MPT_CONSTEXPR11_FUN SampleFormat(unsigned int v) : value(SampleFormatEnum(v)) { }
+	MPT_CONSTEXPR11_FUN operator unsigned long () const { return value; }
+	MPT_CONSTEXPR11_FUN SampleFormat(unsigned long v) : value(SampleFormatEnum(v)) { }
+};
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundbase/SampleFormatConverters.h b/soundbase/SampleFormatConverters.h
new file mode 100644
index 0000000..f6a9bba
--- /dev/null
+++ b/soundbase/SampleFormatConverters.h
@@ -0,0 +1,1199 @@
+/*
+ * SampleFormatConverters.h
+ * ------------------------
+ * Purpose: Functions and functors for reading and converting pretty much any uncompressed sample format supported by OpenMPT.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+
+#include "../common/Endianness.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+// Byte offsets, from lowest significant to highest significant byte (for various functor template parameters)
+#define littleEndian64 0, 1, 2, 3, 4, 5, 6, 7
+#define littleEndian32 0, 1, 2, 3
+#define littleEndian24 0, 1, 2
+#define littleEndian16 0, 1
+
+#define bigEndian64 7, 6, 5, 4, 3, 2, 1, 0
+#define bigEndian32 3, 2, 1, 0
+#define bigEndian24 2, 1, 0
+#define bigEndian16 1, 0
+
+
+namespace SC { // SC = _S_ample_C_onversion
+
+
+
+#if MPT_COMPILER_MSVC
+#if defined(_M_IX86) && !(defined(_M_X64)) && (_M_IX86_FP < 2)
+#define MPT_SC_AVOID_FLOOR 1
+#else
+#define MPT_SC_AVOID_FLOOR 0
+#endif
+#else
+#define MPT_SC_AVOID_FLOOR 0
+#endif
+
+
+
+#if MPT_COMPILER_SHIFT_SIGNED
+
+#define MPT_SC_RSHIFT_SIGNED(val, shift) ((val) >> (shift))
+#define MPT_SC_LSHIFT_SIGNED(val, shift) ((val) << (shift))
+
+#else
+
+//#define MPT_SC_USE_MULDIV
+
+#ifdef MPT_SC_USE_MULDIV
+
+// just use mul and div
+
+template <typename T>
+MPT_FORCEINLINE auto rshift_signed_muldiv(T x, int y) -> decltype(x >> y)
+{
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
+	typedef decltype(x >> y) result_type;
+	return x / (static_cast<result_type>(1) << y);
+}
+
+template <typename T>
+MPT_FORCEINLINE auto lshift_signed_muldiv(T x, int y) -> decltype(x << y)
+{
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
+	MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
+	typedef decltype(x << y) result_type;
+	return x * (static_cast<result_type>(1) << y);
+}
+
+#define MPT_SC_RSHIFT_SIGNED(val, shift) SC::rshift_signed_muldiv((val), (shift))
+#define MPT_SC_LSHIFT_SIGNED(val, shift) SC::lshift_signed_muldiv((val), (shift))
+
+#else
+
+#define MPT_SC_RSHIFT_SIGNED(val, shift) mpt::rshift_signed((val), (shift))
+#define MPT_SC_LSHIFT_SIGNED(val, shift) mpt::lshift_signed((val), (shift))
+
+#endif
+
+#endif
+
+
+
+// Every sample decoding functor has to typedef its input_t and output_t
+// and has to provide a static const input_inc member
+// which describes by how many input_t elements inBuf has to be incremented between invocations.
+// input_inc is normally 1 except when decoding e.g. bigger sample values
+// from multiple mpt::byte values.
+
+
+// decodes signed 7bit values stored as signed int8
+struct DecodeInt7
+{
+	typedef mpt::byte input_t;
+	typedef int8 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 1;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return Clamp(static_cast<int8>(*inBuf), static_cast<int8>(-64), static_cast<int8>(63)) * 2;
+	}
+};
+
+struct DecodeInt8
+{
+	typedef mpt::byte input_t;
+	typedef int8 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 1;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return static_cast<int8>(*inBuf);
+	}
+};
+
+struct DecodeUint8
+{
+	typedef mpt::byte input_t;
+	typedef int8 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 1;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return static_cast<int8>(int(static_cast<uint8>(*inBuf)) - 128);
+	}
+};
+
+struct DecodeInt8Delta
+{
+	typedef mpt::byte input_t;
+	typedef int8 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 1;
+	uint8 delta;
+	DecodeInt8Delta() : delta(0) { }
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		delta += static_cast<uint8>(*inBuf);
+		return static_cast<int8>(delta);
+	}
+};
+
+template <uint16 offset, size_t loByteIndex, size_t hiByteIndex>
+struct DecodeInt16
+{
+	typedef mpt::byte input_t;
+	typedef int16 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 2;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return (static_cast<uint8>(inBuf[loByteIndex]) | (static_cast<uint8>(inBuf[hiByteIndex]) << 8)) - offset;
+	}
+};
+
+template <size_t loByteIndex, size_t hiByteIndex>
+struct DecodeInt16Delta
+{
+	typedef mpt::byte input_t;
+	typedef int16 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 2;
+	uint16 delta;
+	DecodeInt16Delta() : delta(0) { }
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		delta += static_cast<uint8>(inBuf[loByteIndex]) | (static_cast<uint8>(inBuf[hiByteIndex]) << 8);
+		return static_cast<int16>(delta);
+	}
+};
+
+struct DecodeInt16Delta8
+{
+	typedef mpt::byte input_t;
+	typedef int16 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 2;
+	uint16 delta;
+	DecodeInt16Delta8() : delta(0) { }
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		delta += static_cast<uint8>(inBuf[0]);
+		int16 result = delta & 0xFF;
+		delta += static_cast<uint8>(inBuf[1]);
+		result |= (delta << 8);
+		return result;
+	}
+};
+
+template <uint32 offset, size_t loByteIndex, size_t midByteIndex, size_t hiByteIndex>
+struct DecodeInt24
+{
+	typedef mpt::byte input_t;
+	typedef int32 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 3;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return ((static_cast<uint8>(inBuf[loByteIndex]) << 8) | (static_cast<uint8>(inBuf[midByteIndex]) << 16) | (static_cast<uint8>(inBuf[hiByteIndex]) << 24)) - offset;
+	}
+};
+
+template <uint32 offset, size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex>
+struct DecodeInt32
+{
+	typedef mpt::byte input_t;
+	typedef int32 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 4;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return (static_cast<uint8>(inBuf[loLoByteIndex]) | (static_cast<uint8>(inBuf[loHiByteIndex]) << 8) | (static_cast<uint8>(inBuf[hiLoByteIndex]) << 16) | (static_cast<uint8>(inBuf[hiHiByteIndex]) << 24)) - offset;
+	}
+};
+
+template <uint64 offset, size_t b0, size_t b1, size_t b2, size_t b3, size_t b4, size_t b5, size_t b6, size_t b7>
+struct DecodeInt64
+{
+	typedef mpt::byte input_t;
+	typedef int64 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 8;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return (uint64(0)
+			| (static_cast<uint64>(uint8(inBuf[b0])) <<  0)
+			| (static_cast<uint64>(uint8(inBuf[b1])) <<  8)
+			| (static_cast<uint64>(uint8(inBuf[b2])) << 16)
+			| (static_cast<uint64>(uint8(inBuf[b3])) << 24)
+			| (static_cast<uint64>(uint8(inBuf[b4])) << 32)
+			| (static_cast<uint64>(uint8(inBuf[b5])) << 40)
+			| (static_cast<uint64>(uint8(inBuf[b6])) << 48)
+			| (static_cast<uint64>(uint8(inBuf[b7])) << 56)
+			) - offset;
+	}
+};
+
+template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex>
+struct DecodeFloat32
+{
+	typedef mpt::byte input_t;
+	typedef float32 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 4;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return IEEE754binary32LE(static_cast<uint8>(inBuf[loLoByteIndex]), static_cast<uint8>(inBuf[loHiByteIndex]), static_cast<uint8>(inBuf[hiLoByteIndex]), static_cast<uint8>(inBuf[hiHiByteIndex]));
+	}
+};
+
+template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex>
+struct DecodeScaledFloat32
+{
+	typedef mpt::byte input_t;
+	typedef float32 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 4;
+	float factor;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return factor * IEEE754binary32LE(static_cast<uint8>(inBuf[loLoByteIndex]), static_cast<uint8>(inBuf[loHiByteIndex]), static_cast<uint8>(inBuf[hiLoByteIndex]), static_cast<uint8>(inBuf[hiHiByteIndex]));
+	}
+	MPT_FORCEINLINE DecodeScaledFloat32(float scaleFactor)
+		: factor(scaleFactor)
+	{
+		return;
+	}
+};
+
+template <size_t b0, size_t b1, size_t b2, size_t b3, size_t b4, size_t b5, size_t b6, size_t b7>
+struct DecodeFloat64
+{
+	typedef mpt::byte input_t;
+	typedef float64 output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 8;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return IEEE754binary64LE(uint8(inBuf[b0]), uint8(inBuf[b1]), uint8(inBuf[b2]), uint8(inBuf[b3]), uint8(inBuf[b4]), uint8(inBuf[b5]), uint8(inBuf[b6]), uint8(inBuf[b7]));
+	}
+};
+
+template <typename Tsample>
+struct DecodeIdentity
+{
+	typedef Tsample input_t;
+	typedef Tsample output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = 1;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return *inBuf;
+	}
+};
+
+
+
+// Shift input_t down by shift and saturate to output_t.
+template <typename Tdst, typename Tsrc, int shift>
+struct ConvertShift
+{
+	typedef Tsrc input_t;
+	typedef Tdst output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return mpt::saturate_cast<output_t>(MPT_SC_RSHIFT_SIGNED(val, shift));
+	}
+};
+
+
+
+// Shift input_t up by shift and saturate to output_t.
+template <typename Tdst, typename Tsrc, int shift>
+struct ConvertShiftUp
+{
+	typedef Tsrc input_t;
+	typedef Tdst output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return mpt::saturate_cast<output_t>(MPT_SC_LSHIFT_SIGNED(val, shift));
+	}
+};
+
+
+
+
+// Every sample conversion functor has to typedef its input_t and output_t.
+// The input_t argument is taken by value because we only deal with per-single-sample conversions here.
+
+
+// straight forward type conversions, clamping when converting from floating point.
+template <typename Tdst, typename Tsrc>
+struct Convert;
+
+template <typename Tid>
+struct Convert<Tid, Tid>
+{
+	typedef Tid input_t;
+	typedef Tid output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val;
+	}
+};
+
+template <>
+struct Convert<int8, int16>
+{
+	typedef int16 input_t;
+	typedef int8 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int8>(MPT_SC_RSHIFT_SIGNED(val, 8));
+	}
+};
+
+template <>
+struct Convert<int8, int24>
+{
+	typedef int24 input_t;
+	typedef int8 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int8>(MPT_SC_RSHIFT_SIGNED(static_cast<int>(val), 16));
+	}
+};
+
+template <>
+struct Convert<int8, int32>
+{
+	typedef int32 input_t;
+	typedef int8 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int8>(MPT_SC_RSHIFT_SIGNED(val, 24));
+	}
+};
+
+template <>
+struct Convert<int8, int64>
+{
+	typedef int64 input_t;
+	typedef int8 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int8>(MPT_SC_RSHIFT_SIGNED(val, 56));
+	}
+};
+
+template <>
+struct Convert<int8, float32>
+{
+	typedef float32 input_t;
+	typedef int8 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0f, 1.0f);
+		val *= 128.0f;
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int8>(MPT_SC_RSHIFT_SIGNED(static_cast<int>(val * 2.0f + 1.0f), 1));
+#else
+		return mpt::saturate_cast<int8>(static_cast<int>(std::floor(val + 0.5f)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int16, int8>
+{
+	typedef int8 input_t;
+	typedef int16 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int16>(MPT_SC_LSHIFT_SIGNED(val, 8));
+	}
+};
+
+template <>
+struct Convert<int16, int24>
+{
+	typedef int24 input_t;
+	typedef int16 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int16>(MPT_SC_RSHIFT_SIGNED(static_cast<int>(val), 8));
+	}
+};
+
+template <>
+struct Convert<int16, int32>
+{
+	typedef int32 input_t;
+	typedef int16 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int16>(MPT_SC_RSHIFT_SIGNED(val, 16));
+	}
+};
+
+template <>
+struct Convert<int16, int64>
+{
+	typedef int64 input_t;
+	typedef int16 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int16>(MPT_SC_RSHIFT_SIGNED(val, 48));
+	}
+};
+
+template <>
+struct Convert<int16, float32>
+{
+	typedef float32 input_t;
+	typedef int16 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0f, 1.0f);
+		val *= 32768.0f;
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int16>(MPT_SC_RSHIFT_SIGNED(static_cast<int>(val * 2.0f + 1.0f), 1));
+#else
+		return mpt::saturate_cast<int16>(static_cast<int>(std::floor(val + 0.5f)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int8, double>
+{
+	typedef double input_t;
+	typedef int8 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0, 1.0);
+		val *= 128.0;
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int8>(MPT_SC_RSHIFT_SIGNED(static_cast<int>(val * 2.0 + 1.0), 1));
+#else
+		return mpt::saturate_cast<int8>(static_cast<int>(std::floor(val + 0.5)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int16, double>
+{
+	typedef double input_t;
+	typedef int16 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0, 1.0);
+		val *= 32768.0;
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int16>(MPT_SC_RSHIFT_SIGNED(static_cast<int>(val * 2.0 + 1.0), 1));
+#else
+		return mpt::saturate_cast<int16>(static_cast<int>(std::floor(val + 0.5)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int24, int8>
+{
+	typedef int8 input_t;
+	typedef int24 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int24>(MPT_SC_LSHIFT_SIGNED(val, 16));
+	}
+};
+
+template <>
+struct Convert<int24, int16>
+{
+	typedef int16 input_t;
+	typedef int24 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int24>(MPT_SC_LSHIFT_SIGNED(val, 8));
+	}
+};
+
+template <>
+struct Convert<int24, int32>
+{
+	typedef int32 input_t;
+	typedef int24 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int24>(MPT_SC_RSHIFT_SIGNED(val, 8));
+	}
+};
+
+template <>
+struct Convert<int24, int64>
+{
+	typedef int64 input_t;
+	typedef int24 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int24>(MPT_SC_RSHIFT_SIGNED(val, 40));
+	}
+};
+
+template <>
+struct Convert<int32, int8>
+{
+	typedef int8 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int32>(MPT_SC_LSHIFT_SIGNED(val, 24));
+	}
+};
+
+template <>
+struct Convert<int32, int16>
+{
+	typedef int16 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int32>(MPT_SC_LSHIFT_SIGNED(val, 16));
+	}
+};
+
+template <>
+struct Convert<int32, int24>
+{
+	typedef int24 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int32>(MPT_SC_LSHIFT_SIGNED(static_cast<int>(val), 8));
+	}
+};
+
+template <>
+struct Convert<int32, int64>
+{
+	typedef int64 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<int32>(MPT_SC_RSHIFT_SIGNED(val, 32));
+	}
+};
+
+template <>
+struct Convert<int32, float32>
+{
+	typedef float32 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0f, 1.0f);
+		val *= 2147483648.0f;
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int32>(MPT_SC_RSHIFT_SIGNED(static_cast<int64>(val * 2.0f + 1.0f), 1));
+#else
+		return mpt::saturate_cast<int32>(static_cast<int64>(std::floor(val + 0.5f)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int32, double>
+{
+	typedef double input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0, 1.0);
+		val *= 2147483648.0;
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int32>(MPT_SC_RSHIFT_SIGNED(static_cast<int64>(val * 2.0 + 1.0), 1));
+#else
+		return mpt::saturate_cast<int32>(static_cast<int64>(std::floor(val + 0.5)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int64, int8>
+{
+	typedef int8 input_t;
+	typedef int64 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return MPT_SC_LSHIFT_SIGNED(static_cast<int64>(val), 56);
+	}
+};
+
+template <>
+struct Convert<int64, int16>
+{
+	typedef int16 input_t;
+	typedef int64 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return MPT_SC_LSHIFT_SIGNED(static_cast<int64>(val), 48);
+	}
+};
+
+template <>
+struct Convert<int64, int24>
+{
+	typedef int24 input_t;
+	typedef int64 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return MPT_SC_LSHIFT_SIGNED(static_cast<int64>(val), 40);
+	}
+};
+
+template <>
+struct Convert<int64, int32>
+{
+	typedef int32 input_t;
+	typedef int64 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return MPT_SC_LSHIFT_SIGNED(static_cast<int64>(val), 32);
+	}
+};
+
+template <>
+struct Convert<int64, float32>
+{
+	typedef float32 input_t;
+	typedef int64 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0f, 1.0f);
+		val *= static_cast<float>(uint64(1)<<63);
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int64>(MPT_SC_RSHIFT_SIGNED(static_cast<int64>(val * 2.0f + 1.0f), 1));
+#else
+		return mpt::saturate_cast<int32>(static_cast<int64>(std::floor(val + 0.5f)));
+#endif
+	}
+};
+
+template <>
+struct Convert<int64, double>
+{
+	typedef double input_t;
+	typedef int64 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		Limit(val, -1.0, 1.0);
+		val *= static_cast<double>(uint64(1)<<63);
+#if MPT_SC_AVOID_FLOOR
+		// MSVC with x87 floating point math calls floor for the more intuitive version
+		return mpt::saturate_cast<int64>(MPT_SC_RSHIFT_SIGNED(static_cast<int64>(val * 2.0 + 1.0), 1));
+#else
+		return mpt::saturate_cast<int32>(static_cast<int64>(std::floor(val + 0.5)));
+#endif
+	}
+};
+
+template <>
+struct Convert<float32, int8>
+{
+	typedef int8 input_t;
+	typedef float32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1)<<7));
+	}
+};
+
+template <>
+struct Convert<float32, int16>
+{
+	typedef int16 input_t;
+	typedef float32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1)<<15));
+	}
+};
+
+template <>
+struct Convert<float32, int32>
+{
+	typedef int32 input_t;
+	typedef float32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1)<<31));
+	}
+};
+
+template <>
+struct Convert<float32, int64>
+{
+	typedef int64 input_t;
+	typedef float32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0f / static_cast<float>(static_cast<uint64>(1)<<63));
+	}
+};
+
+template <>
+struct Convert<double, int8>
+{
+	typedef int8 input_t;
+	typedef double output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1)<<7));
+	}
+};
+
+template <>
+struct Convert<double, int16>
+{
+	typedef int16 input_t;
+	typedef double output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1)<<15));
+	}
+};
+
+template <>
+struct Convert<double, int32>
+{
+	typedef int32 input_t;
+	typedef double output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1)<<31));
+	}
+};
+
+template <>
+struct Convert<double, int64>
+{
+	typedef int64 input_t;
+	typedef double output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * (1.0 / static_cast<double>(static_cast<uint64>(1)<<63));
+	}
+};
+
+template <>
+struct Convert<double, float>
+{
+	typedef float input_t;
+	typedef double output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val;
+	}
+};
+
+template <>
+struct Convert<float, double>
+{
+	typedef double input_t;
+	typedef float output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return static_cast<float>(val);
+	}
+};
+
+
+template <typename Tdst, typename Tsrc, int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint;
+
+template <int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint<uint8, int32, fractionalBits, clipOutput>
+{
+	typedef int32 input_t;
+	typedef uint8 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		val = MPT_SC_RSHIFT_SIGNED((val + (1<<(shiftBits-1))), shiftBits); // round
+		if(val < int8_min) val = int8_min;
+		if(val > int8_max) val = int8_max;
+		return static_cast<uint8>(val+0x80); // unsigned
+	}
+};
+
+template <int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint<int8, int32, fractionalBits, clipOutput>
+{
+	typedef int32 input_t;
+	typedef int8 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		val = MPT_SC_RSHIFT_SIGNED((val + (1<<(shiftBits-1))), shiftBits); // round
+		if(val < int8_min) val = int8_min;
+		if(val > int8_max) val = int8_max;
+		return static_cast<int8>(val);
+	}
+};
+
+template <int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint<int16, int32, fractionalBits, clipOutput>
+{
+	typedef int32 input_t;
+	typedef int16 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		val = MPT_SC_RSHIFT_SIGNED((val + (1<<(shiftBits-1))), shiftBits); // round
+		if(val < int16_min) val = int16_min;
+		if(val > int16_max) val = int16_max;
+		return static_cast<int16>(val);
+	}
+};
+
+template <int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint<int24, int32, fractionalBits, clipOutput>
+{
+	typedef int32 input_t;
+	typedef int24 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		val = MPT_SC_RSHIFT_SIGNED((val + (1<<(shiftBits-1))), shiftBits); // round
+		if(val < int24_min) val = int24_min;
+		if(val > int24_max) val = int24_max;
+		return static_cast<int24>(val);
+	}
+};
+
+template <int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint<int32, int32, fractionalBits, clipOutput>
+{
+	typedef int32 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		return static_cast<int32>(Clamp(val, static_cast<int>(-((1<<fractionalBits)-1)), static_cast<int>(1<<fractionalBits)-1)) << (sizeof(input_t)*8-1-fractionalBits);
+	}
+};
+
+template <int fractionalBits, bool clipOutput>
+struct ConvertFixedPoint<float32, int32, fractionalBits, clipOutput>
+{
+	typedef int32 input_t;
+	typedef float32 output_t;
+	const float factor;
+	MPT_FORCEINLINE ConvertFixedPoint()
+		: factor( 1.0f / static_cast<float>(1 << fractionalBits) )
+	{
+		return;
+	}
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		MPT_CONSTANT_IF(clipOutput)
+		{
+			float32 out = val * factor;
+			if(out < -1.0f) out = -1.0f;
+			if(out > 1.0f) out = 1.0f;
+			return out;
+		} else
+		{
+			return val * factor;
+		}
+	}
+};
+
+
+template <typename Tdst, typename Tsrc, int fractionalBits>
+struct ConvertToFixedPoint;
+
+template <int fractionalBits>
+struct ConvertToFixedPoint<int32, uint8, fractionalBits>
+{
+	typedef uint8 input_t;
+	typedef int32 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		return MPT_SC_LSHIFT_SIGNED(static_cast<output_t>(static_cast<int>(val)-0x80), shiftBits);
+	}
+};
+
+template <int fractionalBits>
+struct ConvertToFixedPoint<int32, int16, fractionalBits>
+{
+	typedef int16 input_t;
+	typedef int32 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		return MPT_SC_LSHIFT_SIGNED(static_cast<output_t>(val), shiftBits);
+	}
+};
+
+template <int fractionalBits>
+struct ConvertToFixedPoint<int32, int24, fractionalBits>
+{
+	typedef int24 input_t;
+	typedef int32 output_t;
+	static const int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
+		STATIC_ASSERT(shiftBits >= 1);
+		return MPT_SC_LSHIFT_SIGNED(static_cast<output_t>(val), shiftBits);
+	}
+};
+
+template <int fractionalBits>
+struct ConvertToFixedPoint<int32, int32, fractionalBits>
+{
+	typedef int32 input_t;
+	typedef int32 output_t;
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
+		return MPT_SC_RSHIFT_SIGNED(static_cast<output_t>(val), (sizeof(input_t)*8-1-fractionalBits));
+	}
+};
+
+template <int fractionalBits>
+struct ConvertToFixedPoint<int32, float32, fractionalBits>
+{
+	typedef float32 input_t;
+	typedef int32 output_t;
+	const float factor;
+	MPT_FORCEINLINE ConvertToFixedPoint()
+		: factor( static_cast<float>(1 << fractionalBits) )
+	{
+		return;
+	}
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
+		return mpt::saturate_cast<output_t>(std::floor(val * factor + 0.5f));
+	}
+};
+
+
+
+// Reads sample data with Func and passes it directly to Func2.
+// Func1::output_t and Func2::input_t must be identical
+template <typename Func2, typename Func1>
+struct ConversionChain
+{
+	typedef typename Func1::input_t input_t;
+	typedef typename Func2::output_t output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = Func1::input_inc;
+	Func1 func1;
+	Func2 func2;
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return func2(func1(inBuf));
+	}
+	MPT_FORCEINLINE ConversionChain(Func2 f2 = Func2(), Func1 f1 = Func1())
+		: func1(f1)
+		, func2(f2)
+	{
+		return;
+	}
+};
+
+
+
+
+template <typename Tsample>
+struct Normalize;
+
+template <>
+struct Normalize<int32>
+{
+	typedef int32 input_t;
+	typedef int32 output_t;
+	typedef uint32 peak_t;
+	uint32 maxVal;
+	MPT_FORCEINLINE Normalize() : maxVal(0) { }
+	MPT_FORCEINLINE void FindMax(input_t val)
+	{
+		if(val < 0)
+		{
+			if(val == int32_min)
+			{
+				maxVal = static_cast<uint32>(-static_cast<int64>(int32_min));
+				return;
+			}
+			val = -val;
+		}
+		if(static_cast<uint32>(val) > maxVal)
+		{
+			maxVal = static_cast<uint32>(val);
+		}
+	}
+	MPT_FORCEINLINE bool IsSilent() const
+	{
+		return maxVal == 0;
+	}
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return Util::muldivrfloor(val, static_cast<uint32>(1) << 31, maxVal);
+	}
+	MPT_FORCEINLINE peak_t GetSrcPeak() const
+	{
+		return maxVal;
+	}
+};
+
+template <>
+struct Normalize<float32>
+{
+	typedef float32 input_t;
+	typedef float32 output_t;
+	typedef float32 peak_t;
+	float maxVal;
+	float maxValInv;
+	MPT_FORCEINLINE Normalize() : maxVal(0.0f), maxValInv(1.0f) { }
+	MPT_FORCEINLINE void FindMax(input_t val)
+	{
+		float absval = std::fabs(val);
+		if(absval > maxVal)
+		{
+			maxVal = absval;
+		}
+	}
+	MPT_FORCEINLINE bool IsSilent()
+	{
+		if(maxVal == 0.0f)
+		{
+			maxValInv = 1.0f;
+			return true;
+		} else
+		{
+			maxValInv = 1.0f / maxVal;
+			return false;
+		}
+	}
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * maxValInv;
+	}
+	MPT_FORCEINLINE peak_t GetSrcPeak() const
+	{
+		return maxVal;
+	}
+};
+
+template <>
+struct Normalize<float64>
+{
+	typedef float64 input_t;
+	typedef float64 output_t;
+	typedef float64 peak_t;
+	double maxVal;
+	double maxValInv;
+	MPT_FORCEINLINE Normalize() : maxVal(0.0), maxValInv(1.0) { }
+	MPT_FORCEINLINE void FindMax(input_t val)
+	{
+		double absval = std::fabs(val);
+		if(absval > maxVal)
+		{
+			maxVal = absval;
+		}
+	}
+	MPT_FORCEINLINE bool IsSilent()
+	{
+		if(maxVal == 0.0)
+		{
+			maxValInv = 1.0;
+			return true;
+		} else
+		{
+			maxValInv = 1.0 / maxVal;
+			return false;
+		}
+	}
+	MPT_FORCEINLINE output_t operator() (input_t val)
+	{
+		return val * maxValInv;
+	}
+	MPT_FORCEINLINE peak_t GetSrcPeak() const
+	{
+		return maxVal;
+	}
+};
+
+
+// Reads sample data with Func1, then normalizes the sample data, and then converts it with Func2.
+// Func1::output_t and Func2::input_t must be identical.
+// Func1 can also be the identity decode (DecodeIdentity<T>).
+// Func2 can also be the identity conversion (Convert<T,T>).
+template <typename Func2, typename Func1>
+struct NormalizationChain
+{
+	typedef typename Func1::input_t input_t;
+	typedef typename Func1::output_t normalize_t;
+	typedef typename Normalize<normalize_t>::peak_t peak_t;
+	typedef typename Func2::output_t output_t;
+	static MPT_CONSTEXPR11_VAR std::size_t input_inc = Func1::input_inc;
+	Func1 func1;
+	Normalize<normalize_t> normalize;
+	Func2 func2;
+	MPT_FORCEINLINE void FindMax(const input_t *inBuf)
+	{
+		normalize.FindMax(func1(inBuf));
+	}
+	MPT_FORCEINLINE bool IsSilent()
+	{
+		return normalize.IsSilent();
+	}
+	MPT_FORCEINLINE output_t operator() (const input_t *inBuf)
+	{
+		return func2(normalize(func1(inBuf)));
+	}
+	MPT_FORCEINLINE peak_t GetSrcPeak() const
+	{
+		return normalize.GetSrcPeak();
+	}
+	MPT_FORCEINLINE NormalizationChain(Func2 f2 = Func2(), Func1 f1 = Func1())
+		: func1(f1)
+		, func2(f2)
+	{
+		return;
+	}
+};
+
+
+
+#undef MPT_SC_RSHIFT_SIGNED
+#undef MPT_SC_LSHIFT_SIGNED
+
+
+
+} // namespace SC
+
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundbase/SampleFormatCopy.h b/soundbase/SampleFormatCopy.h
new file mode 100644
index 0000000..958385d
--- /dev/null
+++ b/soundbase/SampleFormatCopy.h
@@ -0,0 +1,135 @@
+/*
+ * SampleFormatCopy.h
+ * ------------------
+ * Purpose: Functions for copying sample data.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+
+#include "../common/Endianness.h"
+#include "SampleFormatConverters.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+//////////////////////////////////////////////////////
+// Actual sample conversion functions
+
+// Copy a sample data buffer.
+// targetBuffer: Buffer in which the sample should be copied into.
+// numSamples: Number of samples of size T that should be copied. targetBuffer is expected to be able to hold "numSamples * incTarget" samples.
+// incTarget: Number of samples by which the target data pointer is increased each time.
+// sourceBuffer: Buffer from which the samples should be read.
+// sourceSize: Size of source buffer, in bytes.
+// incSource: Number of samples by which the source data pointer is increased each time.
+//
+// Template arguments:
+// SampleConversion: Functor of type SampleConversionFunctor to apply sample conversion (see above for existing functors).
+template <typename SampleConversion>
+size_t CopySample(typename SampleConversion::output_t * MPT_RESTRICT outBuf, size_t numSamples, size_t incTarget, const typename SampleConversion::input_t * MPT_RESTRICT inBuf, size_t sourceSize, size_t incSource, SampleConversion conv = SampleConversion())
+{
+	const size_t sampleSize = incSource * SampleConversion::input_inc * sizeof(typename SampleConversion::input_t);
+	LimitMax(numSamples, sourceSize / sampleSize);
+	const size_t copySize = numSamples * sampleSize;
+
+	SampleConversion sampleConv(conv);
+	while(numSamples--)
+	{
+		*outBuf = sampleConv(inBuf);
+		outBuf += incTarget;
+		inBuf += incSource * SampleConversion::input_inc;
+	}
+
+	return copySize;
+}
+
+
+// Copy numChannels interleaved sample streams.
+template <typename SampleConversion>
+void CopyInterleavedSampleStreams(typename SampleConversion::output_t * MPT_RESTRICT outBuf, const typename SampleConversion::input_t * MPT_RESTRICT inBuf, size_t numFrames, size_t numChannels, SampleConversion *conv)
+{
+	while(numFrames--)
+	{
+		for(size_t channel = 0; channel < numChannels; ++channel)
+		{
+			*outBuf = conv[channel](*inBuf);
+			inBuf++;
+			outBuf++;
+		}
+	}
+}
+
+
+// Copy numChannels interleaved sample streams.
+template <typename SampleConversion>
+void CopyInterleavedSampleStreams(typename SampleConversion::output_t * MPT_RESTRICT outBuf, const typename SampleConversion::input_t * MPT_RESTRICT inBuf, size_t numFrames, size_t numChannels, std::vector<SampleConversion> &conv)
+{
+	MPT_ASSERT(conv.size() >= numChannels);
+	CopyInterleavedSampleStreams(outBuf, inBuf, numFrames, numChannels, &(conv[0]));
+}
+
+
+
+template<int fractionalBits, bool clipOutput, typename Tsample, typename Tfixed>
+void ConvertInterleavedFixedPointToInterleaved(Tsample * MPT_RESTRICT p, const Tfixed * MPT_RESTRICT mixbuffer, std::size_t channels, std::size_t count)
+{
+	SC::ConvertFixedPoint<Tsample, int, fractionalBits, clipOutput> conv;
+	count *= channels;
+	for(std::size_t i = 0; i < count; ++i)
+	{
+		p[i] = conv(mixbuffer[i]);
+	}
+}
+
+template<int fractionalBits, bool clipOutput, typename Tsample, typename Tfixed>
+void ConvertInterleavedFixedPointToNonInterleaved(Tsample * const * const MPT_RESTRICT buffers, const Tfixed * MPT_RESTRICT mixbuffer, std::size_t channels, std::size_t count)
+{
+	SC::ConvertFixedPoint<Tsample, int, fractionalBits, clipOutput> conv;
+	for(std::size_t i = 0; i < count; ++i)
+	{
+		for(std::size_t channel = 0; channel < channels; ++channel)
+		{
+			buffers[channel][i] = conv(*mixbuffer);
+			mixbuffer++;
+		}
+	}
+}
+
+
+// Copy from an interleaed buffer of #channels.
+template <typename SampleConversion>
+void CopyInterleavedToChannel(typename SampleConversion::output_t * MPT_RESTRICT dst, const typename SampleConversion::input_t * MPT_RESTRICT src, std::size_t channels, std::size_t countChunk, std::size_t channel, SampleConversion conv = SampleConversion())
+{
+	SampleConversion sampleConv(conv);
+	src += channel;
+	for(std::size_t i = 0; i < countChunk; ++i)
+	{
+		*dst = sampleConv(*src);
+		src += channels;
+		dst++;
+	}
+}
+
+
+// Copy buffer to an interleaed buffer of #channels.
+template <typename SampleConversion>
+void CopyChannelToInterleaved(typename SampleConversion::output_t * MPT_RESTRICT dst, const typename SampleConversion::input_t * MPT_RESTRICT src, std::size_t channels, std::size_t countChunk, std::size_t channel, SampleConversion conv = SampleConversion())
+{
+	SampleConversion sampleConv(conv);
+	dst += channel;
+	for(std::size_t i = 0; i < countChunk; ++i)
+	{
+		*dst = sampleConv(*src);
+		src++;
+		dst += channels;
+	}
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/AGC.cpp b/sounddsp/AGC.cpp
new file mode 100644
index 0000000..5051c57
--- /dev/null
+++ b/sounddsp/AGC.cpp
@@ -0,0 +1,142 @@
+/*
+ * AGC.cpp
+ * -------
+ * Purpose: Automatic Gain Control
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "../soundlib/Sndfile.h"
+#include "../sounddsp/AGC.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+	
+//////////////////////////////////////////////////////////////////////////////////
+// Automatic Gain Control
+
+#ifndef NO_AGC
+
+#define AGC_PRECISION		10
+#define AGC_UNITY			(1 << AGC_PRECISION)
+
+// Limiter
+#define MIXING_LIMITMAX		(0x08100000)
+#define MIXING_LIMITMIN		(-MIXING_LIMITMAX)
+
+
+static UINT ProcessAGC(int *pBuffer, int *pRearBuffer, std::size_t nSamples, std::size_t nChannels, int nAGC)
+{
+	if(nChannels == 1)
+	{
+		while(nSamples--)
+		{
+			int val = (int)(((int64)*pBuffer * (int32)nAGC) >> AGC_PRECISION);
+			if(val < MIXING_LIMITMIN || val > MIXING_LIMITMAX) nAGC--;
+			*pBuffer = val;
+			pBuffer++;
+		}
+	} else
+	{
+		if(nChannels == 2)
+		{
+			while(nSamples--)
+			{
+				int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
+				int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
+				bool dec = false;
+				dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX);
+				dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX);
+				if(dec) nAGC--;
+				pBuffer[0] = fl;
+				pBuffer[1] = fr;
+				pBuffer += 2;
+			}
+		} else if(nChannels == 4)
+		{
+			while(nSamples--)
+			{
+				int fl = (int)(((int64)pBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
+				int fr = (int)(((int64)pBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
+				int rl = (int)(((int64)pRearBuffer[0] * (int32)nAGC) >> AGC_PRECISION);
+				int rr = (int)(((int64)pRearBuffer[1] * (int32)nAGC) >> AGC_PRECISION);
+				bool dec = false;
+				dec = dec || (fl < MIXING_LIMITMIN || fl > MIXING_LIMITMAX);
+				dec = dec || (fr < MIXING_LIMITMIN || fr > MIXING_LIMITMAX);
+				dec = dec || (rl < MIXING_LIMITMIN || rl > MIXING_LIMITMAX);
+				dec = dec || (rr < MIXING_LIMITMIN || rr > MIXING_LIMITMAX);
+				if(dec) nAGC--;
+				pBuffer[0] = fl;
+				pBuffer[1] = fr;
+				pRearBuffer[0] = rl;
+				pRearBuffer[1] = rr;
+				pBuffer += 2;
+				pRearBuffer += 2;
+			}
+		}
+	}
+	return nAGC;
+}
+
+
+CAGC::CAGC()
+{
+	Initialize(true, 44100);
+}
+
+
+void CAGC::Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels)
+{
+	UINT agc = ProcessAGC(MixSoundBuffer, RearSoundBuffer, count, nChannels, m_nAGC);
+	// Some kind custom law, so that the AGC stays quite stable, but slowly
+	// goes back up if the sound level stays below a level inversely proportional
+	// to the AGC level. (J'me comprends)
+	if((agc >= m_nAGC) && (m_nAGC < AGC_UNITY))
+	{
+		m_nAGCRecoverCount += count;
+		if(m_nAGCRecoverCount >= m_Timeout)
+		{
+			m_nAGCRecoverCount = 0;
+			m_nAGC++;
+		}
+	} else
+	{
+		m_nAGC = agc;
+		m_nAGCRecoverCount = 0;
+	}
+}
+
+
+void CAGC::Adjust(UINT oldVol, UINT newVol)
+{
+	m_nAGC = m_nAGC * oldVol / newVol;
+	if (m_nAGC > AGC_UNITY) m_nAGC = AGC_UNITY;
+}
+
+
+void CAGC::Initialize(bool bReset, DWORD MixingFreq)
+{
+	if(bReset)
+	{
+		m_nAGC = AGC_UNITY;
+		m_nAGCRecoverCount = 0;
+	}
+	m_Timeout = (MixingFreq >> (AGC_PRECISION-8)) >> 1;
+}
+
+
+#else
+
+
+MPT_MSVC_WORKAROUND_LNK4221(AGC)
+
+
+#endif // NO_AGC
+
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/AGC.h b/sounddsp/AGC.h
new file mode 100644
index 0000000..4c50ea6
--- /dev/null
+++ b/sounddsp/AGC.h
@@ -0,0 +1,36 @@
+/*
+ * AGC.h
+ * -----
+ * Purpose: Automatic Gain Control
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifndef NO_AGC
+
+class CAGC
+{
+private:
+	UINT m_nAGC;
+	std::size_t m_nAGCRecoverCount;
+	UINT m_Timeout;
+public:
+	CAGC();
+	void Initialize(bool bReset, DWORD MixingFreq);
+public:
+	void Process(int *MixSoundBuffer, int *RearSoundBuffer, std::size_t count, std::size_t nChannels);
+	void Adjust(UINT oldVol, UINT newVol);
+};
+
+#endif // NO_AGC
+
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/DSP.cpp b/sounddsp/DSP.cpp
new file mode 100644
index 0000000..b9103c3
--- /dev/null
+++ b/sounddsp/DSP.cpp
@@ -0,0 +1,431 @@
+/*
+ * DSP.cpp
+ * -----------
+ * Purpose: Mixing code for various DSPs (EQ, Mega-Bass, ...)
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "../soundlib/Sndfile.h"
+#include "../sounddsp/DSP.h"
+#include <math.h>
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifndef NO_DSP
+
+
+// Bass Expansion
+#define DEFAULT_XBASS_RANGE		14	// (x+2)*20 Hz (320Hz)
+#define DEFAULT_XBASS_DEPTH		6	// 1+(3>>(x-4)) (+6dB)
+
+
+////////////////////////////////////////////////////////////////////
+// DSP Effects internal state
+
+static void X86_StereoDCRemoval(int *, uint32 count, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l, int32 &nDCRFlt_Y1r, int32 &nDCRFlt_X1r);
+static void X86_MonoDCRemoval(int *, uint32 count, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l);
+
+///////////////////////////////////////////////////////////////////////////////////
+//
+// Biquad setup
+//
+
+
+#define PI	3.14159265358979323f
+static inline float Sgn(float x) { return (x >= 0) ? 1.0f : -1.0f; }
+static void ShelfEQ(int32 scale,
+	int32 &outA1, int32 &outB0, int32 &outB1,
+	int32 F_c, int32 F_s, float gainDC, float gainFT, float gainPI)
+{
+	float a1, b0, b1;
+	float gainFT2, gainDC2, gainPI2;
+	float alpha, beta0, beta1, rho;
+	float wT, quad;
+
+	wT = PI * F_c / F_s;
+	gainPI2 = gainPI * gainPI;
+	gainFT2 = gainFT * gainFT;
+	gainDC2 = gainDC * gainDC;
+
+	quad = gainPI2 + gainDC2 - (gainFT2*2);
+
+	alpha = 0;
+
+	if (quad != 0)
+	{
+		float lambda = (gainPI2 - gainDC2) / quad;
+		alpha  = (float)(lambda - Sgn(lambda)*sqrt(lambda*lambda - 1.0f));
+	}
+
+	beta0 = 0.5f * ((gainDC + gainPI) + (gainDC - gainPI) * alpha);
+	beta1 = 0.5f * ((gainDC - gainPI) + (gainDC + gainPI) * alpha);
+	rho   = (float)((sin((wT*0.5f) - (PI/4.0f))) / (sin((wT*0.5f) + (PI/4.0f))));
+
+	quad  = 1.0f / (1.0f + rho*alpha);
+
+	b0 = ((beta0 + rho*beta1) * quad);
+	b1 = ((beta1 + rho*beta0) * quad);
+	a1 = - ((rho + alpha) * quad);
+
+	outA1 = Util::Round<int32>(a1 * scale);
+	outB0 = Util::Round<int32>(b0 * scale);
+	outB1 = Util::Round<int32>(b1 * scale);
+}
+
+
+CSurroundSettings::CSurroundSettings() : m_nProLogicDepth(12), m_nProLogicDelay(20)
+{
+
+}
+
+
+CMegaBassSettings::CMegaBassSettings() : m_nXBassDepth(DEFAULT_XBASS_DEPTH), m_nXBassRange(DEFAULT_XBASS_RANGE)
+{
+
+}
+
+
+CSurround::CSurround()
+{
+	// Surround Encoding: 1 delay line + low-pass filter + high-pass filter
+	nSurroundSize = 0;
+	nSurroundPos = 0;
+	nDolbyDepth = 0;
+
+	// Surround Biquads
+	nDolbyHP_Y1 = 0;
+	nDolbyHP_X1 = 0;
+	nDolbyLP_Y1 = 0;
+	nDolbyHP_B0 = 0;
+	nDolbyHP_B1 = 0;
+	nDolbyHP_A1 = 0;
+	nDolbyLP_B0 = 0;
+	nDolbyLP_B1 = 0;
+	nDolbyLP_A1 = 0;
+
+	MemsetZero(SurroundBuffer);
+
+}
+
+
+CMegaBass::CMegaBass()
+{
+
+	// Bass Expansion: low-pass filter
+	nXBassFlt_Y1 = 0;
+	nXBassFlt_X1 = 0;
+	nXBassFlt_B0 = 0;
+	nXBassFlt_B1 = 0;
+	nXBassFlt_A1 = 0;
+
+	// DC Removal Biquad
+	nDCRFlt_Y1lf = 0;
+	nDCRFlt_X1lf = 0;
+	nDCRFlt_Y1rf = 0;
+	nDCRFlt_X1rf = 0;
+	nDCRFlt_Y1lb = 0;
+	nDCRFlt_X1lb = 0;
+	nDCRFlt_Y1rb = 0;
+	nDCRFlt_X1rb = 0;
+
+}
+
+
+void CSurround::Initialize(bool bReset, DWORD MixingFreq)
+{
+	MPT_UNREFERENCED_PARAMETER(bReset);
+	if (!m_Settings.m_nProLogicDelay) m_Settings.m_nProLogicDelay = 20;
+
+	// Pro-Logic Surround
+	nSurroundPos = nSurroundSize = 0;
+	{
+		memset(SurroundBuffer, 0, sizeof(SurroundBuffer));
+		nSurroundSize = (MixingFreq * m_Settings.m_nProLogicDelay) / 1000;
+		if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE;
+		nDolbyDepth = m_Settings.m_nProLogicDepth;
+		if (nDolbyDepth < 1) nDolbyDepth = 1;
+		if (nDolbyDepth > 16) nDolbyDepth = 16;
+		// Setup biquad filters
+		ShelfEQ(1024, nDolbyHP_A1, nDolbyHP_B0, nDolbyHP_B1, 200, MixingFreq, 0, 0.5f, 1);
+		ShelfEQ(1024, nDolbyLP_A1, nDolbyLP_B0, nDolbyLP_B1, 7000, MixingFreq, 1, 0.75f, 0);
+		nDolbyHP_X1 = nDolbyHP_Y1 = 0;
+		nDolbyLP_Y1 = 0;
+		// Surround Level
+		nDolbyHP_B0 = (nDolbyHP_B0 * nDolbyDepth) >> 5;
+		nDolbyHP_B1 = (nDolbyHP_B1 * nDolbyDepth) >> 5;
+		// +6dB
+		nDolbyLP_B0 *= 2;
+		nDolbyLP_B1 *= 2;
+	}
+}
+
+
+void CMegaBass::Initialize(bool bReset, DWORD MixingFreq)
+{
+	// Bass Expansion Reset
+	{
+		int32 a1 = 0, b0 = 1024, b1 = 0;
+		int nXBassCutOff = 50 + (m_Settings.m_nXBassRange+2) * 20;
+		int nXBassGain = m_Settings.m_nXBassDepth;
+		nXBassGain = mpt::clamp(nXBassGain, 2, 8);
+		nXBassCutOff = mpt::clamp(nXBassCutOff, 60, 600);
+		ShelfEQ(1024, a1, b0, b1, nXBassCutOff, MixingFreq,
+				1.0f + (1.0f/16.0f) * (0x300 >> nXBassGain),
+				1.0f,
+				0.0000001f);
+		if (nXBassGain > 5)
+		{
+			b0 >>= (nXBassGain-5);
+			b1 >>= (nXBassGain-5);
+		}
+		nXBassFlt_A1 = a1;
+		nXBassFlt_B0 = b0;
+		nXBassFlt_B1 = b1;
+		//Log("b0=%d b1=%d a1=%d\n", b0, b1, a1);
+	}
+	if (bReset)
+	{
+		nXBassFlt_X1 = 0;
+		nXBassFlt_Y1 = 0;
+		nDCRFlt_X1lf = 0;
+		nDCRFlt_X1rf = 0;
+		nDCRFlt_Y1lf = 0;
+		nDCRFlt_Y1rf = 0;
+		nDCRFlt_X1lb = 0;
+		nDCRFlt_X1rb = 0;
+		nDCRFlt_Y1lb = 0;
+		nDCRFlt_Y1rb = 0;
+	}
+}
+
+
+// 2-channel surround
+void CSurround::ProcessStereoSurround(int * MixSoundBuffer, int count)
+{
+	int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1;
+	for (int r=count; r; r--)
+	{
+		// Delay
+		int secho = SurroundBuffer[nSurroundPos];
+		SurroundBuffer[nSurroundPos] = (pr[0]+pr[1]+256) >> 9;
+		// High-pass
+		int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10;
+		nDolbyHP_X1 = secho;
+		// Low-pass
+		int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8);
+		hy1 = v0;
+		nDolbyLP_Y1 = v >> 8;
+		// Add echo
+		pr[0] += v;
+		pr[1] -= v;
+		if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0;
+		pr += 2;
+	}
+	nDolbyHP_Y1 = hy1;
+}
+
+
+// 4-channels surround
+void CSurround::ProcessQuadSurround(int * MixSoundBuffer, int * MixRearBuffer, int count)
+{
+	int *pr = MixSoundBuffer, hy1 = nDolbyHP_Y1;
+	for (int r=count; r; r--)
+	{
+		int vl = pr[0] >> 1;
+		int vr = pr[1] >> 1;
+		pr[(uint32)(MixRearBuffer-MixSoundBuffer)] += vl;
+		pr[((uint32)(MixRearBuffer-MixSoundBuffer))+1] += vr;
+		// Delay
+		int secho = SurroundBuffer[nSurroundPos];
+		SurroundBuffer[nSurroundPos] = (vr+vl+256) >> 9;
+		// High-pass
+		int v0 = (nDolbyHP_B0 * secho + nDolbyHP_B1 * nDolbyHP_X1 + nDolbyHP_A1 * hy1) >> 10;
+		nDolbyHP_X1 = secho;
+		// Low-pass
+		int v = (nDolbyLP_B0 * v0 + nDolbyLP_B1 * hy1 + nDolbyLP_A1 * nDolbyLP_Y1) >> (10-8);
+		hy1 = v0;
+		nDolbyLP_Y1 = v >> 8;
+		// Add echo
+		pr[(uint32)(MixRearBuffer-MixSoundBuffer)] += v;
+		pr[((uint32)(MixRearBuffer-MixSoundBuffer))+1] += v;
+		if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0;
+		pr += 2;
+	}
+	nDolbyHP_Y1 = hy1;
+}
+
+
+void CSurround::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels)
+{
+
+	if(nChannels >= 2)
+
+	// Dolby Pro-Logic Surround
+	{
+		if (nChannels > 2) ProcessQuadSurround(MixSoundBuffer, MixRearBuffer, count); else
+		ProcessStereoSurround(MixSoundBuffer, count);
+	}
+
+}
+
+
+void CMegaBass::Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels)
+{
+
+	if(nChannels >= 2)
+	{
+		X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf, nDCRFlt_Y1rf, nDCRFlt_X1rf);
+		if(nChannels > 2) X86_StereoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lb, nDCRFlt_X1lb, nDCRFlt_Y1rb, nDCRFlt_X1rb);
+		int *px = MixSoundBuffer;
+		int *py = MixRearBuffer;
+		int x1 = nXBassFlt_X1;
+		int y1 = nXBassFlt_Y1;
+		if(nChannels > 2) for (int x=count; x; x--)
+		{
+			int x_m = (px[0]+px[1]+py[0]+py[1]+0x100)>>9;
+
+			y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8);
+			x1 = x_m;
+			px[0] += y1;
+			px[1] += y1;
+			py[0] += y1;
+			py[1] += y1;
+			y1 = (y1+0x80) >> 8;
+			px += 2;
+			py += 2;
+		} else for (int x=count; x; x--)
+		{
+			int x_m = (px[0]+px[1]+0x100)>>9;
+
+			y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8);
+			x1 = x_m;
+			px[0] += y1;
+			px[1] += y1;
+			y1 = (y1+0x80) >> 8;
+			px += 2;
+		}
+		nXBassFlt_X1 = x1;
+		nXBassFlt_Y1 = y1;
+	} else
+	{
+		X86_MonoDCRemoval(MixSoundBuffer, count, nDCRFlt_Y1lf, nDCRFlt_X1lf);
+		int *px = MixSoundBuffer;
+		int x1 = nXBassFlt_X1;
+		int y1 = nXBassFlt_Y1;
+		for (int x=count; x; x--)
+		{
+			int x_m = (px[0]+0x80)>>8;
+
+			y1 = (nXBassFlt_B0 * x_m + nXBassFlt_B1 * x1 + nXBassFlt_A1 * y1) >> (10-8);
+			x1 = x_m;
+			px[0] += y1;
+			y1 = (y1+0x40) >> 8;
+			px++;
+		}
+		nXBassFlt_X1 = x1;
+		nXBassFlt_Y1 = y1;
+	}
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// DC Removal
+//
+
+#define DCR_AMOUNT		9
+
+static void X86_StereoDCRemoval(int *pBuffer, uint32 nSamples, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l, int32 &nDCRFlt_Y1r, int32 &nDCRFlt_X1r)
+{
+	int y1l = nDCRFlt_Y1l, x1l = nDCRFlt_X1l;
+	int y1r = nDCRFlt_Y1r, x1r = nDCRFlt_X1r;
+
+	while(nSamples--)
+	{
+		int inL = pBuffer[0];
+		int inR = pBuffer[1];
+		int diffL = x1l - inL;
+		int diffR = x1r - inR;
+		x1l = inL;
+		x1r = inR;
+		int outL = diffL / (1 << (DCR_AMOUNT + 1)) - diffL + y1l;
+		int outR = diffR / (1 << (DCR_AMOUNT + 1)) - diffR + y1r;
+		pBuffer[0] = outL;
+		pBuffer[1] = outR;
+		pBuffer += 2;
+		y1l = outL - outL / (1 << DCR_AMOUNT);
+		y1r = outR - outR / (1 << DCR_AMOUNT);
+	}
+
+	nDCRFlt_Y1l = y1l;
+	nDCRFlt_X1l = x1l;
+	nDCRFlt_Y1r = y1r;
+	nDCRFlt_X1r = x1r;
+}
+
+
+static void X86_MonoDCRemoval(int *pBuffer, uint32 nSamples, int32 &nDCRFlt_Y1l, int32 &nDCRFlt_X1l)
+{
+	int y1l = nDCRFlt_Y1l, x1l = nDCRFlt_X1l;
+	while(nSamples--)
+	{
+		int inM = pBuffer[0];
+		int diff = x1l - inM;
+		x1l = inM;
+		pBuffer[0] = inM = diff / (1 << (DCR_AMOUNT + 1)) - diff + y1l;
+		pBuffer++;
+		y1l = inM - inM / (1 << DCR_AMOUNT);
+	}
+
+	nDCRFlt_Y1l = y1l;
+	nDCRFlt_X1l = x1l;
+}
+
+
+/////////////////////////////////////////////////////////////////
+// Clean DSP Effects interface
+
+// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100]
+void CMegaBass::SetXBassParameters(uint32 nDepth, uint32 nRange)
+{
+	if (nDepth > 100) nDepth = 100;
+	uint32 gain = nDepth / 20;
+	if (gain > 4) gain = 4;
+	m_Settings.m_nXBassDepth = 8 - gain;	// filter attenuation 1/256 .. 1/16
+	uint32 range = nRange / 5;
+	if (range > 5) range -= 5; else range = 0;
+	if (nRange > 16) nRange = 16;
+	m_Settings.m_nXBassRange = 21 - range;	// filter average on 0.5-1.6ms
+}
+
+
+// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms]
+void CSurround::SetSurroundParameters(uint32 nDepth, uint32 nDelay)
+{
+	uint32 gain = (nDepth * 16) / 100;
+	if (gain > 16) gain = 16;
+	if (gain < 1) gain = 1;
+	m_Settings.m_nProLogicDepth = gain;
+	if (nDelay < 4) nDelay = 4;
+	if (nDelay > 50) nDelay = 50;
+	m_Settings.m_nProLogicDelay = nDelay;
+}
+
+
+#else
+
+
+MPT_MSVC_WORKAROUND_LNK4221(DSP)
+
+
+#endif // NO_DSP
+
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/DSP.h b/sounddsp/DSP.h
new file mode 100644
index 0000000..0b9361d
--- /dev/null
+++ b/sounddsp/DSP.h
@@ -0,0 +1,120 @@
+/*
+ * DSP.h
+ * -----
+ * Purpose: Mixing code for various DSPs (EQ, Mega-Bass, ...)
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifndef NO_DSP
+
+// Buffer Sizes
+#define SURROUNDBUFFERSIZE		2048	// 50ms @ 48kHz
+
+
+class CSurroundSettings
+{
+public:
+	uint32 m_nProLogicDepth;
+	uint32 m_nProLogicDelay;
+public:
+	CSurroundSettings();
+};
+
+
+class CMegaBassSettings
+{
+public:
+	uint32 m_nXBassDepth;
+	uint32 m_nXBassRange;
+public:
+	CMegaBassSettings();
+};
+
+
+class CSurround
+{
+public:
+	CSurroundSettings m_Settings;
+
+	// Surround Encoding: 1 delay line + low-pass filter + high-pass filter
+	int32 nSurroundSize;
+	int32 nSurroundPos;
+	int32 nDolbyDepth;
+
+	// Surround Biquads
+	int32 nDolbyHP_Y1;
+	int32 nDolbyHP_X1;
+	int32 nDolbyLP_Y1;
+	int32 nDolbyHP_B0;
+	int32 nDolbyHP_B1;
+	int32 nDolbyHP_A1;
+	int32 nDolbyLP_B0;
+	int32 nDolbyLP_B1;
+	int32 nDolbyLP_A1;
+
+	int32 SurroundBuffer[SURROUNDBUFFERSIZE];
+
+public:
+	CSurround();
+public:
+	void SetSettings(const CSurroundSettings &settings) { m_Settings = settings; }
+	// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100]
+	bool SetXBassParameters(uint32 nDepth, uint32 nRange);
+	// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-40ms]
+	void SetSurroundParameters(uint32 nDepth, uint32 nDelay);
+	void Initialize(bool bReset, DWORD MixingFreq);
+	void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels);
+private:
+	void ProcessStereoSurround(int * MixSoundBuffer, int count);
+	void ProcessQuadSurround(int * MixSoundBuffer, int * MixRearBuffer, int count);
+};
+
+
+
+class CMegaBass
+{
+public:
+	CMegaBassSettings m_Settings;
+
+	// Bass Expansion: low-pass filter
+	int32 nXBassFlt_Y1;
+	int32 nXBassFlt_X1;
+	int32 nXBassFlt_B0;
+	int32 nXBassFlt_B1;
+	int32 nXBassFlt_A1;
+
+	// DC Removal Biquad
+	int32 nDCRFlt_Y1lf;
+	int32 nDCRFlt_X1lf;
+	int32 nDCRFlt_Y1rf;
+	int32 nDCRFlt_X1rf;
+	int32 nDCRFlt_Y1lb;
+	int32 nDCRFlt_X1lb;
+	int32 nDCRFlt_Y1rb;
+	int32 nDCRFlt_X1rb;
+
+public:
+	CMegaBass();
+public:
+	void SetSettings(const CMegaBassSettings &settings) { m_Settings = settings; }
+	// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 10-100]
+	void SetXBassParameters(uint32 nDepth, uint32 nRange);
+	void Initialize(bool bReset, DWORD MixingFreq);
+	void Process(int * MixSoundBuffer, int * MixRearBuffer, int count, uint32 nChannels);
+};
+
+
+#endif // NO_DSP
+
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/EQ.cpp b/sounddsp/EQ.cpp
new file mode 100644
index 0000000..9a998d5
--- /dev/null
+++ b/sounddsp/EQ.cpp
@@ -0,0 +1,557 @@
+/*
+ * EQ.cpp
+ * ------
+ * Purpose: Mixing code for equalizer.
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "../soundlib/Sndfile.h"
+#include "../soundlib/MixerLoops.h"
+#include "../sounddsp/EQ.h"
+
+#include <cstddef>
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifndef NO_EQ
+
+
+#define EQ_BANDWIDTH	2.0
+#define EQ_ZERO			0.000001
+
+
+
+static const UINT gEqLinearToDB[33] =
+{
+	16, 19, 22, 25, 28, 31, 34, 37,
+	40, 43, 46, 49, 52, 55, 58, 61,
+	64, 76, 88, 100, 112, 124, 136, 148,
+	160, 172, 184, 196, 208, 220, 232, 244, 256
+};
+
+static const EQBANDSTRUCT gEQDefaults[MAX_EQ_BANDS*2] =
+{
+	// Default: Flat EQ
+	{0,0,0,0,0, 0,0,0,0, 1,   120, false},
+	{0,0,0,0,0, 0,0,0,0, 1,   600, false},
+	{0,0,0,0,0, 0,0,0,0, 1,  1200, false},
+	{0,0,0,0,0, 0,0,0,0, 1,  3000, false},
+	{0,0,0,0,0, 0,0,0,0, 1,  6000, false},
+	{0,0,0,0,0, 0,0,0,0, 1, 10000, false},
+	{0,0,0,0,0, 0,0,0,0, 1,   120, false},
+	{0,0,0,0,0, 0,0,0,0, 1,   600, false},
+	{0,0,0,0,0, 0,0,0,0, 1,  1200, false},
+	{0,0,0,0,0, 0,0,0,0, 1,  3000, false},
+	{0,0,0,0,0, 0,0,0,0, 1,  6000, false},
+	{0,0,0,0,0, 0,0,0,0, 1, 10000, false},
+};
+
+#ifdef ENABLE_X86
+
+#if MPT_COMPILER_MSVC
+#pragma warning(push)
+#pragma warning(disable:4100)
+#endif // MPT_COMPILER_MSVC
+
+#define PBS_A0	DWORD PTR [eax + EQBANDSTRUCT.a0]
+#define PBS_A1	DWORD PTR [eax + EQBANDSTRUCT.a1]
+#define PBS_A2	DWORD PTR [eax + EQBANDSTRUCT.a2]
+#define PBS_B1	DWORD PTR [eax + EQBANDSTRUCT.b1]
+#define PBS_B2	DWORD PTR [eax + EQBANDSTRUCT.b2]
+#define PBS_X1	DWORD PTR [eax + EQBANDSTRUCT.x1]
+#define PBS_X2	DWORD PTR [eax + EQBANDSTRUCT.x2]
+#define PBS_Y1	DWORD PTR [eax + EQBANDSTRUCT.y1]
+#define PBS_Y2	DWORD PTR [eax + EQBANDSTRUCT.y2]
+
+static void EQFilter(EQBANDSTRUCT *pbs, float32 *pbuffer, UINT nCount)
+{
+	_asm {
+	mov eax, pbs		// eax = pbs
+	mov edx, nCount		// edx = nCount
+	mov ecx, pbuffer	// ecx = pbuffer
+	fld		PBS_Y2		// ST(3)=y2
+	fld		PBS_Y1		// ST(2)=y1
+	fld		PBS_X2		// ST(1)=x2
+	fld		PBS_X1		// ST(0)=x1
+EQ_Loop:
+	fld		DWORD PTR [ecx]		// ST(0):x ST(1):x1 ST(2):x2 ST(3):y1 ST(4):y2
+	fld		PBS_A0				// ST(0):a0 ST(1):x ST(2):x1 ST(3):x2 ST(4):y1 ST(5):y2
+	fmul	ST(0), ST(1)		// ST(0):a0*x
+	fld		PBS_A1				// ST(0):a1 ST(1):a0*x ST(2):x ST(3):x1 ST(4):x2 ST(5):y1 ST(6):y2
+	fmul	ST(0), ST(3)		// ST(0):a1*x1
+	add		ecx, 4
+
+	faddp	ST(1), ST(0)
+	fld		PBS_A2
+	fmul	ST(0), ST(4)
+	faddp	ST(1), ST(0)
+	fld		PBS_B1
+	fmul	ST(0), ST(5)
+	faddp	ST(1), ST(0)
+	fld		PBS_B2
+	fmul	ST(0), ST(6)
+	sub     edx, 1
+	faddp	ST(1), ST(0)
+	fst		DWORD PTR [ecx-4]		// *pbuffer = a0*x+a1*x1+a2*x2+b1*y1+b2*y2
+	// Here, ST(0)=y ST(1)=x ST(2)=x1 ST(3)=x2 ST(4)=y1 ST(5)=y2
+	fxch	ST(4)	// y1=y
+	fstp	ST(5)	// y2=y1
+	// Here, ST(0)=x ST(1)=x1 ST(2)=x2 ST(3)=y1 ST(4)=y2
+	fxch	ST(1)	// x1=x
+	fstp	ST(2)	// x2=x1
+	jnz		EQ_Loop
+	// Store x1,y1,x2,y2 and pop FPU stack
+	fstp	PBS_X1
+	fstp	PBS_X2
+	fstp	PBS_Y1
+	fstp	PBS_Y2
+	}
+}
+
+
+#ifdef ENABLE_X86_AMD
+
+static void AMD_StereoEQ(EQBANDSTRUCT *pbl, EQBANDSTRUCT *pbr, float32 *pbuffer, UINT nCount)
+{
+	float tmp[16];
+
+	_asm {
+	mov eax, pbl
+	mov edx, pbr
+	mov ebx, pbuffer
+	mov ecx, nCount
+	lea edi, [tmp+8]
+	and edi, 0xfffffff8
+	movd mm7, [eax+EQBANDSTRUCT.a0]
+	movd mm0, [edx+EQBANDSTRUCT.a0]
+	movd mm6, [eax+EQBANDSTRUCT.a1]
+	movd mm1, [edx+EQBANDSTRUCT.a1]
+	punpckldq mm7, mm0
+	punpckldq mm6, mm1
+	movq [edi], mm7						// [edi] = a0
+	movq [edi+8], mm6					// [edi+8] = a1
+	movd mm5, [eax+EQBANDSTRUCT.a2]
+	movd mm0, [edx+EQBANDSTRUCT.a2]
+	movd mm4, [eax+EQBANDSTRUCT.b1]
+	movd mm1, [edx+EQBANDSTRUCT.b1]
+	movd mm3, [eax+EQBANDSTRUCT.b2]
+	movd mm2, [edx+EQBANDSTRUCT.b2]
+	punpckldq mm5, mm0
+	punpckldq mm4, mm1
+	punpckldq mm3, mm2
+	movq [edi+16], mm5					// [edi+16] = a2
+	movq [edi+24], mm4					// [edi+24] = b1
+	movq [edi+32], mm3					// [edi+32] = b2
+	movd mm4, [eax+EQBANDSTRUCT.x1]
+	movd mm0, [edx+EQBANDSTRUCT.x1]
+	movd mm5, [eax+EQBANDSTRUCT.x2]
+	movd mm1, [edx+EQBANDSTRUCT.x2]
+	punpckldq mm4, mm0					// mm4 = x1
+	punpckldq mm5, mm1					// mm5 = x2
+	movd mm6, [eax+EQBANDSTRUCT.y1]
+	movd mm2, [edx+EQBANDSTRUCT.y1]
+	movd mm7, [eax+EQBANDSTRUCT.y2]
+	movd mm3, [edx+EQBANDSTRUCT.y2]
+	punpckldq mm6, mm2					// mm6 = y1
+	punpckldq mm7, mm3					// mm7 = y2
+mainloop:
+	movq mm0, [ebx]
+	movq mm3, [edi+8]
+	add ebx, 8
+	movq mm1, [edi+16]
+	pfmul mm3, mm4						// x1 * a1
+	movq mm2, [edi+32]
+	pfmul mm1, mm5						// x2 * a2
+	movq mm5, mm4						// x2 = x1
+	pfmul mm2, mm7						// y2 * b2
+	movq mm7, mm6						// y2 = y1
+	pfmul mm6, [edi+24]					// y1 * b1
+	movq mm4, mm0						// x1 = x
+	pfmul mm0, [edi]					// x * a0
+	pfadd mm6, mm1						// x2*a2 + y1*b1
+	pfadd mm6, mm2						// x2*a2 + y1*b1 + y2*b2
+	pfadd mm6, mm3						// x1*a1 + x2*a2 + y1*b1 + y2*b2
+	pfadd mm6, mm0						// x*a0 + x1*a1 + x2*a2 + y1*b1 + y2*b2
+	dec ecx
+	movq [ebx-8], mm6
+	jnz mainloop
+	movd [eax+EQBANDSTRUCT.x1], mm4
+	punpckhdq mm4, mm4
+	movd [eax+EQBANDSTRUCT.x2], mm5
+	punpckhdq mm5, mm5
+	movd [eax+EQBANDSTRUCT.y1], mm6
+	punpckhdq mm6, mm6
+	movd [eax+EQBANDSTRUCT.y2], mm7
+	punpckhdq mm7, mm7
+	movd [edx+EQBANDSTRUCT.x1], mm4
+	movd [edx+EQBANDSTRUCT.x2], mm5
+	movd [edx+EQBANDSTRUCT.y1], mm6
+	movd [edx+EQBANDSTRUCT.y2], mm7
+	emms
+	}
+}
+
+#endif // ENABLE_X86_AMD
+
+
+#ifdef ENABLE_SSE
+
+static void SSE_StereoEQ(EQBANDSTRUCT *pbl, EQBANDSTRUCT *pbr, float32 *pbuffer, UINT nCount)
+{
+	static const float gk1 = 1.0f;
+	_asm {
+	mov eax, pbl
+	mov edx, pbr
+	mov ebx, pbuffer
+	mov ecx, nCount
+	movss xmm0, [eax+EQBANDSTRUCT.Gain]
+	movss xmm1, gk1
+	comiss xmm0, xmm1
+	jne doeq
+	movss xmm0, [edx+EQBANDSTRUCT.Gain]
+	comiss xmm0, xmm1
+	je done
+doeq:
+	test ecx, ecx
+	jz done
+	movss xmm6, [eax+EQBANDSTRUCT.a1]
+	movss xmm7, [eax+EQBANDSTRUCT.a2]
+	movss xmm4, [eax+EQBANDSTRUCT.x1]
+	movss xmm5, [eax+EQBANDSTRUCT.x2]
+	movlhps xmm6, xmm7		// xmm6 = [  0 | a2 |  0 | a1 ]
+	movlhps xmm4, xmm5		// xmm4 = [  0 | x2 |  0 | x1 ]
+	movss xmm2, [edx+EQBANDSTRUCT.a1]
+	movss xmm3, [edx+EQBANDSTRUCT.a2]
+	movss xmm0, [edx+EQBANDSTRUCT.x1]
+	movss xmm1, [edx+EQBANDSTRUCT.x2]
+	movlhps xmm2, xmm3		// xmm2 = [ 0 | a'2 | 0 | a'1 ]
+	movlhps xmm0, xmm1		// xmm0 = [ 0 | x'2 | 0 | x'1 ]
+	shufps xmm6, xmm2, 0x88	// xmm6 = [ a'2 | a'1 | a2 | a1 ]
+	shufps xmm4, xmm0, 0x88 // xmm4 = [ x'2 | x'1 | x2 | x1 ]
+	shufps xmm6, xmm6, 0xD8	// xmm6 = [ a'2 | a2 | a'1 | a1 ]
+	shufps xmm4, xmm4, 0xD8	// xmm4 = [ x'2 | x2 | x'1 | x1 ]
+	movss xmm7, [eax+EQBANDSTRUCT.b1]
+	movss xmm0, [eax+EQBANDSTRUCT.b2]
+	movss xmm2, [edx+EQBANDSTRUCT.b1]
+	movss xmm1, [edx+EQBANDSTRUCT.b2]
+	movlhps xmm7, xmm0		// xmm7 = [ 0 |  b2 | 0 |  b1 ]
+	movlhps xmm2, xmm1		// xmm2 = [  0 | b'2 |  0 | b'1 ]
+	shufps xmm7, xmm2, 0x88	// xmm7 = [ b'2 | b'1 | b2 | b1 ]
+	shufps xmm7, xmm7, 0xD8 // xmm7 = [ b'2 | b2 | b'1 | b1 ]
+	movss xmm5, [eax+EQBANDSTRUCT.y1]
+	movss xmm1, [eax+EQBANDSTRUCT.y2]
+	movss xmm3, [edx+EQBANDSTRUCT.y1]
+	movss xmm0, [edx+EQBANDSTRUCT.y2]
+	movlhps xmm5, xmm1		// xmm5 = [  0 |  y2 |  0 |  y1 ]
+	movlhps xmm3, xmm0		// xmm3 = [  0 | y'2 |  0 | y'1 ]
+	shufps xmm5, xmm3, 0x88 // xmm5 = [ y'2 | y'1 | y2 | y1 ]
+	shufps xmm5, xmm5, 0xD8 // xmm5 = [ y'2 |  y2 | y'1 |  y1 ]
+	movss xmm3, [eax+EQBANDSTRUCT.a0]
+	movss xmm2, [edx+EQBANDSTRUCT.a0]
+	shufps xmm3, xmm2, 0x88
+	shufps xmm3, xmm3, 0xD8	// xmm3 = [  0 |  0 | a'0 | a0 ]
+mainloop:
+	movlps xmm0, qword ptr [ebx]
+	add ebx, 8
+	movaps xmm1, xmm5		// xmm1 = [ y2r | y2l | y1r | y1l ]
+	mulps xmm1, xmm7		// xmm1 = [b2r*y2r|b2l*y2l|b1r*y1r|b1l*y1l]
+	movaps xmm2, xmm4		// xmm2 = [ x2r | x2l | x1r | x1l ]
+	mulps xmm2, xmm6		// xmm6 = [a2r*x2r|a2l*x2l|a1r*x1r|a1l*x1l]
+	shufps xmm4, xmm0, 0x44 // xmm4 = [  xr |  xl | x1r | x1l ]
+	mulps xmm0, xmm3		// xmm0 = [   0 |   0 |a0r*xr|a0l*xl]
+	shufps xmm4, xmm4, 0x4E // xmm4 = [ x1r | x1l |  xr |  xl ]
+	addps xmm1, xmm2		// xmm1 = [b2r*y2r+a2r*x2r|b2l*y2l+a2l*x2l|b1r*y1r+a1r*x1r|b1l*y1l+a1l*x1l]
+	addps xmm1, xmm0		// xmm1 = [b2r*y2r+a2r*x2r|b2l*y2l+a2l*x2l|b1r*y1r+a1r*x1r+a0r*xr|b1l*y1l+a1l*x1l+a0l*xl]
+	sub ecx, 1
+	movhlps xmm0, xmm1
+	addps xmm0, xmm1		// xmm0 = [  ? |  ? | yr(n) | yl(n) ]
+	movlps [ebx-8], xmm0
+	shufps xmm0, xmm5, 0x44
+	movaps xmm5, xmm0
+	jnz mainloop
+	movhlps xmm0, xmm4
+	movhlps xmm1, xmm5
+	movss [eax+EQBANDSTRUCT.x1], xmm4
+	movss [eax+EQBANDSTRUCT.x2], xmm0
+	movss [eax+EQBANDSTRUCT.y1], xmm5
+	movss [eax+EQBANDSTRUCT.y2], xmm1
+	shufps xmm4, xmm4, 0x01
+	shufps xmm0, xmm0, 0x01
+	shufps xmm5, xmm5, 0x01
+	shufps xmm1, xmm1, 0x01
+	movss [edx+EQBANDSTRUCT.x1], xmm4
+	movss [edx+EQBANDSTRUCT.x2], xmm0
+	movss [edx+EQBANDSTRUCT.y1], xmm5
+	movss [edx+EQBANDSTRUCT.y2], xmm1
+done:;
+	}
+}
+
+#endif // ENABLE_SSE
+
+#if MPT_COMPILER_MSVC
+#pragma warning(pop)
+#endif // MPT_COMPILER_MSVC
+
+#else
+
+static void EQFilter(EQBANDSTRUCT *pbs, float32 *pbuffer, UINT nCount)
+{
+	for (UINT i=0; i<nCount; i++)
+	{
+		float32 x = pbuffer[i];
+		float32 y = pbs->a1 * pbs->x1 + pbs->a2 * pbs->x2 + pbs->a0 * x + pbs->b1 * pbs->y1 + pbs->b2 * pbs->y2;
+		pbs->x2 = pbs->x1;
+		pbs->y2 = pbs->y1;
+		pbs->x1 = x;
+		pbuffer[i] = y;
+		pbs->y1 = y;
+	}
+}
+
+#endif
+
+
+void CEQ::ProcessMono(int *pbuffer, float *MixFloatBuffer, UINT nCount)
+{
+	MonoMixToFloat(pbuffer, MixFloatBuffer, nCount, 1.0f/MIXING_SCALEF);
+	for (UINT b=0; b<MAX_EQ_BANDS; b++)
+	{
+		if ((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f)) EQFilter(&gEQ[b], MixFloatBuffer, nCount);
+	}
+	FloatToMonoMix(MixFloatBuffer, pbuffer, nCount, MIXING_SCALEF);
+}
+
+
+void CEQ::ProcessStereo(int *pbuffer, float *MixFloatBuffer, UINT nCount)
+{
+
+#ifdef ENABLE_SSE
+
+	if(GetProcSupport() & PROCSUPPORT_SSE)
+	{
+		int sse_state, sse_eqstate;
+		MonoMixToFloat(pbuffer, MixFloatBuffer, nCount*2, 1.0f/MIXING_SCALEF);
+
+		_asm stmxcsr sse_state;
+		sse_eqstate = sse_state | 0xFF80; // set flush-to-zero, denormals-are-zero, round-to-zero, mask all exception, leave flags alone
+		_asm ldmxcsr sse_eqstate;
+		for (UINT b=0; b<MAX_EQ_BANDS; b++)
+		{
+			if ((gEQ[b].bEnable) || (gEQ[b+MAX_EQ_BANDS].bEnable))
+				SSE_StereoEQ(&gEQ[b], &gEQ[b+MAX_EQ_BANDS], MixFloatBuffer, nCount);
+		}
+		_asm ldmxcsr sse_state;
+
+		FloatToMonoMix(MixFloatBuffer, pbuffer, nCount*2, MIXING_SCALEF);
+
+	} else
+
+#endif // ENABLE_SSE
+
+#ifdef ENABLE_X86_AMD
+
+	if(GetProcSupport() & PROCSUPPORT_AMD_3DNOW)
+	{ 
+		MonoMixToFloat(pbuffer, MixFloatBuffer, nCount*2, 1.0f/MIXING_SCALEF);
+
+		for (UINT b=0; b<MAX_EQ_BANDS; b++)
+		{
+			if (((gEQ[b].bEnable) && (gEQ[b].Gain != 1.0f))
+			 || ((gEQ[b+MAX_EQ_BANDS].bEnable) && (gEQ[b+MAX_EQ_BANDS].Gain != 1.0f)))
+				AMD_StereoEQ(&gEQ[b], &gEQ[b+MAX_EQ_BANDS], MixFloatBuffer, nCount);
+		}
+
+		FloatToMonoMix(MixFloatBuffer, pbuffer, nCount*2, MIXING_SCALEF);
+		
+	} else
+#endif // ENABLE_X86_AMD
+
+	{	
+
+		StereoMixToFloat(pbuffer, MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, nCount, 1.0f/MIXING_SCALEF);
+		
+		for (UINT bl=0; bl<MAX_EQ_BANDS; bl++)
+		{
+			if ((gEQ[bl].bEnable) && (gEQ[bl].Gain != 1.0f)) EQFilter(&gEQ[bl], MixFloatBuffer, nCount);
+		}
+		for (UINT br=MAX_EQ_BANDS; br<MAX_EQ_BANDS*2; br++)
+		{
+			if ((gEQ[br].bEnable) && (gEQ[br].Gain != 1.0f)) EQFilter(&gEQ[br], MixFloatBuffer+MIXBUFFERSIZE, nCount);
+		}
+
+		FloatToStereoMix(MixFloatBuffer, MixFloatBuffer+MIXBUFFERSIZE, pbuffer, nCount, MIXING_SCALEF);
+
+	}
+}
+
+
+CEQ::CEQ()
+{
+	#if defined(ENABLE_SSE) || defined(ENABLE_X86_AMD)
+		MPT_ASSERT_ALWAYS(((uintptr_t)&(gEQ[0])) % 4 == 0);
+		MPT_ASSERT_ALWAYS(((uintptr_t)&(gEQ[1])) % 4 == 0);
+	#endif // ENABLE_SSE || ENABLE_X86_AMD
+	memcpy(gEQ, gEQDefaults, sizeof(gEQ));
+}
+
+
+void CEQ::Initialize(bool bReset, DWORD MixingFreq)
+{
+	float32 fMixingFreq = (float32)MixingFreq;
+	// Gain = 0.5 (-6dB) .. 2 (+6dB)
+	for (UINT band=0; band<MAX_EQ_BANDS*2; band++) if (gEQ[band].bEnable)
+	{
+		float32 k, k2, r, f;
+		float32 v0, v1;
+		bool b = bReset;
+
+		f = gEQ[band].CenterFrequency / fMixingFreq;
+		if (f > 0.45f) gEQ[band].Gain = 1;
+		// if (f > 0.25) f = 0.25;
+		// k = tan(PI*f);
+		k = f * 3.141592654f;
+		k = k + k*f;
+//		if (k > (float32)0.707) k = (float32)0.707;
+		k2 = k*k;
+		v0 = gEQ[band].Gain;
+		v1 = 1;
+		if (gEQ[band].Gain < 1.0)
+		{
+			v0 *= (0.5f/EQ_BANDWIDTH);
+			v1 *= (0.5f/EQ_BANDWIDTH);
+		} else
+		{
+			v0 *= (1.0f/EQ_BANDWIDTH);
+			v1 *= (1.0f/EQ_BANDWIDTH);
+		}
+		r = (1 + v0*k + k2) / (1 + v1*k + k2);
+		if (r != gEQ[band].a0)
+		{
+			gEQ[band].a0 = r;
+			b = true;
+		}
+		r = 2 * (k2 - 1) / (1 + v1*k + k2);
+		if (r != gEQ[band].a1)
+		{
+			gEQ[band].a1 = r;
+			b = true;
+		}
+		r = (1 - v0*k + k2) / (1 + v1*k + k2);
+		if (r != gEQ[band].a2)
+		{
+			gEQ[band].a2 = r;
+			b = true;
+		}
+		r = - 2 * (k2 - 1) / (1 + v1*k + k2);
+		if (r != gEQ[band].b1)
+		{
+			gEQ[band].b1 = r;
+			b = true;
+		}
+		r = - (1 - v1*k + k2) / (1 + v1*k + k2);
+		if (r != gEQ[band].b2)
+		{
+			gEQ[band].b2 = r;
+			b = true;
+		}
+		if (b)
+		{
+			gEQ[band].x1 = 0;
+			gEQ[band].x2 = 0;
+			gEQ[band].y1 = 0;
+			gEQ[band].y2 = 0;
+		}
+	} else
+	{
+		gEQ[band].a0 = 0;
+		gEQ[band].a1 = 0;
+		gEQ[band].a2 = 0;
+		gEQ[band].b1 = 0;
+		gEQ[band].b2 = 0;
+		gEQ[band].x1 = 0;
+		gEQ[band].x2 = 0;
+		gEQ[band].y1 = 0;
+		gEQ[band].y2 = 0;
+	}
+}
+
+
+void CEQ::SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, bool bReset, DWORD MixingFreq)
+{
+	for (UINT i=0; i<MAX_EQ_BANDS; i++)
+	{
+		float32 g, f = 0;
+		if (i < nGains)
+		{
+			UINT n = pGains[i];
+			if (n > 32) n = 32;
+			g = ((float32)gEqLinearToDB[n]) / 64.0f;
+			if (pFreqs) f = (float32)(int)pFreqs[i];
+		} else
+		{
+			g = 1;
+		}
+		gEQ[i].Gain = g;
+		gEQ[i].CenterFrequency = f;
+		gEQ[i+MAX_EQ_BANDS].Gain = g;
+		gEQ[i+MAX_EQ_BANDS].CenterFrequency = f;
+		if (f > 20.0f)
+		{
+			gEQ[i].bEnable = true;
+			gEQ[i+MAX_EQ_BANDS].bEnable = true;
+		} else
+		{
+			gEQ[i].bEnable = false;
+			gEQ[i+MAX_EQ_BANDS].bEnable = false;
+		}
+	}
+	Initialize(bReset, MixingFreq);
+}
+
+
+void CQuadEQ::Initialize(bool bReset, DWORD MixingFreq)
+{
+	front.Initialize(bReset, MixingFreq);
+	rear.Initialize(bReset, MixingFreq);
+}
+
+void CQuadEQ::SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, bool bReset, DWORD MixingFreq)
+{
+	front.SetEQGains(pGains, nGains, pFreqs, bReset, MixingFreq);
+	rear.SetEQGains(pGains, nGains, pFreqs, bReset, MixingFreq);
+}
+
+void CQuadEQ::Process(int *frontBuffer, int *rearBuffer, UINT nCount, UINT nChannels)
+{
+	if(nChannels == 1)
+	{
+		front.ProcessMono(frontBuffer, EQTempFloatBuffer, nCount);
+	} else if(nChannels == 2)
+	{
+		front.ProcessStereo(frontBuffer, EQTempFloatBuffer, nCount);
+	} else if(nChannels == 4)
+	{
+		front.ProcessStereo(frontBuffer, EQTempFloatBuffer, nCount);
+		rear.ProcessStereo(rearBuffer, EQTempFloatBuffer, nCount);
+	}
+}
+
+
+#else
+
+
+MPT_MSVC_WORKAROUND_LNK4221(EQ)
+
+
+#endif // !NO_EQ
+
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/EQ.h b/sounddsp/EQ.h
new file mode 100644
index 0000000..0fd073a
--- /dev/null
+++ b/sounddsp/EQ.h
@@ -0,0 +1,67 @@
+/*
+ * EQ.h
+ * ----
+ * Purpose: Mixing code for equalizer.
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#include "../soundlib/Mixer.h"	// For MIXBUFFERSIZE
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifndef NO_EQ
+
+#define MAX_EQ_BANDS	6
+
+typedef struct _EQBANDSTRUCT
+{
+	float32 a0;
+	float32 a1;
+	float32 a2;
+	float32 b1;
+	float32 b2;
+	float32 x1;
+	float32 x2;
+	float32 y1;
+	float32 y2;
+	float32 Gain;
+	float32 CenterFrequency;
+	bool bEnable;
+} EQBANDSTRUCT;
+
+class CEQ
+{
+private:
+	EQBANDSTRUCT gEQ[MAX_EQ_BANDS*2];
+public:
+	CEQ();
+public:
+	void Initialize(bool bReset, DWORD MixingFreq);
+	void ProcessStereo(int *pbuffer, float *MixFloatBuffer, UINT nCount);
+	void ProcessMono(int *pbuffer, float *MixFloatBuffer, UINT nCount);
+	void SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, bool bReset, DWORD MixingFreq);
+};
+
+
+class CQuadEQ
+{
+private:
+	CEQ front;
+	CEQ rear;
+	float EQTempFloatBuffer[MIXBUFFERSIZE * 2];
+public:
+	void Initialize(bool bReset, DWORD MixingFreq);
+	void Process(int *frontBuffer, int *rearBuffer, UINT nCount, UINT nChannels);
+	void SetEQGains(const UINT *pGains, UINT nGains, const UINT *pFreqs, bool bReset, DWORD MixingFreq);
+};
+
+
+#endif // !NO_EQ
+
+OPENMPT_NAMESPACE_END
diff --git a/sounddsp/Reverb.cpp b/sounddsp/Reverb.cpp
new file mode 100644
index 0000000..89f2483
--- /dev/null
+++ b/sounddsp/Reverb.cpp
@@ -0,0 +1,1262 @@
+/*
+ * Reverb.cpp
+ * ----------
+ * Purpose: Mixing code for reverb.
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#ifndef NO_REVERB
+#include "Reverb.h"
+#include "../soundlib/MixerLoops.h"
+
+#ifdef ENABLE_MMX
+#include <mmintrin.h>
+#endif
+#ifdef ENABLE_SSE2
+#include <emmintrin.h>
+#endif
+
+#endif // NO_REVERB
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifndef NO_REVERB
+
+
+#ifdef ENABLE_MMX
+// Load two 32-bit values
+static MPT_FORCEINLINE __m64 Load64MMX(const int32 *x) { return _mm_set_pi32(x[1], x[0]); }
+// Load four 16-bit values
+static MPT_FORCEINLINE __m64 Load64MMX(const LR16 (&x)[2]) { return Load64MMX(&x->lr); }
+// Store 64-bit value from register (MSVC does not have_mm_cvtsi64_si64x) - macro to avoid emms warnings
+#define Store64MMX(dst, src) \
+	MPT_DO \
+	{ \
+		STATIC_ASSERT(sizeof((dst)[0]) == 4); \
+		(dst)[0] = _mm_cvtsi64_si32(src); \
+		(dst)[1] = _mm_cvtsi64_si32(_mm_unpackhi_pi32(src, src)); \
+	} MPT_WHILE_0
+#endif
+#ifdef ENABLE_SSE2
+// Load two 32-bit values
+static MPT_FORCEINLINE __m128i Load64SSE(const int32 *x) { return _mm_loadl_epi64(reinterpret_cast<const __m128i *>(x)); }
+// Load four 16-bit values
+static MPT_FORCEINLINE __m128i Load64SSE(const LR16 (&x)[2]) { return _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&x)); }
+// Store two 32-bit or four 16-bit values from register
+static MPT_FORCEINLINE void Store64SSE(int32 *dst, __m128i src) { return _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), src); }
+static MPT_FORCEINLINE void Store64SSE(LR16 *dst, __m128i src) { return _mm_storel_epi64(reinterpret_cast<__m128i *>(dst), src); }
+#endif
+
+CReverbSettings::CReverbSettings()
+{
+	m_nReverbType = 0;
+	m_nReverbDepth = 8; // 50%
+}
+
+
+CReverb::CReverb()
+{
+	// Shared reverb state
+	InitMixBuffer(MixReverbBuffer, static_cast<uint32>(mpt::size(MixReverbBuffer)));
+	gnRvbROfsVol = 0;
+	gnRvbLOfsVol = 0;
+
+	gnReverbSend = 0;
+
+	gnReverbSamples = 0;
+	gnReverbDecaySamples = 0;
+
+	// Internal reverb state
+	g_bLastInPresent = 0;
+	g_bLastOutPresent = 0;
+	g_nLastRvbIn_xl = 0;
+	g_nLastRvbIn_xr = 0;
+	g_nLastRvbIn_yl = 0;
+	g_nLastRvbIn_yr = 0;
+	g_nLastRvbOut_xl = 0;
+	g_nLastRvbOut_xr = 0;
+	MemsetZero(gnDCRRvb_Y1);
+	MemsetZero(gnDCRRvb_X1);
+
+	// Reverb mix buffers
+	MemsetZero(g_RefDelay);
+	MemsetZero(g_LateReverb);
+
+}
+
+
+static int32 OnePoleLowPassCoef(int32 scale, float g, float F_c, float F_s)
+{
+	if(g > 0.999999f) return 0;
+
+	g *= g;
+	double scale_over_1mg = scale / (1.0 - g);
+	double cosw = std::cos(2.0 * M_PI * F_c / F_s);
+	return Util::Round<int32>((1.0 - (std::sqrt((g + g) * (1.0 - cosw) - g * g * (1.0 - cosw * cosw)) + g * cosw)) * scale_over_1mg);
+}
+
+static float mBToLinear(int32 value_mB)
+{
+	if(!value_mB) return 1;
+	if(value_mB <= -100000) return 0;
+
+	const double val = value_mB * 3.321928094887362304 / (100.0 * 20.0);	// log2(10)/(100*20)
+	return static_cast<float>(std::pow(2.0, val - static_cast<int32>(0.5 + val)));
+}
+
+static int32 mBToLinear(int32 scale, int32 value_mB)
+{
+	return Util::Round<int32>(mBToLinear(value_mB) * scale);
+}
+
+
+struct SNDMIX_REVERB_PROPERTIES
+{
+	int32 lRoom;                   // [-10000, 0]      default: -10000 mB
+	int32 lRoomHF;                 // [-10000, 0]      default: 0 mB
+	float flDecayTime;             // [0.1, 20.0]      default: 1.0 s
+	float flDecayHFRatio;          // [0.1, 2.0]       default: 0.5
+	int32 lReflections;            // [-10000, 1000]   default: -10000 mB
+	float flReflectionsDelay;      // [0.0, 0.3]       default: 0.02 s
+	int32 lReverb;                 // [-10000, 2000]   default: -10000 mB
+	float flReverbDelay;           // [0.0, 0.1]       default: 0.04 s
+	float flDiffusion;             // [0.0, 100.0]     default: 100.0 %
+	float flDensity;               // [0.0, 100.0]     default: 100.0 %
+};
+
+struct SNDMIX_RVBPRESET
+{
+	SNDMIX_REVERB_PROPERTIES Preset;
+	const char *name;
+};
+
+
+static SNDMIX_RVBPRESET gRvbPresets[NUM_REVERBTYPES] =
+{
+	{{ SNDMIX_REVERB_PRESET_PLATE },			"GM Plate"},
+	{{ SNDMIX_REVERB_PRESET_SMALLROOM },		"GM Small Room"},
+	{{ SNDMIX_REVERB_PRESET_MEDIUMROOM },		"GM Medium Room"},
+	{{ SNDMIX_REVERB_PRESET_LARGEROOM },		"GM Large Room"},
+	{{ SNDMIX_REVERB_PRESET_MEDIUMHALL },		"GM Medium Hall"},
+	{{ SNDMIX_REVERB_PRESET_LARGEHALL },		"GM Large Hall"},
+	{{ SNDMIX_REVERB_PRESET_GENERIC },			"Generic"},
+	{{ SNDMIX_REVERB_PRESET_PADDEDCELL },		"Padded Cell"},
+	{{ SNDMIX_REVERB_PRESET_ROOM },				"Room"},
+	{{ SNDMIX_REVERB_PRESET_BATHROOM },			"Bathroom"},
+	{{ SNDMIX_REVERB_PRESET_LIVINGROOM },		"Living Room"},
+	{{ SNDMIX_REVERB_PRESET_STONEROOM },		"Stone Room"},
+	{{ SNDMIX_REVERB_PRESET_AUDITORIUM },		"Auditorium"},
+	{{ SNDMIX_REVERB_PRESET_CONCERTHALL },		"Concert Hall"},
+	{{ SNDMIX_REVERB_PRESET_CAVE },				"Cave"},
+	{{ SNDMIX_REVERB_PRESET_ARENA },			"Arena"},
+	{{ SNDMIX_REVERB_PRESET_HANGAR },			"Hangar"},
+	{{ SNDMIX_REVERB_PRESET_CARPETEDHALLWAY },	"Carpeted Hallway"},
+	{{ SNDMIX_REVERB_PRESET_HALLWAY },			"Hallway"},
+	{{ SNDMIX_REVERB_PRESET_STONECORRIDOR },	"Stone Corridor"},
+	{{ SNDMIX_REVERB_PRESET_ALLEY },			"Alley"},
+	{{ SNDMIX_REVERB_PRESET_FOREST },			"Forest"},
+	{{ SNDMIX_REVERB_PRESET_CITY },				"City"},
+	{{ SNDMIX_REVERB_PRESET_MOUNTAINS },		"Mountains"},
+	{{ SNDMIX_REVERB_PRESET_QUARRY },			"Quarry"},
+	{{ SNDMIX_REVERB_PRESET_PLAIN },			"Plain"},
+	{{ SNDMIX_REVERB_PRESET_PARKINGLOT },		"Parking Lot"},
+	{{ SNDMIX_REVERB_PRESET_SEWERPIPE },		"Sewer Pipe"},
+	{{ SNDMIX_REVERB_PRESET_UNDERWATER },		"Underwater"},
+};
+
+const char *GetReverbPresetName(uint32 nPreset)
+{
+	return (nPreset < NUM_REVERBTYPES) ? gRvbPresets[nPreset].name : nullptr;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// I3DL2 environmental reverb support
+//
+
+struct REFLECTIONPRESET
+{
+	int32 lDelayFactor;
+	int16 sGainLL, sGainRR, sGainLR, sGainRL;
+};
+
+const REFLECTIONPRESET gReflectionsPreset[ENVIRONMENT_NUMREFLECTIONS] =
+{
+	// %Delay, ll,    rr,   lr,    rl
+	{0,    9830,   6554,	  0,     0},
+	{10,   6554,  13107,	  0,     0},
+	{24,  -9830,  13107,	  0,     0},
+	{36,  13107,  -6554,      0,     0},
+	{54,  16384,  16384,  -1638, -1638},
+	{61, -13107,   8192,   -328,  -328},
+	{73, -11468, -11468,  -3277,  3277},
+	{87,  13107,  -9830,   4916, -4916}
+};
+
+////////////////////////////////////////////////////////////////////////////////////
+//
+// Implementation
+//
+
+MPT_FORCEINLINE int32 ftol(float f) { return static_cast<int32>(f); }
+
+static void I3dl2_to_Generic(
+				const SNDMIX_REVERB_PROPERTIES *pReverb,
+				EnvironmentReverb *pRvb,
+				float flOutputFreq,
+				int32 lMinRefDelay,
+				int32 lMaxRefDelay,
+				int32 lMinRvbDelay,
+				int32 lMaxRvbDelay,
+				int32 lTankLength)
+{
+	float flDelayFactor, flDelayFactorHF, flDecayTimeHF;
+	int32 lDensity, lTailDiffusion;
+
+	// Common parameters
+	pRvb->ReverbLevel = pReverb->lReverb;
+	pRvb->ReflectionsLevel = pReverb->lReflections;
+	pRvb->RoomHF = pReverb->lRoomHF;
+
+	// HACK: Somewhat normalize the reverb output level
+	int32 lMaxLevel = (pRvb->ReverbLevel > pRvb->ReflectionsLevel) ? pRvb->ReverbLevel : pRvb->ReflectionsLevel;
+	if (lMaxLevel < -600)
+	{
+		lMaxLevel += 600;
+		pRvb->ReverbLevel -= lMaxLevel;
+		pRvb->ReflectionsLevel -= lMaxLevel;
+	}
+
+	// Pre-Diffusion factor (for both reflections and late reverb)
+	lDensity = 8192 + ftol(79.31f * pReverb->flDensity);
+	pRvb->PreDiffusion = lDensity;
+
+	// Late reverb diffusion
+	lTailDiffusion = ftol((0.15f + pReverb->flDiffusion * (0.36f*0.01f)) * 32767.0f);
+	if (lTailDiffusion > 0x7f00) lTailDiffusion = 0x7f00;
+	pRvb->TankDiffusion = lTailDiffusion;
+
+	// Verify reflections and reverb delay parameters
+	float flRefDelay = pReverb->flReflectionsDelay;
+	if (flRefDelay > 0.100f) flRefDelay = 0.100f;
+	int32 lReverbDelay = ftol(pReverb->flReverbDelay * flOutputFreq);
+	int32 lReflectionsDelay = ftol(flRefDelay * flOutputFreq);
+	int32 lReverbDecayTime = ftol(pReverb->flDecayTime * flOutputFreq);
+	if (lReflectionsDelay < lMinRefDelay)
+	{
+		lReverbDelay -= (lMinRefDelay - lReflectionsDelay);
+		lReflectionsDelay = lMinRefDelay;
+	}
+	if (lReflectionsDelay > lMaxRefDelay)
+	{
+		lReverbDelay += (lReflectionsDelay - lMaxRefDelay);
+		lReflectionsDelay = lMaxRefDelay;
+	}
+	// Adjust decay time when adjusting reverb delay
+	if (lReverbDelay < lMinRvbDelay)
+	{
+		lReverbDecayTime -= (lMinRvbDelay - lReverbDelay);
+		lReverbDelay = lMinRvbDelay;
+	}
+	if (lReverbDelay > lMaxRvbDelay)
+	{
+		lReverbDecayTime += (lReverbDelay - lMaxRvbDelay);
+		lReverbDelay = lMaxRvbDelay;
+	}
+	pRvb->ReverbDelay = lReverbDelay;
+	pRvb->ReverbDecaySamples = lReverbDecayTime;
+	// Setup individual reflections delay and gains
+	for (uint32 iRef=0; iRef<ENVIRONMENT_NUMREFLECTIONS; iRef++)
+	{
+		EnvironmentReflection &ref = pRvb->Reflections[iRef];
+		ref.Delay = lReflectionsDelay + (gReflectionsPreset[iRef].lDelayFactor * lReverbDelay + 50)/100;
+		ref.GainLL = gReflectionsPreset[iRef].sGainLL;
+		ref.GainRL = gReflectionsPreset[iRef].sGainRL;
+		ref.GainLR = gReflectionsPreset[iRef].sGainLR;
+		ref.GainRR = gReflectionsPreset[iRef].sGainRR;
+	}
+
+	// Late reverb decay time
+	if (lTankLength < 10) lTankLength = 10;
+	flDelayFactor = (lReverbDecayTime <= lTankLength) ? 1.0f : ((float)lTankLength / (float)lReverbDecayTime);
+	pRvb->ReverbDecay = ftol(std::pow(0.001f, flDelayFactor) * 32768.0f);
+
+	// Late Reverb Decay HF
+	flDecayTimeHF = (float)lReverbDecayTime * pReverb->flDecayHFRatio;
+	flDelayFactorHF = (flDecayTimeHF <= (float)lTankLength) ? 1.0f : ((float)lTankLength / flDecayTimeHF);
+	pRvb->flReverbDamping = std::pow(0.001f, flDelayFactorHF);
+}
+
+
+void CReverb::Shutdown()
+{
+	gnReverbSend = 0;
+
+	gnRvbLOfsVol = 0;
+	gnRvbROfsVol = 0;
+
+	// Clear out all reverb state
+	g_bLastInPresent = false;
+	g_bLastOutPresent = false;
+	g_nLastRvbIn_xl = g_nLastRvbIn_xr = 0;
+	g_nLastRvbIn_yl = g_nLastRvbIn_yr = 0;
+	g_nLastRvbOut_xl = g_nLastRvbOut_xr = 0;
+	MemsetZero(gnDCRRvb_X1);
+	MemsetZero(gnDCRRvb_Y1);
+
+	// Zero internal buffers
+	MemsetZero(g_LateReverb.Diffusion1);
+	MemsetZero(g_LateReverb.Diffusion2);
+	MemsetZero(g_LateReverb.Delay1);
+	MemsetZero(g_LateReverb.Delay2);
+	MemsetZero(g_RefDelay.RefDelayBuffer);
+	MemsetZero(g_RefDelay.PreDifBuffer);
+	MemsetZero(g_RefDelay.RefOut);
+}
+
+
+void CReverb::Initialize(bool bReset, uint32 MixingFreq)
+{
+	if (m_Settings.m_nReverbType >= NUM_REVERBTYPES) m_Settings.m_nReverbType = 0;
+	static SNDMIX_REVERB_PROPERTIES *spCurrentPreset = nullptr;
+	SNDMIX_REVERB_PROPERTIES *pRvbPreset = &gRvbPresets[m_Settings.m_nReverbType].Preset;
+
+	if ((pRvbPreset != spCurrentPreset) || (bReset))
+	{
+		// Reverb output frequency is half of the dry output rate
+		float flOutputFrequency = (float)MixingFreq;
+		EnvironmentReverb rvb;
+
+		// Reset reverb parameters
+		spCurrentPreset = pRvbPreset;
+		I3dl2_to_Generic(pRvbPreset, &rvb, flOutputFrequency,
+							RVBMINREFDELAY, RVBMAXREFDELAY,
+							RVBMINRVBDELAY, RVBMAXRVBDELAY,
+							( RVBDIF1L_LEN + RVBDIF1R_LEN
+							+ RVBDIF2L_LEN + RVBDIF2R_LEN
+							+ RVBDLY1L_LEN + RVBDLY1R_LEN
+							+ RVBDLY2L_LEN + RVBDLY2R_LEN) / 2);
+
+		// Store reverb decay time (in samples) for reverb auto-shutdown
+		gnReverbDecaySamples = rvb.ReverbDecaySamples;
+
+		// Room attenuation at high frequencies
+		int32 nRoomLP;
+		nRoomLP = OnePoleLowPassCoef(32768, mBToLinear(rvb.RoomHF), 5000, flOutputFrequency);
+		g_RefDelay.nCoeffs.c.l = (int16)nRoomLP;
+		g_RefDelay.nCoeffs.c.r = (int16)nRoomLP;
+
+		// Pre-Diffusion factor (for both reflections and late reverb)
+		g_RefDelay.nPreDifCoeffs.c.l = (int16)(rvb.PreDiffusion*2);
+		g_RefDelay.nPreDifCoeffs.c.r = (int16)(rvb.PreDiffusion*2);
+
+		// Setup individual reflections delay and gains
+		for (uint32 iRef=0; iRef<8; iRef++)
+		{
+			SWRvbReflection &ref = g_RefDelay.Reflections[iRef];
+			ref.DelayDest = rvb.Reflections[iRef].Delay;
+			ref.Delay = ref.DelayDest;
+			ref.Gains[0].c.l = rvb.Reflections[iRef].GainLL;
+			ref.Gains[0].c.r = rvb.Reflections[iRef].GainRL;
+			ref.Gains[1].c.l = rvb.Reflections[iRef].GainLR;
+			ref.Gains[1].c.r = rvb.Reflections[iRef].GainRR;
+		}
+		g_LateReverb.nReverbDelay = rvb.ReverbDelay;
+
+		// Reflections Master Gain
+		uint32 lReflectionsGain = 0;
+		if (rvb.ReflectionsLevel > -9000)
+		{
+			lReflectionsGain = mBToLinear(32768, rvb.ReflectionsLevel);
+		}
+		g_RefDelay.lMasterGain = lReflectionsGain;
+
+		// Late reverb master gain
+		uint32 lReverbGain = 0;
+		if (rvb.ReverbLevel > -9000)
+		{
+			lReverbGain = mBToLinear(32768, rvb.ReverbLevel);
+		}
+		g_LateReverb.lMasterGain = lReverbGain;
+
+		// Late reverb diffusion
+		uint32 nTailDiffusion = rvb.TankDiffusion;
+		if (nTailDiffusion > 0x7f00) nTailDiffusion = 0x7f00;
+		g_LateReverb.nDifCoeffs[0].c.l = (int16)nTailDiffusion;
+		g_LateReverb.nDifCoeffs[0].c.r = (int16)nTailDiffusion;
+		g_LateReverb.nDifCoeffs[1].c.l = (int16)nTailDiffusion;
+		g_LateReverb.nDifCoeffs[1].c.r = (int16)nTailDiffusion;
+		g_LateReverb.Dif2InGains[0].c.l = 0x7000;
+		g_LateReverb.Dif2InGains[0].c.r = 0x1000;
+		g_LateReverb.Dif2InGains[1].c.l = 0x1000;
+		g_LateReverb.Dif2InGains[1].c.r = 0x7000;
+
+		// Late reverb decay time
+		int32 nReverbDecay = rvb.ReverbDecay;
+		Limit(nReverbDecay, 0, 0x7ff0);
+		g_LateReverb.nDecayDC[0].c.l = (int16)nReverbDecay;
+		g_LateReverb.nDecayDC[0].c.r = 0;
+		g_LateReverb.nDecayDC[1].c.l = 0;
+		g_LateReverb.nDecayDC[1].c.r = (int16)nReverbDecay;
+
+		// Late Reverb Decay HF
+		float fReverbDamping = rvb.flReverbDamping * rvb.flReverbDamping;
+		int32 nDampingLowPass;
+
+		nDampingLowPass = OnePoleLowPassCoef(32768, fReverbDamping, 5000, flOutputFrequency);
+		Limit(nDampingLowPass, 0x100, 0x7f00);
+		
+		g_LateReverb.nDecayLP[0].c.l = (int16)nDampingLowPass;
+		g_LateReverb.nDecayLP[0].c.r = 0;
+		g_LateReverb.nDecayLP[1].c.l = 0;
+		g_LateReverb.nDecayLP[1].c.r = (int16)nDampingLowPass;
+	}
+	if (bReset)
+	{
+		gnReverbSamples = 0;
+		Shutdown();
+	}
+	// Wait at least 5 seconds before shutting down the reverb
+	if (gnReverbDecaySamples < MixingFreq*5)
+	{
+		gnReverbDecaySamples = MixingFreq*5;
+	}
+}
+
+
+mixsample_t *CReverb::GetReverbSendBuffer(uint32 nSamples)
+{
+	if(!gnReverbSend)
+	{ // and we did not clear the buffer yet, do it now because we will get new data
+		StereoFill(MixReverbBuffer, nSamples, gnRvbROfsVol, gnRvbLOfsVol);
+	}
+	gnReverbSend = 1; // we will have to process reverb
+	return MixReverbBuffer;
+}
+
+
+// Reverb
+void CReverb::Process(mixsample_t *MixSoundBuffer, uint32 nSamples)
+{
+	if((!gnReverbSend) && (!gnReverbSamples))
+	{ // no data is sent to reverb and reverb decayed completely
+		return;
+	}
+	if(!gnReverbSend)
+	{ // no input data in MixReverbBuffer, so the buffer got not cleared in GetReverbSendBuffer(), do it now for decay
+		StereoFill(MixReverbBuffer, nSamples, gnRvbROfsVol, gnRvbLOfsVol);
+	}
+
+	uint32 nIn, nOut;
+	// Dynamically adjust reverb master gains
+	int32 lMasterGain;
+	lMasterGain = ((g_RefDelay.lMasterGain * m_Settings.m_nReverbDepth) >> 4);
+	if (lMasterGain > 0x7fff) lMasterGain = 0x7fff;
+	g_RefDelay.ReflectionsGain.c.l = (int16)lMasterGain;
+	g_RefDelay.ReflectionsGain.c.r = (int16)lMasterGain;
+	lMasterGain = ((g_LateReverb.lMasterGain * m_Settings.m_nReverbDepth) >> 4);
+	if (lMasterGain > 0x10000) lMasterGain = 0x10000;
+	g_LateReverb.RvbOutGains[0].c.l = (int16)((lMasterGain+0x7f) >> 3);	// l->l
+	g_LateReverb.RvbOutGains[0].c.r = (int16)((lMasterGain+0xff) >> 4);	// r->l
+	g_LateReverb.RvbOutGains[1].c.l = (int16)((lMasterGain+0xff) >> 4);	// l->r
+	g_LateReverb.RvbOutGains[1].c.r = (int16)((lMasterGain+0x7f) >> 3);	// r->r
+	// Process Dry/Wet Mix
+	int32 lMaxRvbGain = (g_RefDelay.lMasterGain > g_LateReverb.lMasterGain) ? g_RefDelay.lMasterGain : g_LateReverb.lMasterGain;
+	if (lMaxRvbGain > 32768) lMaxRvbGain = 32768;
+	int32 lDryVol = (36 - m_Settings.m_nReverbDepth)>>1;
+	if (lDryVol < 8) lDryVol = 8;
+	if (lDryVol > 16) lDryVol = 16;
+	lDryVol = 16 - (((16-lDryVol) * lMaxRvbGain) >> 15);
+	ReverbDryMix(MixSoundBuffer, MixReverbBuffer, lDryVol, nSamples);
+	// Downsample 2x + 1st stage of lowpass filter
+	nIn = ReverbProcessPreFiltering1x(MixReverbBuffer, nSamples);
+	nOut = nIn;
+	// Main reverb processing: split into small chunks (needed for short reverb delays)
+	// Reverb Input + Low-Pass stage #2 + Pre-diffusion
+	if (nIn > 0) ProcessPreDelay(&g_RefDelay, MixReverbBuffer, nIn);
+	// Process Reverb Reflections and Late Reverberation
+	int32 *pRvbOut = MixReverbBuffer;
+	uint32 nRvbSamples = nOut, nCount = 0;
+	while (nRvbSamples > 0)
+	{
+		uint32 nPosRef = g_RefDelay.nRefOutPos & SNDMIX_REVERB_DELAY_MASK;
+		uint32 nPosRvb = (nPosRef - g_LateReverb.nReverbDelay) & SNDMIX_REVERB_DELAY_MASK;
+		uint32 nmax1 = (SNDMIX_REVERB_DELAY_MASK+1) - nPosRef;
+		uint32 nmax2 = (SNDMIX_REVERB_DELAY_MASK+1) - nPosRvb;
+		nmax1 = (nmax1 < nmax2) ? nmax1 : nmax2;
+		uint32 n = nRvbSamples;
+		if (n > nmax1) n = nmax1;
+		if (n > 64) n = 64;
+		// Reflections output + late reverb delay
+		ProcessReflections(&g_RefDelay, &g_RefDelay.RefOut[nPosRef], pRvbOut, n);
+		// Late Reverberation
+		ProcessLateReverb(&g_LateReverb, &g_RefDelay.RefOut[nPosRvb], pRvbOut, n);
+		// Update delay positions
+		g_RefDelay.nRefOutPos = (g_RefDelay.nRefOutPos + n) & SNDMIX_REVERB_DELAY_MASK;
+		g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos + n) & SNDMIX_REFLECTIONS_DELAY_MASK;
+		nCount += n*2;
+		pRvbOut += n*2;
+		nRvbSamples -= n;
+	}
+	// Adjust nDelayPos, in case nIn != nOut
+	g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos - nOut + nIn) & SNDMIX_REFLECTIONS_DELAY_MASK;
+	// Upsample 2x
+	ReverbProcessPostFiltering1x(MixReverbBuffer, MixSoundBuffer, nSamples);
+	// Automatically shut down if needed
+	if(gnReverbSend) gnReverbSamples = gnReverbDecaySamples; // reset decay counter
+	else if(gnReverbSamples > nSamples) gnReverbSamples -= nSamples; // decay
+	else // decayed
+	{
+		Shutdown();
+		gnReverbSamples = 0;
+	}
+	gnReverbSend = 0; // no input data in MixReverbBuffer
+}
+
+
+void CReverb::ReverbDryMix(int32 * MPT_RESTRICT pDry, int32 * MPT_RESTRICT pWet, int lDryVol, uint32 nSamples)
+{
+	for (uint32 i=0; i<nSamples; i++)
+	{
+		pDry[i*2] += (pWet[i*2]>>4) * lDryVol;
+		pDry[i*2+1] += (pWet[i*2+1]>>4) * lDryVol;
+	}
+}
+
+
+uint32 CReverb::ReverbProcessPreFiltering2x(int32 * MPT_RESTRICT pWet, uint32 nSamples)
+{
+	uint32 nOutSamples = 0;
+	int lowpass = g_RefDelay.nCoeffs.c.l;
+	int y1_l = g_nLastRvbIn_yl, y1_r = g_nLastRvbIn_yr;
+	uint32 n = nSamples;
+
+	if (g_bLastInPresent)
+	{
+		int x1_l = g_nLastRvbIn_xl, x1_r = g_nLastRvbIn_xr;
+		int x2_l = pWet[0], x2_r = pWet[1];
+		x1_l = (x1_l+x2_l)>>13;
+		x1_r = (x1_r+x2_r)>>13;
+		y1_l = x1_l + (((x1_l - y1_l)*lowpass)>>15);
+		y1_r = x1_r + (((x1_r - y1_r)*lowpass)>>15);
+		pWet[0] = y1_l;
+		pWet[1] = y1_r;
+		pWet+=2;
+		n--;
+		nOutSamples = 1;
+		g_bLastInPresent = false;
+	}
+	if (n & 1)
+	{
+		n--;
+		g_nLastRvbIn_xl = pWet[n*2];
+		g_nLastRvbIn_xr = pWet[n*2+1];
+		g_bLastInPresent = true;
+	}
+	n >>= 1;
+	for (uint32 i=0; i<n; i++)
+	{
+		int x1_l = pWet[i*4];
+		int x2_l = pWet[i*4+2];
+		x1_l = (x1_l+x2_l)>>13;
+		int x1_r = pWet[i*4+1];
+		int x2_r = pWet[i*4+3];
+		x1_r = (x1_r+x2_r)>>13;
+		y1_l = x1_l + (((x1_l - y1_l)*lowpass)>>15);
+		y1_r = x1_r + (((x1_r - y1_r)*lowpass)>>15);
+		pWet[i*2] = y1_l;
+		pWet[i*2+1] = y1_r;
+	}
+	g_nLastRvbIn_yl = y1_l;
+	g_nLastRvbIn_yr = y1_r;
+	return nOutSamples + n;
+}
+
+
+uint32 CReverb::ReverbProcessPreFiltering1x(int32 * MPT_RESTRICT pWet, uint32 nSamples)
+{
+	int lowpass = g_RefDelay.nCoeffs.c.l;
+	int y1_l = g_nLastRvbIn_yl, y1_r = g_nLastRvbIn_yr;
+
+	for (uint32 i=0; i<nSamples; i++)
+	{
+		int x_l = pWet[i*2] >> 12;
+		int x_r = pWet[i*2+1] >> 12;
+		y1_l = x_l + (((x_l - y1_l)*lowpass)>>15);
+		y1_r = x_r + (((x_r - y1_r)*lowpass)>>15);
+		pWet[i*2] = y1_l;
+		pWet[i*2+1] = y1_r;
+	}
+	g_nLastRvbIn_yl = y1_l;
+	g_nLastRvbIn_yr = y1_r;
+	return nSamples;
+}
+
+
+void CReverb::ReverbProcessPostFiltering2x(const int32 * MPT_RESTRICT pRvb, int32 * MPT_RESTRICT pDry, uint32 nSamples)
+{
+	uint32 n0 = nSamples, n;
+	int x1_l = g_nLastRvbOut_xl, x1_r = g_nLastRvbOut_xr;
+
+	if (g_bLastOutPresent)
+	{
+		pDry[0] += x1_l;
+		pDry[1] += x1_r;
+		pDry += 2;
+		n0--;
+		g_bLastOutPresent = false;
+	}
+	n  = n0 >> 1;
+	for (uint32 i=0; i<n; i++)
+	{
+		int x_l = pRvb[i*2], x_r = pRvb[i*2+1];
+		pDry[i*4] += (x_l + x1_l)>>1;
+		pDry[i*4+1] += (x_r + x1_r)>>1;
+		pDry[i*4+2] += x_l;
+		pDry[i*4+3] += x_r;
+		x1_l = x_l;
+		x1_r = x_r;
+	}
+	if (n0 & 1)
+	{
+		int x_l = pRvb[n*2], x_r = pRvb[n*2+1];
+		pDry[n*4] += (x_l + x1_l)>>1;
+		pDry[n*4+1] += (x_r + x1_r)>>1;
+		x1_l = x_l;
+		x1_r = x_r;
+		g_bLastOutPresent = true;
+	}
+	g_nLastRvbOut_xl = x1_l;
+	g_nLastRvbOut_xr = x1_r;
+}
+
+
+#define DCR_AMOUNT		9
+
+// Stereo Add + DC removal
+void CReverb::ReverbProcessPostFiltering1x(const int32 * MPT_RESTRICT pRvb, int32 * MPT_RESTRICT pDry, uint32 nSamples)
+{
+#ifdef ENABLE_MMX
+	if(GetProcSupport() & PROCSUPPORT_MMX)
+	{
+		__m64 nDCRRvb_Y1 = Load64MMX(gnDCRRvb_Y1);
+		__m64 nDCRRvb_X1 = Load64MMX(gnDCRRvb_X1);
+		__m64 in = _mm_set1_pi32(0);
+		while(nSamples--)
+		{
+			in = Load64MMX(pRvb);
+			pRvb += 2;
+			// x(n-1) - x(n)
+			__m64 diff = _mm_sub_pi32(nDCRRvb_X1, in);
+			nDCRRvb_X1 = _mm_add_pi32(nDCRRvb_Y1, _mm_sub_pi32(_mm_srai_pi32(diff, DCR_AMOUNT + 1), diff));
+			__m64 out = _mm_add_pi32(Load64MMX(pDry), nDCRRvb_X1);
+			nDCRRvb_Y1 = _mm_sub_pi32(nDCRRvb_X1, _mm_srai_pi32(nDCRRvb_X1, DCR_AMOUNT));
+			nDCRRvb_X1 = in;
+			Store64MMX(pDry, out);
+			pDry += 2;
+		}
+		Store64MMX(gnDCRRvb_X1, in);
+		Store64MMX(gnDCRRvb_Y1, nDCRRvb_Y1);
+		_mm_empty();
+		return;
+	}
+#endif
+	int32 X1L = gnDCRRvb_X1[0], X1R = gnDCRRvb_X1[1];
+	int32 Y1L = gnDCRRvb_Y1[0], Y1R = gnDCRRvb_Y1[1];
+	int32 inL = 0, inR = 0;
+	while(nSamples--)
+	{
+		inL = pRvb[0];
+		inR = pRvb[1];
+		pRvb += 2;
+		int32 outL = pDry[0], outR = pDry[1];
+
+		// x(n-1) - x(n)
+		X1L -= inL;
+		X1R -= inR;
+		X1L = X1L / (1 << (DCR_AMOUNT + 1)) - X1L;
+		X1R = X1R / (1 << (DCR_AMOUNT + 1)) - X1R;
+		Y1L += X1L;
+		Y1R += X1R;
+		// add to dry mix
+		outL += Y1L;
+		outR += Y1R;
+		Y1L -= Y1L / (1 << DCR_AMOUNT);
+		Y1R -= Y1R / (1 << DCR_AMOUNT);
+		X1L = inL;
+		X1R = inR;
+
+		pDry[0] = outL;
+		pDry[1] = outR;
+		pDry += 2;
+	}
+	gnDCRRvb_Y1[0] = Y1L;
+	gnDCRRvb_Y1[1] = Y1R;
+	gnDCRRvb_X1[0] = inL;
+	gnDCRRvb_X1[1] = inR;
+}
+
+
+void CReverb::ReverbDCRemoval(int32 * MPT_RESTRICT pBuffer, uint32 nSamples)
+{
+#ifdef ENABLE_MMX
+	if(GetProcSupport() & PROCSUPPORT_MMX)
+	{
+		__m64 nDCRRvb_Y1 = Load64MMX(gnDCRRvb_Y1);
+		__m64 nDCRRvb_X1 = Load64MMX(gnDCRRvb_X1);
+		while(nSamples--)
+		{
+			__m64 in = Load64MMX(pBuffer);
+			__m64 diff = _mm_sub_pi32(nDCRRvb_X1, in);
+			__m64 out = _mm_add_pi32(nDCRRvb_Y1, _mm_sub_pi32(_mm_srai_pi32(diff, DCR_AMOUNT + 1), diff));
+			Store64MMX(pBuffer, out);
+			pBuffer += 2;
+			nDCRRvb_Y1 = _mm_sub_pi32(out, _mm_srai_pi32(out, DCR_AMOUNT));
+			nDCRRvb_X1 = in;
+		}
+		Store64MMX(gnDCRRvb_X1, nDCRRvb_X1);
+		Store64MMX(gnDCRRvb_Y1, nDCRRvb_Y1);
+		_mm_empty();
+		return;
+	}
+#endif
+	int32 X1L = gnDCRRvb_X1[0], X1R = gnDCRRvb_X1[1];
+	int32 Y1L = gnDCRRvb_Y1[0], Y1R = gnDCRRvb_Y1[1];
+	int32 inL = 0, inR = 0;
+	while(nSamples--)
+	{
+		inL = pBuffer[0];
+		inR = pBuffer[1];
+		// x(n-1) - x(n)
+		X1L -= inL;
+		X1R -= inR;
+		X1L = X1L / (1 << (DCR_AMOUNT + 1)) - X1L;
+		X1R = X1R / (1 << (DCR_AMOUNT + 1)) - X1R;
+		Y1L += X1L;
+		Y1R += X1R;
+		pBuffer[0] = Y1L;
+		pBuffer[1] = Y1R;
+		pBuffer += 2;
+		Y1L -= Y1L / (1 << DCR_AMOUNT);
+		Y1R -= Y1R / (1 << DCR_AMOUNT);
+		X1L = inL;
+		X1R = inR;
+	}
+	gnDCRRvb_Y1[0] = Y1L;
+	gnDCRRvb_Y1[1] = Y1R;
+	gnDCRRvb_X1[0] = inL;
+	gnDCRRvb_X1[1] = inR;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Pre-Delay:
+//
+// 1. Saturate and low-pass the reverb input (stage 2 of roomHF)
+// 2. Process pre-diffusion
+// 3. Insert the result in the reflections delay buffer
+//
+
+// Save some typing
+static MPT_FORCEINLINE int32 Clamp16(int32 x) { return Clamp(x, int16_min, int16_max); }
+
+void CReverb::ProcessPreDelay(SWRvbRefDelay * MPT_RESTRICT pPreDelay, const int32 * MPT_RESTRICT pIn, uint32 nSamples)
+{
+	uint32 preDifPos = pPreDelay->nPreDifPos;
+	uint32 delayPos = pPreDelay->nDelayPos - 1;
+#ifdef ENABLE_SSE2
+	if(GetProcSupport() & PROCSUPPORT_SSE2)
+	{
+		__m128i coeffs = _mm_cvtsi32_si128(pPreDelay->nCoeffs.lr);
+		__m128i history = _mm_cvtsi32_si128(pPreDelay->History.lr);
+		__m128i preDifCoeffs = _mm_cvtsi32_si128(pPreDelay->nPreDifCoeffs.lr);
+		while(nSamples--)
+		{
+			__m128i in32 = Load64SSE(pIn);					// 16-bit unsaturated reverb input [  r  |  l  ]
+			__m128i inSat = _mm_packs_epi32(in32, in32);	// [ r | l | r | l ] (16-bit saturated)
+			pIn += 2;
+			// Low-pass
+			__m128i lp = _mm_mulhi_epi16(_mm_subs_epi16(history, inSat), coeffs);
+			__m128i preDif = _mm_cvtsi32_si128(pPreDelay->PreDifBuffer[preDifPos].lr);
+			history = _mm_adds_epi16(_mm_adds_epi16(lp, lp), inSat);
+			// Pre-Diffusion
+			preDifPos = (preDifPos + 1) & SNDMIX_PREDIFFUSION_DELAY_MASK;
+			delayPos = (delayPos + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			__m128i preDif2 = _mm_subs_epi16(history, _mm_mulhi_epi16(preDif, preDifCoeffs));
+			pPreDelay->PreDifBuffer[preDifPos].lr = _mm_cvtsi128_si32(preDif2);
+			pPreDelay->RefDelayBuffer[delayPos].lr = _mm_cvtsi128_si32(_mm_adds_epi16(_mm_mulhi_epi16(preDifCoeffs, preDif2), preDif));
+		}
+		pPreDelay->nPreDifPos = preDifPos;
+		pPreDelay->History.lr = _mm_cvtsi128_si32(history);
+		return;
+	}
+#endif
+#ifdef ENABLE_MMX
+	if(GetProcSupport() & PROCSUPPORT_MMX)
+	{
+		__m64 coeffs = _mm_cvtsi32_si64(pPreDelay->nCoeffs.lr);
+		__m64 history = _mm_cvtsi32_si64(pPreDelay->History.lr);
+		__m64 preDifCoeffs = _mm_cvtsi32_si64(pPreDelay->nPreDifCoeffs.lr);
+		while(nSamples--)
+		{
+			__m64 in32 = Load64MMX(pIn);				// 16-bit unsaturated reverb input [  r  |  l  ]
+			__m64 inSat = _mm_packs_pi32(in32, in32);	// [ r | l | r | l ] (16-bit saturated)
+			pIn += 2;
+			// Low-pass
+			__m64 lp = _mm_mulhi_pi16(_mm_subs_pi16(history, inSat), coeffs);
+			__m64 preDif = _mm_cvtsi32_si64(pPreDelay->PreDifBuffer[preDifPos].lr);
+			history = _mm_adds_pi16(_mm_adds_pi16(lp, lp), inSat);
+			// Pre-Diffusion
+			preDifPos = (preDifPos + 1) & SNDMIX_PREDIFFUSION_DELAY_MASK;
+			delayPos = (delayPos + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			__m64 preDif2 = _mm_subs_pi16(history, _mm_mulhi_pi16(preDif, preDifCoeffs));
+			pPreDelay->PreDifBuffer[preDifPos].lr = _mm_cvtsi64_si32(preDif2);
+			pPreDelay->RefDelayBuffer[delayPos].lr = _mm_cvtsi64_si32(_mm_adds_pi16(_mm_mulhi_pi16(preDifCoeffs, preDif2), preDif));
+		}
+		pPreDelay->nPreDifPos = preDifPos;
+		pPreDelay->History.lr = _mm_cvtsi64_si32(history);
+		_mm_empty();
+		return;
+	}
+#endif
+	const int32 coeffsL = pPreDelay->nCoeffs.c.l, coeffsR = pPreDelay->nCoeffs.c.r;
+	const int32 preDifCoeffsL = pPreDelay->nPreDifCoeffs.c.l, preDifCoeffsR = pPreDelay->nPreDifCoeffs.c.r;
+	int16 historyL = pPreDelay->History.c.l, historyR = pPreDelay->History.c.r;
+	while(nSamples--)
+	{
+		int32 inL = Clamp16(pIn[0]);
+		int32 inR = Clamp16(pIn[1]);
+		pIn += 2;
+		// Low-pass
+		int32 lpL = (Clamp16(historyL - inL) * coeffsL) / 65536;
+		int32 lpR = (Clamp16(historyR - inR) * coeffsR) / 65536;
+		historyL = mpt::saturate_cast<int16>(Clamp16(lpL + lpL) + inL);
+		historyR = mpt::saturate_cast<int16>(Clamp16(lpR + lpR) + inR);
+		// Pre-Diffusion
+		int32 preDifL = pPreDelay->PreDifBuffer[preDifPos].c.l;
+		int32 preDifR = pPreDelay->PreDifBuffer[preDifPos].c.r;
+		preDifPos = (preDifPos + 1) & SNDMIX_PREDIFFUSION_DELAY_MASK;
+		delayPos = (delayPos + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+		int16 preDif2L = mpt::saturate_cast<int16>(historyL - preDifL * preDifCoeffsL / 65536);
+		int16 preDif2R = mpt::saturate_cast<int16>(historyR - preDifR * preDifCoeffsR / 65536);
+		pPreDelay->PreDifBuffer[preDifPos].c.l = preDif2L;
+		pPreDelay->PreDifBuffer[preDifPos].c.r = preDif2R;
+		pPreDelay->RefDelayBuffer[delayPos].c.l = mpt::saturate_cast<int16>(preDifCoeffsL * preDif2L / 65536 + preDifL);
+		pPreDelay->RefDelayBuffer[delayPos].c.r = mpt::saturate_cast<int16>(preDifCoeffsR * preDif2R / 65536 + preDifR);
+	}
+	pPreDelay->nPreDifPos = preDifPos;
+	pPreDelay->History.c.l = historyL;
+	pPreDelay->History.c.r = historyR;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// ProcessReflections:
+// First stage:
+//	- process 4 reflections, output to pRefOut
+//	- output results to pRefOut
+// Second stage:
+//	- process another 3 reflections
+//	- sum with pRefOut
+//	- apply reflections master gain and accumulate in the given output
+//
+
+void CReverb::ProcessReflections(SWRvbRefDelay * MPT_RESTRICT pPreDelay, LR16 * MPT_RESTRICT pRefOut, int32 * MPT_RESTRICT pOut, uint32 nSamples)
+{
+#ifdef ENABLE_SSE2
+	if(GetProcSupport() & PROCSUPPORT_SSE2)
+	{
+		union
+		{
+			__m128i xmm;
+			int16 i[8];
+		} pos;
+		const LR16 *refDelayBuffer = pPreDelay->RefDelayBuffer;
+#define GETDELAY(x) static_cast<int16>(pPreDelay->Reflections[x].Delay)
+		__m128i delayPos = _mm_set_epi16(GETDELAY(7), GETDELAY(6), GETDELAY(5), GETDELAY(4), GETDELAY(3), GETDELAY(2), GETDELAY(1), GETDELAY(0));
+#undef GETDELAY
+		delayPos = _mm_sub_epi16(_mm_set1_epi16(static_cast<int16>(pPreDelay->nDelayPos - 1)), delayPos);
+		__m128i gain12 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[0].Gains), Load64SSE(pPreDelay->Reflections[1].Gains));
+		__m128i gain34 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[2].Gains), Load64SSE(pPreDelay->Reflections[3].Gains));
+		__m128i gain56 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[4].Gains), Load64SSE(pPreDelay->Reflections[5].Gains));
+		__m128i gain78 = _mm_unpacklo_epi64(Load64SSE(pPreDelay->Reflections[6].Gains), Load64SSE(pPreDelay->Reflections[7].Gains));
+		// For 28-bit final output: 16+15-3 = 28
+		__m128i refGain = _mm_srai_epi32(_mm_set_epi32(0, 0, pPreDelay->ReflectionsGain.c.r, pPreDelay->ReflectionsGain.c.l), 3);
+		__m128i delayInc = _mm_set1_epi16(1), delayMask = _mm_set1_epi16(SNDMIX_REFLECTIONS_DELAY_MASK);
+		while(nSamples--)
+		{
+			delayPos = _mm_and_si128(_mm_add_epi16(delayInc, delayPos), delayMask);
+			_mm_storeu_si128(&pos.xmm, delayPos);
+			__m128i ref12 = _mm_set_epi32(refDelayBuffer[pos.i[1]].lr, refDelayBuffer[pos.i[1]].lr, refDelayBuffer[pos.i[0]].lr, refDelayBuffer[pos.i[0]].lr);
+			__m128i ref34 = _mm_set_epi32(refDelayBuffer[pos.i[3]].lr, refDelayBuffer[pos.i[3]].lr, refDelayBuffer[pos.i[2]].lr, refDelayBuffer[pos.i[2]].lr);
+			__m128i ref56 = _mm_set_epi32(refDelayBuffer[pos.i[5]].lr, refDelayBuffer[pos.i[5]].lr, refDelayBuffer[pos.i[4]].lr, refDelayBuffer[pos.i[4]].lr);
+			__m128i ref78 = _mm_set_epi32(0,                           0,                           refDelayBuffer[pos.i[6]].lr, refDelayBuffer[pos.i[6]].lr);
+			// First stage
+			__m128i refOut1 = _mm_add_epi32(_mm_madd_epi16(ref12, gain12), _mm_madd_epi16(ref34, gain34));
+			refOut1 = _mm_srai_epi32(_mm_add_epi32(refOut1, _mm_shuffle_epi32(refOut1, _MM_SHUFFLE(1, 0, 3, 2))), 15);
+
+			// Second stage
+			__m128i refOut2 = _mm_add_epi32(_mm_madd_epi16(ref56, gain56), _mm_madd_epi16(ref78, gain78));
+			refOut2 = _mm_srai_epi32(_mm_add_epi32(refOut2, _mm_shuffle_epi32(refOut2, _MM_SHUFFLE(1, 0, 3, 2))), 15);
+
+			// Saturate to 16-bit and sum stages
+			__m128i refOut = _mm_adds_epi16(_mm_packs_epi32(refOut1, refOut1), _mm_packs_epi32(refOut2, refOut2));
+			pRefOut->lr = _mm_cvtsi128_si32(refOut);
+			pRefOut++;
+
+			__m128i out = _mm_madd_epi16(_mm_unpacklo_epi16(refOut, refOut), refGain);	// Apply reflections gain
+			// At this, point, this is the only output of the reverb
+			Store64SSE(pOut, out);
+			pOut += 2;
+		}
+		return;
+	}
+#endif
+#ifdef ENABLE_MMX
+	if(GetProcSupport() & PROCSUPPORT_MMX)
+	{
+		// First stage
+		uint32 numSamples = nSamples;
+		const LR16 *refDelayBuffer = pPreDelay->RefDelayBuffer;
+		int pos1 = pPreDelay->nDelayPos - pPreDelay->Reflections[0].Delay - 1;
+		int pos2 = pPreDelay->nDelayPos - pPreDelay->Reflections[1].Delay - 1;
+		int pos3 = pPreDelay->nDelayPos - pPreDelay->Reflections[2].Delay - 1;
+		int pos4 = pPreDelay->nDelayPos - pPreDelay->Reflections[3].Delay - 1;
+		__m64 gain1 = Load64MMX(pPreDelay->Reflections[0].Gains);
+		__m64 gain2 = Load64MMX(pPreDelay->Reflections[1].Gains);
+		__m64 gain3 = Load64MMX(pPreDelay->Reflections[2].Gains);
+		__m64 gain4 = Load64MMX(pPreDelay->Reflections[3].Gains);
+		while(numSamples--)
+		{
+			pos1 = (pos1 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			pos2 = (pos2 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			pos3 = (pos3 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			pos4 = (pos4 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			__m64 ref1 = _mm_cvtsi32_si64(refDelayBuffer[pos1].lr);	// [0 | 0 | r | l ]
+			__m64 ref2 = _mm_cvtsi32_si64(refDelayBuffer[pos2].lr);
+			__m64 ref3 = _mm_cvtsi32_si64(refDelayBuffer[pos3].lr);
+			__m64 ref4 = _mm_cvtsi32_si64(refDelayBuffer[pos4].lr);
+			__m64 refOut = _mm_srai_pi32(_mm_add_pi32(
+				_mm_add_pi32(_mm_madd_pi16(_mm_unpacklo_pi32(ref1, ref1), gain1), _mm_madd_pi16(_mm_unpacklo_pi32(ref2, ref2), gain2)),
+				_mm_add_pi32(_mm_madd_pi16(_mm_unpacklo_pi32(ref3, ref3), gain3), _mm_madd_pi16(_mm_unpacklo_pi32(ref4, ref4), gain4))),
+				15);
+			pRefOut->lr = _mm_cvtsi64_si32(_mm_packs_pi32(refOut, refOut));
+			pRefOut++;
+		}
+
+		// Second stage
+		numSamples = nSamples;
+		pRefOut -= nSamples;
+
+		__m64 refGain = _mm_unpacklo_pi16(_mm_cvtsi32_si64(pPreDelay->ReflectionsGain.lr), _mm_cvtsi32_si64(0));	// [0 | g_r | 0 | g_l]
+		refGain = _mm_srai_pi32(refGain, 3);	// For 28-bit final output: 16+15-3 = 28
+		int pos5 = pPreDelay->nDelayPos - pPreDelay->Reflections[4].Delay - 1;
+		int pos6 = pPreDelay->nDelayPos - pPreDelay->Reflections[5].Delay - 1;
+		int pos7 = pPreDelay->nDelayPos - pPreDelay->Reflections[6].Delay - 1;
+		__m64 gain5 = Load64MMX(pPreDelay->Reflections[4].Gains);
+		__m64 gain6 = Load64MMX(pPreDelay->Reflections[5].Gains);
+		__m64 gain7 = Load64MMX(pPreDelay->Reflections[6].Gains);
+		while(numSamples--)
+		{
+			pos5 = (pos5 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			pos6 = (pos6 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			pos7 = (pos7 + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			__m64 ref5 = _mm_cvtsi32_si64(refDelayBuffer[pos5].lr);	// [0 | 0 | r | l ]
+			__m64 ref6 = _mm_cvtsi32_si64(refDelayBuffer[pos6].lr);
+			__m64 ref7 = _mm_cvtsi32_si64(refDelayBuffer[pos7].lr);
+			__m64 refPrev = _mm_cvtsi32_si64(pRefOut->lr);	// output of previous reflections
+			__m64 refOut = _mm_srai_pi32(_mm_add_pi32(
+				_mm_add_pi32(_mm_madd_pi16(_mm_unpacklo_pi32(ref5, ref5), gain5), _mm_madd_pi16(_mm_unpacklo_pi32(ref7, ref7), gain7)),
+				_mm_madd_pi16(_mm_unpacklo_pi32(ref6, ref6), gain6)),
+				15);
+			refOut = _mm_adds_pi16(_mm_packs_pi32(refOut, refOut), refPrev);
+			pRefOut->lr = _mm_cvtsi64_si32(refOut);	// late reverb stereo input
+			pRefOut++;
+			__m64 out = _mm_madd_pi16(_mm_unpacklo_pi16(refOut, refOut), refGain);	// Apply reflections gain
+			// At this, point, this is the only output of the reverb
+			Store64MMX(pOut, out);
+			pOut += 2;
+		}
+		_mm_empty();
+		return;
+	}
+#endif
+	int pos[7];
+	for(int i = 0; i < 7; i++)
+		pos[i] = pPreDelay->nDelayPos - pPreDelay->Reflections[i].Delay - 1;
+	// For 28-bit final output: 16+15-3 = 28
+	int16 refGain = pPreDelay->ReflectionsGain.c.l / (1 << 3);
+	while(nSamples--)
+	{
+		// First stage
+		int32 refOutL = 0, refOutR = 0;
+		for(int i = 0; i < 4; i++)
+		{
+			pos[i] = (pos[i] + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			int16 refL = pPreDelay->RefDelayBuffer[pos[i]].c.l, refR = pPreDelay->RefDelayBuffer[pos[i]].c.r;
+			refOutL += refL * pPreDelay->Reflections[i].Gains[0].c.l + refR * pPreDelay->Reflections[i].Gains[0].c.r;
+			refOutR += refL * pPreDelay->Reflections[i].Gains[1].c.l + refR * pPreDelay->Reflections[i].Gains[1].c.r;
+		}
+		int16 stage1l = mpt::saturate_cast<int16>(refOutL / (1 << 15));
+		int16 stage1r = mpt::saturate_cast<int16>(refOutR / (1 << 15));
+		// Second stage
+		refOutL = 0;
+		refOutR = 0;
+		for(int i = 4; i < 7; i++)
+		{
+			pos[i] = (pos[i] + 1) & SNDMIX_REFLECTIONS_DELAY_MASK;
+			int16 refL = pPreDelay->RefDelayBuffer[pos[i]].c.l, refR = pPreDelay->RefDelayBuffer[pos[i]].c.r;
+			refOutL += refL * pPreDelay->Reflections[i].Gains[0].c.l + refR * pPreDelay->Reflections[i].Gains[0].c.r;
+			refOutR += refL * pPreDelay->Reflections[i].Gains[1].c.l + refR * pPreDelay->Reflections[i].Gains[1].c.r;
+		}
+		pOut[0] = (pRefOut->c.l = mpt::saturate_cast<int16>(stage1l + refOutL / (1 << 15))) * refGain;
+		pOut[1] = (pRefOut->c.r = mpt::saturate_cast<int16>(stage1r + refOutR / (1 << 15))) * refGain;
+		pRefOut++;
+		pOut += 2;
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Late reverberation (with SW reflections)
+//
+
+void CReverb::ProcessLateReverb(SWLateReverb * MPT_RESTRICT pReverb, LR16 * MPT_RESTRICT pRefOut, int32 * MPT_RESTRICT pMixOut, uint32 nSamples)
+{
+	// Calculate delay line offset from current delay position
+	#define DELAY_OFFSET(x) ((delayPos - (x)) & RVBDLY_MASK)
+
+#ifdef ENABLE_SSE2
+	if(GetProcSupport() & PROCSUPPORT_SSE2)
+	{
+		int delayPos = pReverb->nDelayPos & RVBDLY_MASK;
+		__m128i rvbOutGains = Load64SSE(pReverb->RvbOutGains);
+		__m128i difCoeffs = Load64SSE(pReverb->nDifCoeffs);
+		__m128i decayLP = Load64SSE(pReverb->nDecayLP);
+		__m128i lpHistory = Load64SSE(pReverb->LPHistory);
+		while(nSamples--)
+		{
+			__m128i refIn = _mm_cvtsi32_si128(pRefOut->lr);	// 16-bit stereo input
+			pRefOut++;
+
+			__m128i delay2 = _mm_unpacklo_epi32(
+				_mm_cvtsi32_si128(pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].lr),
+				_mm_cvtsi32_si128(pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].lr));
+
+			// Unsigned to avoid sign extension
+			uint16 diff1L = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1L_LEN)].c.l;
+			uint16 diff1R = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1R_LEN)].c.r;
+			int32 diffusion1 = diff1L | (diff1R << 16);	// diffusion1 history
+
+			uint16 diff2L = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2L_LEN)].c.l;
+			uint16 diff2R = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2R_LEN)].c.r;
+			int32 diffusion2 = diff2L | (diff2R << 16);	// diffusion2 history
+
+			__m128i lpDecay = _mm_mulhi_epi16(_mm_subs_epi16(lpHistory, delay2), decayLP);
+			lpHistory = _mm_adds_epi16(_mm_adds_epi16(lpDecay, lpDecay), delay2);	// Low-passed decay
+
+			// Apply decay gain
+			__m128i histDecay = _mm_srai_epi32(_mm_madd_epi16(Load64SSE(pReverb->nDecayDC), lpHistory), 15);
+			__m128i histDecayPacked = _mm_shuffle_epi32(_mm_packs_epi32(histDecay, histDecay), _MM_SHUFFLE(2, 0, 2, 0));
+			__m128i histDecayIn = _mm_adds_epi16(_mm_shuffle_epi32(_mm_packs_epi32(histDecay, histDecay), _MM_SHUFFLE(2, 0, 2, 0)), _mm_srai_epi16(_mm_unpacklo_epi32(refIn, refIn), 2));
+			__m128i histDecayInDiff = _mm_subs_epi16(histDecayIn, _mm_mulhi_epi16(_mm_cvtsi32_si128(diffusion1), difCoeffs));
+			pReverb->Diffusion1[delayPos].lr = _mm_cvtsi128_si32(histDecayInDiff);
+
+			__m128i delay1Out = _mm_adds_epi16(_mm_mulhi_epi16(difCoeffs, histDecayInDiff), _mm_cvtsi32_si128(diffusion1));
+			// Insert the diffusion output in the reverb delay line
+			pReverb->Delay1[delayPos].lr = _mm_cvtsi128_si32(delay1Out);
+			__m128i histDecayInDelay = _mm_adds_epi16(histDecayIn, _mm_unpacklo_epi32(delay1Out, delay1Out));
+
+			// Input to second diffuser
+			__m128i delay1 = _mm_unpacklo_epi32(
+				_mm_cvtsi32_si128(pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].lr),
+				_mm_cvtsi32_si128(pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].lr));
+
+			__m128i delay1Gains = _mm_srai_epi32(_mm_madd_epi16(delay1, Load64SSE(pReverb->Dif2InGains)), 15);
+			__m128i delay1GainsSat = _mm_shuffle_epi32(_mm_packs_epi32(delay1Gains, delay1Gains), _MM_SHUFFLE(2, 0, 2, 0));
+			__m128i histDelay1 = _mm_subs_epi16(_mm_adds_epi16(histDecayInDelay, delay1), delay1GainsSat);	// accumulate with reverb output
+			__m128i diff2out = _mm_subs_epi16(delay1GainsSat, _mm_mulhi_epi16(_mm_cvtsi32_si128(diffusion2), difCoeffs));
+			__m128i diff2outCoeffs = _mm_mulhi_epi16(difCoeffs, diff2out);
+			pReverb->Diffusion2[delayPos].lr = _mm_cvtsi128_si32(diff2out);
+
+			__m128i mixOut = Load64SSE(pMixOut);
+			__m128i delay2out = _mm_adds_epi16(diff2outCoeffs, _mm_cvtsi32_si128(diffusion2));
+			pReverb->Delay2[delayPos].lr = _mm_cvtsi128_si32(delay2out);
+			delayPos = (delayPos + 1) & RVBDLY_MASK;
+			// Accumulate with reverb output
+			__m128i out = _mm_add_epi32(_mm_madd_epi16(_mm_adds_epi16(histDelay1, delay2out), rvbOutGains), mixOut);
+			Store64SSE(pMixOut, out);
+			pMixOut += 2;
+		}
+		Store64SSE(pReverb->LPHistory, lpHistory);
+		pReverb->nDelayPos = delayPos;
+		return;
+	}
+#endif
+#ifdef ENABLE_MMX
+	if(GetProcSupport() & PROCSUPPORT_MMX)
+	{
+		int delayPos = pReverb->nDelayPos & RVBDLY_MASK;
+		__m64 rvbOutGains = Load64MMX(pReverb->RvbOutGains);
+		__m64 difCoeffs = Load64MMX(pReverb->nDifCoeffs);
+		__m64 decayLP = Load64MMX(pReverb->nDecayLP);
+		__m64 lpHistory = Load64MMX(pReverb->LPHistory);
+		while(nSamples--)
+		{
+			__m64 refIn = _mm_cvtsi32_si64(pRefOut->lr);	// 16-bit stereo input
+			pRefOut++;
+
+			__m64 delay2 = _mm_unpacklo_pi32(
+				_mm_cvtsi32_si64(pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].lr),
+				_mm_cvtsi32_si64(pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].lr));
+
+			// Unsigned to avoid sign extension
+			uint16 diff1L = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1L_LEN)].c.l;
+			uint16 diff1R = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1R_LEN)].c.r;
+			int32 diffusion1 = diff1L | (diff1R << 16);	// diffusion1 history
+
+			uint16 diff2L = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2L_LEN)].c.l;
+			uint16 diff2R = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2R_LEN)].c.r;
+			int32 diffusion2 = diff2L | (diff2R << 16);	// diffusion2 history
+
+			__m64 lpDecay = _mm_mulhi_pi16(_mm_subs_pi16(lpHistory, delay2), decayLP);
+			lpHistory = _mm_adds_pi16(_mm_adds_pi16(lpDecay, lpDecay), delay2);	// Low-passed decay
+
+			// Apply decay gain
+			__m64 histDecay = _mm_srai_pi32(_mm_madd_pi16(Load64MMX(pReverb->nDecayDC), lpHistory), 15);
+			__m64 histDecayIn = _mm_adds_pi16(_mm_packs_pi32(histDecay, histDecay), _mm_srai_pi16(_mm_unpacklo_pi32(refIn, refIn), 2));
+			__m64 histDecayInDiff = _mm_subs_pi16(histDecayIn, _mm_mulhi_pi16(_mm_cvtsi32_si64(diffusion1), difCoeffs));
+			pReverb->Diffusion1[delayPos].lr = _mm_cvtsi64_si32(histDecayInDiff);
+
+			__m64 delay1Out = _mm_adds_pi16(_mm_mulhi_pi16(difCoeffs, histDecayInDiff), _mm_cvtsi32_si64(diffusion1));
+			// Insert the diffusion output in the reverb delay line
+			pReverb->Delay1[delayPos].lr = _mm_cvtsi64_si32(delay1Out);
+			__m64 histDecayInDelay = _mm_adds_pi16(histDecayIn, _mm_unpacklo_pi32(delay1Out, delay1Out));
+
+			// Input to second diffuser
+			__m64 delay1 = _mm_unpacklo_pi32(
+				_mm_cvtsi32_si64(pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].lr),
+				_mm_cvtsi32_si64(pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].lr));
+
+			__m64 delay1Gains = _mm_srai_pi32(_mm_madd_pi16(delay1, Load64MMX(pReverb->Dif2InGains)), 15);
+			__m64 delay1GainsSat = _mm_packs_pi32(delay1Gains, delay1Gains);
+			__m64 histDelay1 = _mm_subs_pi16(_mm_adds_pi16(histDecayInDelay, delay1), delay1GainsSat);	// accumulate with reverb output
+			__m64 diff2out = _mm_subs_pi16(delay1GainsSat, _mm_mulhi_pi16(_mm_cvtsi32_si64(diffusion2), difCoeffs));
+			__m64 diff2outCoeffs = _mm_mulhi_pi16(difCoeffs, diff2out);
+			pReverb->Diffusion2[delayPos].lr = _mm_cvtsi64_si32(diff2out);
+
+			__m64 mixOut = Load64MMX(pMixOut);
+			__m64 delay2out = _mm_adds_pi16(diff2outCoeffs, _mm_cvtsi32_si64(diffusion2));
+			pReverb->Delay2[delayPos].lr = _mm_cvtsi64_si32(delay2out);
+			delayPos = (delayPos + 1) & RVBDLY_MASK;
+			// Accumulate with reverb output
+			__m64 out = _mm_add_pi32(_mm_madd_pi16(_mm_adds_pi16(histDelay1, delay2out), rvbOutGains), mixOut);
+			Store64MMX(pMixOut, out);
+			pMixOut += 2;
+		}
+		Store64MMX(&pReverb->LPHistory[0].lr, lpHistory);
+		pReverb->nDelayPos = delayPos;
+		_mm_empty();
+		return;
+	}
+#endif
+	int delayPos = pReverb->nDelayPos & RVBDLY_MASK;
+	while(nSamples--)
+	{
+		int16 refInL = pRefOut->c.l, refInR = pRefOut->c.r;
+		pRefOut++;
+
+		int32 delay2LL = pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].c.l, delay2LR = pReverb->Delay2[DELAY_OFFSET(RVBDLY2L_LEN)].c.r;
+		int32 delay2RL = pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].c.l, delay2RR = pReverb->Delay2[DELAY_OFFSET(RVBDLY2R_LEN)].c.r;
+
+		int32 diff1L = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1L_LEN)].c.l;
+		int32 diff1R = pReverb->Diffusion1[DELAY_OFFSET(RVBDIF1R_LEN)].c.r;
+
+		int32 diff2L = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2L_LEN)].c.l;
+		int32 diff2R = pReverb->Diffusion2[DELAY_OFFSET(RVBDIF2R_LEN)].c.r;
+
+		int32 lpDecayLL = Clamp16(pReverb->LPHistory[0].c.l - delay2LL) * pReverb->nDecayLP[0].c.l / 65536;
+		int32 lpDecayLR = Clamp16(pReverb->LPHistory[0].c.r - delay2LR) * pReverb->nDecayLP[0].c.r / 65536;
+		int32 lpDecayRL = Clamp16(pReverb->LPHistory[1].c.l - delay2RL) * pReverb->nDecayLP[1].c.l / 65536;
+		int32 lpDecayRR = Clamp16(pReverb->LPHistory[1].c.r - delay2RR) * pReverb->nDecayLP[1].c.r / 65536;
+		// Low-passed decay
+		pReverb->LPHistory[0].c.l = mpt::saturate_cast<int16>(Clamp16(lpDecayLL + lpDecayLL) + delay2LL);
+		pReverb->LPHistory[0].c.r = mpt::saturate_cast<int16>(Clamp16(lpDecayLR + lpDecayLR) + delay2LR);
+		pReverb->LPHistory[1].c.l = mpt::saturate_cast<int16>(Clamp16(lpDecayRL + lpDecayRL) + delay2RL);
+		pReverb->LPHistory[1].c.r = mpt::saturate_cast<int16>(Clamp16(lpDecayRR + lpDecayRR) + delay2RR);
+
+		// Apply decay gain
+		int32 histDecayL = Clamp16((int32)pReverb->nDecayDC[0].c.l * pReverb->LPHistory[0].c.l / (1 << 15));
+		int32 histDecayR = Clamp16((int32)pReverb->nDecayDC[1].c.r * pReverb->LPHistory[1].c.r / (1 << 15));
+		int32 histDecayInL = Clamp16(histDecayL + refInL / 4);
+		int32 histDecayInR = Clamp16(histDecayR + refInR / 4);
+		int32 histDecayInDiffL = Clamp16(histDecayInL - diff1L * pReverb->nDifCoeffs[0].c.l / 65536);
+		int32 histDecayInDiffR = Clamp16(histDecayInR - diff1R * pReverb->nDifCoeffs[0].c.r / 65536);
+		pReverb->Diffusion1[delayPos].c.l = static_cast<int16>(histDecayInDiffL);
+		pReverb->Diffusion1[delayPos].c.r = static_cast<int16>(histDecayInDiffR);
+
+		int32 delay1L = Clamp16(pReverb->nDifCoeffs[0].c.l * histDecayInDiffL / 65536 + diff1L);
+		int32 delay1R = Clamp16(pReverb->nDifCoeffs[0].c.r * histDecayInDiffR / 65536 + diff1R);
+		// Insert the diffusion output in the reverb delay line
+		pReverb->Delay1[delayPos].c.l = static_cast<int16>(delay1L);
+		pReverb->Delay1[delayPos].c.r = static_cast<int16>(delay1R);
+		int32 histDecayInDelayL = Clamp16(histDecayInL + delay1L);
+		int32 histDecayInDelayR = Clamp16(histDecayInR + delay1R);
+
+		// Input to second diffuser
+		int32 delay1LL = pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].c.l, delay1LR = pReverb->Delay1[DELAY_OFFSET(RVBDLY1L_LEN)].c.r;
+		int32 delay1RL = pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].c.l, delay1RR = pReverb->Delay1[DELAY_OFFSET(RVBDLY1R_LEN)].c.r;
+
+		int32 delay1GainsL = Clamp16((delay1LL * pReverb->Dif2InGains[0].c.l + delay1LR * pReverb->Dif2InGains[0].c.r) / (1 << 15));
+		int32 delay1GainsR = Clamp16((delay1RL * pReverb->Dif2InGains[1].c.l + delay1RR * pReverb->Dif2InGains[1].c.r) / (1 << 15));
+
+		// accumulate with reverb output
+		int32 histDelay1LL = Clamp16(Clamp16(histDecayInDelayL + delay1LL) - delay1GainsL);
+		int32 histDelay1LR = Clamp16(Clamp16(histDecayInDelayR + delay1LR) - delay1GainsR);
+		int32 histDelay1RL = Clamp16(Clamp16(histDecayInDelayL + delay1RL) - delay1GainsL);
+		int32 histDelay1RR = Clamp16(Clamp16(histDecayInDelayR + delay1RR) - delay1GainsR);
+		int32 diff2outL = Clamp16(delay1GainsL - diff2L * pReverb->nDifCoeffs[0].c.l / 65536);
+		int32 diff2outR = Clamp16(delay1GainsR - diff2R * pReverb->nDifCoeffs[0].c.r / 65536);
+		int32 diff2outCoeffsL = pReverb->nDifCoeffs[0].c.l * diff2outL / 65536;
+		int32 diff2outCoeffsR = pReverb->nDifCoeffs[0].c.r * diff2outR / 65536;
+		pReverb->Diffusion2[delayPos].c.l = static_cast<int16>(diff2outL);
+		pReverb->Diffusion2[delayPos].c.r = static_cast<int16>(diff2outR);
+
+		int32 delay2outL = Clamp16(diff2outCoeffsL + diff2L);
+		int32 delay2outR = Clamp16(diff2outCoeffsR + diff2R);
+		pReverb->Delay2[delayPos].c.l = static_cast<int16>(delay2outL);
+		pReverb->Delay2[delayPos].c.r = static_cast<int16>(delay2outR);
+		delayPos = (delayPos + 1) & RVBDLY_MASK;
+		// Accumulate with reverb output
+		pMixOut[0] += Clamp16(histDelay1LL + delay2outL) * pReverb->RvbOutGains[0].c.l + Clamp16(histDelay1LR + delay2outR) * pReverb->RvbOutGains[0].c.r;
+		pMixOut[1] += Clamp16(histDelay1RL + Clamp16(diff2outCoeffsL)) * pReverb->RvbOutGains[1].c.l + Clamp16(histDelay1RR + Clamp16(diff2outCoeffsR)) * pReverb->RvbOutGains[1].c.r;
+		pMixOut += 2;
+	}
+	pReverb->nDelayPos = delayPos;
+
+	#undef DELAY_OFFSET
+}
+
+
+#else
+
+
+MPT_MSVC_WORKAROUND_LNK4221(Reverb)
+
+
+#endif // NO_REVERB
+
+
+OPENMPT_NAMESPACE_END
+
diff --git a/sounddsp/Reverb.h b/sounddsp/Reverb.h
new file mode 100644
index 0000000..d018a9d
--- /dev/null
+++ b/sounddsp/Reverb.h
@@ -0,0 +1,280 @@
+/*
+ * Reverb.h
+ * --------
+ * Purpose: Mixing code for reverb.
+ * Notes  : Ugh... This should really be removed at some point.
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#ifndef NO_REVERB
+
+#include "../soundlib/Mixer.h"	// For MIXBUFFERSIZE
+
+OPENMPT_NAMESPACE_BEGIN
+
+////////////////////////////////////////////////////////////////////////
+// Reverberation
+
+#define NUM_REVERBTYPES			29
+
+const char *GetReverbPresetName(uint32 nPreset);
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// SW Reverb structures
+//
+
+// Length-1 (in samples) of the reflections delay buffer: 32K, 371ms at 22kHz
+#define SNDMIX_REFLECTIONS_DELAY_MASK	0x1fff
+#define SNDMIX_PREDIFFUSION_DELAY_MASK	0x7f	// 128 samples
+#define SNDMIX_REVERB_DELAY_MASK		0xfff	// 4K samples (92ms @ 44kHz)
+
+union LR16
+{
+	struct { int16 l, r; } c;
+	int32 lr;
+};
+
+struct SWRvbReflection
+{
+	uint32 Delay, DelayDest;
+	LR16   Gains[2];	// g_ll, g_rl, g_lr, g_rr
+};
+
+struct SWRvbRefDelay
+{
+	uint32 nDelayPos, nPreDifPos, nRefOutPos;
+	int32  lMasterGain;			// reflections linear master gain
+	LR16   nCoeffs;				// room low-pass coefficients
+	LR16   History;				// room low-pass history
+	LR16   nPreDifCoeffs;		// prediffusion coefficients
+	LR16   ReflectionsGain;		// master reflections gain
+	SWRvbReflection Reflections[8];	// Up to 8 SW Reflections
+	LR16   RefDelayBuffer[SNDMIX_REFLECTIONS_DELAY_MASK + 1]; // reflections delay buffer
+	LR16   PreDifBuffer[SNDMIX_PREDIFFUSION_DELAY_MASK + 1]; // pre-diffusion
+	LR16   RefOut[SNDMIX_REVERB_DELAY_MASK + 1]; // stereo output of reflections
+};
+
+
+// Late reverberation
+// Tank diffusers lengths
+#define RVBDIF1L_LEN		(149*2)	// 6.8ms
+#define RVBDIF1R_LEN		(223*2)	// 10.1ms
+#define RVBDIF2L_LEN		(421*2)	// 19.1ms
+#define RVBDIF2R_LEN		(647*2)	// 29.3ms
+// Tank delay lines lengths
+#define RVBDLY1L_LEN		(683*2)	// 30.9ms
+#define RVBDLY1R_LEN	    (811*2) // 36.7ms
+#define RVBDLY2L_LEN		(773*2)	// 35.1ms
+#define RVBDLY2R_LEN	    (1013*2) // 45.9ms
+// Tank delay lines mask
+#define RVBDLY_MASK			2047
+
+// Min/Max reflections delay
+#define RVBMINREFDELAY		96		// 96 samples
+#define RVBMAXREFDELAY		7500	// 7500 samples
+// Min/Max reverb delay
+#define RVBMINRVBDELAY		128		// 256 samples (11.6ms @ 22kHz)
+#define RVBMAXRVBDELAY		3800	// 1900 samples (86ms @ 24kHz)
+
+struct SWLateReverb
+{
+	uint32 nReverbDelay;		// Reverb delay (in samples)
+	uint32 nDelayPos;			// Delay line position
+	LR16   nDifCoeffs[2];		// Reverb diffusion
+	LR16   nDecayDC[2];			// Reverb DC decay
+	LR16   nDecayLP[2];			// Reverb HF decay
+	LR16   LPHistory[2];		// Low-pass history
+	LR16   Dif2InGains[2];		// 2nd diffuser input gains
+	LR16   RvbOutGains[2];		// 4x2 Reverb output gains
+	int32  lMasterGain;			// late reverb master gain
+	int32  lDummyAlign;
+	// Tank Delay lines
+	LR16   Diffusion1[RVBDLY_MASK + 1];	// {dif1_l, dif1_r}
+	LR16   Diffusion2[RVBDLY_MASK + 1];	// {dif2_l, dif2_r}
+	LR16   Delay1[RVBDLY_MASK + 1];		// {dly1_l, dly1_r}
+	LR16   Delay2[RVBDLY_MASK + 1];		// {dly2_l, dly2_r}
+};
+
+#define ENVIRONMENT_NUMREFLECTIONS		8
+
+struct EnvironmentReflection
+{
+	int16  GainLL, GainRR, GainLR, GainRL;	// +/- 32K scale
+	uint32 Delay;							// In samples
+};
+
+struct EnvironmentReverb
+{
+	int32  ReverbLevel;			// Late reverb gain (mB)
+	int32  ReflectionsLevel;	// Master reflections gain (mB)
+	int32  RoomHF;				// Room gain HF (mB)
+	uint32 ReverbDecay;			// Reverb tank decay (0-7fff scale)
+	int32  PreDiffusion;		// Reverb pre-diffusion amount (+/- 32K scale)
+	int32  TankDiffusion;		// Reverb tank diffusion (+/- 32K scale)
+	uint32 ReverbDelay;			// Reverb delay (in samples)
+	float  flReverbDamping;		// HF tank gain [0.0, 1.0]
+	int32  ReverbDecaySamples;	// Reverb decay time (in samples)
+	EnvironmentReflection Reflections[ENVIRONMENT_NUMREFLECTIONS];
+};
+
+
+class CReverbSettings
+{
+public:
+	uint32 m_nReverbDepth;
+	uint32 m_nReverbType;
+public:
+	CReverbSettings();
+};
+
+
+class CReverb
+{
+public:
+	CReverbSettings m_Settings;
+
+	// Shared reverb state
+private:
+	mixsample_t MixReverbBuffer[MIXBUFFERSIZE * 2];
+public:
+	mixsample_t gnRvbROfsVol, gnRvbLOfsVol;
+
+private:
+
+	uint32 gnReverbSend;
+
+	uint32 gnReverbSamples;
+	uint32 gnReverbDecaySamples;
+
+	// Internal reverb state
+	bool g_bLastInPresent;
+	bool g_bLastOutPresent;
+	int g_nLastRvbIn_xl;
+	int g_nLastRvbIn_xr;
+	int g_nLastRvbIn_yl;
+	int g_nLastRvbIn_yr;
+	int g_nLastRvbOut_xl;
+	int g_nLastRvbOut_xr;
+	int32 gnDCRRvb_Y1[2];
+	int32 gnDCRRvb_X1[2];
+
+	// Reverb mix buffers
+	SWRvbRefDelay g_RefDelay;
+	SWLateReverb g_LateReverb;
+
+public:
+	CReverb();
+public:
+	void Initialize(bool bReset, uint32 MixingFreq);
+
+	// can be called multiple times or never (if no data is sent to reverb)
+	mixsample_t *GetReverbSendBuffer(uint32 nSamples);
+
+	// call once after all data has been sent.
+	void Process(mixsample_t *MixSoundBuffer, uint32 nSamples);
+
+private:
+	void Shutdown();
+	// Pre/Post resampling and filtering
+	uint32 ReverbProcessPreFiltering1x(int32 *pWet, uint32 nSamples);
+	uint32 ReverbProcessPreFiltering2x(int32 *pWet, uint32 nSamples);
+	void ReverbProcessPostFiltering1x(const int32 *pRvb, int32 *pDry, uint32 nSamples);
+	void ReverbProcessPostFiltering2x(const int32 *pRvb, int32 *pDry, uint32 nSamples);
+	void ReverbDCRemoval(int32 *pBuffer, uint32 nSamples);
+	void ReverbDryMix(int32 *pDry, int32 *pWet, int lDryVol, uint32 nSamples);
+	// Process pre-diffusion and pre-delay
+	static void ProcessPreDelay(SWRvbRefDelay *pPreDelay, const int32 *pIn, uint32 nSamples);
+	// Process reflections
+	static void ProcessReflections(SWRvbRefDelay *pPreDelay, LR16 *pRefOut, int32 *pMixOut, uint32 nSamples);
+	// Process Late Reverb (SW Reflections): stereo reflections output, 32-bit reverb output, SW reverb gain
+	static void ProcessLateReverb(SWLateReverb *pReverb, LR16 *pRefOut, int32 *pMixOut, uint32 nSamples);
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// I3DL2 reverb presets
+//
+
+#define SNDMIX_REVERB_PRESET_DEFAULT \
+-10000,    0, 1.00f,0.50f,-10000,0.020f,-10000,0.040f,100.0f,100.0f
+
+#define SNDMIX_REVERB_PRESET_GENERIC \
+ -1000, -100, 1.49f,0.83f, -2602,0.007f,   200,0.011f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_PADDEDCELL \
+ -1000,-6000, 0.17f,0.10f, -1204,0.001f,   207,0.002f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_ROOM \
+ -1000, -454, 0.40f,0.83f, -1646,0.002f,    53,0.003f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_BATHROOM \
+ -1000,-1200, 1.49f,0.54f,  -370,0.007f,  1030,0.011f,100.0f, 60.0f
+#define SNDMIX_REVERB_PRESET_LIVINGROOM \
+ -1000,-6000, 0.50f,0.10f, -1376,0.003f, -1104,0.004f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_STONEROOM \
+ -1000, -300, 2.31f,0.64f,  -711,0.012f,    83,0.017f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_AUDITORIUM \
+ -1000, -476, 4.32f,0.59f,  -789,0.020f,  -289,0.030f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_CONCERTHALL \
+ -1000, -500, 3.92f,0.70f, -1230,0.020f,    -2,0.029f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_CAVE \
+ -1000,    0, 2.91f,1.30f,  -602,0.015f,  -302,0.022f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_ARENA \
+ -1000, -698, 7.24f,0.33f, -1166,0.020f,    16,0.030f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_HANGAR \
+ -1000,-1000,10.05f,0.23f,  -602,0.020f,   198,0.030f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_CARPETEDHALLWAY \
+ -1000,-4000, 0.30f,0.10f, -1831,0.002f, -1630,0.030f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_HALLWAY \
+ -1000, -300, 1.49f,0.59f, -1219,0.007f,   441,0.011f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_STONECORRIDOR \
+ -1000, -237, 2.70f,0.79f, -1214,0.013f,   395,0.020f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_ALLEY \
+ -1000, -270, 1.49f,0.86f, -1204,0.007f,    -4,0.011f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_FOREST \
+ -1000,-3300, 1.49f,0.54f, -2560,0.162f,  -613,0.088f, 79.0f,100.0f
+#define SNDMIX_REVERB_PRESET_CITY \
+ -1000, -800, 1.49f,0.67f, -2273,0.007f, -2217,0.011f, 50.0f,100.0f
+#define SNDMIX_REVERB_PRESET_MOUNTAINS \
+ -1000,-2500, 1.49f,0.21f, -2780,0.300f, -2014,0.100f, 27.0f,100.0f
+#define SNDMIX_REVERB_PRESET_QUARRY \
+ -1000,-1000, 1.49f,0.83f,-10000,0.061f,   500,0.025f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_PLAIN \
+ -1000,-2000, 1.49f,0.50f, -2466,0.179f, -2514,0.100f, 21.0f,100.0f
+#define SNDMIX_REVERB_PRESET_PARKINGLOT \
+ -1000,    0, 1.65f,1.50f, -1363,0.008f, -1153,0.012f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_SEWERPIPE \
+ -1000,-1000, 2.81f,0.14f,   429,0.014f,   648,0.021f, 80.0f, 60.0f
+#define SNDMIX_REVERB_PRESET_UNDERWATER \
+ -1000,-4000, 1.49f,0.10f,  -449,0.007f,  1700,0.011f,100.0f,100.0f
+
+// Examples simulating General MIDI 2'musical' reverb presets
+//
+// Name  (Decay time)  Description
+//
+// Small Room  (1.1s)  A small size room with a length of 5m or so.
+// Medium Room (1.3s)  A medium size room with a length of 10m or so.
+// Large Room  (1.5s)  A large size room suitable for live performances.
+// Medium Hall (1.8s)  A medium size concert hall.
+// Large Hall  (1.8s)  A large size concert hall suitable for a full orchestra.
+// Plate       (1.3s)  A plate reverb simulation.
+
+#define SNDMIX_REVERB_PRESET_SMALLROOM \
+ -1000, -600, 1.10f,0.83f,  -400,0.005f,   500,0.010f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_MEDIUMROOM \
+ -1000, -600, 1.30f,0.83f, -1000,0.010f,  -200,0.020f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_LARGEROOM \
+ -1000, -600, 1.50f,0.83f, -1600,0.020f, -1000,0.040f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_MEDIUMHALL \
+ -1000, -600, 1.80f,0.70f, -1300,0.015f,  -800,0.030f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_LARGEHALL \
+ -1000, -600, 1.80f,0.70f, -2000,0.030f, -1400,0.060f,100.0f,100.0f
+#define SNDMIX_REVERB_PRESET_PLATE \
+ -1000, -200, 1.30f,0.90f,     0,0.002f,     0,0.010f,100.0f, 75.0f
+
+OPENMPT_NAMESPACE_END
+
+#endif // NO_REVERB
diff --git a/soundlib/AudioCriticalSection.cpp b/soundlib/AudioCriticalSection.cpp
index ea20441..c1c10df 100644
--- a/soundlib/AudioCriticalSection.cpp
+++ b/soundlib/AudioCriticalSection.cpp
@@ -26,6 +26,13 @@ CriticalSection::CriticalSection()
 	Enter();
 }
 
+CriticalSection::CriticalSection(CriticalSection &&other)
+	: m_refGlobalMutex(other.m_refGlobalMutex)
+	, inSection(other.inSection)
+{
+	other.inSection = false;
+}
+
 CriticalSection::CriticalSection(InitialState state)
 	: m_refGlobalMutex(Tracker::GetGlobalMutexRef())
 	, inSection(false)
diff --git a/soundlib/AudioCriticalSection.h b/soundlib/AudioCriticalSection.h
index 07b1780..5ce5300 100644
--- a/soundlib/AudioCriticalSection.h
+++ b/soundlib/AudioCriticalSection.h
@@ -40,6 +40,7 @@ public:
 	};
 public:
 	CriticalSection();
+	CriticalSection(CriticalSection &&other);
 	explicit CriticalSection(InitialState state);
 	void Enter();
 	void Leave();
diff --git a/soundlib/AudioReadTarget.h b/soundlib/AudioReadTarget.h
index a5c1757..162e971 100644
--- a/soundlib/AudioReadTarget.h
+++ b/soundlib/AudioReadTarget.h
@@ -10,8 +10,9 @@
 
 #include "Sndfile.h"
 #include "Dither.h"
-#include "SampleFormatConverters.h"
-#include "SampleFormat.h"
+#include "../soundbase/SampleFormat.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
 #include "MixerLoops.h"
 #include "Mixer.h"
 
@@ -74,9 +75,7 @@ public:
 #if defined(MODPLUG_TRACKER)
 
 
-//===========================================
 class AudioReadTargetBufferInterleavedDynamic
-//===========================================
 	: public IAudioReadTarget
 {
 private:
diff --git a/soundlib/ChunkReader.h b/soundlib/ChunkReader.h
index 9b0e409..a51c73c 100644
--- a/soundlib/ChunkReader.h
+++ b/soundlib/ChunkReader.h
@@ -18,80 +18,60 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-//===================================
 class ChunkReader : public FileReader
-//===================================
 {
 public:
 
-	ChunkReader(mpt::span<const mpt::byte> bytedata) : FileReader(bytedata) { }
+	template <typename Tbyte> ChunkReader(mpt::span<Tbyte> bytedata) : FileReader(bytedata) { }
 	ChunkReader(const FileReader &other) : FileReader(other) { }
+	ChunkReader(FileReader &&other) : FileReader(std::move(other)) { }
 
 	template<typename T>
-	//=================
-	class ChunkListItem
-	//=================
+	class Item
 	{
 	private:
 		T chunkHeader;
 		FileReader chunkData;
 
 	public:
-		ChunkListItem(const T &header, const FileReader &data) : chunkHeader(header), chunkData(data) { }
-
-		ChunkListItem<T> &operator= (const ChunkListItem<T> &other)
-		{ 
-			chunkHeader = other.chunkHeader;
-			chunkData = other.chunkData;
-			return *this;
-		}
+		Item(const T &header, FileReader &&data) : chunkHeader(header), chunkData(std::move(data)) { }
+		Item(const Item<T> &) = default;
+		Item(Item<T> &&) noexcept = default;
 
 		const T &GetHeader() const { return chunkHeader; }
 		const FileReader &GetData() const { return chunkData; }
 	};
 
 	template<typename T>
-	//=====================================================
-	class ChunkList : public std::vector<ChunkListItem<T> >
-	//=====================================================
+	class ChunkList : public std::vector<Item<T>>
 	{
 	public:
+		typedef decltype(T().GetID()) id_type;
 
 		// Check if the list contains a given chunk.
-		bool ChunkExists(typename T::id_type id) const
+		bool ChunkExists(id_type id) const
 		{
-			for(typename std::vector<ChunkListItem<T> >::const_iterator iter = this->begin(); iter != this->end(); iter++)
-			{
-				if(iter->GetHeader().GetID() == id)
-				{
-					return true;
-				}
-			}
-			return false;
+			return std::find_if(this->cbegin(), this->cend(), [&id](const Item<T> &item) { return item.GetHeader().GetID() == id; }) != this->cend();
 		}
 
 		// Retrieve the first chunk with a given ID.
-		FileReader GetChunk(typename T::id_type id) const
+		FileReader GetChunk(id_type id) const
 		{
-			for(typename std::vector<ChunkListItem<T> >::const_iterator iter = this->begin(); iter != this->end(); iter++)
-			{
-				if(iter->GetHeader().GetID() == id)
-				{
-					return iter->GetData();
-				}
-			}
+			auto item = std::find_if(this->cbegin(), this->cend(), [&id](const Item<T> &item) { return item.GetHeader().GetID() == id; });
+			if(item != this->cend())
+				return item->GetData();
 			return FileReader();
 		}
 
 		// Retrieve all chunks with a given ID.
-		std::vector<FileReader> GetAllChunks(typename T::id_type id) const
+		std::vector<FileReader> GetAllChunks(id_type id) const
 		{
 			std::vector<FileReader> result;
-			for(typename std::vector<ChunkListItem<T> >::const_iterator iter = this->begin(); iter != this->end(); iter++)
+			for(const auto &item : *this)
 			{
-				if(iter->GetHeader().GetID() == id)
+				if(item.GetHeader().GetID() == id)
 				{
-					result.push_back(iter->GetData());
+					result.push_back(item.GetData());
 				}
 			}
 			return result;
@@ -99,11 +79,10 @@ public:
 	};
 
 	// Read a single "T" chunk.
-	// T is required to have the methods GetID() and GetLength(), as well as an id_type typedef.
+	// T is required to have the methods GetID() and GetLength().
 	// GetLength() must return the chunk size in bytes, and GetID() the chunk ID.
-	// id_type must reflect the type that is returned by GetID().
 	template<typename T>
-	ChunkListItem<T> GetNextChunk(off_t padding)
+	Item<T> GetNextChunk(off_t padding)
 	{
 		T chunkHeader;
 		off_t dataSize = 0;
@@ -111,7 +90,7 @@ public:
 		{
 			dataSize = chunkHeader.GetLength();
 		}
-		ChunkListItem<T> resultItem(chunkHeader, ReadChunk(dataSize));
+		Item<T> resultItem(chunkHeader, ReadChunk(dataSize));
 
 		// Skip padding bytes
 		if(padding != 0 && dataSize % padding != 0)
@@ -123,9 +102,8 @@ public:
 	}
 
 	// Read a series of "T" chunks until the end of file is reached.
-	// T is required to have the methods GetID() and GetLength(), as well as an id_type typedef.
+	// T is required to have the methods GetID() and GetLength().
 	// GetLength() must return the chunk size in bytes, and GetID() the chunk ID.
-	// id_type must reflect the type that is returned by GetID().
 	template<typename T>
 	ChunkList<T> ReadChunks(off_t padding)
 	{
@@ -139,11 +117,10 @@ public:
 	}
 
 	// Read a series of "T" chunks until a given chunk ID is found.
-	// T is required to have the methods GetID() and GetLength(), as well as an id_type typedef.
+	// T is required to have the methods GetID() and GetLength().
 	// GetLength() must return the chunk size in bytes, and GetID() the chunk ID.
-	// id_type must reflect the type that is returned by GetID().
 	template<typename T>
-	ChunkList<T> ReadChunksUntil(off_t padding, typename T::id_type stopAtID)
+	ChunkList<T> ReadChunksUntil(off_t padding, decltype(T().GetID()) stopAtID)
 	{
 		ChunkList<T> result;
 		while(CanRead(sizeof(T)))
diff --git a/soundlib/Container.h b/soundlib/Container.h
new file mode 100644
index 0000000..4760d88
--- /dev/null
+++ b/soundlib/Container.h
@@ -0,0 +1,41 @@
+/*
+ * Container.h
+ * -----------
+ * Purpose: General interface for MDO container and/or packers.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#include "../common/FileReader.h"
+
+#include <vector>
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+struct ContainerItem
+{
+	mpt::ustring name;
+	FileReader file;
+	std::unique_ptr<std::vector<char> > data_cache; // may be empty
+};
+
+
+enum ContainerLoadingFlags
+{
+	ContainerOnlyVerifyHeader = 0x00,
+	ContainerUnwrapData       = 0x01,
+};
+
+
+bool UnpackXPK(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags);
+bool UnpackPP20(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags);
+bool UnpackMMCMP(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags);
+bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags);
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/ContainerMMCMP.cpp b/soundlib/ContainerMMCMP.cpp
new file mode 100644
index 0000000..76a6412
--- /dev/null
+++ b/soundlib/ContainerMMCMP.cpp
@@ -0,0 +1,436 @@
+/*
+ * ContainerMMCMP.cpp
+ * ------------------
+ * Purpose: Handling of MMCMP compressed modules
+ * Notes  : (currently none)
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#include "../common/FileReader.h"
+#include "Container.h"
+#include "Sndfile.h"
+
+#include <stdexcept>
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+//#define MMCMP_LOG
+
+
+struct MMCMPFILEHEADER
+{
+	char     id[8];	// "ziRCONia"
+	uint16le hdrsize;
+};
+
+MPT_BINARY_STRUCT(MMCMPFILEHEADER, 10)
+
+struct MMCMPHEADER
+{
+	uint16le version;
+	uint16le nblocks;
+	uint32le filesize;
+	uint32le blktable;
+	uint8le  glb_comp;
+	uint8le  fmt_comp;
+};
+
+MPT_BINARY_STRUCT(MMCMPHEADER, 14)
+
+struct MMCMPBLOCK
+{
+	uint32le unpk_size;
+	uint32le pk_size;
+	uint32le xor_chk;
+	uint16le sub_blk;
+	uint16le flags;
+	uint16le tt_entries;
+	uint16le num_bits;
+};
+
+MPT_BINARY_STRUCT(MMCMPBLOCK, 20)
+
+struct MMCMPSUBBLOCK
+{
+	uint32le unpk_pos;
+	uint32le unpk_size;
+};
+
+MPT_BINARY_STRUCT(MMCMPSUBBLOCK, 8)
+
+
+#define MMCMP_COMP		0x0001
+#define MMCMP_DELTA		0x0002
+#define MMCMP_16BIT		0x0004
+#define MMCMP_STEREO	0x0100
+#define MMCMP_ABS16		0x0200
+#define MMCMP_ENDIAN	0x0400
+
+struct MMCMPBITBUFFER
+{
+	uint32 bitcount;
+	uint32 bitbuffer;
+	const uint8 *pSrc;
+	uint32 bytesLeft;
+
+	uint32 GetBits(uint32 nBits);
+};
+
+
+uint32 MMCMPBITBUFFER::GetBits(uint32 nBits)
+{
+	uint32 d;
+	if (!nBits) return 0;
+	while (bitcount < 24)
+	{
+		if(bytesLeft)
+		{
+			bitbuffer |= *pSrc << bitcount;
+			pSrc++;
+			bytesLeft--;
+		}
+		bitcount += 8;
+	}
+	d = bitbuffer & ((1 << nBits) - 1);
+	bitbuffer >>= nBits;
+	bitcount -= nBits;
+	return d;
+}
+
+static const uint8 MMCMP8BitCommands[8] =
+{
+	0x01, 0x03,	0x07, 0x0F,	0x1E, 0x3C,	0x78, 0xF8
+};
+
+static const uint8 MMCMP8BitFetch[8] =
+{
+	3, 3, 3, 3, 2, 1, 0, 0
+};
+
+static const uint16 MMCMP16BitCommands[16] =
+{
+	0x01, 0x03,	0x07, 0x0F,	0x1E, 0x3C,	0x78, 0xF0,
+	0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
+};
+
+static const uint8 MMCMP16BitFetch[16] =
+{
+	4, 4, 4, 4, 3, 2, 1, 0,
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+static bool MMCMP_IsDstBlockValid(const std::vector<char> &unpackedData, uint32 pos, uint32 len)
+{
+	if(pos >= unpackedData.size()) return false;
+	if(len > unpackedData.size()) return false;
+	if(len > unpackedData.size() - pos) return false;
+	return true;
+}
+
+
+static bool MMCMP_IsDstBlockValid(const std::vector<char> &unpackedData, const MMCMPSUBBLOCK &subblk)
+{
+	return MMCMP_IsDstBlockValid(unpackedData, subblk.unpk_pos, subblk.unpk_size);
+}
+
+
+static bool ValidateHeader(const MMCMPFILEHEADER &mfh)
+{
+	if(std::memcmp(mfh.id, "ziRCONia", 8) != 0)
+	{
+		return false;
+	}
+	if(mfh.hdrsize != sizeof(MMCMPHEADER))
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static bool ValidateHeader(const MMCMPHEADER &mmh)
+{
+	if(mmh.nblocks == 0)
+	{
+		return false;
+	}
+	if(mmh.filesize == 0)
+	{
+		return false;
+	}
+	if(mmh.filesize > 0x80000000)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize)
+{
+	MMCMPFILEHEADER mfh;
+	if(!file.ReadStruct(mfh))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(mfh))
+	{
+		return ProbeFailure;
+	}
+	MMCMPHEADER mmh;
+	if(!file.ReadStruct(mmh))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(mmh))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool UnpackMMCMP(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
+{
+	file.Rewind();
+	containerItems.clear();
+
+	MMCMPFILEHEADER mfh;
+	if(!file.ReadStruct(mfh))
+	{
+		return false;
+	}
+	if(!ValidateHeader(mfh))
+	{
+		return false;
+	}
+	MMCMPHEADER mmh;
+	if(!file.ReadStruct(mmh))
+	{
+		return false;
+	}
+	if(!ValidateHeader(mmh))
+	{
+		return false;
+	}
+	if(loadFlags == ContainerOnlyVerifyHeader)
+	{
+		return true;
+	}
+	if(mmh.blktable > file.GetLength()) return false;
+	if(mmh.blktable + 4 * mmh.nblocks > file.GetLength()) return false;
+
+	containerItems.emplace_back();
+	containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
+	std::vector<char> & unpackedData = *(containerItems.back().data_cache);
+
+	unpackedData.resize(mmh.filesize);
+	// 8-bit deltas
+	uint8 ptable[256] = { 0 };
+
+	for (uint32 nBlock=0; nBlock<mmh.nblocks; nBlock++)
+	{
+		if(!file.Seek(mmh.blktable + 4*nBlock)) return false;
+		if(!file.CanRead(4)) return false;
+		uint32 blkPos = file.ReadUint32LE();
+		if(!file.Seek(blkPos)) return false;
+		MMCMPBLOCK blk;
+		if(!file.ReadStruct(blk)) return false;
+		std::vector<MMCMPSUBBLOCK> subblks(blk.sub_blk);
+		for(uint32 i=0; i<blk.sub_blk; ++i)
+		{
+			if(!file.ReadStruct(subblks[i])) return false;
+		}
+		const MMCMPSUBBLOCK *psubblk = blk.sub_blk > 0 ? subblks.data() : nullptr;
+
+		if(blkPos + sizeof(MMCMPBLOCK) + blk.sub_blk * sizeof(MMCMPSUBBLOCK) >= file.GetLength()) return false;
+		uint32 memPos = blkPos + sizeof(MMCMPBLOCK) + blk.sub_blk * sizeof(MMCMPSUBBLOCK);
+
+#ifdef MMCMP_LOG
+		Log("block %d: flags=%04X sub_blocks=%d", nBlock, (uint32)pblk->flags, (uint32)pblk->sub_blk);
+		Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size);
+		Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits);
+#endif
+		// Data is not packed
+		if (!(blk.flags & MMCMP_COMP))
+		{
+			for (uint32 i=0; i<blk.sub_blk; i++)
+			{
+				if(!psubblk) return false;
+				if(!MMCMP_IsDstBlockValid(unpackedData, *psubblk)) return false;
+#ifdef MMCMP_LOG
+				Log("  Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size);
+#endif
+				if(!file.Seek(memPos)) return false;
+				if(file.ReadRaw(&(unpackedData[psubblk->unpk_pos]), psubblk->unpk_size) != psubblk->unpk_size) return false;
+				psubblk++;
+			}
+		} else
+		// Data is 16-bit packed
+		if (blk.flags & MMCMP_16BIT)
+		{
+			MMCMPBITBUFFER bb;
+			uint32 subblk = 0;
+			if(!psubblk) return false;
+			if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
+			char *pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
+			uint32 dwSize = psubblk[subblk].unpk_size;
+			uint32 dwPos = 0;
+			uint32 numbits = blk.num_bits;
+			uint32 oldval = 0;
+
+#ifdef MMCMP_LOG
+			Log("  16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size);
+			if (pblk->flags & MMCMP_DELTA) Log("DELTA ");
+			if (pblk->flags & MMCMP_ABS16) Log("ABS16 ");
+			Log("\n");
+#endif
+			bb.bitcount = 0;
+			bb.bitbuffer = 0;
+			if(!file.Seek(memPos + blk.tt_entries)) return false;
+			if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false;
+			bb.pSrc = file.GetRawData<uint8>();
+			bb.bytesLeft = blk.pk_size - blk.tt_entries;
+			while (subblk < blk.sub_blk)
+			{
+				uint32 newval = 0x10000;
+				uint32 d = bb.GetBits(numbits+1);
+
+				uint32 command = MMCMP16BitCommands[numbits & 0x0F];
+				if (d >= command)
+				{
+					uint32 nFetch = MMCMP16BitFetch[numbits & 0x0F];
+					uint32 newbits = bb.GetBits(nFetch) + ((d - command) << nFetch);
+					if (newbits != numbits)
+					{
+						numbits = newbits & 0x0F;
+					} else
+					{
+						if ((d = bb.GetBits(4)) == 0x0F)
+						{
+							if (bb.GetBits(1)) break;
+							newval = 0xFFFF;
+						} else
+						{
+							newval = 0xFFF0 + d;
+						}
+					}
+				} else
+				{
+					newval = d;
+				}
+				if (newval < 0x10000)
+				{
+					newval = (newval & 1) ? (uint32)(-(int32)((newval+1) >> 1)) : (uint32)(newval >> 1);
+					if (blk.flags & MMCMP_DELTA)
+					{
+						newval += oldval;
+						oldval = newval;
+					} else
+					if (!(blk.flags & MMCMP_ABS16))
+					{
+						newval ^= 0x8000;
+					}
+					pDest[dwPos + 0] = (uint8)(((uint16)newval) & 0xFF);
+					pDest[dwPos + 1] = (uint8)(((uint16)newval) >> 8);
+					dwPos += 2;
+				}
+				if (dwPos >= dwSize)
+				{
+					subblk++;
+					dwPos = 0;
+					if(!(subblk < blk.sub_blk)) break;
+					if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
+					dwSize = psubblk[subblk].unpk_size;
+					pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
+				}
+			}
+		} else
+		// Data is 8-bit packed
+		{
+			MMCMPBITBUFFER bb;
+			uint32 subblk = 0;
+			if(!psubblk) return false;
+			if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
+			char *pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
+			uint32 dwSize = psubblk[subblk].unpk_size;
+			uint32 dwPos = 0;
+			uint32 numbits = blk.num_bits;
+			uint32 oldval = 0;
+			if(blk.tt_entries > sizeof(ptable)
+				|| !file.Seek(memPos)
+				|| file.ReadRaw(ptable, blk.tt_entries) < blk.tt_entries)
+				return false;
+
+			bb.bitcount = 0;
+			bb.bitbuffer = 0;
+			if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false;
+			bb.pSrc = file.GetRawData<uint8>();
+			bb.bytesLeft = blk.pk_size - blk.tt_entries;
+			while (subblk < blk.sub_blk)
+			{
+				uint32 newval = 0x100;
+				uint32 d = bb.GetBits(numbits+1);
+
+				uint32 command = MMCMP8BitCommands[numbits & 0x07];
+				if (d >= command)
+				{
+					uint32 nFetch = MMCMP8BitFetch[numbits & 0x07];
+					uint32 newbits = bb.GetBits(nFetch) + ((d - command) << nFetch);
+					if (newbits != numbits)
+					{
+						numbits = newbits & 0x07;
+					} else
+					{
+						if ((d = bb.GetBits(3)) == 7)
+						{
+							if (bb.GetBits(1)) break;
+							newval = 0xFF;
+						} else
+						{
+							newval = 0xF8 + d;
+						}
+					}
+				} else
+				{
+					newval = d;
+				}
+				if (newval < sizeof(ptable))
+				{
+					int n = ptable[newval];
+					if (blk.flags & MMCMP_DELTA)
+					{
+						n += oldval;
+						oldval = n;
+					}
+					pDest[dwPos++] = (uint8)n;
+				}
+				if (dwPos >= dwSize)
+				{
+					subblk++;
+					dwPos = 0;
+					if(!(subblk < blk.sub_blk)) break;
+					if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
+					dwSize = psubblk[subblk].unpk_size;
+					pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
+				}
+			}
+		}
+	}
+
+	containerItems.back().file = FileReader(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(unpackedData)));
+
+	return true;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/ContainerPP20.cpp b/soundlib/ContainerPP20.cpp
new file mode 100644
index 0000000..8d2869e
--- /dev/null
+++ b/soundlib/ContainerPP20.cpp
@@ -0,0 +1,219 @@
+/*
+ * ContainerPP20.cpp
+ * -----------------
+ * Purpose: Handling of PowerPack PP20 compressed modules
+ * Notes  : (currently none)
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#include "../common/FileReader.h"
+#include "Container.h"
+#include "Sndfile.h"
+
+#include <stdexcept>
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+//#define MMCMP_LOG
+
+
+struct PPBITBUFFER
+{
+	uint32 bitcount;
+	uint32 bitbuffer;
+	const uint8 *pStart;
+	const uint8 *pSrc;
+
+	uint32 GetBits(uint32 n);
+};
+
+
+uint32 PPBITBUFFER::GetBits(uint32 n)
+{
+	uint32 result = 0;
+
+	for (uint32 i=0; i<n; i++)
+	{
+		if (!bitcount)
+		{
+			bitcount = 8;
+			if (pSrc != pStart) pSrc--;
+			bitbuffer = *pSrc;
+		}
+		result = (result<<1) | (bitbuffer&1);
+		bitbuffer >>= 1;
+		bitcount--;
+	}
+	return result;
+}
+
+
+static bool PP20_DoUnpack(const uint8 *pSrc, uint32 nSrcLen, uint8 *pDst, uint32 nDstLen)
+{
+	PPBITBUFFER BitBuffer;
+	uint32 nBytesLeft;
+
+	BitBuffer.pStart = pSrc;
+	BitBuffer.pSrc = pSrc + nSrcLen - 4;
+	BitBuffer.bitbuffer = 0;
+	BitBuffer.bitcount = 0;
+	BitBuffer.GetBits(pSrc[nSrcLen-1]);
+	nBytesLeft = nDstLen;
+	while (nBytesLeft > 0)
+	{
+		if (!BitBuffer.GetBits(1))
+		{
+			uint32 n = 1;
+			while (n < nBytesLeft)
+			{
+				uint32 code = BitBuffer.GetBits(2);
+				n += code;
+				if (code != 3) break;
+			}
+			LimitMax(n, nBytesLeft);
+			for (uint32 i=0; i<n; i++)
+			{
+				pDst[--nBytesLeft] = (uint8)BitBuffer.GetBits(8);
+			}
+			if (!nBytesLeft) break;
+		}
+		{
+			uint32 n = BitBuffer.GetBits(2)+1;
+			if(n < 1 || n-1 >= nSrcLen) return false;
+			uint32 nbits = pSrc[n-1];
+			uint32 nofs;
+			if (n==4)
+			{
+				nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 );
+				while (n < nBytesLeft)
+				{
+					uint32 code = BitBuffer.GetBits(3);
+					n += code;
+					if (code != 7) break;
+				}
+			} else
+			{
+				nofs = BitBuffer.GetBits(nbits);
+			}
+			LimitMax(n, nBytesLeft);
+			for (uint32 i=0; i<=n; i++)
+			{
+				pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0;
+				if (!--nBytesLeft) break;
+			}
+		}
+	}
+	return true;
+}
+
+
+struct PP20header
+{
+	char    magic[4];       // "PP20"
+	uint8be efficiency[4];
+};
+
+MPT_BINARY_STRUCT(PP20header, 8)
+
+
+static bool ValidateHeader(const PP20header &hdr)
+{
+	if(std::memcmp(hdr.magic, "PP20", 4) != 0)
+	{
+		return false;
+	}
+	if(hdr.efficiency[0] < 9 || hdr.efficiency[0] > 15
+		|| hdr.efficiency[1] < 9 || hdr.efficiency[1] > 15
+		|| hdr.efficiency[2] < 9 || hdr.efficiency[2] > 15
+		|| hdr.efficiency[3] < 9 || hdr.efficiency[3] > 15)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize)
+{
+	PP20header hdr;
+	if(!file.ReadStruct(hdr))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(hdr))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool UnpackPP20(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
+{
+	file.Rewind();
+	containerItems.clear();
+
+	PP20header hdr;
+	if(!file.ReadStruct(hdr))
+	{
+		return false;
+	}
+	if(!ValidateHeader(hdr))
+	{
+		return false;
+	}
+	if(loadFlags == ContainerOnlyVerifyHeader)
+	{
+		return true;
+	}
+
+	if(!file.CanRead(4))
+	{
+		return false;
+	}
+
+	containerItems.emplace_back();
+	containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
+	std::vector<char> & unpackedData = *(containerItems.back().data_cache);
+
+	FileReader::off_t length = file.GetLength();
+	if(!Util::TypeCanHoldValue<uint32>(length)) return false;
+	// Length word must be aligned
+	if((length % 2u) != 0)
+		return false;
+
+	file.Seek(length - 4);
+	uint32 dstLen = 0;
+	dstLen |= file.ReadUint8() << 16;
+	dstLen |= file.ReadUint8() << 8;
+	dstLen |= file.ReadUint8() << 0;
+	if(dstLen == 0) return false;
+	try
+	{
+		unpackedData.resize(dstLen);
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		return false;
+	}
+	file.Seek(4);
+	bool result = PP20_DoUnpack(file.GetRawData<uint8>(), static_cast<uint32>(length - 4), mpt::byte_cast<uint8 *>(unpackedData.data()), dstLen);
+
+	if(result)
+	{
+		containerItems.back().file = FileReader(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(unpackedData)));
+	}
+
+	return result;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/ContainerUMX.cpp b/soundlib/ContainerUMX.cpp
new file mode 100644
index 0000000..a5c4bfe
--- /dev/null
+++ b/soundlib/ContainerUMX.cpp
@@ -0,0 +1,205 @@
+/*
+ * ContainerUMX.cpp
+ * ----------------
+ * Purpose: UMX (Unreal Music) module ripper
+ * Notes  : Obviously, this code only rips modules from older Unreal Engine games, such as Unreal 1, Unreal Tournament 1 and Deus Ex.
+ * Authors: Johannes Schultz (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format)
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Loaders.h"
+#include "UMXTools.h"
+#include "Container.h"
+#include "Sndfile.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+static bool ValidateHeader(const UMXFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
+		|| fileHeader.nameCount == 0
+		|| fileHeader.exportCount == 0
+		|| fileHeader.importCount == 0
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize)
+{
+	UMXFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	if(!FindUMXNameTableEntryMemory(file, fileHeader, "music"))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
+{
+	file.Rewind();
+	containerItems.clear();
+
+	UMXFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+
+	// Note that this can be a false positive, e.g. Unreal maps will have music and sound
+	// in their name table because they usually import such files. However, it spares us
+	// from wildly seeking through the file, as the name table is usually right at the
+	// start of the file, so it is hopefully a good enough heuristic for our purposes.
+	if(!FindUMXNameTableEntry(file, fileHeader, "music"))
+	{
+		return false;
+	}
+
+	if(loadFlags == ContainerOnlyVerifyHeader)
+	{
+		return true;
+	}
+
+	// Read name table
+	std::vector<std::string> names = ReadUMXNameTable(file, fileHeader);
+
+	// Read import table
+	if(!file.Seek(fileHeader.importOffset))
+	{
+		return false;
+	}
+
+	std::vector<int32> classes;
+	classes.reserve(fileHeader.importCount);
+	for(uint32 i = 0; i < fileHeader.importCount && file.CanRead(4); i++)
+	{
+		int32 objName = ReadUMXImportTableEntry(file, fileHeader.packageVersion);
+		if(static_cast<size_t>(objName) < names.size())
+		{
+			classes.push_back(objName);
+		}
+	}
+
+	// Read export table
+	if(!file.Seek(fileHeader.exportOffset))
+	{
+		return false;
+	}
+
+	// Now we can be pretty sure that we're doing the right thing.
+	
+	for(uint32 i = 0; i < fileHeader.exportCount && file.CanRead(4); i++)
+	{
+		int32 objClass, objOffset, objSize, objName;
+		ReadUMXExportTableEntry(file, objClass, objOffset, objSize, objName, fileHeader.packageVersion);
+
+		if(objSize <= 0 || objClass >= 0)
+		{
+			continue;
+		}
+
+		// Look up object class name (we only want music).
+		objClass = -objClass - 1;
+		bool isMusic = false;
+		if(static_cast<size_t>(objClass) < classes.size())
+		{
+			isMusic = (names[classes[objClass]] == "music");
+		}
+		if(!isMusic)
+		{
+			continue;
+		}
+
+		FileReader chunk = file.GetChunkAt(objOffset, objSize);
+
+		if(chunk.IsValid())
+		{
+			if(fileHeader.packageVersion < 40)
+			{
+				chunk.Skip(8); // 00 00 00 00 00 00 00 00
+			}
+			if(fileHeader.packageVersion < 60)
+			{
+				chunk.Skip(16); // 81 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00
+			}
+			// Read object properties
+#if 0
+			size_t propertyName = static_cast<size_t>(ReadUMXIndex(chunk));
+			if(propertyName >= names.size() || names[propertyName] != "none")
+			{
+				// Can't bother to implement property reading, as no UMX files I've seen so far use properties for the relevant objects,
+				// and only the UAX files in the Unreal 1997/98 beta seem to use this and still load just fine when ignoring it.
+				// If it should be necessary to implement this, check CUnProperty.cpp in http://ut-files.com/index.php?dir=Utilities/&file=utcms_source.zip
+				MPT_ASSERT_NOTREACHED();
+				continue;
+			}
+#else
+			ReadUMXIndex(chunk);
+#endif
+
+			if(fileHeader.packageVersion >= 120)
+			{
+				// UT2003 Packages
+				ReadUMXIndex(chunk);
+				chunk.Skip(8);
+			} else if(fileHeader.packageVersion >= 100)
+			{
+				// AAO Packages
+				chunk.Skip(4);
+				ReadUMXIndex(chunk);
+				chunk.Skip(4);
+			} else if(fileHeader.packageVersion >= 62)
+			{
+				// UT Packages
+				// Mech8.umx and a few other UT tunes have packageVersion = 62.
+				// In CUnSound.cpp, the condition above reads "packageVersion >= 63" but if that is used, those tunes won't load properly.
+				ReadUMXIndex(chunk);
+				chunk.Skip(4);
+			} else
+			{
+				// Old Unreal Packagaes
+				ReadUMXIndex(chunk);
+			}
+
+			int32 size = ReadUMXIndex(chunk);
+
+			ContainerItem item;
+
+			if(objName >= 0 && static_cast<std::size_t>(objName) < names.size())
+			{
+				item.name = mpt::ToUnicode(mpt::CharsetISO8859_1, names[objName]);
+			}
+
+			item.file = chunk.ReadChunk(size);
+
+			containerItems.push_back(std::move(item));
+
+		}
+	}
+
+	return !containerItems.empty();
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/ContainerXPK.cpp b/soundlib/ContainerXPK.cpp
new file mode 100644
index 0000000..3ade69d
--- /dev/null
+++ b/soundlib/ContainerXPK.cpp
@@ -0,0 +1,440 @@
+/*
+ * ContainerXPK.cpp
+ * ----------------
+ * Purpose: Handling of XPK compressed modules
+ * Notes  : (currently none)
+ * Authors: Olivier Lapicque
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#include "../common/FileReader.h"
+#include "Container.h"
+#include "Sndfile.h"
+
+#include <stdexcept>
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+//#define MMCMP_LOG
+
+
+struct XPKFILEHEADER
+{
+	char     XPKF[4];
+	uint32be SrcLen;
+	char     SQSH[4];
+	uint32be DstLen;
+	char     Name[16];
+	uint32be Reserved;
+};
+
+MPT_BINARY_STRUCT(XPKFILEHEADER, 36)
+
+
+struct XPK_error : public std::range_error
+{
+	XPK_error() : std::range_error("invalid XPK data") { }
+};
+
+struct XPK_BufferBounds
+{
+	const uint8 *pSrcBeg;
+	std::size_t SrcSize;
+	uint8 *pDstBeg;
+	std::size_t DstSize;
+
+	inline uint8 SrcRead(std::size_t index)
+	{
+		if(index >= SrcSize) throw XPK_error();
+		return pSrcBeg[index];
+	}
+	inline void DstWrite(std::size_t index, uint8 value)
+	{
+		if(index >= DstSize) throw XPK_error();
+		pDstBeg[index] = value;
+	}
+	inline uint8 DstRead(std::size_t index)
+	{
+		if(index >= DstSize) throw XPK_error();
+		return pDstBeg[index];
+	}
+};
+
+static int32 bfextu(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
+{
+	int32 r;
+
+	p += bo / 8;
+	r = bufs.SrcRead(p); p++;
+	r <<= 8;
+	r |= bufs.SrcRead(p); p++;
+	r <<= 8;
+	r |= bufs.SrcRead(p);
+	r <<= bo % 8;
+	r &= 0xffffff;
+	r >>= 24 - bc;
+
+	return r;
+}
+
+static int32 bfexts(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
+{
+	int32 r;
+
+	p += bo / 8;
+	r = bufs.SrcRead(p); p++;
+	r <<= 8;
+	r |= bufs.SrcRead(p); p++;
+	r <<= 8;
+	r |= bufs.SrcRead(p);
+	r <<= (bo % 8) + 8;
+	r >>= 32 - bc;
+
+	return r;
+}
+
+
+static uint8 XPK_ReadTable(int32 index)
+{
+	static const uint8 xpk_table[] = {
+		2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,2,6,7,8,0,5,4,6,2,3,7,8,0,6,5,7,2,3,4,8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0
+	};
+	if(index < 0) throw XPK_error();
+	if(static_cast<std::size_t>(index) >= mpt::size(xpk_table)) throw XPK_error();
+	return xpk_table[index];
+}
+
+static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector<char> &unpackedData, int32 len)
+{
+	if(len <= 0) return false;
+	int32 d0,d1,d2,d3,d4,d5,d6,a2,a5;
+	int32 cp, cup1, type;
+	std::size_t c;
+	std::size_t src;
+	std::size_t dst;
+
+	std::size_t phist = 0;
+	std::size_t dstmax = len;
+
+	unpackedData.resize(len);
+
+	XPK_BufferBounds bufs;
+	bufs.pSrcBeg = src_;
+	bufs.SrcSize = srcLen;
+	bufs.pDstBeg = mpt::byte_cast<uint8 *>(unpackedData.data());
+	bufs.DstSize = len;
+
+	src = 0;
+	dst = 0;
+	c = src;
+	while (len > 0)
+	{
+		type = bufs.SrcRead(c+0);
+		cp = (bufs.SrcRead(c+4)<<8) | (bufs.SrcRead(c+5)); // packed
+		cup1 = (bufs.SrcRead(c+6)<<8) | (bufs.SrcRead(c+7)); // unpacked
+		//Log("  packed=%6d unpacked=%6d bytes left=%d dst=%08X(%d)\n", cp, cup1, len, dst, dst);
+		c += 8;
+		src = c+2;
+		if (type == 0)
+		{
+			// RAW chunk
+			if(cp < 0) throw XPK_error();
+			for(int32 i = 0; i < cp; ++i)
+			{
+				bufs.DstWrite(dst + i, bufs.SrcRead(c + i));
+			}
+			dst+=cp;
+			c+=cp;
+			len -= cp;
+			continue;
+		}
+
+		if (type != 1)
+		{
+		#ifdef MMCMP_LOG
+			Log("Invalid XPK type! (%d bytes left)\n", len);
+		#endif
+			break;
+		}
+		len -= cup1;
+		cp = (cp + 3) & 0xfffc;
+		c += cp;
+
+		d0 = d1 = d2 = a2 = 0;
+		d3 = bufs.SrcRead(src); src++;
+		bufs.DstWrite(dst, (uint8)d3);
+		if (dst < dstmax) dst++;
+		cup1--;
+
+		while (cup1 > 0)
+		{
+			if (d1 >= 8) goto l6dc;
+			if (bfextu(src,d0,1,bufs)) goto l75a;
+			d0 += 1;
+			d5 = 0;
+			d6 = 8;
+			goto l734;
+
+		l6dc:
+			if (bfextu(src,d0,1,bufs)) goto l726;
+			d0 += 1;
+			if (! bfextu(src,d0,1,bufs)) goto l75a;
+			d0 += 1;
+			if (bfextu(src,d0,1,bufs)) goto l6f6;
+			d6 = 2;
+			goto l708;
+
+		l6f6:
+			d0 += 1;
+			if (!bfextu(src,d0,1,bufs)) goto l706;
+			d6 = bfextu(src,d0,3,bufs);
+			d0 += 3;
+			goto l70a;
+
+		l706:
+			d6 = 3;
+		l708:
+			d0 += 1;
+		l70a:
+			d6 = XPK_ReadTable((8*a2) + d6 -17);
+			if (d6 != 8) goto l730;
+		l718:
+			if (d2 >= 20)
+			{
+				d5 = 1;
+				goto l732;
+			}
+			d5 = 0;
+			goto l734;
+
+		l726:
+			d0 += 1;
+			d6 = 8;
+			if (d6 == a2) goto l718;
+			d6 = a2;
+		l730:
+			d5 = 4;
+		l732:
+			d2 += 8;
+		l734:
+			while ((d5 >= 0) && (cup1 > 0))
+			{
+				d4 = bfexts(src,d0,d6,bufs);
+				d0 += d6;
+				d3 -= d4;
+				bufs.DstWrite(dst, (uint8)d3);
+				if (dst < dstmax) dst++;
+				cup1--;
+				d5--;
+			}
+			if (d1 != 31) d1++;
+			a2 = d6;
+		l74c:
+			d6 = d2;
+			d6 >>= 3;
+			d2 -= d6;
+		}
+	}
+	unpackedData.resize(bufs.DstSize - len);
+	return !unpackedData.empty();
+
+l75a:
+	d0 += 1;
+	if (bfextu(src,d0,1,bufs)) goto l766;
+	d4 = 2;
+	goto l79e;
+
+l766:
+	d0 += 1;
+	if (bfextu(src,d0,1,bufs)) goto l772;
+	d4 = 4;
+	goto l79e;
+
+l772:
+	d0 += 1;
+	if (bfextu(src,d0,1,bufs)) goto l77e;
+	d4 = 6;
+	goto l79e;
+
+l77e:
+	d0 += 1;
+	if (bfextu(src,d0,1,bufs)) goto l792;
+	d0 += 1;
+	d6 = bfextu(src,d0,3,bufs);
+	d0 += 3;
+	d6 += 8;
+	goto l7a8;
+
+l792:
+	d0 += 1;
+	d6 = bfextu(src,d0,5,bufs);
+	d0 += 5;
+	d4 = 16;
+	goto l7a6;
+
+l79e:
+	d0 += 1;
+	d6 = bfextu(src,d0,1,bufs);
+	d0 += 1;
+l7a6:
+	d6 += d4;
+l7a8:
+	if (bfextu(src,d0,1,bufs)) goto l7c4;
+	d0 += 1;
+	if (bfextu(src,d0,1,bufs)) goto l7bc;
+	d5 = 8;
+	a5 = 0;
+	goto l7ca;
+
+l7bc:
+	d5 = 14;
+	a5 = -0x1100;
+	goto l7ca;
+
+l7c4:
+	d5 = 12;
+	a5 = -0x100;
+l7ca:
+	d0 += 1;
+	d4 = bfextu(src,d0,d5,bufs);
+	d0 += d5;
+	d6 -= 3;
+	if (d6 >= 0)
+	{
+		if (d6 > 0) d1 -= 1;
+		d1 -= 1;
+		if (d1 < 0) d1 = 0;
+	}
+	d6 += 2;
+	phist = dst + a5 - d4 - 1;
+
+	while ((d6 >= 0) && (cup1 > 0))
+	{
+		d3 = bufs.DstRead(phist); phist++;
+		bufs.DstWrite(dst, (uint8)d3);
+		if (dst < dstmax) dst++;
+		cup1--;
+		d6--;
+	}
+	goto l74c;
+}
+
+
+static bool ValidateHeader(const XPKFILEHEADER &header)
+{
+	if(std::memcmp(header.XPKF, "XPKF", 4) != 0)
+	{
+		return false;
+	}
+	if(std::memcmp(header.SQSH, "SQSH", 4) != 0)
+	{
+		return false;
+	}
+	if(header.SrcLen == 0)
+	{
+		return false;
+	}
+	if(header.DstLen == 0)
+	{
+		return false;
+	}
+	MPT_STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
+	if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8))
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static bool ValidateHeaderFileSize(const XPKFILEHEADER &header, uint64 filesize)
+{
+	if(filesize < header.SrcLen - 8)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize)
+{
+	XPKFILEHEADER header;
+	if(!file.ReadStruct(header))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(header))
+	{
+		return ProbeFailure;
+	}
+	if(pfilesize)
+	{
+		if(!ValidateHeaderFileSize(header, *pfilesize))
+		{
+			return ProbeFailure;
+		}
+	}
+	return ProbeSuccess;
+}
+
+
+bool UnpackXPK(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
+{
+	file.Rewind();
+	containerItems.clear();
+
+	XPKFILEHEADER header;
+	if(!file.ReadStruct(header))
+	{
+		return false;
+	}
+	if(!ValidateHeader(header))
+	{
+		return false;
+	}
+	if(loadFlags == ContainerOnlyVerifyHeader)
+	{
+		return true;
+	}
+
+	if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8)))
+	{
+		return false;
+	}
+
+	containerItems.emplace_back();
+	containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
+	std::vector<char> & unpackedData = *(containerItems.back().data_cache);
+
+#ifdef MMCMP_LOG
+	Log("XPK detected (SrcLen=%d DstLen=%d) filesize=%d\n", header.SrcLen, header.DstLen, file.GetLength());
+#endif
+	bool result = false;
+	try
+	{
+		result = XPK_DoUnpack(file.GetRawData<uint8>(), header.SrcLen - (sizeof(XPKFILEHEADER) - 8), unpackedData, header.DstLen);
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		return false;
+	} catch(const XPK_error &)
+	{
+		return false;
+	}
+
+	if(result)
+	{
+		containerItems.back().file = FileReader(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(unpackedData)));
+	}
+	return result;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/Dither.cpp b/soundlib/Dither.cpp
index 69bb13e..a04d671 100644
--- a/soundlib/Dither.cpp
+++ b/soundlib/Dither.cpp
@@ -24,7 +24,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 mpt::ustring Dither::GetModeName(DitherMode mode)
-//-----------------------------------------------
 {
 	switch(mode)
 	{
@@ -45,7 +44,6 @@ mpt::ustring Dither::GetModeName(DitherMode mode)
 #ifdef ENABLE_X86
 
 void X86_Dither(int *pBuffer, uint32 nSamples, uint32 nBits, DitherModPlugState *state)
-//-------------------------------------------------------------------------------------
 {
 	if(nBits + MIXING_ATTENUATION + 1 >= 32) //if(nBits>16)
 	{
@@ -95,8 +93,7 @@ noiseloop:
 #endif // ENABLE_X86
 
 
-static forceinline int32 dither_rand(uint32 &a, uint32 &b)
-//--------------------------------------------------------
+static MPT_FORCEINLINE int32 dither_rand(uint32 &a, uint32 &b)
 {
 	a = (a << 1) | (a >> 31);
 	a ^= 0x10204080u;
@@ -106,7 +103,6 @@ static forceinline int32 dither_rand(uint32 &a, uint32 &b)
 }
 
 static void C_Dither(int *pBuffer, std::size_t count, uint32 nBits, DitherModPlugState *state)
-//--------------------------------------------------------------------------------------------
 {
 	if(nBits + MIXING_ATTENUATION + 1 >= 32) //if(nBits>16)
 	{
@@ -131,7 +127,6 @@ static void C_Dither(int *pBuffer, std::size_t count, uint32 nBits, DitherModPlu
 }
 
 static void Dither_ModPlug(int *pBuffer, std::size_t count, std::size_t channels, uint32 nBits, DitherModPlugState &state)
-//------------------------------------------------------------------------------------------------------------------------
 {
 	#ifdef ENABLE_X86
 		X86_Dither(pBuffer, count * channels, nBits, &state);
@@ -145,7 +140,6 @@ template<int targetbits, int channels, int ditherdepth = 1, bool triangular = fa
 struct Dither_SimpleTemplate
 {
 MPT_NOINLINE void operator () (int *mixbuffer, std::size_t count, DitherSimpleState &state, mpt::fast_prng &prng)
-//---------------------------------------------------------------------------------------------------------------
 {
 	STATIC_ASSERT(sizeof(int) == 4);
 	const int rshift = (32-targetbits) - MIXING_ATTENUATION;
@@ -188,7 +182,6 @@ MPT_NOINLINE void operator () (int *mixbuffer, std::size_t count, DitherSimpleSt
 };
 
 static void Dither_Simple(int *mixbuffer, std::size_t count, std::size_t channels, int bits, DitherSimpleState &state, mpt::fast_prng &prng)
-//------------------------------------------------------------------------------------------------------------------------------------------
 {
 	switch(bits)
 	{
@@ -239,28 +232,24 @@ static void Dither_Simple(int *mixbuffer, std::size_t count, std::size_t channel
 
 
 void Dither::Reset()
-//------------------
 {
 	state.Reset();
 	}
 
 
 void Dither::SetMode(DitherMode mode_)
-//------------------------------------
 {
 	mode = mode_;
 }
 
 
 DitherMode Dither::GetMode() const
-//--------------------------------
 {
 	return mode;
 }
 
 
 void Dither::Process(int *mixbuffer, std::size_t count, std::size_t channels, int bits)
-//-------------------------------------------------------------------------------------
 {
 	switch(mode)
 	{
diff --git a/soundlib/Dither.h b/soundlib/Dither.h
index 44edb97..9ba6ac0 100644
--- a/soundlib/Dither.h
+++ b/soundlib/Dither.h
@@ -75,7 +75,6 @@ private:
 public:
 	template <typename Trd>
 	Dither(Trd & rd)
-	//--------------
 		: state(rd)
 	{
 		mode = DitherDefault;
diff --git a/soundlib/Dlsbank.cpp b/soundlib/Dlsbank.cpp
index 2512b05..d1841cd 100644
--- a/soundlib/Dlsbank.cpp
+++ b/soundlib/Dlsbank.cpp
@@ -45,12 +45,23 @@ OPENMPT_NAMESPACE_BEGIN
 #define CONN_SRC_EG2               0x0005
 #define CONN_SRC_PITCHWHEEL        0x0006
 
+#define CONN_SRC_POLYPRESSURE      0x0007
+#define CONN_SRC_CHANNELPRESSURE   0x0008
+#define CONN_SRC_VIBRATO           0x0009
+
 // Midi Controllers 0-127
 #define CONN_SRC_CC1               0x0081
 #define CONN_SRC_CC7               0x0087
 #define CONN_SRC_CC10              0x008a
 #define CONN_SRC_CC11              0x008b
 
+#define CONN_SRC_CC91              0x00db
+#define CONN_SRC_CC93              0x00dd
+
+#define CONN_SRC_RPN0              0x0100
+#define CONN_SRC_RPN1              0x0101
+#define CONN_SRC_RPN2              0x0102
+
 // Generic Destinations
 #define CONN_DST_NONE              0x0000
 #define CONN_DST_ATTENUATION       0x0001
@@ -62,6 +73,8 @@ OPENMPT_NAMESPACE_BEGIN
 #define CONN_DST_LFO_FREQUENCY     0x0104
 #define CONN_DST_LFO_STARTDELAY    0x0105
 
+#define CONN_DST_KEYNUMBER         0x0005
+
 // EG1 Destinations
 #define CONN_DST_EG1_ATTACKTIME    0x0206
 #define CONN_DST_EG1_DECAYTIME     0x0207
@@ -69,6 +82,10 @@ OPENMPT_NAMESPACE_BEGIN
 #define CONN_DST_EG1_RELEASETIME   0x0209
 #define CONN_DST_EG1_SUSTAINLEVEL  0x020a
 
+#define CONN_DST_EG1_DELAYTIME     0x020b
+#define CONN_DST_EG1_HOLDTIME      0x020c
+#define CONN_DST_EG1_SHUTDOWNTIME  0x020d
+
 // EG2 Destinations
 #define CONN_DST_EG2_ATTACKTIME    0x030a
 #define CONN_DST_EG2_DECAYTIME     0x030b
@@ -76,6 +93,9 @@ OPENMPT_NAMESPACE_BEGIN
 #define CONN_DST_EG2_RELEASETIME   0x030d
 #define CONN_DST_EG2_SUSTAINLEVEL  0x030e
 
+#define CONN_DST_EG2_DELAYTIME     0x030f
+#define CONN_DST_EG2_HOLDTIME      0x0310
+
 #define CONN_TRN_NONE              0x0000
 #define CONN_TRN_CONCAVE           0x0001
 
@@ -98,6 +118,9 @@ OPENMPT_NAMESPACE_BEGIN
 #define ART_VOL_EG_DECAYTIME	MAKE_ART(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_EG1_DECAYTIME)
 #define ART_VOL_EG_SUSTAINLEVEL	MAKE_ART(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_EG1_SUSTAINLEVEL)
 #define ART_VOL_EG_RELEASETIME	MAKE_ART(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_EG1_RELEASETIME)
+#define ART_VOL_EG_DELAYTIME	MAKE_ART(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_EG1_DELAYTIME)
+#define ART_VOL_EG_HOLDTIME		MAKE_ART(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_EG1_HOLDTIME)
+#define ART_VOL_EG_SHUTDOWNTIME	MAKE_ART(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_EG1_SHUTDOWNTIME)
 #define ART_VOL_EG_VELTOATTACK	MAKE_ART(CONN_SRC_KEYONVELOCITY,	CONN_SRC_NONE,	CONN_DST_EG1_ATTACKTIME)
 #define ART_VOL_EG_KEYTODECAY	MAKE_ART(CONN_SRC_KEYNUMBER,		CONN_SRC_NONE,	CONN_DST_EG1_DECAYTIME)
 
@@ -112,11 +135,6 @@ OPENMPT_NAMESPACE_BEGIN
 // Default Pan
 #define ART_DEFAULTPAN		MAKE_ART	(CONN_SRC_NONE,	CONN_SRC_NONE,	CONN_DST_PAN)
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 //////////////////////////////////////////////////////////
 // DLS IFF Chunk IDs
 
@@ -157,155 +175,137 @@ OPENMPT_NAMESPACE_BEGIN
 //////////////////////////////////////////////////////////
 // DLS Structures definitions
 
-typedef struct PACKED IFFCHUNK
-{
-	uint32 id;
-	uint32 len;
-} IFFCHUNK, *LPIFFCHUNK;
-
-STATIC_ASSERT(sizeof(IFFCHUNK) == 8);
-
-typedef struct PACKED RIFFCHUNKID
+struct IFFCHUNK
 {
-	uint32 id_RIFF;
-	uint32 riff_len;
-	uint32 id_DLS;
-} RIFFCHUNKID;
+	uint32le id;
+	uint32le len;
+};
 
-STATIC_ASSERT(sizeof(RIFFCHUNKID) == 12);
+MPT_BINARY_STRUCT(IFFCHUNK, 8)
 
-typedef struct PACKED LISTCHUNK
+struct RIFFCHUNKID
 {
-	uint32 id;
-	uint32 len;
-	uint32 listid;
-} LISTCHUNK;
+	uint32le id_RIFF;
+	uint32le riff_len;
+	uint32le id_DLS;
+};
 
-STATIC_ASSERT(sizeof(LISTCHUNK) == 12);
+MPT_BINARY_STRUCT(RIFFCHUNKID, 12)
 
-typedef struct PACKED DLSRGNRANGE
+struct LISTCHUNK
 {
-	uint16 usLow;
-	uint16 usHigh;
-} DLSRGNRANGE;
+	uint32le id;
+	uint32le len;
+	uint32le listid;
+};
 
-STATIC_ASSERT(sizeof(DLSRGNRANGE) == 4);
+MPT_BINARY_STRUCT(LISTCHUNK, 12)
 
-typedef struct PACKED COLHCHUNK
+struct DLSRGNRANGE
 {
-	uint32 id;
-	uint32 len;
-	uint32 ulInstruments;
-} COLHCHUNK;
+	uint16le usLow;
+	uint16le usHigh;
+};
 
-STATIC_ASSERT(sizeof(COLHCHUNK) == 12);
+MPT_BINARY_STRUCT(DLSRGNRANGE, 4)
 
-typedef struct PACKED VERSCHUNK
+struct VERSCHUNK
 {
-	uint32 id;
-	uint32 len;
-	uint16 version[4];
-} VERSCHUNK;
+	uint32le id;
+	uint32le len;
+	uint16le version[4];
+};
 
-STATIC_ASSERT(sizeof(VERSCHUNK) == 16);
+MPT_BINARY_STRUCT(VERSCHUNK, 16)
 
-typedef struct PACKED PTBLCHUNK
+struct PTBLCHUNK
 {
-	uint32 id;
-	uint32 len;
-	uint32 cbSize;
-	uint32 cCues;
-	uint32 ulOffsets[1];
-} PTBLCHUNK;
+	uint32le cbSize;
+	uint32le cCues;
+};
 
-STATIC_ASSERT(sizeof(PTBLCHUNK) == 20);
+MPT_BINARY_STRUCT(PTBLCHUNK, 8)
 
-typedef struct PACKED INSHCHUNK
+struct INSHCHUNK
 {
-	uint32 id;
-	uint32 len;
-	uint32 cRegions;
-	uint32 ulBank;
-	uint32 ulInstrument;
-} INSHCHUNK;
+	uint32le id;
+	uint32le len;
+	uint32le cRegions;
+	uint32le ulBank;
+	uint32le ulInstrument;
+};
 
-STATIC_ASSERT(sizeof(INSHCHUNK) == 20);
+MPT_BINARY_STRUCT(INSHCHUNK, 20)
 
-typedef struct PACKED RGNHCHUNK
+struct RGNHCHUNK
 {
-	uint32 id;
-	uint32 len;
+	uint32le id;
+	uint32le len;
 	DLSRGNRANGE RangeKey;
 	DLSRGNRANGE RangeVelocity;
-	uint16 fusOptions;
-	uint16 usKeyGroup;
-} RGNHCHUNK;
+	uint16le fusOptions;
+	uint16le usKeyGroup;
+};
 
-STATIC_ASSERT(sizeof(RGNHCHUNK) == 20);
+MPT_BINARY_STRUCT(RGNHCHUNK, 20)
 
-typedef struct PACKED WLNKCHUNK
+struct WLNKCHUNK
 {
-	uint32 id;
-	uint32 len;
-	uint16 fusOptions;
-	uint16 usPhaseGroup;
-	uint32 ulChannel;
-	uint32 ulTableIndex;
-} WLNKCHUNK;
+	uint32le id;
+	uint32le len;
+	uint16le fusOptions;
+	uint16le usPhaseGroup;
+	uint32le ulChannel;
+	uint32le ulTableIndex;
+};
 
-STATIC_ASSERT(sizeof(WLNKCHUNK) == 20);
+MPT_BINARY_STRUCT(WLNKCHUNK, 20)
 
-typedef struct PACKED ART1CHUNK
+struct ART1CHUNK
 {
-	uint32 id;
-	uint32 len;
-	uint32 cbSize;
-	uint32 cConnectionBlocks;
-} ART1CHUNK;
+	uint32le id;
+	uint32le len;
+	uint32le cbSize;
+	uint32le cConnectionBlocks;
+};
 
-STATIC_ASSERT(sizeof(ART1CHUNK) == 16);
+MPT_BINARY_STRUCT(ART1CHUNK, 16)
 
-typedef struct PACKED CONNECTIONBLOCK
+struct CONNECTIONBLOCK
 {
-	uint16 usSource;
-	uint16 usControl;
-	uint16 usDestination;
-	uint16 usTransform;
-	LONG lScale;
-} CONNECTIONBLOCK;
+	uint16le usSource;
+	uint16le usControl;
+	uint16le usDestination;
+	uint16le usTransform;
+	int32le  lScale;
+};
 
-STATIC_ASSERT(sizeof(CONNECTIONBLOCK) == 12);
+MPT_BINARY_STRUCT(CONNECTIONBLOCK, 12)
 
-typedef struct PACKED WSMPCHUNK
+struct WSMPCHUNK
 {
-	uint32 id;
-	uint32 len;
-	uint32 cbSize;
-	uint16 usUnityNote;
-	int16 sFineTune;
-	LONG lAttenuation;
-	uint32 fulOptions;
-	uint32 cSampleLoops;
-} WSMPCHUNK;
-
-STATIC_ASSERT(sizeof(WSMPCHUNK) == 28);
-
-typedef struct PACKED WSMPSAMPLELOOP
+	uint32le id;
+	uint32le len;
+	uint32le cbSize;
+	uint16le usUnityNote;
+	int16le  sFineTune;
+	int32le  lAttenuation;
+	uint32le fulOptions;
+	uint32le cSampleLoops;
+};
+
+MPT_BINARY_STRUCT(WSMPCHUNK, 28)
+
+struct WSMPSAMPLELOOP
 {
-	uint32 cbSize;
-	uint32 ulLoopType;
-	uint32 ulLoopStart;
-	uint32 ulLoopLength;
-	void ConvertEndianness()
-	{
-		SwapBytesLE(cbSize);
-		SwapBytesLE(ulLoopType);
-		SwapBytesLE(ulLoopStart);
-		SwapBytesLE(ulLoopLength);
-	}
-} WSMPSAMPLELOOP;
+	uint32le cbSize;
+	uint32le ulLoopType;
+	uint32le ulLoopStart;
+	uint32le ulLoopLength;
 
-STATIC_ASSERT(sizeof(WSMPSAMPLELOOP) == 16);
+};
+
+MPT_BINARY_STRUCT(WSMPSAMPLELOOP, 16)
 
 
 /////////////////////////////////////////////////////////////////////
@@ -325,121 +325,143 @@ STATIC_ASSERT(sizeof(WSMPSAMPLELOOP) == 16);
 ///////////////////////////////////////////
 // SF2 Generators IDs
 
-#define SF2_GEN_MODENVTOFILTERFC		11
-#define SF2_GEN_PAN						17
-#define SF2_GEN_DECAYMODENV				28
-#define SF2_GEN_DECAYVOLENV				36
-#define SF2_GEN_RELEASEVOLENV			38
-#define SF2_GEN_INSTRUMENT				41
-#define SF2_GEN_KEYRANGE				43
-#define SF2_GEN_ATTENUATION				48
-#define SF2_GEN_COARSETUNE				51
-#define SF2_GEN_FINETUNE				52
-#define SF2_GEN_SAMPLEID				53
-#define SF2_GEN_SAMPLEMODES				54
-#define SF2_GEN_KEYGROUP				57
-#define SF2_GEN_UNITYNOTE				58
+enum SF2Generators
+{
+	SF2_GEN_MODENVTOFILTERFC	= 11,
+	SF2_GEN_PAN					= 17,
+	SF2_GEN_DECAYMODENV			= 28,
+	SF2_GEN_ATTACKVOLENV		= 34,
+	SF2_GEN_HOLDVOLENV			= 34,
+	SF2_GEN_DECAYVOLENV			= 36,
+	SF2_GEN_SUSTAINVOLENV		= 37,
+	SF2_GEN_RELEASEVOLENV		= 38,
+	SF2_GEN_INSTRUMENT			= 41,
+	SF2_GEN_KEYRANGE			= 43,
+	SF2_GEN_ATTENUATION			= 48,
+	SF2_GEN_COARSETUNE			= 51,
+	SF2_GEN_FINETUNE			= 52,
+	SF2_GEN_SAMPLEID			= 53,
+	SF2_GEN_SAMPLEMODES			= 54,
+	SF2_GEN_KEYGROUP			= 57,
+	SF2_GEN_UNITYNOTE			= 58,
+};
 
 /////////////////////////////////////////////////////////////////////
 // SF2 Structures Definitions
 
-typedef struct PACKED SFPRESETHEADER
+struct SFPRESETHEADER
 {
-	char achPresetName[20];
-	uint16 wPreset;
-	uint16 wBank;
-	uint16 wPresetBagNdx;
-	uint32 dwLibrary;
-	uint32 dwGenre;
-	uint32 dwMorphology;
-} SFPRESETHEADER;
-
-STATIC_ASSERT(sizeof(SFPRESETHEADER) == 38);
-
-typedef struct PACKED SFPRESETBAG
+	char     achPresetName[20];
+	uint16le wPreset;
+	uint16le wBank;
+	uint16le wPresetBagNdx;
+	uint32le dwLibrary;
+	uint32le dwGenre;
+	uint32le dwMorphology;
+};
+
+MPT_BINARY_STRUCT(SFPRESETHEADER, 38)
+
+struct SFPRESETBAG
 {
-	uint16 wGenNdx;
-	uint16 wModNdx;
-} SFPRESETBAG;
+	uint16le wGenNdx;
+	uint16le wModNdx;
+};
 
-STATIC_ASSERT(sizeof(SFPRESETBAG) == 4);
+MPT_BINARY_STRUCT(SFPRESETBAG, 4)
 
-typedef struct PACKED SFGENLIST
+struct SFGENLIST
 {
-	uint16 sfGenOper;
-	uint16 genAmount;
-} SFGENLIST;
+	uint16le sfGenOper;
+	uint16le genAmount;
+};
 
-STATIC_ASSERT(sizeof(SFGENLIST) == 4);
+MPT_BINARY_STRUCT(SFGENLIST, 4)
 
-typedef struct PACKED SFINST
+struct SFINST
 {
-	char achInstName[20];
-	uint16 wInstBagNdx;
-} SFINST;
+	char     achInstName[20];
+	uint16le wInstBagNdx;
+};
 
-STATIC_ASSERT(sizeof(SFINST) == 22);
+MPT_BINARY_STRUCT(SFINST, 22)
 
-typedef struct PACKED SFINSTBAG
+struct SFINSTBAG
 {
-	uint16 wGenNdx;
-	uint16 wModNdx;
-} SFINSTBAG;
+	uint16le wGenNdx;
+	uint16le wModNdx;
+};
 
-STATIC_ASSERT(sizeof(SFINSTBAG) == 4);
+MPT_BINARY_STRUCT(SFINSTBAG, 4)
 
-typedef struct PACKED SFINSTGENLIST
+struct SFINSTGENLIST
 {
-	uint16 sfGenOper;
-	uint16 genAmount;
-} SFINSTGENLIST;
+	uint16le sfGenOper;
+	uint16le genAmount;
+};
 
-STATIC_ASSERT(sizeof(SFINSTGENLIST) == 4);
+MPT_BINARY_STRUCT(SFINSTGENLIST, 4)
 
-typedef struct PACKED SFSAMPLE
+struct SFSAMPLE
 {
-	char achSampleName[20];
-	uint32 dwStart;
-	uint32 dwEnd;
-	uint32 dwStartloop;
-	uint32 dwEndloop;
-	uint32 dwSampleRate;
-	uint8 byOriginalPitch;
-	char chPitchCorrection;
-	uint16 wSampleLink;
-	uint16 sfSampleType;
-} SFSAMPLE;
-
-STATIC_ASSERT(sizeof(SFSAMPLE) == 46);
+	char     achSampleName[20];
+	uint32le dwStart;
+	uint32le dwEnd;
+	uint32le dwStartloop;
+	uint32le dwEndloop;
+	uint32le dwSampleRate;
+	uint8le  byOriginalPitch;
+	int8le   chPitchCorrection;
+	uint16le wSampleLink;
+	uint16le sfSampleType;
+};
+
+MPT_BINARY_STRUCT(SFSAMPLE, 46)
 
 // End of structures definitions
 /////////////////////////////////////////////////////////////////////
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
 
-typedef struct SF2LOADERINFO
+struct SF2LOADERINFO
 {
 	uint32 nPresetBags;
-	SFPRESETBAG *pPresetBags;
+	const SFPRESETBAG *pPresetBags;
 	uint32 nPresetGens;
-	SFGENLIST *pPresetGens;
+	const SFGENLIST *pPresetGens;
 	uint32 nInsts;
-	SFINST *pInsts;
+	const SFINST *pInsts;
 	uint32 nInstBags;
-	SFINSTBAG *pInstBags;
+	const SFINSTBAG *pInstBags;
 	uint32 nInstGens;
-	SFINSTGENLIST *pInstGens;
-} SF2LOADERINFO;
+	const SFINSTGENLIST *pInstGens;
+};
 
 
 /////////////////////////////////////////////////////////////////////
 // Unit conversion
 
-LONG CDLSBank::DLS32BitTimeCentsToMilliseconds(LONG lTimeCents)
-//-------------------------------------------------------------
+static uint8 DLSSustainLevelToLinear(int32 sustain)
+{
+	// 0.1% units
+	if(sustain >= 0)
+	{
+		int32 l = sustain / (1000 * 512);
+		if(l >= 0 || l <= 128)
+			return static_cast<uint8>(l);
+	}
+	return 128;
+}
+
+
+static uint8 SF2SustainLevelToLinear(int32 sustain)
+{
+	// 0.1% units
+	int32 l = 128 * (1000 - Clamp(sustain, 0, 1000)) / 1000;
+	return static_cast<uint8>(l);
+}
+
+
+int32 CDLSBank::DLS32BitTimeCentsToMilliseconds(int32 lTimeCents)
 {
 	// tc = log2(time[secs]) * 1200*65536
 	// time[secs] = 2^(tc/(1200*65536))
@@ -447,30 +469,27 @@ LONG CDLSBank::DLS32BitTimeCentsToMilliseconds(LONG lTimeCents)
 	double fmsecs = 1000.0 * pow(2.0, ((double)lTimeCents)/(1200.0*65536.0));
 	if (fmsecs < -32767) return -32767;
 	if (fmsecs > 32767) return 32767;
-	return (LONG)fmsecs;
+	return (int32)fmsecs;
 }
 
 
 // 0dB = 0x10000
-LONG CDLSBank::DLS32BitRelativeGainToLinear(LONG lCentibels)
-//----------------------------------------------------------
+int32 CDLSBank::DLS32BitRelativeGainToLinear(int32 lCentibels)
 {
 	// v = 10^(cb/(200*65536)) * V
-	return (LONG)(65536.0 * pow(10.0, ((double)lCentibels)/(200*65536.0)) );
+	return (int32)(65536.0 * pow(10.0, ((double)lCentibels)/(200*65536.0)) );
 }
 
 
-LONG CDLSBank::DLS32BitRelativeLinearToGain(LONG lGain)
-//-----------------------------------------------------
+int32 CDLSBank::DLS32BitRelativeLinearToGain(int32 lGain)
 {
 	// cb = log10(v/V) * 200 * 65536
 	if (lGain <= 0) return -960 * 65536;
-	return (LONG)( 200*65536.0 * log10( ((double)lGain)/65536.0 ) );
+	return (int32)( 200*65536.0 * log10( ((double)lGain)/65536.0 ) );
 }
 
 
-LONG CDLSBank::DLSMidiVolumeToLinear(uint32 nMidiVolume)
-//------------------------------------------------------
+int32 CDLSBank::DLSMidiVolumeToLinear(uint32 nMidiVolume)
 {
 	return (nMidiVolume * nMidiVolume << 16) / (127*127);
 }
@@ -480,67 +499,28 @@ LONG CDLSBank::DLSMidiVolumeToLinear(uint32 nMidiVolume)
 // Implementation
 
 CDLSBank::CDLSBank()
-//------------------
 {
-	m_nInstruments = 0;
-	m_nWaveForms = 0;
-	m_nEnvelopes = 0;
-	m_nSamplesEx = 0;
 	m_nMaxWaveLink = 0;
-	m_pWaveForms = NULL;
-	m_pInstruments = NULL;
-	m_pSamplesEx = NULL;
 	m_nType = SOUNDBANK_TYPE_INVALID;
-	MemsetZero(m_BankInfo);
-}
-
-
-CDLSBank::~CDLSBank()
-//-------------------
-{
-	Destroy();
-}
-
-
-void CDLSBank::Destroy()
-//----------------------
-{
-	if (m_pWaveForms)
-	{
-		delete[] m_pWaveForms;
-		m_pWaveForms = NULL;
-		m_nWaveForms = 0;
-	}
-	if (m_pSamplesEx)
-	{
-		delete[] m_pSamplesEx;
-		m_pSamplesEx = NULL;
-		m_nSamplesEx = 0;
-	}
-	if (m_pInstruments)
-	{
-		delete[] m_pInstruments;
-		m_pInstruments = NULL;
-		m_nInstruments = 0;
-	}
 }
 
 
 bool CDLSBank::IsDLSBank(const mpt::PathString &filename)
-//-------------------------------------------------------
 {
 	RIFFCHUNKID riff;
 	FILE *f;
 	if(filename.empty()) return false;
-	if((f = mpt_fopen(filename, "rb")) == NULL) return false;
+	if((f = mpt_fopen(filename, "rb")) == nullptr) return false;
 	MemsetZero(riff);
 	fread(&riff, sizeof(RIFFCHUNKID), 1, f);
 	// Check for embedded DLS sections
 	if (riff.id_RIFF == IFFID_FORM)
 	{
+		// Miles Sound System
 		do
 		{
-			int len = BigEndian(riff.riff_len);
+			uint32 len = riff.riff_len;
+			len = SwapBytesBE(len);
 			if (len <= 4) break;
 			if (riff.id_DLS == IFFID_XDLS)
 			{
@@ -558,7 +538,8 @@ bool CDLSBank::IsDLSBank(const mpt::PathString &filename)
 		{
 			if(!fread(&riff, sizeof(RIFFCHUNKID), 1, f))
 				break;
-			if (riff.id_DLS == IFFID_DLS) break; // found it
+			if (riff.id_DLS == IFFID_DLS)
+				break; // found it
 			int len = riff.riff_len;
 			if((len % 2u) != 0)
 				len++;
@@ -567,8 +548,8 @@ bool CDLSBank::IsDLSBank(const mpt::PathString &filename)
 	}
 	fclose(f);
 	return ((riff.id_RIFF == IFFID_RIFF)
-		 && ((riff.id_DLS == IFFID_DLS) || (riff.id_DLS == IFFID_MLS) || (riff.id_DLS == IFFID_sfbk))
-		 && (riff.riff_len >= 256));
+		&& ((riff.id_DLS == IFFID_DLS) || (riff.id_DLS == IFFID_MLS) || (riff.id_DLS == IFFID_sfbk))
+		&& (riff.riff_len >= 256));
 }
 
 
@@ -576,12 +557,11 @@ bool CDLSBank::IsDLSBank(const mpt::PathString &filename)
 // Find an instrument based on the given parameters
 
 DLSINSTRUMENT *CDLSBank::FindInstrument(bool bDrum, uint32 nBank, uint32 dwProgram, uint32 dwKey, uint32 *pInsNo)
-//---------------------------------------------------------------------------------------------------------------
 {
-	if ((!m_pInstruments) || (!m_nInstruments)) return NULL;
-	for (uint32 iIns=0; iIns<m_nInstruments; iIns++)
+	if (m_Instruments.empty()) return NULL;
+	for (uint32 iIns=0; iIns<m_Instruments.size(); iIns++)
 	{
-		DLSINSTRUMENT *pDlsIns = &m_pInstruments[iIns];
+		DLSINSTRUMENT *pDlsIns = &m_Instruments[iIns];
 		uint32 insbank = ((pDlsIns->ulBank & 0x7F00) >> 1) | (pDlsIns->ulBank & 0x7F);
 		if ((nBank >= 0x4000) || (insbank == nBank))
 		{
@@ -623,10 +603,8 @@ DLSINSTRUMENT *CDLSBank::FindInstrument(bool bDrum, uint32 nBank, uint32 dwProgr
 ///////////////////////////////////////////////////////////////
 // Update DLS instrument definition from an IFF chunk
 
-bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk, uint32 dwMaxLen)
-//-----------------------------------------------------------------------------------------------
+bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, const IFFCHUNK *pchunk, uint32 dwMaxLen)
 {
-	IFFCHUNK *pchunk = (IFFCHUNK *)pvchunk;
 	if ((!pchunk->len) || (pchunk->len+8 > dwMaxLen)) return false;
 	if (pchunk->id == IFFID_LIST)
 	{
@@ -634,10 +612,10 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 		uint32 dwPos = 12;
 		while (dwPos < plist->len)
 		{
-			LPIFFCHUNK p = (LPIFFCHUNK)(((uint8 *)plist) + dwPos);
+			const IFFCHUNK *p = (const IFFCHUNK *)(((uint8 *)plist) + dwPos);
 			if (!(p->id & 0xFF))
 			{
-				p = (LPIFFCHUNK)( ((uint8 *)p)+1  );
+				p = (const IFFCHUNK *)( ((uint8 *)p)+1  );
 				dwPos++;
 			}
 			if (dwPos + p->len + 8 <= plist->len + 12)
@@ -683,7 +661,7 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 				DLSREGION *pregion = &pDlsIns->Regions[pDlsIns->nRegions];
 				WLNKCHUNK *p = (WLNKCHUNK *)pchunk;
 				pregion->nWaveLink = (uint16)p->ulTableIndex;
-				if ((pregion->nWaveLink < 16384) && (pregion->nWaveLink >= m_nMaxWaveLink)) m_nMaxWaveLink = pregion->nWaveLink + 1;
+				if ((pregion->nWaveLink < uint16_max) && (pregion->nWaveLink >= m_nMaxWaveLink)) m_nMaxWaveLink = pregion->nWaveLink + 1;
 				//Log("  WaveLink %d: fusOptions=0x%02X usPhaseGroup=0x%04X ", pDlsIns->nRegions, p->fusOptions, p->usPhaseGroup);
 				//Log("ulChannel=%d ulTableIndex=%4d\n", p->ulChannel, p->ulTableIndex);
 			}
@@ -697,7 +675,7 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 				pregion->fuOptions |= DLSREGION_OVERRIDEWSMP;
 				pregion->uUnityNote = (uint8)p->usUnityNote;
 				pregion->sFineTune = p->sFineTune;
-				LONG lVolume = DLS32BitRelativeGainToLinear(p->lAttenuation) / 256;
+				int32 lVolume = DLS32BitRelativeGainToLinear(p->lAttenuation) / 256;
 				if (lVolume > 256) lVolume = 256;
 				if (lVolume < 4) lVolume = 4;
 				pregion->usVolume = (uint16)lVolume;
@@ -720,7 +698,6 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 
 		case IFFID_art1:
 		case IFFID_art2:
-			if (m_nEnvelopes < DLSMAXENVELOPES)
 			{
 				ART1CHUNK *p = (ART1CHUNK *)pchunk;
 				if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
@@ -728,13 +705,13 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 					if (pDlsIns->nRegions >= DLSMAXREGIONS) break;
 				} else
 				{
-					pDlsIns->nMelodicEnv = m_nEnvelopes + 1;
+					pDlsIns->nMelodicEnv = m_Envelopes.size() + 1;
 				}
 				if (p->cbSize+p->cConnectionBlocks*sizeof(CONNECTIONBLOCK) > p->len) break;
-				DLSENVELOPE *pDlsEnv = &m_Envelopes[m_nEnvelopes];
-				MemsetZero(*pDlsEnv);
-				pDlsEnv->nDefPan = 128;
-				pDlsEnv->nVolSustainLevel = 128;
+				DLSENVELOPE dlsEnv;
+				MemsetZero(dlsEnv);
+				dlsEnv.nDefPan = 128;
+				dlsEnv.nVolSustainLevel = 128;
 				//Log("  art1 (%3d bytes): cbSize=%d cConnectionBlocks=%d\n", p->len, p->cbSize, p->cConnectionBlocks);
 				CONNECTIONBLOCK *pblk = (CONNECTIONBLOCK *)( ((uint8 *)p)+8+p->cbSize );
 				for (uint32 iblk=0; iblk<p->cConnectionBlocks; iblk++, pblk++)
@@ -751,13 +728,13 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 							int32 pan = 128 + pblk->lScale / (65536000/128);
 							if (pan < 0) pan = 0;
 							if (pan > 255) pan = 255;
-							pDlsEnv->nDefPan = (uint8)pan;
+							dlsEnv.nDefPan = (uint8)pan;
 						}
 						break;
 
 					case ART_VOL_EG_ATTACKTIME:
 						// 32-bit time cents units. range = [0s, 20s]
-						pDlsEnv->wVolAttack = 0;
+						dlsEnv.wVolAttack = 0;
 						if (pblk->lScale > -0x40000000)
 						{
 							int32 l = pblk->lScale - 78743200; // maximum velocity
@@ -765,32 +742,32 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 							int32 attacktime = DLS32BitTimeCentsToMilliseconds(l);
 							if (attacktime < 0) attacktime = 0;
 							if (attacktime > 20000) attacktime = 20000;
-							if (attacktime >= 20) pDlsEnv->wVolAttack = (uint16)(attacktime / 20);
-							//Log("%3d: Envelope Attack Time set to %d (%d time cents)\n", (uint32)(pDlsEnv->ulInstrument & 0x7F)|((pDlsEnv->ulBank >> 16) & 0x8000), attacktime, pblk->lScale);
+							if (attacktime >= 20) dlsEnv.wVolAttack = (uint16)(attacktime / 20);
+							//Log("%3d: Envelope Attack Time set to %d (%d time cents)\n", (uint32)(dlsEnv.ulInstrument & 0x7F)|((dlsEnv.ulBank >> 16) & 0x8000), attacktime, pblk->lScale);
 						}
 						break;
 
 					case ART_VOL_EG_DECAYTIME:
 						// 32-bit time cents units. range = [0s, 20s]
-						pDlsEnv->wVolDecay = 0;
+						dlsEnv.wVolDecay = 0;
 						if (pblk->lScale > -0x40000000)
 						{
 							int32 decaytime = DLS32BitTimeCentsToMilliseconds(pblk->lScale);
 							if (decaytime > 20000) decaytime = 20000;
-							if (decaytime >= 20) pDlsEnv->wVolDecay = (uint16)(decaytime / 20);
-							//Log("%3d: Envelope Decay Time set to %d (%d time cents)\n", (uint32)(pDlsEnv->ulInstrument & 0x7F)|((pDlsEnv->ulBank >> 16) & 0x8000), decaytime, pblk->lScale);
+							if (decaytime >= 20) dlsEnv.wVolDecay = (uint16)(decaytime / 20);
+							//Log("%3d: Envelope Decay Time set to %d (%d time cents)\n", (uint32)(dlsEnv.ulInstrument & 0x7F)|((dlsEnv.ulBank >> 16) & 0x8000), decaytime, pblk->lScale);
 						}
 						break;
 
 					case ART_VOL_EG_RELEASETIME:
 						// 32-bit time cents units. range = [0s, 20s]
-						pDlsEnv->wVolRelease = 0;
+						dlsEnv.wVolRelease = 0;
 						if (pblk->lScale > -0x40000000)
 						{
 							int32 releasetime = DLS32BitTimeCentsToMilliseconds(pblk->lScale);
 							if (releasetime > 20000) releasetime = 20000;
-							if (releasetime >= 20) pDlsEnv->wVolRelease = (uint16)(releasetime / 20);
-							//Log("%3d: Envelope Release Time set to %d (%d time cents)\n", (uint32)(pDlsEnv->ulInstrument & 0x7F)|((pDlsEnv->ulBank >> 16) & 0x8000), pDlsEnv->wVolRelease, pblk->lScale);
+							if (releasetime >= 20) dlsEnv.wVolRelease = (uint16)(releasetime / 20);
+							//Log("%3d: Envelope Release Time set to %d (%d time cents)\n", (uint32)(dlsEnv.ulInstrument & 0x7F)|((dlsEnv.ulBank >> 16) & 0x8000), dlsEnv.wVolRelease, pblk->lScale);
 						}
 						break;
 
@@ -798,9 +775,7 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 						// 0.1% units
 						if (pblk->lScale >= 0)
 						{
-							int32 l = pblk->lScale / (1000*512);
-							if ((l >= 0) || (l <= 128)) pDlsEnv->nVolSustainLevel = (uint8)l;
-							//Log("%3d: Envelope Sustain Level set to %d (%d)\n", (uint32)(pDlsIns->ulInstrument & 0x7F)|((pDlsIns->ulBank >> 16) & 0x8000), l, pblk->lScale);
+							dlsEnv.nVolSustainLevel = DLSSustainLevelToLinear(pblk->lScale);
 						}
 						break;
 
@@ -808,7 +783,7 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 					//	Log("    Articulation = 0x%08X value=%d\n", dwArticulation, pblk->lScale);
 					}
 				}
-				m_nEnvelopes++;
+				m_Envelopes.push_back(dlsEnv);
 			}
 			break;
 
@@ -821,7 +796,7 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 				char sid[5];
 				memcpy(sid, &pchunk->id, 4);
 				sid[4] = 0;
-				Log("    \"%s\": %d bytes\n", (uint32)sid, pchunk->len);
+				Log("    \"%s\": %d bytes\n", (uint32)sid, pchunk->len.get());
 			}
 	#endif
 		}
@@ -832,49 +807,47 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pvchunk,
 ///////////////////////////////////////////////////////////////
 // Converts SF2 chunks to DLS
 
-bool CDLSBank::UpdateSF2PresetData(void *pvsf2, void *pvchunk, uint32 dwMaxLen)
-//-----------------------------------------------------------------------------
+bool CDLSBank::UpdateSF2PresetData(SF2LOADERINFO &sf2info, const IFFCHUNK &header, FileReader &chunk)
 {
-	SF2LOADERINFO *psf2 = (SF2LOADERINFO *)pvsf2;
-	IFFCHUNK *pchunk = (IFFCHUNK *)pvchunk;
-	if ((!pchunk->len) || (pchunk->len+8 > dwMaxLen)) return false;
-	switch(pchunk->id)
+	if (!chunk.IsValid()) return false;
+	switch(header.id)
 	{
 	case IFFID_phdr:
-		if (m_nInstruments) break;
-		m_nInstruments = pchunk->len / sizeof(SFPRESETHEADER);
-		if (m_nInstruments) m_nInstruments--; // Disgard EOP
-		if (!m_nInstruments) break;
-		m_pInstruments = new DLSINSTRUMENT[m_nInstruments];
-		if (m_pInstruments)
+		if (m_Instruments.empty())
 		{
-			memset(m_pInstruments, 0, m_nInstruments * sizeof(DLSINSTRUMENT));
+			uint32 numIns = chunk.GetLength() / sizeof(SFPRESETHEADER);
+			if(numIns <= 1)
+				break;
+			// The terminal sfPresetHeader record should never be accessed, and exists only to provide a terminal wPresetBagNdx with which to determine the number of zones in the last preset.
+			numIns--;
+			m_Instruments.resize(numIns);
+
 		#ifdef DLSBANK_LOG
-			Log("phdr: %d instruments\n", m_nInstruments);
+			Log("phdr: %d instruments\n", m_Instruments.size());
 		#endif
-			SFPRESETHEADER *psfh = (SFPRESETHEADER *)(pchunk+1);
-			DLSINSTRUMENT *pDlsIns = m_pInstruments;
-			for (uint32 i=0; i<m_nInstruments; i++, psfh++, pDlsIns++)
+			SFPRESETHEADER psfh;
+			chunk.ReadStruct(psfh);
+			for (auto &dlsIns : m_Instruments)
 			{
-				mpt::String::Copy(pDlsIns->szName, psfh->achPresetName);
-				pDlsIns->szName[20] = 0;
-				pDlsIns->ulInstrument = psfh->wPreset & 0x7F;
-				pDlsIns->ulBank = (psfh->wBank >= 128) ? F_INSTRUMENT_DRUMS : (psfh->wBank << 8);
-				pDlsIns->wPresetBagNdx = psfh->wPresetBagNdx;
-				pDlsIns->wPresetBagNum = 1;
-				if (psfh[1].wPresetBagNdx > pDlsIns->wPresetBagNdx) pDlsIns->wPresetBagNum = (uint16)(psfh[1].wPresetBagNdx - pDlsIns->wPresetBagNdx);
+				mpt::String::Copy(dlsIns.szName, psfh.achPresetName);
+				dlsIns.ulInstrument = psfh.wPreset & 0x7F;
+				dlsIns.ulBank = (psfh.wBank >= 128) ? F_INSTRUMENT_DRUMS : (psfh.wBank << 8);
+				dlsIns.wPresetBagNdx = psfh.wPresetBagNdx;
+				dlsIns.wPresetBagNum = 1;
+				chunk.ReadStruct(psfh);
+				if (psfh.wPresetBagNdx > dlsIns.wPresetBagNdx) dlsIns.wPresetBagNum = static_cast<uint16>(psfh.wPresetBagNdx - dlsIns.wPresetBagNdx);
 			}
 		}
 		break;
 
 	case IFFID_pbag:
-		if (m_pInstruments)
+		if (!m_Instruments.empty())
 		{
-			uint32 nBags = pchunk->len / sizeof(SFPRESETBAG);
+			uint32 nBags = chunk.GetLength() / sizeof(SFPRESETBAG);
 			if (nBags)
 			{
-				psf2->nPresetBags = nBags;
-				psf2->pPresetBags = (SFPRESETBAG *)(pchunk+1);
+				sf2info.nPresetBags = nBags;
+				sf2info.pPresetBags = reinterpret_cast<const SFPRESETBAG *>(chunk.GetRawData());
 			}
 		}
 	#ifdef DLSINSTR_LOG
@@ -883,13 +856,13 @@ bool CDLSBank::UpdateSF2PresetData(void *pvsf2, void *pvchunk, uint32 dwMaxLen)
 		break;
 
 	case IFFID_pgen:
-		if (m_pInstruments)
+		if (!m_Instruments.empty())
 		{
-			uint32 nGens = pchunk->len / sizeof(SFGENLIST);
+			uint32 nGens = chunk.GetLength() / sizeof(SFGENLIST);
 			if (nGens)
 			{
-				psf2->nPresetGens = nGens;
-				psf2->pPresetGens = (SFGENLIST *)(pchunk+1);
+				sf2info.nPresetGens = nGens;
+				sf2info.pPresetGens = reinterpret_cast<const SFGENLIST *>(chunk.GetRawData());
 			}
 		}
 	#ifdef DLSINSTR_LOG
@@ -898,71 +871,69 @@ bool CDLSBank::UpdateSF2PresetData(void *pvsf2, void *pvchunk, uint32 dwMaxLen)
 		break;
 
 	case IFFID_inst:
-		if (m_pInstruments)
+		if (!m_Instruments.empty())
 		{
-			uint32 nIns = pchunk->len / sizeof(SFINST);
-			psf2->nInsts = nIns;
-			psf2->pInsts = (SFINST *)(pchunk+1);
+			uint32 nIns = chunk.GetLength() / sizeof(SFINST);
+			sf2info.nInsts = nIns;
+			sf2info.pInsts = reinterpret_cast<const SFINST *>(chunk.GetRawData());
 		}
 		break;
 
 	case IFFID_ibag:
-		if (m_pInstruments)
+		if (!m_Instruments.empty())
 		{
-			uint32 nBags = pchunk->len / sizeof(SFINSTBAG);
+			uint32 nBags = chunk.GetLength() / sizeof(SFINSTBAG);
 			if (nBags)
 			{
-				psf2->nInstBags = nBags;
-				psf2->pInstBags = (SFINSTBAG *)(pchunk+1);
+				sf2info.nInstBags = nBags;
+				sf2info.pInstBags = reinterpret_cast<const SFINSTBAG *>(chunk.GetRawData());
 			}
 		}
 		break;
 
 	case IFFID_igen:
-		if (m_pInstruments)
+		if (!m_Instruments.empty())
 		{
-			uint32 nGens = pchunk->len / sizeof(SFINSTGENLIST);
+			uint32 nGens = chunk.GetLength() / sizeof(SFINSTGENLIST);
 			if (nGens)
 			{
-				psf2->nInstGens = nGens;
-				psf2->pInstGens = (SFINSTGENLIST *)(pchunk+1);
+				sf2info.nInstGens = nGens;
+				sf2info.pInstGens = reinterpret_cast<const SFINSTGENLIST *>(chunk.GetRawData());
 			}
 		}
 		break;
 
 	case IFFID_shdr:
-		if (m_pSamplesEx) break;
-		m_nSamplesEx = pchunk->len / sizeof(SFSAMPLE);
+		if (m_SamplesEx.empty())
+		{
+			uint32 numSmp = chunk.GetLength() / sizeof(SFSAMPLE);
+			if (numSmp < 1) break;
+			m_SamplesEx.resize(numSmp);
+			m_WaveForms.resize(numSmp);
 	#ifdef DLSINSTR_LOG
-		Log("shdr: %d samples\n", m_nSamplesEx);
+		Log("shdr: %d samples\n", m_SamplesEx.size());
 	#endif
-		if (m_nSamplesEx < 1) break;
-		m_nWaveForms = m_nSamplesEx;
-		m_pSamplesEx = new DLSSAMPLEEX[m_nSamplesEx];
-		m_pWaveForms = new uint32[m_nWaveForms];
-		if ((m_pSamplesEx) && (m_pWaveForms))
-		{
-			memset(m_pSamplesEx, 0, sizeof(DLSSAMPLEEX)*m_nSamplesEx);
-			memset(m_pWaveForms, 0, sizeof(uint32)*m_nWaveForms);
-			DLSSAMPLEEX *pDlsSmp = m_pSamplesEx;
-			SFSAMPLE *p = (SFSAMPLE *)(pchunk+1);
-			for (uint32 i=0; i<m_nSamplesEx; i++, pDlsSmp++, p++)
+
+			for (uint32 i = 0; i < numSmp; i++)
 			{
-				mpt::String::Copy(pDlsSmp->szName, p->achSampleName);
-				pDlsSmp->dwLen = 0;
-				pDlsSmp->dwSampleRate = p->dwSampleRate;
-				pDlsSmp->byOriginalPitch = p->byOriginalPitch;
-				pDlsSmp->chPitchCorrection = p->chPitchCorrection;
-				if (((p->sfSampleType & 0x7FFF) <= 4) && (p->dwStart < 0x08000000) && (p->dwEnd >= p->dwStart+8))
+				SFSAMPLE p;
+				chunk.ReadStruct(p);
+				DLSSAMPLEEX &dlsSmp = m_SamplesEx[i];
+				mpt::String::Copy(dlsSmp.szName, p.achSampleName);
+				dlsSmp.dwLen = 0;
+				dlsSmp.dwSampleRate = p.dwSampleRate;
+				dlsSmp.byOriginalPitch = p.byOriginalPitch;
+				dlsSmp.chPitchCorrection = static_cast<int8>(Util::muldivr(p.chPitchCorrection, 128, 100));
+				if (((p.sfSampleType & 0x7FFF) <= 4) && (p.dwStart < 0x08000000) && (p.dwEnd >= p.dwStart+8))
 				{
-					pDlsSmp->dwLen = (p->dwEnd - p->dwStart) * 2;
-					if ((p->dwEndloop > p->dwStartloop + 7) && (p->dwStartloop >= p->dwStart))
+					dlsSmp.dwLen = (p.dwEnd - p.dwStart) * 2;
+					if ((p.dwEndloop > p.dwStartloop + 7) && (p.dwStartloop >= p.dwStart))
 					{
-						pDlsSmp->dwStartloop = p->dwStartloop - p->dwStart;
-						pDlsSmp->dwEndloop = p->dwEndloop - p->dwStart;
+						dlsSmp.dwStartloop = p.dwStartloop - p.dwStart;
+						dlsSmp.dwEndloop = p.dwEndloop - p.dwStart;
 					}
-					m_pWaveForms[i] = p->dwStart * 2;
-					//Log("  offset[%d]=%d len=%d\n", i, p->dwStart*2, psmp->dwLen);
+					m_WaveForms[i] = p.dwStart * 2;
+					//Log("  offset[%d]=%d len=%d\n", i, p.dwStart*2, psmp->dwLen);
 				}
 			}
 		}
@@ -972,9 +943,9 @@ bool CDLSBank::UpdateSF2PresetData(void *pvsf2, void *pvchunk, uint32 dwMaxLen)
 	default:
 		{
 			char sdbg[5];
-			memcpy(sdbg, &pchunk->id, 4);
+			memcpy(sdbg, &header.id, 4);
 			sdbg[4] = 0;
-			Log("Unsupported SF2 chunk: %s (%d bytes)\n", sdbg, pchunk->len);
+			Log("Unsupported SF2 chunk: %s (%d bytes)\n", sdbg, header.len.get());
 		}
 	#endif
 	}
@@ -982,21 +953,24 @@ bool CDLSBank::UpdateSF2PresetData(void *pvsf2, void *pvchunk, uint32 dwMaxLen)
 }
 
 
+static int16 SF2TimeToDLS(int16 amount)
+{
+	int32 time = CDLSBank::DLS32BitTimeCentsToMilliseconds(static_cast<int32>(amount) << 16);
+	return static_cast<int16>(Clamp(time, 20, 20000) / 20);
+}
+
+
 // Convert all instruments to the DLS format
-bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
-//---------------------------------------------
+bool CDLSBank::ConvertSF2ToDLS(SF2LOADERINFO &sf2info)
 {
-	SF2LOADERINFO *psf2;
-	DLSINSTRUMENT *pDlsIns;
+	if (m_Instruments.empty() || m_SamplesEx.empty())
+		return false;
 
-	if ((!m_pInstruments) || (!m_pSamplesEx)) return false;
-	psf2 = (SF2LOADERINFO *)pvsf2info;
-	pDlsIns = m_pInstruments;
-	for (uint32 nIns=0; nIns<m_nInstruments; nIns++, pDlsIns++)
+	for (auto &dlsIns : m_Instruments)
 	{
 		DLSENVELOPE dlsEnv;
 		uint32 nInstrNdx = 0;
-		LONG lAttenuation = 0;
+		int32 lAttenuation = 0;
 		// Default Envelope Values
 		dlsEnv.wVolAttack = 0;
 		dlsEnv.wVolDecay = 0;
@@ -1004,33 +978,33 @@ bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
 		dlsEnv.nVolSustainLevel = 128;
 		dlsEnv.nDefPan = 128;
 		// Load Preset Bags
-		for (uint32 ipbagcnt=0; ipbagcnt<(uint32)pDlsIns->wPresetBagNum; ipbagcnt++)
+		for (uint32 ipbagcnt=0; ipbagcnt<(uint32)dlsIns.wPresetBagNum; ipbagcnt++)
 		{
-			uint32 ipbagndx = pDlsIns->wPresetBagNdx + ipbagcnt;
-			if ((ipbagndx+1 >= psf2->nPresetBags) || (!psf2->pPresetBags)) break;
+			uint32 ipbagndx = dlsIns.wPresetBagNdx + ipbagcnt;
+			if ((ipbagndx+1 >= sf2info.nPresetBags) || (!sf2info.pPresetBags)) break;
 			// Load generators for each preset bag
-			SFPRESETBAG *pbag = psf2->pPresetBags + ipbagndx;
+			const SFPRESETBAG *pbag = sf2info.pPresetBags + ipbagndx;
 			for (uint32 ipgenndx=pbag[0].wGenNdx; ipgenndx<pbag[1].wGenNdx; ipgenndx++)
 			{
-				if ((!psf2->pPresetGens) || (ipgenndx+1 >= psf2->nPresetGens)) break;
-				SFGENLIST *pgen = psf2->pPresetGens + ipgenndx;
+				if ((!sf2info.pPresetGens) || (ipgenndx+1 >= sf2info.nPresetGens)) break;
+				const SFGENLIST *pgen = sf2info.pPresetGens + ipgenndx;
 				switch(pgen->sfGenOper)
 				{
+				case SF2_GEN_ATTACKVOLENV:
+					dlsEnv.wVolAttack = SF2TimeToDLS(pgen->genAmount);
+					break;
 				case SF2_GEN_DECAYVOLENV:
+					dlsEnv.wVolDecay = SF2TimeToDLS(pgen->genAmount);
+					break;
+				case SF2_GEN_SUSTAINVOLENV:
+					// 0.1% units
+					if(pgen->genAmount >= 0)
 					{
-						LONG decaytime = DLS32BitTimeCentsToMilliseconds(((LONG)(short int)pgen->genAmount)<<16);
-						if (decaytime > 20000) decaytime = 20000;
-						if (decaytime >= 20) dlsEnv.wVolDecay = (uint16)(decaytime / 20);
-						//Log("  vol decay time set to %d\n", decaytime);
+						dlsEnv.nVolSustainLevel = SF2SustainLevelToLinear(pgen->genAmount);
 					}
 					break;
 				case SF2_GEN_RELEASEVOLENV:
-					{
-						LONG releasetime = DLS32BitTimeCentsToMilliseconds(((LONG)(short int)pgen->genAmount)<<16);
-						if (releasetime > 20000) releasetime = 20000;
-						if (releasetime >= 20) dlsEnv.wVolRelease = (uint16)(releasetime / 20);
-						//Log("  vol release time set to %d\n", releasetime);
-					}
+					dlsEnv.wVolRelease = SF2TimeToDLS(pgen->genAmount);
 					break;
 				case SF2_GEN_INSTRUMENT:
 					nInstrNdx = pgen->genAmount + 1;
@@ -1048,50 +1022,39 @@ bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
 			}
 		}
 		// Envelope
-		if ((m_nEnvelopes < DLSMAXENVELOPES) && (!(pDlsIns->ulBank & F_INSTRUMENT_DRUMS)))
+		if (!(dlsIns.ulBank & F_INSTRUMENT_DRUMS))
 		{
-			m_Envelopes[m_nEnvelopes] = dlsEnv;
-			m_nEnvelopes++;
-			pDlsIns->nMelodicEnv = m_nEnvelopes;
+			m_Envelopes.push_back(dlsEnv);
+			dlsIns.nMelodicEnv = m_Envelopes.size();
 		}
 		// Load Instrument Bags
-		if ((!nInstrNdx) || (nInstrNdx >= psf2->nInsts) || (!psf2->pInsts)) continue;
+		if ((!nInstrNdx) || (nInstrNdx >= sf2info.nInsts) || (!sf2info.pInsts)) continue;
 		nInstrNdx--;
-		pDlsIns->nRegions = psf2->pInsts[nInstrNdx+1].wInstBagNdx - psf2->pInsts[nInstrNdx].wInstBagNdx;
+		dlsIns.nRegions = sf2info.pInsts[nInstrNdx+1].wInstBagNdx - sf2info.pInsts[nInstrNdx].wInstBagNdx;
 		//Log("\nIns %3d, %2d regions:\n", nIns, pSmp->nRegions);
-		if (pDlsIns->nRegions > DLSMAXREGIONS) pDlsIns->nRegions = DLSMAXREGIONS;
-		DLSREGION *pRgn = pDlsIns->Regions;
-		for (uint32 nRgn=0; nRgn<pDlsIns->nRegions; nRgn++, pRgn++)
+		if (dlsIns.nRegions > DLSMAXREGIONS) dlsIns.nRegions = DLSMAXREGIONS;
+		DLSREGION *pRgn = dlsIns.Regions;
+		for (uint32 nRgn = 0; nRgn < dlsIns.nRegions; nRgn++, pRgn++)
 		{
-			uint32 ibagcnt = psf2->pInsts[nInstrNdx].wInstBagNdx + nRgn;
-			if ((ibagcnt >= psf2->nInstBags) || (!psf2->pInstBags)) break;
+			uint32 ibagcnt = sf2info.pInsts[nInstrNdx].wInstBagNdx + nRgn;
+			if ((ibagcnt >= sf2info.nInstBags) || (!sf2info.pInstBags)) break;
 			// Create a new envelope for drums
 			DLSENVELOPE *pDlsEnv = &dlsEnv;
-			if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
+			if (!(dlsIns.ulBank & F_INSTRUMENT_DRUMS) && dlsIns.nMelodicEnv > 0 && dlsIns.nMelodicEnv <= m_Envelopes.size())
 			{
-				if ((m_nEnvelopes < DLSMAXENVELOPES) && (!(pDlsIns->ulBank & F_INSTRUMENT_DRUMS)))
-				{
-					m_Envelopes[m_nEnvelopes] = dlsEnv;
-					pDlsEnv = &m_Envelopes[m_nEnvelopes];
-					m_nEnvelopes++;
-					pRgn->uPercEnv = (uint16)m_nEnvelopes;
-				}
-			} else
-			if (pDlsIns->nMelodicEnv)
-			{
-				pDlsEnv = &m_Envelopes[pDlsIns->nMelodicEnv-1];
+				pDlsEnv = &m_Envelopes[dlsIns.nMelodicEnv - 1];
 			}
 			// Region Default Values
-			LONG lAttn = lAttenuation;
+			int32 lAttn = lAttenuation;
 			pRgn->uUnityNote = 0xFF;	// 0xFF means undefined -> use sample
 			pRgn->sFineTune = 0;
 			pRgn->nWaveLink = Util::MaxValueOfType(pRgn->nWaveLink);
 			// Load Generators
-			SFINSTBAG *pbag = psf2->pInstBags + ibagcnt;
+			const SFINSTBAG *pbag = sf2info.pInstBags + ibagcnt;
 			for (uint32 igenndx=pbag[0].wGenNdx; igenndx<pbag[1].wGenNdx; igenndx++)
 			{
-				if ((igenndx >= psf2->nInstGens) || (!psf2->pInstGens)) break;
-				SFINSTGENLIST *pgen = psf2->pInstGens + igenndx;
+				if ((igenndx >= sf2info.nInstGens) || (!sf2info.pInstGens)) break;
+				const SFINSTGENLIST *pgen = sf2info.pInstGens + igenndx;
 				uint16 value = pgen->genAmount;
 				switch(pgen->sfGenOper)
 				{
@@ -1100,23 +1063,29 @@ bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
 					pRgn->uKeyMax = (uint8)(value >> 8);
 					if (pRgn->uKeyMin > pRgn->uKeyMax)
 					{
-						uint8 b = pRgn->uKeyMax;
-						pRgn->uKeyMax = pRgn->uKeyMin;
-						pRgn->uKeyMin = b;
+						std::swap(pRgn->uKeyMin, pRgn->uKeyMax);
 					}
 					//if (nIns == 9) Log("  keyrange: %d-%d\n", pRgn->uKeyMin, pRgn->uKeyMax);
 					break;
 				case SF2_GEN_UNITYNOTE:
 					if (value < 128) pRgn->uUnityNote = (uint8)value;
 					break;
-				case SF2_GEN_RELEASEVOLENV:
+				case SF2_GEN_ATTACKVOLENV:
+					pDlsEnv->wVolAttack = SF2TimeToDLS(pgen->genAmount);
+					break;
+				case SF2_GEN_DECAYVOLENV:
+					pDlsEnv->wVolDecay = SF2TimeToDLS(pgen->genAmount);
+					break;
+				case SF2_GEN_SUSTAINVOLENV:
+					// 0.1% units
+					if(pgen->genAmount >= 0)
 					{
-						LONG releasetime = DLS32BitTimeCentsToMilliseconds(((LONG)(short int)pgen->genAmount)<<16);
-						if (releasetime > 20000) releasetime = 20000;
-						if (releasetime >= 20) pDlsEnv->wVolRelease = (uint16)(releasetime / 20);
-						//Log("  vol release time set to %d\n", releasetime);
+						pDlsEnv->nVolSustainLevel = SF2SustainLevelToLinear(pgen->genAmount);
 					}
 					break;
+				case SF2_GEN_RELEASEVOLENV:
+					pDlsEnv->wVolRelease = SF2TimeToDLS(pgen->genAmount);
+					break;
 				case SF2_GEN_PAN:
 					{
 						int pan = (short int)value;
@@ -1130,16 +1099,16 @@ bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
 					lAttn = -(int)value;
 					break;
 				case SF2_GEN_SAMPLEID:
-					if ((m_pSamplesEx) && ((uint32)value < m_nSamplesEx))
+					if (value < m_SamplesEx.size())
 					{
 						pRgn->nWaveLink = value;
-						pRgn->ulLoopStart = m_pSamplesEx[value].dwStartloop;
-						pRgn->ulLoopEnd = m_pSamplesEx[value].dwEndloop;
+						pRgn->ulLoopStart = m_SamplesEx[value].dwStartloop;
+						pRgn->ulLoopEnd = m_SamplesEx[value].dwEndloop;
 					}
 					break;
 				case SF2_GEN_SAMPLEMODES:
 					value &= 3;
-					pRgn->fuOptions &= ~(DLSREGION_SAMPLELOOP|DLSREGION_PINGPONGLOOP|DLSREGION_SUSTAINLOOP);
+					pRgn->fuOptions &= uint16(~(DLSREGION_SAMPLELOOP|DLSREGION_PINGPONGLOOP|DLSREGION_SUSTAINLOOP));
 					if (value == 1) pRgn->fuOptions |= DLSREGION_SAMPLELOOP; else
 					if (value == 2) pRgn->fuOptions |= DLSREGION_SAMPLELOOP|DLSREGION_PINGPONGLOOP; else
 					if (value == 3) pRgn->fuOptions |= DLSREGION_SAMPLELOOP|DLSREGION_SUSTAINLOOP;
@@ -1158,7 +1127,7 @@ bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
 				//	Log("    gen=%d value=%04X\n", pgen->sfGenOper, pgen->genAmount);
 				}
 			}
-			LONG lVolume = DLS32BitRelativeGainToLinear((lAttn/10) << 16) / 256;
+			int32 lVolume = DLS32BitRelativeGainToLinear((lAttn/10) << 16) / 256;
 			if (lVolume < 16) lVolume = 16;
 			if (lVolume > 256) lVolume = 256;
 			pRgn->usVolume = (uint16)lVolume;
@@ -1173,7 +1142,6 @@ bool CDLSBank::ConvertSF2ToDLS(void *pvsf2info)
 // Open: opens a DLS bank
 
 bool CDLSBank::Open(const mpt::PathString &filename)
-//--------------------------------------------------
 {
 	if(filename.empty()) return false;
 	m_szFileName = filename;
@@ -1184,66 +1152,62 @@ bool CDLSBank::Open(const mpt::PathString &filename)
 
 
 bool CDLSBank::Open(FileReader file)
-//----------------------------------
 {
 	SF2LOADERINFO sf2info;
-	const uint8 *lpMemFile;	// Pointer to memory-mapped file
-	RIFFCHUNKID *priff;
-	uint32 dwMemPos, dwMemLength;
 	uint32 nInsDef;
 
+	if(!file.GetFileName().empty())
+		m_szFileName = file.GetFileName();
+
 	file.Rewind();
-	m_szFileName = file.GetFileName();
-	lpMemFile = file.GetRawData<uint8>();
-	dwMemLength = file.GetLength();
-	if (!lpMemFile || dwMemLength < 256)
+	const uint8 *lpMemFile = file.GetRawData<uint8>();
+	uint32 dwMemLength = file.GetLength();
+	uint32 dwMemPos = 0;
+	if(!file.CanRead(256))
 	{
 		return false;
 	}
 
-#ifdef DLSBANK_LOG
-	Log("\nOpening DLS bank: %s\n", m_szFileName);
-#endif
-
-	priff = (RIFFCHUNKID *)lpMemFile;
-	dwMemPos = 0;
-
+	RIFFCHUNKID riff;
+	file.ReadStruct(riff);
 	// Check DLS sections embedded in RMI midi files
-	if ((priff->id_RIFF == IFFID_RIFF) && (priff->id_DLS == IFFID_RMID))
+	if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_RMID)
 	{
-		dwMemPos = 12;
-		while (dwMemPos + 12 <= dwMemLength)
+		while(file.ReadStruct(riff))
 		{
-			priff = (RIFFCHUNKID *)(lpMemFile + dwMemPos);
-			if ((priff->id_RIFF == IFFID_RIFF) && (priff->id_DLS == IFFID_DLS)) break;
-			uint32 len = priff->riff_len;
+			if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_DLS)
+			{
+				file.SkipBack(sizeof(riff));
+				break;
+			}
+			uint32 len = riff.riff_len;
 			if((len % 2u) != 0)
 				len++;
-			dwMemPos += len + 8;
+			file.SkipBack(4);
+			file.Skip(len);
 		}
 	}
 
-	// Check XDLS sections embedded in big endian IFF files
-	if (priff->id_RIFF == IFFID_FORM)
+	// Check XDLS sections embedded in big endian IFF files (Miles Sound System)
+	if (riff.id_RIFF == IFFID_FORM)
 	{
-		do {
-			priff = (RIFFCHUNKID *)(lpMemFile + dwMemPos);
-			int len = BigEndian(priff->riff_len);
-			if((len % 2u) != 0)
-				len++;
-			if ((len <= 4) || ((uint32)len >= dwMemLength - dwMemPos)) break;
-			if (priff->id_DLS == IFFID_XDLS)
+		do
+		{
+			if(riff.id_DLS == IFFID_XDLS)
 			{
-				dwMemPos += 12;
-				priff = (RIFFCHUNKID *)(lpMemFile + dwMemPos);
+				file.ReadStruct(riff);
 				break;
 			}
-			dwMemPos += len + 8;
-		} while (dwMemPos + 24 < dwMemLength);
+			uint32 len = SwapBytesBE(riff.riff_len);
+			if((len % 2u) != 0)
+				len++;
+			file.SkipBack(4);
+			file.Skip(len);
+		} while(file.ReadStruct(riff));
 	}
-	if ((priff->id_RIFF != IFFID_RIFF)
-	 || ((priff->id_DLS != IFFID_DLS) && (priff->id_DLS != IFFID_MLS) && (priff->id_DLS != IFFID_sfbk))
-	 || (dwMemPos + priff->riff_len > dwMemLength-8))
+	if (riff.id_RIFF != IFFID_RIFF
+		|| (riff.id_DLS != IFFID_DLS && riff.id_DLS != IFFID_MLS && riff.id_DLS != IFFID_sfbk)
+		|| !file.CanRead(riff.riff_len - 4))
 	{
 	#ifdef DLSBANK_LOG
 		Log("Invalid DLS bank!\n");
@@ -1251,38 +1215,37 @@ bool CDLSBank::Open(FileReader file)
 		return false;
 	}
 	MemsetZero(sf2info);
-	m_nType = (priff->id_DLS == IFFID_sfbk) ? SOUNDBANK_TYPE_SF2 : SOUNDBANK_TYPE_DLS;
+	m_nType = (riff.id_DLS == IFFID_sfbk) ? SOUNDBANK_TYPE_SF2 : SOUNDBANK_TYPE_DLS;
 	m_dwWavePoolOffset = 0;
-	m_nInstruments = 0;
-	m_nWaveForms = 0;
-	m_nEnvelopes = 0;
-	m_pInstruments = NULL;
-	m_pWaveForms = NULL;
+	m_Instruments.clear();
+	m_WaveForms.clear();
+	m_Envelopes.clear();
 	nInsDef = 0;
-	if (dwMemLength > 8 + priff->riff_len + dwMemPos) dwMemLength = 8 + priff->riff_len + dwMemPos;
-	dwMemPos += sizeof(RIFFCHUNKID);
-	while (dwMemPos + sizeof(IFFCHUNK) < dwMemLength)
+	if (dwMemLength > 8 + riff.riff_len + dwMemPos) dwMemLength = 8 + riff.riff_len + dwMemPos;
+	while(file.CanRead(sizeof(IFFCHUNK)))
 	{
-		IFFCHUNK *pchunk = (IFFCHUNK *)(lpMemFile + dwMemPos);
+		IFFCHUNK chunkHeader;
+		file.ReadStruct(chunkHeader);
+		dwMemPos = file.GetPosition();
+		FileReader chunk = file.ReadChunk(chunkHeader.len);
+		if(chunkHeader.len % 2u)
+			file.Skip(1);
+
+		if(!chunk.LengthIsAtLeast(chunkHeader.len))
+			break;
 
-		if (dwMemPos + 8 + pchunk->len > dwMemLength) break;
-		switch(pchunk->id)
+		switch(chunkHeader.id)
 		{
 		// DLS 1.0: Instruments Collection Header
 		case IFFID_colh:
 		#ifdef DLSBANK_LOG
-			Log("colh (%d bytes)\n", pchunk->len);
+			Log("colh (%d bytes)\n", chunkHeader.len);
 		#endif
-			if (!m_pInstruments)
+			if (m_Instruments.empty())
 			{
-				m_nInstruments = ((COLHCHUNK *)pchunk)->ulInstruments;
-				if (m_nInstruments)
-				{
-					m_pInstruments = new DLSINSTRUMENT[m_nInstruments];
-					if (m_pInstruments) memset(m_pInstruments, 0, m_nInstruments * sizeof(DLSINSTRUMENT));
-				}
+				m_Instruments.resize(chunk.ReadUint32LE());
 			#ifdef DLSBANK_LOG
-				Log("  %d instruments\n", m_nInstruments);
+				Log("  %d instruments\n", m_Instruments.size());
 			#endif
 			}
 			break;
@@ -1290,21 +1253,21 @@ bool CDLSBank::Open(FileReader file)
 		// DLS 1.0: Instruments Pointers Table
 		case IFFID_ptbl:
 		#ifdef DLSBANK_LOG
-			Log("ptbl (%d bytes)\n", pchunk->len);
+			Log("ptbl (%d bytes)\n", chunkHeader.len);
 		#endif
-			if (!m_pWaveForms)
+			if (m_WaveForms.empty())
 			{
-				m_nWaveForms = ((PTBLCHUNK *)pchunk)->cCues;
-				if (m_nWaveForms)
+				PTBLCHUNK ptbl;
+				chunk.ReadStruct(ptbl);
+				chunk.Skip(ptbl.cbSize - 8);
+				uint32 cues = std::min(ptbl.cCues.get(), mpt::saturate_cast<uint32>(chunk.BytesLeft() / sizeof(uint32)));
+				m_WaveForms.reserve(cues);
+				for(uint32 i = 0; i < cues; i++)
 				{
-					m_pWaveForms = new uint32[m_nWaveForms];
-					if (m_pWaveForms)
-					{
-						memcpy(m_pWaveForms, (lpMemFile + dwMemPos + 8 + ((PTBLCHUNK *)pchunk)->cbSize), m_nWaveForms * sizeof(uint32));
-					}
+					m_WaveForms.push_back(chunk.ReadUint32LE());
 				}
 			#ifdef DLSBANK_LOG
-				Log("  %d waveforms\n", m_nWaveForms);
+				Log("  %d waveforms\n", m_WaveForms.size());
 			#endif
 			}
 			break;
@@ -1315,69 +1278,70 @@ bool CDLSBank::Open(FileReader file)
 			Log("LIST\n");
 		#endif
 			{
-				LISTCHUNK *plist = (LISTCHUNK *)pchunk;
-				uint32 dwPos = dwMemPos + sizeof(LISTCHUNK);
-				uint32 dwMaxPos = dwMemPos + 8 + plist->len;
-				if (dwMaxPos > dwMemLength) dwMaxPos = dwMemLength;
-				if (((plist->listid == IFFID_wvpl) && (m_nType & SOUNDBANK_TYPE_DLS))
-				 || ((plist->listid == IFFID_sdta) && (m_nType & SOUNDBANK_TYPE_SF2)))
+				uint32 listid = chunk.ReadUint32LE();
+				if (((listid == IFFID_wvpl) && (m_nType & SOUNDBANK_TYPE_DLS))
+				 || ((listid == IFFID_sdta) && (m_nType & SOUNDBANK_TYPE_SF2)))
 				{
-					m_dwWavePoolOffset = dwPos;
+					m_dwWavePoolOffset = dwMemPos + 4;
 				#ifdef DLSBANK_LOG
 					Log("Wave Pool offset: %d\n", m_dwWavePoolOffset);
 				#endif
 					break;
 				}
-				while (dwPos + 12 < dwMaxPos)
+
+				while (chunk.CanRead(12))
 				{
-					if (!(lpMemFile[dwPos])) dwPos++;
-					LISTCHUNK *psublist = (LISTCHUNK *)(lpMemFile+dwPos);
-					if (dwPos + psublist->len + 8 > dwMemLength) break;
+					IFFCHUNK listHeader;
+					const void *subData = chunk.GetRawData();
+					chunk.ReadStruct(listHeader);
+
+					if(!chunk.CanRead(listHeader.len))
+						break;
+
+					FileReader listChunk = chunk.ReadChunk(listHeader.len);
+					if(listHeader.len % 2u)
+						chunk.Skip(1);
 					// DLS Instrument Headers
-					if ((psublist->id == IFFID_LIST) && (m_nType & SOUNDBANK_TYPE_DLS))
+					if (listHeader.id == IFFID_LIST && (m_nType & SOUNDBANK_TYPE_DLS))
 					{
-						if ((psublist->listid == IFFID_ins) && (nInsDef < m_nInstruments) && (m_pInstruments))
+						uint32 subID = listChunk.ReadUint32LE();
+						if ((subID == IFFID_ins) && (nInsDef < m_Instruments.size()))
 						{
-							DLSINSTRUMENT *pDlsIns = &m_pInstruments[nInsDef];
+							DLSINSTRUMENT *pDlsIns = &m_Instruments[nInsDef];
 							//Log("Instrument %d:\n", nInsDef);
-							UpdateInstrumentDefinition(pDlsIns, (IFFCHUNK *)psublist, psublist->len + 8);
+							UpdateInstrumentDefinition(pDlsIns, static_cast<const IFFCHUNK *>(subData), listHeader.len + 8);
 							nInsDef++;
 						}
 					} else
 					// DLS/SF2 Bank Information
-					if ((plist->listid == IFFID_INFO) && (psublist->len))
+					if (listid == IFFID_INFO && listHeader.len)
 					{
-						uint32 len = (psublist->len < 255) ? psublist->len : 255;
-						const char *pszInfo = (const char *)(lpMemFile+dwPos+8);
-						switch(psublist->id)
+						switch(listHeader.id)
 						{
 						case IFFID_INAM:
-							lstrcpynA(m_BankInfo.szBankName, pszInfo, len);
+							listChunk.ReadString<mpt::String::maybeNullTerminated>(m_BankInfo.szBankName, listChunk.BytesLeft());
 							break;
 						case IFFID_IENG:
-							lstrcpynA(m_BankInfo.szEngineer, pszInfo, len);
+							listChunk.ReadString<mpt::String::maybeNullTerminated>(m_BankInfo.szEngineer, listChunk.BytesLeft());
 							break;
 						case IFFID_ICOP:
-							lstrcpynA(m_BankInfo.szCopyRight, pszInfo, len);
+							listChunk.ReadString<mpt::String::maybeNullTerminated>(m_BankInfo.szCopyRight, listChunk.BytesLeft());
 							break;
 						case IFFID_ICMT:
-							len = psublist->len;
-							if (len > sizeof(m_BankInfo.szComments)-1) len = sizeof(m_BankInfo.szComments)-1;
-							lstrcpynA(m_BankInfo.szComments, pszInfo, len);
+							listChunk.ReadString<mpt::String::maybeNullTerminated>(m_BankInfo.szComments, listChunk.BytesLeft());
 							break;
 						case IFFID_ISFT:
-							lstrcpynA(m_BankInfo.szSoftware, pszInfo, len);
+							listChunk.ReadString<mpt::String::maybeNullTerminated>(m_BankInfo.szSoftware, listChunk.BytesLeft());
 							break;
 						case IFFID_ISBJ:
-							lstrcpynA(m_BankInfo.szDescription, pszInfo, len);
+							listChunk.ReadString<mpt::String::maybeNullTerminated>(m_BankInfo.szDescription, listChunk.BytesLeft());
 							break;
 						}
 					} else
-					if ((plist->listid == IFFID_pdta) && (m_nType & SOUNDBANK_TYPE_SF2))
+					if ((listid == IFFID_pdta) && (m_nType & SOUNDBANK_TYPE_SF2))
 					{
-						UpdateSF2PresetData(&sf2info, (IFFCHUNK *)psublist, psublist->len + 8);
+						UpdateSF2PresetData(sf2info, listHeader, listChunk);
 					}
-					dwPos += 8 + psublist->len;
 				}
 			}
 			break;
@@ -1386,42 +1350,37 @@ bool CDLSBank::Open(FileReader file)
 		default:
 			{
 				char sdbg[5];
-				memcpy(sdbg, &pchunk->id, 4);
+				memcpy(sdbg, &chunkHeader.id, 4);
 				sdbg[4] = 0;
-				Log("Unsupported chunk: %s (%d bytes)\n", sdbg, pchunk->len);
+				Log("Unsupported chunk: %s (%d bytes)\n", sdbg, chunkHeader.len);
 			}
 			break;
 		#endif
 		}
-		dwMemPos += 8 + pchunk->len;
 	}
 	// Build the ptbl is not present in file
-	if ((!m_pWaveForms) && (m_dwWavePoolOffset) && (m_nType & SOUNDBANK_TYPE_DLS) && (m_nMaxWaveLink > 0))
+	if ((m_WaveForms.empty()) && (m_dwWavePoolOffset) && (m_nType & SOUNDBANK_TYPE_DLS) && (m_nMaxWaveLink > 0))
 	{
 	#ifdef DLSBANK_LOG
 		Log("ptbl not present: building table (%d wavelinks)...\n", m_nMaxWaveLink);
 	#endif
-		m_pWaveForms = new uint32[m_nMaxWaveLink];
-		if (m_pWaveForms)
+		m_WaveForms.reserve(m_nMaxWaveLink);
+		dwMemPos = m_dwWavePoolOffset;
+		while (dwMemPos + sizeof(IFFCHUNK) < dwMemLength)
 		{
-			memset(m_pWaveForms, 0, m_nMaxWaveLink * sizeof(uint32));
-			dwMemPos = m_dwWavePoolOffset;
-			while (dwMemPos + sizeof(IFFCHUNK) < dwMemLength)
-			{
-				IFFCHUNK *pchunk = (IFFCHUNK *)(lpMemFile + dwMemPos);
-				if (pchunk->id == IFFID_LIST) m_pWaveForms[m_nWaveForms++] = dwMemPos - m_dwWavePoolOffset;
-				dwMemPos += 8 + pchunk->len;
-				if (m_nWaveForms >= m_nMaxWaveLink) break;
-			}
-		#ifdef DLSBANK_LOG
-			Log("Found %d waveforms\n", m_nWaveForms);
-		#endif
+			IFFCHUNK *pchunk = (IFFCHUNK *)(lpMemFile + dwMemPos);
+			if (pchunk->id == IFFID_LIST) m_WaveForms.push_back(dwMemPos - m_dwWavePoolOffset);
+			dwMemPos += 8 + pchunk->len;
+			if (m_WaveForms.size() >= m_nMaxWaveLink) break;
 		}
+#ifdef DLSBANK_LOG
+		Log("Found %d waveforms\n", m_WaveForms.size());
+#endif
 	}
 	// Convert the SF2 data to DLS
-	if ((m_nType & SOUNDBANK_TYPE_SF2) && (m_pSamplesEx) && (m_pInstruments))
+	if ((m_nType & SOUNDBANK_TYPE_SF2) && !m_SamplesEx.empty() && !m_Instruments.empty())
 	{
-		ConvertSF2ToDLS(&sf2info);
+		ConvertSF2ToDLS(sf2info);
 	}
 #ifdef DLSBANK_LOG
 	Log("DLS bank closed\n");
@@ -1433,12 +1392,11 @@ bool CDLSBank::Open(FileReader file)
 // Extracts the WaveForms from a DLS bank
 
 uint32 CDLSBank::GetRegionFromKey(uint32 nIns, uint32 nKey)
-//---------------------------------------------------------
 {
 	DLSINSTRUMENT *pDlsIns;
 
-	if ((!m_pInstruments) || (nIns >= m_nInstruments)) return 0;
-	pDlsIns = &m_pInstruments[nIns];
+	if (nIns >= m_Instruments.size()) return 0;
+	pDlsIns = &m_Instruments[nIns];
 	for (uint32 rgn=0; rgn<pDlsIns->nRegions; rgn++)
 	{
 		if ((nKey >= pDlsIns->Regions[rgn].uKeyMin) && (nKey <= pDlsIns->Regions[rgn].uKeyMax))
@@ -1451,56 +1409,53 @@ uint32 CDLSBank::GetRegionFromKey(uint32 nIns, uint32 nKey)
 
 
 bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length)
-//----------------------------------------------------------------------------------------------------
 {
-	DLSINSTRUMENT *pDlsIns;
-	uint32 dwOffset;
-	uint32 nWaveLink;
-	FILE *f;
+	waveData.clear();
+	length = 0;
 
-	if ((!m_pInstruments) || (nIns >= m_nInstruments)
-	 || (!m_dwWavePoolOffset) || (!m_pWaveForms))
+	if (nIns >= m_Instruments.size() || !m_dwWavePoolOffset)
 	{
 	#ifdef DLSBANK_LOG
-		Log("ExtractWaveForm(%d) failed: m_nInstruments=%d m_dwWavePoolOffset=%d m_pWaveForms=0x%08X\n", nIns, m_nInstruments, m_dwWavePoolOffset, m_pWaveForms);
+		Log("ExtractWaveForm(%d) failed: m_Instruments.size()=%d m_dwWavePoolOffset=%d m_WaveForms.size()=%d\n", nIns, m_Instruments.size(), m_dwWavePoolOffset, m_WaveForms.size());
 	#endif
 		return false;
 	}
-	waveData.clear();
-	length = 0;
-	pDlsIns = &m_pInstruments[nIns];
-	if (nRgn >= pDlsIns->nRegions)
+	DLSINSTRUMENT &dlsIns = m_Instruments[nIns];
+	if (nRgn >= dlsIns.nRegions)
 	{
 	#ifdef DLSBANK_LOG
 		Log("invalid waveform region: nIns=%d nRgn=%d pSmp->nRegions=%d\n", nIns, nRgn, pSmp->nRegions);
 	#endif
 		return false;
 	}
-	nWaveLink = pDlsIns->Regions[nRgn].nWaveLink;
-	if (nWaveLink >= m_nWaveForms)
+	uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink;
+	if(nWaveLink >= m_WaveForms.size())
 	{
 	#ifdef DLSBANK_LOG
-		Log("Invalid wavelink id: nWaveLink=%d nWaveForms=%d\n", nWaveLink, m_nWaveForms);
+		Log("Invalid wavelink id: nWaveLink=%d nWaveForms=%d\n", nWaveLink, m_WaveForms.size());
 	#endif
 		return false;
 	}
-	dwOffset = m_pWaveForms[nWaveLink] + m_dwWavePoolOffset;
-	if((f = mpt_fopen(m_szFileName, "rb")) == NULL) return false;
+
+	uint32 dwOffset = m_WaveForms[nWaveLink] + m_dwWavePoolOffset;
+	FILE *f = mpt_fopen(m_szFileName, "rb");
+	if(f == nullptr) return false;
 	if (fseek(f, dwOffset, SEEK_SET) == 0)
 	{
 		if (m_nType & SOUNDBANK_TYPE_SF2)
 		{
-			if ((m_pSamplesEx) && (m_pSamplesEx[nWaveLink].dwLen))
+			if (m_SamplesEx[nWaveLink].dwLen)
 			{
 				if (fseek(f, 8, SEEK_CUR) == 0)
 				{
-					length = m_pSamplesEx[nWaveLink].dwLen;
+					length = m_SamplesEx[nWaveLink].dwLen;
 					try
 					{
 						waveData.assign(length + 8, 0);
-						fread(&waveData[0], 1, length, f);
-					} catch(MPTMemoryException)
+						fread(waveData.data(), 1, length, f);
+					} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 					{
+						MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 					}
 				}
 			}
@@ -1515,10 +1470,11 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &wav
 					try
 					{
 						waveData.assign(chunk.len + 8, 0);
-						memcpy(&waveData[0], &chunk, 12);
+						memcpy(waveData.data(), &chunk, 12);
 						fread(&waveData[12], 1, length - 12, f);
-					} catch(MPTMemoryException)
+					} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 					{
+						MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 					}
 				}
 			}
@@ -1530,15 +1486,14 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &wav
 
 
 bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose)
-//-------------------------------------------------------------------------------------------------------------
 {
 	DLSINSTRUMENT *pDlsIns;
 	std::vector<uint8> pWaveForm;
 	uint32 dwLen = 0;
 	bool bOk, bWaveForm;
 
-	if ((!m_pInstruments) || (nIns >= m_nInstruments)) return false;
-	pDlsIns = &m_pInstruments[nIns];
+	if (nIns >= m_Instruments.size()) return false;
+	pDlsIns = &m_Instruments[nIns];
 	if (nRgn >= pDlsIns->nRegions) return false;
 	if (!ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen)) return false;
 	if (dwLen < 16) return false;
@@ -1551,9 +1506,9 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
 		uint32 nWaveLink = pDlsIns->Regions[nRgn].nWaveLink;
 		ModSample &sample = sndFile.GetSample(nSample);
 		if (sndFile.m_nSamples < nSample) sndFile.m_nSamples = nSample;
-		if ((nWaveLink < m_nSamplesEx) && (m_pSamplesEx))
+		if (nWaveLink < m_SamplesEx.size())
 		{
-			DLSSAMPLEEX *p = &m_pSamplesEx[nWaveLink];
+			DLSSAMPLEEX *p = &m_SamplesEx[nWaveLink];
 		#ifdef DLSINSTR_LOG
 			Log("  SF2 WaveLink #%3d: %5dHz\n", nWaveLink, p->dwSampleRate);
 		#endif
@@ -1569,7 +1524,7 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
 			else if(pDlsIns->szName[0])
 				mpt::String::Copy(sndFile.m_szNames[nSample], pDlsIns->szName);
 
-			FileReader chunk(&pWaveForm[0], dwLen);
+			FileReader chunk(mpt::as_span(pWaveForm.data(), dwLen));
 			SampleIO(
 				SampleIO::_16bit,
 				SampleIO::mono,
@@ -1580,7 +1535,7 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
 		bWaveForm = sample.pSample != nullptr;
 	} else
 	{
-		FileReader file(&pWaveForm[0], dwLen);
+		FileReader file(mpt::as_span(pWaveForm.data(), dwLen));
 		bWaveForm = sndFile.ReadWAVSample(nSample, file, false, &wsmpChunk);
 		if(pDlsIns->szName[0])
 			mpt::String::Copy(sndFile.m_szNames[nSample], pDlsIns->szName);
@@ -1627,7 +1582,7 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
 				{
 					WSMPSAMPLELOOP loop;
 					wsmpChunk.Skip(8 + wsmp.cbSize);
-					wsmpChunk.ReadConvertEndianness(loop);
+					wsmpChunk.ReadStruct(loop);
 					if(loop.ulLoopLength > 3)
 					{
 						sample.uFlags.set(CHN_LOOP);
@@ -1646,7 +1601,7 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
 		#endif
 			if (usUnityNote > 0x7F) usUnityNote = 60;
 			int steps = (60 + transpose - usUnityNote) * 128 + sFineTune;
-			sample.nC5Speed = Util::Round<uint32>(std::pow(2.0, steps * (1.0 / (12.0 * 128.0))) * sample.nC5Speed);
+			sample.Transpose(steps * (1.0 / (12.0 * 128.0)));
 
 			Limit(lVolume, 16, 256);
 			sample.nGlobalVol = (uint8)(lVolume / 4);	// 0-64
@@ -1661,16 +1616,21 @@ bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nI
 }
 
 
+static uint16 ScaleEnvelope(uint32 time, float tempoScale)
+{
+	return std::max<uint16>(Util::Round<uint16>(time * tempoScale), 1);
+}
+
+
 bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn)
-//---------------------------------------------------------------------------------------------------------
 {
 	SAMPLEINDEX RgnToSmp[DLSMAXREGIONS];
 	DLSINSTRUMENT *pDlsIns;
 	ModInstrument *pIns;
 	uint32 nRgnMin, nRgnMax, nEnv;
 
-	if ((!m_pInstruments) || (nIns >= m_nInstruments)) return false;
-	pDlsIns = &m_pInstruments[nIns];
+	if (nIns >= m_Instruments.size()) return false;
+	pDlsIns = &m_Instruments[nIns];
 	if (pDlsIns->ulBank & F_INSTRUMENT_DRUMS)
 	{
 		if (nDrumRgn >= pDlsIns->nRegions) return false;
@@ -1827,7 +1787,7 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
 					if(ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen) && dwLen >= sample.GetSampleSizeInBytes() / 2)
 					{
 						SmpLength len = sample.nLength;
-						const int16 *src = reinterpret_cast<int16 *>(&pWaveForm[0]);
+						const int16 *src = reinterpret_cast<int16 *>(pWaveForm.data());
 						int16 *dst = sample.pSample16 + ((pan1 == 0) ? 0 : 1);
 						while(len--)
 						{
@@ -1840,8 +1800,18 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
 			}
 		}
 	}
+
+	float tempoScale = 1.0f;
+	if(sndFile.m_nTempoMode == tempoModeModern)
+	{
+		uint32 ticksPerBeat = sndFile.m_nDefaultRowsPerBeat * sndFile.m_nDefaultSpeed;
+		if(ticksPerBeat == 0)
+			ticksPerBeat = 24;
+		tempoScale = ticksPerBeat / 24.0f;
+	}
+
 	// Initializes Envelope
-	if ((nEnv) && (nEnv <= m_nEnvelopes))
+	if ((nEnv) && (nEnv <= m_Envelopes.size()))
 	{
 		DLSENVELOPE *part = &m_Envelopes[nEnv-1];
 		// Volume Envelope
@@ -1851,17 +1821,15 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
 			// Delay section
 			// -> DLS level 2
 			// Attack section
-			pIns->VolEnv.assign(2, EnvelopeNode());
+			pIns->VolEnv.clear();
 			if (part->wVolAttack)
 			{
-				pIns->VolEnv[0].value = (uint8)(ENVELOPE_MAX / (part->wVolAttack / 2 + 2) + 8);   //	/-----
-				pIns->VolEnv[1].tick = part->wVolAttack;                                          //	|
+				pIns->VolEnv.push_back(0, (uint8)(ENVELOPE_MAX / (part->wVolAttack / 2 + 2) + 8)); //	/-----
+				pIns->VolEnv.push_back(ScaleEnvelope(part->wVolAttack, tempoScale), ENVELOPE_MAX); //	|
 			} else
 			{
-				pIns->VolEnv[0].value = ENVELOPE_MAX;  //	|-----
-				pIns->VolEnv[1].tick = 1;              //	|
+				pIns->VolEnv.push_back(0, ENVELOPE_MAX);
 			}
-			pIns->VolEnv[1].value = ENVELOPE_MAX;
 			// Hold section
 			// -> DLS Level 2
 			// Sustain Level
@@ -1869,76 +1837,82 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
 			{
 				if (part->nVolSustainLevel < 128)
 				{
-					LONG lStartTime = pIns->VolEnv.back().tick;
-					LONG lSusLevel = - DLS32BitRelativeLinearToGain(part->nVolSustainLevel << 9) / 65536;
-					LONG lDecayTime = 1;
+					uint16 lStartTime = pIns->VolEnv.back().tick;
+					int32 lSusLevel = - DLS32BitRelativeLinearToGain(part->nVolSustainLevel << 9) / 65536;
+					int32 lDecayTime = 1;
 					if (lSusLevel > 0)
 					{
-						lDecayTime = (lSusLevel * (LONG)part->wVolDecay) / 960;
+						lDecayTime = (lSusLevel * (int32)part->wVolDecay) / 960;
 						for (uint32 i=0; i<7; i++)
 						{
-							LONG lFactor = 128 - (1 << i);
+							int32 lFactor = 128 - (1 << i);
 							if (lFactor <= part->nVolSustainLevel) break;
-							LONG lev = - DLS32BitRelativeLinearToGain(lFactor << 9) / 65536;
+							int32 lev = - DLS32BitRelativeLinearToGain(lFactor << 9) / 65536;
 							if (lev > 0)
 							{
-								LONG ltime = (lev * (LONG)part->wVolDecay) / 960;
+								int32 ltime = (lev * (int32)part->wVolDecay) / 960;
 								if ((ltime > 1) && (ltime < lDecayTime))
 								{
-									ltime += lStartTime;
-									if (ltime > pIns->VolEnv.back().tick)
+									uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale);
+									if(tick > pIns->VolEnv.back().tick)
 									{
-										pIns->VolEnv.push_back(EnvelopeNode((uint16)ltime, (uint8)(lFactor / 2)));
+										pIns->VolEnv.push_back(tick, (uint8)(lFactor / 2));
 									}
 								}
 							}
 						}
 					}
 
-					if (lStartTime + lDecayTime > (LONG)pIns->VolEnv.back().tick)
+					uint16 decayEnd = lStartTime + ScaleEnvelope(lDecayTime, tempoScale);
+					if (decayEnd > pIns->VolEnv.back().tick)
 					{
-						pIns->VolEnv.push_back(EnvelopeNode((uint16)(lStartTime+lDecayTime), (uint8)((part->nVolSustainLevel+1) / 2)));
+						pIns->VolEnv.push_back(decayEnd, (uint8)((part->nVolSustainLevel+1) / 2));
 					}
 				}
 				pIns->VolEnv.dwFlags.set(ENV_SUSTAIN);
 			} else
 			{
 				pIns->VolEnv.dwFlags.set(ENV_SUSTAIN);
-				pIns->VolEnv.push_back(EnvelopeNode((uint16)(pIns->VolEnv.back().tick + 1), pIns->VolEnv.back().value));
+				pIns->VolEnv.push_back(pIns->VolEnv.back().tick + 1u, pIns->VolEnv.back().value);
 			}
 			pIns->VolEnv.nSustainStart = pIns->VolEnv.nSustainEnd = (uint8)(pIns->VolEnv.size() - 1);
 			// Release section
 			if ((part->wVolRelease) && (pIns->VolEnv.back().value > 1))
 			{
-				LONG lReleaseTime = part->wVolRelease;
-				LONG lStartTime = pIns->VolEnv.back().tick;
-				LONG lStartFactor = pIns->VolEnv.back().value;
-				LONG lSusLevel = - DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536;
-				LONG lDecayEndTime = (lReleaseTime * lSusLevel) / 960;
+				int32 lReleaseTime = part->wVolRelease;
+				uint16 lStartTime = pIns->VolEnv.back().tick;
+				int32 lStartFactor = pIns->VolEnv.back().value;
+				int32 lSusLevel = - DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536;
+				int32 lDecayEndTime = (lReleaseTime * lSusLevel) / 960;
 				lReleaseTime -= lDecayEndTime;
 				for (uint32 i=0; i<5; i++)
 				{
-					LONG lFactor = 1 + ((lStartFactor * 3) >> (i+2));
+					int32 lFactor = 1 + ((lStartFactor * 3) >> (i+2));
 					if ((lFactor <= 1) || (lFactor >= lStartFactor)) continue;
-					LONG lev = - DLS32BitRelativeLinearToGain(lFactor << 10) / 65536;
+					int32 lev = - DLS32BitRelativeLinearToGain(lFactor << 10) / 65536;
 					if (lev > 0)
 					{
-						LONG ltime = (((LONG)part->wVolRelease * lev) / 960) - lDecayEndTime;
+						int32 ltime = (((int32)part->wVolRelease * lev) / 960) - lDecayEndTime;
 						if ((ltime > 1) && (ltime < lReleaseTime))
 						{
-							ltime += lStartTime;
-							if (ltime > pIns->VolEnv.back().tick)
+							uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale);
+							if(tick > pIns->VolEnv.back().tick)
 							{
-								pIns->VolEnv.push_back(EnvelopeNode((uint16)ltime, (uint8)lFactor));
+								pIns->VolEnv.push_back(tick, (uint8)lFactor);
 							}
 						}
 					}
 				}
 				if (lReleaseTime < 1) lReleaseTime = 1;
-				pIns->VolEnv.push_back(EnvelopeNode((uint16)(lStartTime + lReleaseTime), ENVELOPE_MIN));
+				auto releaseTicks = ScaleEnvelope(lReleaseTime, tempoScale);
+				pIns->VolEnv.push_back(lStartTime + releaseTicks, ENVELOPE_MIN);
+				if(releaseTicks > 0)
+				{
+					pIns->nFadeOut = 32768 / releaseTicks;
+				}
 			} else
 			{
-				pIns->VolEnv.push_back(EnvelopeNode((uint16)(pIns->VolEnv.back().tick + 1), ENVELOPE_MIN));
+				pIns->VolEnv.push_back(pIns->VolEnv.back().tick + 1u, ENVELOPE_MIN);
 			}
 		}
 	}
@@ -1950,14 +1924,10 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
 		{
 			pIns->VolEnv.dwFlags.set(ENV_ENABLED);
 			pIns->VolEnv.resize(4);
-			pIns->VolEnv[0].tick = 0;
-			pIns->VolEnv[0].value = ENVELOPE_MAX;
-			pIns->VolEnv[1].tick = 5;
-			pIns->VolEnv[1].value = ENVELOPE_MAX;
-			pIns->VolEnv[2].tick = 10;
-			pIns->VolEnv[2].value = ENVELOPE_MID;
-			pIns->VolEnv[3].tick = 20;	// 1 second max. for drums
-			pIns->VolEnv[3].value = ENVELOPE_MIN;
+			pIns->VolEnv[0] = EnvelopeNode(0, ENVELOPE_MAX);
+			pIns->VolEnv[1] = EnvelopeNode(ScaleEnvelope(5, tempoScale), ENVELOPE_MAX);
+			pIns->VolEnv[2] = EnvelopeNode(pIns->VolEnv[1].tick * 2u, ENVELOPE_MID);
+			pIns->VolEnv[3] = EnvelopeNode(pIns->VolEnv[2].tick * 2u, ENVELOPE_MIN);	// 1 second max. for drums
 		}
 	}
 	return true;
@@ -1965,21 +1935,17 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
 
 
 const char *CDLSBank::GetRegionName(uint32 nIns, uint32 nRgn) const
-//-----------------------------------------------------------------
 {
-	DLSINSTRUMENT *pDlsIns;
-
-	if ((!m_pInstruments) || (nIns >= m_nInstruments)) return nullptr;
-	pDlsIns = &m_pInstruments[nIns];
-	if (nRgn >= pDlsIns->nRegions) return nullptr;
+	if (nIns >= m_Instruments.size()) return nullptr;
+	const DLSINSTRUMENT &dlsIns = m_Instruments[nIns];
+	if (nRgn >= dlsIns.nRegions) return nullptr;
 
 	if (m_nType & SOUNDBANK_TYPE_SF2)
 	{
-		uint32 nWaveLink = pDlsIns->Regions[nRgn].nWaveLink;
-		if ((nWaveLink < m_nSamplesEx) && (m_pSamplesEx))
+		uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink;
+		if (nWaveLink < m_SamplesEx.size())
 		{
-			DLSSAMPLEEX *p = &m_pSamplesEx[nWaveLink];
-			return p->szName;
+			return m_SamplesEx[nWaveLink].szName;
 		}
 	}
 	return nullptr;
@@ -1987,21 +1953,20 @@ const char *CDLSBank::GetRegionName(uint32 nIns, uint32 nRgn) const
 
 
 uint8 CDLSBank::GetPanning(uint32 ins, uint32 region) const
-//---------------------------------------------------------
 {
-	const DLSINSTRUMENT &dlsIns = m_pInstruments[ins];
+	const DLSINSTRUMENT &dlsIns = m_Instruments[ins];
 	if(region >= CountOf(dlsIns.Regions))
 		return 128;
 	const DLSREGION &rgn = dlsIns.Regions[region];
 	if(dlsIns.ulBank & F_INSTRUMENT_DRUMS)
 	{
-		if(rgn.uPercEnv > 0 && rgn.uPercEnv <= m_nEnvelopes)
+		if(rgn.uPercEnv > 0 && rgn.uPercEnv <= m_Envelopes.size())
 		{
 			return m_Envelopes[rgn.uPercEnv - 1].nDefPan;
 		}
 	} else
 	{
-		if(dlsIns.nMelodicEnv > 0 && dlsIns.nMelodicEnv <= m_nEnvelopes)
+		if(dlsIns.nMelodicEnv > 0 && dlsIns.nMelodicEnv <= m_Envelopes.size())
 		{
 			return m_Envelopes[dlsIns.nMelodicEnv - 1].nDefPan;
 		}
diff --git a/soundlib/Dlsbank.h b/soundlib/Dlsbank.h
index c339600..01adb84 100644
--- a/soundlib/Dlsbank.h
+++ b/soundlib/Dlsbank.h
@@ -18,12 +18,10 @@ OPENMPT_NAMESPACE_END
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
+#ifdef MODPLUG_TRACKER
+
 
 #define DLSMAXREGIONS		128
-#define DLSMAXENVELOPES		2048
 
 // Region Flags
 #define DLSREGION_KEYGROUPMASK		0x0F
@@ -33,39 +31,34 @@ OPENMPT_NAMESPACE_BEGIN
 #define DLSREGION_SELFNONEXCLUSIVE	0x80
 #define DLSREGION_SUSTAINLOOP		0x100
 
-typedef struct PACKED DLSREGION
+struct DLSREGION
 {
 	uint32 ulLoopStart;
 	uint32 ulLoopEnd;
 	uint16 nWaveLink;
 	uint16 uPercEnv;
-	uint16 usVolume;		// 0..256
+	uint16 usVolume;	// 0..256
 	uint16 fuOptions;	// flags + key group
-	int16 sFineTune;	// 1..100
-	uint8 uKeyMin;
-	uint8 uKeyMax;
-	uint8 uUnityNote;
-} DLSREGION;
-
-STATIC_ASSERT(sizeof(DLSREGION) == 21);
+	int16  sFineTune;	// +128 = +1 semitone
+	uint8  uKeyMin;
+	uint8  uKeyMax;
+	uint8  uUnityNote;
+};
 
-typedef struct PACKED DLSENVELOPE
+struct DLSENVELOPE
 {
 	// Volume Envelope
 	uint16 wVolAttack;		// Attack Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
-	uint16 wVolDecay;			// Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
+	uint16 wVolDecay;		// Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
 	uint16 wVolRelease;		// Release Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s]
-	uint8 nVolSustainLevel;	// Sustain Level: 0-128, 128=100%
-	// Default Pan
-	uint8 nDefPan;
-} DLSENVELOPE;
-
-STATIC_ASSERT(sizeof(DLSENVELOPE) == 8);
+	uint8 nVolSustainLevel;	// Sustain Level: 0-128, 128=100%	
+	uint8 nDefPan;			// Default Pan
+};
 
 // Special Bank bits
 #define F_INSTRUMENT_DRUMS		0x80000000
 
-typedef struct PACKED DLSINSTRUMENT
+struct DLSINSTRUMENT
 {
 	uint32 ulBank, ulInstrument;
 	uint32 nRegions, nMelodicEnv;
@@ -73,49 +66,38 @@ typedef struct PACKED DLSINSTRUMENT
 	char szName[32];
 	// SF2 stuff (DO NOT USE! -> used internally by the SF2 loader)
 	uint16 wPresetBagNdx, wPresetBagNum;
-} DLSINSTRUMENT;
-
-STATIC_ASSERT(sizeof(DLSINSTRUMENT) == 2740);
+};
 
-typedef struct PACKED DLSSAMPLEEX
+struct DLSSAMPLEEX
 {
-	char szName[20];
+	char   szName[20];
 	uint32 dwLen;
 	uint32 dwStartloop;
 	uint32 dwEndloop;
 	uint32 dwSampleRate;
-	uint8 byOriginalPitch;
-	char chPitchCorrection;
-} DLSSAMPLEEX;
-
-STATIC_ASSERT(sizeof(DLSSAMPLEEX) == 38);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
-
-#ifdef MODPLUG_TRACKER
+	uint8  byOriginalPitch;
+	int8   chPitchCorrection;
+};
 
 
 #define SOUNDBANK_TYPE_INVALID	0
 #define SOUNDBANK_TYPE_DLS		0x01
 #define SOUNDBANK_TYPE_SF2		0x02
 
-typedef struct SOUNDBANKINFO
+struct SOUNDBANKINFO
 {
-	char szBankName[256];
-	char szCopyRight[256];
-	char szComments[512];
-	char szEngineer[256];
-	char szSoftware[256];		// ISFT: Software
-	char szDescription[256];	// ISBJ: Subject
-} SOUNDBANKINFO;
+	std::string szBankName,
+		szCopyRight,
+		szComments,
+		szEngineer,
+		szSoftware,		// ISFT: Software
+		szDescription;	// ISBJ: Subject
+};
 
+struct IFFCHUNK;
+struct SF2LOADERINFO;
 
-//============
 class CDLSBank
-//============
 {
 protected:
 	SOUNDBANKINFO m_BankInfo;
@@ -123,16 +105,14 @@ protected:
 	uint32 m_nType;
 	uint32 m_dwWavePoolOffset;
 	// DLS Information
-	uint32 m_nInstruments, m_nWaveForms, m_nEnvelopes, m_nSamplesEx, m_nMaxWaveLink;
-	uint32 *m_pWaveForms;
-	DLSINSTRUMENT *m_pInstruments;
-	DLSSAMPLEEX *m_pSamplesEx;
-	DLSENVELOPE m_Envelopes[DLSMAXENVELOPES];
+	uint32 m_nMaxWaveLink;
+	std::vector<uint32> m_WaveForms;
+	std::vector<DLSINSTRUMENT> m_Instruments;
+	std::vector<DLSSAMPLEEX> m_SamplesEx;
+	std::vector<DLSENVELOPE> m_Envelopes;
 
 public:
 	CDLSBank();
-	virtual ~CDLSBank();
-	void Destroy();
 	static bool IsDLSBank(const mpt::PathString &filename);
 	static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));}
 	static uint32 MakeDrumCode(uint32 rgn, uint32 instr) { return (0x80000000 | (rgn << 16) | (instr));}
@@ -142,15 +122,14 @@ public:
 	bool Open(FileReader file);
 	mpt::PathString GetFileName() const { return m_szFileName; }
 	uint32 GetBankType() const { return m_nType; }
-	uint32 GetBankInfo(SOUNDBANKINFO *pBankInfo=NULL) const { if (pBankInfo) *pBankInfo = m_BankInfo; return m_nType; }
+	const SOUNDBANKINFO &GetBankInfo() const { return m_BankInfo; }
 
 public:
-	uint32 GetNumInstruments() const { return m_nInstruments; }
-	uint32 GetNumSamples() const { return m_nWaveForms; }
-	DLSINSTRUMENT *GetInstrument(uint32 iIns) { return (m_pInstruments) ? &m_pInstruments[iIns] : NULL; }
-	DLSINSTRUMENT *FindInstrument(bool bDrum, uint32 nBank=0xFF, uint32 dwProgram=0xFF, uint32 dwKey=0xFF, uint32 *pInsNo=NULL);
+	uint32 GetNumInstruments() const { return static_cast<uint32>(m_Instruments.size()); }
+	uint32 GetNumSamples() const { return static_cast<uint32>(m_WaveForms.size()); }
+	DLSINSTRUMENT *GetInstrument(uint32 iIns) { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; }
+	DLSINSTRUMENT *FindInstrument(bool bDrum, uint32 nBank=0xFF, uint32 dwProgram=0xFF, uint32 dwKey=0xFF, uint32 *pInsNo=nullptr);
 	uint32 GetRegionFromKey(uint32 nIns, uint32 nKey);
-	bool FreeWaveForm(uint8 *p);
 	bool ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length);
 	bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose=0);
 	bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn);
@@ -159,16 +138,16 @@ public:
 
 // Internal Loader Functions
 protected:
-	bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, void *pchunk, uint32 dwMaxLen);
-	bool UpdateSF2PresetData(void *psf2info, void *pchunk, uint32 dwMaxLen);
-	bool ConvertSF2ToDLS(void *psf2info);
+	bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, const IFFCHUNK *pchunk, uint32 dwMaxLen);
+	bool UpdateSF2PresetData(SF2LOADERINFO &sf2info, const IFFCHUNK &header, FileReader &chunk);
+	bool ConvertSF2ToDLS(SF2LOADERINFO &sf2info);
 
 public:
 	// DLS Unit conversion
-	static LONG DLS32BitTimeCentsToMilliseconds(LONG lTimeCents);
-	static LONG DLS32BitRelativeGainToLinear(LONG lCentibels);	// 0dB = 0x10000
-	static LONG DLS32BitRelativeLinearToGain(LONG lGain);		// 0dB = 0x10000
-	static LONG DLSMidiVolumeToLinear(uint32 nMidiVolume);		// [0-127] -> [0-0x10000]
+	static int32 DLS32BitTimeCentsToMilliseconds(int32 lTimeCents);
+	static int32 DLS32BitRelativeGainToLinear(int32 lCentibels);	// 0dB = 0x10000
+	static int32 DLS32BitRelativeLinearToGain(int32 lGain);		// 0dB = 0x10000
+	static int32 DLSMidiVolumeToLinear(uint32 nMidiVolume);		// [0-127] -> [0-0x10000]
 };
 
 
diff --git a/soundlib/Fastmix.cpp b/soundlib/Fastmix.cpp
index cf76493..e9d3370 100644
--- a/soundlib/Fastmix.cpp
+++ b/soundlib/Fastmix.cpp
@@ -30,182 +30,249 @@ OPENMPT_NAMESPACE_BEGIN
 
 /////////////////////////////////////////////////////////////////////////
 
-// Returns the number of samples (in 16.16 format) that are going to be read from a sample, given a mix buffer length and the channel's playback speed.
-// Result is negative in case of backwards-playing sample.
-static forceinline int32 BufferLengthToSamples(int32 mixBufferCount, const ModChannel &chn)
-//-----------------------------------------------------------------------------------------
+struct MixLoopState
 {
-	return (mixBufferCount * chn.nInc + static_cast<int32>(chn.nPosLo));
-}
+	const int8 * samplePointer;
+	const int8 * lookaheadPointer;
+	SmpLength lookaheadStart;
+	uint32 maxSamples;
 
+	MixLoopState(const ModChannel &chn)
+	{
+		UpdateLookaheadPointers(chn);
+
+		// For platforms that have no fast 64-bit division, precompute this constant
+		// as it won't change during the invocation of CreateStereoMix.
+		SamplePosition increment = chn.increment;
+		if(increment.IsNegative())
+			increment.Negate();
+		maxSamples = 16384u / (increment.GetUInt() + 1u);
+		if(maxSamples < 2) maxSamples = 2;
+	}
 
-// Returns the buffer length required to render a certain amount of samples, based on the channel's playback speed.
-static forceinline int32 SamplesToBufferLength(int32 numSamples, const ModChannel &chn)
-//-------------------------------------------------------------------------------------
-{
-	return std::max(1, ((numSamples << 16)/* + static_cast<int32>(chn.nPosLo) + 0xFFFF*/) / mpt::abs(chn.nInc));
-}
+	// Calculate offset of loop wrap-around buffer for this sample.
+	void UpdateLookaheadPointers(const ModChannel &chn)
+	{
+		samplePointer = static_cast<const int8 *>(chn.pCurrentSample);
+		lookaheadPointer = nullptr;
+		if(chn.nLoopEnd < InterpolationMaxLookahead)
+			lookaheadStart = chn.nLoopStart;
+		else
+			lookaheadStart = std::max(chn.nLoopStart, chn.nLoopEnd - InterpolationMaxLookahead);
+		// We only need to apply the loop wrap-around logic if the sample is actually looping and if interpolation is applied.
+		// If there is no interpolation happening, there is no lookahead happening the sample read-out is exact.
+		if(chn.dwFlags[CHN_LOOP] && chn.resamplingMode != SRCMODE_NEAREST)
+		{
+			const bool inSustainLoop = chn.InSustainLoop();
 
+			// Do not enable wraparound magic if we're previewing a custom loop!
+			if(inSustainLoop || chn.nLoopEnd == chn.pModSample->nLoopEnd)
+			{
+				SmpLength lookaheadOffset = 3 * InterpolationMaxLookahead + chn.pModSample->nLength - chn.nLoopEnd;
+				if(inSustainLoop)
+				{
+					lookaheadOffset += 4 * InterpolationMaxLookahead;
+				}
+				lookaheadPointer = samplePointer + lookaheadOffset * chn.pModSample->GetBytesPerSample();
+			}
+		}
+	}
 
-// Check how many samples can be rendered without encountering loop or sample end, and also update loop position / direction
-static forceinline int32 GetSampleCount(ModChannel &chn, int32 nSamples, bool ITBidiMode)
-//---------------------------------------------------------------------------------------
-{
-	int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
-	int32 nInc = chn.nInc;
+	// Returns the buffer length required to render a certain amount of samples, based on the channel's playback speed.
+	static MPT_FORCEINLINE uint32 DistanceToBufferLength(SamplePosition from, SamplePosition to, SamplePosition inc)
+	{
+		return static_cast<uint32>((to - from - SamplePosition(1)) / inc) + 1;
+	}
 
-	if ((nSamples <= 0) || (!nInc) || (!chn.nLength)) return 0;
-	// Under zero ?
-	if ((int32)chn.nPos < nLoopStart)
+	// Check how many samples can be rendered without encountering loop or sample end, and also update loop position / direction
+	MPT_FORCEINLINE uint32 GetSampleCount(ModChannel &chn, uint32 nSamples, bool ITPingPongMode) const
 	{
-		if (nInc < 0)
+		int32 nLoopStart = chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0;
+		SamplePosition nInc = chn.increment;
+
+		if ((nSamples <= 0) || nInc.IsZero() || (!chn.nLength)) return 0;
+
+		// Part 1: Making sure the play position is valid, and if necessary, invert the play direction in case we reached a loop boundary of a ping-pong loop.
+		chn.pCurrentSample = samplePointer;
+
+		// Under zero ?
+		if (chn.position.GetInt() < nLoopStart)
 		{
-			// Invert loop for bidi loops
-			int32 nDelta = ((nLoopStart - chn.nPos) << 16) - (chn.nPosLo & 0xffff);
-			chn.nPos = nLoopStart + (nDelta >> 16);
-			chn.nPosLo = nDelta & 0xffff;
-			if (((int32)chn.nPos < nLoopStart) || (chn.nPos >= (nLoopStart+chn.nLength)/2))
-			{
-				chn.nPos = nLoopStart; chn.nPosLo = 0;
-			}
-			nInc = -nInc;
-			chn.nInc = nInc;
-			if(chn.dwFlags[CHN_PINGPONGLOOP])
+			if (nInc.IsNegative())
 			{
-				chn.dwFlags.reset(CHN_PINGPONGFLAG); // go forward
+				// Invert loop for bidi loops
+				chn.position = SamplePosition(nLoopStart + nLoopStart, 0) - chn.position;
+				if ((chn.position.GetInt() < nLoopStart) || (chn.position.GetUInt() >= (nLoopStart + chn.nLength) / 2))
+				{
+					chn.position.Set(nLoopStart, 0);
+				}
+				nInc.Negate();
+				chn.increment = nInc;
+				if(chn.dwFlags[CHN_PINGPONGLOOP])
+				{
+					chn.dwFlags.reset(CHN_PINGPONGFLAG); // go forward
+				} else
+				{
+					chn.dwFlags.set(CHN_PINGPONGFLAG);
+					chn.position.SetInt(chn.nLength - 1);
+					chn.increment.Negate();
+				}
+				if(!chn.dwFlags[CHN_LOOP] || chn.position.GetUInt() >= chn.nLength)
+				{
+					chn.position.Set(chn.nLength);
+					return 0;
+				}
 			} else
 			{
-				chn.dwFlags.set(CHN_PINGPONGFLAG);
-				chn.nPos = chn.nLength - 1;
-				chn.nInc = -nInc;
-			}
-			if(!chn.dwFlags[CHN_LOOP] || chn.nPos >= chn.nLength)
-			{
-				chn.nPos = chn.nLength;
-				chn.nPosLo = 0;
-				return 0;
+				// We probably didn't hit the loop end yet (first loop), so we do nothing
+				if (chn.position.GetInt() < 0) chn.position.SetInt(0);
 			}
-		} else
+		} else if (chn.position.GetUInt() >= chn.nLength)
 		{
-			// We probably didn't hit the loop end yet (first loop), so we do nothing
-			if ((int32)chn.nPos < 0) chn.nPos = 0;
-		}
-	} else
-	// Past the end
-	if (chn.nPos >= chn.nLength)
-	{
-		if(!chn.dwFlags[CHN_LOOP]) return 0; // not looping -> stop this channel
-		if(chn.dwFlags[CHN_PINGPONGLOOP])
-		{
-			// Invert loop
-			if (nInc > 0)
+			// Past the end
+			if(!chn.dwFlags[CHN_LOOP]) return 0; // not looping -> stop this channel
+			if(chn.dwFlags[CHN_PINGPONGLOOP])
 			{
-				nInc = -nInc;
-				chn.nInc = nInc;
-			}
-			chn.dwFlags.set(CHN_PINGPONGFLAG);
-			// adjust loop position
-			int32 nDeltaHi = (chn.nPos - chn.nLength);
-			int32 nDeltaLo = 0x10000 - (chn.nPosLo & 0xffff);
-			chn.nPos = chn.nLength - nDeltaHi - (nDeltaLo>>16);
-			chn.nPosLo = nDeltaLo & 0xffff;
-			// Impulse Tracker's software mixer would put a -2 (instead of -1) in the following line (doesn't happen on a GUS)
-			if ((chn.nPos <= chn.nLoopStart) || (chn.nPos >= chn.nLength)) chn.nPos = chn.nLength - (ITBidiMode ? 2 : 1);
-		} else
-		{
-			if (nInc < 0) // This is a bug
+				// Invert loop
+				if (nInc.IsPositive())
+				{
+					nInc.Negate();
+					chn.increment = nInc;
+				}
+				chn.dwFlags.set(CHN_PINGPONGFLAG);
+				// adjust loop position
+
+				SamplePosition invFract = chn.position.GetInvertedFract();
+				chn.position = SamplePosition(chn.nLength - (chn.position.GetInt() - chn.nLength) - invFract.GetInt(), invFract.GetFract());
+				if ((chn.position.GetUInt() <= chn.nLoopStart) || (chn.position.GetUInt() >= chn.nLength))
+				{
+					// Impulse Tracker's software mixer would put a -2 (instead of -1) in the following line (doesn't happen on a GUS)
+					chn.position.SetInt(chn.nLength - std::min<SmpLength>(chn.nLength, ITPingPongMode ? 2 : 1));
+				}
+			} else
 			{
-				nInc = -nInc;
-				chn.nInc = nInc;
+				if (nInc.IsNegative()) // This is a bug
+				{
+					nInc.Negate();
+					chn.increment = nInc;
+				}
+				// Restart at loop start
+				chn.position += SamplePosition(nLoopStart - chn.nLength, 0);
+				MPT_ASSERT(chn.position.GetInt() >= nLoopStart);
+				// Interpolate correctly after wrapping around
+				chn.dwFlags.set(CHN_WRAPPED_LOOP);
 			}
-			// Restart at loop start
-			chn.nPos += nLoopStart - chn.nLength;
-			if ((int32)chn.nPos < nLoopStart) chn.nPos = chn.nLoopStart;
 		}
-	}
-	int32 nPos = chn.nPos;
-	// too big increment, and/or too small loop length
-	if (nPos < nLoopStart)
-	{
-		if ((nPos < 0) || (nInc < 0)) return 0;
-	}
-	if ((nPos < 0) || (nPos >= (int32)chn.nLength)) return 0;
-	int32 nPosLo = (uint16)chn.nPosLo, nSmpCount = nSamples;
-	if (nInc < 0)
-	{
-		int32 nInv = -nInc;
-		int32 maxsamples = 16384 / ((nInv>>16)+1);
-		if (maxsamples < 2) maxsamples = 2;
-		if (nSamples > maxsamples) nSamples = maxsamples;
-		int32 nDeltaHi = (nInv>>16) * (nSamples - 1);
-		int32 nDeltaLo = (nInv&0xffff) * (nSamples - 1);
-		int32 nPosDest = nPos - nDeltaHi + ((nPosLo - nDeltaLo) >> 16);
-		if (nPosDest < nLoopStart)
+
+		// Part 2: Compute how many samples we can render until we reach the end of sample / loop boundary / etc.
+
+		SamplePosition nPos = chn.position;
+		// too big increment, and/or too small loop length
+		if (nPos.GetInt() < nLoopStart)
 		{
-			nSmpCount = (uint32)(((((int64)nPos - nLoopStart) << 16) + nPosLo - 1) / nInv) + 1;
+			if (nPos.IsNegative() || nInc.IsNegative()) return 0;
 		}
-	} else
-	{
-		int32 maxsamples = 16384 / ((nInc>>16)+1);
-		if (maxsamples < 2) maxsamples = 2;
-		if (nSamples > maxsamples) nSamples = maxsamples;
-		int32 nDeltaHi = (nInc>>16) * (nSamples - 1);
-		int32 nDeltaLo = (nInc&0xffff) * (nSamples - 1);
-		int32 nPosDest = nPos + nDeltaHi + ((nPosLo + nDeltaLo)>>16);
-		if (nPosDest >= (int32)chn.nLength)
+		if (nPos.IsNegative() || nPos.GetUInt() >= chn.nLength) return 0;
+		uint32 nSmpCount = nSamples;
+		SamplePosition nInv = nInc;
+		if (nInc.IsNegative())
 		{
-			nSmpCount = (uint32)(((((int64)chn.nLength - nPos) << 16) - nPosLo - 1) / nInc) + 1;
+			nInv.Negate();
 		}
-	}
-#ifdef _DEBUG
-	{
-		int32 nDeltaHi = (nInc>>16) * (nSmpCount - 1);
-		int32 nDeltaLo = (nInc&0xffff) * (nSmpCount - 1);
-		int32 nPosDest = nPos + nDeltaHi + ((nPosLo + nDeltaLo)>>16);
-		if ((nPosDest < 0) || (nPosDest > (int32)chn.nLength))
+		LimitMax(nSamples, maxSamples);
+		SamplePosition incSamples = nInc * (nSamples - 1);
+		int32 nPosDest = (nPos + incSamples).GetInt();
+
+		const SmpLength nPosInt = nPos.GetUInt();
+		const bool isAtLoopStart = (nPosInt >= chn.nLoopStart && nPosInt < chn.nLoopStart + InterpolationMaxLookahead);
+		if(!isAtLoopStart)
 		{
-			Log("Incorrect delta:\n");
-			Log("nSmpCount=%d: nPos=%5d.x%04X Len=%5d Inc=%2d.x%04X\n",
-				nSmpCount, nPos, nPosLo, chn.nLength, chn.nInc>>16, chn.nInc&0xffff);
-			return 0;
+			chn.dwFlags.reset(CHN_WRAPPED_LOOP);
 		}
-	}
+
+		// Loop wrap-around magic.
+		bool checkDest = true;
+		if(lookaheadPointer != nullptr)
+		{
+			if(nPos.GetUInt() >= lookaheadStart)
+			{
+#if 0
+				const uint32 oldCount = nSmpCount;
+
+				// When going backwards - we can only go back up to lookaheadStart.
+				// When going forwards - read through the whole pre-computed wrap-around buffer if possible.
+				// TODO: ProTracker sample swapping needs hard cut at sample end.
+				int32 samplesToRead = nInc.IsNegative()
+					? (nPosInt - lookaheadStart)
+					//: 2 * InterpolationMaxLookahead - (nPosInt - mixLoopState.lookaheadStart);
+					: (chn.nLoopEnd - nPosInt);
+				//LimitMax(samplesToRead, chn.nLoopEnd - chn.nLoopStart);
+				nSmpCount = SamplesToBufferLength(samplesToRead, chn);
+				Limit(nSmpCount, 1u, oldCount);
+#else
+				if (nInc.IsNegative())
+				{
+					nSmpCount = DistanceToBufferLength(SamplePosition(lookaheadStart, 0), nPos, nInv);
+				} else
+				{
+					nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLoopEnd, 0), nInv);
+				}
 #endif
-	if (nSmpCount <= 1) return 1;
-	if (nSmpCount > nSamples) return nSamples;
-	return nSmpCount;
-}
+				chn.pCurrentSample = lookaheadPointer;
+				checkDest = false;
+			} else if(chn.dwFlags[CHN_WRAPPED_LOOP] && isAtLoopStart)
+			{
+				// We just restarted the loop, so interpolate correctly after wrapping around
+				nSmpCount = DistanceToBufferLength(nPos, SamplePosition(nLoopStart + InterpolationMaxLookahead, 0), nInv);
+				chn.pCurrentSample = lookaheadPointer + (chn.nLoopEnd - nLoopStart) * chn.pModSample->GetBytesPerSample();
+				checkDest = false;
+			} else if(nInc.IsPositive() && static_cast<SmpLength>(nPosDest) >= lookaheadStart && nSmpCount > 1)
+			{
+				// We shouldn't read that far if we're not using the pre-computed wrap-around buffer.
+				nSmpCount = DistanceToBufferLength(nPos, SamplePosition(lookaheadStart, 0), nInv);
+				checkDest = false;
+			}
+		}
 
+		if(checkDest)
+		{
+			// Fix up sample count if target position is invalid
+			if (nInc.IsNegative())
+			{
+				if (nPosDest < nLoopStart)
+				{
+					nSmpCount = DistanceToBufferLength(SamplePosition(chn.nLoopStart, 0), nPos, nInv);
+				}
+			} else
+			{
+				if (nPosDest >= (int32)chn.nLength)
+				{
+					nSmpCount = DistanceToBufferLength(nPos, SamplePosition(chn.nLength, 0), nInv);
+				}
+			}
+		}
 
-// Calculate offset of loop wrap-around buffer for this sample.
-static inline void UpdateLookaheadPointers(const int8* &samplePointer, const int8* &lookaheadPointer, SmpLength &lookaheadStart, const ModChannel &chn)
-//-----------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	samplePointer = static_cast<const int8 *>(chn.pCurrentSample);
-	lookaheadStart = chn.nLoopEnd - InterpolationMaxLookahead;
-	// We only need to apply the loop wrap-around logic if the sample is actually looping and if interpolation is applied.
-	// If there is no interpolation happening, there is no lookahead happening the sample read-out is exact.
-	if(chn.dwFlags[CHN_LOOP] && chn.resamplingMode != SRCMODE_NEAREST)
-	{
-		const bool inSustainLoop = chn.InSustainLoop();
+		Limit(nSmpCount, 1u, nSamples);
 
-		// Do not enable wraparound magic if we're previewing a custom loop!
-		if(inSustainLoop || chn.nLoopEnd == chn.pModSample->nLoopEnd)
+#ifdef _DEBUG
 		{
-			SmpLength lookaheadOffset = 3 * InterpolationMaxLookahead + chn.pModSample->nLength - chn.nLoopEnd;
-			if(inSustainLoop)
+			SmpLength posDest = (nPos + nInc * (nSmpCount - 1)).GetUInt();
+			if (posDest < 0 || posDest > chn.nLength)
 			{
-				lookaheadOffset += 4 * InterpolationMaxLookahead;
+				// We computed an invalid delta!
+				MPT_ASSERT_NOTREACHED();
+				return 0;
 			}
-			lookaheadPointer = samplePointer + lookaheadOffset * chn.pModSample->GetBytesPerSample();
 		}
+#endif
+
+		return nSmpCount;
 	}
-}
+};
 
 
 // Render count * number of channels samples
 void CSoundFile::CreateStereoMix(int count)
-//-----------------------------------------
 {
 	mixsample_t *pOfsL, *pOfsR;
 
@@ -218,7 +285,6 @@ void CSoundFile::CreateStereoMix(int count)
 	CHANNELINDEX nchmixed = 0;
 
 	const bool ITPingPongMode = m_playBehaviour[kITPingPongMode];
-	const bool realtimeMix = !IsRenderingToDisc();
 
 	for(uint32 nChn = 0; nChn < m_nMixChannels; nChn++)
 	{
@@ -237,18 +303,13 @@ void CSoundFile::CreateStereoMix(int count)
 
 		mixsample_t *pbuffer = MixSoundBuffer;
 #ifndef NO_REVERB
-#ifdef ENABLE_MMX
-		if(GetProcSupport() & PROCSUPPORT_MMX)
+		if(((m_MixerSettings.DSPMask & SNDDSP_REVERB) && !chn.dwFlags[CHN_NOREVERB]) || chn.dwFlags[CHN_REVERB])
 		{
-			if(((m_MixerSettings.DSPMask & SNDDSP_REVERB) && !chn.dwFlags[CHN_NOREVERB]) || chn.dwFlags[CHN_REVERB])
-			{
-				pbuffer = m_Reverb.GetReverbSendBuffer(count);
-				pOfsR = &m_Reverb.gnRvbROfsVol;
-				pOfsL = &m_Reverb.gnRvbLOfsVol;
-			}
+			pbuffer = m_Reverb.GetReverbSendBuffer(count);
+			pOfsR = &m_Reverb.gnRvbROfsVol;
+			pOfsL = &m_Reverb.gnRvbLOfsVol;
 		}
 #endif
-#endif
 		if(chn.dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels > 2)
 			pbuffer = MixRearBuffer;
 
@@ -274,11 +335,7 @@ void CSoundFile::CreateStereoMix(int count)
 		}
 #endif // NO_PLUGINS
 
-		const int8 * samplePointer = nullptr;
-		const int8 * lookaheadPointer = nullptr;
-		SmpLength lookaheadStart = 0;
-
-		UpdateLookaheadPointers(samplePointer, lookaheadPointer, lookaheadStart, chn);
+		MixLoopState mixLoopState(chn);
 
 		////////////////////////////////////////////////////
 		CHANNELINDEX naddmix = 0;
@@ -293,13 +350,12 @@ void CSoundFile::CreateStereoMix(int count)
 				if (nrampsamples > chn.nRampLength) nrampsamples = chn.nRampLength;
 			}
 
-			if((nSmpCount = GetSampleCount(chn, nrampsamples, ITPingPongMode)) <= 0)
+			if((nSmpCount = mixLoopState.GetSampleCount(chn, nrampsamples, ITPingPongMode)) <= 0)
 			{
 				// Stopping the channel
 				chn.pCurrentSample = nullptr;
 				chn.nLength = 0;
-				chn.nPos = 0;
-				chn.nPosLo = 0;
+				chn.position.Set(0);
 				chn.nRampLength = 0;
 				EndChannelOfs(chn, pbuffer, nsamples);
 				*pOfsR += chn.nROfs;
@@ -310,54 +366,27 @@ void CSoundFile::CreateStereoMix(int count)
 			}
 
 			// Should we mix this channel ?
-			if((nchmixed >= m_MixerSettings.m_nMaxMixChannels && realtimeMix)	// Too many channels
-				|| (!chn.nRampLength && !(chn.leftVol | chn.rightVol)))			// Channel is completely silent
+			if((nchmixed >= m_MixerSettings.m_nMaxMixChannels)				// Too many channels
+				|| (!chn.nRampLength && !(chn.leftVol | chn.rightVol)))		// Channel is completely silent
 			{
-				int32 delta = BufferLengthToSamples(nSmpCount, chn);
-				chn.nPosLo = delta & 0xFFFF;
-				chn.nPos += (delta >> 16);
+				chn.position += chn.increment * nSmpCount;
 				chn.nROfs = chn.nLOfs = 0;
 				pbuffer += nSmpCount * 2;
 				naddmix = 0;
 			} else
 			{
 				// Do mixing
-
-				// Loop wrap-around magic.
-				if(lookaheadPointer != nullptr)
-				{
-					const int32 readLength = BufferLengthToSamples(nSmpCount, chn) >> 16;
-					
-					chn.pCurrentSample = samplePointer;
-					if(chn.nPos >= lookaheadStart)
-					{
-						const int32 oldCount = nSmpCount;
-
-						// When going backwards - we can only go back up to lookaheadStart.
-						// When going forwards - read through the whole pre-computed wrap-around buffer if possible.
-						const int32 samplesToRead = chn.nInc < 0
-							? (chn.nPos - lookaheadStart)
-							: 2 * InterpolationMaxLookahead - (chn.nPos - lookaheadStart);
-						nSmpCount = SamplesToBufferLength(samplesToRead, chn);
-						Limit(nSmpCount, 1, oldCount);
-						chn.pCurrentSample = lookaheadPointer;
-					} else if(chn.nInc > 0 && chn.nPos + readLength >= lookaheadStart && nSmpCount > 1)
-					{
-						// We shouldn't read that far if we're not using the pre-computed wrap-around buffer.
-						const int32 oldCount = nSmpCount;
-						nSmpCount = SamplesToBufferLength(lookaheadStart - chn.nPos, chn);
-						Limit(nSmpCount, 1, oldCount - 1);
-					}
-				}
-
-
 				mixsample_t *pbufmax = pbuffer + (nSmpCount * 2);
 				chn.nROfs = - *(pbufmax-2);
 				chn.nLOfs = - *(pbufmax-1);
 
-				uint32 targetpos = chn.nPos + (BufferLengthToSamples(nSmpCount, chn) >> 16);
+#ifdef _DEBUG
+				SamplePosition targetpos = chn.position + chn.increment * nSmpCount;
+#endif
 				MixFuncTable::Functions[functionNdx | (chn.nRampLength ? MixFuncTable::ndxRamp : 0)](chn, m_Resampler, pbuffer, nSmpCount);
-				MPT_ASSERT(chn.nPos == targetpos); MPT_UNUSED_VARIABLE(targetpos);
+#ifdef _DEBUG
+				MPT_ASSERT(chn.position.GetUInt() == targetpos.GetUInt());
+#endif
 
 				chn.nROfs += *(pbufmax-2);
 				chn.nLOfs += *(pbufmax-1);
@@ -385,7 +414,7 @@ void CSoundFile::CreateStereoMix(int count)
 				}
 			}
 
-			if(chn.nPos >= chn.nLoopEnd && chn.dwFlags[CHN_LOOP])
+			if(chn.position.GetUInt() >= chn.nLoopEnd && chn.dwFlags[CHN_LOOP])
 			{
 				if(m_playBehaviour[kMODSampleSwap] && chn.nNewIns && chn.nNewIns <= GetNumSamples() && chn.pModSample != &Samples[chn.nNewIns])
 				{
@@ -398,8 +427,8 @@ void CSoundFile::CreateStereoMix(int count)
 					chn.nLength = smp.uFlags[CHN_LOOP] ? smp.nLoopEnd : smp.nLength;
 					chn.nLoopStart = smp.nLoopStart;
 					chn.nLoopEnd = smp.nLoopEnd;
-					chn.nPos = chn.nLoopStart;
-					UpdateLookaheadPointers(samplePointer, lookaheadPointer, lookaheadStart, chn);
+					chn.position.SetInt(chn.nLoopStart);
+					mixLoopState.UpdateLookaheadPointers(chn);
 					if(!chn.pCurrentSample)
 					{
 						break;
@@ -407,14 +436,14 @@ void CSoundFile::CreateStereoMix(int count)
 				} else if(m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0)
 				{
 					// ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end)
-					chn.nPos = 0;
+					chn.position.SetInt(0);
 					chn.nLoopEnd = chn.nLength = chn.pModSample->nLoopEnd;
 				}
 			}
 		} while(nsamples > 0);
 
 		// Restore sample pointer in case it got changed through loop wrap-around
-		chn.pCurrentSample = samplePointer;
+		chn.pCurrentSample = mixLoopState.samplePointer;
 		nchmixed += naddmix;
 	
 #ifndef NO_PLUGINS
@@ -429,7 +458,6 @@ void CSoundFile::CreateStereoMix(int count)
 
 
 void CSoundFile::ProcessPlugins(uint32 nCount)
-//--------------------------------------------
 {
 #ifndef NO_PLUGINS
 	// If any sample channels are active or any plugin has some input, possibly suspended master plugins need to be woken up.
diff --git a/soundlib/FloatMixer.h b/soundlib/FloatMixer.h
index a8ebb8b..442c837 100644
--- a/soundlib/FloatMixer.h
+++ b/soundlib/FloatMixer.h
@@ -3,8 +3,7 @@
  * ------------
  * Purpose: Floating point mixer classes
  * Notes  : (currently none)
- * Authors: Olivier Lapicque
- *          OpenMPT Devs
+ * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  */
 
@@ -22,9 +21,9 @@ struct IntToFloatTraits : public MixerTraits<channelsOut, channelsIn, out, in>
 	static_assert(std::numeric_limits<input_t>::is_integer, "Input must be integer");
 	static_assert(!std::numeric_limits<output_t>::is_integer, "Output must be floating point");
 
-	static forceinline output_t Convert(const input_t x)
+	static MPT_CONSTEXPR11_FUN output_t Convert(const input_t x)
 	{
-		return static_cast<output_t>(x) * (static_cast<output_t>(1.0f) / static_cast<output_t>(int2float));
+		return static_cast<output_t>(x) * (static_cast<output_t>(1) / static_cast<output_t>(int2float));
 	}
 };
 
@@ -40,19 +39,19 @@ typedef IntToFloatTraits<2, 2, mixsample_t, int16, -int16_min> Int16SToFloatS;
 template<class Traits>
 struct LinearInterpolation
 {
-	forceinline void Start(const ModChannel &, const CResampler &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const Traits::output_t fract = CResampler::LinearTablef[posLo >> 8];
+		const typename Traits::output_t fract = posLo / static_cast<typename Traits::output_t>(0x100000000); //CResampler::LinearTablef[posLo >> 24];
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
-			Traits::output_t srcVol = Traits::Convert(inBuffer[i]);
-			Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]);
+			typename Traits::output_t srcVol = Traits::Convert(inBuffer[i]);
+			typename Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]);
 
 			outSample[i] = srcVol + fract * (destVol - srcVol);
 		}
@@ -63,13 +62,13 @@ struct LinearInterpolation
 template<class Traits>
 struct FastSincInterpolation
 {
-	forceinline void Start(const ModChannel &, const CResampler &) { }
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const Traits::output_t *lut = CResampler::FastSincTablef + ((posLo >> 6) & 0x3FC);
+		const typename Traits::output_t *lut = CResampler::FastSincTablef + ((posLo >> 22) & 0x3FC);
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -88,18 +87,18 @@ struct PolyphaseInterpolation
 {
 	const typename Traits::output_t *sinc;
 
-	forceinline void Start(const ModChannel &chn, const CResampler &resampler)
+	MPT_FORCEINLINE void Start(const ModChannel &chn, const CResampler &resampler)
 	{
-		sinc = (((chn.nInc > 0x13000) || (chn.nInc < -0x13000)) ?
-			(((chn.nInc > 0x18000) || (chn.nInc < -0x18000)) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
+		sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < -SamplePosition(-0x130000000ll))) ?
+			(((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
 	}
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const Traits::output_t *lut = sinc + ((posLo >> (16 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH;
+		const typename Traits::output_t *lut = sinc + ((posLo >> (32 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH;
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -122,17 +121,17 @@ struct FIRFilterInterpolation
 {
 	const typename Traits::output_t *WFIRlut;
 
-	forceinline void Start(const ModChannel &, const CResampler &resampler)
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &resampler)
 	{
 		WFIRlut = resampler.m_WindowedFIR.lut;
 	}
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const Traits::output_t * const lut = WFIRlut + (((posLo + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK);
+		const typename Traits::output_t * const lut = WFIRlut + ((((posLo >> 16) + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK);
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -158,13 +157,13 @@ struct NoRamp
 {
 	typename Traits::output_t lVol, rVol;
 
-	forceinline void Start(const ModChannel &chn)
+	MPT_FORCEINLINE void Start(const ModChannel &chn)
 	{
 		lVol = static_cast<Traits::output_t>(chn.leftVol) * (1.0f / 4096.0f);
 		rVol = static_cast<Traits::output_t>(chn.rightVol) * (1.0f / 4096.0f);
 	}
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 };
 
 
@@ -172,13 +171,13 @@ struct Ramp
 {
 	int32 lRamp, rRamp;
 
-	forceinline void Start(const ModChannel &chn)
+	MPT_FORCEINLINE void Start(const ModChannel &chn)
 	{
 		lRamp = chn.rampLeftVol;
 		rRamp = chn.rampRightVol;
 	}
 
-	forceinline void End(ModChannel &chn)
+	MPT_FORCEINLINE void End(ModChannel &chn)
 	{
 		chn.rampLeftVol = lRamp; chn.leftVol = lRamp >> VOLUMERAMPPRECISION;
 		chn.rampRightVol = rRamp; chn.rightVol = rRamp >> VOLUMERAMPPRECISION;
@@ -190,9 +189,9 @@ struct Ramp
 template<class Traits>
 struct MixMonoFastNoRamp : public NoRamp<Traits>
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer)
 	{
-		Traits::output_t vol = outSample[0] * lVol;
+		typename Traits::output_t vol = outSample[0] * lVol;
 		for(int i = 0; i < Traits::numChannelsOut; i++)
 		{
 			outBuffer[i] += vol;
@@ -204,7 +203,7 @@ struct MixMonoFastNoRamp : public NoRamp<Traits>
 template<class Traits>
 struct MixMonoNoRamp : public NoRamp<Traits>
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer)
 	{
 		outBuffer[0] += outSample[0] * lVol;
 		outBuffer[1] += outSample[0] * rVol;
@@ -215,7 +214,7 @@ struct MixMonoNoRamp : public NoRamp<Traits>
 template<class Traits>
 struct MixMonoRamp : public Ramp
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer)
 	{
 		// TODO volume is not float, can we optimize this?
 		lRamp += chn.leftRamp;
@@ -229,7 +228,7 @@ struct MixMonoRamp : public Ramp
 template<class Traits>
 struct MixStereoNoRamp : public NoRamp<Traits>
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer)
 	{
 		outBuffer[0] += outSample[0] * lVol;
 		outBuffer[1] += outSample[1] * rVol;
@@ -240,7 +239,7 @@ struct MixStereoNoRamp : public NoRamp<Traits>
 template<class Traits>
 struct MixStereoRamp : public Ramp
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer)
 	{
 		// TODO volume is not float, can we optimize this?
 		lRamp += chn.leftRamp;
@@ -258,10 +257,10 @@ struct MixStereoRamp : public Ramp
 template<class Traits>
 struct NoFilter
 {
-	forceinline void Start(const ModChannel &) { }
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
 };
 
 
@@ -272,7 +271,7 @@ struct ResonantFilter
 	// Filter history
 	typename Traits::output_t fy[Traits::numChannelsIn][2];
 
-	forceinline void Start(const ModChannel &chn)
+	MPT_FORCEINLINE void Start(const ModChannel &chn)
 	{
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -281,7 +280,7 @@ struct ResonantFilter
 		}
 	}
 
-	forceinline void End(ModChannel &chn)
+	MPT_FORCEINLINE void End(ModChannel &chn)
 	{
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -293,13 +292,13 @@ struct ResonantFilter
 	// Filter values are clipped to double the input range
 #define ClipFilter(x) Clamp(x, static_cast<Traits::output_t>(-2.0f), static_cast<Traits::output_t>(2.0f))
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
-			Traits::output_t val = outSample[i] * chn.nFilter_A0 + ClipFilter(fy[i][0]) * chn.nFilter_B0 + ClipFilter(fy[i][1]) * chn.nFilter_B1;
+			typename Traits::output_t val = outSample[i] * chn.nFilter_A0 + ClipFilter(fy[i][0]) * chn.nFilter_B0 + ClipFilter(fy[i][1]) * chn.nFilter_B1;
 			fy[i][1] = fy[i][0];
 			fy[i][0] = val - (outSample[i] * chn.nFilter_HP);
 			outSample[i] = val;
diff --git a/soundlib/ITCompression.cpp b/soundlib/ITCompression.cpp
index 0993fd7..efcfe13 100644
--- a/soundlib/ITCompression.cpp
+++ b/soundlib/ITCompression.cpp
@@ -9,7 +9,7 @@
  */
 
 
-#include <stdafx.h>
+#include "stdafx.h"
 #include <ostream>
 #include "ITCompression.h"
 #include "../common/misc_util.h"
@@ -26,8 +26,8 @@ struct IT16BitParams
 	typedef int16 sample_t;
 	static const int16 lowerTab[];
 	static const int16 upperTab[];
-	static const int fetchA = 4, lowerB = -8, upperB = 7, defWidth = 17;
-	static int Clamp(sample_t v) { return int(v) & 0xFFFF; }
+	static const int8 fetchA = 4, lowerB = -8, upperB = 7, defWidth = 17;
+	static const int mask = 0xFFFF;
 };
 
 const int16 IT16BitParams::lowerTab[] = { 0, -1, -3, -7, -15, -31, -56, -120, -248, -504, -1016, -2040, -4088, -8184, -16376, -32760, -32768 };
@@ -39,14 +39,14 @@ struct IT8BitParams
 	typedef int8 sample_t;
 	static const int8 lowerTab[];
 	static const int8 upperTab[];
-	static const int fetchA = 3, lowerB = -4, upperB = 3, defWidth = 9;
-	static int Clamp(sample_t v) { return int(v) & 0xFF; }
+	static const int8 fetchA = 3, lowerB = -4, upperB = 3, defWidth = 9;
+	static const int mask = 0xFF;
 };
 
 const int8 IT8BitParams::lowerTab[] = { 0, -1, -3, -7, -15, -31, -60, -124, -128 };
 const int8 IT8BitParams::upperTab[] = { 0, 1, 3, 7, 15, 31, 59, 123, 127 };
 
-static const int ITWidthChangeSize[] = { 4, 5, 6, 7, 8, 9, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
+static const int8 ITWidthChangeSize[] = { 4, 5, 6, 7, 8, 9, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
 
 //////////////////////////////////////////////////////////////////////////////
 // IT 2.14 compression
@@ -56,7 +56,6 @@ ITCompression::ITCompression(const ModSample &sample, bool it215, std::ostream *
 	: file(f)
 	, mptSample(sample)
 	, is215(it215)
-//-----------------------------------------------------------------------------------------------------
 {
 	packedData = new (std::nothrow) uint8[bufferSize];
 	sampleData = new (std::nothrow) uint8[blockSize];
@@ -85,7 +84,7 @@ ITCompression::ITCompression(const ModSample &sample, bool it215, std::ostream *
 			else
 				Compress<IT8BitParams>(sample.pSample8 + chn, offset, remain);
 
-			if(file) mpt::IO::WriteRaw(*file, &packedData[0], packedLength);
+			if(file) mpt::IO::WriteRaw(*file, packedData, packedLength);
 			packedTotalLength += packedLength;
 
 			offset += baseLength;
@@ -100,7 +99,6 @@ ITCompression::ITCompression(const ModSample &sample, bool it215, std::ostream *
 
 template<typename T>
 void ITCompression::CopySample(void *target, const void *source, SmpLength offset, SmpLength length, SmpLength skip)
-//------------------------------------------------------------------------------------------------------------------
 {
 	T *out = static_cast<T *>(target);
 	const T *in = static_cast<const T *>(source) + offset * skip;
@@ -114,7 +112,6 @@ void ITCompression::CopySample(void *target, const void *source, SmpLength offse
 // Convert sample to delta values.
 template<typename T>
 void ITCompression::Deltafy()
-//---------------------------
 {
 	T *p = static_cast<T *>(sampleData);
 	int oldVal = 0;
@@ -129,7 +126,6 @@ void ITCompression::Deltafy()
 
 template<typename Properties>
 void ITCompression::Compress(const void *data, SmpLength offset, SmpLength actualLength)
-//--------------------------------------------------------------------------------------
 {
 	baseLength = std::min(actualLength, SmpLength(blockSize / sizeof(typename Properties::sample_t)));
 
@@ -141,7 +137,7 @@ void ITCompression::Compress(const void *data, SmpLength offset, SmpLength actua
 		Deltafy<typename Properties::sample_t>();
 	}
 
-	const int defWidth = Properties::defWidth; // gcc static const member reference workaround
+	const int8 defWidth = Properties::defWidth; // gcc static const member reference workaround
 
 	// Initialise bit width table with initial values
 	bwt.assign(baseLength, defWidth);
@@ -151,7 +147,7 @@ void ITCompression::Compress(const void *data, SmpLength offset, SmpLength actua
 	
 	// Write those bits!
 	const typename Properties::sample_t *p = static_cast<typename Properties::sample_t *>(sampleData);
-	int width = defWidth;
+	int8 width = defWidth;
 	for(size_t i = 0; i < baseLength; i++)
 	{
 		if(bwt[i] != width)
@@ -176,21 +172,20 @@ void ITCompression::Compress(const void *data, SmpLength offset, SmpLength actua
 
 			width = bwt[i];
 		}
-		WriteBits(width, Properties::Clamp(p[i]));
+		WriteBits(width, static_cast<int>(p[i]) & Properties::mask);
 	}
 
 	// Write last byte and update block length
 	WriteByte(byteVal);
-	packedData[0] = uint8((packedLength - 2) & 0xFF);
-	packedData[1] = uint8((packedLength - 2) >> 8);
+	packedData[0] = static_cast<uint8>((packedLength - 2) & 0xFF);
+	packedData[1] = static_cast<uint8>((packedLength - 2) >> 8);
 }
 
 
-int ITCompression::GetWidthChangeSize(int w, bool is16)
-//-----------------------------------------------------
+int8 ITCompression::GetWidthChangeSize(int8 w, bool is16)
 {
 	MPT_ASSERT(w > 0 && static_cast<unsigned int>(w) <= CountOf(ITWidthChangeSize));
-	int wcs = ITWidthChangeSize[w - 1];
+	int8 wcs = ITWidthChangeSize[w - 1];
 	if(w <= 6 && is16)
 		wcs++;
 	return wcs;
@@ -198,8 +193,7 @@ int ITCompression::GetWidthChangeSize(int w, bool is16)
 
 
 template<typename Properties>
-void ITCompression::SquishRecurse(int sWidth, int lWidth, int rWidth, int width, SmpLength offset, SmpLength length)
-//------------------------------------------------------------------------------------------------------------------
+void ITCompression::SquishRecurse(int8 sWidth, int8 lWidth, int8 rWidth, int8 width, SmpLength offset, SmpLength length)
 {
 	if(width + 1 < 1)
 	{
@@ -226,13 +220,13 @@ void ITCompression::SquishRecurse(int sWidth, int lWidth, int rWidth, int width,
 			}
 
 			const SmpLength blockLength = i - start;
-			const int xlwidth = start == offset ? lWidth : sWidth;
-			const int xrwidth = i == end ? rWidth : sWidth;
+			const int8 xlwidth = start == offset ? lWidth : sWidth;
+			const int8 xrwidth = i == end ? rWidth : sWidth;
 
 			const bool is16 = sizeof(typename Properties::sample_t) > 1;
-			const int wcsl = GetWidthChangeSize(xlwidth, is16);
-			const int wcss = GetWidthChangeSize(sWidth, is16);
-			const int wcsw = GetWidthChangeSize(width + 1, is16);
+			const int8 wcsl = GetWidthChangeSize(xlwidth, is16);
+			const int8 wcss = GetWidthChangeSize(sWidth, is16);
+			const int8 wcsw = GetWidthChangeSize(width + 1, is16);
 
 			bool comparison;
 			if(i == baseLength)
@@ -266,8 +260,7 @@ void ITCompression::SquishRecurse(int sWidth, int lWidth, int rWidth, int width,
 }
 
 
-int ITCompression::ConvertWidth(int curWidth, int newWidth)
-//---------------------------------------------------------
+int8 ITCompression::ConvertWidth(int8 curWidth, int8 newWidth)
 {
 	curWidth--;
 	newWidth--;
@@ -278,8 +271,7 @@ int ITCompression::ConvertWidth(int curWidth, int newWidth)
 }
 
 
-void ITCompression::WriteBits(int width, int v)
-//---------------------------------------------
+void ITCompression::WriteBits(int8 width, int v)
 {
 	while(width > remBits)
 	{
@@ -302,7 +294,6 @@ void ITCompression::WriteBits(int width, int v)
 
 
 void ITCompression::WriteByte(uint8 v)
-//------------------------------------
 {
 	if(packedLength < bufferSize)
 	{
@@ -322,15 +313,16 @@ void ITCompression::WriteByte(uint8 v)
 ITDecompression::ITDecompression(FileReader &file, ModSample &sample, bool it215)
 	: mptSample(sample)
 	, is215(it215)
-//-------------------------------------------------------------------------------
 {
 	for(uint8 chn = 0; chn < mptSample.GetNumChannels(); chn++)
 	{
 		writtenSamples = writePos = 0;
 		while(writtenSamples < sample.nLength && file.CanRead(sizeof(uint16)))
 		{
-			chunk = file.ReadChunk(file.ReadUint16LE());
-			chunkView = chunk.GetPinnedRawDataView();
+			dataSize = file.ReadUint16LE();
+			if(!dataSize)
+				continue;	// Malformed sample?
+			file.ReadRaw(chunk, dataSize);
 
 			// Initialise bit reader
 			dataPos = 0;
@@ -349,7 +341,6 @@ ITDecompression::ITDecompression(FileReader &file, ModSample &sample, bool it215
 
 template<typename Properties>
 void ITDecompression::Uncompress(typename Properties::sample_t *target)
-//---------------------------------------------------------------------
 {
 	curLength = std::min(mptSample.nLength - writtenSamples, SmpLength(ITCompression::blockSize / sizeof(typename Properties::sample_t)));
 
@@ -358,7 +349,7 @@ void ITDecompression::Uncompress(typename Properties::sample_t *target)
 	int width = defWidth;
 	while(curLength > 0)
 	{
-		if(width < 1 || width > defWidth || dataPos >= chunkView.size())
+		if(width < 1 || width > defWidth || dataPos >= dataSize)
 		{
 			// Error!
 			return;
@@ -392,26 +383,31 @@ void ITDecompression::Uncompress(typename Properties::sample_t *target)
 }
 
 
+#if MPT_MSVC_AT_LEAST(2017,3)
+// Work-around compiler crash in VS2017.3 / cl 19.11.25506
+// https://developercommunity.visualstudio.com/content/problem/96687/c1063-and-c1001-while-compiling-trivial-code-in-vs.html
+MPT_NOINLINE
+#endif
 void ITDecompression::ChangeWidth(int &curWidth, int width)
-//---------------------------------------------------------
 {
 	width++;
 	if(width >= curWidth)
 		width++;
-
-	MPT_ASSERT(curWidth != width);
 	curWidth = width;
 }
 
 
+#if MPT_MSVC_AT_LEAST(2017,3)
+// Work-around compiler crash in VS2017.3 / cl 19.11.25506
+// https://developercommunity.visualstudio.com/content/problem/96687/c1063-and-c1001-while-compiling-trivial-code-in-vs.html
+MPT_NOINLINE
+#endif
 int ITDecompression::ReadBits(int width)
-//--------------------------------------
 {
-	const mpt::byte *data = chunkView.begin();
 	int v = 0, vPos = 0, vMask = (1 << width) - 1;
-	while(width >= remBits && dataPos < chunkView.size())
+	while(width >= remBits && dataPos < dataSize)
 	{
-		v |= (data[dataPos] >> bitPos) << vPos;
+		v |= (chunk[dataPos] >> bitPos) << vPos;
 		vPos += remBits;
 		width -= remBits;
 		dataPos++;
@@ -419,9 +415,9 @@ int ITDecompression::ReadBits(int width)
 		bitPos = 0;
 	}
 
-	if(width > 0 && dataPos < chunkView.size())
+	if(width > 0 && dataPos < dataSize)
 	{
-		v |= (data[dataPos] >> bitPos) << vPos;
+		v |= (chunk[dataPos] >> bitPos) << vPos;
 		v &= vMask;
 		remBits -= width;
 		bitPos += width;
@@ -432,13 +428,12 @@ int ITDecompression::ReadBits(int width)
 
 template<typename Properties>
 void ITDecompression::Write(int v, int topBit, typename Properties::sample_t *target)
-//-----------------------------------------------------------------------------------
 {
 	if(v & topBit)
 		v -= (topBit << 1);
 	mem1 += v;
 	mem2 += mem1;
-	target[writePos] = static_cast<typename Properties::sample_t>(is215 ? (int)mem2 : (int)mem1);
+	target[writePos] = static_cast<typename Properties::sample_t>(static_cast<int>(is215 ? mem2 : mem1));
 	writtenSamples++;
 	writePos += mptSample.GetNumChannels();
 	curLength--;
diff --git a/soundlib/ITCompression.h b/soundlib/ITCompression.h
index 9eb0979..07ce110 100644
--- a/soundlib/ITCompression.h
+++ b/soundlib/ITCompression.h
@@ -20,9 +20,7 @@ OPENMPT_NAMESPACE_BEGIN
 
 struct ModSample;
 
-//=================
 class ITCompression
-//=================
 {
 public:
 	ITCompression(const ModSample &sample, bool it215, std::ostream *f, SmpLength maxLength = 0);
@@ -32,7 +30,7 @@ public:
 	static const size_t blockSize = 0x8000;			// Block size (in bytes) in which samples are being processed
 
 protected:
-	std::vector<int> bwt;			// Bit width table
+	std::vector<int8> bwt;			// Bit width table for each sampling point
 	uint8 *packedData;				// Compressed data for current sample block
 	std::ostream *file;				// File to which compressed data will be written (can be nullptr if you only want to find out the sample size)
 	void *sampleData;				// Pre-processed sample data for currently compressed sample block
@@ -42,8 +40,8 @@ protected:
 	SmpLength baseLength;			// Length of the currently compressed sample block (in samples)
 
 	// Bit writer
-	int bitPos;		// Current bit position in this byte
-	int remBits;	// Remaining bits in this byte
+	int8 bitPos;	// Current bit position in this byte
+	int8 remBits;	// Remaining bits in this byte
 	uint8 byteVal;	// Current byte value to be written
 
 	bool is215;		// Use IT2.15 compression (double deltas)
@@ -57,42 +55,39 @@ protected:
 	template<typename Properties>
 	void Compress(const void *data, SmpLength offset, SmpLength actualLength);
 
-	static int GetWidthChangeSize(int w, bool is16);
+	static int8 GetWidthChangeSize(int8 w, bool is16);
 
 	template<typename Properties>
-	void SquishRecurse(int sWidth, int lWidth, int rWidth, int width, SmpLength offset, SmpLength length);
+	void SquishRecurse(int8 sWidth, int8 lWidth, int8 rWidth, int8 width, SmpLength offset, SmpLength length);
 
-	static int ConvertWidth(int curWidth, int newWidth);
-	void WriteBits(int width, int v);
+	static int8 ConvertWidth(int8 curWidth, int8 newWidth);
+	void WriteBits(int8 width, int v);
 
 	void WriteByte(uint8 v);
 };
 
 
-//===================
 class ITDecompression
-//===================
 {
 public:
 	ITDecompression(FileReader &file, ModSample &sample, bool it215);
 
 protected:
-	FileReader chunk;			// Currently processed block
-	FileReader::PinnedRawDataView chunkView;	// view into Currently processed block
-
 	ModSample &mptSample;		// Sample that is being processed
 
 	SmpLength writtenSamples;	// Number of samples so far written on this channel
 	SmpLength writePos;			// Absolut write position in sample (for stereo samples)
 	SmpLength curLength;		// Length of currently processed block
-	FileReader::off_t dataPos;	// Position in input block
-	unsigned int mem1, mem2;				// Integrator memory
+	unsigned int mem1, mem2;	// Integrator memory
+	int dataPos, dataSize;		// Position in and size of input block
 
 	// Bit reader
-	int bitPos;		// Current bit position in this byte
-	int remBits;	// Remaining bits in this byte
+	int bitPos;					// Current bit position in this byte
+	int remBits;				// Remaining bits in this byte
 
-	bool is215;		// Use IT2.15 compression (double deltas)
+	bool is215;					// Use IT2.15 compression (double deltas)
+
+	mpt::byte chunk[65535];		// Input block
 
 	template<typename Properties>
 	void Uncompress(typename Properties::sample_t *target);
diff --git a/soundlib/ITTools.cpp b/soundlib/ITTools.cpp
index 5b8fabb..2e8b7c2 100644
--- a/soundlib/ITTools.cpp
+++ b/soundlib/ITTools.cpp
@@ -19,26 +19,8 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void ITFileHeader::ConvertEndianness()
-//------------------------------------
-{
-	SwapBytesLE(ordnum);
-	SwapBytesLE(insnum);
-	SwapBytesLE(smpnum);
-	SwapBytesLE(patnum);
-	SwapBytesLE(cwtv);
-	SwapBytesLE(cmwt);
-	SwapBytesLE(flags);
-	SwapBytesLE(special);
-	SwapBytesLE(msglength);
-	SwapBytesLE(msgoffset);
-}
-
-
 // Convert OpenMPT's internal envelope format into an IT/MPTM envelope.
 void ITEnvelope::ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 envDefault)
-//-----------------------------------------------------------------------------------------------
 {
 	// Envelope Flags
 	if(mptEnv.dwFlags[ENV_ENABLED]) flags |= ITEnvelope::envEnabled;
@@ -76,7 +58,6 @@ void ITEnvelope::ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset,
 
 // Convert IT/MPTM envelope data into OpenMPT's internal envelope format - To be used by ITInstrToMPT()
 void ITEnvelope::ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 maxNodes) const
-//----------------------------------------------------------------------------------------------
 {
 	// Envelope Flags
 	mptEnv.dwFlags.set(ENV_ENABLED, (flags & ITEnvelope::envEnabled) != 0);
@@ -114,18 +95,8 @@ void ITEnvelope::ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void ITOldInstrument::ConvertEndianness()
-//---------------------------------------
-{
-	SwapBytesLE(fadeout);
-	SwapBytesLE(trkvers);
-}
-
-
 // Convert an ITOldInstrument to OpenMPT's internal instrument representation.
 void ITOldInstrument::ConvertToMPT(ModInstrument &mptIns) const
-//-------------------------------------------------------------
 {
 	// Header
 	if(memcmp(id, "IMPI", 4))
@@ -191,18 +162,8 @@ void ITOldInstrument::ConvertToMPT(ModInstrument &mptIns) const
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void ITInstrument::ConvertEndianness()
-//------------------------------------
-{
-	SwapBytesLE(fadeout);
-	SwapBytesLE(trkvers);
-}
-
-
 // Convert OpenMPT's internal instrument representation to an ITInstrument.
 uint32 ITInstrument::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile)
-//---------------------------------------------------------------------------------------------------------
 {
 	MemsetZero(*this);
 
@@ -295,7 +256,6 @@ uint32 ITInstrument::ConvertToIT(const ModInstrument &mptIns, bool compatExport,
 
 // Convert an ITInstrument to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
 uint32 ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) const
-//-------------------------------------------------------------------------------
 {
 	if(memcmp(id, "IMPI", 4))
 	{
@@ -314,8 +274,8 @@ uint32 ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) cons
 	mptIns.dwFlags.set(INS_SETPANNING, !(dfp & ITInstrument::ignorePanning));
 
 	// Random Variation
-	mptIns.nVolSwing = std::min(rv, uint8(100));
-	mptIns.nPanSwing = std::min(rp, uint8(64));
+	mptIns.nVolSwing = std::min<uint8>(rv, 100);
+	mptIns.nPanSwing = std::min<uint8>(rp, 64);
 
 	// NNA Stuff
 	mptIns.nNNA = nna;
@@ -335,8 +295,8 @@ uint32 ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) cons
 	// MPT used to have a slightly different encoding of MIDI program and banks which we are trying to fix here.
 	// Impulse Tracker / Schism Tracker will set trkvers to 0 in IT files,
 	// and we won't care about correctly importing MIDI programs and banks in ITI files.
-	// Chibi Tracker sets trkvers to 0x214, but always writes mpr=mbank=0.
-	// BeRoTracker sets trkvers to 0x214, but only writes mpr correctly.
+	// Chibi Tracker sets trkvers to 0x214, but always writes mpr=mbank=0 anyway.
+	// Old BeRoTracker versions set trkvers to 0x214 or 0x217.
 	//        <= MPT 1.07          <= MPT 1.16       OpenMPT 1.17-?      <= OpenMPT 1.26     definitely not MPT
 	if((trkvers == 0x0202 || trkvers == 0x0211 || trkvers == 0x0220 || trkvers == 0x0214) && mpr != 0xFF)
 	{
@@ -404,17 +364,8 @@ uint32 ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) cons
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void ITInstrumentEx::ConvertEndianness()
-//--------------------------------------
-{
-	iti.ConvertEndianness();
-}
-
-
 // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written to file.
 uint32 ITInstrumentEx::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile)
-//-----------------------------------------------------------------------------------------------------------
 {
 	uint32 instSize = iti.ConvertToIT(mptIns, compatExport, sndFile);
 
@@ -463,7 +414,6 @@ uint32 ITInstrumentEx::ConvertToIT(const ModInstrument &mptIns, bool compatExpor
 
 // Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
 uint32 ITInstrumentEx::ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const
-//--------------------------------------------------------------------------------
 {
 	uint32 insSize = iti.ConvertToMPT(mptIns, fromType);
 
@@ -484,23 +434,8 @@ uint32 ITInstrumentEx::ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) con
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void ITSample::ConvertEndianness()
-//--------------------------------
-{
-	SwapBytesLE(length);
-	SwapBytesLE(loopbegin);
-	SwapBytesLE(loopend);
-	SwapBytesLE(C5Speed);
-	SwapBytesLE(susloopbegin);
-	SwapBytesLE(susloopend);
-	SwapBytesLE(samplepointer);
-}
-
-
 // Convert OpenMPT's internal sample representation to an ITSample.
 void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal)
-//--------------------------------------------------------------------------------------------------------------------------
 {
 	MemsetZero(*this);
 
@@ -590,7 +525,6 @@ void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compr
 
 // Convert an ITSample to OpenMPT's internal sample representation.
 uint32 ITSample::ConvertToMPT(ModSample &mptSmp) const
-//----------------------------------------------------
 {
 	if(memcmp(id, "IMPS", 4))
 	{
@@ -646,7 +580,6 @@ uint32 ITSample::ConvertToMPT(ModSample &mptSmp) const
 
 // Retrieve the internal sample format flags for this instrument.
 SampleIO ITSample::GetSampleFormat(uint16 cwtv) const
-//---------------------------------------------------
 {
 	SampleIO sampleIO(
 		(flags & ITSample::sample16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
@@ -692,19 +625,8 @@ SampleIO ITSample::GetSampleFormat(uint16 cwtv) const
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void ITHistoryStruct::ConvertEndianness()
-//---------------------------------------
-{
-	SwapBytesLE(fatdate);
-	SwapBytesLE(fattime);
-	SwapBytesLE(runtime);
-}
-
-
 // Convert an ITHistoryStruct to OpenMPT's internal edit history representation
 void ITHistoryStruct::ConvertToMPT(FileHistory &mptHistory) const
-//---------------------------------------------------------------
 {
 	// Decode FAT date and time
 	MemsetZero(mptHistory.loadDate);
@@ -720,7 +642,6 @@ void ITHistoryStruct::ConvertToMPT(FileHistory &mptHistory) const
 
 // Convert OpenMPT's internal edit history representation to an ITHistoryStruct
 void ITHistoryStruct::ConvertToIT(const FileHistory &mptHistory)
-//--------------------------------------------------------------
 {
 	// Create FAT file dates
 	fatdate = static_cast<uint16>(mptHistory.loadDate.tm_mday | ((mptHistory.loadDate.tm_mon + 1) << 5) | ((mptHistory.loadDate.tm_year - 80) << 9));
diff --git a/soundlib/ITTools.h b/soundlib/ITTools.h
index f177502..298c456 100644
--- a/soundlib/ITTools.h
+++ b/soundlib/ITTools.h
@@ -16,11 +16,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED ITFileHeader
+struct ITFileHeader
 {
 	// Header Flags
 	enum ITHeaderFlags
@@ -45,38 +41,35 @@ struct PACKED ITFileHeader
 		embedMIDIConfiguration	= 0x08,
 	};
 
-	char   id[4];			// Magic Bytes (IMPM)
-	char   songname[26];	// Song Name, null-terminated (but may also contain nulls)
-	uint8  highlight_minor;	// Rows per Beat highlight
-	uint8  highlight_major;	// Rows per Measure highlight
-	uint16 ordnum;			// Number of Orders
-	uint16 insnum;			// Number of Instruments
-	uint16 smpnum;			// Number of Samples
-	uint16 patnum;			// Number of Patterns
-	uint16 cwtv;			// "Made With" Tracker
-	uint16 cmwt;			// "Compatible With" Tracker
-	uint16 flags;			// Header Flags
-	uint16 special;			// Special Flags, for embedding extra information
-	uint8  globalvol;		// Global Volume (0...128)
-	uint8  mv;				// Master Volume (0...128), referred to as Sample Volume in OpenMPT
-	uint8  speed;			// Initial Speed (1...255)
-	uint8  tempo;			// Initial Tempo (31...255)
-	uint8  sep;				// Pan Separation (0...128)
-	uint8  pwd;				// Pitch Wheel Depth
-	uint16 msglength;		// Length of Song Message
-	uint32 msgoffset;		// Offset of Song Message in File (IT crops message after first null)
-	char   reserved[4];		// Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT writes "OMPT" here in some cases, see Load_it.cpp
-	uint8  chnpan[64];		// Initial Channel Panning
-	uint8  chnvol[64];		// Initial Channel Volume
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	char     id[4];				// Magic Bytes (IMPM)
+	char     songname[26];		// Song Name, null-terminated (but may also contain nulls)
+	uint8le  highlight_minor;	// Rows per Beat highlight
+	uint8le  highlight_major;	// Rows per Measure highlight
+	uint16le ordnum;			// Number of Orders
+	uint16le insnum;			// Number of Instruments
+	uint16le smpnum;			// Number of Samples
+	uint16le patnum;			// Number of Patterns
+	uint16le cwtv;				// "Made With" Tracker
+	uint16le cmwt;				// "Compatible With" Tracker
+	uint16le flags;				// Header Flags
+	uint16le special;			// Special Flags, for embedding extra information
+	uint8le  globalvol;			// Global Volume (0...128)
+	uint8le  mv;				// Master Volume (0...128), referred to as Sample Volume in OpenMPT
+	uint8le  speed;				// Initial Speed (1...255)
+	uint8le  tempo;				// Initial Tempo (31...255)
+	uint8le  sep;				// Pan Separation (0...128)
+	uint8le  pwd;				// Pitch Wheel Depth
+	uint16le msglength;			// Length of Song Message
+	uint32le msgoffset;			// Offset of Song Message in File (IT crops message after first null)
+	uint32le reserved;			// Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT writes "OMPT" here in some cases, see Load_it.cpp
+	uint8le  chnpan[64];		// Initial Channel Panning
+	uint8le  chnvol[64];		// Initial Channel Volume
 };
 
-STATIC_ASSERT(sizeof(ITFileHeader) == 192);
+MPT_BINARY_STRUCT(ITFileHeader, 192)
 
 
-struct PACKED ITEnvelope
+struct ITEnvelope
 {
 	// Envelope Flags
 	enum ITEnvelopeFlags
@@ -103,11 +96,11 @@ struct PACKED ITEnvelope
 	void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 maxNodes) const;
 };
 
-STATIC_ASSERT(sizeof(ITEnvelope) == 82);
+MPT_BINARY_STRUCT(ITEnvelope, 82)
 
 
 // Old Impulse Instrument Format (cmwt < 0x200)
-struct PACKED ITOldInstrument
+struct ITOldInstrument
 {
 	enum ITOldInstrFlags
 	{
@@ -116,38 +109,35 @@ struct PACKED ITOldInstrument
 		envSustain	= 0x04,
 	};
 
-	char   id[4];			// Magic Bytes (IMPI)
-	char   filename[13];	// DOS Filename, null-terminated
-	uint8  flags;			// Volume Envelope Flags
-	uint8  vls;				// Envelope Loop Start
-	uint8  vle;				// Envelope Loop End
-	uint8  sls;				// Envelope Sustain Start
-	uint8  sle;				// Envelope Sustain End
-	char   reserved1[2];	// Reserved
-	uint16 fadeout;			// Instrument Fadeout (0...128)
-	uint8  nna;				// New Note Action
-	uint8  dnc;				// Duplicate Note Check Type
-	uint16 trkvers;			// Tracker ID
-	uint8  nos;				// Number of embedded samples
-	char   reserved2;		// Reserved
-	char   name[26];		// Instrument Name, null-terminated (but may also contain nulls)
-	char   reserved3[6];	// Even more reserved bytes
-	uint8  keyboard[240];	// Sample / Transpose map
-	uint8  volenv[200];		// This appears to be a pre-computed (interpolated) version of the volume envelope data found below.
-	uint8  nodes[25 * 2];	// Volume Envelope Node Positions / Values
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	char     id[4];			// Magic Bytes (IMPI)
+	char     filename[13];	// DOS Filename, null-terminated
+	uint8le  flags;			// Volume Envelope Flags
+	uint8le  vls;			// Envelope Loop Start
+	uint8le  vle;			// Envelope Loop End
+	uint8le  sls;			// Envelope Sustain Start
+	uint8le  sle;			// Envelope Sustain End
+	char     reserved1[2];	// Reserved
+	uint16le fadeout;		// Instrument Fadeout (0...128)
+	uint8le  nna;			// New Note Action
+	uint8le  dnc;			// Duplicate Note Check Type
+	uint16le trkvers;		// Tracker ID
+	uint8le  nos;			// Number of embedded samples
+	char     reserved2;		// Reserved
+	char     name[26];		// Instrument Name, null-terminated (but may also contain nulls)
+	char     reserved3[6];	// Even more reserved bytes
+	uint8le  keyboard[240];	// Sample / Transpose map
+	uint8le  volenv[200];	// This appears to be a pre-computed (interpolated) version of the volume envelope data found below.
+	uint8le  nodes[25 * 2];	// Volume Envelope Node Positions / Values
 
 	// Convert an ITOldInstrument to OpenMPT's internal instrument representation.
 	void ConvertToMPT(ModInstrument &mptIns) const;
 };
 
-STATIC_ASSERT(sizeof(ITOldInstrument) == 554);
+MPT_BINARY_STRUCT(ITOldInstrument, 554)
 
 
 // Impulse Instrument Format
-struct PACKED ITInstrument
+struct ITInstrument
 {
 	enum ITInstrumentFlags
 	{
@@ -156,35 +146,32 @@ struct PACKED ITInstrument
 		enableResonance	= 0x80,
 	};
 
-	char   id[4];			// Magic Bytes (IMPI)
-	char   filename[13];	// DOS Filename, null-terminated
-	uint8  nna;				// New Note Action
-	uint8  dct;				// Duplicate Note Check Type
-	uint8  dca;				// Duplicate Note Check Action
-	uint16 fadeout;		// Instrument Fadeout (0...256, although values up to 1024 would be sensible. Up to IT2.07, the limit was 0...128)
-	int8   pps;				// Pitch/Pan Separatation
-	uint8  ppc;				// Pitch/Pan Centre
-	uint8  gbv;				// Global Volume
-	uint8  dfp;				// Panning
-	uint8  rv;				// Vol Swing
-	uint8  rp;				// Pan Swing
-	uint16 trkvers;			// Tracker ID
-	uint8  nos;				// Number of embedded samples
-	char   reserved1;		// Reserved
-	char   name[26];		// Instrument Name, null-terminated (but may also contain nulls)
-	uint8  ifc;				// Filter Cutoff
-	uint8  ifr;				// Filter Resonance
-	uint8  mch;				// MIDI Channel
-	uint8  mpr;				// MIDI Program
-	uint8  mbank[2];		// MIDI Bank
-	uint8  keyboard[240];	// Sample / Transpose map
+	char     id[4];			// Magic Bytes (IMPI)
+	char     filename[13];	// DOS Filename, null-terminated
+	uint8le  nna;			// New Note Action
+	uint8le  dct;			// Duplicate Note Check Type
+	uint8le  dca;			// Duplicate Note Check Action
+	uint16le fadeout;		// Instrument Fadeout (0...256, although values up to 1024 would be sensible. Up to IT2.07, the limit was 0...128)
+	int8le   pps;			// Pitch/Pan Separatation
+	uint8le  ppc;			// Pitch/Pan Centre
+	uint8le  gbv;			// Global Volume
+	uint8le  dfp;			// Panning
+	uint8le  rv;			// Vol Swing
+	uint8le  rp;			// Pan Swing
+	uint16le trkvers;		// Tracker ID
+	uint8le  nos;			// Number of embedded samples
+	char     reserved1;		// Reserved
+	char     name[26];		// Instrument Name, null-terminated (but may also contain nulls)
+	uint8le  ifc;			// Filter Cutoff
+	uint8le  ifr;			// Filter Resonance
+	uint8le  mch;			// MIDI Channel
+	uint8le  mpr;			// MIDI Program
+	uint8le  mbank[2];		// MIDI Bank
+	uint8le  keyboard[240];	// Sample / Transpose map
 	ITEnvelope volenv;		// Volume Envelope
 	ITEnvelope panenv;		// Pan Envelope
 	ITEnvelope pitchenv;	// Pitch / Filter Envelope
-	char   dummy[4];		// IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks.
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	char       dummy[4];	// IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks.
 
 	// Convert OpenMPT's internal instrument representation to an ITInstrument. Returns amount of bytes that need to be written.
 	uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile);
@@ -192,29 +179,26 @@ struct PACKED ITInstrument
 	uint32 ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const;
 };
 
-STATIC_ASSERT(sizeof(ITInstrument) == 554);
+MPT_BINARY_STRUCT(ITInstrument, 554)
 
 
 // MPT IT Instrument Extension
-struct PACKED ITInstrumentEx
+struct ITInstrumentEx
 {
 	ITInstrument iti;		// Normal IT Instrument
 	uint8 keyboardhi[120];	// High Byte of Sample map
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
-
+	
 	// Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written.
 	uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile);
 	// Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
 	uint32 ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const;
 };
 
-STATIC_ASSERT(sizeof(ITInstrumentEx) == sizeof(ITInstrument) + 120);
+MPT_BINARY_STRUCT(ITInstrumentEx, sizeof(ITInstrument) + 120)
 
 
 // IT Sample Format
-struct PACKED ITSample
+struct ITSample
 {
 	// Magic Bytes
 	enum Magic
@@ -245,28 +229,25 @@ struct PACKED ITSample
 		cvtPTM8to16			= 0x08,
 	};
 
-	char   id[4];			// Magic Bytes (IMPS)
-	char   filename[13];	// DOS Filename, null-terminated
-	uint8  gvl;				// Global Volume
-	uint8  flags;			// Sample Flags
-	uint8  vol;				// Default Volume
-	char   name[26];		// Sample Name, null-terminated (but may also contain nulls)
-	uint8  cvt;				// Sample Import Format
-	uint8  dfp;				// Sample Panning
-	uint32 length;			// Sample Length (in samples)
-	uint32 loopbegin;		// Sample Loop Begin (in samples)
-	uint32 loopend;			// Sample Loop End (in samples)
-	uint32 C5Speed;			// C-5 frequency
-	uint32 susloopbegin;	// Sample Sustain Begin (in samples)
-	uint32 susloopend;		// Sample Sustain End (in samples)
-	uint32 samplepointer;	// Pointer to sample data
-	uint8  vis;				// Auto-Vibrato Rate (called Sweep in IT)
-	uint8  vid;				// Auto-Vibrato Depth
-	uint8  vir;				// Auto-Vibrato Sweep (called Rate in IT)
-	uint8  vit;				// Auto-Vibrato Type
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	char     id[4];			// Magic Bytes (IMPS)
+	char     filename[13];	// DOS Filename, null-terminated
+	uint8le  gvl;			// Global Volume
+	uint8le  flags;			// Sample Flags
+	uint8le  vol;			// Default Volume
+	char     name[26];		// Sample Name, null-terminated (but may also contain nulls)
+	uint8le  cvt;			// Sample Import Format
+	uint8le  dfp;			// Sample Panning
+	uint32le length;		// Sample Length (in samples)
+	uint32le loopbegin;		// Sample Loop Begin (in samples)
+	uint32le loopend;		// Sample Loop End (in samples)
+	uint32le C5Speed;		// C-5 frequency
+	uint32le susloopbegin;	// Sample Sustain Begin (in samples)
+	uint32le susloopend;	// Sample Sustain End (in samples)
+	uint32le samplepointer;	// Pointer to sample data
+	uint8le  vis;			// Auto-Vibrato Rate (called Sweep in IT)
+	uint8le  vid;			// Auto-Vibrato Depth
+	uint8le  vir;			// Auto-Vibrato Sweep (called Rate in IT)
+	uint8le  vit;			// Auto-Vibrato Type
 
 	// Convert OpenMPT's internal sample representation to an ITSample.
 	void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal);
@@ -276,20 +257,17 @@ struct PACKED ITSample
 	SampleIO GetSampleFormat(uint16 cwtv = 0x214) const;
 };
 
-STATIC_ASSERT(sizeof(ITSample) == 80);
+MPT_BINARY_STRUCT(ITSample, 80)
 
 
 struct FileHistory;
 
 // IT Header extension: Save history
-struct PACKED ITHistoryStruct
+struct ITHistoryStruct
 {
-	uint16 fatdate;	// DOS / FAT date when the file was opened / created in the editor. For details, read http://msdn.microsoft.com/en-us/library/ms724247(VS.85).aspx
-	uint16 fattime;	// DOS / FAT time when the file was opened / created in the editor.
-	uint32 runtime;	// The time how long the file was open in the editor, in 1/18.2th seconds. (= ticks of the DOS timer)
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	uint16le fatdate;	// DOS / FAT date when the file was opened / created in the editor. For details, read http://msdn.microsoft.com/en-us/library/ms724247(VS.85).aspx
+	uint16le fattime;	// DOS / FAT time when the file was opened / created in the editor.
+	uint32le runtime;	// The time how long the file was open in the editor, in 1/18.2th seconds. (= ticks of the DOS timer)
 
 	// Convert an ITHistoryStruct to OpenMPT's internal edit history representation
 	void ConvertToMPT(FileHistory &mptHistory) const;
@@ -298,11 +276,8 @@ struct PACKED ITHistoryStruct
 
 };
 
-STATIC_ASSERT(sizeof(ITHistoryStruct) == 8);
+MPT_BINARY_STRUCT(ITHistoryStruct, 8)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
 enum IT_ReaderBitMasks
 {
diff --git a/soundlib/InstrumentExtensions.cpp b/soundlib/InstrumentExtensions.cpp
index aa3e368..f30ce8d 100644
--- a/soundlib/InstrumentExtensions.cpp
+++ b/soundlib/InstrumentExtensions.cpp
@@ -181,7 +181,7 @@ bool IsNegative(const T &val)
 	if(only_this_code == fcode || only_this_code == Util::MaxValueOfType(only_this_code)) \
 	{ \
 		type tmp = input-> name; \
-		tmp = SwapBytesReturnLE(tmp); \
+		tmp = SwapBytesLE(tmp); \
 		fwrite(&tmp , 1 , fsize , file); \
 	} \
 /**/
@@ -198,7 +198,7 @@ bool IsNegative(const T &val)
 		mpt::IO::WriteIntLE<uint32>(file, fcode); \
 		mpt::IO::WriteIntLE<uint16>(file, fsize); \
 		type tmp = (type)(input-> name ); \
-		tmp = SwapBytesReturnLE(tmp); \
+		tmp = SwapBytesLE(tmp); \
 		fwrite(&tmp , 1 , fsize , file); \
 	} else if(only_this_code == fcode)\
 	{ \
@@ -207,7 +207,7 @@ bool IsNegative(const T &val)
 		/* This worked fine on little-endian, on big-endian not so much. Thus support writing size-mismatched fields. */ \
 		MPT_ASSERT(fixedsize >= fsize); \
 		type tmp = (type)(input-> name ); \
-		tmp = SwapBytesReturnLE(tmp); \
+		tmp = SwapBytesLE(tmp); \
 		fwrite(&tmp , 1 , fsize , file); \
 		if(fixedsize > fsize) \
 		{ \
@@ -243,7 +243,7 @@ bool IsNegative(const T &val)
 		{ \
 			type tmp; \
 			tmp = input-> name [i]; \
-			tmp = SwapBytesReturnLE(tmp); \
+			tmp = SwapBytesLE(tmp); \
 			fwrite(&tmp, 1, sizeof(type), file); \
 		} \
 	} \
@@ -275,14 +275,14 @@ bool IsNegative(const T &val)
 			{ \
 				type tmp; \
 				tmp = env[i]. envField; \
-				tmp = SwapBytesReturnLE(tmp); \
+				tmp = SwapBytesLE(tmp); \
 				fwrite(&tmp, 1, sizeof(type), file); \
 			} \
 			/* Not every instrument's envelope will be the same length. fill up with zeros. */ \
 			for(uint32 i = maxNodes; i < fsize/sizeof(type); ++i) \
 			{ \
 				type tmp = 0; \
-				tmp = SwapBytesReturnLE(tmp); \
+				tmp = SwapBytesLE(tmp); \
 				fwrite(&tmp, 1, sizeof(type), file); \
 			} \
 		} \
@@ -344,7 +344,6 @@ if(!writeAll)
 // whereas ITP saves [code][size][ins1.Value][code][size][ins2.Value]...
 // too late to turn back....
 void CSoundFile::SaveExtendedInstrumentProperties(INSTRUMENTINDEX nInstruments, FILE *f) const
-//--------------------------------------------------------------------------------------------
 {
 	uint32 code = MAGIC4BE('M','P','T','X');	// write extension header code
 	mpt::IO::WriteIntLE<uint32>(f, code);
@@ -409,7 +408,6 @@ void CSoundFile::SaveExtendedInstrumentProperties(INSTRUMENTINDEX nInstruments,
 }
 
 void CSoundFile::WriteInstrumentPropertyForAllInstruments(uint32 code, uint16 size, FILE *f, INSTRUMENTINDEX nInstruments) const
-//------------------------------------------------------------------------------------------------------------------------------
 {
 	mpt::IO::WriteIntLE<uint32>(f, code);		//write code
 	mpt::IO::WriteIntLE<uint16>(f, size);		//write size
@@ -576,7 +574,6 @@ bool ReadInstrumentHeaderField(ModInstrument *input, uint32 fcode, uint16 fsize,
 
 // Convert instrument flags which were read from 'dF..' extension to proper internal representation.
 static void ConvertReadExtendedFlags(ModInstrument *pIns)
-//-------------------------------------------------------
 {
 	// Flags of 'dF..' datafield in extended instrument properties.
 	enum
@@ -623,7 +620,6 @@ static void ConvertReadExtendedFlags(ModInstrument *pIns)
 
 
 void ReadInstrumentExtensionField(ModInstrument* pIns, const uint32 code, const uint16 size, FileReader &file)
-//------------------------------------------------------------------------------------------------------------
 {
 	if(code == MAGIC4BE('K','[','.','.'))
 	{
@@ -651,7 +647,6 @@ void ReadInstrumentExtensionField(ModInstrument* pIns, const uint32 code, const
 
 
 void ReadExtendedInstrumentProperty(ModInstrument* pIns, const uint32 code, FileReader &file)
-//-------------------------------------------------------------------------------------------
 {
 	uint16 size = file.ReadUint16LE();
 	if(!file.CanRead(size))
@@ -663,7 +658,6 @@ void ReadExtendedInstrumentProperty(ModInstrument* pIns, const uint32 code, File
 
 
 void ReadExtendedInstrumentProperties(ModInstrument* pIns, FileReader &file)
-//--------------------------------------------------------------------------
 {
 	if(!file.ReadMagic("XTPM"))	// 'MPTX'
 	{
@@ -678,7 +672,6 @@ void ReadExtendedInstrumentProperties(ModInstrument* pIns, FileReader &file)
 
 
 void CSoundFile::LoadExtendedInstrumentProperties(FileReader &file, bool *pInterpretMptMade)
-//------------------------------------------------------------------------------------------
 {
 	if(!file.ReadMagic("XTPM"))	// 'MPTX'
 	{
diff --git a/soundlib/IntMixer.h b/soundlib/IntMixer.h
index 9e58c5c..61798bd 100644
--- a/soundlib/IntMixer.h
+++ b/soundlib/IntMixer.h
@@ -13,6 +13,7 @@
 
 #include "Resampler.h"
 #include "MixerInterface.h"
+#include "Paula.h"
 
 OPENMPT_NAMESPACE_BEGIN
 
@@ -23,7 +24,7 @@ struct IntToIntTraits : public MixerTraits<channelsOut, channelsIn, out, in>
 	typedef typename base_t::input_t input_t;
 	typedef typename base_t::output_t output_t;
 
-	static forceinline output_t Convert(const input_t x)
+	static MPT_CONSTEXPR11_FUN output_t Convert(const input_t x)
 	{
 		static_assert(std::numeric_limits<input_t>::is_integer, "Input must be integer");
 		static_assert(std::numeric_limits<output_t>::is_integer, "Output must be integer");
@@ -42,24 +43,80 @@ typedef IntToIntTraits<2, 2, mixsample_t, int16, 16> Int16SToIntS;
 //////////////////////////////////////////////////////////////////////////
 // Interpolation templates
 
+
+template<class Traits>
+struct AmigaBlepInterpolation
+{
+	SamplePosition subIncrement;
+	Paula::State *paula;
+	int numSteps;
+	bool filter;
+
+	MPT_FORCEINLINE void Start(ModChannel &chn, const CResampler &)
+	{
+		paula = &chn.paulaState;
+		numSteps = paula->numSteps;
+		filter = chn.dwFlags[CHN_AMIGAFILTER];
+		if(numSteps)
+			subIncrement = chn.increment / paula->numSteps;
+	}
+
+	MPT_FORCEINLINE void End(const ModChannel &) { }
+
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
+	{
+		SamplePosition pos(0, posLo);
+		// First, process steps of full length (one Amiga clock interval)
+		for(int step = numSteps; step > 0; step--)
+		{
+			typename Traits::output_t inSample = 0;
+			int32 posInt = pos.GetInt() * Traits::numChannelsIn;
+			for(int32 i = 0; i < Traits::numChannelsIn; i++)
+				inSample += Traits::Convert(inBuffer[posInt + i]);
+			paula->InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
+			paula->Clock(Paula::MINIMUM_INTERVAL);
+			pos += subIncrement;
+		}
+		paula->remainder += paula->stepRemainder;
+
+		// Now, process any remaining integer clock amount < MINIMUM_INTERVAL
+		uint32 remainClocks = paula->remainder.GetInt();
+		if(remainClocks)
+		{
+			typename Traits::output_t inSample = 0;
+			int32 posInt = pos.GetInt() * Traits::numChannelsIn;
+			for(int32 i = 0; i < Traits::numChannelsIn; i++)
+				inSample += Traits::Convert(inBuffer[posInt + i]);
+			paula->InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
+			paula->Clock(remainClocks);
+			paula->remainder.RemoveInt();
+		}
+
+		auto out = paula->OutputSample(filter);
+		for(unsigned int i = 0; i < Traits::numChannelsOut; i++)
+			outSample[i] = out;
+	}
+};
+
+
 template<class Traits>
 struct LinearInterpolation
 {
-	forceinline void Start(const ModChannel &, const CResampler &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const typename Traits::output_t fract = posLo >> 8;
+		const typename Traits::output_t fract = posLo >> 18u;
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
 			typename Traits::output_t srcVol = Traits::Convert(inBuffer[i]);
 			typename Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]);
 
-			outSample[i] = srcVol + ((fract * (destVol - srcVol)) >> 8);
+			outSample[i] = srcVol + ((fract * (destVol - srcVol)) / 16384);
 		}
 	}
 };
@@ -68,13 +125,13 @@ struct LinearInterpolation
 template<class Traits>
 struct FastSincInterpolation
 {
-	forceinline void Start(const ModChannel &, const CResampler &) { }
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const int16 *lut = CResampler::FastSincTable + ((posLo >> 6) & 0x3FC);
+		const int16 *lut = CResampler::FastSincTable + ((posLo >> 22) & 0x3FC);
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -82,7 +139,7 @@ struct FastSincInterpolation
 				 (lut[0] * Traits::Convert(inBuffer[i - Traits::numChannelsIn])
 				+ lut[1] * Traits::Convert(inBuffer[i])
 				+ lut[2] * Traits::Convert(inBuffer[i + Traits::numChannelsIn])
-				+ lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])) >> 14;
+				+ lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])) / 16384;
 		}
 	}
 };
@@ -93,7 +150,7 @@ struct PolyphaseInterpolation
 {
 	const SINC_TYPE *sinc;
 
-	forceinline void Start(const ModChannel &chn, const CResampler &resampler)
+	MPT_FORCEINLINE void Start(const ModChannel &chn, const CResampler &resampler)
 	{
 		#ifdef MODPLUG_TRACKER
 			// Otherwise causes "warning C4100: 'resampler' : unreferenced formal parameter"
@@ -101,16 +158,16 @@ struct PolyphaseInterpolation
 			// #pragma warning fails with this templated case for unknown reasons.
 			MPT_UNREFERENCED_PARAMETER(resampler);
 		#endif // MODPLUG_TRACKER
-		sinc = (((chn.nInc > 0x13000) || (chn.nInc < -0x13000)) ?
-			(((chn.nInc > 0x18000) || (chn.nInc < -0x18000)) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
+		sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < SamplePosition(-0x130000000ll))) ?
+			(((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
 	}
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const SINC_TYPE *lut = sinc + ((posLo >> (16 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH;
+		const SINC_TYPE *lut = sinc + ((posLo >> (32 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH;
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -122,7 +179,7 @@ struct PolyphaseInterpolation
 				+ lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn])
 				+ lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])
 				+ lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn])
-				+ lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn])) >> SINC_QUANTSHIFT;
+				+ lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn])) / (1 << SINC_QUANTSHIFT);
 		}
 	}
 };
@@ -133,17 +190,17 @@ struct FIRFilterInterpolation
 {
 	const int16 *WFIRlut;
 
-	forceinline void Start(const ModChannel &, const CResampler &resampler)
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &resampler)
 	{
 		WFIRlut = resampler.m_WindowedFIR.lut;
 	}
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const int32 posLo)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
-		const int16 * const lut = WFIRlut + (((posLo + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK);
+		const int16 * const lut = WFIRlut + ((((posLo >> 16) + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK);
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -157,7 +214,7 @@ struct FIRFilterInterpolation
 				+ (lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]))
 				+ (lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]))
 				+ (lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]));
-			outSample[i] = ((vol1 >> 1) + (vol2 >> 1)) >> (WFIR_16BITSHIFT - 1);
+			outSample[i] = ((vol1 / 2) + (vol2 / 2)) / (1 << (WFIR_16BITSHIFT - 1));
 		}
 	}
 };
@@ -171,13 +228,13 @@ struct NoRamp
 {
 	typename Traits::output_t lVol, rVol;
 
-	forceinline void Start(const ModChannel &chn)
+	MPT_FORCEINLINE void Start(const ModChannel &chn)
 	{
 		lVol = chn.leftVol;
 		rVol = chn.rightVol;
 	}
 
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 };
 
 
@@ -185,13 +242,13 @@ struct Ramp
 {
 	int32 lRamp, rRamp;
 
-	forceinline void Start(const ModChannel &chn)
+	MPT_FORCEINLINE void Start(const ModChannel &chn)
 	{
 		lRamp = chn.rampLeftVol;
 		rRamp = chn.rampRightVol;
 	}
 
-	forceinline void End(ModChannel &chn)
+	MPT_FORCEINLINE void End(ModChannel &chn)
 	{
 		chn.rampLeftVol = lRamp; chn.leftVol = lRamp >> VOLUMERAMPPRECISION;
 		chn.rampRightVol = rRamp; chn.rightVol = rRamp >> VOLUMERAMPPRECISION;
@@ -204,7 +261,7 @@ template<class Traits>
 struct MixMonoFastNoRamp : public NoRamp<Traits>
 {
 	typedef NoRamp<Traits> base_t;
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
 	{
 		typename Traits::output_t vol = outSample[0] * base_t::lVol;
 		for(int i = 0; i < Traits::numChannelsOut; i++)
@@ -219,7 +276,7 @@ template<class Traits>
 struct MixMonoNoRamp : public NoRamp<Traits>
 {
 	typedef NoRamp<Traits> base_t;
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
 	{
 		outBuffer[0] += outSample[0] * base_t::lVol;
 		outBuffer[1] += outSample[0] * base_t::rVol;
@@ -230,7 +287,7 @@ struct MixMonoNoRamp : public NoRamp<Traits>
 template<class Traits>
 struct MixMonoRamp : public Ramp
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
 	{
 		lRamp += chn.leftRamp;
 		rRamp += chn.rightRamp;
@@ -244,7 +301,7 @@ template<class Traits>
 struct MixStereoNoRamp : public NoRamp<Traits>
 {
 	typedef NoRamp<Traits> base_t;
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
 	{
 		outBuffer[0] += outSample[0] * base_t::lVol;
 		outBuffer[1] += outSample[1] * base_t::rVol;
@@ -255,7 +312,7 @@ struct MixStereoNoRamp : public NoRamp<Traits>
 template<class Traits>
 struct MixStereoRamp : public Ramp
 {
-	forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
 	{
 		lRamp += chn.leftRamp;
 		rRamp += chn.rightRamp;
@@ -272,10 +329,10 @@ struct MixStereoRamp : public Ramp
 template<class Traits>
 struct NoFilter
 {
-	forceinline void Start(const ModChannel &) { }
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
+	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
 };
 
 
@@ -286,7 +343,7 @@ struct ResonantFilter
 	// Filter history
 	typename Traits::output_t fy[Traits::numChannelsIn][2];
 
-	forceinline void Start(const ModChannel &chn)
+	MPT_FORCEINLINE void Start(const ModChannel &chn)
 	{
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -295,7 +352,7 @@ struct ResonantFilter
 		}
 	}
 
-	forceinline void End(ModChannel &chn)
+	MPT_FORCEINLINE void End(ModChannel &chn)
 	{
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
@@ -307,14 +364,17 @@ struct ResonantFilter
 	// Filter values are clipped to double the input range
 #define ClipFilter(x) Clamp<typename Traits::output_t, typename Traits::output_t>(x, int16_min * 2, int16_max * 2)
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
 
 		for(int i = 0; i < Traits::numChannelsIn; i++)
 		{
-			typename Traits::output_t val = (outSample[i] * chn.nFilter_A0 + ClipFilter(fy[i][0]) * chn.nFilter_B0 + ClipFilter(fy[i][1]) * chn.nFilter_B1
-				+ (1 << (MIXING_FILTER_PRECISION - 1))) >> MIXING_FILTER_PRECISION;
+			typename Traits::output_t val = static_cast<typename Traits::output_t>((
+				Util::mul32to64(outSample[i], chn.nFilter_A0) +
+				Util::mul32to64(ClipFilter(fy[i][0]), chn.nFilter_B0) +
+				Util::mul32to64(ClipFilter(fy[i][1]), chn.nFilter_B1) +
+				(1 << (MIXING_FILTER_PRECISION - 1))) / (1 << MIXING_FILTER_PRECISION));
 			fy[i][1] = fy[i][0];
 			fy[i][0] = val - (outSample[i] & chn.nFilter_HP);
 			outSample[i] = val;
diff --git a/soundlib/Load_669.cpp b/soundlib/Load_669.cpp
index 7e5e232..d6953e2 100644
--- a/soundlib/Load_669.cpp
+++ b/soundlib/Load_669.cpp
@@ -15,51 +15,27 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED _669FileHeader
+struct _669FileHeader
 {
-	enum MagicBytes
-	{
-		magic669	= 0x6669,	// 'if'
-		magic669Ext	= 0x4E4A	// 'JN'
-	};
-
-	uint16 sig;					// 'if' or 'JN'
-	char   songMessage[108];	// Song Message
-	uint8  samples;				// number of samples (1-64)
-	uint8  patterns;			// number of patterns (1-128)
-	uint8  restartPos;
-	uint8  orders[128];
-	uint8  tempoList[128];
-	uint8  breaks[128];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(sig);
-	}
+	char  magic[2];			// 'if' (0x6669, ha ha) or 'JN'
+	char  songMessage[108];	// Song Message
+	uint8 samples;			// number of samples (1-64)
+	uint8 patterns;			// number of patterns (1-128)
+	uint8 restartPos;
+	uint8 orders[128];
+	uint8 tempoList[128];
+	uint8 breaks[128];
 };
 
-STATIC_ASSERT(sizeof(_669FileHeader) == 497);
+MPT_BINARY_STRUCT(_669FileHeader, 497)
 
 
-struct PACKED _669Sample
+struct _669Sample
 {
-	char   filename[13];
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-	}
+	char     filename[13];
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
 
 	// Convert a 669 sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -83,39 +59,80 @@ struct PACKED _669Sample
 	}
 };
 
-STATIC_ASSERT(sizeof(_669Sample) == 25);
+MPT_BINARY_STRUCT(_669Sample, 25)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+
+static bool ValidateHeader(const _669FileHeader &fileHeader)
+{
+	if((std::memcmp(fileHeader.magic, "if", 2) && std::memcmp(fileHeader.magic, "JN", 2))
+		|| fileHeader.samples > 64
+		|| fileHeader.restartPos >= 128
+		|| fileHeader.patterns > 128)
+	{
+		return false;
+	}
+	for(std::size_t i = 0; i < CountOf(fileHeader.breaks); i++)
+	{
+		if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
+		{
+			return false;
+		}
+		if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
+		{
+			return false;
+		}
+		if(fileHeader.breaks[i] >= 64)
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const _669FileHeader &fileHeader)
+{
+	return fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize)
+{
+	_669FileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	_669FileHeader fileHeader;
 
 	file.Rewind();
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| (fileHeader.sig != _669FileHeader::magic669 && fileHeader.sig != _669FileHeader::magic669Ext)
-		|| fileHeader.samples > 64
-		|| fileHeader.restartPos >= 128
-		|| fileHeader.patterns > 128
-		|| !file.CanRead(fileHeader.samples * sizeof(_669Sample)))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
 	}
-	
-	for(size_t i = 0; i < CountOf(fileHeader.breaks); i++)
+	if(!ValidateHeader(fileHeader))
 	{
-		if(fileHeader.breaks[i] > 64)
-			return false;
+		return false;
 	}
-
 	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
+	
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
 
 	InitializeGlobals(MOD_TYPE_669);
 	m_nMinPeriod = 28 << 2;
@@ -128,16 +145,16 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
 	m_SongFlags.set(SONG_LINEARSLIDES);
 #endif // MODPLUG_TRACKER
 
-	if(fileHeader.sig == _669FileHeader::magic669)
-		m_madeWithTracker = "Composer 669";
+	if(!memcmp(fileHeader.magic, "if", 2))
+		m_madeWithTracker = MPT_USTRING("Composer 669");
 	else
-		m_madeWithTracker = "UNIS 669";
+		m_madeWithTracker = MPT_USTRING("UNIS 669");
 
 	m_nSamples = fileHeader.samples;
 	for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
 	{
 		_669Sample sampleHeader;
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		// Since 669 files have very unfortunate magic bytes ("if") and can
 		// hardly be validated, reject any file with far too big samples.
 		if(sampleHeader.length >= 0x4000000)
@@ -152,9 +169,9 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
 	m_songMessage.ReadFixedLineLength(mpt::byte_cast<const mpt::byte*>(fileHeader.songMessage), 108, 36, 0);
 
 	// Reading Orders
-	Order.ReadFromArray(fileHeader.orders, CountOf(fileHeader.orders), 0xFF, 0xFE);
-	if(Order[fileHeader.restartPos] < fileHeader.patterns)
-		Order.SetRestartPos(fileHeader.restartPos);
+	ReadOrderFromArray(Order(), fileHeader.orders, MPT_ARRAY_COUNT(fileHeader.orders), 0xFF, 0xFE);
+	if(Order()[fileHeader.restartPos] < fileHeader.patterns)
+		Order().SetRestartPos(fileHeader.restartPos);
 
 	// Set up panning
 	for(CHANNELINDEX chn = 0; chn < 8; chn++)
@@ -164,6 +181,7 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Reading Patterns
+	Patterns.ResizeArray(fileHeader.patterns);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.patterns; pat++)
 	{
 		if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
@@ -287,10 +305,10 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
 		// Write pattern break
 		if(fileHeader.breaks[pat] < 63)
 		{
-			Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(fileHeader.breaks[pat]).Retry(EffectWriter::rmTryNextRow));
+			Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(fileHeader.breaks[pat]).RetryNextRow());
 		}
 		// And of course the speed...
-		Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, fileHeader.tempoList[pat]).Retry(EffectWriter::rmTryNextRow));
+		Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, fileHeader.tempoList[pat]).RetryNextRow());
 	}
 
 	if(loadFlags & loadSampleData)
diff --git a/soundlib/Load_amf.cpp b/soundlib/Load_amf.cpp
index c06e8f2..53c1f27 100644
--- a/soundlib/Load_amf.cpp
+++ b/soundlib/Load_amf.cpp
@@ -18,13 +18,8 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // ASYLUM AMF File Header
-struct PACKED AsylumFileHeader
+struct AsylumFileHeader
 {
 	char  signature[32];
 	uint8 defaultSpeed;
@@ -35,34 +30,26 @@ struct PACKED AsylumFileHeader
 	uint8 restartPos;
 };
 
-STATIC_ASSERT(sizeof(AsylumFileHeader) == 38);
+MPT_BINARY_STRUCT(AsylumFileHeader, 38)
 
 
 // ASYLUM AMF Sample Header
-struct PACKED AsylumSampleHeader
+struct AsylumSampleHeader
 {
-	char   name[22];
-	uint8  finetune;
-	uint8  defaultVolume;
-	int8   transpose;
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopLength;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopLength);
-	}
+	char     name[22];
+	uint8le  finetune;
+	uint8le  defaultVolume;
+	int8le   transpose;
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopLength;
 
 	// Convert an AMF sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const
 	{
 		mptSmp.Initialize();
 		mptSmp.nFineTune = MOD2XMFineTune(finetune);
-		mptSmp.nVolume = std::min(defaultVolume, uint8(64)) * 4u;
+		mptSmp.nVolume = std::min<uint8>(defaultVolume, 64) * 4u;
 		mptSmp.RelativeTone = transpose;
 		mptSmp.nLength = length;
 
@@ -75,48 +62,75 @@ struct PACKED AsylumSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(AsylumSampleHeader) == 37);
+MPT_BINARY_STRUCT(AsylumSampleHeader, 37)
 
 
 // DSMI AMF File Header
-struct PACKED AMFFileHeader
+struct AMFFileHeader
 {
-	char   amf[3];
-	uint8  version;
-	char   title[32];
-	uint8  numSamples;
-	uint8  numOrders;
-	uint16 numTracks;
-	uint8  numChannels;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numTracks);
-	}
+	char     amf[3];
+	uint8le  version;
+	char     title[32];
+	uint8le  numSamples;
+	uint8le  numOrders;
+	uint16le numTracks;
+	uint8le  numChannels;
 };
 
-STATIC_ASSERT(sizeof(AMFFileHeader) == 41);
+MPT_BINARY_STRUCT(AMFFileHeader, 41)
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static bool ValidateHeader(const AsylumFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
+		|| fileHeader.numSamples > 64
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AsylumFileHeader &fileHeader)
+{
+	return 256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize)
+{
+	AsylumFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
-//--------------------------------------------------------------------------
 {
 	file.Rewind();
 
 	AsylumFileHeader fileHeader;
-	if(!file.ReadStruct(fileHeader)
-		|| memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
-		|| fileHeader.numSamples > 64
-		|| !file.CanRead(256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -129,17 +143,19 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
 	m_nSamples = fileHeader.numSamples;
 	if(fileHeader.restartPos < fileHeader.numOrders)
 	{
-		Order.SetRestartPos(fileHeader.restartPos);
+		Order().SetRestartPos(fileHeader.restartPos);
 	}
 	m_songName.clear();
 
-	Order.ReadAsByte(file, 256, fileHeader.numOrders);
+	uint8 orders[256];
+	file.ReadArray(orders);
+	ReadOrderFromArray(Order(), orders, fileHeader.numOrders);
 
 	// Read Sample Headers
 	for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
 	{
 		AsylumSampleHeader sampleHeader;
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		sampleHeader.ConvertToMPT(Samples[smp]);
 		mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp], sampleHeader.name);
 	}
@@ -147,6 +163,7 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
 	file.Skip((64 - fileHeader.numSamples) * sizeof(AsylumSampleHeader));
 
 	// Read Patterns
+	Patterns.ResizeArray(fileHeader.numPatterns);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
 	{
 		if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
@@ -155,21 +172,19 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
 			continue;
 		}
 
-		ModCommand *p = Patterns[pat];
-		for(size_t i = 0; i < 8 * 64; i++, p++)
+		for(auto &m : Patterns[pat])
 		{
 			uint8 data[4];
 			file.ReadArray(data);
 
-			p->note = NOTE_NONE;
 			if(data[0] && data[0] + 12 + NOTE_MIN <= NOTE_MAX)
 			{
-				p->note = data[0] + 12 + NOTE_MIN;
+				m.note = data[0] + 12 + NOTE_MIN;
 			}
-			p->instr = data[1];
-			p->command = data[2];
-			p->param = data[3];
-			ConvertModCommand(*p);
+			m.instr = data[1];
+			m.command = data[2];
+			m.param = data[3];
+			ConvertModCommand(m);
 		}
 	}
 
@@ -194,7 +209,6 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
 
 // Read a single AMF track (channel) into a pattern.
 static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &fileChunk)
-//------------------------------------------------------------------------------------
 {
 	fileChunk.Rewind();
 	ModCommand::INSTR lastInstr = 0;
@@ -364,19 +378,49 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file
 }
 
 
+static bool ValidateHeader(const AMFFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.amf, "AMF", 3)
+		|| fileHeader.version < 8 || fileHeader.version > 14
+		|| ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10)
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize)
+{
+	AMFFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
-//------------------------------------------------------------------------
 {
 	file.Rewind();
 
 	AMFFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.amf, "AMF", 3)
-		|| fileHeader.version < 8 || fileHeader.version > 14
-		|| ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -438,7 +482,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Setup Order List
-	Order.resize(fileHeader.numOrders);
+	Order().resize(fileHeader.numOrders);
 	std::vector<uint16> patternLength;
 	const FileReader::off_t trackStartPos = file.GetPosition() + (fileHeader.version >= 14 ? 2 : 0);
 	if(fileHeader.version >= 14)
@@ -448,7 +492,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
 
 	for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++)
 	{
-		Order[ord] = ord;
+		Order()[ord] = ord;
 		if(fileHeader.version >= 14)
 		{
 			patternLength[ord] = file.ReadUint16LE();
@@ -516,16 +560,14 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
 	}
 	
 	// Read Track Mapping Table
-	std::vector<uint16> trackMap;
-	if(!file.ReadVectorLE(trackMap, fileHeader.numTracks))
+	std::vector<uint16le> trackMap;
+	if(!file.ReadVector(trackMap, fileHeader.numTracks))
 	{
 		return false;
 	}
 	uint16 trackCount = 0;
-	for(std::vector<uint16>::const_iterator i = trackMap.begin(); i != trackMap.end(); i++)
-	{
-		trackCount = std::max(trackCount, *i);
-	}
+	if(!trackMap.empty())
+		trackCount = *std::max_element(trackMap.cbegin(), trackMap.cend());
 
 	// Store Tracks Positions
 	std::vector<FileReader> trackData(trackCount);
@@ -552,9 +594,9 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
 		// First, try compacting the sample indices so that the loop won't have 2^32 iterations in the worst case.
 		std::vector<uint32> samplePosCompact = samplePos;
 		std::sort(samplePosCompact.begin(), samplePosCompact.end());
-		std::vector<uint32>::const_iterator end = std::unique(samplePosCompact.begin(), samplePosCompact.end());
+		auto end = std::unique(samplePosCompact.begin(), samplePosCompact.end());
 
-		for(std::vector<uint32>::const_iterator pos = samplePosCompact.begin(); pos != end && file.CanRead(1); pos++)
+		for(auto pos = samplePosCompact.begin(); pos != end && file.CanRead(1); pos++)
 		{
 			for(SAMPLEINDEX smp = 0; smp < GetNumSamples() && file.CanRead(1); smp++)
 			{
@@ -573,6 +615,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Create the patterns from the list of tracks
+	Patterns.ResizeArray(fileHeader.numOrders);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numOrders; pat++)
 	{
 		uint16 patLength = pat < patternLength.size() ? patternLength[pat] : 64;
@@ -583,8 +626,8 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
 
 		// Get table with per-channel track assignments
 		file.Seek(trackStartPos + pat * (GetNumChannels() * 2 + (fileHeader.version >= 14 ? 2 : 0)));
-		std::vector<uint16> tracks;
-		if(!file.ReadVectorLE(tracks, GetNumChannels()))
+		std::vector<uint16le> tracks;
+		if(!file.ReadVector(tracks, GetNumChannels()))
 		{
 			continue;
 		}
diff --git a/soundlib/Load_ams.cpp b/soundlib/Load_ams.cpp
index 45e3ad9..412690f 100644
--- a/soundlib/Load_ams.cpp
+++ b/soundlib/Load_ams.cpp
@@ -22,30 +22,8 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-/////////////////////////////////////////////////////////////////////
-// Common code for both AMS formats
-
-// Read variable-length AMS string (we ignore the maximum text length specified by the AMS specs and accept any length).
-template<size_t destSize>
-static bool ReadAMSString(char (&destBuffer)[destSize], FileReader &file)
-//-----------------------------------------------------------------------
-{
-	const size_t length = file.ReadUint8();
-	return file.ReadString<mpt::String::spacePadded>(destBuffer, length);
-}
-
-// Read variable-length AMS string (we ignore the maximum text length specified by the AMS specs and accept any length).
-static bool ReadAMSString(std::string &dest, FileReader &file)
-//------------------------------------------------------------
-{
-	const size_t length = file.ReadUint8();
-	return file.ReadString<mpt::String::spacePadded>(dest, length);
-}
-
-
 // Read AMS or AMS2 (newVersion = true) pattern. At least this part of the format is more or less identical between the two trackers...
 static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patternChunk)
-//--------------------------------------------------------------------------------------
 {
 	enum
 	{
@@ -279,36 +257,24 @@ static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patte
 /////////////////////////////////////////////////////////////////////
 // AMS (Extreme's Tracker) 1.x loader
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // AMS File Header
-struct PACKED AMSFileHeader
+struct AMSFileHeader
 {
-	uint8  versionLow;
-	uint8  versionHigh;
-	uint8  channelConfig;
-	uint8  numSamps;
-	uint16 numPats;
-	uint16 numOrds;
-	uint8  midiChannels;
-	uint16 extraSize;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numPats);
-		SwapBytesLE(numOrds);
-		SwapBytesLE(extraSize);
-	}
+	uint8le  versionLow;
+	uint8le  versionHigh;
+	uint8le  channelConfig;
+	uint8le  numSamps;
+	uint16le numPats;
+	uint16le numOrds;
+	uint8le  midiChannels;
+	uint16le extraSize;
 };
 
-STATIC_ASSERT(sizeof(AMSFileHeader) == 11);
+MPT_BINARY_STRUCT(AMSFileHeader, 11)
 
 
 // AMS Sample Header
-struct PACKED AMSSampleHeader
+struct AMSSampleHeader
 {
 	enum SampleFlags
 	{
@@ -317,22 +283,13 @@ struct PACKED AMSSampleHeader
 		smpPacked	= 0x03,
 	};
 
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint8  panFinetune;		// High nibble = pan position, low nibble = finetune value
-	uint16 sampleRate;
-	uint8  volume;			// 0...127
-	uint8  flags;			// See SampleFlags
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sampleRate);
-	}
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint8le  panFinetune;	// High nibble = pan position, low nibble = finetune value
+	uint16le sampleRate;
+	uint8le  volume;		// 0...127
+	uint8le  flags;			// See SampleFlags
 
 	// Convert sample header to OpenMPT's internal format.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -343,7 +300,7 @@ struct PACKED AMSSampleHeader
 		mptSmp.nLoopStart = std::min(loopStart, length);
 		mptSmp.nLoopEnd = std::min(loopEnd, length);
 
-		mptSmp.nVolume = (std::min(uint8(127), volume) * 256 + 64) / 127;
+		mptSmp.nVolume = (std::min<uint8>(127, volume) * 256 + 64) / 127;
 		if(panFinetune & 0xF0)
 		{
 			mptSmp.nPan = (panFinetune & 0xF0);
@@ -364,35 +321,81 @@ struct PACKED AMSSampleHeader
 			mptSmp.uFlags.set(CHN_LOOP);
 		}
 
-		if((flags & smp16Bit) || (flags & smp16BitOld))
+		if(flags & (smp16Bit | smp16BitOld))
 		{
 			mptSmp.uFlags.set(CHN_16BIT);
 		}
 	}
 };
 
-STATIC_ASSERT(sizeof(AMSSampleHeader) == 17);
+MPT_BINARY_STRUCT(AMSSampleHeader, 17)
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static bool ValidateHeader(const AMSFileHeader &fileHeader)
+{
+	if(fileHeader.versionHigh != 0x01)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMSFileHeader &fileHeader)
+{
+	return fileHeader.extraSize + 3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize)
+{
+	if(!file.CanRead(7))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!file.ReadMagic("Extreme"))
+	{
+		return ProbeFailure;
+	}
+	AMSFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 
+	if(!file.ReadMagic("Extreme"))
+	{
+		return false;
+	}
 	AMSFileHeader fileHeader;
-	if(!file.ReadMagic("Extreme")
-		|| !file.ReadConvertEndianness(fileHeader)
-		|| !file.Skip(fileHeader.extraSize)
-		|| !file.CanRead(3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u)
-		|| fileHeader.versionHigh != 0x01)
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.Skip(fileHeader.extraSize))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -403,7 +406,7 @@ bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
 	m_nChannels = (fileHeader.channelConfig & 0x1F) + 1;
 	m_nSamples = fileHeader.numSamps;
 	SetupMODPanning(true);
-	m_madeWithTracker = mpt::String::Print("Extreme's Tracker %1.%2", fileHeader.versionHigh, fileHeader.versionLow);
+	m_madeWithTracker = mpt::format(MPT_USTRING("Extreme's Tracker %1.%2"))(fileHeader.versionHigh, fileHeader.versionLow);
 
 	std::vector<bool> packSample(fileHeader.numSamps);
 
@@ -411,32 +414,33 @@ bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
 	for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
 	{
 		AMSSampleHeader sampleHeader;
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		sampleHeader.ConvertToMPT(Samples[smp]);
 		packSample[smp - 1] = (sampleHeader.flags & AMSSampleHeader::smpPacked) != 0;
 	}
 
 	// Texts
-	ReadAMSString(m_songName, file);
+	file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName);
 
 	// Read sample names
 	for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
 	{
-		ReadAMSString(m_szNames[smp], file);
+		file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_szNames[smp]);
 	}
 
 	// Read channel names
 	for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
 	{
 		ChnSettings[chn].Reset();
-		ReadAMSString(ChnSettings[chn].szName, file);
+		file.ReadSizedString<uint8le, mpt::String::spacePadded>(ChnSettings[chn].szName);
 	}
 
 	// Read pattern names
+	Patterns.ResizeArray(fileHeader.numPats);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++)
 	{
 		char name[11];
-		ReadAMSString(name, file);
+		file.ReadSizedString<uint8le, mpt::String::spacePadded>(name);
 		// Create pattern now, so name won't be reset later.
 		if(Patterns.Insert(pat, 64))
 		{
@@ -453,14 +457,14 @@ bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
 		std::string textOut;
 		textOut.reserve(packedLength);
 
-		for(std::vector<uint8>::iterator c = textIn.begin(); c != textIn.end(); c++)
+		for(auto c : textIn)
 		{
-			if(*c & 0x80)
+			if(c & 0x80)
 			{
-				textOut.insert(textOut.end(), (*c & 0x7F), ' ');
+				textOut.insert(textOut.end(), (c & 0x7F), ' ');
 			} else
 			{
-				textOut.push_back(*c);
+				textOut.push_back(c);
 			}
 		}
 
@@ -471,15 +475,7 @@ bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Read Order List
-	std::vector<uint16> orders;
-	if(file.ReadVectorLE(orders, fileHeader.numOrds))
-	{
-		Order.resize(fileHeader.numOrds);
-		for(ORDERINDEX i = 0; i < Order.size(); i++)
-		{
-			Order[i] = orders[i];
-		}
-	}
+	ReadOrderFromFile<uint16le>(Order(), file, fileHeader.numOrds);
 
 	// Read patterns
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++)
@@ -514,39 +510,27 @@ bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
 /////////////////////////////////////////////////////////////////////
 // AMS (Velvet Studio) 2.0 - 2.02 loader
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // AMS2 File Header
-struct PACKED AMS2FileHeader
+struct AMS2FileHeader
 {
 	enum FileFlags
 	{
 		linearSlides	= 0x40,
 	};
 
-	uint8  versionLow;		// Version of format (Hi = MainVer, Low = SubVer e.g. 0202 = 2.02)
-	uint8  versionHigh;		// ditto
-	uint8  numIns;			// Nr of Instruments (0-255)
-	uint16 numPats;			// Nr of Patterns (1-1024)
-	uint16 numOrds;			// Nr of Positions (1-65535)
+	uint8le  versionLow;		// Version of format (Hi = MainVer, Low = SubVer e.g. 0202 = 2.02)
+	uint8le  versionHigh;		// ditto
+	uint8le  numIns;			// Nr of Instruments (0-255)
+	uint16le numPats;			// Nr of Patterns (1-1024)
+	uint16le numOrds;			// Nr of Positions (1-65535)
 	// Rest of header differs between format revision 2.01 and 2.02
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numPats);
-		SwapBytesLE(numOrds);
-	};
 };
 
-STATIC_ASSERT(sizeof(AMS2FileHeader) == 7);
+MPT_BINARY_STRUCT(AMS2FileHeader, 7)
 
 
 // AMS2 Instument Envelope
-struct PACKED AMS2Envelope
+struct AMS2Envelope
 {
 	uint8 speed;		// Envelope speed (currently not supported, always the same as current BPM)
 	uint8 sustainPoint;	// Envelope sustain point
@@ -586,11 +570,11 @@ struct PACKED AMS2Envelope
 	}
 };
 
-STATIC_ASSERT(sizeof(AMS2Envelope) == 5);
+MPT_BINARY_STRUCT(AMS2Envelope, 5)
 
 
 // AMS2 Instrument Data
-struct PACKED AMS2Instrument
+struct AMS2Instrument
 {
 	enum EnvelopeFlags
 	{
@@ -608,16 +592,9 @@ struct PACKED AMS2Instrument
 		fadeOutMask	= 0xFFF,
 	};
 
-	uint8  shadowInstr;		// Shadow Instrument. If non-zero, the value=the shadowed inst.
-	uint16 vibampFadeout;	// Vib.Amplify + Volume fadeout in one variable!
-	uint16 envFlags;		// See EnvelopeFlags
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(vibampFadeout);
-		SwapBytesLE(envFlags);
-	}
+	uint8le  shadowInstr;	// Shadow Instrument. If non-zero, the value=the shadowed inst.
+	uint16le vibampFadeout;	// Vib.Amplify + Volume fadeout in one variable!
+	uint16le envFlags;		// See EnvelopeFlags
 
 	void ApplyFlags(InstrumentEnvelope &mptEnv, EnvelopeFlags shift) const
 	{
@@ -638,11 +615,11 @@ struct PACKED AMS2Instrument
 
 };
 
-STATIC_ASSERT(sizeof(AMS2Instrument) == 5);
+MPT_BINARY_STRUCT(AMS2Instrument, 5)
 
 
 // AMS2 Sample Header
-struct PACKED AMS2SampleHeader
+struct AMS2SampleHeader
 {
 	enum SampleFlags
 	{
@@ -653,25 +630,15 @@ struct PACKED AMS2SampleHeader
 		smpReverse	= 0x40,
 	};
 
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint16 sampledRate;		// Whyyyy?
-	uint8  panFinetune;		// High nibble = pan position, low nibble = finetune value
-	uint16 c4speed;			// Why is all of this so redundant?
-	int8   relativeTone;	// q.e.d.
-	uint8  volume;			// 0...127
-	uint8  flags;			// See SampleFlags
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sampledRate);
-		SwapBytesLE(c4speed);
-	}
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint16le sampledRate;		// Whyyyy?
+	uint8le  panFinetune;		// High nibble = pan position, low nibble = finetune value
+	uint16le c4speed;			// Why is all of this so redundant?
+	int8le   relativeTone;		// q.e.d.
+	uint8le  volume;			// 0...127
+	uint8le  flags;			// See SampleFlags
 
 	// Convert sample header to OpenMPT's internal format.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -691,7 +658,7 @@ struct PACKED AMS2SampleHeader
 		uint32 newC4speed = ModSample::TransposeToFrequency(relativeTone, MOD2XMFineTune(panFinetune & 0x0F));
 		mptSmp.nC5Speed = (mptSmp.nC5Speed * newC4speed) / 8363;
 
-		mptSmp.nVolume = (std::min(uint8(127), volume) * 256 + 64) / 127;
+		mptSmp.nVolume = (std::min<uint8>(volume, 127) * 256 + 64) / 127;
 		if(panFinetune & 0xF0)
 		{
 			mptSmp.nPan = (panFinetune & 0xF0);
@@ -708,62 +675,109 @@ struct PACKED AMS2SampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(AMS2SampleHeader) == 20);
+MPT_BINARY_STRUCT(AMS2SampleHeader, 20)
 
 
 // AMS2 Song Description Header
-struct PACKED AMS2Description
+struct AMS2Description
 {
-	uint32 packedLen;		// Including header
-	uint32 unpackedLen;
-	uint8  packRoutine;		// 01
-	uint8  preProcessing;	// None!
-	uint8  packingMethod;	// RLE
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
+	uint32le packedLen;		// Including header
+	uint32le unpackedLen;
+	uint8le  packRoutine;	// 01
+	uint8le  preProcessing;	// None!
+	uint8le  packingMethod;	// RLE
+};
+
+MPT_BINARY_STRUCT(AMS2Description, 11)
+
+
+static bool ValidateHeader(const AMS2FileHeader &fileHeader)
+{
+	if(fileHeader.versionHigh != 2 || fileHeader.versionLow > 2)
 	{
-		SwapBytesLE(packedLen);
-		SwapBytesLE(unpackedLen);
+		return false;
 	}
-};
+	return true;
+}
+
 
-STATIC_ASSERT(sizeof(AMS2Description) == 11);
+static uint64 GetHeaderMinimumAdditionalSize(const AMS2FileHeader &fileHeader)
+{
+	return 36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize)
+{
+	if(!file.CanRead(7))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!file.ReadMagic("AMShdr\x1A"))
+	{
+		return ProbeFailure;
+	}
+	if(!file.CanRead(1))
+	{
+		return ProbeWantMoreData;
+	}
+	const uint8 songNameLength = file.ReadUint8();
+	if(!file.Skip(songNameLength))
+	{
+		return ProbeWantMoreData;
+	}
+	AMS2FileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
-//--------------------------------------------------------------------
 {
 	file.Rewind();
 
-	AMS2FileHeader fileHeader;
 	if(!file.ReadMagic("AMShdr\x1A"))
 	{
 		return false;
 	}
-
-	InitializeGlobals(MOD_TYPE_AMS2);
-
-	if(!ReadAMSString(m_songName, file)
-		|| !file.ReadConvertEndianness(fileHeader)
-		|| fileHeader.versionHigh != 2 || fileHeader.versionLow > 2
-		|| !file.CanRead(36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u))
+	std::string songName;
+	if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(songName))
+	{
+		return false;
+	}
+	AMS2FileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 	
+	InitializeGlobals(MOD_TYPE_AMS2);
+	
+	m_songName = songName;
+
 	m_nInstruments = fileHeader.numIns;
 	m_nChannels = 32;
 	SetupMODPanning(true);
-	m_madeWithTracker = mpt::String::Print("Velvet Studio %1.%2", fileHeader.versionHigh, mpt::fmt::dec0<2>(fileHeader.versionLow));
+	m_madeWithTracker = mpt::format(MPT_USTRING("Velvet Studio %1.%2"))(fileHeader.versionHigh.get(), mpt::ufmt::dec0<2>(fileHeader.versionLow.get()));
 
 	uint16 headerFlags;
 	if(fileHeader.versionLow >= 2)
@@ -798,7 +812,7 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		ModInstrument *instrument = AllocateInstrument(ins);
 		if(instrument == nullptr
-			|| !ReadAMSString(instrument->name, file))
+			|| !file.ReadSizedString<uint8le, mpt::String::spacePadded>(instrument->name))
 		{
 			break;
 		}
@@ -826,7 +840,7 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 		vibratoEnv.ConvertToMPT(instrument->PitchEnv, file);
 
 		AMS2Instrument instrHeader;
-		file.ReadConvertEndianness(instrHeader);
+		file.ReadStruct(instrHeader);
 		instrument->nFadeOut = (instrHeader.vibampFadeout & AMS2Instrument::fadeOutMask);
 		const int16 vibAmp = 1 << ((instrHeader.vibampFadeout & AMS2Instrument::vibAmpMask) >> AMS2Instrument::vibAmpShift);
 
@@ -835,21 +849,21 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 		instrHeader.ApplyFlags(instrument->PitchEnv, AMS2Instrument::vibEnvShift);
 
 		// Scale envelopes to correct range
-		for(InstrumentEnvelope::iterator it = instrument->VolEnv.begin(); it != instrument->VolEnv.end(); it++)
+		for(auto &p : instrument->VolEnv)
 		{
-			it->value = std::min(uint8(ENVELOPE_MAX), static_cast<uint8>((it->value * ENVELOPE_MAX + 64u) / 127u));
+			p.value = std::min(uint8(ENVELOPE_MAX), static_cast<uint8>((p.value * ENVELOPE_MAX + 64u) / 127u));
 		}
-		for(InstrumentEnvelope::iterator it = instrument->PanEnv.begin(); it != instrument->PanEnv.end(); it++)
+		for(auto &p : instrument->PanEnv)
 		{
-			it->value = std::min(uint8(ENVELOPE_MAX), static_cast<uint8>((it->value * ENVELOPE_MAX + 128u) / 255u));
+			p.value = std::min(uint8(ENVELOPE_MAX), static_cast<uint8>((p.value * ENVELOPE_MAX + 128u) / 255u));
 		}
-		for(InstrumentEnvelope::iterator it = instrument->PitchEnv.begin(); it != instrument->PitchEnv.end(); it++)
+		for(auto &p : instrument->PitchEnv)
 		{
 #ifdef MODPLUG_TRACKER
-			it->value = std::min(uint8(ENVELOPE_MAX), static_cast<uint8>(32 + Util::muldivrfloor(static_cast<int8>(it->value - 128), vibAmp, 255)));
+			p.value = std::min(uint8(ENVELOPE_MAX), static_cast<uint8>(32 + Util::muldivrfloor(static_cast<int8>(p.value - 128), vibAmp, 255)));
 #else
 			// Try to keep as much precision as possible... divide by 8 since that's the highest possible vibAmp factor.
-			it->value = static_cast<uint8>(128 + Util::muldivrfloor(static_cast<int8>(it->value - 128), vibAmp, 8));
+			p.value = static_cast<uint8>(128 + Util::muldivrfloor(static_cast<int8>(p.value - 128), vibAmp, 8));
 #endif
 		}
 
@@ -863,10 +877,10 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 				file.Skip(sizeof(AMS2SampleHeader));
 				break;
 			}
-			ReadAMSString(m_szNames[firstSmp + smp], file);
+			file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_szNames[firstSmp + smp]);
 
 			AMS2SampleHeader sampleHeader;
-			file.ReadConvertEndianness(sampleHeader);
+			file.ReadStruct(sampleHeader);
 			sampleHeader.ConvertToMPT(Samples[firstSmp + smp]);
 
 			uint16 settings = (instrHeader.shadowInstr & instrIndexMask)
@@ -894,12 +908,12 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 	for(CHANNELINDEX chn = 0; chn < 32; chn++)
 	{
 		ChnSettings[chn].Reset();
-		ReadAMSString(ChnSettings[chn].szName, file);
+		file.ReadSizedString<uint8le, mpt::String::spacePadded>(ChnSettings[chn].szName);
 	}
 
 	// RLE-Packed description text
 	AMS2Description descriptionHeader;
-	if(!file.ReadConvertEndianness(descriptionHeader))
+	if(!file.ReadStruct(descriptionHeader))
 	{
 		return true;
 	}
@@ -931,17 +945,11 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Read Order List
-	std::vector<uint16> orders;
-	if(file.ReadVectorLE(orders, fileHeader.numOrds))
-	{
-		Order.resize(fileHeader.numOrds);
-		for(ORDERINDEX i = 0; i < Order.size(); i++)
-		{
-			Order[i] = orders[i];
-		}
-	}
+	ReadOrderFromFile<uint16le>(Order(), file, fileHeader.numOrds);
 
 	// Read Patterns
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.numPats);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPats; pat++)
 	{
 		uint32 patLength = file.ReadUint32LE();
@@ -959,7 +967,7 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 			}
 
 			char patternName[11];
-			ReadAMSString(patternName, patternChunk);
+			patternChunk.ReadSizedString<uint8le, mpt::String::spacePadded>(patternName);
 			Patterns[pat].SetName(patternName);
 
 			ReadAMSPattern(Patterns[pat], true, patternChunk);
@@ -1021,7 +1029,6 @@ bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
 // AMS Sample unpacking
 
 void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest, const size_t destSize, char packCharacter)
-//------------------------------------------------------------------------------------------------------------------------
 {
 	std::vector<int8> tempBuf(destSize, 0);
 	size_t depackSize = destSize;
@@ -1029,7 +1036,7 @@ void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest,
 	// Unpack Loop
 	{
 		const int8 *in = source;
-		int8 *out = &tempBuf[0];
+		int8 *out = tempBuf.data();
 
 		size_t i = sourceSize, j = destSize;
 		while(i != 0 && j != 0)
@@ -1065,7 +1072,7 @@ void AMSUnpack(const int8 * const source, size_t sourceSize, void * const dest,
 
 	// Bit Unpack Loop
 	{
-		int8 *out = &tempBuf[0];
+		int8 *out = tempBuf.data();
 		uint16 bitcount = 0x80;
 		size_t k = 0;
 		uint8 *dst = static_cast<uint8 *>(dest);
diff --git a/soundlib/Load_dbm.cpp b/soundlib/Load_dbm.cpp
index c468a09..890a8eb 100644
--- a/soundlib/Load_dbm.cpp
+++ b/soundlib/Load_dbm.cpp
@@ -22,11 +22,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED DBMFileHeader
+struct DBMFileHeader
 {
 	char  dbm0[4];
 	uint8 trkVerHi;
@@ -34,69 +30,59 @@ struct PACKED DBMFileHeader
 	char  reserved[2];
 };
 
+MPT_BINARY_STRUCT(DBMFileHeader, 8)
 
-// RIFF-style Chunk
-struct PACKED DBMChunk
+
+// IFF-style Chunk
+struct DBMChunk
 {
 	// 32-Bit chunk identifiers
 	enum ChunkIdentifiers
 	{
-		idNAME	= 0x454D414E,
-		idINFO	= 0x4F464E49,
-		idSONG	= 0x474E4F53,
-		idINST	= 0x54534E49,
-		idVENV	= 0x564E4556,
-		idPENV	= 0x564E4550,
-		idPATT	= 0x54544150,
-		idPNAM	= 0x4D414E50,
-		idSMPL	= 0x4C504D53,
-		idDSPE	= 0x45505344,
-		idMPEG	= 0x4745504D,
+		idNAME	= MAGIC4BE('N','A','M','E'),
+		idINFO	= MAGIC4BE('I','N','F','O'),
+		idSONG	= MAGIC4BE('S','O','N','G'),
+		idINST	= MAGIC4BE('I','N','S','T'),
+		idVENV	= MAGIC4BE('V','E','N','V'),
+		idPENV	= MAGIC4BE('P','E','N','V'),
+		idPATT	= MAGIC4BE('P','A','T','T'),
+		idPNAM	= MAGIC4BE('P','N','A','M'),
+		idSMPL	= MAGIC4BE('S','M','P','L'),
+		idDSPE	= MAGIC4BE('D','S','P','E'),
+		idMPEG	= MAGIC4BE('M','P','E','G'),
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint32 id;
-	uint32 length;
+	uint32be id;
+	uint32be length;
 
 	size_t GetLength() const
 	{
-		return SwapBytesReturnBE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(DBMChunk) == 8);
+MPT_BINARY_STRUCT(DBMChunk, 8)
 
 
-struct PACKED DBMInfoChunk
+struct DBMInfoChunk
 {
-	uint16 instruments;
-	uint16 samples;
-	uint16 songs;
-	uint16 patterns;
-	uint16 channels;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(instruments);
-		SwapBytesBE(samples);
-		SwapBytesBE(songs);
-		SwapBytesBE(patterns);
-		SwapBytesBE(channels);
-	}
+	uint16be instruments;
+	uint16be samples;
+	uint16be songs;
+	uint16be patterns;
+	uint16be channels;
 };
 
-STATIC_ASSERT(sizeof(DBMInfoChunk) == 10);
+MPT_BINARY_STRUCT(DBMInfoChunk, 10)
 
 
 // Instrument header
-struct PACKED DBMInstrument
+struct DBMInstrument
 {
 	enum DBMInstrFlags
 	{
@@ -104,33 +90,21 @@ struct PACKED DBMInstrument
 		smpPingPongLoop	= 0x02,
 	};
 
-	char   name[30];
-	uint16 sample;		// Sample reference
-	uint16 volume;		// 0...64
-	uint32 sampleRate;
-	uint32 loopStart;
-	uint32 loopLength;
-	int16  panning;		// -128...128
-	uint16 flags;		// See DBMInstrFlags
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(sample);
-		SwapBytesBE(volume);
-		SwapBytesBE(sampleRate);
-		SwapBytesBE(loopStart);
-		SwapBytesBE(loopLength);
-		SwapBytesBE(panning);
-		SwapBytesBE(flags);
-	}
+	char     name[30];
+	uint16be sample;		// Sample reference
+	uint16be volume;		// 0...64
+	uint32be sampleRate;
+	uint32be loopStart;
+	uint32be loopLength;
+	int16be  panning;		// -128...128
+	uint16be flags;			// See DBMInstrFlags
 };
 
-STATIC_ASSERT(sizeof(DBMInstrument) == 50);
+MPT_BINARY_STRUCT(DBMInstrument, 50)
 
 
 // Volume or panning envelope
-struct PACKED DBMEnvelope
+struct DBMEnvelope
 {
 	enum DBMEnvelopeFlags
 	{
@@ -139,32 +113,17 @@ struct PACKED DBMEnvelope
 		envLoop		= 0x04,
 	};
 
-	uint16 instrument;
-	uint8  flags;		// See DBMEnvelopeFlags
-	uint8  numSegments;	// Number of envelope points - 1
-	uint8  sustain1;
-	uint8  loopBegin;
-	uint8  loopEnd;
-	uint8  sustain2;	// Second sustain point
-	uint16 data[2 * 32];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(instrument);
-		for(size_t i = 0; i < CountOf(data); i++)
-		{
-			SwapBytesBE(data[i]);
-		}
-	}
+	uint16be instrument;
+	uint8be  flags;			// See DBMEnvelopeFlags
+	uint8be  numSegments;	// Number of envelope points - 1
+	uint8be  sustain1;
+	uint8be  loopBegin;
+	uint8be  loopEnd;
+	uint8be  sustain2;		// Second sustain point
+	uint16be data[2 * 32];
 };
 
-STATIC_ASSERT(sizeof(DBMEnvelope) == 136);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(DBMEnvelope, 136)
 
 
 // Note: Unlike in MOD, 1Fx, 2Fx, 5Fx / 5xF, 6Fx / 6xF and AFx / AxF are fine slides.
@@ -189,7 +148,6 @@ static const ModCommand::COMMAND dbmEffects[] =
 
 
 static void ConvertDBMEffect(uint8 &command, uint8 &param)
-//--------------------------------------------------------
 {
 	uint8 oldCmd = command;
 	if(command < CountOf(dbmEffects))
@@ -197,13 +155,29 @@ static void ConvertDBMEffect(uint8 &command, uint8 &param)
 	else
 		command = CMD_NONE;
 
-	switch (command)
+	switch(command)
 	{
 	case CMD_ARPEGGIO:
 		if(param == 0)
 			command = CMD_NONE;
 		break;
 
+#ifdef MODPLUG_TRACKER
+	case CMD_VIBRATO:
+		if(param & 0x0F)
+		{
+			// DBM vibrato is half as deep as most other trackers. Convert it to IT fine vibrato range if possible.
+			uint8 depth = (param & 0x0F) * 2u;
+			param &= 0xF0;
+			if(depth < 16)
+				command = CMD_FINEVIBRATO;
+			else
+				depth = (depth + 2u) / 4u;
+			param |= depth;
+		}
+		break;
+#endif
+
 	// Volume slide nibble priority - first nibble (slide up) has precedence.
 	case CMD_VOLUMESLIDE:
 	case CMD_TONEPORTAVOL:
@@ -273,17 +247,17 @@ static void ConvertDBMEffect(uint8 &command, uint8 &param)
 
 // Read a chunk of volume or panning envelopes
 static void ReadDBMEnvelopeChunk(FileReader chunk, EnvelopeType envType, CSoundFile &sndFile, bool scaleEnv)
-//----------------------------------------------------------------------------------------------------------
 {
 	uint16 numEnvs = chunk.ReadUint16BE();
 	for(uint16 env = 0; env < numEnvs; env++)
 	{
 		DBMEnvelope dbmEnv;
-		chunk.ReadConvertEndianness(dbmEnv);
+		chunk.ReadStruct(dbmEnv);
 
-		ModInstrument *mptIns;
-		if(dbmEnv.instrument && dbmEnv.instrument < MAX_INSTRUMENTS && (mptIns = sndFile.Instruments[dbmEnv.instrument]) != nullptr)
+		uint16 dbmIns = dbmEnv.instrument;
+		if(dbmIns > 0 && dbmIns <= sndFile.GetNumInstruments() && (sndFile.Instruments[dbmIns] != nullptr))
 		{
+			ModInstrument *mptIns = sndFile.Instruments[dbmIns];
 			InstrumentEnvelope &mptEnv = mptIns->GetEnvelope(envType);
 
 			if(dbmEnv.numSegments)
@@ -293,13 +267,14 @@ static void ReadDBMEnvelopeChunk(FileReader chunk, EnvelopeType envType, CSoundF
 				if(dbmEnv.flags & DBMEnvelope::envLoop) mptEnv.dwFlags.set(ENV_LOOP);
 			}
 
-			mptEnv.resize(std::min<uint32>(dbmEnv.numSegments + 1, 32));
+			uint8 numPoints = std::min<uint8>(dbmEnv.numSegments, 31) + 1;
+			mptEnv.resize(numPoints);
 
 			mptEnv.nLoopStart = dbmEnv.loopBegin;
 			mptEnv.nLoopEnd = dbmEnv.loopEnd;
 			mptEnv.nSustainStart = mptEnv.nSustainEnd = dbmEnv.sustain1;
 
-			for(uint32 i = 0; i < mptEnv.size(); i++)
+			for(uint8 i = 0; i < numPoints; i++)
 			{
 				mptEnv[i].tick = dbmEnv.data[i * 2];
 				uint16 val = dbmEnv.data[i * 2 + 1];
@@ -316,29 +291,57 @@ static void ReadDBMEnvelopeChunk(FileReader chunk, EnvelopeType envType, CSoundF
 }
 
 
-bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const DBMFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.dbm0, "DBM0", 4)
+		|| fileHeader.trkVerHi > 3)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize)
 {
 	DBMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
+{
 
 	file.Rewind();
-	if(!file.ReadStruct(fileHeader)
-		|| memcmp(fileHeader.dbm0, "DBM0", 4)
-		|| fileHeader.trkVerHi > 3)
+	DBMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
 	ChunkReader chunkFile(file);
-	ChunkReader::ChunkList<DBMChunk> chunks = chunkFile.ReadChunks<DBMChunk>(1);
+	auto chunks = chunkFile.ReadChunks<DBMChunk>(1);
 
 	// Globals
-	FileReader infoChunk = chunks.GetChunk(DBMChunk::idINFO);
 	DBMInfoChunk infoData;
-	if(!infoChunk.ReadConvertEndianness(infoData))
+	if(!chunks.GetChunk(DBMChunk::idINFO).ReadStruct(infoData))
 	{
 		return false;
 	}
@@ -346,11 +349,12 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 	InitializeGlobals(MOD_TYPE_DBM);
 	InitializeChannels();
 	m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS;
-	m_nChannels = Clamp(infoData.channels, uint16(1), uint16(MAX_BASECHANNELS));	// note: MAX_BASECHANNELS is currently 127, but DBPro 2 supports up to 128 channels, DBPro 3 apparently up to 254.
+	m_nChannels = Clamp<uint16, uint16>(infoData.channels, 1, MAX_BASECHANNELS);	// note: MAX_BASECHANNELS is currently 127, but DBPro 2 supports up to 128 channels, DBPro 3 apparently up to 254.
 	m_nInstruments = std::min<INSTRUMENTINDEX>(infoData.instruments, MAX_INSTRUMENTS - 1);
 	m_nSamples = std::min<SAMPLEINDEX>(infoData.samples, MAX_SAMPLES - 1);
-	m_madeWithTracker = mpt::String::Print("DigiBooster Pro %1.%2", mpt::fmt::hex(fileHeader.trkVerHi), mpt::fmt::hex(fileHeader.trkVerLo));
+	m_madeWithTracker = mpt::format(MPT_USTRING("DigiBooster Pro %1.%2"))(mpt::ufmt::hex(fileHeader.trkVerHi), mpt::ufmt::hex(fileHeader.trkVerLo));
 	m_playBehaviour.set(kSlidesAtSpeed1);
+	m_playBehaviour.reset(kITVibratoTremoloPanbrello);
 
 	// Name chunk
 	FileReader nameChunk = chunks.GetChunk(DBMChunk::idNAME);
@@ -358,8 +362,9 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 
 	// Song chunk
 	FileReader songChunk = chunks.GetChunk(DBMChunk::idSONG);
-	Order.clear();
-	for(size_t i = 0; i < infoData.songs; i++)
+	Order().clear();
+	uint16 numSongs = infoData.songs;
+	for(uint16 i = 0; i < numSongs && songChunk.CanRead(46); i++)
 	{
 		char name[44];
 		songChunk.ReadString<mpt::String::maybeNullTerminated>(name, 44);
@@ -367,37 +372,41 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 		{
 			m_songName = name;
 		}
-#ifdef MPT_DBM_USE_REAL_SUBSONGS
-		if(i > 0) Order.AddSequence(false);
-		Order.clear();
-		Order.SetName(name);
-#endif // MPT_DBM_USE_REAL_SUBSONGS
-
 		uint16 numOrders = songChunk.ReadUint16BE();
-		const ORDERINDEX startIndex = Order.GetLength();
-		if(startIndex < ORDERINDEX_MAX && songChunk.CanRead(2))
-		{
-			LimitMax(numOrders, static_cast<ORDERINDEX>(ORDERINDEX_MAX - startIndex - 1));
-			Order.resize(startIndex + numOrders + 1, Order.GetInvalidPatIndex());
 
+#ifdef MPT_DBM_USE_REAL_SUBSONGS
+		if(!Order().empty())
+		{
+			// Add a new sequence for this song
+			if(Order.AddSequence(false) == SEQUENCEINDEX_INVALID)
+				break;
+		}
+		Order().SetName(name);
+		ReadOrderFromFile<uint16be>(Order(), songChunk, numOrders);
+#else
+		const ORDERINDEX startIndex = Order().GetLength();
+		if(startIndex < MAX_ORDERS && songChunk.CanRead(numOrders * 2u))
+		{
+			LimitMax(numOrders, static_cast<ORDERINDEX>(MAX_ORDERS - startIndex - 1));
+			Order().resize(startIndex + numOrders + 1);
 			for(uint16 ord = 0; ord < numOrders; ord++)
 			{
-				Order[startIndex + ord] = static_cast<PATTERNINDEX>(songChunk.ReadUint16BE());
+				Order()[startIndex + ord] = static_cast<PATTERNINDEX>(songChunk.ReadUint16BE());
 			}
 		}
+#endif // MPT_DBM_USE_REAL_SUBSONGS
 	}
 #ifdef MPT_DBM_USE_REAL_SUBSONGS
 	Order.SetSequence(0);
 #endif // MPT_DBM_USE_REAL_SUBSONGS
 
 	// Read instruments
-	FileReader instChunk = chunks.GetChunk(DBMChunk::idINST);
-	if(instChunk.IsValid())
+	if(FileReader instChunk = chunks.GetChunk(DBMChunk::idINST))
 	{
 		for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
 		{
 			DBMInstrument instrHeader;
-			instChunk.ReadConvertEndianness(instrHeader);
+			instChunk.ReadStruct(instrHeader);
 
 			ModInstrument *mptIns = AllocateInstrument(i, instrHeader.sample);
 			if(mptIns == nullptr || instrHeader.sample >= MAX_SAMPLES)
@@ -416,7 +425,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 
 			// Sample Info
 			mptSmp.Initialize();
-			mptSmp.nVolume = std::min(instrHeader.volume, uint16(64)) * 4u;
+			mptSmp.nVolume = std::min<uint16>(instrHeader.volume, 64) * 4u;
 			mptSmp.nC5Speed = instrHeader.sampleRate;
 
 			if(instrHeader.loopLength && (instrHeader.flags & (DBMInstrument::smpLoop | DBMInstrument::smpPingPongLoop)))
@@ -427,18 +436,18 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 				if(instrHeader.flags & DBMInstrument::smpPingPongLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP);
 			}
 		}
-	}
 
-	// Read envelopes
-	ReadDBMEnvelopeChunk(chunks.GetChunk(DBMChunk::idVENV), ENV_VOLUME, *this, false);
-	ReadDBMEnvelopeChunk(chunks.GetChunk(DBMChunk::idPENV), ENV_PANNING, *this, fileHeader.trkVerHi > 2);
+		// Read envelopes
+		ReadDBMEnvelopeChunk(chunks.GetChunk(DBMChunk::idVENV), ENV_VOLUME, *this, false);
+		ReadDBMEnvelopeChunk(chunks.GetChunk(DBMChunk::idPENV), ENV_PANNING, *this, fileHeader.trkVerHi > 2);
 
-	// Note-Off cuts samples if there's no envelope.
-	for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
-	{
-		if(Instruments[i] != nullptr && !Instruments[i]->VolEnv.dwFlags[ENV_ENABLED])
+		// Note-Off cuts samples if there's no envelope.
+		for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
 		{
-			Instruments[i]->nFadeOut = 32767;
+			if(Instruments[i] != nullptr && !Instruments[i]->VolEnv.dwFlags[ENV_ENABLED])
+			{
+				Instruments[i]->nFadeOut = 32767;
+			}
 		}
 	}
 
@@ -452,6 +461,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 		FileReader patternNameChunk = chunks.GetChunk(DBMChunk::idPNAM);
 		patternNameChunk.Skip(1);	// Encoding, should be UTF-8 or ASCII
 
+		Patterns.ResizeArray(infoData.patterns);
 		for(PATTERNINDEX pat = 0; pat < infoData.patterns; pat++)
 		{
 			uint16 numRows = patternChunk.ReadUint16BE();
@@ -464,18 +474,21 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 			}
 
 			std::string patName;
-			patternNameChunk.ReadString<mpt::String::maybeNullTerminated>(patName, patternNameChunk.ReadUint8());
+			patternNameChunk.ReadSizedString<uint8be, mpt::String::maybeNullTerminated>(patName);
 			Patterns[pat].SetName(patName);
 
 			PatternRow patRow = Patterns[pat].GetRow(0);
 			ROWINDEX row = 0;
-			while(chunk.CanRead(1) && row < numRows)
+			while(chunk.CanRead(1))
 			{
 				const uint8 ch = chunk.ReadUint8();
 
 				if(!ch)
 				{
-					row++;
+					// End Of Row
+					if(++row >= numRows)
+						break;
+
 					patRow = Patterns[pat].GetRow(row);
 					continue;
 				}
@@ -556,8 +569,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 		// DBP 3 Documentation says that the defaults are 64/128/128/255, but they appear to be 80/150/80/255 in DBP 2.21
 		uint8 settings[8] = { 0, 80, 0, 150, 0, 80, 0, 255 };
 
-		FileReader dspChunk = chunks.GetChunk(DBMChunk::idDSPE);
-		if(dspChunk.IsValid())
+		if(FileReader dspChunk = chunks.GetChunk(DBMChunk::idDSPE))
 		{
 			uint16 maskLen = dspChunk.ReadUint16BE();
 			for(uint16 i = 0; i < maskLen; i++)
@@ -592,16 +604,12 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 			plugin.Info.gain = 10;
 			plugin.Info.reserved = 0;
 			plugin.Info.dwOutputRouting = 0;
-			std::fill(plugin.Info.dwReserved, plugin.Info.dwReserved + CountOf(plugin.Info.dwReserved), 0);
+			std::fill(plugin.Info.dwReserved, plugin.Info.dwReserved + mpt::size(plugin.Info.dwReserved), 0);
 			mpt::String::Write<mpt::String::nullTerminated>(plugin.Info.szName, "Echo");
 			mpt::String::Write<mpt::String::nullTerminated>(plugin.Info.szLibraryName, "DigiBooster Pro Echo");
 
-			plugin.nPluginDataSize = sizeof(DigiBoosterEcho::PluginChunk);
-			plugin.pPluginData = new (std::nothrow) char[sizeof(DigiBoosterEcho::PluginChunk)];
-			if(plugin.pPluginData != nullptr)
-			{
-				new (plugin.pPluginData) DigiBoosterEcho::PluginChunk(settings[1], settings[3], settings[5], settings[7]);
-			}
+			plugin.pluginData.resize(sizeof(DigiBoosterEcho::PluginChunk));
+			new (plugin.pluginData.data()) DigiBoosterEcho::PluginChunk(settings[1], settings[3], settings[5], settings[7]);
 		}
 	}
 
@@ -660,20 +668,24 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
 		{
 			ModSample &srcSample = Samples[0];
 			const int8 *smpData = srcSample.pSample8;
+			uint32 predelay = Util::muldiv_unsigned(20116, srcSample.nC5Speed, 100000);
+			smpData += predelay * srcSample.GetBytesPerSample();
+			srcSample.nLength -= predelay;
 
 			for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
 			{
 				ModSample &sample = Samples[smp];
 				sample.uFlags.set(srcSample.uFlags);
-				sample.nLength *= 2;
 				LimitMax(sample.nLength, srcSample.nLength);
 				if(sample.nLength)
 				{
 					sample.AllocateSample();
 					memcpy(sample.pSample, smpData, sample.GetSampleSizeInBytes());
-					CSoundFile::AdjustSampleLoop(sample);
 					smpData += sample.GetSampleSizeInBytes();
 					srcSample.nLength -= sample.nLength;
+					uint32 gap = Util::muldiv_unsigned(454, srcSample.nC5Speed, 10000);
+					smpData += gap * srcSample.GetBytesPerSample();
+					srcSample.nLength -= gap;
 				}
 			}
 			srcSample.FreeSample();
diff --git a/soundlib/Load_digi.cpp b/soundlib/Load_digi.cpp
index cd3c5c5..90c91d9 100644
--- a/soundlib/Load_digi.cpp
+++ b/soundlib/Load_digi.cpp
@@ -13,49 +13,29 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // DIGI File Header
-struct PACKED DIGIFileHeader
+struct DIGIFileHeader
 {
-	char   signature[20];
-	char   versionStr[4];	// Supposed to be "V1.6" or similar, but other values like "TAP!" have been found as well.
-	uint8  versionInt;		// e.g. 0x16 = 1.6
-	uint8  numChannels;
-	uint8  packEnable;
-	char   unknown[19];
-	uint8  lastPatIndex;
-	uint8  lastOrdIndex;
-	uint8  orders[128];
-	uint32 smpLength[31];
-	uint32 smpLoopStart[31];
-	uint32 smpLoopLength[31];
-	uint8  smpVolume[31];
-	uint8  smpFinetune[31];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(SAMPLEINDEX i = 0; i < 31; i++)
-		{
-			SwapBytesBE(smpLength[i]);
-			SwapBytesBE(smpLoopStart[i]);
-			SwapBytesBE(smpLoopLength[i]);
-		}
-	}
+	char     signature[20];
+	char     versionStr[4];	// Supposed to be "V1.6" or similar, but other values like "TAP!" have been found as well.
+	uint8be  versionInt;	// e.g. 0x16 = 1.6
+	uint8be  numChannels;
+	uint8be  packEnable;
+	char     unknown[19];
+	uint8be  lastPatIndex;
+	uint8be  lastOrdIndex;
+	uint8be  orders[128];
+	uint32be smpLength[31];
+	uint32be smpLoopStart[31];
+	uint32be smpLoopLength[31];
+	uint8be  smpVolume[31];
+	uint8be  smpFinetune[31];
 };
 
-STATIC_ASSERT(sizeof(DIGIFileHeader) == 610);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(DIGIFileHeader, 610)
 
 
 static void ReadDIGIPatternEntry(FileReader &file, ModCommand &m)
-//---------------------------------------------------------------
 {
 	CSoundFile::ReadMODPatternEntry(file, m);
 	CSoundFile::ConvertModCommand(m);
@@ -92,20 +72,49 @@ static void ReadDIGIPatternEntry(FileReader &file, ModCommand &m)
 }
 
 
+static bool ValidateHeader(const DIGIFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
+		|| !fileHeader.numChannels
+		|| fileHeader.numChannels > 8
+		|| fileHeader.lastOrdIndex > 127)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize)
+{
+	DIGIFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
-//--------------------------------------------------------------------
 {
 	file.Rewind();
 
 	DIGIFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
-		|| !fileHeader.numChannels
-		|| fileHeader.numChannels > 8
-		|| fileHeader.lastOrdIndex > 127)
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -117,9 +126,9 @@ bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
 	m_nChannels = fileHeader.numChannels;
 	m_nSamples = 31;
 	m_nSamplePreAmp = 256 / m_nChannels;
-	m_madeWithTracker = mpt::String::Print("Digi Booster %1.%2", fileHeader.versionInt >> 4, fileHeader.versionInt & 0x0F);
+	m_madeWithTracker = mpt::format(MPT_USTRING("Digi Booster %1.%2"))(fileHeader.versionInt >> 4, fileHeader.versionInt & 0x0F);
 
-	Order.ReadFromArray(fileHeader.orders, fileHeader.lastOrdIndex + 1);
+	ReadOrderFromArray(Order(), fileHeader.orders, fileHeader.lastOrdIndex + 1);
 
 	// Read sample headers
 	for(SAMPLEINDEX smp = 0; smp < 31; smp++)
@@ -135,7 +144,7 @@ bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
 		}
 		sample.SanitizeLoops();
 	
-		sample.nVolume = std::min(fileHeader.smpVolume[smp], uint8(64)) * 4;
+		sample.nVolume = std::min<uint8>(fileHeader.smpVolume[smp], 64) * 4;
 		sample.nFineTune = MOD2XMFineTune(fileHeader.smpFinetune[smp]);
 	}
 
@@ -146,6 +155,9 @@ bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
 		file.ReadString<mpt::String::maybeNullTerminated>(m_szNames[smp], 30);
 	}
 
+
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.lastPatIndex + 1);
 	for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPatIndex; pat++)
 	{
 		FileReader patternChunk;
@@ -164,8 +176,8 @@ bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
 
 		if(fileHeader.packEnable)
 		{
-			std::vector<uint8> eventMask;
-			patternChunk.ReadVector(eventMask, 64);
+			uint8 eventMask[64];
+			patternChunk.ReadArray(eventMask);
 
 			// Compressed patterns are stored in row-major order...
 			for(ROWINDEX row = 0; row < 64; row++)
diff --git a/soundlib/Load_dmf.cpp b/soundlib/Load_dmf.cpp
index bc0c94a..c585e3e 100644
--- a/soundlib/Load_dmf.cpp
+++ b/soundlib/Load_dmf.cpp
@@ -20,12 +20,8 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // DMF header
-struct PACKED DMFFileHeader
+struct DMFFileHeader
 {
 	char   signature[4];	// "DDMF"
 	uint8  version;			// 1 - 7 are beta versions, 8 is the official thing, 10 is xtracker32
@@ -37,9 +33,9 @@ struct PACKED DMFFileHeader
 	uint8  creationYear;
 };
 
-STATIC_ASSERT(sizeof(DMFFileHeader) == 66);
+MPT_BINARY_STRUCT(DMFFileHeader, 66)
 
-struct PACKED DMFChunk
+struct DMFChunk
 {
 	// 32-Bit chunk identifiers
 	enum ChunkIdentifiers
@@ -54,77 +50,55 @@ struct PACKED DMFChunk
 		idSETT	= MAGIC4LE('S','E','T','T'),	// Probably contains GUI settings
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint32 id;
-	uint32 length;
+	uint32le id;
+	uint32le length;
 
 	size_t GetLength() const
 	{
-		return SwapBytesReturnLE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(DMFChunk) == 8);
+MPT_BINARY_STRUCT(DMFChunk, 8)
 
 // Order list
-struct PACKED DMFSequence
+struct DMFSequence
 {
-	uint16 loopStart;
-	uint16 loopEnd;
+	uint16le loopStart;
+	uint16le loopEnd;
 	// order list follows here ...
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-	}
 };
 
-STATIC_ASSERT(sizeof(DMFSequence) == 4);
+MPT_BINARY_STRUCT(DMFSequence, 4)
 
 // Pattern header (global)
-struct PACKED DMFPatterns
+struct DMFPatterns
 {
-	uint16 numPatterns;	// 1..1024 patterns
-	uint8  numTracks;	// 1..32 channels
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numPatterns);
-	}
+	uint16le numPatterns;	// 1..1024 patterns
+	uint8le  numTracks;		// 1..32 channels
 };
 
-STATIC_ASSERT(sizeof(DMFPatterns) == 3);
+MPT_BINARY_STRUCT(DMFPatterns, 3)
 
 // Pattern header (for each pattern)
-struct PACKED DMFPatternHeader
+struct DMFPatternHeader
 {
-	uint8  numTracks;	// 1..32 channels
-	uint8  beat;		// [hi|lo] -> hi = rows per beat, lo = reserved
-	uint16 numRows;
-	uint32 patternLength;
+	uint8le  numTracks;	// 1..32 channels
+	uint8le  beat;		// [hi|lo] -> hi = rows per beat, lo = reserved
+	uint16le numRows;
+	uint32le patternLength;
 	// patttern data follows here ...
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numRows);
-		SwapBytesLE(patternLength);
-	}
 };
 
-STATIC_ASSERT(sizeof(DMFPatternHeader) == 8);
+MPT_BINARY_STRUCT(DMFPatternHeader, 8)
 
 // Sample header
-struct PACKED DMFSampleHeader
+struct DMFSampleHeader
 {
 	enum SampleFlags
 	{
@@ -138,12 +112,12 @@ struct PACKED DMFSampleHeader
 		smpLibrary	= 0x80,	// Sample is stored in a library
 	};
 
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint16 c3freq;		// 1000..45000hz
-	uint8  volume;		// 0 = ignore
-	uint8  flags;
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint16le c3freq;		// 1000..45000hz
+	uint8le  volume;		// 0 = ignore
+	uint8le  flags;
 
 	// Convert an DMFSampleHeader to OpenMPT's internal sample representation.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -159,6 +133,7 @@ struct PACKED DMFSampleHeader
 			mptSmp.nVolume = volume + 1;
 		else
 			mptSmp.nVolume = 256;
+		mptSmp.uFlags.set(SMP_NODEFAULTVOLUME, volume == 0);
 
 		if((flags & smpLoop) != 0 && mptSmp.nSustainEnd > mptSmp.nSustainStart)
 		{
@@ -172,31 +147,19 @@ struct PACKED DMFSampleHeader
 			mptSmp.nSustainEnd /= 2;
 		}
 	}
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(c3freq);
-	}
 };
 
-STATIC_ASSERT(sizeof(DMFSampleHeader) == 16);
+MPT_BINARY_STRUCT(DMFSampleHeader, 16)
 
 // Sample header tail (between head and tail, there might be the library name of the sample, depending on the DMF version)
-struct PACKED DMFSampleHeaderTail
+struct DMFSampleHeaderTail
 {
-	uint16 filler;
-	uint32 crc32;
+	uint16le filler;
+	uint32le crc32;
 };
 
-STATIC_ASSERT(sizeof(DMFSampleHeaderTail) == 6);
+MPT_BINARY_STRUCT(DMFSampleHeaderTail, 6)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
 // Pattern translation memory
 struct DMFPatternSettings
@@ -220,7 +183,7 @@ struct DMFPatternSettings
 		}
 	};
 
-	std::vector<ChannelState> channels;			// Memory for each channel's state
+	std::vector<ChannelState> channels;		// Memory for each channel's state
 	bool realBPMmode;						// true = BPM mode
 	uint8 beat;								// Rows per beat
 	uint8 tempoTicks;						// Tick mode param
@@ -240,7 +203,6 @@ struct DMFPatternSettings
 
 // Convert portamento value (not very accurate due to X-Tracker's higher granularity, to say the least)
 static uint8 DMFporta2MPT(uint8 val, const uint8 internalTicks, const bool hasFine)
-//---------------------------------------------------------------------------------
 {
 	if(val == 0)
 		return 0;
@@ -253,7 +215,6 @@ static uint8 DMFporta2MPT(uint8 val, const uint8 internalTicks, const bool hasFi
 
 // Convert portamento / volume slide value (not very accurate due to X-Tracker's higher granularity, to say the least)
 static uint8 DMFslide2MPT(uint8 val, const uint8 internalTicks, const bool up)
-//----------------------------------------------------------------------------
 {
 	val = std::max<uint8>(1, val / 4);
 	const bool isFine = (val < 0x0F) || (internalTicks < 2);
@@ -270,7 +231,6 @@ static uint8 DMFslide2MPT(uint8 val, const uint8 internalTicks, const bool up)
 
 // Calculate tremor on/off param
 static uint8 DMFtremor2MPT(uint8 val, const uint8 internalTicks)
-//--------------------------------------------------------------
 {
 	uint8 ontime = (val >> 4);
 	uint8 offtime = (val & 0x0F);
@@ -282,7 +242,6 @@ static uint8 DMFtremor2MPT(uint8 val, const uint8 internalTicks)
 
 // Calculate delay parameter for note cuts / delays
 static uint8 DMFdelay2MPT(uint8 val, const uint8 internalTicks)
-//-------------------------------------------------------------
 {
 	int newval = (int)val * (int)internalTicks / 255;
 	Limit(newval, 0, 15);
@@ -292,7 +251,6 @@ static uint8 DMFdelay2MPT(uint8 val, const uint8 internalTicks)
 
 // Convert vibrato-style command parameters
 static uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks)
-//---------------------------------------------------------------
 {
 	// MPT: 1 vibrato period == 64 ticks... we have internalTicks ticks per row.
 	// X-Tracker: Period length specified in rows!
@@ -304,7 +262,6 @@ static uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks)
 
 // Try using effect memory (zero paramer) to give the effect swapper some optimization hints.
 static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, uint8 effect, uint8 &param)
-//--------------------------------------------------------------------------------------------------------------------
 {
 	if(effect == CMD_NONE || param == 0)
 	{
@@ -367,7 +324,6 @@ static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX nu
 
 
 static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &settings, CSoundFile &sndFile)
-//--------------------------------------------------------------------------------------------------------
 {
 	// Pattern flags
 	enum PatternFlags
@@ -388,7 +344,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &sett
 	file.Rewind();
 	
 	DMFPatternHeader patHead;
-	file.ReadConvertEndianness(patHead);
+	file.ReadStruct(patHead);
 
 	const ROWINDEX numRows = Clamp(ROWINDEX(patHead.numRows), ROWINDEX(1), MAX_PATTERN_ROWS);
 	const PATTERNINDEX pat = sndFile.Patterns.InsertAny(numRows);
@@ -664,7 +620,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &sett
 						// Put high offset on previous row
 						if(row > 0 && effect1 != settings.channels[chn].highOffset)
 						{
-							if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(row - 1).Channel(chn).Retry(EffectWriter::rmTryPreviousRow)))
+							if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(row - 1).Channel(chn).RetryPreviousRow()))
 							{
 								settings.channels[chn].highOffset = effect1;
 							}
@@ -748,7 +704,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &sett
 						// Put vibrato type on previous row
 						if(row > 0 && effect2 != settings.channels[chn].vibratoType)
 						{
-							if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(row - 1).Channel(chn).Retry(EffectWriter::rmTryPreviousRow)))
+							if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(row - 1).Channel(chn).RetryPreviousRow()))
 							{
 								settings.channels[chn].vibratoType = effect2;
 							}
@@ -807,7 +763,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &sett
 						// Put tremolo type on previous row
 						if(row > 0 && effect3 != settings.channels[chn].tremoloType)
 						{
-							if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(row - 1).Channel(chn).Retry(EffectWriter::rmTryPreviousRow)))
+							if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(row - 1).Channel(chn).RetryPreviousRow()))
 							{
 								settings.channels[chn].tremoloType = effect3;
 							}
@@ -904,18 +860,18 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &sett
 		{
 			tempoChange = false;
 			
-			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast<ModCommand::PARAM>(tempo)).Row(row).Channel(0).Retry(EffectWriter::rmTryNextRow));
-			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, static_cast<ModCommand::PARAM>(speed)).Row(row).Retry(EffectWriter::rmTryNextRow));
+			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast<ModCommand::PARAM>(tempo)).Row(row).Channel(0).RetryNextRow());
+			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, static_cast<ModCommand::PARAM>(speed)).Row(row).RetryNextRow());
 		}
 		// Try to put delay effects somewhere as well
 		if(writeDelay & 0xF0)
 		{
-			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(row).AllowMultiple().Retry(EffectWriter::rmIgnore));
+			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(row).AllowMultiple());
 		}
 		if(writeDelay & 0x0F)
 		{
 			const uint8 param = (writeDelay & 0x0F) * settings.internalTicks / 15;
-			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(row).AllowMultiple().Retry(EffectWriter::rmIgnore));
+			sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(row).AllowMultiple());
 		}
 		writeDelay = 0;
 	}	// End for all rows
@@ -924,17 +880,47 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &sett
 }
 
 
-bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const DMFFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.signature, "DDMF", 4)
+		|| !fileHeader.version || fileHeader.version > 10)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize)
 {
 	DMFFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
+{
 	file.Rewind();
-	if(!file.ReadStruct(fileHeader)
-		|| memcmp(fileHeader.signature, "DDMF", 4)
-		|| !fileHeader.version || fileHeader.version > 10)
+
+	DMFFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -963,25 +949,19 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
 	// Read order list
 	DMFSequence seqHeader;
 	chunk = chunks.GetChunk(DMFChunk::idSEQU);
-	if(!chunk.ReadConvertEndianness(seqHeader))
+	if(!chunk.ReadStruct(seqHeader))
 	{
 		return false;
 	}
-	const ORDERINDEX numOrders = std::min(MAX_ORDERS, static_cast<ORDERINDEX>((chunk.GetLength() - sizeof(DMFSequence)) / 2));
-	Order.resize(numOrders, Order.GetInvalidPatIndex());
-
-	for(ORDERINDEX i = 0; i < numOrders; i++)
-	{
-		Order[i] = chunk.ReadUint16LE();
-	}
+	ReadOrderFromFile<uint16le>(Order(), chunk, (chunk.GetLength() - sizeof(DMFSequence)) / 2);
 
 	// Read patterns
 	chunk = chunks.GetChunk(DMFChunk::idPATT);
 	if(chunk.IsValid() && (loadFlags & loadPatternData))
 	{
 		DMFPatterns patHeader;
-		chunk.ReadConvertEndianness(patHeader);
-		m_nChannels = Clamp(patHeader.numTracks, uint8(1), uint8(32)) + 1;	// + 1 for global track (used for tempo stuff)
+		chunk.ReadStruct(patHeader);
+		m_nChannels = Clamp<uint8, uint8>(patHeader.numTracks, 1, 32) + 1;	// + 1 for global track (used for tempo stuff)
 
 		std::vector<FileReader> patternChunks;
 		patternChunks.reserve(patHeader.numPatterns);
@@ -990,7 +970,7 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
 		for(PATTERNINDEX pat = 0; pat < patHeader.numPatterns; pat++)
 		{
 			DMFPatternHeader header;
-			chunk.ReadConvertEndianness(header);
+			chunk.ReadStruct(header);
 			chunk.SkipBack(sizeof(header));
 			patternChunks.push_back(chunk.ReadChunk(sizeof(header) + header.patternLength));
 		}
@@ -998,18 +978,19 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
 		// Now go through the order list and load them.
 		DMFPatternSettings settings(GetNumChannels());
 
-		for(ORDERINDEX ord = 0; ord < Order.GetLength(); ord++)
+		Patterns.ResizeArray(Order().GetLength());
+		for(ORDERINDEX ord = 0; ord < Order().GetLength(); ord++)
 		{
 			// Create one pattern for each order item, as the same pattern can be played with different settings
-			PATTERNINDEX pat = Order[ord];
+			PATTERNINDEX pat = Order()[ord];
 			if(pat < patternChunks.size())
 			{
 				pat = ConvertDMFPattern(patternChunks[pat], settings, *this);
-				Order[ord] = pat;
+				Order()[ord] = pat;
 				// Loop end?
-				if(pat != PATTERNINDEX_INVALID && ord == seqHeader.loopEnd && (seqHeader.loopStart > 0 || ord < Order.GetLength() - 1))
+				if(pat != PATTERNINDEX_INVALID && ord == seqHeader.loopEnd && (seqHeader.loopStart > 0 || ord < Order().GetLastIndex()))
 				{
-					Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(seqHeader.loopStart)).Row(Patterns[pat].GetNumRows() - 1).Retry(EffectWriter::rmTryPreviousRow));
+					Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(seqHeader.loopStart)).Row(Patterns[pat].GetNumRows() - 1).RetryPreviousRow());
 				}
 			}
 		}
@@ -1033,10 +1014,10 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
 
 	for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
 	{
-		chunk.ReadString<mpt::String::spacePadded>(m_szNames[smp], chunk.ReadUint8());
+		chunk.ReadSizedString<uint8le, mpt::String::spacePadded>(m_szNames[smp]);
 		DMFSampleHeader sampleHeader;
 		ModSample &sample = Samples[smp];
-		chunk.ReadConvertEndianness(sampleHeader);
+		chunk.ReadStruct(sampleHeader);
 		sampleHeader.ConvertToMPT(sample);
 
 		if(fileHeader.version >= 8)
@@ -1073,7 +1054,7 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
 
 
 ///////////////////////////////////////////////////////////////////////
-// DMF Compression (from libmodplug)
+// DMF Compression
 
 struct DMFHNode
 {
@@ -1151,7 +1132,6 @@ struct DMFHTree
 
 
 uintptr_t DMFUnpack(uint8 *psample, const uint8 *ibuf, const uint8 *ibufmax, uint32 maxlen)
-//-----------------------------------------------------------------------------------------
 {
 	DMFHTree tree;
 
diff --git a/soundlib/Load_dsm.cpp b/soundlib/Load_dsm.cpp
index de4b683..204ff03 100644
--- a/soundlib/Load_dsm.cpp
+++ b/soundlib/Load_dsm.cpp
@@ -24,77 +24,48 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED DSMChunk
+struct DSMChunk
 {
-	char   magic[4];
-	uint32 size;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(size);
-	}
+	char     magic[4];
+	uint32le size;
 };
 
-STATIC_ASSERT(sizeof(DSMChunk) == 8);
+MPT_BINARY_STRUCT(DSMChunk, 8)
 
 
-struct PACKED DSMSongHeader
+struct DSMSongHeader
 {
-	char   songName[28];
-	char   reserved1[2];
-	uint16 flags;
-	char   reserved2[4];
-	uint16 numOrders;
-	uint16 numSamples;
-	uint16 numPatterns;
-	uint16 numChannels;
-	uint8  globalVol;
-	uint8  mastervol;
-	uint8  speed;
-	uint8  bpm;
-	uint8  panPos[16];
-	uint8  orders[128];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(flags);
-		SwapBytesLE(numOrders);
-		SwapBytesLE(numSamples);
-		SwapBytesLE(numPatterns);
-		SwapBytesLE(numChannels);
-	}
+	char     songName[28];
+	char     reserved1[2];
+	uint16le flags;
+	char     reserved2[4];
+	uint16le numOrders;
+	uint16le numSamples;
+	uint16le numPatterns;
+	uint16le numChannels;
+	uint8le  globalVol;
+	uint8le  mastervol;
+	uint8le  speed;
+	uint8le  bpm;
+	uint8le  panPos[16];
+	uint8le  orders[128];
 };
 
-STATIC_ASSERT(sizeof(DSMSongHeader) == 192);
+MPT_BINARY_STRUCT(DSMSongHeader, 192)
 
 
-struct PACKED DSMSampleHeader
+struct DSMSampleHeader
 {
-	char   filename[13];
-	uint8  flags;
-	char   reserved1;
-	uint8  volume;
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	char   reserved2[4];
-	uint32 sampleRate;
-	char   sampleName[28];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sampleRate);
-	}
+	char     filename[13];
+	uint8le  flags;
+	char     reserved1;
+	uint8le  volume;
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	char     reserved2[4];
+	uint32le sampleRate;
+	char     sampleName[28];
 
 	// Convert a DSM sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -107,7 +78,7 @@ struct PACKED DSMSampleHeader
 		mptSmp.nLength = length;
 		mptSmp.nLoopStart = loopStart;
 		mptSmp.nLoopEnd = loopEnd;
-		mptSmp.nVolume = std::min(volume, uint8(64)) * 4;
+		mptSmp.nVolume = std::min<uint8>(volume, 64) * 4;
 	}
 
 	// Retrieve the internal sample format flags for this sample.
@@ -126,65 +97,113 @@ struct PACKED DSMSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(DSMSampleHeader) == 64);
-
+MPT_BINARY_STRUCT(DSMSampleHeader, 64)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
-
-bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct DSMHeader
 {
-	file.Rewind();
-
 	char fileMagic0[4];
 	char fileMagic1[4];
 	char fileMagic2[4];
+};
 
-	if(!file.ReadArray(fileMagic0)) return false;
-	if(!file.ReadArray(fileMagic1)) return false;
-	if(!file.ReadArray(fileMagic2)) return false;
+MPT_BINARY_STRUCT(DSMHeader, 12)
 
-	if(!memcmp(fileMagic0, "RIFF", 4)
-		&& !memcmp(fileMagic2, "DSMF", 4))
+
+static bool ValidateHeader(const DSMHeader &fileHeader)
+{
+	if(!std::memcmp(fileHeader.fileMagic0, "RIFF", 4)
+		&& !std::memcmp(fileHeader.fileMagic2, "DSMF", 4))
 	{
 		// "Normal" DSM files with RIFF header
 		// <RIFF> <file size> <DSMF>
-	} else if(!memcmp(fileMagic0, "DSMF", 4))
+		return true;
+	} else if(!std::memcmp(fileHeader.fileMagic0, "DSMF", 4))
 	{
 		// DSM files with alternative header
 		// <DSMF> <4 bytes, usually 4x NUL or RIFF> <file size> <4 bytes, usually DSMF but not always>
-		file.Skip(4);
+		return true;
 	} else
 	{
 		return false;
 	}
+}
+
 
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	DSMHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+	{
+		if(!file.Skip(4))
+		{
+			return ProbeWantMoreData;
+		}
+	}
 	DSMChunk chunkHeader;
+	if(!file.ReadStruct(chunkHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(std::memcmp(chunkHeader.magic, "SONG", 4))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
 
-	file.ReadConvertEndianness(chunkHeader);
+bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+
+	DSMHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+	{
+		file.Skip(4);
+	}
+	DSMChunk chunkHeader;
+	if(!file.ReadStruct(chunkHeader))
+	{
+		return false;
+	}
 	// Technically, the song chunk could be anywhere in the file, but we're going to simplify
 	// things by not using a chunk header here and just expect it to be right at the beginning.
-	if(memcmp(chunkHeader.magic, "SONG", 4))
+	if(std::memcmp(chunkHeader.magic, "SONG", 4))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
 	DSMSongHeader songHeader;
 	file.ReadStructPartial(songHeader, chunkHeader.size);
-	songHeader.ConvertEndianness();
 
 	InitializeGlobals(MOD_TYPE_DSM);
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, songHeader.songName);
-	m_nChannels = Clamp(songHeader.numChannels, uint16(1), uint16(16));
+	m_nChannels = Clamp<uint16, uint16>(songHeader.numChannels, 1, 16);
 	m_nDefaultSpeed = songHeader.speed;
 	m_nDefaultTempo.Set(songHeader.bpm);
-	m_nDefaultGlobalVolume = std::min(songHeader.globalVol, uint8(64)) * 4u;
+	m_nDefaultGlobalVolume = std::min<uint8>(songHeader.globalVol, 64) * 4u;
 	if(!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
 	if(songHeader.mastervol == 0x80)
 	{
@@ -204,11 +223,11 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
 		}
 	}
 
-	Order.ReadFromArray(songHeader.orders, songHeader.numOrders, 0xFF, 0xFE);
+	ReadOrderFromArray(Order(), songHeader.orders, songHeader.numOrders, 0xFF, 0xFE);
 
 	// Read pattern and sample chunks
 	PATTERNINDEX patNum = 0;
-	while(file.ReadConvertEndianness(chunkHeader))
+	while(file.ReadStruct(chunkHeader))
 	{
 		FileReader chunk = file.ReadChunk(chunkHeader.size);
 
@@ -222,7 +241,7 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
 			chunk.Skip(2);
 
 			ROWINDEX row = 0;
-			PatternRow rowBase = Patterns[patNum];
+			PatternRow rowBase = Patterns[patNum].GetRow(0);
 			while(chunk.CanRead(1) && row < 64)
 			{
 				uint8 flag = chunk.ReadUint8();
@@ -289,7 +308,7 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
 			ModSample &sample = Samples[m_nSamples];
 
 			DSMSampleHeader sampleHeader;
-			chunk.ReadConvertEndianness(sampleHeader);
+			chunk.ReadStruct(sampleHeader);
 			sampleHeader.ConvertToMPT(sample);
 
 			mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[m_nSamples], sampleHeader.sampleName);
diff --git a/soundlib/Load_dtm.cpp b/soundlib/Load_dtm.cpp
new file mode 100644
index 0000000..6e5f30f
--- /dev/null
+++ b/soundlib/Load_dtm.cpp
@@ -0,0 +1,594 @@
+/*
+ * Load_dtm.cpp
+ * ------------
+ * Purpose: Digital Tracker / Digital Home Studio module Loader (DTM)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Loaders.h"
+#include "ChunkReader.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+enum PatternFormats : uint32
+{
+	DTM_PT_PATTERN_FORMAT = 0,
+	DTM_204_PATTERN_FORMAT = MAGIC4BE('2', '.', '0', '4'),
+	DTM_206_PATTERN_FORMAT = MAGIC4BE('2', '.', '0', '6'),
+};
+
+
+struct DTMFileHeader
+{
+	char     magic[4];
+	uint32be headerSize;
+	uint16be type;        // 0 = module
+	uint8be  stereoMode;  // FF = panoramic stereo, 00 = old stereo
+	uint8be  bitDepth;    // Typically 8, sometimes 16, but is not actually used anywhere?
+	uint16be reserved;    // Usually 0, but not in unknown title 1.dtm and unknown title 2.dtm
+	uint16be speed;
+	uint16be tempo;
+	uint32be forcedSampleRate; // Seems to be ignored in newer files
+};
+
+MPT_BINARY_STRUCT(DTMFileHeader, 22)
+
+
+// IFF-style Chunk
+struct DTMChunk
+{
+	// 32-Bit chunk identifiers
+	enum ChunkIdentifiers
+	{
+		idS_Q_ = MAGIC4BE('S', '.', 'Q', '.'),
+		idPATT = MAGIC4BE('P', 'A', 'T', 'T'),
+		idINST = MAGIC4BE('I', 'N', 'S', 'T'),
+		idIENV = MAGIC4BE('I', 'E', 'N', 'V'),
+		idDAPT = MAGIC4BE('D', 'A', 'P', 'T'),
+		idDAIT = MAGIC4BE('D', 'A', 'I', 'T'),
+		idTEXT = MAGIC4BE('T', 'E', 'X', 'T'),
+		idPATN = MAGIC4BE('P', 'A', 'T', 'N'),
+		idTRKN = MAGIC4BE('T', 'R', 'K', 'N'),
+		idVERS = MAGIC4BE('V', 'E', 'R', 'S'),
+		idSV19 = MAGIC4BE('S', 'V', '1', '9'),
+	};
+
+	uint32be id;
+	uint32be length;
+
+	size_t GetLength() const
+	{
+		return length;
+	}
+
+	ChunkIdentifiers GetID() const
+	{
+		return static_cast<ChunkIdentifiers>(id.get());
+	}
+};
+
+MPT_BINARY_STRUCT(DTMChunk, 8)
+
+
+struct DTMSample
+{
+	uint32be reserved;   // 0x204 for first sample, 0x208 for second, etc...
+	uint32be length;     // in bytes
+	uint8be  finetune;   // -8....7
+	uint8be  volume;     // 0...64
+	uint32be loopStart;  // in bytes
+	uint32be loopLength; // ditto
+	char     name[22];
+	uint8be  stereo;
+	uint8be  bitDepth;
+	uint16be transpose;
+	uint16be unknown;
+	uint32be sampleRate;
+
+	void ConvertToMPT(ModSample &mptSmp, uint32 forcedSampleRate, uint32 formatVersion) const
+	{
+		mptSmp.Initialize(MOD_TYPE_IT);
+		mptSmp.nLength = length;
+		mptSmp.nLoopStart = loopStart;
+		mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength;
+		// In revolution to come.dtm, the file header says samples rate is 24512 Hz, but samples say it's 50000 Hz
+		// Digital Home Studio ignores the header setting in 2.04-/2.06-style modules
+		mptSmp.nC5Speed = (formatVersion == DTM_PT_PATTERN_FORMAT && forcedSampleRate > 0) ? forcedSampleRate : sampleRate;
+		int32 transposeAmount = MOD2XMFineTune(finetune);
+		if(formatVersion == DTM_206_PATTERN_FORMAT && transpose > 0 && transpose != 48)
+		{
+			// Digital Home Studio applies this unconditionally, but some old songs sound wrong then (delirium.dtm).
+			// Maybe this should not be applied for "real" Digital Tracker modules?
+			transposeAmount += (48 - transpose) * 128;
+		}
+		mptSmp.Transpose(transposeAmount * (1.0 / (12.0 * 128.0)));
+		mptSmp.nVolume = std::min<uint8>(volume, 64u) * 4u;
+		if(stereo & 1)
+		{
+			mptSmp.uFlags.set(CHN_STEREO);
+			mptSmp.nLength /= 2u;
+			mptSmp.nLoopStart /= 2u;
+			mptSmp.nLoopEnd /= 2u;
+		}
+		if(bitDepth > 8)
+		{
+			mptSmp.uFlags.set(CHN_16BIT);
+			mptSmp.nLength /= 2u;
+			mptSmp.nLoopStart /= 2u;
+			mptSmp.nLoopEnd /= 2u;
+		}
+		if(mptSmp.nLoopEnd > mptSmp.nLoopStart + 1)
+		{
+			mptSmp.uFlags.set(CHN_LOOP);
+		} else
+		{
+			mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
+		}
+	}
+};
+
+MPT_BINARY_STRUCT(DTMSample, 50)
+
+
+struct DTMInstrument
+{
+	uint16be insNum;
+	uint8be  unknown1;
+	uint8be  envelope; // 0xFF = none
+	uint8be  sustain;  // 0xFF = no sustain point
+	uint16be fadeout;
+	uint8be  vibRate;
+	uint8be  vibDepth;
+	uint8be  modulationRate;
+	uint8be  modulationDepth;
+	uint8be  breathRate;
+	uint8be  breathDepth;
+	uint8be  volumeRate;
+	uint8be  volumeDepth;
+};
+
+MPT_BINARY_STRUCT(DTMInstrument, 15)
+
+
+struct DTMEnvelope
+{
+	struct DTMEnvPoint
+	{
+		uint8be value;
+		uint8be tick;
+	};
+	uint16be numPoints;
+	DTMEnvPoint points[16];
+};
+
+MPT_BINARY_STRUCT(DTMEnvelope::DTMEnvPoint, 2)
+MPT_BINARY_STRUCT(DTMEnvelope, 34)
+
+
+struct DTMText
+{
+	uint16be textType;	// 0 = pattern, 1 = free, 2 = song
+	uint32be textLength;
+	uint16be tabWidth;
+	uint16be reserved;
+	uint16be oddLength;
+};
+
+MPT_BINARY_STRUCT(DTMText, 12)
+
+
+static bool ValidateHeader(const DTMFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.magic, "D.T.", 4)
+		|| fileHeader.headerSize < sizeof(fileHeader) - 8u
+		|| fileHeader.headerSize > 256 // Excessively long song title?
+		|| fileHeader.type != 0)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	DTMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+
+	DTMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
+	{
+		return true;
+	}
+
+	InitializeGlobals(MOD_TYPE_DTM);
+	InitializeChannels();
+	m_SongFlags.set(SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS);
+	m_playBehaviour.reset(kITVibratoTremoloPanbrello);
+	// Various files have a default speed or tempo of 0
+	if(fileHeader.tempo)
+		m_nDefaultTempo.Set(fileHeader.tempo);
+	if(fileHeader.speed)
+		m_nDefaultSpeed = fileHeader.speed;
+	if(fileHeader.stereoMode == 0)
+		SetupMODPanning(true);
+
+	file.ReadString<mpt::String::maybeNullTerminated>(m_songName, fileHeader.headerSize - (sizeof(fileHeader) - 8u));
+
+	auto chunks = ChunkReader(file).ReadChunks<DTMChunk>(1);
+
+	// Read order list
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idS_Q_))
+	{
+		uint16 ordLen = chunk.ReadUint16BE();
+		uint16 restartPos = chunk.ReadUint16BE();
+		chunk.Skip(4);	// Reserved
+		ReadOrderFromFile<uint8>(Order(), chunk, ordLen);
+		Order().SetRestartPos(restartPos);
+	} else
+	{
+		return false;
+	}
+
+	// Read pattern properties
+	uint32 patternFormat;
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idPATT))
+	{
+		m_nChannels = chunk.ReadUint16BE();
+		if(m_nChannels < 1 || m_nChannels > 32)
+		{
+			return false;
+		}
+		Patterns.ResizeArray(chunk.ReadUint16BE());	// Number of stored patterns, may be lower than highest pattern number
+		patternFormat = chunk.ReadUint32BE();
+		if(patternFormat != DTM_PT_PATTERN_FORMAT && patternFormat != DTM_204_PATTERN_FORMAT && patternFormat != DTM_206_PATTERN_FORMAT)
+		{
+			return false;
+		}
+	} else
+	{
+		return false;
+	}
+
+	// Read global info
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idSV19))
+	{
+		chunk.Skip(2);	// Ticks per quarter note, typically 24
+		uint32 fractionalTempo = chunk.ReadUint32BE();
+		m_nDefaultTempo = TEMPO(m_nDefaultTempo.GetInt() + fractionalTempo / 4294967296.0);
+
+		uint16be panning[32];
+		chunk.ReadArray(panning);
+		for(CHANNELINDEX chn = 0; chn < 32 && chn < GetNumChannels(); chn++)
+		{
+			// Panning is in range 0...180, 90 = center
+			ChnSettings[chn].nPan = static_cast<uint16>(128 + Util::muldivr(std::min<int>(panning[chn], 180) - 90, 128, 90));
+		}
+
+		chunk.Skip(146);
+		uint16be volume[32];
+		if(chunk.ReadArray(volume))
+		{
+			for(CHANNELINDEX chn = 0; chn < 32 && chn < GetNumChannels(); chn++)
+			{
+				// Volume is in range 0...128, 64 = normal
+				ChnSettings[chn].nVolume = static_cast<uint8>(std::min<int>(volume[chn], 128) / 2);
+			}
+			m_nSamplePreAmp *= 2;	// Compensate for channel volume range
+		}
+	}
+
+	// Read song message
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idTEXT))
+	{
+		DTMText text;
+		chunk.ReadStruct(text);
+		if(text.oddLength == 0xFFFF)
+		{
+			chunk.Skip(1);
+		}
+		m_songMessage.Read(chunk, chunk.BytesLeft(), SongMessage::leCRLF);
+	}
+
+	// Read sample headers
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idINST))
+	{
+		uint16 numSamples = chunk.ReadUint16BE();
+		bool newSamples = (numSamples >= 0x8000);
+		numSamples &= 0x7FFF;
+		if(numSamples >= MAX_SAMPLES || !chunk.CanRead(numSamples) * sizeof(DTMSample))
+		{
+			return false;
+		}
+		
+		m_nSamples = numSamples;
+		for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++)
+		{
+			SAMPLEINDEX realSample = newSamples ? (chunk.ReadUint16BE() + 1u) : smp;
+			DTMSample dtmSample;
+			chunk.ReadStruct(dtmSample);
+			if(realSample < 1 || realSample >= MAX_SAMPLES)
+			{
+				continue;
+			}
+			m_nSamples = std::max(m_nSamples, realSample);
+			ModSample &mptSmp = Samples[realSample];
+			dtmSample.ConvertToMPT(mptSmp, fileHeader.forcedSampleRate, patternFormat);
+			mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[realSample], dtmSample.name);
+		}
+	
+		if(chunk.ReadUint16BE() == 0x0004)
+		{
+			// Digital Home Studio instruments
+			m_nInstruments = std::min<INSTRUMENTINDEX>(m_nSamples, MAX_INSTRUMENTS - 1);
+
+			FileReader envChunk = chunks.GetChunk(DTMChunk::idIENV);
+			while(chunk.CanRead(sizeof(DTMInstrument)))
+			{
+				DTMInstrument instr;
+				chunk.ReadStruct(instr);
+				if(instr.insNum < GetNumInstruments())
+				{
+					Samples[instr.insNum + 1].nVibDepth = instr.vibDepth;
+					Samples[instr.insNum + 1].nVibRate = instr.vibRate;
+					Samples[instr.insNum + 1].nVibSweep = 255;
+
+					ModInstrument *mptIns = AllocateInstrument(instr.insNum + 1, instr.insNum + 1);
+					if(mptIns != nullptr)
+					{
+						InstrumentEnvelope &mptEnv = mptIns->VolEnv;
+						mptIns->nFadeOut = std::min<uint16>(instr.fadeout, 0xFFF);
+						if(instr.envelope != 0xFF && envChunk.Seek(2 + sizeof(DTMEnvelope) * instr.envelope))
+						{
+							DTMEnvelope env;
+							envChunk.ReadStruct(env);
+							mptEnv.dwFlags.set(ENV_ENABLED);
+							mptEnv.resize(std::min<size_t>({ env.numPoints, mpt::size(env.points), MAX_ENVPOINTS }));
+							for(size_t i = 0; i < mptEnv.size(); i++)
+							{
+								mptEnv[i].value = std::min<uint8>(64, env.points[i].value);
+								mptEnv[i].tick = env.points[i].tick;
+							}
+
+							if(instr.sustain != 0xFF)
+							{
+								mptEnv.dwFlags.set(ENV_SUSTAIN);
+								mptEnv.nSustainStart = mptEnv.nSustainEnd = instr.sustain;
+							}
+							if(!mptEnv.empty())
+							{
+								mptEnv.dwFlags.set(ENV_LOOP);
+								mptEnv.nLoopStart = mptEnv.nLoopEnd = static_cast<uint8>(mptEnv.size() - 1);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	// Read pattern data
+	for(auto &chunk : chunks.GetAllChunks(DTMChunk::idDAPT))
+	{
+		chunk.Skip(4);	// FF FF FF FF
+		PATTERNINDEX patNum = chunk.ReadUint16BE();
+		ROWINDEX numRows = chunk.ReadUint16BE();
+		if(patternFormat == DTM_206_PATTERN_FORMAT)
+		{
+			// The stored data is actually not row-based, but tick-based.
+			numRows /= m_nDefaultSpeed;
+		}
+		if(!(loadFlags & loadPatternData) || patNum > 255 || !Patterns.Insert(patNum, numRows))
+		{
+			continue;
+		}
+
+		if(patternFormat == DTM_206_PATTERN_FORMAT)
+		{
+			chunk.Skip(4);
+			for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
+			{
+				uint16 length = chunk.ReadUint16BE();
+				if(length % 2u) length++;
+				FileReader rowChunk = chunk.ReadChunk(length);
+				int tick = 0;
+				std::div_t position = { 0, 0 };
+				while(rowChunk.CanRead(6) && static_cast<ROWINDEX>(position.quot) < numRows)
+				{
+					ModCommand *m = Patterns[patNum].GetpModCommand(position.quot, chn);
+
+					uint8 data[6];
+					rowChunk.ReadArray(data);
+					if(data[0] > 0 && data[0] <= 96)
+					{
+						m->note = data[0] + NOTE_MIN + 12;
+						if(position.rem)
+						{
+							m->command = CMD_MODCMDEX;
+							m->param = 0xD0 | static_cast<ModCommand::PARAM>(std::min(position.rem, 15));
+						}
+					} else if(data[0] & 0x80)
+					{
+						// Lower 7 bits contain note, probably intended for MIDI-like note-on/note-off events
+						if(position.rem)
+						{
+							m->command = CMD_MODCMDEX;
+							m->param = 0xC0 | static_cast<ModCommand::PARAM>(std::min(position.rem, 15));
+						} else
+						{
+							m->note = NOTE_NOTECUT;
+						}
+					}
+					if(data[1])
+					{
+						m->volcmd = VOLCMD_VOLUME;
+						m->vol = std::min(data[1], uint8(64)); // Volume can go up to 255, but we do not support over-amplification at the moment.
+					}
+					if(data[2])
+					{
+						m->instr = data[2];
+					}
+					if(data[3] || data[4])
+					{
+						m->command = data[3];
+						m->param = data[4];
+						ConvertModCommand(*m);
+#ifdef MODPLUG_TRACKER
+						m->Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this);
+#endif
+					}
+					if(data[5] & 0x80)
+						tick += (data[5] & 0x7F) * 0x100 + rowChunk.ReadUint8();
+					else
+						tick += data[5];
+					position = std::div(tick, m_nDefaultSpeed);
+				}
+			}
+		} else
+		{
+			ModCommand *m = Patterns[patNum].GetpModCommand(0, 0);
+			for(ROWINDEX row = 0; row < numRows; row++)
+			{
+				for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, m++)
+				{
+					uint8 data[4];
+					chunk.ReadArray(data);
+					if(patternFormat == DTM_204_PATTERN_FORMAT)
+					{
+						if(data[0] > 0 && data[0] < 0x80)
+						{
+							m->note = (data[0] >> 4) * 12 + (data[0] & 0x0F) + NOTE_MIN + 11;
+						}
+						uint8 vol = data[1] >> 2;
+						if(vol)
+						{
+							m->volcmd = VOLCMD_VOLUME;
+							m->vol = vol - 1u;
+						}
+						m->instr = ((data[1] & 0x03) << 4) | (data[2] >> 4);
+						m->command = data[2] & 0x0F;
+						m->param = data[3];
+					} else
+					{
+						ReadMODPatternEntry(data, *m);
+						m->instr |= data[0] & 0x30;	// Allow more than 31 instruments
+					}
+					ConvertModCommand(*m);
+					// Fix commands without memory and slide nibble precedence
+					switch(m->command)
+					{
+					case CMD_PORTAMENTOUP:
+					case CMD_PORTAMENTODOWN:
+						if(!m->param)
+						{
+							m->command = CMD_NONE;
+						}
+						break;
+					case CMD_VOLUMESLIDE:
+					case CMD_TONEPORTAVOL:
+					case CMD_VIBRATOVOL:
+						if(m->param & 0xF0)
+						{
+							m->param &= 0xF0;
+						} else if(!m->param)
+						{
+							m->command = CMD_NONE;
+						}
+						break;
+					default:
+						break;
+					}
+#ifdef MODPLUG_TRACKER
+					m->Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this);
+#endif
+				}
+			}
+		}
+	}
+
+	// Read pattern names
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idPATN))
+	{
+		PATTERNINDEX pat = 0;
+		std::string name;
+		while(chunk.CanRead(1) && pat < Patterns.Size())
+		{
+			chunk.ReadNullString(name, 32);
+			Patterns[pat].SetName(name);
+			pat++;
+		}
+	}
+
+	// Read channel names
+	if(FileReader chunk = chunks.GetChunk(DTMChunk::idTRKN))
+	{
+		CHANNELINDEX chn = 0;
+		std::string name;
+		while(chunk.CanRead(1) && chn < GetNumChannels())
+		{
+			chunk.ReadNullString(name, 32);
+			mpt::String::Copy(ChnSettings[chn].szName, name);
+			chn++;
+		}
+	}
+
+	// Read sample data
+	for(auto &chunk : chunks.GetAllChunks(DTMChunk::idDAIT))
+	{
+		PATTERNINDEX smp = chunk.ReadUint16BE() + 1;
+		if(smp == 0 || smp > GetNumSamples() || !(loadFlags & loadSampleData))
+		{
+			continue;
+		}
+		ModSample &mptSmp = Samples[smp];
+		SampleIO(
+			mptSmp.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit,
+			mptSmp.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved: SampleIO::mono,
+			SampleIO::bigEndian,
+			SampleIO::signedPCM).ReadSample(mptSmp, chunk);
+	}
+
+	// Is this accurate?
+	if(patternFormat == DTM_206_PATTERN_FORMAT)
+	{
+		m_madeWithTracker = MPT_USTRING("Digital Home Studio");
+	} else if(FileReader chunk = chunks.GetChunk(DTMChunk::idVERS))
+	{
+		uint32 version = chunk.ReadUint32BE();
+		m_madeWithTracker = mpt::format(MPT_USTRING("Digital Tracker %1.%2"))(version >> 4, version & 0x0F);
+	} else
+	{
+		m_madeWithTracker = MPT_USTRING("Digital Tracker");
+	}
+
+	return true;
+}
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/Load_far.cpp b/soundlib/Load_far.cpp
index 5c3a094..b6e4b3d 100644
--- a/soundlib/Load_far.cpp
+++ b/soundlib/Load_far.cpp
@@ -14,60 +14,39 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // FAR File Header
-struct PACKED FARFileHeader
+struct FARFileHeader
 {
-	uint8  magic[4];
-	char   songName[40];
-	uint8  eof[3];
-	uint16 headerLength;
-	uint8  version;
-	uint8  onOff[16];
-	uint8  editingState[9];	// Stuff we don't care about
-	uint8  defaultSpeed;
-	uint8  chnPanning[16];
-	uint8  patternState[4];	// More stuff we don't care about
-	uint16 messageLength;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(headerLength);
-		SwapBytesLE(messageLength);
-	}
+	uint8le  magic[4];
+	char     songName[40];
+	uint8le  eof[3];
+	uint16le headerLength;
+	uint8le  version;
+	uint8le  onOff[16];
+	uint8le  editingState[9];	// Stuff we don't care about
+	uint8le  defaultSpeed;
+	uint8le  chnPanning[16];
+	uint8le  patternState[4];	// More stuff we don't care about
+	uint16le messageLength;
 };
 
-STATIC_ASSERT(sizeof(FARFileHeader) == 98);
+MPT_BINARY_STRUCT(FARFileHeader, 98)
 
 
-struct PACKED FAROrderHeader
+struct FAROrderHeader
 {
-	uint8  orders[256];
-	uint8  numPatterns;	// supposed to be "number of patterns stored in the file"; apparently that's wrong
-	uint8  numOrders;
-	uint8  restartPos;
-	uint16 patternSize[256];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(size_t i = 0; i < CountOf(patternSize); i++)
-		{
-			SwapBytesLE(patternSize[i]);
-		}
-	}
+	uint8le  orders[256];
+	uint8le  numPatterns;	// supposed to be "number of patterns stored in the file"; apparently that's wrong
+	uint8le  numOrders;
+	uint8le  restartPos;
+	uint16le patternSize[256];
 };
 
-STATIC_ASSERT(sizeof(FAROrderHeader) == 771);
+MPT_BINARY_STRUCT(FAROrderHeader, 771)
 
 
 // FAR Sample header
-struct PACKED FARSampleHeader
+struct FARSampleHeader
 {
 	// Sample flags
 	enum SampleFlags
@@ -76,22 +55,14 @@ struct PACKED FARSampleHeader
 		smpLoop		= 0x08,
 	};
 
-	char   name[32];
-	uint32 length;
-	uint8  finetune;
-	uint8  volume;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint8  type;
-	uint8  loop;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-	}
+	char     name[32];
+	uint32le length;
+	uint8le  finetune;
+	uint8le  volume;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint8le  type;
+	uint8le  loop;
 
 	// Convert sample header to OpenMPT's internal format.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -113,7 +84,7 @@ struct PACKED FARSampleHeader
 
 		if((loop & 8) && mptSmp.nLoopEnd > mptSmp.nLoopStart)
 		{
-			mptSmp.uFlags |= CHN_LOOP;
+			mptSmp.uFlags.set(CHN_LOOP);
 		}
 	}
 
@@ -128,26 +99,64 @@ struct PACKED FARSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(FARSampleHeader) == 48);
+MPT_BINARY_STRUCT(FARSampleHeader, 48)
+
+
+static bool ValidateHeader(const FARFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
+		|| std::memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
+		)
+	{
+		return false;
+	}
+	if(fileHeader.headerLength < sizeof(FARFileHeader))
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const FARFileHeader &fileHeader)
+{
+	return fileHeader.headerLength - sizeof(FARFileHeader);
+}
+
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize)
+{
+	FARFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 
 	FARFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
-		|| memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
-		|| !file.LengthIsAtLeast(fileHeader.headerLength))
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -178,17 +187,17 @@ bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
 
 	// Read orders
 	FAROrderHeader orderHeader;
-	if(!file.ReadConvertEndianness(orderHeader))
+	if(!file.ReadStruct(orderHeader))
 	{
 		return false;
 	}
-	Order.ReadFromArray(orderHeader.orders, orderHeader.numOrders, 0xFF, 0xFE);
-	Order.SetRestartPos(orderHeader.restartPos);
+	ReadOrderFromArray(Order(), orderHeader.orders, orderHeader.numOrders, 0xFF, 0xFE);
+	Order().SetRestartPos(orderHeader.restartPos);
 
 	file.Seek(fileHeader.headerLength);
 	
 	// Pattern effect LUT
-	static const uint8 farEffects[] =
+	static const EffectCommand farEffects[] =
 	{
 		CMD_NONE,
 		CMD_PORTAMENTOUP,
@@ -288,7 +297,7 @@ bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
 			}
 		}
 
-		Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(breakRow).Retry(EffectWriter::rmTryNextRow));
+		Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(breakRow).RetryNextRow());
 	}
 	
 	if(!(loadFlags & loadSampleData))
@@ -308,7 +317,7 @@ bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
 		}
 
 		FARSampleHeader sampleHeader;
-		if(!file.ReadConvertEndianness(sampleHeader))
+		if(!file.ReadStruct(sampleHeader))
 		{
 			return true;
 		}
diff --git a/soundlib/Load_gdm.cpp b/soundlib/Load_gdm.cpp
index e5966d9..8125b8a 100644
--- a/soundlib/Load_gdm.cpp
+++ b/soundlib/Load_gdm.cpp
@@ -21,141 +21,133 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-
 // GDM File Header
-struct PACKED GDMFileHeader
+struct GDMFileHeader
 {
-	char   magic[4];				// ID: 'GDM\xFE'
-	char   songTitle[32];			// Music's title
-	char   songMusician[32];		// Name of music's composer
-	char   dosEOF[3];				// 13, 10, 26
-	char   magic2[4];				// ID: 'GMFS'
-	uint8  formatMajorVer;			// Format major version
-	uint8  formatMinorVer;			// Format minor version
-	uint16 trackerID;				// Composing Tracker ID code (00 = 2GDM)
-	uint8  trackerMajorVer;			// Tracker's major version
-	uint8  trackerMinorVer;			// Tracker's minor version
-	uint8  panMap[32];				// 0-Left to 15-Right, 255-N/U
-	uint8  masterVol;				// Range: 0...64
-	uint8  tempo;					// Initial music tempo (6)
-	uint8  bpm;						// Initial music BPM (125)
-	uint16 originalFormat;			// Original format ID:
+	char     magic[4];				// ID: 'GDM\xFE'
+	char     songTitle[32];			// Music's title
+	char     songMusician[32];		// Name of music's composer
+	char     dosEOF[3];				// 13, 10, 26
+	char     magic2[4];				// ID: 'GMFS'
+	uint8le  formatMajorVer;		// Format major version
+	uint8le  formatMinorVer;		// Format minor version
+	uint16le trackerID;				// Composing Tracker ID code (00 = 2GDM)
+	uint8le  trackerMajorVer;		// Tracker's major version
+	uint8le  trackerMinorVer;		// Tracker's minor version
+	uint8le  panMap[32];			// 0-Left to 15-Right, 255-N/U
+	uint8le  masterVol;				// Range: 0...64
+	uint8le  tempo;					// Initial music tempo (6)
+	uint8le  bpm;					// Initial music BPM (125)
+	uint16le originalFormat;		// Original format ID:
 		// 1-MOD, 2-MTM, 3-S3M, 4-669, 5-FAR, 6-ULT, 7-STM, 8-MED, 9-PSM
 		// (versions of 2GDM prior to v1.15 won't set this correctly)
 		// 2GDM v1.17 will only spit out 0-byte files when trying to convert a PSM16 file,
 		// and fail outright when trying to convert a new PSM file.
 
-	uint32 orderOffset;
-	uint8  lastOrder;				// Number of orders in module - 1
-	uint32 patternOffset;
-	uint8  lastPattern;				// Number of patterns in module - 1
-	uint32 sampleHeaderOffset;
-	uint32 sampleDataOffset;
-	uint8  lastSample;				// Number of samples in module - 1
-	uint32 messageTextOffset;		// Offset of song message
-	uint32 messageTextLength;
-	uint32 scrollyScriptOffset;		// Offset of scrolly script (huh?)
-	uint16 scrollyScriptLength;
-	uint32 textGraphicOffset;		// Offset of text graphic (huh?)
-	uint16 textGraphicLength;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(trackerID);
-		SwapBytesLE(originalFormat);
-		SwapBytesLE(orderOffset);
-		SwapBytesLE(patternOffset);
-		SwapBytesLE(sampleHeaderOffset);
-		SwapBytesLE(sampleDataOffset);
-		SwapBytesLE(messageTextOffset);
-		SwapBytesLE(messageTextLength);
-		SwapBytesLE(messageTextOffset);
-		SwapBytesLE(messageTextLength);
-		SwapBytesLE(scrollyScriptOffset);
-		SwapBytesLE(scrollyScriptLength);
-		SwapBytesLE(textGraphicOffset);
-		SwapBytesLE(textGraphicLength);
-	}
+	uint32le orderOffset;
+	uint8le  lastOrder;				// Number of orders in module - 1
+	uint32le patternOffset;
+	uint8le  lastPattern;			// Number of patterns in module - 1
+	uint32le sampleHeaderOffset;
+	uint32le sampleDataOffset;
+	uint8le  lastSample;			// Number of samples in module - 1
+	uint32le messageTextOffset;		// Offset of song message
+	uint32le messageTextLength;
+	uint32le scrollyScriptOffset;		// Offset of scrolly script (huh?)
+	uint16le scrollyScriptLength;
+	uint32le textGraphicOffset;		// Offset of text graphic (huh?)
+	uint16le textGraphicLength;
 };
 
-STATIC_ASSERT(sizeof(GDMFileHeader) == 157);
+MPT_BINARY_STRUCT(GDMFileHeader, 157)
 
 
 // GDM Sample Header
-struct PACKED GDMSampleHeader
+struct GDMSampleHeader
 {
 	enum SampleFlags
 	{
 		smpLoop		= 0x01,
-		smp16Bit	= 0x02,		// 16-Bit samples are not handled correctly by 2GDM (not implemented)
+		smp16Bit	= 0x02,	// 16-Bit samples are not handled correctly by 2GDM (not implemented)
 		smpVolume	= 0x04,
 		smpPanning	= 0x08,
-		smpLZW		= 0x10,		// LZW-compressed samples are not implemented in 2GDM
-		smpStereo	= 0x20,		// Stereo samples are not handled correctly by 2GDM (not implemented)
+		smpLZW		= 0x10,	// LZW-compressed samples are not implemented in 2GDM
+		smpStereo	= 0x20,	// Stereo samples are not handled correctly by 2GDM (not implemented)
 	};
 
-	char   name[32];		// sample's name
-	char   fileName[12];	// sample's filename
-	uint8  emsHandle;		// useless
-	uint32 length;			// length in bytes
-	uint32 loopBegin;		// loop start in samples
-	uint32 loopEnd;			// loop end in samples
-	uint8  flags;			// misc. flags
-	uint16 c4Hertz;			// frequency
-	uint8  volume;			// default volume
-	uint8  panning;			// default pan
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopBegin);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(c4Hertz);
-	}
+	char     name[32];		// sample's name
+	char     fileName[12];	// sample's filename
+	uint8le  emsHandle;		// useless
+	uint32le length;		// length in bytes
+	uint32le loopBegin;		// loop start in samples
+	uint32le loopEnd;		// loop end in samples
+	uint8le  flags;			// misc. flags
+	uint16le c4Hertz;		// frequency
+	uint8le  volume;		// default volume
+	uint8le  panning;		// default pan
 };
 
-STATIC_ASSERT(sizeof(GDMSampleHeader) == 62);
+MPT_BINARY_STRUCT(GDMSampleHeader, 62)
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static const MODTYPE gdmFormatOrigin[] =
+{
+	MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
+};
 
 
-bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const GDMFileHeader &fileHeader)
 {
-	file.Rewind();
+	if(std::memcmp(fileHeader.magic, "GDM\xFE", 4)
+		|| fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26
+		|| std::memcmp(fileHeader.magic2, "GMFS", 4)
+		|| fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0
+		|| fileHeader.originalFormat >= mpt::size(gdmFormatOrigin)
+		|| fileHeader.originalFormat == 0)
+	{
+		return false;
+	}
+	return true;
+}
 
-	const MODTYPE gdmFormatOrigin[] =
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	GDMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
 	{
-		MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
-	};
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
 
 	GDMFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.magic, "GDM\xFE", 4)
-		|| fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26
-		|| memcmp(fileHeader.magic2, "GMFS", 4)
-		|| fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0
-		|| fileHeader.originalFormat >= CountOf(gdmFormatOrigin)
-		|| fileHeader.originalFormat == 0)
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
 	InitializeGlobals(gdmFormatOrigin[fileHeader.originalFormat]);
 	m_ContainerType = MOD_CONTAINERTYPE_GDM;
-	m_madeWithTracker = mpt::String::Print("BWSB 2GDM %1.%2 (converted from %3)", fileHeader.trackerMajorVer, fileHeader.formatMinorVer, ModTypeToTracker(GetType()));
+	m_madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2 (converted from %3)"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer, ModTypeToTracker(GetType()));
 
 	// Song name
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songTitle);
@@ -188,15 +180,19 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 			break;
 		}
 	}
+	if(m_nChannels < 1)
+	{
+		return false;
+	}
 
-	m_nDefaultGlobalVolume = MIN(fileHeader.masterVol * 4, 256);
+	m_nDefaultGlobalVolume = std::min(fileHeader.masterVol * 4u, 256u);
 	m_nDefaultSpeed = fileHeader.tempo;
 	m_nDefaultTempo.Set(fileHeader.bpm);
 
 	// Read orders
 	if(file.Seek(fileHeader.orderOffset))
 	{
-		Order.ReadAsByte(file, fileHeader.lastOrder + 1, fileHeader.lastOrder + 1, 0xFF, 0xFE);
+		ReadOrderFromFile<uint8>(Order(), file, fileHeader.lastOrder + 1, 0xFF, 0xFE);
 	}
 
 	// Read samples
@@ -211,7 +207,7 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 	for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
 	{
 		GDMSampleHeader gdmSample;
-		if(!file.ReadConvertEndianness(gdmSample))
+		if(!file.ReadStruct(gdmSample))
 		{
 			break;
 		}
@@ -256,10 +252,10 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 		if(gdmSample.flags & GDMSampleHeader::smpVolume)
 		{
 			// Default volume is used... 0...64, 255 = no default volume
-			sample.nVolume = std::min(gdmSample.volume, uint8(64)) * 4;
+			sample.nVolume = std::min<uint8>(gdmSample.volume, 64) * 4;
 		} else
 		{
-			sample.nVolume = 256;
+			sample.uFlags.set(SMP_NODEFAULTVOLUME);
 		}
 
 		if(gdmSample.flags & GDMSampleHeader::smpPanning)
@@ -290,9 +286,10 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Read patterns
-	Patterns.ResizeArray(MAX(MAX_PATTERNS, fileHeader.lastPattern + 1));
+	Patterns.ResizeArray(fileHeader.lastPattern + 1);
 
 	const CModSpecifications &modSpecs = GetModSpecifications(GetBestSaveFormat());
+	bool onlyAmigaNotes = true;
 
 	// We'll start at position patternsOffset and decode all patterns
 	file.Seek(fileHeader.patternOffset);
@@ -347,6 +344,10 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 						noteByte = (noteByte & 0x7F) - 1; // This format doesn't have note cuts
 						if(noteByte < 0xF0) noteByte = (noteByte & 0x0F) + 12 * (noteByte >> 4) + 12 + NOTE_MIN;
 						m.note = noteByte;
+						if(!m.IsAmigaNote())
+						{
+							onlyAmigaNotes = false;
+						}
 					}
 					m.instr = noteSample;
 				}
@@ -359,16 +360,14 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 
 					while(chunk.CanRead(2))
 					{
-						uint8 effByte = chunk.ReadUint8();
-						uint8 paramByte = chunk.ReadUint8();
-
 						// We may want to restore the old command in some cases.
 						const ModCommand oldCmd = m;
-						m.command = effByte & effectMask;
-						m.param = paramByte;
+
+						uint8 effByte = chunk.ReadUint8();
+						m.param = chunk.ReadUint8();
 
 						// Effect translation LUT
-						static const uint8 gdmEffTrans[] =
+						static const EffectCommand gdmEffTrans[] =
 						{
 							CMD_NONE, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO,
 							CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO,
@@ -381,8 +380,9 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 						};
 
 						// Translate effect
-						if(m.command < CountOf(gdmEffTrans))
-							m.command = gdmEffTrans[m.command];
+						uint8 command = effByte & effectMask;
+						if(command < CountOf(gdmEffTrans))
+							m.command = gdmEffTrans[command];
 						else
 							m.command = CMD_NONE;
 
@@ -507,6 +507,8 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
 		}
 	}
 
+	m_SongFlags.set(SONG_AMIGALIMITS | SONG_ISAMIGA, GetType() == MOD_TYPE_MOD && GetNumChannels() == 4 && onlyAmigaNotes);
+
 	// Read song comments
 	if(fileHeader.messageTextLength > 0 && file.Seek(fileHeader.messageTextOffset))
 	{
diff --git a/soundlib/Load_imf.cpp b/soundlib/Load_imf.cpp
index 1788785..9192bc1 100644
--- a/soundlib/Load_imf.cpp
+++ b/soundlib/Load_imf.cpp
@@ -14,11 +14,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED IMFChannel
+struct IMFChannel
 {
 	char  name[12];	// Channel name (ASCIIZ-String, max 11 chars)
 	uint8 chorus;	// Default chorus
@@ -27,42 +23,33 @@ struct PACKED IMFChannel
 	uint8 status;	// Channel status: 0 = enabled, 1 = mute, 2 = disabled (ignore effects!)
 };
 
-STATIC_ASSERT(sizeof(IMFChannel) == 16);
+MPT_BINARY_STRUCT(IMFChannel, 16)
 
-struct PACKED IMFFileHeader
+struct IMFFileHeader
 {
 	enum SongFlags
 	{
 		linearSlides = 0x01,
 	};
 
-	char   title[32];			// Songname (ASCIIZ-String, max. 31 chars)
-	uint16 ordNum;				// Number of orders saved
-	uint16 patNum;				// Number of patterns saved
-	uint16 insNum;				// Number of instruments saved
-	uint16 flags;				// See SongFlags
-	uint8  unused1[8];
-	uint8  tempo;				// Default tempo (Axx, 1...255)
-	uint8  bpm;					// Default beats per minute (BPM) (Txx, 32...255)
-	uint8  master;				// Default master volume (Vxx, 0...64)
-	uint8  amp;					// Amplification factor (mixing volume, 4...127)
-	uint8  unused2[8];
-	char   im10[4];				// 'IM10'
+	char     title[32];			// Songname (ASCIIZ-String, max. 31 chars)
+	uint16le ordNum;			// Number of orders saved
+	uint16le patNum;			// Number of patterns saved
+	uint16le insNum;			// Number of instruments saved
+	uint16le flags;				// See SongFlags
+	uint8le  unused1[8];
+	uint8le  tempo;				// Default tempo (Axx, 1...255)
+	uint8le  bpm;				// Default beats per minute (BPM) (Txx, 32...255)
+	uint8le  master;			// Default master volume (Vxx, 0...64)
+	uint8le  amp;				// Amplification factor (mixing volume, 4...127)
+	uint8le  unused2[8];
+	char     im10[4];			// 'IM10'
 	IMFChannel channels[32];	// Channel settings
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(ordNum);
-		SwapBytesLE(patNum);
-		SwapBytesLE(insNum);
-		SwapBytesLE(flags);
-	}
 };
 
-STATIC_ASSERT(sizeof(IMFFileHeader) == 576);
+MPT_BINARY_STRUCT(IMFFileHeader, 576)
 
-struct PACKED IMFEnvelope
+struct IMFEnvelope
 {
 	enum EnvFlags
 	{
@@ -73,23 +60,23 @@ struct PACKED IMFEnvelope
 
 	uint8 points;		// Number of envelope points
 	uint8 sustain;		// Envelope sustain point
-	uint8 loop_start;	// Envelope loop start point
-	uint8 loop_end;		// Envelope loop end point
+	uint8 loopStart;	// Envelope loop start point
+	uint8 loopEnd;		// Envelope loop end point
 	uint8 flags;		// See EnvFlags
 	uint8 unused[3];
 };
 
-STATIC_ASSERT(sizeof(IMFEnvelope) == 8);
+MPT_BINARY_STRUCT(IMFEnvelope, 8)
 
-struct PACKED IMFEnvNode
+struct IMFEnvNode
 {
-	uint16 tick;
-	uint16 value;
+	uint16le tick;
+	uint16le value;
 };
 
-STATIC_ASSERT(sizeof(IMFEnvNode) == 4);
+MPT_BINARY_STRUCT(IMFEnvNode, 4)
 
-struct PACKED IMFInstrument
+struct IMFInstrument
 {
 	enum EnvTypes
 	{
@@ -98,14 +85,14 @@ struct PACKED IMFInstrument
 		filterEnv = 2,
 	};
 
-	char  name[32];		// Inst. name (ASCIIZ-String, max. 31 chars)
-	uint8 map[120];		// Multisample settings
-	uint8 unused[8];
-	IMFEnvNode nodes[3][16];
+	char        name[32];	// Inst. name (ASCIIZ-String, max. 31 chars)
+	uint8le     map[120];	// Multisample settings
+	uint8le     unused[8];
+	IMFEnvNode  nodes[3][16];
 	IMFEnvelope env[3];
-	uint16 fadeout;		// Fadeout rate (0...0FFFH)
-	uint16 smpNum;		// Number of samples in instrument
-	char   ii10[4];		// 'II10'
+	uint16le    fadeout;	// Fadeout rate (0...0FFFH)
+	uint16le    smpNum;		// Number of samples in instrument
+	char        ii10[4];	// 'II10'
 
 	void ConvertEnvelope(InstrumentEnvelope &mptEnv, EnvTypes e) const
 	{
@@ -116,14 +103,14 @@ struct PACKED IMFInstrument
 		mptEnv.dwFlags.set(ENV_LOOP, (env[e].flags & 4) != 0);
 
 		mptEnv.resize(Clamp(env[e].points, uint8(2), uint8(16)));
-		mptEnv.nLoopStart = env[e].loop_start;
-		mptEnv.nLoopEnd = env[e].loop_end;
+		mptEnv.nLoopStart = env[e].loopStart;
+		mptEnv.nLoopEnd = env[e].loopEnd;
 		mptEnv.nSustainStart = mptEnv.nSustainEnd = env[e].sustain;
 
 		uint16 minTick = 0; // minimum tick value for next node
 		for(uint32 n = 0; n < mptEnv.size(); n++)
 		{
-			minTick = mptEnv[n].tick = std::max(minTick, nodes[e][n].tick);
+			minTick = mptEnv[n].tick = std::max<uint16>(minTick, nodes[e][n].tick);
 			minTick++;
 			mptEnv[n].value = static_cast<uint8>(std::min(nodes[e][n].value >> shift, ENVELOPE_MAX));
 		}
@@ -155,26 +142,11 @@ struct PACKED IMFInstrument
 		if(!mptIns.VolEnv.dwFlags[ENV_ENABLED] && !mptIns.nFadeOut)
 			mptIns.nFadeOut = 8192;
 	}
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(size_t e = 0; e < CountOf(nodes); e++)
-		{
-			for(size_t n = 0; n < CountOf(nodes[0]); n++)
-			{
-				SwapBytesLE(nodes[e][n].tick);
-				SwapBytesLE(nodes[e][n].value);
-			}
-		}
-		SwapBytesLE(fadeout);
-		SwapBytesLE(smpNum);
-	}
 };
 
-STATIC_ASSERT(sizeof(IMFInstrument) == 384);
+MPT_BINARY_STRUCT(IMFInstrument, 384)
 
-struct PACKED IMFSample
+struct IMFSample
 {
 	enum SampleFlags
 	{
@@ -184,20 +156,20 @@ struct PACKED IMFSample
 		smpPanning		= 0x08,
 	};
 
-	char   filename[13];	// Sample filename (12345678.ABC) */
-	uint8  unused1[3];
-	uint32 length;			// Length (in bytes)
-	uint32 loopStart;		// Loop start (in bytes)
-	uint32 loopEnd;			// Loop end (in bytes)
-	uint32 c5Speed;			// Samplerate
-	uint8  volume;			// Default volume (0...64)
-	uint8  panning;			// Default pan (0...255)
-	uint8  unused2[14];
-	uint8  flags;			// Sample flags
-	uint8  unused3[5];
-	uint16 ems;				// Reserved for internal usage
-	uint32 dram;			// Reserved for internal usage
-	char   is10[4];			// 'IS10'
+	char     filename[13];	// Sample filename (12345678.ABC) */
+	uint8le  unused1[3];
+	uint32le length;		// Length (in bytes)
+	uint32le loopStart;		// Loop start (in bytes)
+	uint32le loopEnd;		// Loop end (in bytes)
+	uint32le c5Speed;		// Samplerate
+	uint8le  volume;		// Default volume (0...64)
+	uint8le  panning;		// Default pan (0...255)
+	uint8le  unused2[14];
+	uint8le  flags;			// Sample flags
+	uint8le  unused3[5];
+	uint16le ems;			// Reserved for internal usage
+	uint32le dram;			// Reserved for internal usage
+	char     is10[4];		// 'IS10'
 
 	// Convert an IMFSample to OpenMPT's internal sample representation.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -225,24 +197,12 @@ struct PACKED IMFSample
 		if(flags & smpPanning)
 			mptSmp.uFlags.set(CHN_PANNING);
 	}
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(c5Speed);
-	}
 };
 
-STATIC_ASSERT(sizeof(IMFSample) == 64);
+MPT_BINARY_STRUCT(IMFSample, 64)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
-static const uint8 imfEffects[] =
+static const EffectCommand imfEffects[] =
 {
 	CMD_NONE,
 	CMD_SPEED,			// 0x01 1xx Set Tempo
@@ -293,7 +253,6 @@ static const uint8 imfEffects[] =
 };
 
 static void ImportIMFEffect(ModCommand &m)
-//----------------------------------------
 {
 	uint8 n;
 	// fix some of them
@@ -381,7 +340,7 @@ static void ImportIMFEffect(ModCommand &m)
 			m.param = n | (m.param & 0x0F);
 		break;
 	}
-	m.command = (m.command < CountOf(imfEffects)) ? imfEffects[m.command] : (int)CMD_NONE;
+	m.command = (m.command < CountOf(imfEffects)) ? imfEffects[m.command] : CMD_NONE;
 	if(m.command == CMD_VOLUME && m.volcmd == VOLCMD_NONE)
 	{
 		m.volcmd = VOLCMD_VOLUME;
@@ -391,19 +350,80 @@ static void ImportIMFEffect(ModCommand &m)
 	}
 }
 
+
+static bool ValidateHeader(const IMFFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.im10, "IM10", 4)
+		|| fileHeader.ordNum > 256
+		|| fileHeader.insNum >= MAX_INSTRUMENTS
+		)
+	{
+		return false;
+	}
+	bool channelFound = false;
+	for(uint8 chn = 0; chn < 32; chn++)
+	{
+		switch(fileHeader.channels[chn].status)
+		{
+		case 0: // enabled; don't worry about it
+			channelFound = true;
+			break;
+		case 1: // mute
+			channelFound = true;
+			break;
+		case 2: // disabled
+			// nothing
+			break;
+		default: // uhhhh.... freak out
+			return false;
+		}
+	}
+	if(!channelFound)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const IMFFileHeader &fileHeader)
+{
+	MPT_UNREFERENCED_PARAMETER(fileHeader);
+	return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize)
+{
+	IMFFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
 bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	IMFFileHeader fileHeader;
 	file.Rewind();
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.im10, "IM10", 4)
-		|| fileHeader.ordNum > 256
-		|| fileHeader.insNum >= MAX_INSTRUMENTS)
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
 	{
 		return false;
 	}
-
 
 	// Read channel configuration
 	std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled
@@ -437,7 +457,9 @@ bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
 	if(!detectedChannels)
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -463,15 +485,19 @@ bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
 	m_SongFlags = (fileHeader.flags & IMFFileHeader::linearSlides) ? SONG_LINEARSLIDES : SongFlags(0);
 	m_nDefaultSpeed = fileHeader.tempo;
 	m_nDefaultTempo.Set(fileHeader.bpm);
-	m_nDefaultGlobalVolume = Clamp(fileHeader.master, uint8(0), uint8(64)) * 4;
-	m_nSamplePreAmp = Clamp(fileHeader.amp, uint8(4), uint8(127));
+	m_nDefaultGlobalVolume = Clamp<uint8, uint8>(fileHeader.master, 0, 64) * 4;
+	m_nSamplePreAmp = Clamp<uint8, uint8>(fileHeader.amp, 4, 127);
 
 	m_nInstruments = fileHeader.insNum;
 	m_nSamples = 0; // Will be incremented later
 
-	Order.ReadAsByte(file, 256, fileHeader.ordNum, uint16_max, 0xFF);
+	uint8 orders[256];
+	file.ReadArray(orders);
+	ReadOrderFromArray(Order(), orders, fileHeader.ordNum, uint16_max, 0xFF);
 
 	// Read patterns
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.patNum);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.patNum; pat++)
 	{
 		const uint16 length = file.ReadUint16LE(), numRows = file.ReadUint16LE();
@@ -575,7 +601,7 @@ bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		ModInstrument *instr = AllocateInstrument(ins + 1);
 		IMFInstrument instrumentHeader;
-		if(!file.ReadConvertEndianness(instrumentHeader) || instr == nullptr)
+		if(!file.ReadStruct(instrumentHeader) || instr == nullptr)
 		{
 			continue;
 		}
@@ -589,7 +615,7 @@ bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
 		for(SAMPLEINDEX smp = 0; smp < instrumentHeader.smpNum; smp++)
 		{
 			IMFSample sampleHeader;
-			file.ReadConvertEndianness(sampleHeader);
+			file.ReadStruct(sampleHeader);
 
 			const SAMPLEINDEX smpID = firstSample + smp;
 			if(memcmp(sampleHeader.is10, "IS10", 4) || smpID >= MAX_SAMPLES)
@@ -601,7 +627,7 @@ bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
 			ModSample &sample = Samples[smpID];
 
 			sampleHeader.ConvertToMPT(sample);
-			strcpy(m_szNames[smpID], sample.filename);
+			mpt::String::Copy(m_szNames[smpID], sample.filename);
 
 			if(sampleHeader.length)
 			{
diff --git a/soundlib/Load_it.cpp b/soundlib/Load_it.cpp
index b34932e..dc0a7a6 100644
--- a/soundlib/Load_it.cpp
+++ b/soundlib/Load_it.cpp
@@ -14,7 +14,7 @@
 #include "tuningcollection.h"
 #include "mod_specifications.h"
 #ifdef MODPLUG_TRACKER
-#include "../mptrack/moddoc.h"
+#include "../mptrack/Moddoc.h"
 #include "../mptrack/TrackerSettings.h"
 #endif // MODPLUG_TRACKER
 #ifdef MPT_EXTERNAL_SAMPLES
@@ -60,7 +60,6 @@ MPTM version history for cwtv-field in "IT" header (only for MPTM files!):
 #ifndef MODPLUG_NO_FILESAVE
 
 static bool AreNonDefaultTuningsUsed(CSoundFile& sf)
-//--------------------------------------------------
 {
 	const INSTRUMENTINDEX iCount = sf.GetNumInstruments();
 	for(INSTRUMENTINDEX i = 1; i <= iCount; i++)
@@ -71,10 +70,12 @@ static bool AreNonDefaultTuningsUsed(CSoundFile& sf)
 	return false;
 }
 
-static void WriteTuningCollection(std::ostream& oStrm, const CTuningCollection& tc) {tc.Serialize(oStrm);}
+static void WriteTuningCollection(std::ostream& oStrm, const CTuningCollection& tc)
+{
+	tc.Serialize(oStrm, "Tune specific tunings");
+}
 
 static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
-//-------------------------------------------------------------------
 {
 	if(sf.GetNumInstruments() > 0)
 	{
@@ -87,9 +88,7 @@ static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
 		//T1 1 T2 2 1 1 1 2 2 2
 
 		//Creating the tuning address <-> tuning id number map.
-		typedef std::map<CTuning*, uint16> TNTS_MAP;
-		typedef TNTS_MAP::iterator TNTS_MAP_ITER;
-		TNTS_MAP tNameToShort_Map;
+		std::map<CTuning*, uint16> tNameToShort_Map;
 
 		unsigned short figMap = 0;
 		for(INSTRUMENTINDEX i = 1; i <= sf.GetNumInstruments(); i++)
@@ -99,7 +98,7 @@ static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
 			{
 				pTuning = sf.Instruments[i]->pTuning;
 			}
-			TNTS_MAP_ITER iter = tNameToShort_Map.find(pTuning);
+			auto iter = tNameToShort_Map.find(pTuning);
 			if(iter != tNameToShort_Map.end())
 				continue; //Tuning already mapped.
 
@@ -111,14 +110,14 @@ static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
 		//the addresses.
 		const uint16 tuningMapSize = static_cast<uint16>(tNameToShort_Map.size());
 		mpt::IO::WriteIntLE<uint16>(oStrm, tuningMapSize);
-		for(TNTS_MAP_ITER iter = tNameToShort_Map.begin(); iter != tNameToShort_Map.end(); iter++)
+		for(auto &iter : tNameToShort_Map)
 		{
-			if(iter->first)
-				mpt::IO::WriteSizedStringLE<uint8>(oStrm, iter->first->GetName());
+			if(iter.first)
+				mpt::IO::WriteSizedStringLE<uint8>(oStrm, iter.first->GetName());
 			else //Case: Using original IT tuning.
 				mpt::IO::WriteSizedStringLE<uint8>(oStrm, "->MPT_ORIGINAL_IT<-");
 
-			mpt::IO::WriteIntLE<uint16>(oStrm, iter->second);
+			mpt::IO::WriteIntLE<uint16>(oStrm, iter.second);
 		}
 
 		//Writing tuning data for instruments.
@@ -129,7 +128,7 @@ static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
 			{
 				pTuning = sf.Instruments[i]->pTuning;
 			}
-			TNTS_MAP_ITER iter = tNameToShort_Map.find(pTuning);
+			auto iter = tNameToShort_Map.find(pTuning);
 			if(iter == tNameToShort_Map.end()) //Should never happen
 			{
 				sf.AddToLog("Error: 210807_1");
@@ -143,18 +142,22 @@ static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
 #endif // MODPLUG_NO_FILESAVE
 
 
-static void ReadTuningCollection(std::istream& iStrm, CTuningCollection& tc, const size_t) {tc.Deserialize(iStrm);}
+static void ReadTuningCollection(std::istream& iStrm, CTuningCollection& tc, const size_t)
+{
+	std::string name;
+	tc.Deserialize(iStrm, name);
+}
+
 
 template<class TUNNUMTYPE, class STRSIZETYPE>
 static bool ReadTuningMapTemplate(std::istream& iStrm, std::map<uint16, std::string>& shortToTNameMap, const size_t maxNum = 500)
-//-------------------------------------------------------------------------------------------------------------------------------
 {
 	TUNNUMTYPE numTuning = 0;
-	mpt::IO::ReadIntLE<uint16>(iStrm, numTuning);
+	mpt::IO::ReadIntLE<TUNNUMTYPE>(iStrm, numTuning);
 	if(numTuning > maxNum)
 		return true;
 
-	for(size_t i = 0; i<numTuning; i++)
+	for(size_t i = 0; i < numTuning; i++)
 	{
 		std::string temp;
 		uint16 ui = 0;
@@ -171,21 +174,24 @@ static bool ReadTuningMapTemplate(std::istream& iStrm, std::map<uint16, std::str
 }
 
 
-static void ReadTuningMap(std::istream& iStrm, CSoundFile& csf, const size_t = 0)
-//-------------------------------------------------------------------------------
+static void ReadTuningMapImpl(std::istream& iStrm, CSoundFile& csf, const size_t = 0, bool old = false)
 {
-	typedef std::map<uint16, std::string> MAP;
-	typedef MAP::iterator MAP_ITER;
-	MAP shortToTNameMap;
-	ReadTuningMapTemplate<uint16, uint8>(iStrm, shortToTNameMap);
+	std::map<uint16, std::string> shortToTNameMap;
+	if(old)
+	{
+		ReadTuningMapTemplate<uint32, uint32>(iStrm, shortToTNameMap);
+	} else
+	{
+		ReadTuningMapTemplate<uint16, uint8>(iStrm, shortToTNameMap);
+	}
 
-	//Read & set tunings for instruments
+	// Read & set tunings for instruments
 	std::vector<std::string> notFoundTunings;
 	for(INSTRUMENTINDEX i = 1; i<=csf.GetNumInstruments(); i++)
 	{
 		uint16 ui = 0;
 		mpt::IO::ReadIntLE<uint16>(iStrm, ui);
-		MAP_ITER iter = shortToTNameMap.find(ui);
+		auto iter = shortToTNameMap.find(ui);
 		if(csf.Instruments[i] && iter != shortToTNameMap.end())
 		{
 			const std::string str = iter->second;
@@ -201,31 +207,59 @@ static void ReadTuningMap(std::istream& iStrm, CSoundFile& csf, const size_t = 0
 				continue;
 
 #ifdef MODPLUG_TRACKER
-			csf.Instruments[i]->pTuning = csf.GetLocalTunings().GetTuning(str);
-			if(csf.Instruments[i]->pTuning)
-				continue;
+			CTuning *localTuning = TrackerSettings::Instance().oldLocalTunings->GetTuning(str);
+			if(localTuning)
+			{
+				CTuning* pNewTuning = new CTuning(*localTuning);
+				if(!csf.GetTuneSpecificTunings().AddTuning(pNewTuning))
+				{
+					csf.AddToLog("Local tunings are deprecated and no longer supported. Tuning '" + str + "' found in Local tunings has been copied to Tune-specific tunings and will be saved in the module file.");
+					csf.Instruments[i]->pTuning = pNewTuning;
+					if(csf.GetpModDoc() != nullptr)
+					{
+						csf.GetpModDoc()->SetModified();
+					}
+					continue;
+				} else
+				{
+					delete pNewTuning;
+					csf.AddToLog("Copying Local tuning '" + str + "' to Tune-specific tunings failed.");
+				}
+			}
 #endif
 
-			csf.Instruments[i]->pTuning = csf.GetBuiltInTunings().GetTuning(str);
-			if(csf.Instruments[i]->pTuning)
-				continue;
-
-			if(str == "TET12" && csf.GetBuiltInTunings().GetNumTunings() > 0)
-				csf.Instruments[i]->pTuning = &csf.GetBuiltInTunings().GetTuning(0);
-
-			if(csf.Instruments[i]->pTuning)
-				continue;
+			if(str == "12TET [[fs15 1.17.02.49]]" || str == "12TET")
+			{
+				CTuning* pNewTuning = csf.CreateTuning12TET(str);
+				if(!csf.GetTuneSpecificTunings().AddTuning(pNewTuning))
+				{
+					#ifdef MODPLUG_TRACKER
+						csf.AddToLog("Built-in tunings will no longer be used. Tuning '" + str + "' has been copied to Tune-specific tunings and will be saved in the module file.");
+						csf.Instruments[i]->pTuning = pNewTuning;
+						if(csf.GetpModDoc() != nullptr)
+						{
+							csf.GetpModDoc()->SetModified();
+						}
+					#endif
+					continue;
+				} else
+				{
+					delete pNewTuning;
+					#ifdef MODPLUG_TRACKER
+						csf.AddToLog("Copying Built-in tuning '" + str + "' to Tune-specific tunings failed.");
+					#endif
+				}
+			}
 
-			//Checking if not found tuning already noticed.
+			// Checking if not found tuning already noticed.
 			if(std::find(notFoundTunings.begin(), notFoundTunings.end(), str) == notFoundTunings.end())
 			{
 				notFoundTunings.push_back(str);
-				std::string erm = std::string("Tuning ") + str + std::string(" used by the module was not found.");
-				csf.AddToLog(erm);
+				csf.AddToLog("Tuning '" + str + "' used by the module was not found.");
 #ifdef MODPLUG_TRACKER
 				if(csf.GetpModDoc() != nullptr)
 				{
-					csf.GetpModDoc()->SetModified(); //The tuning is changed so the modified flag is set.
+					csf.GetpModDoc()->SetModified(); // The tuning is changed so the modified flag is set.
 				}
 #endif // MODPLUG_TRACKER
 
@@ -244,29 +278,23 @@ static void ReadTuningMap(std::istream& iStrm, CSoundFile& csf, const size_t = 0
 }
 
 
-
-//////////////////////////////////////////////////////////
-// Impulse Tracker IT file support
-
-#ifndef MODPLUG_NO_FILESAVE
-
-static uint8 ConvertVolParam(const ModCommand *m)
-//-----------------------------------------------
+static void ReadTuningMap(std::istream& iStrm, CSoundFile& csf, const size_t dummy = 0)
 {
-	return MIN(m->vol, 9);
+	ReadTuningMapImpl(iStrm, csf, dummy, false);
 }
 
-#endif // MODPLUG_NO_FILESAVE
+
+//////////////////////////////////////////////////////////
+// Impulse Tracker IT file support
 
 
 size_t CSoundFile::ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers)
-//-----------------------------------------------------------------------------------
 {
 	if(trkvers < 0x0200)
 	{
 		// Load old format (IT 1.xx) instrument (early IT 2.xx modules may have cmwt set to 1.00 for backwards compatibility)
 		ITOldInstrument instrumentHeader;
-		if(!file.ReadConvertEndianness(instrumentHeader))
+		if(!file.ReadStruct(instrumentHeader))
 		{
 			return 0;
 		} else
@@ -281,7 +309,6 @@ size_t CSoundFile::ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trk
 		// Try loading extended instrument... instSize will differ between normal and extended instruments.
 		ITInstrumentEx instrumentHeader;
 		file.ReadStructPartial(instrumentHeader);
-		instrumentHeader.ConvertEndianness();
 		size_t instSize = instrumentHeader.ConvertToMPT(ins, GetType());
 		file.Seek(offset + instSize);
 
@@ -309,7 +336,6 @@ size_t CSoundFile::ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trk
 
 
 static void CopyPatternName(CPattern &pattern, FileReader &file)
-//--------------------------------------------------------------
 {
 	char name[MAX_PATTERNNAME] = "";
 	file.ReadString<mpt::String::maybeNullTerminated>(name, MAX_PATTERNNAME);
@@ -325,7 +351,7 @@ struct SchismVersionFromDate
 	static const int32 yy = y - mm / 10;
 	static const int32 date = yy * 365 + yy / 4 - yy / 100 + yy / 400 + (mm * 306 + 5) / 10 + (d - 1);
 
-	static int32 Version()
+	static constexpr int32 Version()
 	{
 		return 0x1050 + date - SchismVersionFromDate<2009, 10, 31>::date;
 	}
@@ -333,8 +359,7 @@ struct SchismVersionFromDate
 
 
 // Get version of Schism Tracker that was used to create an IT/S3M file.
-std::string CSoundFile::GetSchismTrackerVersion(uint16 cwtv)
-//----------------------------------------------------------
+mpt::ustring CSoundFile::GetSchismTrackerVersion(uint16 cwtv)
 {
 	// Schism Tracker version information in a nutshell:
 	// < 0x020: a proper version (files saved by such versions are likely very rare)
@@ -343,7 +368,7 @@ std::string CSoundFile::GetSchismTrackerVersion(uint16 cwtv)
 	// > 0x050: the number of days since 2009-10-31
 
 	cwtv &= 0xFFF;
-	std::string version;
+	mpt::ustring version;
 	if(cwtv > 0x050)
 	{
 		int32 date = SchismVersionFromDate<2009, 10, 31>::date + cwtv - 0x050;
@@ -355,32 +380,70 @@ std::string CSoundFile::GetSchismTrackerVersion(uint16 cwtv)
 			ddd = date - (365 * y + y / 4 - y / 100 + y / 400);
 		}
 		int32 mi = (100 * ddd + 52) / 3060;
-		version = mpt::String::Print("Schism Tracker %1-%2-%3",
-			mpt::fmt::dec0<4>(y + (mi + 2) / 12),
-			mpt::fmt::dec0<2>((mi + 2) % 12 + 1),
-			mpt::fmt::dec0<2>(ddd - (mi * 306 + 5) / 10 + 1));
+		version = mpt::format(MPT_USTRING("Schism Tracker %1-%2-%3"))(
+			mpt::ufmt::dec0<4>(y + (mi + 2) / 12),
+			mpt::ufmt::dec0<2>((mi + 2) % 12 + 1),
+			mpt::ufmt::dec0<2>(ddd - (mi * 306 + 5) / 10 + 1));
 	} else
 	{
-		version = mpt::String::Print("Schism Tracker 0.%1", mpt::fmt::hex(cwtv));
+		version = mpt::format(MPT_USTRING("Schism Tracker 0.%1"))(mpt::ufmt::hex(cwtv));
 	}
 	return version;
 }
 
 
+static bool ValidateHeader(const ITFileHeader &fileHeader)
+{
+	if((std::memcmp(fileHeader.id, "IMPM", 4) && std::memcmp(fileHeader.id, "tpm.", 4))
+		|| fileHeader.insnum > 0xFF
+		|| fileHeader.smpnum >= MAX_SAMPLES
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITFileHeader &fileHeader)
+{
+	return fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize)
+{
+	ITFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
 bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
-//------------------------------------------------------------------
 {
 	file.Rewind();
 
 	ITFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| (memcmp(fileHeader.id, "IMPM", 4) && memcmp(fileHeader.id, "tpm.", 4))
-		|| fileHeader.insnum > 0xFF
-		|| fileHeader.smpnum >= MAX_SAMPLES
-		|| !file.CanRead(fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4))
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -390,35 +453,47 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	bool interpretModPlugMade = false;
 
 	// OpenMPT crap at the end of file
-	file.Seek(file.GetLength() - 4);
-	size_t mptStartPos = file.ReadUint32LE();
-	if(mptStartPos >= file.GetLength() || mptStartPos < 0x100)
-	{
-		mptStartPos = file.GetLength();
-	}
+	size_t mptStartPos = 0;
 
 	if(!memcmp(fileHeader.id, "tpm.", 4))
 	{
-		// Legacy MPTM files (old 1.17.02.xx releases)
+		// Legacy MPTM files (old 1.17.02.4x releases)
 		SetType(MOD_TYPE_MPT);
+		file.Seek(file.GetLength() - 4);
+		mptStartPos = file.ReadUint32LE();
 	} else
 	{
-		if(mptStartPos <= file.GetLength() - 3 && fileHeader.cwtv > 0x888 && fileHeader.cwtv <= 0xFFF)
+		if(fileHeader.cwtv > 0x888 && fileHeader.cwtv <= 0xFFF)
 		{
-			file.Seek(mptStartPos);
-			if(file.ReadMagic("228"))
-				SetType(MOD_TYPE_MPT);
+			file.Seek(file.GetLength() - 4);
+			mptStartPos = file.ReadUint32LE();
+			if(mptStartPos >= 0x100 && mptStartPos < file.GetLength())
+			{
+				if(file.Seek(mptStartPos) && file.ReadMagic("228"))
+				{
+					SetType(MOD_TYPE_MPT);
+
+					if(fileHeader.cwtv >= verMptFileVerLoadLimit)
+					{
+						AddToLog(str_LoadingIncompatibleVersion);
+						return false;
+					} else if(fileHeader.cwtv > verMptFileVer)
+					{
+						AddToLog(str_LoadingMoreRecentVersion);
+					}
+				}
+			}
 		}
 
 		if(GetType() == MOD_TYPE_IT)
 		{
-			// Which tracker was used to made this?
+			// Which tracker was used to make this?
 			if((fileHeader.cwtv & 0xF000) == 0x5000)
 			{
 				// OpenMPT Version number (Major.Minor)
 				// This will only be interpreted as "made with ModPlug" (i.e. disable compatible playback etc) if the "reserved" field is set to "OMPT" - else, compatibility was used.
 				m_dwLastSavedWithVersion = (fileHeader.cwtv & 0x0FFF) << 16;
-				if(!memcmp(fileHeader.reserved, "OMPT", 4))
+				if(!memcmp(&fileHeader.reserved, "OMPT", 4))
 					interpretModPlugMade = true;
 			} else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888)
 			{
@@ -426,53 +501,39 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 				// Exact version number will be determined later.
 				interpretModPlugMade = true;
 				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00);
-			} else if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
+			} else if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0)
 			{
 				if(memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != nullptr)
 				{
-					// ModPlug Tracker 1.16 (semi-raped IT format)
+					// ModPlug Tracker 1.16 (semi-raped IT format) or BeRoTracker (will be determined later)
 					m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00);
-					m_madeWithTracker = "ModPlug Tracker 1.09 - 1.16";
+					m_madeWithTracker = MPT_USTRING("ModPlug Tracker 1.09 - 1.16");
 				} else
 				{
 					// OpenMPT 1.17 disguised as this in compatible mode,
 					// but never writes 0xFF in the pan map for unused channels (which is an invalid value).
 					m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00);
-					m_madeWithTracker = "OpenMPT 1.17 (compatibility export)";
+					m_madeWithTracker = MPT_USTRING("OpenMPT 1.17 (compatibility export)");
 				}
 				interpretModPlugMade = true;
-			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
+			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && fileHeader.reserved == 0)
 			{
 				// ModPlug Tracker b3.3 - 1.09, instruments 557 bytes apart
 				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 09, 00, 00);
-				m_madeWithTracker = "ModPlug Tracker b3.3 - 1.09";
+				m_madeWithTracker = MPT_USTRING("ModPlug Tracker b3.3 - 1.09");
 				interpretModPlugMade = true;
-			} else if(fileHeader.cwtv == 0x0300 && fileHeader.cmwt == 0x0300 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4) && fileHeader.ordnum == 256 && fileHeader.sep == 128 && fileHeader.pwd == 0)
+			} else if(fileHeader.cwtv == 0x0300 && fileHeader.cmwt == 0x0300 && fileHeader.reserved == 0 && fileHeader.ordnum == 256 && fileHeader.sep == 128 && fileHeader.pwd == 0)
 			{
 				// A rare variant used from OpenMPT 1.17.02.20 (r113) to 1.17.02.25 (r121), found e.g. in xTr1m-SD.it
 				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 02, 20);
 				interpretModPlugMade = true;
 			}
-		} else // case: type == MOD_TYPE_MPT
-		{
-			if (fileHeader.cwtv >= verMptFileVerLoadLimit)
-			{
-				AddToLog(str_LoadingIncompatibleVersion);
-				return false;
-			}
-			else if (fileHeader.cwtv > verMptFileVer)
-			{
-				AddToLog(str_LoadingMoreRecentVersion);
-			}
 		}
 	}
 
-	if(GetType() == MOD_TYPE_IT) mptStartPos = file.GetLength();
-
 	m_SongFlags.set(SONG_LINEARSLIDES, (fileHeader.flags & ITFileHeader::linearSlides) != 0);
 	m_SongFlags.set(SONG_ITOLDEFFECTS, (fileHeader.flags & ITFileHeader::itOldEffects) != 0);
 	m_SongFlags.set(SONG_ITCOMPATGXX, (fileHeader.flags & ITFileHeader::itCompatGxx) != 0);
-	m_SongFlags.set(SONG_EMBEDMIDICFG, (fileHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (fileHeader.special & ITFileHeader::embedMIDIConfiguration));
 	m_SongFlags.set(SONG_EXFILTERRANGE, (fileHeader.flags & ITFileHeader::extendedFilterRange) != 0);
 
 	mpt::String::Read<mpt::String::spacePadded>(m_songName, fileHeader.songname);
@@ -501,14 +562,14 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	m_nDefaultGlobalVolume = fileHeader.globalvol << 1;
 	if(m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
 	if(fileHeader.speed) m_nDefaultSpeed = fileHeader.speed;
-	m_nDefaultTempo.Set(std::max(uint8(31), fileHeader.tempo));
-	m_nSamplePreAmp = std::min(fileHeader.mv, uint8(128));
+	m_nDefaultTempo.Set(std::max<uint8>(31, fileHeader.tempo));
+	m_nSamplePreAmp = std::min<uint8>(fileHeader.mv, 128);
 
 	// Reading Channels Pan Positions
 	for(CHANNELINDEX i = 0; i < 64; i++) if(fileHeader.chnpan[i] != 0xFF)
 	{
 		ChnSettings[i].Reset();
-		ChnSettings[i].nVolume = Clamp(fileHeader.chnvol[i], uint8(0), uint8(64));
+		ChnSettings[i].nVolume = Clamp<uint8, uint8>(fileHeader.chnvol[i], 0, 64);
 		if(fileHeader.chnpan[i] & 0x80) ChnSettings[i].dwFlags.set(CHN_MUTE);
 		uint8 n = fileHeader.chnpan[i] & 0x7F;
 		if(n <= 64) ChnSettings[i].nPan = n * 4;
@@ -517,25 +578,25 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 
 	// Reading orders
 	file.Seek(sizeof(ITFileHeader));
-	if(GetType() == MOD_TYPE_IT)
-	{
-		Order.ReadAsByte(file, fileHeader.ordnum, fileHeader.ordnum, 0xFF, 0xFE);
+	if(GetType() == MOD_TYPE_MPT && fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D)
+	{
+		// Deprecated format used for MPTm files created with OpenMPT 1.17.02.46 - 1.17.02.48.
+		uint16 version = file.ReadUint16LE();
+		if(version != 0)
+			return false;
+		uint32 numOrd = file.ReadUint32LE();
+		if(numOrd > ModSpecs::mptm.ordersMax || !ReadOrderFromFile<uint32le>(Order(), file, numOrd))
+			return false;
 	} else
 	{
-		if(fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D)
-		{
-			Order.Deserialize(file);
-		} else
-		{
-			Order.ReadAsByte(file, fileHeader.ordnum, fileHeader.ordnum, 0xFF, 0xFE);
-		}
+		ReadOrderFromFile<uint8>(Order(), file, fileHeader.ordnum, 0xFF, 0xFE);
 	}
 
 	// Reading instrument, sample and pattern offsets
-	std::vector<uint32> insPos, smpPos, patPos;
-	if(!file.ReadVectorLE(insPos, fileHeader.insnum)
-		|| !file.ReadVectorLE(smpPos, fileHeader.smpnum)
-		|| !file.ReadVectorLE(patPos, fileHeader.patnum))
+	std::vector<uint32le> insPos, smpPos, patPos;
+	if(!file.ReadVector(insPos, fileHeader.insnum)
+		|| !file.ReadVector(smpPos, fileHeader.smpnum)
+		|| !file.ReadVector(patPos, fileHeader.patnum))
 	{
 		return false;
 	}
@@ -545,28 +606,25 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	// as some early versions of Schism Tracker set the history flag, but didn't save anything.
 	// We will consider the history invalid if it ends after the first parapointer.
 	uint32 minPtr = Util::MaxValueOfType(minPtr);
-	for(uint16 n = 0; n < fileHeader.insnum; n++)
+	for(uint32 pos : insPos)
 	{
-		if(insPos[n] > 0) minPtr = std::min(minPtr, insPos[n]);
+		if(pos > 0) minPtr = std::min(minPtr, pos);
 	}
-
-	for(uint16 n = 0; n < fileHeader.smpnum; n++)
+	for(uint32 pos : smpPos)
 	{
-		if(smpPos[n] > 0) minPtr = std::min(minPtr, smpPos[n]);
+		if(pos > 0) minPtr = std::min(minPtr, pos);
 	}
-
-	for(uint16 n = 0; n < fileHeader.patnum; n++)
+	for(uint32 pos : patPos)
 	{
-		if(patPos[n] > 0) minPtr = std::min(minPtr, patPos[n]);
+		if(pos > 0) minPtr = std::min(minPtr, pos);
 	}
-
 	if(fileHeader.special & ITFileHeader::embedSongMessage)
 	{
-		minPtr = std::min(minPtr, fileHeader.msgoffset);
+		minPtr = std::min<uint32>(minPtr, fileHeader.msgoffset);
 	}
 
 	const bool possiblyUNMO3 = fileHeader.cmwt == 0x0214 && fileHeader.cwtv == 0x0214 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0
-		&& fileHeader.pwd == 0 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4) && (fileHeader.flags & (ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig)) == 0;
+		&& fileHeader.pwd == 0 && fileHeader.reserved == 0 && (fileHeader.flags & (ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig)) == 0;
 
 	if(possiblyUNMO3 && fileHeader.insnum == 0 && fileHeader.smpnum > 0 && file.GetPosition() + 4 * smpPos.size() + 2 <= minPtr)
 	{
@@ -586,7 +644,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 		}
 		if(oldUNMO3)
 		{
-			m_madeWithTracker = "UNMO3 <= 2.4";
+			m_madeWithTracker = MPT_USTRING("UNMO3 <= 2.4");
 		}
 	}
 
@@ -602,22 +660,20 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 
 		if(file.CanRead(nflt * sizeof(ITHistoryStruct)) && file.GetPosition() + nflt * sizeof(ITHistoryStruct) <= minPtr)
 		{
-			m_FileHistory.reserve(nflt);
-			for(size_t n = 0; n < nflt; n++)
+			m_FileHistory.resize(nflt);
+			for(auto &mptHistory : m_FileHistory)
 			{
-				FileHistory mptHistory;
 				ITHistoryStruct itHistory;
-				file.ReadConvertEndianness(itHistory);
+				file.ReadStruct(itHistory);
 				itHistory.ConvertToMPT(mptHistory);
-				m_FileHistory.push_back(mptHistory);
 			}
 
 			if(possiblyUNMO3 && nflt == 0)
 			{
 				if(fileHeader.special & ITFileHeader::embedPatternHighlights)
-					m_madeWithTracker = "UNMO3 <= 2.4.0.1";	// Set together with MIDI macro embed flag
+					m_madeWithTracker = MPT_USTRING("UNMO3 <= 2.4.0.1");	// Set together with MIDI macro embed flag
 				else
-					m_madeWithTracker = "UNMO3";	// Either 2.4.0.2+ or no MIDI macros embedded
+					m_madeWithTracker = MPT_USTRING("UNMO3");	// Either 2.4.0.2+ or no MIDI macros embedded
 			}
 		} else
 		{
@@ -632,7 +688,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 		// Otherwise we end up here and might have to read the edit history length.
 		if(file.ReadUint16LE() == 0)
 		{
-			m_madeWithTracker = "UNMO3 <= 2.4";
+			m_madeWithTracker = MPT_USTRING("UNMO3 <= 2.4");
 		} else
 		{
 			// These were not zero bytes, but potentially belong to the upcoming MIDI config - need to skip back.
@@ -643,17 +699,16 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Reading MIDI Output & Macros
-	if(m_SongFlags[SONG_EMBEDMIDICFG] && file.ReadStruct<MIDIMacroConfigData>(m_MidiCfg))
+	bool hasMidiConfig = (fileHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (fileHeader.special & ITFileHeader::embedMIDIConfiguration);
+	if(hasMidiConfig && file.ReadStruct<MIDIMacroConfigData>(m_MidiCfg))
 	{
-			m_MidiCfg.Sanitize();
+		m_MidiCfg.Sanitize();
 	}
 
 	// Ignore MIDI data. Fixes some files like denonde.it that were made with old versions of Impulse Tracker (which didn't support Zxx filters) and have Zxx effects in the patterns.
 	if(fileHeader.cwtv < 0x0214)
 	{
-		MemsetZero(m_MidiCfg.szMidiSFXExt);
-		MemsetZero(m_MidiCfg.szMidiZXXExt);
-		m_SongFlags.set(SONG_EMBEDMIDICFG);
+		m_MidiCfg.ClearZxxMacros();
 	}
 
 	// Read pattern names: "PNAM"
@@ -694,7 +749,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	m_nInstruments = 0;
 	if(fileHeader.flags & ITFileHeader::instrumentMode)
 	{
-		m_nInstruments = std::min(fileHeader.insnum, INSTRUMENTINDEX(MAX_INSTRUMENTS - 1));
+		m_nInstruments = std::min<INSTRUMENTINDEX>(fileHeader.insnum, MAX_INSTRUMENTS - 1);
 	}
 	for(INSTRUMENTINDEX i = 0; i < GetNumInstruments(); i++)
 	{
@@ -722,12 +777,12 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	bool possibleXMconversion = false;
 
 	// Reading Samples
-	m_nSamples = std::min(fileHeader.smpnum, SAMPLEINDEX(MAX_SAMPLES - 1));
+	m_nSamples = std::min<SAMPLEINDEX>(fileHeader.smpnum, MAX_SAMPLES - 1);
 	bool lastSampleCompressed = false;
 	for(SAMPLEINDEX i = 0; i < GetNumSamples(); i++)
 	{
 		ITSample sampleHeader;
-		if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadConvertEndianness(sampleHeader))
+		if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadStruct(sampleHeader))
 		{
 			// IT does not check for the IMPS magic, and some bad XM->IT converter out there doesn't write the magic bytes for empty sample slots.
 			ModSample &sample = Samples[i + 1];
@@ -767,10 +822,10 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 				{
 					std::string filenameU8;
 					file.ReadString<mpt::String::maybeNullTerminated>(filenameU8, strLen);
-#ifdef MPT_EXTERNAL_SAMPLES
+#if defined(MPT_EXTERNAL_SAMPLES)
 					SetSamplePath(i + 1, mpt::PathString::FromUTF8(filenameU8));
-#else
-					AddToLog(LogWarning, mpt::String::Print(MPT_USTRING("Loading external sample %1 ('%2') failed: External samples are not supported."), i, mpt::ToUnicode(mpt::CharsetUTF8, filenameU8)));
+#elif !defined(LIBOPENMPT_BUILD_TEST)
+					AddToLog(LogWarning, mpt::format(MPT_USTRING("Loading external sample %1 ('%2') failed: External samples are not supported."))(i, mpt::ToUnicode(mpt::CharsetUTF8, filenameU8)));
 #endif // MPT_EXTERNAL_SAMPLES
 				} else
 				{
@@ -782,17 +837,27 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	}
 	m_nSamples = std::max(SAMPLEINDEX(1), GetNumSamples());
 
-	if(possibleXMconversion && fileHeader.cwtv == 0x0204 && fileHeader.cmwt == 0x0200 && fileHeader.special == 0 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4)
+	if(possibleXMconversion && fileHeader.cwtv == 0x0204 && fileHeader.cmwt == 0x0200 && fileHeader.special == 0 && fileHeader.reserved == 0
 		&& (fileHeader.flags & ~ITFileHeader::linearSlides) == (ITFileHeader::useStereoPlayback | ITFileHeader::instrumentMode | ITFileHeader::itOldEffects)
 		&& fileHeader.globalvol == 128 && fileHeader.mv == 48 && fileHeader.sep == 128 && fileHeader.pwd == 0 && fileHeader.msglength == 0)
 	{
-		for(size_t i = 20; i < CountOf(fileHeader.songname); i++)
+		for(uint8 pan : fileHeader.chnpan)
+		{
+			if(pan != 0x20 && pan != 0xA0)
+				possibleXMconversion = false;
+		}
+		for(uint8 vol : fileHeader.chnvol)
+		{
+			if(vol != 0x40)
+				possibleXMconversion = false;
+		}
+		for(size_t i = 20; i < mpt::size(fileHeader.songname); i++)
 		{
 			if(fileHeader.songname[i] != 0)
 				possibleXMconversion = false;
 		}
 		if(possibleXMconversion)
-			m_madeWithTracker = "XM Conversion";
+			m_madeWithTracker = MPT_USTRING("XM Conversion");
 	}
 
 	m_nMinPeriod = 0;
@@ -803,7 +868,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	if(numPats != patPos.size())
 	{
 		// Hack: Notify user here if file contains more patterns than what can be read.
-		AddToLog(mpt::String::Print(str_PatternSetTruncationNote, patPos.size(), numPats));
+		AddToLog(mpt::format(str_PatternSetTruncationNote)(patPos.size(), numPats));
 	}
 
 	if(!(loadFlags & loadPatternData))
@@ -902,7 +967,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 
 	// Load instrument and song extensions.
 	LoadExtendedInstrumentProperties(file, &interpretModPlugMade);
-	if(interpretModPlugMade && m_madeWithTracker != "BeRoTracker")
+	if(interpretModPlugMade && m_madeWithTracker != MPT_USTRING("BeRoTracker"))
 	{
 		m_playBehaviour.reset();
 		m_nMixLevels = mixLevelsOriginal;
@@ -911,7 +976,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 	LoadExtendedSongProperties(file, &interpretModPlugMade);
 
 	// Reading Patterns
-	Patterns.ResizeArray(std::max(MAX_PATTERNS, numPats));
+	Patterns.ResizeArray(numPats);
 	for(PATTERNINDEX pat = 0; pat < numPats; pat++)
 	{
 		if(patPos[pat] == 0 || !file.Seek(patPos[pat]))
@@ -919,7 +984,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 			// Empty 64-row pattern
 			if(!Patterns.Insert(pat, 64))
 			{
-				AddToLog(mpt::String::Print("Allocating patterns failed starting from pattern %1", pat));
+				AddToLog(mpt::format("Allocating patterns failed starting from pattern %1")(pat));
 				break;
 			}
 			// Now (after the Insert() call), we can read the pattern name.
@@ -942,7 +1007,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 		std::vector<uint8> chnMask(GetNumChannels());
 		std::vector<ModCommand> lastValue(GetNumChannels(), ModCommand::Empty());
 
-		ModCommand *patData = Patterns[pat];
+		auto patData = Patterns[pat].begin();
 		ROWINDEX row = 0;
 		while(row < numRows && patternData.CanRead(1))
 		{
@@ -1037,7 +1102,8 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 				// 203-212: Vibrato depth
 				if(vol >= 203 && vol <= 212)
 				{
-					m.volcmd = VOLCMD_VIBRATODEPTH; m.vol = vol - 203;
+					m.volcmd = VOLCMD_VIBRATODEPTH;
+					m.vol = vol - 203;
 					// Old versions of ModPlug saved this as vibrato speed instead, so let's fix that.
 					if(m.vol && m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MAKE_VERSION_NUMERIC(1, 17, 02, 54))
 						m.volcmd = VOLCMD_VIBRATOSPEED;
@@ -1054,7 +1120,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 				m.command = patternData.ReadUint8();
 				m.param = patternData.ReadUint8();
 				S3MConvert(m, true);
-				// In some IT-compatible trackers, it is possible to input an parameter without a command.
+				// In some IT-compatible trackers, it is possible to input a parameter without a command.
 				// In this case, we still need to update the last value memory. OpenMPT didn't do this until v1.25.01.07.
 				// Example: ckbounce.it
 				lastValue[ch].command = m.command;
@@ -1072,13 +1138,13 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 
 	if(m_dwLastSavedWithVersion && m_madeWithTracker.empty())
 	{
-		m_madeWithTracker = "OpenMPT " + MptVersion::ToStr(m_dwLastSavedWithVersion);
-		if(memcmp(fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000)
+		m_madeWithTracker = MPT_USTRING("OpenMPT ") + MptVersion::ToUString(m_dwLastSavedWithVersion);
+		if(memcmp(&fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000)
 		{
-			m_madeWithTracker += " (compatibility export)";
+			m_madeWithTracker += MPT_USTRING(" (compatibility export)");
 		} else if(MptVersion::IsTestBuild(m_dwLastSavedWithVersion))
 		{
-			m_madeWithTracker += " (test build)";
+			m_madeWithTracker += MPT_USTRING(" (test build)");
 		}
 	} else
 	{
@@ -1092,44 +1158,42 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 				&& fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0
 				&& fileHeader.insnum == 0 && fileHeader.patnum + 1 == fileHeader.ordnum
 				&& fileHeader.globalvol == 128 && fileHeader.mv == 100 && fileHeader.speed == 1 && fileHeader.sep == 128 && fileHeader.pwd == 0
-				&& fileHeader.msglength == 0 && fileHeader.msgoffset == 0 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
+				&& fileHeader.msglength == 0 && fileHeader.msgoffset == 0 && fileHeader.reserved == 0)
 			{
-				m_madeWithTracker = "OpenSPC conversion";
-			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4))
+				m_madeWithTracker = MPT_USTRING("OpenSPC conversion");
+			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0)
 			{
 				// ModPlug Tracker 1.00a5, instruments 560 bytes apart
 				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 00, 00, A5);
-				m_madeWithTracker = "ModPlug Tracker 1.00a5";
+				m_madeWithTracker = MPT_USTRING("ModPlug Tracker 1.00a5");
 				interpretModPlugMade = true;
-			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !memcmp(fileHeader.reserved, "CHBI", 4))
+			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !memcmp(&fileHeader.reserved, "CHBI", 4))
 			{
-				m_madeWithTracker = "ChibiTracker";
-			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && fileHeader.special <= 1 && fileHeader.pwd == 0 && !memcmp(fileHeader.reserved, "\0\0\0\0", 4)
+				m_madeWithTracker = MPT_USTRING("ChibiTracker");
+			} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && fileHeader.special <= 1 && fileHeader.pwd == 0 && fileHeader.reserved == 0
 				&& (fileHeader.flags & (ITFileHeader::vol0Optimisations | ITFileHeader::instrumentMode | ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig | ITFileHeader::extendedFilterRange)) == ITFileHeader::instrumentMode
 				&& m_nSamples > 0 && !strcmp(Samples[1].filename, "XXXXXXXX.YYY"))
 			{
-				m_madeWithTracker = "CheeseTracker";
-			} else if(fileHeader.cmwt < 0x0888)
+				m_madeWithTracker = MPT_USTRING("CheeseTracker");
+			} else if(fileHeader.cmwt < 0x0300)
 			{
 				if(fileHeader.cmwt > 0x0214)
 				{
-					m_madeWithTracker = "Impulse Tracker 2.15";
+					m_madeWithTracker = MPT_USTRING("Impulse Tracker 2.15");
 				} else if(fileHeader.cwtv > 0x0214)
 				{
 					// Patched update of IT 2.14 (0x0215 - 0x0217 == p1 - p3)
 					// p4 (as found on modland) adds the ITVSOUND driver, but doesn't seem to change
 					// anything as far as file saving is concerned.
-					m_madeWithTracker = mpt::String::Print("Impulse Tracker 2.14p%1", fileHeader.cwtv - 0x0214);
+					m_madeWithTracker = mpt::format(MPT_USTRING("Impulse Tracker 2.14p%1"))(fileHeader.cwtv - 0x0214);
 				} else
 				{
-					m_madeWithTracker = mpt::String::Print("Impulse Tracker %1.%2", (fileHeader.cwtv & 0x0F00) >> 8, mpt::fmt::hex0<2>((fileHeader.cwtv & 0xFF)));
+					m_madeWithTracker = mpt::format(MPT_USTRING("Impulse Tracker %1.%2"))((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>((fileHeader.cwtv & 0xFF)));
 				}
-				if(m_FileHistory.empty() && memcmp(fileHeader.reserved, "\0\0\0\0", 4))
+				if(m_FileHistory.empty() && fileHeader.reserved != 0)
 				{
-					// IT encrypts the total edit time of a module in the "reserved" field
-					uint32 editTime;
-					memcpy(&editTime, fileHeader.reserved, 4);
-					SwapBytesLE(editTime);
+					// Starting from  version 2.07, IT encrypts the total edit time of a module in the "reserved" field
+					uint32 editTime = fileHeader.reserved;
 					if(fileHeader.cwtv >= 0x0208)
 					{
 						editTime ^= 0x4954524B;	// 'ITRK'
@@ -1156,16 +1220,16 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 				m_playBehaviour.reset(kITShortSampleRetrig);
 			break;
 		case 4:
-			m_madeWithTracker = mpt::format("pyIT %1.%2")((fileHeader.cwtv & 0x0F00) >> 8, mpt::fmt::hex0<2>((fileHeader.cwtv & 0xFF)));
+			m_madeWithTracker = mpt::format(MPT_USTRING("pyIT %1.%2"))((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>((fileHeader.cwtv & 0xFF)));
 			break;
 		case 6:
-			m_madeWithTracker = "BeRoTracker";
+			m_madeWithTracker = MPT_USTRING("BeRoTracker");
 			break;
 		case 7:
-			m_madeWithTracker = mpt::format("ITMCK %1.%2.%3")((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F);
+			m_madeWithTracker = mpt::format(MPT_USTRING("ITMCK %1.%2.%3"))((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F);
 			break;
 		case 0xD:
-			m_madeWithTracker = "spc2it";
+			m_madeWithTracker = MPT_USTRING("spc2it");
 			break;
 		}
 	}
@@ -1184,7 +1248,6 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
 
 
 void CSoundFile::LoadMPTMProperties(FileReader &file, uint16 cwtv)
-//----------------------------------------------------------------
 {
 	mpt::istringstream iStrm(file.GetRawDataAsString());
 
@@ -1205,12 +1268,13 @@ void CSoundFile::LoadMPTMProperties(FileReader &file, uint16 cwtv)
 	} else
 	{
 		// Loading for older files.
-		if(GetTuneSpecificTunings().Deserialize(iStrm))
+		std::string name;
+		if(GetTuneSpecificTunings().Deserialize(iStrm, name) != Tuning::SerializationResult::Success)
 		{
 			AddToLog(LogError, MPT_USTRING("Loading tune specific tunings failed."));
 		} else
 		{
-			ReadTuningMap(iStrm, *this);
+			ReadTuningMapImpl(iStrm, *this, 0, cwtv < 0x88C);
 		}
 	}
 }
@@ -1220,7 +1284,6 @@ void CSoundFile::LoadMPTMProperties(FileReader &file, uint16 cwtv)
 
 // Save edit history. Pass a null pointer for *f to retrieve the number of bytes that would be written.
 static uint32 SaveITEditHistory(const CSoundFile &sndFile, FILE *f)
-//-----------------------------------------------------------------
 {
 	size_t num = sndFile.GetFileHistory().size();
 #ifdef MODPLUG_TRACKER
@@ -1269,8 +1332,7 @@ static uint32 SaveITEditHistory(const CSoundFile &sndFile, FILE *f)
 
 		ITHistoryStruct itHistory;
 		itHistory.ConvertToIT(mptHistory);
-		itHistory.ConvertEndianness();
-		fwrite(&itHistory, 1, sizeof(itHistory), f);
+		mpt::IO::Write(f, itHistory);
 	}
 
 	return bytesWritten;
@@ -1278,7 +1340,6 @@ static uint32 SaveITEditHistory(const CSoundFile &sndFile, FILE *f)
 
 
 bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExport)
-//--------------------------------------------------------------------------------
 {
 	const CModSpecifications &specs = (GetType() == MOD_TYPE_MPT ? ModSpecs::mptm : (compatibilityExport ? ModSpecs::it : ModSpecs::itEx));
 
@@ -1301,16 +1362,17 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 
 	if(GetType() == MOD_TYPE_MPT)
 	{
-		if(!Order.NeedsExtraDatafield()) itHeader.ordnum = Order.size();
-		else itHeader.ordnum = std::min(Order.size(), MAX_ORDERS); //Writing MAX_ORDERS at max here, and if there's more, writing them elsewhere.
-
-		//Crop unused orders from the end.
-		while(itHeader.ordnum > 1 && Order[itHeader.ordnum - 1] == Order.GetInvalidPatIndex()) itHeader.ordnum--;
+		itHeader.ordnum = Order().GetLengthTailTrimmed();
+		if(Order().NeedsExtraDatafield() && itHeader.ordnum > 256)
+		{
+			// If there are more order items, write them elsewhere.
+			itHeader.ordnum = 256;
+		}
 	} else
 	{
 		// An additional "---" pattern is appended so Impulse Tracker won't ignore the last order item.
 		// Interestingly, this can exceed IT's 256 order limit. Also, IT will always save at least two orders.
-		itHeader.ordnum = std::min(Order.GetLengthTailTrimmed(), specs.ordersMax) + 1;
+		itHeader.ordnum = std::min(Order().GetLengthTailTrimmed(), specs.ordersMax) + 1;
 		if(itHeader.ordnum < 2) itHeader.ordnum = 2;
 	}
 
@@ -1348,7 +1410,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 		if(!compatibilityExport)
 		{
 			// This way, we indicate that the file will most likely contain OpenMPT hacks. Compatibility export puts 0 here.
-			memcpy(itHeader.reserved, "OMPT", 4);
+			memcpy(&itHeader.reserved, "OMPT", 4);
 		}
 	}
 
@@ -1385,6 +1447,9 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 		itHeader.chnpan[ich] = (uint8)(ChnSettings[ich].nPan >> 2);
 		if (ChnSettings[ich].dwFlags[CHN_SURROUND]) itHeader.chnpan[ich] = 100;
 		itHeader.chnvol[ich] = (uint8)(ChnSettings[ich].nVolume);
+#ifdef MODPLUG_TRACKER
+		if(TrackerSettings::Instance().MiscSaveChannelMuteStatus)
+#endif
 		if (ChnSettings[ich].dwFlags[CHN_MUTE]) itHeader.chnpan[ich] |= 0x80;
 	}
 
@@ -1401,7 +1466,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 		if(dwChnNamLen) dwExtra += dwChnNamLen + 8;
 	}
 
-	if(m_SongFlags[SONG_EMBEDMIDICFG])
+	if(!m_MidiCfg.IsMacroDefaultSetupUsed())
 	{
 		itHeader.flags |= ITFileHeader::reqEmbeddedMIDIConfig;
 		itHeader.special |= ITFileHeader::embedMIDIConfiguration;
@@ -1434,12 +1499,9 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 	}
 
 	// Write file header
-	itHeader.ConvertEndianness();
-	fwrite(&itHeader, 1, sizeof(itHeader), f);
-	// Convert endianness again as we access some of the header variables with native endianness here.
-	itHeader.ConvertEndianness();
+	mpt::IO::Write(f, itHeader);
 
-	Order.WriteAsByte(f, itHeader.ordnum);
+	Order().WriteAsByte(f, itHeader.ordnum);
 	for(uint16 i = 0; i < itHeader.insnum; ++i)
 	{
 		mpt::IO::WriteIntLE<uint32>(f, inspos[i]);
@@ -1459,37 +1521,34 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 	// Writing midi cfg
 	if(itHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig)
 	{
-		fwrite(static_cast<MIDIMacroConfigData*>(&m_MidiCfg), 1, sizeof(MIDIMacroConfigData), f);
+		mpt::IO::Write(f, static_cast<MIDIMacroConfigData &>(m_MidiCfg));
 	}
 
 	// Writing pattern names
 	if(numNamedPats)
 	{
-		char magic[4];
-		memcpy(magic, "PNAM", 4);
-		fwrite(magic, 4, 1, f);
+		mpt::IO::WriteRaw(f, "PNAM", 4);
 		mpt::IO::WriteIntLE<uint32>(f, numNamedPats * MAX_PATTERNNAME);
 
-		for(PATTERNINDEX nPat = 0; nPat < numNamedPats; nPat++)
+		for(PATTERNINDEX pat = 0; pat < numNamedPats; pat++)
 		{
 			char name[MAX_PATTERNNAME];
-			MemsetZero(name);
-			Patterns[nPat].GetName(name);
-			fwrite(name, 1, MAX_PATTERNNAME, f);
+			mpt::String::Write<mpt::String::maybeNullTerminated>(name, Patterns[pat].GetName());
+			mpt::IO::Write(f, name);
 		}
 	}
 
 	// Writing channel names
 	if(dwChnNamLen && !compatibilityExport)
 	{
-		char magic[4];
-		memcpy(magic, "CNAM", 4);
-		fwrite(magic, 4, 1, f);
+		mpt::IO::WriteRaw(f, "CNAM", 4);
 		mpt::IO::WriteIntLE<uint32>(f, dwChnNamLen);
 		uint32 nChnNames = dwChnNamLen / MAX_CHANNELNAME;
 		for(uint32 inam = 0; inam < nChnNames; inam++)
 		{
-			fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f);
+			char name[MAX_CHANNELNAME];
+			mpt::String::Write<mpt::String::maybeNullTerminated>(name, ChnSettings[inam].szName);
+			mpt::IO::Write(f, name);
 		}
 	}
 
@@ -1504,7 +1563,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 	if(itHeader.special & ITFileHeader::embedSongMessage)
 	{
 		dwPos += msglength;
-		fwrite(m_songMessage.c_str(), 1, msglength, f);
+		mpt::IO::WriteRaw(f, m_songMessage.c_str(), msglength);
 	}
 
 	// Writing instruments
@@ -1520,8 +1579,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 		// Writing instrument
 		inspos[nins - 1] = static_cast<uint32>(dwPos);
 		dwPos += instSize;
-		iti.ConvertEndianness();
-		fwrite(&iti, 1, instSize, f);
+		mpt::IO::WritePartial(f, iti, instSize);
 	}
 
 	// Writing dummy sample headers (until we know the correct sample data offset)
@@ -1531,7 +1589,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 	{
 		smppos[smp] = static_cast<uint32>(dwPos);
 		dwPos += sizeof(ITSample);
-		fwrite(&itss, 1, sizeof(ITSample), f);
+		mpt::IO::Write(f, itss);
 	}
 
 	// Writing Patterns
@@ -1539,7 +1597,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 	for(PATTERNINDEX pat = 0; pat < itHeader.patnum; pat++)
 	{
 		uint32 dwPatPos = static_cast<uint32>(dwPos);
-		if (!Patterns[pat]) continue;
+		if (!Patterns.IsValidPat(pat)) continue;
 
 		if(Patterns[pat].GetOverrideSignature())
 			bNeedsMptPatSave = true;
@@ -1555,14 +1613,14 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 
 		// Write pattern header
 		ROWINDEX writeRows = mpt::saturate_cast<uint16>(Patterns[pat].GetNumRows());
-		uint16 patinfo[4];
+		uint16 writeSize = 0;
+		uint16le patinfo[4];
 		patinfo[0] = 0;
 		patinfo[1] = (uint16)writeRows;
 		patinfo[2] = 0;
 		patinfo[3] = 0;
-		SwapBytesLE(patinfo[1]);
 
-		fwrite(patinfo, 8, 1, f);
+		mpt::IO::Write(f, patinfo);
 		dwPos += 8;
 
 		const CHANNELINDEX maxChannels = std::min(specs.channelsMax, GetNumChannels());
@@ -1596,29 +1654,30 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 				if (m->instr) b |= 2;
 				if (m->volcmd != VOLCMD_NONE)
 				{
+					vol = std::min(m->vol, uint8(9));
 					switch(m->volcmd)
 					{
-					case VOLCMD_VOLUME:			vol = m->vol; if (vol > 64) vol = 64; break;
-					case VOLCMD_PANNING:		vol = m->vol + 128; if (vol > 192) vol = 192; break;
-					case VOLCMD_VOLSLIDEUP:		vol = 85 + ConvertVolParam(m); break;
-					case VOLCMD_VOLSLIDEDOWN:	vol = 95 + ConvertVolParam(m); break;
-					case VOLCMD_FINEVOLUP:		vol = 65 + ConvertVolParam(m); break;
-					case VOLCMD_FINEVOLDOWN:	vol = 75 + ConvertVolParam(m); break;
-					case VOLCMD_VIBRATODEPTH:	vol = 203 + ConvertVolParam(m); break;
+					case VOLCMD_VOLUME:			vol = std::min(m->vol, uint8(64)); break;
+					case VOLCMD_PANNING:		vol = std::min(m->vol, uint8(64)) + 128; break;
+					case VOLCMD_VOLSLIDEUP:		vol += 85; break;
+					case VOLCMD_VOLSLIDEDOWN:	vol += 95; break;
+					case VOLCMD_FINEVOLUP:		vol += 65; break;
+					case VOLCMD_FINEVOLDOWN:	vol += 75; break;
+					case VOLCMD_VIBRATODEPTH:	vol += 203; break;
 					case VOLCMD_VIBRATOSPEED:	if(command == CMD_NONE)
 												{
 													// illegal command -> move if possible
 													command = CMD_VIBRATO;
-													param = ConvertVolParam(m) << 4;
+													param = std::min(m->vol, uint8(15)) << 4;
 												} else
 												{
 													vol = 203;
 												}
 												break;
-					case VOLCMD_TONEPORTAMENTO:	vol = 193 + ConvertVolParam(m); break;
-					case VOLCMD_PORTADOWN:		vol = 105 + ConvertVolParam(m); break;
-					case VOLCMD_PORTAUP:		vol = 115 + ConvertVolParam(m); break;
-					case VOLCMD_OFFSET:			if(!compatibilityExport) vol = 223 + ConvertVolParam(m); //rewbs.volOff
+					case VOLCMD_TONEPORTAMENTO:	vol += 193; break;
+					case VOLCMD_PORTADOWN:		vol += 105; break;
+					case VOLCMD_PORTAUP:		vol += 115; break;
+					case VOLCMD_OFFSET:			if(!compatibilityExport) vol += 223;
 												break;
 					default:					vol = 0xFF;
 					}
@@ -1705,27 +1764,28 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 				}
 			}
 			buf[len++] = 0;
-			if(patinfo[0] > uint16_max - len)
+			if(writeSize > uint16_max - len)
 			{
-				AddToLog(mpt::String::Print("%1 (%2 %3)", str_tooMuchPatternData, str_pattern, pat));
+				AddToLog(mpt::format("%1 (%2 %3)")(str_tooMuchPatternData, str_pattern, pat));
 				break;
 			} else
 			{
 				dwPos += len;
-				patinfo[0] += (uint16)len;
-				fwrite(buf, 1, len, f);
+				writeSize += (uint16)len;
+				mpt::IO::WriteRaw(f, buf, len);
 			}
 		}
+
 		fseek(f, dwPatPos, SEEK_SET);
-		SwapBytesLE(patinfo[0]);
-		fwrite(patinfo, 8, 1, f);
+		patinfo[0] = writeSize;
+		mpt::IO::Write(f, patinfo);
 		fseek(f, static_cast<long>(dwPos), SEEK_SET);
 	}
 	// Writing Sample Data
 	for(SAMPLEINDEX smp = 1; smp <= itHeader.smpnum; smp++)
 	{
 #ifdef MODPLUG_TRACKER
-		int type = GetType() == MOD_TYPE_IT ? 1 : 4;
+		uint32 type = GetType() == MOD_TYPE_IT ? 1 : 4;
 		if(compatibilityExport) type = 2;
 		bool compress = ((((Samples[smp].GetNumChannels() > 1) ? TrackerSettings::Instance().MiscITCompressionStereo : TrackerSettings::Instance().MiscITCompressionMono) & type) != 0);
 #else
@@ -1742,14 +1802,13 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 		if(dwPos > uint32_max)
 		{
 			// Sample position does not fit into sample pointer!
-			AddToLog(mpt::String::Print("Cannot save sample %1: File size exceeds 4 GB.", smp));
+			AddToLog(mpt::format("Cannot save sample %1: File size exceeds 4 GB.")(smp));
 			itss.samplepointer = 0;
 			itss.length = 0;
 		}
 		SmpLength smpLength = itss.length;	// Possibly truncated to 2^32 samples
-		itss.ConvertEndianness();
 		fseek(f, smppos[smp - 1], SEEK_SET);
-		fwrite(&itss, 1, sizeof(ITSample), f);
+		mpt::IO::Write(f, itss);
 		if(dwPos > uint32_max)
 		{
 			continue;
@@ -1761,7 +1820,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 			if(Samples[smp].nLength != smpLength)
 			{
 				// Sample length does not fit into IT header!
-				AddToLog(mpt::String::Print("Truncating sample %1: Length exceeds exceeds 4 gigasamples.", smp));
+				AddToLog(mpt::format("Truncating sample %1: Length exceeds exceeds 4 gigasamples.")(smp));
 			}
 			dwPos += itss.GetSampleFormat().WriteSample(f, Samples[smp], smpLength);
 		} else
@@ -1773,7 +1832,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 			if(mpt::IO::WriteVarInt(f, strSize, &intBytes))
 			{
 				dwPos += intBytes + strSize;
-				mpt::IO::WriteRaw(f, &filenameU8[0], strSize);
+				mpt::IO::WriteRaw(f, filenameU8.data(), strSize);
 			}
 #endif // MPT_EXTERNAL_SAMPLES
 		}
@@ -1812,7 +1871,6 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 
 	//hack
 	//BEGIN: MPT SPECIFIC:
-	//--------------------
 
 	bool success = true;
 
@@ -1832,7 +1890,7 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 		ssb.WriteItem(GetTuneSpecificTunings(), "0", &WriteTuningCollection);
 	if(AreNonDefaultTuningsUsed(*this))
 		ssb.WriteItem(*this, "1", &WriteTuningMap);
-	if(Order.NeedsExtraDatafield())
+	if(Order().NeedsExtraDatafield())
 		ssb.WriteItem(Order, "2", &WriteModSequenceOld);
 	if(bNeedsMptPatSave)
 		ssb.WriteItem(Patterns, FileIdPatterns, &WriteModPatterns);
@@ -1859,7 +1917,6 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 	f = nullptr;
 
 	//END  : MPT SPECIFIC
-	//-------------------
 
 	//NO WRITING HERE ANYMORE.
 
@@ -1873,7 +1930,6 @@ bool CSoundFile::SaveIT(const mpt::PathString &filename, bool compatibilityExpor
 #ifndef MODPLUG_NO_FILESAVE
 
 uint32 CSoundFile::SaveMixPlugins(FILE *f, bool bUpdate)
-//------------------------------------------------------
 {
 #ifndef NO_PLUGINS
 	uint32 chinfo[MAX_BASECHANNELS];
@@ -1892,10 +1948,7 @@ uint32 CSoundFile::SaveMixPlugins(FILE *f, bool bUpdate)
 			{
 				plugin.pMixPlugin->SaveAllParameters();
 			}
-			if(plugin.pPluginData)
-			{
-				nPluginSize += plugin.nPluginDataSize;
-			}
+			nPluginSize += plugin.pluginData.size();
 
 			uint32 MPTxPlugDataSize = 4 + sizeof(float32) +		// 4 for ID and size of dryRatio
 									 4 + sizeof(int32);			// Default Program
@@ -1909,31 +1962,30 @@ uint32 CSoundFile::SaveMixPlugins(FILE *f, bool bUpdate)
 				id[1] = i < 100 ? 'X' : '0' + i / 100;
 				id[2] = '0' + (i / 10) % 10u;
 				id[3] = '0' + (i % 10u);
-				fwrite(id, 1, 4, f);
+				mpt::IO::WriteRaw(f, id, 4);
 
 				// write plugin size:
 				mpt::IO::WriteIntLE<uint32>(f, nPluginSize);
-				SNDMIXPLUGININFO tmpPluginInfo = m_MixPlugins[i].Info;
-				tmpPluginInfo.ConvertEndianness();
-				fwrite(&tmpPluginInfo, 1, sizeof(SNDMIXPLUGININFO), f);
-				mpt::IO::WriteIntLE<uint32>(f, m_MixPlugins[i].nPluginDataSize);
-				if(m_MixPlugins[i].pPluginData)
+				mpt::IO::Write(f, m_MixPlugins[i].Info);
+				uint32 dataSize = mpt::saturate_cast<uint32>(m_MixPlugins[i].pluginData.size());
+				mpt::IO::WriteIntLE<uint32>(f, dataSize);
+				if(dataSize)
 				{
-					fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f);
+					mpt::IO::WriteRaw(f, m_MixPlugins[i].pluginData.data(), dataSize);
 				}
 
 				mpt::IO::WriteIntLE<uint32>(f, MPTxPlugDataSize);
 
 				// Dry/Wet ratio
 				memcpy(id, "DWRT", 4);
-				fwrite(id, 1, 4, f);
+				mpt::IO::WriteRaw(f, id, 4);
 				// DWRT chunk does not include a size, so better make sure we always write 4 bytes here.
 				STATIC_ASSERT(sizeof(IEEE754binary32LE) == 4);
 				mpt::IO::Write(f, IEEE754binary32LE(m_MixPlugins[i].fDryRatio));
 
 				// Default program
 				memcpy(id, "PROG", 4);
-				fwrite(id, 1, 4, f);
+				mpt::IO::WriteRaw(f, id, 4);
 				// PROG chunk does not include a size, so better make sure we always write 4 bytes here.
 				STATIC_ASSERT(sizeof(m_MixPlugins[i].defaultProgram) == sizeof(int32));
 				mpt::IO::WriteIntLE<int32>(f, m_MixPlugins[i].defaultProgram);
@@ -1958,7 +2010,7 @@ uint32 CSoundFile::SaveMixPlugins(FILE *f, bool bUpdate)
 		if(f)
 		{
 			memcpy(id, "CHFX", 4);
-			fwrite(id, 1, 4, f);
+			mpt::IO::WriteRaw(f, id, 4);
 			mpt::IO::WriteIntLE<uint32>(f, nChInfo * 4);
 			for(uint32 i = 0; i < nChInfo; ++i)
 			{
@@ -1979,7 +2031,6 @@ uint32 CSoundFile::SaveMixPlugins(FILE *f, bool bUpdate)
 
 
 void CSoundFile::LoadMixPlugins(FileReader &file)
-//-----------------------------------------------
 {
 	while(file.CanRead(9))
 	{
@@ -2002,7 +2053,7 @@ void CSoundFile::LoadMixPlugins(FileReader &file)
 		{
 			for (size_t ch = 0; ch < MAX_BASECHANNELS; ch++)
 			{
-				ChnSettings[ch].nMixPlugin = (uint8)chunk.ReadUint32LE();
+				ChnSettings[ch].nMixPlugin = static_cast<PLUGINDEX>(chunk.ReadUint32LE());
 			}
 #ifndef NO_PLUGINS
 		}
@@ -2021,7 +2072,7 @@ void CSoundFile::LoadMixPlugins(FileReader &file)
 #endif // NO_PLUGINS
 		} else if(!memcmp(code, "MODU", 4))
 		{
-			m_madeWithTracker = "BeRoTracker";
+			m_madeWithTracker = MPT_USTRING("BeRoTracker");
 			m_dwLastSavedWithVersion = 0;	// Reset MPT detection for old files that have a similar fingerprint
 		}
 	}
@@ -2030,27 +2081,21 @@ void CSoundFile::LoadMixPlugins(FileReader &file)
 
 #ifndef NO_PLUGINS
 void CSoundFile::ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin)
-//-------------------------------------------------------------------------
 {
 	// MPT's standard plugin data. Size not specified in file.. grrr..
-	file.ReadConvertEndianness(plugin.Info);
+	file.ReadStruct(plugin.Info);
 	mpt::String::SetNullTerminator(plugin.Info.szName);
 	mpt::String::SetNullTerminator(plugin.Info.szLibraryName);
 	plugin.editorX = plugin.editorY = int32_min;
 
-	//data for VST setchunk? size lies just after standard plugin data.
+	// Plugin user data
 	const uint32 pluginDataChunkSize = file.ReadUint32LE();
 	FileReader pluginDataChunk = file.ReadChunk(pluginDataChunkSize);
 
 	if(pluginDataChunk.IsValid())
 	{
-		plugin.nPluginDataSize = 0;
-		plugin.pPluginData = new (std::nothrow) char[pluginDataChunkSize];
-		if(plugin.pPluginData)
-		{
-			plugin.nPluginDataSize = pluginDataChunkSize;
-			pluginDataChunk.ReadRaw(plugin.pPluginData, pluginDataChunkSize);
-		}
+		plugin.pluginData.resize(pluginDataChunkSize);
+		pluginDataChunk.ReadRaw(plugin.pluginData.data(), pluginDataChunkSize);
 	}
 
 	FileReader modularData = file.ReadChunk(file.ReadUint32LE());
@@ -2094,7 +2139,6 @@ void CSoundFile::ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin)
 #ifndef MODPLUG_NO_FILESAVE
 
 void CSoundFile::SaveExtendedSongProperties(FILE* f) const
-//--------------------------------------------------------
 {
 	const CModSpecifications &specs = GetModSpecifications();
 	// Extra song data - Yet Another Hack.
@@ -2143,14 +2187,14 @@ void CSoundFile::SaveExtendedSongProperties(FILE* f) const
 			if (ChnSettings[chn].dwFlags[CHN_SURROUND]) panvol[0] = 100;
 			if (ChnSettings[chn].dwFlags[CHN_MUTE]) panvol[0] |= 0x80;
 			panvol[1] = (uint8)ChnSettings[chn].nVolume;
-			fwrite(&panvol, sizeof(panvol), 1, f);
+			mpt::IO::Write(f, panvol);
 		}
 	}
 
 	{
 		WRITEMODULARHEADER(MAGIC4BE('T','M','.','.'), 1);
 		uint8 mode = static_cast<uint8>(m_nTempoMode);
-		fwrite(&mode, sizeof(mode), 1, f);
+		mpt::IO::WriteIntLE(f, mode);
 	}
 
 	const int32 tmpMixLevels = static_cast<int32>(m_nMixLevels);
@@ -2170,9 +2214,9 @@ void CSoundFile::SaveExtendedSongProperties(FILE* f) const
 		WRITEMODULAR(MAGIC4BE('D','G','V','.'), m_nDefaultGlobalVolume);
 	}
 
-	if(GetType() != MOD_TYPE_XM && Order.GetRestartPos() != 0)
+	if(GetType() != MOD_TYPE_XM && Order().GetRestartPos() != 0)
 	{
-		WRITEMODULAR(MAGIC4BE('R','P','.','.'), Order.GetRestartPos());
+		WRITEMODULAR(MAGIC4BE('R','P','.','.'), Order().GetRestartPos());
 	}
 
 	if(m_nResampling != SRCMODE_DEFAULT && specs.hasDefaultResampling)
@@ -2209,7 +2253,7 @@ void CSoundFile::SaveExtendedSongProperties(FILE* f) const
 		std::string data = oStrm.str();
 		uint16 length = mpt::saturate_cast<uint16>(data.size());
 		WRITEMODULARHEADER(MAGIC4LE('S','W','N','G'), length);
-		mpt::IO::WriteRaw(f, &data[0], length);
+		mpt::IO::WriteRaw(f, data.data(), length);
 	}
 
 	// Playback compatibility flags
@@ -2242,7 +2286,7 @@ void CSoundFile::SaveExtendedSongProperties(FILE* f) const
 	// MIDI mapping directives
 	if(GetMIDIMapper().GetCount() > 0)
 	{
-		const size_t objectsize = GetMIDIMapper().GetSerializationSize();
+		const size_t objectsize = GetMIDIMapper().Serialize();
 		if(!Util::TypeCanHoldValue<uint16>(objectsize))
 		{
 			AddToLog("Too many MIDI Mapping directives to save; data won't be written.");
@@ -2264,7 +2308,6 @@ void CSoundFile::SaveExtendedSongProperties(FILE* f) const
 
 template<typename T>
 void ReadField(FileReader &chunk, std::size_t size, T &field)
-//-----------------------------------------------------------
 {
 	field = chunk.ReadSizedIntLE<T>(size);
 }
@@ -2272,7 +2315,6 @@ void ReadField(FileReader &chunk, std::size_t size, T &field)
 
 template<typename T>
 void ReadFieldCast(FileReader &chunk, std::size_t size, T &field)
-//---------------------------------------------------------------
 {
 	STATIC_ASSERT(sizeof(T) <= sizeof(int32));
 	field = static_cast<T>(chunk.ReadSizedIntLE<int32>(size));
@@ -2280,7 +2322,6 @@ void ReadFieldCast(FileReader &chunk, std::size_t size, T &field)
 
 
 void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMptMade)
-//------------------------------------------------------------------------------------
 {
 	if(!file.ReadMagic("STPM"))	// 'MPTS'
 	{
@@ -2299,12 +2340,12 @@ void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMp
 		const uint32 code = file.ReadUint32LE();
 		const uint16 size = file.ReadUint16LE();
 
-		// Start of MPTM extensions, truncated field or non-ASCII ID
+		// Start of MPTM extensions, non-ASCII ID or truncated field
 		if(code == MAGIC4LE('2','2','8',4))
 		{
 			file.SkipBack(6);
 			break;
-		} else if(!file.CanRead(size) || (code & 0x80808080) || !(code & 0x60606060))
+		} else if((code & 0x80808080) || !(code & 0x60606060) || !file.CanRead(size))
 		{
 			break;
 		}
@@ -2317,6 +2358,7 @@ void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMp
 			case MAGIC4LE('D','T','F','R'): { uint32 tempoFract; ReadField(chunk, size, tempoFract); m_nDefaultTempo.Set(m_nDefaultTempo.GetInt(), tempoFract); break; }
 			case MAGIC4BE('R','P','B','.'): ReadField(chunk, size, m_nDefaultRowsPerBeat); break;
 			case MAGIC4BE('R','P','M','.'): ReadField(chunk, size, m_nDefaultRowsPerMeasure); break;
+				// FIXME: If there are only PC events on the last few channels in an MPTM MO3, they won't be imported!
 			case MAGIC4BE('C','.','.','.'): if(GetType() != MOD_TYPE_XM && m_ContainerType != MOD_CONTAINERTYPE_MO3) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); m_nChannels = Clamp(chn, m_nChannels, MAX_BASECHANNELS); } break;
 			case MAGIC4BE('T','M','.','.'): ReadFieldCast(chunk, size, m_nTempoMode); break;
 			case MAGIC4BE('P','M','M','.'): ReadFieldCast(chunk, size, m_nMixLevels); break;
@@ -2325,7 +2367,7 @@ void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMp
 			case MAGIC4BE('S','P','A','.'): ReadField(chunk, size, m_nSamplePreAmp); break;
 			case MAGIC4BE('V','S','T','V'): ReadField(chunk, size, m_nVSTiVolume); break;
 			case MAGIC4BE('D','G','V','.'): ReadField(chunk, size, m_nDefaultGlobalVolume); break;
-			case MAGIC4BE('R','P','.','.'): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order.SetRestartPos(restartPos); } break;
+			case MAGIC4BE('R','P','.','.'): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
 			case MAGIC4LE('R','S','M','P'):
 				ReadFieldCast(chunk, size, m_nResampling);
 				if(!IsKnownResamplingMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
@@ -2399,7 +2441,7 @@ void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMp
 						uint8 b = chunk.ReadUint8();
 						for(uint8 i = 0; i < 8; i++, bit++)
 						{
-							if((b & (1 << i)) && bit <= kFT2FinetunePrecision)
+							if((b & (1 << i)) && bit < m_playBehaviour.size())
 							{
 								m_playBehaviour.set(bit);
 							}
diff --git a/soundlib/Load_itp.cpp b/soundlib/Load_itp.cpp
index 071ded3..3930d73 100644
--- a/soundlib/Load_itp.cpp
+++ b/soundlib/Load_itp.cpp
@@ -36,16 +36,84 @@ OPENMPT_NAMESPACE_BEGIN
 // v1.01: Added option to embed instrument headers
 
 
+struct ITPModCommand
+{
+	uint8le note;
+	uint8le instr;
+	uint8le volcmd;
+	uint8le command;
+	uint8le vol;
+	uint8le param;
+	operator ModCommand() const
+	{
+		ModCommand result;
+		result.note = (ModCommand::IsNote(note) || ModCommand::IsSpecialNote(note)) ? note : NOTE_NONE;
+		result.instr = instr;
+		result.command = (command < MAX_EFFECTS) ? static_cast<EffectCommand>(command.get()) : CMD_NONE;
+		result.volcmd = (volcmd < MAX_VOLCMDS) ? static_cast<VolumeCommand>(volcmd.get()) : VOLCMD_NONE;
+		result.vol = vol;
+		result.param = param;
+		return result;
+	}
+};
+
+MPT_BINARY_STRUCT(ITPModCommand, 6)
+
+
+struct ITPHeader
+{
+	uint32le magic;
+	uint32le version;
+};
+
+MPT_BINARY_STRUCT(ITPHeader, 8)
+
+
+static bool ValidateHeader(const ITPHeader &hdr)
+{
+	if(hdr.magic != MAGIC4BE('.','i','t','p'))
+	{
+		return false;
+	}
+	if(hdr.version > 0x00000103 || hdr.version < 0x00000100)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITPHeader &hdr)
+{
+	MPT_UNREFERENCED_PARAMETER(hdr);
+	return 12 + 4 + 24 + 4 - sizeof(ITPHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize)
+{
+	ITPHeader hdr;
+	if(!file.ReadStruct(hdr))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(hdr))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(hdr));
+}
+
+
 bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------------
 {
-#ifndef MPT_EXTERNAL_SAMPLES
+#if !defined(MPT_EXTERNAL_SAMPLES) && !defined(MPT_FUZZ_TRACKER)
 	// Doesn't really make sense to support this format when there's no support for external files...
 	MPT_UNREFERENCED_PARAMETER(file);
 	MPT_UNREFERENCED_PARAMETER(loadFlags);
 	return false;
-#else // MPT_EXTERNAL_SAMPLES
-	
+#else // !MPT_EXTERNAL_SAMPLES && !MPT_FUZZ_TRACKER
+
 	enum ITPSongFlags
 	{
 		ITP_EMBEDMIDICFG	= 0x00001,	// Embed macros in file
@@ -57,25 +125,32 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 		ITP_ITPEMBEDIH		= 0x40000,	// Embed instrument headers in project file
 	};
 
-	uint32 version, size;
-
 	file.Rewind();
 
-	// Check file ID
-	if(!file.CanRead(12 + 4 + 24 + 4)
-		|| file.ReadUint32LE() != MAGIC4BE('.','i','t','p')	// Magic bytes
-		|| (version = file.ReadUint32LE()) > 0x00000103		// Format version
-		|| version < 0x00000100)
+	ITPHeader hdr;
+	if(!file.ReadStruct(hdr))
+	{
+		return false;
+	}
+	if(!ValidateHeader(hdr))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(hdr))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
+	uint32 version, size;
+	version = hdr.version;
+
 	InitializeGlobals(MOD_TYPE_IT);
 	m_playBehaviour.reset();
-	file.ReadString<mpt::String::maybeNullTerminated>(m_songName, file.ReadUint32LE());
+	file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(m_songName);
 
 	// Song comments
 	m_songMessage.Read(file, file.ReadUint32LE(), SongMessage::leCR);
@@ -86,7 +161,6 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		return false;
 	}
-	if(songFlags & ITP_EMBEDMIDICFG)	m_SongFlags.set(SONG_EMBEDMIDICFG);
 	if(songFlags & ITP_ITOLDEFFECTS)	m_SongFlags.set(SONG_ITOLDEFFECTS);
 	if(songFlags & ITP_ITCOMPATGXX)		m_SongFlags.set(SONG_ITCOMPATGXX);
 	if(songFlags & ITP_LINEARSLIDES)	m_SongFlags.set(SONG_LINEARSLIDES);
@@ -124,7 +198,7 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// MIDI Macro config
-	file.ReadStructPartial(m_MidiCfg, file.ReadUint32LE());
+	file.ReadStructPartial<MIDIMacroConfigData>(m_MidiCfg, file.ReadUint32LE());
 	m_MidiCfg.Sanitize();
 
 	// Song Instruments
@@ -150,18 +224,29 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 		}
 		std::string path;
 		file.ReadString<mpt::String::maybeNullTerminated>(path, size);
+#ifdef MODPLUG_TRACKER
 		if(version <= 0x00000102)
 		{
 			instrPaths[ins] = mpt::PathString::FromLocaleSilent(path);
 		} else
+#endif // MODPLUG_TRACKER
 		{
 			instrPaths[ins] = mpt::PathString::FromUTF8(path);
 		}
+#ifdef MODPLUG_TRACKER
+		if(!file.GetFileName().empty())
+		{
+			instrPaths[ins] = instrPaths[ins].RelativePathToAbsolute(file.GetFileName().GetPath());
+		} else if(GetpModDoc() != nullptr)
+		{
+			instrPaths[ins] = instrPaths[ins].RelativePathToAbsolute(GetpModDoc()->GetPathNameMpt().GetPath());
+		}
+#endif // MODPLUG_TRACKER
 	}
 
 	// Song Orders
 	size = file.ReadUint32LE();
-	Order.ReadAsByte(file, size, size, 0xFF, 0xFE);
+	ReadOrderFromFile<uint8>(Order(), file, size, 0xFF, 0xFE);
 
 	// Song Patterns
 	const PATTERNINDEX numPats = static_cast<PATTERNINDEX>(file.ReadUint32LE());
@@ -176,6 +261,8 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 		return false;
 	}
 
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(numPats);
 	for(PATTERNINDEX pat = 0; pat < numPats; pat++)
 	{
 		const ROWINDEX numRows = file.ReadUint32LE();
@@ -198,17 +285,13 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 		// Pattern data
 		size_t numCommands = GetNumChannels() * numRows;
 
-		if(patternChunk.CanRead(sizeof(MODCOMMAND_ORIGINAL) * numCommands))
+		if(patternChunk.CanRead(sizeof(ITPModCommand) * numCommands))
 		{
 			ModCommand *target = Patterns[pat].GetpModCommand(0, 0);
 			while(numCommands-- != 0)
 			{
-				STATIC_ASSERT(sizeof(MODCOMMAND_ORIGINAL) == 6);
-				MODCOMMAND_ORIGINAL data;
+				ITPModCommand data;
 				patternChunk.ReadStruct(data);
-				if(data.command >= MAX_EFFECTS) data.command = CMD_NONE;
-				if(data.volcmd >= MAX_VOLCMDS) data.volcmd = VOLCMD_NONE;
-				if(data.note > NOTE_MAX && data.note < NOTE_MIN_SPECIAL) data.note = NOTE_NONE;
 				*(target++) = data;
 			}
 		}
@@ -232,7 +315,7 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		uint32 realSample = file.ReadUint32LE();
 		ITSample sampleHeader;
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		FileReader sampleData = file.ReadChunk(file.ReadUint32LE());
 
 		if(realSample >= 1 && realSample <= GetNumSamples() && !memcmp(sampleHeader.id, "IMPS", 4) && (loadFlags & loadSampleData))
@@ -251,23 +334,16 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 		if(instrPaths[ins].empty())
 			continue;
 
-		if(!file.GetFileName().empty())
-		{
-			instrPaths[ins] = instrPaths[ins].RelativePathToAbsolute(file.GetFileName().GetPath());
-		}
-#ifdef MODPLUG_TRACKER
-		else if(GetpModDoc() != nullptr)
-		{
-			instrPaths[ins] = instrPaths[ins].RelativePathToAbsolute(GetpModDoc()->GetPathNameMpt().GetPath());
-		}
-#endif // MODPLUG_TRACKER
-
+#ifdef MPT_EXTERNAL_SAMPLES
 		InputFile f(instrPaths[ins]);
 		FileReader instrFile = GetFileReader(f);
 		if(!ReadInstrumentFromFile(ins + 1, instrFile, true))
 		{
 			AddToLog(LogWarning, MPT_USTRING("Unable to open instrument: ") + instrPaths[ins].ToUnicode());
 		}
+#else
+		AddToLog(LogWarning, mpt::format(MPT_USTRING("Loading external instrument %1 ('%2') failed: External instruments are not supported."))(ins, instrPaths[ins].ToUnicode()));
+#endif // MPT_EXTERNAL_SAMPLES
 	}
 
 	// Extra info data
@@ -308,15 +384,12 @@ bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
 	m_nMinPeriod = 8;
 
 	// Before OpenMPT 1.20.01.09, the MIDI macros were always read from the file, even if the "embed" flag was not set.
-	if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1,20,01,09) && !m_SongFlags[SONG_EMBEDMIDICFG])
+	if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1,20,01,09) && !(songFlags & ITP_EMBEDMIDICFG))
 	{
 		m_MidiCfg.Reset();
-	} else if(!m_MidiCfg.IsMacroDefaultSetupUsed())
-	{
-		m_SongFlags.set(SONG_EMBEDMIDICFG);
 	}
 
-	m_madeWithTracker = "OpenMPT " + MptVersion::ToStr(m_dwLastSavedWithVersion);
+	m_madeWithTracker = MPT_USTRING("OpenMPT ") + MptVersion::ToUString(m_dwLastSavedWithVersion);
 
 	return true;
 #endif // MPT_EXTERNAL_SAMPLES
diff --git a/soundlib/Load_mdl.cpp b/soundlib/Load_mdl.cpp
index d664fb7..55caa27 100644
--- a/soundlib/Load_mdl.cpp
+++ b/soundlib/Load_mdl.cpp
@@ -16,22 +16,18 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // MDL file header
-struct PACKED MDLFileHeader
+struct MDLFileHeader
 {
 	char  id[4];	// "DMDL"
 	uint8 version;
 };
 
-STATIC_ASSERT(sizeof(MDLFileHeader) == 5);
+MPT_BINARY_STRUCT(MDLFileHeader, 5)
 
 
 // RIFF-style Chunk
-struct PACKED MDLChunk
+struct MDLChunk
 {
 	// 16-Bit chunk identifiers
 	enum ChunkIdentifiers
@@ -49,219 +45,71 @@ struct PACKED MDLChunk
 		ifSampleData	= MAGIC2LE('S','A'),
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint16 id;
-	uint32 length;
+	uint16le id;
+	uint32le length;
 
 	size_t GetLength() const
 	{
-		return SwapBytesReturnLE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(MDLChunk) == 6);
+MPT_BINARY_STRUCT(MDLChunk, 6)
 
 
-struct PACKED MDLInfoBlock
+struct MDLInfoBlock
 {
-	char   title[32];
-	char   composer[20];
-	uint16 numOrders;
-	uint16 restartPos;
-	uint8  globalVol;		// 1...255
-	uint8  speed;			// 1...255
-	uint8  tempo;			// 4...255
-	uint8  chnSetup[32];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numOrders);
-		SwapBytesLE(restartPos);
-	}
+	char     title[32];
+	char     composer[20];
+	uint16le numOrders;
+	uint16le restartPos;
+	uint8le  globalVol;	// 1...255
+	uint8le  speed;		// 1...255
+	uint8le  tempo;		// 4...255
+	uint8le  chnSetup[32];
 };
 
-STATIC_ASSERT(sizeof(MDLInfoBlock) == 91);
+MPT_BINARY_STRUCT(MDLInfoBlock, 91)
 
 
 // Sample header in II block
-struct PACKED MDLSampleHeader
+struct MDLSampleHeader
 {
-	uint8  smpNum;
-	uint8  lastNote;
-	uint8  volume;
-	uint8  volEnvFlags; // 6 bits env #, 2 bits flags
-	uint8  panning;
-	uint8  panEnvFlags;
-	uint16 fadeout;
-	uint8  vibSpeed;
-	uint8  vibDepth;
-	uint8  vibSweep;
-	uint8  vibType;
-	uint8  reserved; // zero
-	uint8  freqEnvFlags;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(fadeout);
-	}
+	uint8le  smpNum;
+	uint8le  lastNote;
+	uint8le  volume;
+	uint8le  volEnvFlags;	// 6 bits env #, 2 bits flags
+	uint8le  panning;
+	uint8le  panEnvFlags;
+	uint16le fadeout;
+	uint8le  vibSpeed;
+	uint8le  vibDepth;
+	uint8le  vibSweep;
+	uint8le  vibType;
+	uint8le  reserved;		// zero
+	uint8le  freqEnvFlags;
 };
 
-STATIC_ASSERT(sizeof(MDLSampleHeader) == 14);
+MPT_BINARY_STRUCT(MDLSampleHeader, 14)
 
 
 // Part of the sample header that's common between v0 and v1.
-struct PACKED MDLSampleInfoCommon
-{
-	uint8 sampleIndex;
-	char  name[32];
-	char  filename[8];
-};
-
-STATIC_ASSERT(sizeof(MDLSampleInfoCommon) == 41);
-
-
-struct PACKED MDLSampleInfov0
-{
-	enum SampleFlags
-	{
-		smp16Bit		= 0x01,
-		smpPingPong		= 0x02,
-
-		smpNoPack		= 0x00,
-		smpPack8Bit		= 0x04,
-		smpPack16Bit	= 0x08,
-		smpPackMask		= 0x0C,
-	};
-
-	uint16 c4speed;
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopLength;
-	uint8  volume;
-	uint8  flags;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(c4speed);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopLength);
-	}
-
-	// Convert an MDL sample header to OpenMPT's internal sample header.
-	SampleIO ConvertToMPT(ModSample &mptSmp) const
-	{
-		mptSmp.nC5Speed = c4speed * 2;
-		mptSmp.nLength = length;
-		mptSmp.nVolume = volume;
-		mptSmp.nLoopStart = loopStart;
-		mptSmp.nLoopEnd = loopLength;
-		if(loopLength != 0)
-		{
-			mptSmp.nLoopEnd += mptSmp.nLoopStart;
-			mptSmp.uFlags.set(CHN_LOOP);
-		}
-
-		if(flags & smp16Bit)
-		{
-			mptSmp.uFlags.set(CHN_16BIT);
-			mptSmp.nLength /= 2;
-			mptSmp.nLoopStart /= 2;
-			mptSmp.nLoopEnd /= 2;
-		}
-
-		if(flags & smpPingPong)
-		{
-			mptSmp.uFlags.set(CHN_PINGPONGLOOP);
-		}
-
-		return SampleIO(
-			(flags & smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
-			SampleIO::mono,
-			SampleIO::littleEndian,
-			(flags & smpPackMask) ? SampleIO::MDL : SampleIO::signedPCM);
-	}
-};
-
-STATIC_ASSERT(sizeof(MDLSampleInfov0) == 16);
-
-
-struct PACKED MDLSampleInfo
+struct MDLSampleInfoCommon
 {
-	enum SampleFlags
-	{
-		smp16Bit		= 0x01,
-		smpPingPong		= 0x02,
-
-		smpNoPack		= 0x00,
-		smpPack8Bit		= 0x04,
-		smpPack16Bit	= 0x08,
-		smpPackMask		= 0x0C,
-	};
-
-	uint32 c4speed;
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopLength;
-	uint8  unused;		// was volume in v0.0, why it was changed I have no idea
-	uint8  flags;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(c4speed);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopLength);
-	}
-
-	// Convert an MDL sample header to OpenMPT's internal sample header.
-	SampleIO ConvertToMPT(ModSample &mptSmp) const
-	{
-		mptSmp.nC5Speed = c4speed * 2;
-		mptSmp.nLength = length;
-		mptSmp.nLoopStart = loopStart;
-		mptSmp.nLoopEnd = loopLength;
-		if(loopLength != 0)
-		{
-			mptSmp.nLoopEnd += mptSmp.nLoopStart;
-			mptSmp.uFlags.set(CHN_LOOP);
-		}
-
-		if(flags & smp16Bit)
-		{
-			mptSmp.uFlags.set(CHN_16BIT);
-			mptSmp.nLength /= 2;
-			mptSmp.nLoopStart /= 2;
-			mptSmp.nLoopEnd /= 2;
-		}
-
-		if(flags & smpPingPong)
-		{
-			mptSmp.uFlags.set(CHN_PINGPONGLOOP);
-		}
-
-		return SampleIO(
-			(flags & smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
-			SampleIO::mono,
-			SampleIO::littleEndian,
-			(flags & smpPackMask) ? SampleIO::MDL : SampleIO::signedPCM);
-	}
+	uint8le sampleIndex;
+	char    name[32];
+	char    filename[8];
 };
 
-STATIC_ASSERT(sizeof(MDLSampleInfo) == 18);
+MPT_BINARY_STRUCT(MDLSampleInfoCommon, 41)
 
 
-struct PACKED MDLEnvelope
+struct MDLEnvelope
 {
 	uint8 envNum;
 	struct
@@ -295,22 +143,17 @@ struct PACKED MDLEnvelope
 	}
 };
 
-STATIC_ASSERT(sizeof(MDLEnvelope) == 33);
+MPT_BINARY_STRUCT(MDLEnvelope, 33)
 
 
-struct PACKED MDLPatternHeader
+struct MDLPatternHeader
 {
-	uint8 channels;
-	uint8 lastRow;
-	char  name[16];
+	uint8le channels;
+	uint8le lastRow;
+	char    name[16];
 };
 
-STATIC_ASSERT(sizeof(MDLPatternHeader) == 18);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(MDLPatternHeader, 18)
 
 
 enum
@@ -358,7 +201,6 @@ static const ModCommand::COMMAND MDLEffTrans[] =
 
 // receive an MDL effect, give back a 'normal' one.
 static void ConvertMDLCommand(uint8_t &cmd, uint8_t &param)
-//---------------------------------------------------------
 {
 	if(cmd >= CountOf(MDLEffTrans))
 		return;
@@ -472,7 +314,6 @@ static void ConvertMDLCommand(uint8_t &cmd, uint8_t &param)
 
 // Returns true if command was lost
 static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 e1, uint8 e2, uint8 p1, uint8 p2)
-//---------------------------------------------------------------------------------------------
 {
 	// Map second effect values 1-6 to effects G-L
 	if(e2 >= 1 && e2 <= 6)
@@ -552,7 +393,6 @@ static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 e1, uint8 e2, uint
 
 
 static void MDLReadEnvelopes(FileReader file, std::vector<MDLEnvelope> &envelopes)
-//--------------------------------------------------------------------------------
 {
 	if(!file.CanRead(1))
 		return;
@@ -570,7 +410,6 @@ static void MDLReadEnvelopes(FileReader file, std::vector<MDLEnvelope> &envelope
 
 
 static void CopyEnvelope(InstrumentEnvelope &mptEnv, uint8 flags, std::vector<MDLEnvelope> &envelopes)
-//----------------------------------------------------------------------------------------------------
 {
 	uint8 envNum = flags & 0x3F;
 	if(envNum < envelopes.size())
@@ -579,17 +418,46 @@ static void CopyEnvelope(InstrumentEnvelope &mptEnv, uint8 flags, std::vector<MD
 }
 
 
+static bool ValidateHeader(const MDLFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.id, "DMDL", 4)
+		|| fileHeader.version >= 0x20)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize)
+{
+	MDLFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 	MDLFileHeader fileHeader;
-	if(!file.ReadStruct(fileHeader)
-		|| memcmp(fileHeader.id, "DMDL", 4)
-		|| fileHeader.version >= 0x20)
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -600,7 +468,7 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 	// Read global info
 	FileReader chunk = chunks.GetChunk(MDLChunk::idInfo);
 	MDLInfoBlock info;
-	if(!chunk.IsValid() || !chunk.ReadConvertEndianness(info))
+	if(!chunk.IsValid() || !chunk.ReadStruct(info))
 	{
 		return false;
 	}
@@ -611,11 +479,11 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 	m_playBehaviour.reset(kITVibratoTremoloPanbrello);
 	m_playBehaviour.reset(kITSCxStopsSample);	// Gate effect in underbeat.mdl
 
-	m_madeWithTracker = std::string("Digitrakker ") + (
-		(fileHeader.version == 0x11) ? "3" // really could be 2.99b - close enough
-		: (fileHeader.version == 0x10) ? "2.3"
-		: (fileHeader.version == 0x00) ? "2.0 - 2.2b" // there was no 1.x release
-		: "");
+	m_madeWithTracker = MPT_USTRING("Digitrakker ") + (
+		(fileHeader.version == 0x11) ? MPT_USTRING("3") // really could be 2.99b - close enough
+		: (fileHeader.version == 0x10) ? MPT_USTRING("2.3")
+		: (fileHeader.version == 0x00) ? MPT_USTRING("2.0 - 2.2b") // there was no 1.x release
+		: MPT_USTRING(""));
 
 	mpt::String::Read<mpt::String::spacePadded>(m_songName, info.title);
 	{
@@ -625,11 +493,11 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	m_nDefaultGlobalVolume = info.globalVol + 1;
-	m_nDefaultSpeed = Clamp(info.speed, uint8(1), uint8(255));
-	m_nDefaultTempo.Set(Clamp(info.tempo, uint8(4), uint8(255)));
+	m_nDefaultSpeed = Clamp<uint8, uint8>(info.speed, 1, 255);
+	m_nDefaultTempo.Set(Clamp<uint8, uint8>(info.tempo, 4, 255));
 
-	Order.ReadAsByte(chunk, info.numOrders);
-	Order.SetRestartPos(info.restartPos);
+	ReadOrderFromFile<uint8>(Order(), chunk, info.numOrders);
+	Order().SetRestartPos(info.restartPos);
 
 	m_nChannels = 0;
 	for(CHANNELINDEX c = 0; c < 32; c++)
@@ -677,20 +545,43 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 			mpt::String::Read<mpt::String::spacePadded>(m_szNames[header.sampleIndex], header.name);
 			mpt::String::Read<mpt::String::spacePadded>(sample.filename, header.filename);
 
-			SampleIO sampleIO;
-			if(fileHeader.version >= 0x10)
+			uint32 c4speed;
+			if(fileHeader.version < 0x10)
+				c4speed = chunk.ReadUint16LE();
+			else
+				c4speed = chunk.ReadUint32LE();
+			sample.nC5Speed = c4speed * 2u;
+			sample.nLength = chunk.ReadUint32LE();
+			sample.nLoopStart = chunk.ReadUint32LE();
+			sample.nLoopEnd = chunk.ReadUint32LE();
+			if(sample.nLoopEnd != 0)
 			{
-				MDLSampleInfo sampleHeader;
-				chunk.ReadConvertEndianness(sampleHeader);
-				sampleIO = sampleHeader.ConvertToMPT(sample);
-			} else
+				sample.uFlags.set(CHN_LOOP);
+				sample.nLoopEnd += sample.nLoopStart;
+			}
+			if(fileHeader.version < 0x10)
+				sample.nVolume = chunk.ReadUint8();
+			else
+				chunk.Skip(1);
+			uint8 flags = chunk.ReadUint8();
+
+			if(flags & 0x01)
 			{
-				MDLSampleInfov0 sampleHeader;
-				chunk.ReadConvertEndianness(sampleHeader);
-				sampleIO = sampleHeader.ConvertToMPT(sample);
+				sample.uFlags.set(CHN_16BIT);
+				sample.nLength /= 2u;
+				sample.nLoopStart /= 2u;
+				sample.nLoopEnd /= 2u;
 			}
 
-			if((loadFlags & loadSampleData) && (sample.nLength || sampleIO.GetEncoding() == SampleIO::MDL))
+			sample.uFlags.set(CHN_PINGPONGLOOP, (flags & 0x02) != 0);
+
+			SampleIO sampleIO(
+				(flags & 0x01) ? SampleIO::_16bit : SampleIO::_8bit,
+				SampleIO::mono,
+				SampleIO::littleEndian,
+				(flags & 0x0C) ? SampleIO::MDL : SampleIO::signedPCM);
+
+			if(loadFlags & loadSampleData)
 			{
 				sampleIO.ReadSample(sample, dataChunk);
 			}
@@ -719,13 +610,12 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 				chunk.Skip(32 + sizeof(MDLSampleHeader) * numSamples);
 				continue;
 			}
-			m_nInstruments = std::max<INSTRUMENTINDEX>(m_nInstruments, ins);
 
 			chunk.ReadString<mpt::String::spacePadded>(mptIns->name, 32);
 			while(numSamples--)
 			{
 				MDLSampleHeader sampleHeader;
-				chunk.ReadConvertEndianness(sampleHeader);
+				chunk.ReadStruct(sampleHeader);
 				if(sampleHeader.smpNum == 0)
 					continue;
 				#if 1
@@ -754,20 +644,22 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 					mptIns->VolEnv.nLoopStart = mptIns->VolEnv.nLoopEnd = static_cast<uint8>(mptIns->VolEnv.size() - 1);
 					mptIns->VolEnv.dwFlags.set(ENV_LOOP);
 				}
-				for(InstrumentEnvelope::iterator it = mptIns->PitchEnv.begin(); it != mptIns->PitchEnv.end(); it++)
+				for(auto &p : mptIns->PitchEnv)
 				{
 					// Scale pitch envelope
-					it->value = (it->value * 6u) / 16u;
+					p.value = (p.value * 6u) / 16u;
 				}
 #endif // MODPLUG_TRACKER
 
 				// Samples were already initialized above. Let's hope they are not going to be re-used with different volume / panning / vibrato...
 				ModSample &mptSmp = Samples[sampleHeader.smpNum];
 
-				// Not quite correct - this flag literally enables and disables the default volume of a sample. If you disable this flag,
+				// This flag literally enables and disables the default volume of a sample. If you disable this flag,
 				// the sample volume of a previously sample is re-used, even if you put an instrument number next to the note.
 				if(sampleHeader.volEnvFlags & 0x40)
 					mptSmp.nVolume = sampleHeader.volume;
+				else
+					mptSmp.uFlags.set(SMP_NODEFAULTVOLUME);
 				mptSmp.nPan = std::min<uint16>(sampleHeader.panning * 2, 254);
 				mptSmp.nVibType = MDLVibratoType[sampleHeader.vibType & 3];
 				mptSmp.nVibSweep = sampleHeader.vibSweep;
@@ -816,6 +708,7 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 		}
 		chunk.Seek(1);
 
+		Patterns.ResizeArray(numPats);
 		for(PATTERNINDEX pat = 0; pat < numPats; pat++)
 		{
 			CHANNELINDEX numChans = 32;
@@ -936,7 +829,6 @@ bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
 
 // MDL Huffman ReadBits compression
 uint8 MDLReadBits(uint32 &bitbuf, int32 &bitnum, const uint8 *(&ibuf), size_t &bytesLeft, int8 n)
-//-----------------------------------------------------------------------------------------------
 {
 	if(bitnum < n)
 	{
diff --git a/soundlib/Load_med.cpp b/soundlib/Load_med.cpp
index 2d6ad15..332d12f 100644
--- a/soundlib/Load_med.cpp
+++ b/soundlib/Load_med.cpp
@@ -59,53 +59,49 @@ OPENMPT_NAMESPACE_BEGIN
 #define	MMDTAG_FX_GROUPNAME	(MMDTAG_PTR|5)	// the Global Effects group shouldn't have name saved!
 #define	MMDTAG_FX_GRPNAMELEN 6	// namelen includes zero term.
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 
-typedef struct PACKED tagMEDMODULEHEADER
+struct MEDMODULEHEADER
 {
-	char  id[4];	// MMD1-MMD3
-	uint32 modlen;	// Size of file
-	uint32 song;		// Position in file for this song
-	uint16 psecnum;
-	uint16 pseq;
-	uint32 blockarr;	// Position in file for blocks
-	uint32 mmdflags;
-	uint32 smplarr;	// Position in file for samples
-	uint32 reserved;
-	uint32 expdata;	// Absolute offset in file for ExpData (0 if not present)
-	uint32 reserved2;
-	uint16 pstate;
-	uint16 pblock;
-	uint16 pline;
-	uint16 pseqnum;
-	uint16 actplayline;
-	uint8 counter;
-	uint8 extra_songs;	// # of songs - 1
-} MEDMODULEHEADER;
-
-STATIC_ASSERT(sizeof(MEDMODULEHEADER) == 52);
-
-
-typedef struct PACKED tagMMD0SAMPLE
+	char     id[4];		// MMD1-MMD3
+	uint32be modlen;	// Size of file
+	uint32be song;		// Position in file for this song
+	uint16be psecnum;
+	uint16be pseq;
+	uint32be blockarr;	// Position in file for blocks
+	uint32be mmdflags;
+	uint32be smplarr;	// Position in file for samples
+	uint32be reserved;
+	uint32be expdata;	// Absolute offset in file for ExpData (0 if not present)
+	uint32be reserved2;
+	uint16be pstate;
+	uint16be pblock;
+	uint16be pline;
+	uint16be pseqnum;
+	uint16be actplayline;
+	uint8be  counter;
+	uint8be  extra_songs;	// # of songs - 1
+};
+
+MPT_BINARY_STRUCT(MEDMODULEHEADER, 52)
+
+
+struct MMD0SAMPLE
 {
-	uint16 rep, replen;
-	uint8 midich;
-	uint8 midipreset;
-	uint8 svol;
-	signed char strans;
-} MMD0SAMPLE;
+	uint16be rep, replen;
+	uint8be  midich;
+	uint8be  midipreset;
+	uint8be  svol;
+	int8be   strans;
+};
 
-STATIC_ASSERT(sizeof(MMD0SAMPLE) == 8);
+MPT_BINARY_STRUCT(MMD0SAMPLE, 8)
 
 
 // Sample header is immediately followed by sample data...
-typedef struct PACKED tagMMDSAMPLEHEADER
+struct MMDSAMPLEHEADER
 {
-	uint32 length;     // length of *one* *unpacked* channel in *bytes*
-	uint16 type;
+	uint32be length;     // length of *one* *unpacked* channel in *bytes*
+	uint16be type;
 				// if non-negative
 					// bits 0-3 reserved for multi-octave instruments, not supported on the PC
 					// 0x10: 16 bit (otherwise 8 bit)
@@ -115,73 +111,73 @@ typedef struct PACKED tagMMDSAMPLEHEADER
 				// -1: Synth
 				// -2: Hybrid
 	// if type indicates packed data, these fields follow, otherwise we go right to the data
-	uint16 packtype;	// Only 1 = ADPCM is supported
-	uint16 subtype;	// Packing subtype
+	uint16be packtype;	// Only 1 = ADPCM is supported
+	uint16be subtype;	// Packing subtype
 		// ADPCM subtype
 		// 1: g723_40
 		// 2: g721
 		// 3: g723_24
-	uint8 commonflags;	// flags common to all packtypes (none defined so far)
-	uint8 packerflags;	// flags for the specific packtype
-	uint32 leftchlen;	// packed length of left channel in bytes
-	uint32 rightchlen;	// packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES)
-	uint8 SampleData[1];	// Sample Data
-} MMDSAMPLEHEADER;
+	uint8be  commonflags;	// flags common to all packtypes (none defined so far)
+	uint8be  packerflags;	// flags for the specific packtype
+	uint32be leftchlen;	// packed length of left channel in bytes
+	uint32be rightchlen;	// packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES)
+	uint8be  SampleData[1];	// Sample Data
+};
 
-STATIC_ASSERT(sizeof(MMDSAMPLEHEADER) == 21);
+MPT_BINARY_STRUCT(MMDSAMPLEHEADER, 21)
 
 
 // MMD0/MMD1 song header
-typedef struct PACKED tagMMD0SONGHEADER
+struct MMD0SONGHEADER
 {
 	MMD0SAMPLE sample[63];
-	uint16 numblocks;		// # of blocks
-	uint16 songlen;		// # of entries used in playseq
-	uint8 playseq[256];	// Play sequence
-	uint16 deftempo;		// BPM tempo
-	signed char playtransp;	// Play transpose
-	uint8 flags;			// 0x10: Hex Volumes | 0x20: ST/NT/PT Slides | 0x40: 8 Channels song
-	uint8 flags2;		// [b4-b0]+1: Tempo LPB, 0x20: tempo mode, 0x80: mix_conv=on
-	uint8 tempo2;		// tempo TPL
-	uint8 trkvol[16];	// track volumes
-	uint8 mastervol;		// master volume
-	uint8 numsamples;	// # of samples (max=63)
-} MMD0SONGHEADER;
-
-STATIC_ASSERT(sizeof(MMD0SONGHEADER) == 788);
+	uint16be numblocks;		// # of blocks
+	uint16be songlen;		// # of entries used in playseq
+	uint8be  playseq[256];	// Play sequence
+	uint16be deftempo;		// BPM tempo
+	int8be   playtransp;	// Play transpose
+	uint8be  flags;			// 0x10: Hex Volumes | 0x20: ST/NT/PT Slides | 0x40: 8 Channels song
+	uint8be  flags2;		// [b4-b0]+1: Tempo LPB, 0x20: tempo mode, 0x80: mix_conv=on
+	uint8be  tempo2;		// tempo TPL
+	uint8be  trkvol[16];	// track volumes
+	uint8be  mastervol;		// master volume
+	uint8be  numsamples;	// # of samples (max=63)
+};
+
+MPT_BINARY_STRUCT(MMD0SONGHEADER, 788)
 
 
 // MMD2/MMD3 song header
-typedef struct PACKED tagMMD2SONGHEADER
+struct MMD2SONGHEADER
 {
 	MMD0SAMPLE sample[63];
-	uint16 numblocks;		// # of blocks
-	uint16 numsections;	// # of sections
-	uint32 playseqtable;	// filepos of play sequence
-	uint32 sectiontable;	// filepos of sections table (uint16 array)
-	uint32 trackvols;	// filepos of tracks volume (uint8 array)
-	uint16 numtracks;		// # of tracks (max 64)
-	uint16 numpseqs;		// # of play sequences
-	uint32 trackpans;	// filepos of tracks pan values (uint8 array)
-	int32 flags3;		// 0x1:stereo_mix, 0x2:free_panning, 0x4:GM/XG compatibility
-	uint16 voladj;		// vol_adjust (set to 100 if 0)
-	uint16 channels;		// # of channels (4 if =0)
-	uint8 mix_echotype;	// 1:normal,2:xecho
-	uint8 mix_echodepth;	// 1..6
-	uint16 mix_echolen;	// > 0
-	signed char mix_stereosep;	// -4..4
-	uint8 pad0[223];
-	uint16 deftempo;		// BPM tempo
-	signed char playtransp;	// play transpose
-	uint8 flags;			// 0x1:filteron, 0x2:jumpingon, 0x4:jump8th, 0x8:instr_attached, 0x10:hex_vol, 0x20:PT_slides, 0x40:8ch_conv,0x80:hq slows playing speed
-	uint8 flags2;		// 0x80:mix_conv=on, [b4-b0]+1:tempo LPB, 0x20:tempo_mode
-	uint8 tempo2;		// tempo TPL
-	uint8 pad1[16];
-	uint8 mastervol;		// master volume
-	uint8 numsamples;	// # of samples (max 63)
-} MMD2SONGHEADER;
-
-STATIC_ASSERT(sizeof(MMD2SONGHEADER) == 788);
+	uint16be numblocks;		// # of blocks
+	uint16be numsections;	// # of sections
+	uint32be playseqtable;	// filepos of play sequence
+	uint32be sectiontable;	// filepos of sections table (uint16_be array)
+	uint32be trackvols;		// filepos of tracks volume (uint8_be array)
+	uint16be numtracks;		// # of tracks (max 64)
+	uint16be numpseqs;		// # of play sequences
+	uint32be trackpans;		// filepos of tracks pan values (uint8_be array)
+	int32be  flags3;		// 0x1:stereo_mix, 0x2:free_panning, 0x4:GM/XG compatibility
+	uint16be voladj;		// vol_adjust (set to 100 if 0)
+	uint16be channels;		// # of channels (4 if =0)
+	uint8be  mix_echotype;	// 1:normal,2:xecho
+	uint8be  mix_echodepth;	// 1..6
+	uint16be mix_echolen;	// > 0
+	int8be   mix_stereosep;	// -4..4
+	uint8be  pad0[223];
+	uint16be deftempo;		// BPM tempo
+	int8be   playtransp;	// play transpose
+	uint8be  flags;			// 0x1:filteron, 0x2:jumpingon, 0x4:jump8th, 0x8:instr_attached, 0x10:hex_vol, 0x20:PT_slides, 0x40:8ch_conv,0x80:hq slows playing speed
+	uint8be  flags2;		// 0x80:mix_conv=on, [b4-b0]+1:tempo LPB, 0x20:tempo_mode
+	uint8be  tempo2;		// tempo TPL
+	uint8be  pad1[16];
+	uint8be  mastervol;		// master volume
+	uint8be  numsamples;	// # of samples (max 63)
+};
+
+MPT_BINARY_STRUCT(MMD2SONGHEADER, 788)
 
 
 // For MMD0 the note information is held in 3 bytes, byte0, byte1, byte2.  For reference we
@@ -191,13 +187,13 @@ STATIC_ASSERT(sizeof(MMD2SONGHEADER) == 788);
 // The command number is bits 3,2,1,0 of byte1, command data is in byte2:
 // For command 0, byte2 represents the second data byte, otherwise byte2
 // represents the first data byte.
-typedef struct PACKED tagMMD0BLOCK
+struct MMD0BLOCK
 {
-	uint8 numtracks;
-	uint8 lines;		// File value is 1 less than actual, so 0 -> 1 line
-} MMD0BLOCK;			// uint8 data[lines+1][tracks][3];
+	uint8be numtracks;
+	uint8be lines;		// File value is 1 less than actual, so 0 -> 1 line
+};			// uint8_be data[lines+1][tracks][3];
 
-STATIC_ASSERT(sizeof(MMD0BLOCK) == 2);
+MPT_BINARY_STRUCT(MMD0BLOCK, 2)
 
 
 // For MMD1,MMD2,MMD3 the note information is carried in 4 bytes, byte0, byte1,
@@ -207,102 +203,95 @@ STATIC_ASSERT(sizeof(MMD0BLOCK) == 2);
 // The command number is held as byte2, command data is in byte3
 // For commands 0 and 0x19 byte3 represents the second data byte,
 // otherwise byte2 represents the first data byte.
-typedef struct PACKED tagMMD1BLOCK
+struct MMD1BLOCK
 {
-	uint16 numtracks;	// Number of tracks, may be > 64, but then that data is skipped.
-	uint16 lines;		// Stored value is 1 less than actual, so 0 -> 1 line
-	uint32 info;		// Offset of BlockInfo (if 0, no block_info is present)
-} MMD1BLOCK;
+	uint16be numtracks;	// Number of tracks, may be > 64, but then that data is skipped.
+	uint16be lines;		// Stored value is 1 less than actual, so 0 -> 1 line
+	uint32be info;			// Offset of BlockInfo (if 0, no block_info is present)
+};
 
-STATIC_ASSERT(sizeof(MMD1BLOCK) == 8);
+MPT_BINARY_STRUCT(MMD1BLOCK, 8)
 
 
-typedef struct PACKED tagMMD1BLOCKINFO
+struct MMD1BLOCKINFO
 {
-	uint32 hlmask;		// Unimplemented - ignore
-	uint32 blockname;	// file offset of block name
-	uint32 blocknamelen;	// length of block name (including term. 0)
-	uint32 pagetable;	// file offset of command page table
-	uint32 cmdexttable;	// file offset of command extension table
-	uint32 reserved[4];	// future expansion
-} MMD1BLOCKINFO;
+	uint32be hlmask;		// Unimplemented - ignore
+	uint32be blockname;		// file offset of block name
+	uint32be blocknamelen;	// length of block name (including term. 0)
+	uint32be pagetable;		// file offset of command page table
+	uint32be cmdexttable;	// file offset of command extension table
+	uint32be reserved[4];	// future expansion
+};
 
-STATIC_ASSERT(sizeof(MMD1BLOCKINFO) == 36);
+MPT_BINARY_STRUCT(MMD1BLOCKINFO, 36)
 
 
-// A set of play sequences is stored as an array of uint32 files offsets
+// A set of play sequences is stored as an array of uint32_be files offsets
 // Each offset points to the play sequence itself.
-typedef struct PACKED tagMMD2PLAYSEQ
+struct MMD2PLAYSEQ
 {
-	char name[32];
-	uint32 command_offs;	// filepos of command table
-	uint32 reserved;
-	uint16 length;
-	uint16 seq[512];	// skip if > 0x8000
-} MMD2PLAYSEQ;
+	char     name[32];
+	uint32be command_offs;	// filepos of command table
+	uint32be reserved;
+	uint16be length;
+	uint16be seq[512];		// skip if > 0x8000
+};
 
-STATIC_ASSERT(sizeof(MMD2PLAYSEQ) == 1066);
+MPT_BINARY_STRUCT(MMD2PLAYSEQ, 1066)
 
 
 // A command table contains commands that effect a particular play sequence
 // entry.  The only commands read in are STOP or POSJUMP, all others are ignored
 // POSJUMP is presumed to have extra bytes containing a uint16 for the position
-typedef struct PACKED tagMMDCOMMAND
+struct MMDCOMMAND
 {
-	uint16 offset;			// Offset within current sequence entry
-	uint8 cmdnumber;		// STOP (537) or POSJUMP (538) (others skipped)
-	uint8 extra_count;
-	uint8 extra_bytes[4];	// [extra_count];
-} MMDCOMMAND;  // Last entry has offset == 0xFFFF, cmd_number == 0 and 0 extrabytes
+	uint16be offset;			// Offset within current sequence entry
+	uint8be cmdnumber;			// STOP (537) or POSJUMP (538) (others skipped)
+	uint8be extra_count;
+	uint8be extra_bytes[4];	// [extra_count];
+};  // Last entry has offset == 0xFFFF, cmd_number == 0 and 0 extrabytes
 
-STATIC_ASSERT(sizeof(MMDCOMMAND) == 8);
+MPT_BINARY_STRUCT(MMDCOMMAND, 8)
 
 
-typedef struct PACKED tagMMD0EXP
+struct MMD0EXP
 {
-	uint32 nextmod;			// File offset of next Hdr
-	uint32 exp_smp;			// Pointer to extra instrument data
-	uint16 s_ext_entries;	// Number of extra instrument entries
-	uint16 s_ext_entrsz;	// Size of extra instrument data
-	uint32 annotxt;
-	uint32 annolen;
-	uint32 iinfo;			// Instrument names
-	uint16 i_ext_entries;
-	uint16 i_ext_entrsz;
-	uint32 jumpmask;
-	uint32 rgbtable;
-	uint8  channelsplit[4];	// Only used if 8ch_conv (extra channel for every nonzero entry)
-	uint32 n_info;
-	uint32 songname;		// Song name
-	uint32 songnamelen;
-	uint32 dumps;
-	uint32 mmdinfo;
-	uint32 mmdrexx;
-	uint32 mmdcmd3x;
-	uint32 trackinfo_ofs;	// ptr to song->numtracks ptrs to tag lists
-	uint32 effectinfo_ofs;	// ptr to group ptrs
-	uint32 tag_end;
-} MMD0EXP;
-
-STATIC_ASSERT(sizeof(MMD0EXP) == 80);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
+	uint32be nextmod;			// File offset of next Hdr
+	uint32be exp_smp;			// Pointer to extra instrument data
+	uint16be s_ext_entries;		// Number of extra instrument entries
+	uint16be s_ext_entrsz;		// Size of extra instrument data
+	uint32be annotxt;
+	uint32be annolen;
+	uint32be iinfo;				// Instrument names
+	uint16be i_ext_entries;
+	uint16be i_ext_entrsz;
+	uint32be jumpmask;
+	uint32be rgbtable;
+	uint8be  channelsplit[4];	// Only used if 8ch_conv (extra channel for every nonzero entry)
+	uint32be n_info;
+	uint32be songname;			// Song name
+	uint32be songnamelen;
+	uint32be dumps;
+	uint32be mmdinfo;
+	uint32be mmdrexx;
+	uint32be mmdcmd3x;
+	uint32be trackinfo_ofs;		// ptr to song->numtracks ptrs to tag lists
+	uint32be effectinfo_ofs;	// ptr to group ptrs
+	uint32be tag_end;
+};
+
+MPT_BINARY_STRUCT(MMD0EXP, 80)
 
 
 static const uint8 bpmvals[9] = { 179,164,152,141,131,123,116,110,104};
 
-static void MedConvert(ModCommand *p, const MMD0SONGHEADER *pmsh)
-//---------------------------------------------------------------
+static void MedConvert(ModCommand &p, const MMD0SONGHEADER *pmsh)
 {
-	ModCommand::COMMAND command = p->command;
-	uint32 param = p->param;
+	ModCommand::COMMAND command = p.command;
+	uint32 param = p.param;
 	switch(command)
 	{
-	case 0x00:	if (param) command = CMD_ARPEGGIO; else command = 0; break;
+	case 0x00:	if (param) command = CMD_ARPEGGIO; else command = CMD_NONE; break;
 	case 0x01:	command = CMD_PORTAMENTOUP; break;
 	case 0x02:	command = CMD_PORTAMENTODOWN; break;
 	case 0x03:	command = CMD_TONEPORTAMENTO; break;
@@ -310,7 +299,7 @@ static void MedConvert(ModCommand *p, const MMD0SONGHEADER *pmsh)
 	case 0x05:	command = CMD_TONEPORTAVOL; break;
 	case 0x06:	command = CMD_VIBRATOVOL; break;
 	case 0x07:	command = CMD_TREMOLO; break;
-	case 0x0A:	if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
+	case 0x0A:	if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = CMD_NONE; break;
 	case 0x0B:	command = CMD_POSITIONJUMP; break;
 	case 0x0C:	command = CMD_VOLUME;
 				if (pmsh->flags & MMD_FLAG_VOLHEX)
@@ -318,18 +307,18 @@ static void MedConvert(ModCommand *p, const MMD0SONGHEADER *pmsh)
 					if (param < 0x80)
 					{
 						param = (param+1) / 2;
-					} else command = 0;
+					} else command = CMD_NONE;
 				} else
 				{
 					if (param <= 0x99)
 					{
 						param = (param >> 4)*10+((param & 0x0F) % 10);
 						if (param > 64) param = 64;
-					} else command = 0;
+					} else command = CMD_NONE;
 				}
 				break;
 	case 0x09:	command = static_cast<ModCommand::COMMAND>((param <= 0x20) ? CMD_SPEED : CMD_TEMPO); break;
-	case 0x0D:	if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
+	case 0x0D:	if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = CMD_NONE; break;
 	case 0x0F:	// Set Tempo / Special
 		// F.00 = Pattern Break
 		if (!param)	command = CMD_PATTERNBREAK;	else
@@ -414,7 +403,8 @@ static void MedConvert(ModCommand *p, const MMD0SONGHEADER *pmsh)
 #ifdef MED_LOG
 			Log("Unknown Fxx command: cmd=0x%02X param=0x%02X\n", command, param);
 #endif
-			param = command = 0;
+			command = CMD_NONE;
+			param = 0;
 		}
 		break;
 	// 11.0x: Fine Slide Up
@@ -494,30 +484,71 @@ static void MedConvert(ModCommand *p, const MMD0SONGHEADER *pmsh)
 		// 0x2E ?
 		Log("Unknown command: cmd=0x%02X param=0x%02X\n", command, param);
 #endif
-		command = 0;
+		command = CMD_NONE;
 		param = 0;
 	}
-	p->command = command;
-	p->param = static_cast<ModCommand::PARAM>(param);
+	p.command = command;
+	p.param = static_cast<ModCommand::PARAM>(param);
+}
+
+
+static bool ValidateHeader(const MEDMODULEHEADER &pmmh)
+{
+	if(std::memcmp(pmmh.id, "MMD", 3)
+		|| pmmh.id[3] < '0' || pmmh.id[3] > '3'
+		|| pmmh.song == 0
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MEDMODULEHEADER &pmmh)
+{
+	MPT_UNREFERENCED_PARAMETER(pmmh);
+	return sizeof(MMD0SONGHEADER);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize)
+{
+	MEDMODULEHEADER pmmh;
+	if(!file.ReadStruct(pmmh))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(pmmh))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(pmmh));
 }
 
 
 bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
-//------------------------------------------------------------------
 {
 	file.Rewind();
 	MEDMODULEHEADER pmmh;
-	uint32 dwSong;
-	if(!file.CanRead(512)
-		|| !file.ReadStruct(pmmh)
-		|| memcmp(pmmh.id, "MMD", 3)
-		|| pmmh.id[3] < '0' || pmmh.id[3] > '3'
-		|| (dwSong = BigEndian(pmmh.song)) == 0
-		|| !file.LengthIsAtLeast(dwSong)
-		|| !file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+	if(!file.ReadStruct(pmmh))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(pmmh))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(pmmh))))
+	{
+		return false;
+	}
+	const uint32 dwSong = pmmh.song;
+	if(!file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -528,102 +559,36 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 	const MMD0SONGHEADER *pmsh;
 	const MMD2SONGHEADER *pmsh2;
 	const MMD0EXP *pmex;
-	uint32 dwBlockArr, dwSmplArr, dwExpData, wNumBlocks;
-	const_unaligned_ptr_le<uint32> pdwTable;
+	uint32 dwBlockArr, dwSmplArr, dwExpData;
+	const_unaligned_ptr_be<uint32> pdwTable;
 	int8 version = pmmh.id[3];
 	uint32 deftempo;
 	int playtransp = 0;
 
-#ifdef MED_LOG
-	Log("\nLoading MMD%c module (flags=0x%02X)...\n", version, BigEndian(pmmh.mmdflags));
-	Log("  modlen   = %d\n", BigEndian(pmmh.modlen));
-	Log("  song     = 0x%08X\n", BigEndian(pmmh.song));
-	Log("  psecnum  = %d\n", BigEndianW(pmmh.psecnum));
-	Log("  pseq     = %d\n", BigEndianW(pmmh.pseq));
-	Log("  blockarr = 0x%08X\n", BigEndian(pmmh.blockarr));
-	Log("  mmdflags = 0x%08X\n", BigEndian(pmmh.mmdflags));
-	Log("  smplarr  = 0x%08X\n", BigEndian(pmmh.smplarr));
-	Log("  reserved = 0x%08X\n", BigEndian(pmmh.reserved));
-	Log("  expdata  = 0x%08X\n", BigEndian(pmmh.expdata));
-	Log("  reserved2= 0x%08X\n", BigEndian(pmmh.reserved2));
-	Log("  pstate   = %d\n", BigEndianW(pmmh.pstate));
-	Log("  pblock   = %d\n", BigEndianW(pmmh.pblock));
-	Log("  pline    = %d\n", BigEndianW(pmmh.pline));
-	Log("  pseqnum  = %d\n", BigEndianW(pmmh.pseqnum));
-	Log("  actplayline=%d\n", BigEndianW(pmmh.actplayline));
-	Log("  counter  = %d\n", pmmh.counter);
-	Log("  extra_songs = %d\n", pmmh.extra_songs);
-	Log("\n");
-#endif
-
 	InitializeGlobals(MOD_TYPE_MED);
 	InitializeChannels();
 	// Setup channel pan positions and volume
 	SetupMODPanning(true);
-	m_madeWithTracker = mpt::String::Print("OctaMED (MMD%1)", std::string(1, version));
+	m_madeWithTracker = mpt::format(MPT_USTRING("OctaMED (MMD%1)"))(mpt::ToUnicode(mpt::CharsetISO8859_1, std::string(1, version)));
 
 	m_nSamplePreAmp = 32;
-	dwBlockArr = BigEndian(pmmh.blockarr);
-	dwSmplArr = BigEndian(pmmh.smplarr);
-	dwExpData = BigEndian(pmmh.expdata);
+	dwBlockArr = pmmh.blockarr;
+	dwSmplArr = pmmh.smplarr;
+	dwExpData = pmmh.expdata;
 	if ((dwExpData) && (dwExpData < dwMemLength - sizeof(MMD0EXP)))
 		pmex = (const MMD0EXP *)(lpStream+dwExpData);
 	else
 		pmex = NULL;
 	pmsh = (const MMD0SONGHEADER *)(lpStream + dwSong);
 	pmsh2 = (const MMD2SONGHEADER *)pmsh;
-#ifdef MED_LOG
-	if (version < '2')
-	{
-		Log("MMD0 Header:\n");
-		Log("  numblocks  = %d\n", BigEndianW(pmsh->numblocks));
-		Log("  songlen    = %d\n", BigEndianW(pmsh->songlen));
-		Log("  playseq    = ");
-		for (uint32 idbg1=0; idbg1<16; idbg1++) Log("%2d, ", pmsh->playseq[idbg1]);
-		Log("...\n");
-		Log("  deftempo   = 0x%04X\n", BigEndianW(pmsh->deftempo));
-		Log("  playtransp = %d\n", (signed char)pmsh->playtransp);
-		Log("  flags(1,2) = 0x%02X, 0x%02X\n", pmsh->flags, pmsh->flags2);
-		Log("  tempo2     = %d\n", pmsh->tempo2);
-		Log("  trkvol     = ");
-		for (uint32 idbg2=0; idbg2<16; idbg2++) Log("0x%02X, ", pmsh->trkvol[idbg2]);
-		Log("...\n");
-		Log("  mastervol  = 0x%02X\n", pmsh->mastervol);
-		Log("  numsamples = %d\n", pmsh->numsamples);
-	} else
-	{
-		Log("MMD2 Header:\n");
-		Log("  numblocks  = %d\n", BigEndianW(pmsh2->numblocks));
-		Log("  numsections= %d\n", BigEndianW(pmsh2->numsections));
-		Log("  playseqptr = 0x%04X\n", BigEndian(pmsh2->playseqtable));
-		Log("  sectionptr = 0x%04X\n", BigEndian(pmsh2->sectiontable));
-		Log("  trackvols  = 0x%04X\n", BigEndian(pmsh2->trackvols));
-		Log("  numtracks  = %d\n", BigEndianW(pmsh2->numtracks));
-		Log("  numpseqs   = %d\n", BigEndianW(pmsh2->numpseqs));
-		Log("  trackpans  = 0x%04X\n", BigEndian(pmsh2->trackpans));
-		Log("  flags3     = 0x%08X\n", BigEndian(pmsh2->flags3));
-		Log("  voladj     = %d\n", BigEndianW(pmsh2->voladj));
-		Log("  channels   = %d\n", BigEndianW(pmsh2->channels));
-		Log("  echotype   = %d\n", pmsh2->mix_echotype);
-		Log("  echodepth  = %d\n", pmsh2->mix_echodepth);
-		Log("  echolen    = %d\n", BigEndianW(pmsh2->mix_echolen));
-		Log("  stereosep  = %d\n", (signed char)pmsh2->mix_stereosep);
-		Log("  deftempo   = 0x%04X\n", BigEndianW(pmsh2->deftempo));
-		Log("  playtransp = %d\n", (signed char)pmsh2->playtransp);
-		Log("  flags(1,2) = 0x%02X, 0x%02X\n", pmsh2->flags, pmsh2->flags2);
-		Log("  tempo2     = %d\n", pmsh2->tempo2);
-		Log("  mastervol  = 0x%02X\n", pmsh2->mastervol);
-		Log("  numsamples = %d\n", pmsh->numsamples);
-	}
-	Log("\n");
-#endif
-	wNumBlocks = BigEndianW(pmsh->numblocks);
+
+	uint16 wNumBlocks = pmsh->numblocks;
 	m_nChannels = 4;
 	m_nSamples = pmsh->numsamples;
 	if (m_nSamples > 63) m_nSamples = 63;
 	// Tempo
 	m_nDefaultTempo.Set(125);
-	deftempo = BigEndianW(pmsh->deftempo);
+	deftempo = pmsh->deftempo;
 	if (!deftempo) deftempo = 125;
 	if (pmsh->flags2 & MMD_FLAG2_BPM)
 	{
@@ -632,7 +597,7 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 		deftempo *= tempo_tpl;
 		deftempo /= 4;
 	#ifdef MED_LOG
-		Log("newtempo: %3d bpm (bpm=%3d lpb=%2d)\n", deftempo, BigEndianW(pmsh->deftempo), (pmsh->flags2 & MMD_FLAG2_BMASK)+1);
+		Log("newtempo: %3d bpm (bpm=%3d lpb=%2d)\n", deftempo, pmsh->deftempo, (pmsh->flags2 & MMD_FLAG2_BMASK)+1);
 	#endif
 	} else
 	{
@@ -641,7 +606,7 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 		else
 			deftempo = Util::muldiv(deftempo, 5 * 715909, 2 * 474326);
 	#ifdef MED_LOG
-		Log("oldtempo: %3d bpm (bpm=%3d)\n", deftempo, BigEndianW(pmsh->deftempo));
+		Log("oldtempo: %3d bpm (bpm=%3d)\n", deftempo, pmsh->deftempo);
 	#endif
 	}
 	// Speed
@@ -653,8 +618,8 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 	for (uint32 iSHdr=0; iSHdr<m_nSamples; iSHdr++)
 	{
 		ModSample &sample = Samples[iSHdr + 1];
-		sample.nLoopStart = BigEndianW(pmsh->sample[iSHdr].rep) << 1;
-		sample.nLoopEnd = sample.nLoopStart + (BigEndianW(pmsh->sample[iSHdr].replen) << 1);
+		sample.nLoopStart = pmsh->sample[iSHdr].rep * 2u;
+		sample.nLoopEnd = sample.nLoopStart + (pmsh->sample[iSHdr].replen * 2u);
 		sample.nVolume = (pmsh->sample[iSHdr].svol << 2);
 		sample.nGlobalVol = 64;
 		if (sample.nVolume > 256) sample.nVolume = 256;
@@ -671,32 +636,31 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 	// Reading play sequence
 	if (version < '2')
 	{
-		uint32 nbo = BigEndianW(pmsh->songlen);
-		if (nbo >= MAX_ORDERS) nbo = MAX_ORDERS-1;
+		uint32 nbo = pmsh->songlen;
 		if (!nbo) nbo = 1;
-		Order.ReadFromArray(pmsh->playseq, nbo);
+		ReadOrderFromArray(Order(), pmsh->playseq, nbo);
 		playtransp = pmsh->playtransp;
 	} else
 	{
 		uint32 nSections;
 		ORDERINDEX nOrders = 0;
-		uint16 nTrks = BigEndianW(pmsh2->numtracks);
+		uint16 nTrks = pmsh2->numtracks;
 		if ((nTrks >= 4) && (nTrks <= 32)) m_nChannels = nTrks;
-		uint32 playseqtable = BigEndian(pmsh2->playseqtable);
-		uint32 numplayseqs = BigEndianW(pmsh2->numpseqs);
+		uint32 playseqtable = pmsh2->playseqtable;
+		uint32 numplayseqs = pmsh2->numpseqs;
 		if (!numplayseqs) numplayseqs = 1;
-		nSections = BigEndianW(pmsh2->numsections);
-		uint32 sectiontable = BigEndian(pmsh2->sectiontable);
+		nSections = pmsh2->numsections;
+		uint32 sectiontable = pmsh2->sectiontable;
 		if ((!nSections) || (!sectiontable) || (sectiontable >= dwMemLength-2)) nSections = 1;
 		nOrders = 0;
-		Order.resize(0);
+		Order().clear();
 		for (uint32 iSection=0; iSection<nSections; iSection++)
 		{
 			uint32 nplayseq = 0;
 			if (sectiontable && sectiontable < dwMemLength && 2 >= dwMemLength - sectiontable)
 			{
-				nplayseq = lpStream[sectiontable+1];
-				sectiontable += 2; // uint16s
+				nplayseq = *const_unaligned_ptr_be<uint16>(lpStream + sectiontable);
+				sectiontable += 2;
 			} else
 			{
 				nSections = 0;
@@ -705,22 +669,22 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 
 			if ((playseqtable) && (playseqtable < dwMemLength) && (nplayseq * 4 <= dwMemLength - playseqtable))
 			{
-				pseq = BigEndian((const_unaligned_ptr_le<uint32>(lpStream+playseqtable))[nplayseq]);
+				pseq = (const_unaligned_ptr_be<uint32>(lpStream+playseqtable))[nplayseq];
 			}
 			if (pseq && pseq < dwMemLength && sizeof(MMD2PLAYSEQ) <= dwMemLength - pseq)
 			{
 				const MMD2PLAYSEQ *pmps = (const MMD2PLAYSEQ *)(lpStream + pseq);
 				if(m_songName.empty()) mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, pmps->name);
-				ORDERINDEX n = std::min<ORDERINDEX>(BigEndianW(pmps->length), ORDERINDEX_MAX - nOrders);
-				if (n <= (dwMemLength - pseq + 42) / 2u)
+				ORDERINDEX n = std::min<ORDERINDEX>(pmps->length, MAX_ORDERS - nOrders);
+				if (n <= (dwMemLength - pseq + 42) / 2u && n < MPT_ARRAY_COUNT(pmps->seq))
 				{
-					Order.resize(nOrders + n);
+					Order().resize(nOrders + n);
 					for (uint32 i=0; i<n; i++)
 					{
-						uint16 seqval = BigEndianW(pmps->seq[i]);
-						if ((seqval < wNumBlocks) && (nOrders < MAX_ORDERS-1))
+						uint16 seqval = pmps->seq[i];
+						if (seqval < wNumBlocks)
 						{
-							Order[nOrders++] = (ORDERINDEX)seqval;
+							Order()[nOrders++] = static_cast<ORDERINDEX>(seqval);
 						}
 					}
 				}
@@ -740,53 +704,53 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 			}
 		}
 		// Song Comments (null-terminated)
-		uint32 annotxt = BigEndian(pmex->annotxt);
-		uint32 annolen = BigEndian(pmex->annolen);
+		uint32 annotxt = pmex->annotxt;
+		uint32 annolen = pmex->annolen;
 		annolen = std::min<uint32>(annolen, MED_MAX_COMMENT_LENGTH); //Thanks to Luigi Auriemma for pointing out an overflow risk
 		if ((annotxt) && (annolen) && (annolen <= dwMemLength) && (annotxt <= dwMemLength - annolen) )
 		{
 			m_songMessage.Read(lpStream + annotxt, annolen - 1, SongMessage::leAutodetect);
 		}
 		// Song Name
-		uint32 songname = BigEndian(pmex->songname);
-		uint32 songnamelen = BigEndian(pmex->songnamelen);
+		uint32 songname = pmex->songname;
+		uint32 songnamelen = pmex->songnamelen;
 		if ((songname) && (songnamelen) && (songname <= dwMemLength) && (songnamelen <= dwMemLength-songname))
 		{
-			mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, reinterpret_cast<const char *>(lpStream + songname), songnamelen);
+			mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, lpStream + songname, songnamelen);
 		}
 		// Sample Names
-		uint32 smpinfoex = BigEndian(pmex->iinfo);
+		uint32 smpinfoex = pmex->iinfo;
 		if (smpinfoex)
 		{
-			uint32 iinfoptr = BigEndian(pmex->iinfo);
-			uint32 ientries = BigEndianW(pmex->i_ext_entries);
-			uint32 ientrysz = BigEndianW(pmex->i_ext_entrsz);
+			uint32 iinfoptr = pmex->iinfo;
+			uint32 ientries = pmex->i_ext_entries;
+			uint32 ientrysz = pmex->i_ext_entrsz;
 
 			if ((iinfoptr) && (ientrysz < 256) && (ientries*ientrysz < dwMemLength) && (iinfoptr < dwMemLength - ientries*ientrysz))
 			{
 				const char *psznames = (const char *)(lpStream + iinfoptr);
 				for (uint32 i=0; i<ientries; i++) if (i < m_nSamples)
 				{
-					mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[i + 1], reinterpret_cast<const char *>(psznames + i * ientrysz), ientrysz);
+					mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[i + 1], (psznames + i * ientrysz), ientrysz);
 				}
 			}
 		}
 		// Track Names
-		uint32 trackinfo_ofs = BigEndian(pmex->trackinfo_ofs);
+		uint32 trackinfo_ofs = pmex->trackinfo_ofs;
 		if ((trackinfo_ofs) && (trackinfo_ofs < dwMemLength) && (m_nChannels * 4u < dwMemLength - trackinfo_ofs))
 		{
-			const_unaligned_ptr_le<uint32> ptrktags = const_unaligned_ptr_le<uint32>(lpStream + trackinfo_ofs);
+			const_unaligned_ptr_be<uint32> ptrktags = const_unaligned_ptr_be<uint32>(lpStream + trackinfo_ofs);
 			for (uint32 i=0; i<m_nChannels; i++)
 			{
 				uint32 trknameofs = 0, trknamelen = 0;
-				uint32 trktagofs = BigEndian(ptrktags[i]);
+				uint32 trktagofs = ptrktags[i];
 				if (trktagofs && (trktagofs <= dwMemLength - 8) )
 				{
 					while (trktagofs < dwMemLength - 8)
 					{
-						uint32 ntag = BigEndian(*const_unaligned_ptr_le<uint32>(lpStream + trktagofs));
+						uint32 ntag = *const_unaligned_ptr_be<uint32>(lpStream + trktagofs);
 						if (ntag == MMDTAG_END) break;
-						uint32 tagdata = BigEndian(*const_unaligned_ptr_le<uint32>(lpStream + trktagofs + 4));
+						uint32 tagdata = *const_unaligned_ptr_be<uint32>(lpStream + trktagofs + 4);
 						switch(ntag)
 						{
 						case MMDTAG_TRK_NAMELEN:	trknamelen = tagdata; break;
@@ -796,7 +760,7 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 					}
 					if ((trknameofs) && (trknameofs < dwMemLength - trknamelen) && trknamelen < dwMemLength)
 					{
-						mpt::String::Read<mpt::String::maybeNullTerminated>(ChnSettings[i].szName, reinterpret_cast<const char *>(lpStream + trknameofs), trknamelen);
+						mpt::String::Read<mpt::String::maybeNullTerminated>(ChnSettings[i].szName, lpStream + trknameofs, trknamelen);
 					}
 				}
 			}
@@ -804,18 +768,18 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 	}
 	// Reading samples
 	if (dwSmplArr > dwMemLength - 4*m_nSamples) return true;
-	pdwTable = const_unaligned_ptr_le<uint32>(lpStream + dwSmplArr);
+	pdwTable = const_unaligned_ptr_be<uint32>(lpStream + dwSmplArr);
 	for (uint32 iSmp=0; iSmp<m_nSamples; iSmp++) if (pdwTable[iSmp])
 	{
-		uint32 dwPos = BigEndian(pdwTable[iSmp]);
+		uint32 dwPos = pdwTable[iSmp];
 		if ((dwPos >= dwMemLength) || (dwPos + sizeof(MMDSAMPLEHEADER) >= dwMemLength)) continue;
 		const MMDSAMPLEHEADER *psdh = (const MMDSAMPLEHEADER *)(lpStream + dwPos);
-		uint32 len = BigEndian(psdh->length);
+		uint32 len = psdh->length;
 	#ifdef MED_LOG
-		Log("SampleData %d: stype=0x%02X len=%d\n", iSmp, BigEndianW(psdh->type), len);
+		Log("SampleData %d: stype=0x%02X len=%d\n", iSmp, psdh->type, len);
 	#endif
 		if(dwPos + len + 6 > dwMemLength) len = 0;
-		uint32 stype = BigEndianW(psdh->type);
+		uint32 stype = psdh->type;
 		const char *psdata = (const char *)(lpStream + dwPos + 6);
 
 		SampleIO sampleIO(
@@ -853,12 +817,13 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 		return true;
 	}
 	if (wNumBlocks > MAX_PATTERNS) wNumBlocks = MAX_PATTERNS;
-	if ((!dwBlockArr) || (dwBlockArr > dwMemLength - 4*wNumBlocks) || (4*wNumBlocks > dwMemLength)) return true;
-	pdwTable = const_unaligned_ptr_le<uint32>(lpStream + dwBlockArr);
+	if ((!dwBlockArr) || (dwBlockArr > dwMemLength - 4u*wNumBlocks) || (4u*wNumBlocks > dwMemLength)) return true;
+	pdwTable = const_unaligned_ptr_be<uint32>(lpStream + dwBlockArr);
 	playtransp += (version == '3') ? 24 : 48;
+	Patterns.ResizeArray(wNumBlocks);
 	for (PATTERNINDEX iBlk=0; iBlk<wNumBlocks; iBlk++)
 	{
-		uint32 dwPos = BigEndian(pdwTable[iBlk]);
+		uint32 dwPos = pdwTable[iBlk];
 		if ((!dwPos) || (dwPos >= dwMemLength) || (dwPos >= dwMemLength - 8)) continue;
 		uint32 lines = 64, tracks = 4;
 		if (version == '0')
@@ -868,7 +833,7 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 			tracks = pmb->numtracks;
 			if (!tracks) tracks = m_nChannels;
 			if(!Patterns.Insert(iBlk, lines)) continue;
-			ModCommand *p = Patterns[iBlk];
+			auto p = Patterns[iBlk].begin();
 			const uint8 * s = (const uint8 *)(lpStream + dwPos + 2);
 			uint32 maxlen = tracks*lines*3;
 			if (maxlen + dwPos > dwMemLength - 2) break;
@@ -885,7 +850,7 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 					p->command = s[1] & 0x0F;
 					p->param = s[2];
 					// if (!iBlk) Log("%02X.%02X.%02X | ", s[0], s[1], s[2]);
-					MedConvert(p, pmsh);
+					MedConvert(*p, pmsh);
 					p++;
 				}
 				//if (!iBlk) Log("\n");
@@ -895,26 +860,26 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 			const MMD1BLOCK *pmb = (const MMD1BLOCK *)(lpStream + dwPos);
 		#ifdef MED_LOG
 			Log("MMD1BLOCK:   lines=%2d, tracks=%2d, offset=0x%04X\n",
-				BigEndianW(pmb->lines), BigEndianW(pmb->numtracks), BigEndian(pmb->info));
+				pmb->lines, pmb->numtracks, pmb->info);
 		#endif
 			const MMD1BLOCKINFO *pbi = NULL;
 			const uint8 *pcmdext = NULL;
-			lines = (pmb->lines >> 8) + 1;
-			tracks = pmb->numtracks >> 8;
+			lines = pmb->lines + 1;
+			tracks = pmb->numtracks;
 			if (!tracks) tracks = m_nChannels;
 			Patterns.Insert(iBlk, lines);
-			uint32 dwBlockInfo = BigEndian(pmb->info);
+			uint32 dwBlockInfo = pmb->info;
 			if ((dwBlockInfo) && (dwBlockInfo < dwMemLength - sizeof(MMD1BLOCKINFO)))
 			{
 				pbi = (const MMD1BLOCKINFO *)(lpStream + dwBlockInfo);
 			#ifdef MED_LOG
 				Log("  BLOCKINFO: blockname=0x%04X namelen=%d pagetable=0x%04X &cmdexttable=0x%04X\n",
-					BigEndian(pbi->blockname), BigEndian(pbi->blocknamelen), BigEndian(pbi->pagetable), BigEndian(pbi->cmdexttable));
+					pbi->blockname, pbi->blocknamelen, pbi->pagetable, pbi->cmdexttable);
 			#endif
 				if ((pbi->blockname) && (pbi->blocknamelen))
 				{
-					uint32 nameofs = BigEndian(pbi->blockname);
-					uint32 namelen = BigEndian(pbi->blocknamelen);
+					uint32 nameofs = pbi->blockname;
+					uint32 namelen = pbi->blocknamelen;
 					if ((nameofs < dwMemLength) && (namelen < dwMemLength - nameofs))
 					{
 						Patterns[iBlk].SetName((const char *)(lpStream + nameofs), namelen);
@@ -922,10 +887,10 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 				}
 				if (pbi->cmdexttable)
 				{
-					uint32 cmdexttable = BigEndian(pbi->cmdexttable);
+					uint32 cmdexttable = pbi->cmdexttable;
 					if (cmdexttable < dwMemLength - 4)
 					{
-						cmdexttable = BigEndian(*const_unaligned_ptr_le<uint32>(lpStream + cmdexttable));
+						cmdexttable = *const_unaligned_ptr_be<uint32>(lpStream + cmdexttable);
 						if ((cmdexttable) && (cmdexttable <= dwMemLength - lines*tracks))
 						{
 							pcmdext = (const uint8 *)(lpStream + cmdexttable);
@@ -933,10 +898,10 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 					}
 				}
 			}
-			ModCommand *p = Patterns[iBlk];
 			const uint8 * s = (const uint8 *)(lpStream + dwPos + 8);
 			uint32 maxlen = tracks*lines*4;
-			if (maxlen + dwPos > dwMemLength - 8 || p == nullptr) break;
+			if (maxlen + dwPos > dwMemLength - 8 || !Patterns.IsValidPat(iBlk)) break;
+			auto p = Patterns[iBlk].begin();
 			for (uint32 y=0; y<lines; y++)
 			{
 				for (uint32 x=0; x<tracks; x++, s+=4) if (x < m_nChannels)
@@ -953,7 +918,7 @@ bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
 					p->command = s[2];
 					p->param = s[3];
 					if (pcmdext) p->vol = pcmdext[x];
-					MedConvert(p, pmsh);
+					MedConvert(*p, pmsh);
 					p++;
 				}
 				if (pcmdext) pcmdext += tracks;
diff --git a/soundlib/Load_mid.cpp b/soundlib/Load_mid.cpp
index 07f9761..7296eab 100644
--- a/soundlib/Load_mid.cpp
+++ b/soundlib/Load_mid.cpp
@@ -2,9 +2,8 @@
  * Load_mid.cpp
  * ------------
  * Purpose: MIDI file loader
- * Notes  : MIDI import is pretty crappy.
- * Authors: Olivier Lapicque
- *          OpenMPT Devs
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  */
 
@@ -12,94 +11,25 @@
 #include "stdafx.h"
 #include "Loaders.h"
 #include "Dlsbank.h"
+#include "MIDIEvents.h"
 #ifdef MODPLUG_TRACKER
 #include "../mptrack/TrackerSettings.h"
+#include "../mptrack/Moddoc.h"
+#include "../mptrack/Mptrack.h"
+#include "../common/mptFileIO.h"
 #endif // MODPLUG_TRACKER
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef MODPLUG_TRACKER
-
-#pragma warning(disable:4244)
-//#define MIDI_LOG
+#if defined(MODPLUG_TRACKER) || defined(MPT_FUZZ_TRACKER)
 
-#ifdef MIDI_LOG
-//#define MIDI_DETAILED_LOG
-#endif
+#ifdef LIBOPENMPT_BUILD
+struct CDLSBank { static int32 DLSMidiVolumeToLinear(uint32) { return 256; } };
+#endif // LIBOPENMPT_BUILD
 
 #define MIDI_DRUMCHANNEL	10
 
-//uint32 gnMidiImportSpeed = 3;
-//uint32 gnMidiPatternLen = 128;
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-typedef struct PACKED MIDIFILEHEADER
-{
-	char  id[4];		// "MThd" = 0x6468544D
-	uint32 len;		// 6
-	uint16 w1;		// 1?
-	uint16 wTrks;		// 2?
-	uint16 wDivision;	// F0
-} MIDIFILEHEADER;
-
-STATIC_ASSERT(sizeof(MIDIFILEHEADER) == 14);
-
-typedef struct PACKED MIDITRACKHEADER
-{
-	uint32 id;	// "MTrk" = 0x6B72544D
-	uint32 len;
-} MIDITRACKHEADER;
-
-STATIC_ASSERT(sizeof(MIDITRACKHEADER) == 8);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
-//////////////////////////////////////////////////////////////////////
-// Midi Loader Internal Structures
-
-#define CHNSTATE_NOTEOFFPENDING		0x0001
-
-// MOD Channel State description (current volume, panning, etc...)
-typedef struct MODCHANNELSTATE
-{
-	uint32 flags;	// Channel Flags
-	uint16 idlecount;
-	uint16 pitchsrc, pitchdest;	// Pitch Bend (current position/new position)
-	uint8 parent;	// Midi Channel parent
-	uint8 pan;		// Channel Panning			0-255
-	uint8 note;		// Note On # (0=available)
-} MODCHANNELSTATE;
-
-// MIDI Channel State (Midi Channels 0-15)
-typedef struct MIDICHANNELSTATE
-{
-	uint32 flags;		// Channel Flags
-	uint16 pitchbend;		// Pitch Bend Amount (14-bits unsigned)
-	uint8 note_on[128];	// If note=on -> MOD channel # + 1 (0 if note=off)
-	uint8 program;		// Channel Midi Program
-	uint16 bank;			// 0-16383
-	// -- Controllers --------- function ---------- CC# --- range  --- init (midi) ---
-	uint8 pan;			// Channel Panning			CC10	[0-255]		128 (64)
-	uint8 expression;	// Channel Expression		CC11	0-128		128	(127)
-	uint8 volume;		// Channel Volume			CC7		0-128		80	(100)
-	uint8 modulation;	// Modulation				CC1		0-127		0
-	uint8 pitchbendrange;// Pitch Bend Range								64
-} MIDICHANNELSTATE;
-
-typedef struct MIDITRACK
-{
-	const uint8 *ptracks, *ptrmax;
-	uint32 status;
-	LONG nexteventtime;
-} MIDITRACK;
-
-
-extern const char *szMidiGroupNames[17] =
+const char *szMidiGroupNames[17] =
 {
 	"Piano",
 	"Chromatic Percussion",
@@ -121,7 +51,7 @@ extern const char *szMidiGroupNames[17] =
 };
 
 
-extern const char *szMidiProgramNames[128] =
+const char *szMidiProgramNames[128] =
 {
 	// 1-8: Piano
 	"Acoustic Grand Piano",
@@ -271,7 +201,7 @@ extern const char *szMidiProgramNames[128] =
 
 
 // Notes 25-85
-extern const char *szMidiPercussionNames[61] =
+const char *szMidiPercussionNames[61] =
 {
 	"Seq Click",
 	"Brush Tap",
@@ -291,7 +221,7 @@ extern const char *szMidiPercussionNames[61] =
 	"Hand Clap",
 	"Electric Snare",
 	"Low Floor Tom",
-	"Closed Hi Hat",
+	"Closed Hi-Hat",
 	"High Floor Tom",
 	"Pedal Hi-Hat",
 	"Low Tom",
@@ -337,86 +267,29 @@ extern const char *szMidiPercussionNames[61] =
 };
 
 
-///////////////////////////////////////////////////////////////////////////
-// Helper functions
-
-// Convert a variable-length MIDI integer held in the byte buffer <value> to a normal integer <result>.
-// maxLength bytes are read from the byte buffer at max.
-// Function returns how many bytes have been read.
-template <class TOut>
-static size_t ConvertMIDI2Int(TOut &result, uint8 *value, size_t maxLength)
-//-------------------------------------------------------------------------
-{
-	static_assert(std::numeric_limits<TOut>::is_integer == true, "Output type is a not an integer");
-
-	if(maxLength <= 0)
-	{
-		result = 0;
-		return 0;
-	}
-	size_t bytesUsed = 0;
-	result = 0;
-	uint8 b;
-	do
-	{
-		b = *value;
-		result <<= 7;
-		result |= (b & 0x7F);
-		value++;
-	} while (++bytesUsed < maxLength && (b & 0x80) != 0);
-	return bytesUsed;
-}
-
-// Returns MOD tempo and tick multiplier
-static int ConvertMidiTempo(int tempo_us, int &tickMultiplier, int importSpeed)
-//-----------------------------------------------------------------------------
-{
-	int nBestModTempo = 120;
-	int nBestError = 1000000; // 1s
-	int nBestMultiplier = 1;
-	int nSpeed = importSpeed;
-	for (int nModTempo=110; nModTempo<=240; nModTempo++)
-	{
-		int tick_us = (2500000) / nModTempo;
-		int nFactor = (tick_us+tempo_us/2) / tempo_us;
-		if (!nFactor) nFactor = 1;
-		int nError = tick_us - tempo_us * nFactor;
-		if (nError < 0) nError = -nError;
-		if (nError < nBestError)
-		{
-			nBestError = nError;
-			nBestModTempo = nModTempo;
-			nBestMultiplier = nFactor;
-		}
-		if ((!nError) || ((nError<=1) && (nFactor==64))) break;
-	}
-	tickMultiplier = nBestMultiplier * nSpeed;
-	return nBestModTempo;
-}
-
-
 ////////////////////////////////////////////////////////////////////////////////
 // Maps a midi instrument - returns the instrument number in the file
-uint32 CSoundFile::MapMidiInstrument(uint32 dwBankProgram, uint32 nChannel, uint32 nNote)
-//---------------------------------------------------------------------------------------
+uint32 CSoundFile::MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<16> drumChns)
 {
 	ModInstrument *pIns;
-	uint32 nProgram = dwBankProgram & 0x7F;
-	uint32 nBank = dwBankProgram >> 7;
+	program &= 0x7F;
+	bank &= 0x3FFF;
+	note &= 0x7F;
 
-	nNote &= 0x7F;
-	if (nNote >= NOTE_MAX) return 0;
-	for (uint32 i=1; i<=m_nInstruments; i++) if (Instruments[i])
+	// In XG mode, extra drums are on banks with MSB 7F
+	const bool isDrum = drumChns[midiChannel - 1] || (bank >= 0x3F80 && isXG);
+
+	for (uint32 i = 1; i <= m_nInstruments; i++) if (Instruments[i])
 	{
 		ModInstrument *p = Instruments[i];
-		// Drum Kit ?
-		if (nChannel == MIDI_DRUMCHANNEL)
+		// Drum Kit?
+		if (isDrum)
 		{
-			if (nNote == p->nMidiDrumKey) return i;
+			if (note == p->nMidiDrumKey && bank + 1 == p->wMidiBank) return i;
 		} else
 		// Melodic Instrument
 		{
-			if (nProgram + 1 == p->nMidiProgram && p->nMidiDrumKey == 0) return i;
+			if (program + 1 == p->nMidiProgram && bank + 1 == p->wMidiBank && p->nMidiDrumKey == 0) return i;
 		}
 	}
 	if ((m_nInstruments + 1 >= MAX_INSTRUMENTS) || (m_nSamples + 1 >= MAX_SAMPLES)) return 0;
@@ -428,73 +301,294 @@ uint32 CSoundFile::MapMidiInstrument(uint32 dwBankProgram, uint32 nChannel, uint
 	}
 
 	m_nSamples++;
-	m_nInstruments++;
-	pIns->wMidiBank = nBank;
-	pIns->nMidiProgram = nProgram + 1;
-	pIns->nMidiChannel = nChannel;
-	if (nChannel == MIDI_DRUMCHANNEL) pIns->nMidiDrumKey = nNote;
+	pIns->wMidiBank = bank + 1;
+	pIns->nMidiProgram = program + 1;
 	pIns->nFadeOut = 1024;
 	pIns->nNNA = NNA_NOTEOFF;
-	pIns->nDCT = (nChannel == MIDI_DRUMCHANNEL) ? DCT_SAMPLE : DCT_NOTE;
+	pIns->nDCT = isDrum ? DCT_SAMPLE : DCT_NOTE;
 	pIns->nDNA = DNA_NOTEFADE;
-	for (uint32 j=0; j<NOTE_MAX; j++)
+	if(isDrum)
 	{
-		int mapnote = j+1;
-		if (nChannel == MIDI_DRUMCHANNEL)
+		pIns->nMidiChannel = MIDI_DRUMCHANNEL;
+		pIns->nMidiDrumKey = note;
+		for(auto &key : pIns->NoteMap)
 		{
-			mapnote = NOTE_MIDDLEC;
-			/*mapnote = 61 + j - nNote;
-			if (mapnote < 1) mapnote = 1;
-			if (mapnote > 120) mapnote = 120;*/
+			key = NOTE_MIDDLEC;
 		}
-		pIns->Keyboard[j] = m_nSamples;
-		pIns->NoteMap[j] = (uint8)mapnote;
 	}
 	pIns->VolEnv.dwFlags.set(ENV_ENABLED);
-	if (nChannel != MIDI_DRUMCHANNEL) pIns->VolEnv.dwFlags.set(ENV_SUSTAIN);
+	if (!isDrum) pIns->VolEnv.dwFlags.set(ENV_SUSTAIN);
 	pIns->VolEnv.reserve(4);
 	pIns->VolEnv.push_back(EnvelopeNode(0, ENVELOPE_MAX));
 	pIns->VolEnv.push_back(EnvelopeNode(10, ENVELOPE_MAX));
 	pIns->VolEnv.push_back(EnvelopeNode(15, (ENVELOPE_MAX + ENVELOPE_MID) / 2));
 	pIns->VolEnv.push_back(EnvelopeNode(20, ENVELOPE_MIN));
 	pIns->VolEnv.nSustainStart = pIns->VolEnv.nSustainEnd = 1;
-	// Sample
-	Samples[m_nSamples].nPan = 128;
-	Samples[m_nSamples].nVolume = 256;
-	Samples[m_nSamples].nGlobalVol = 64;
-	if (nChannel != MIDI_DRUMCHANNEL)
+	// Set GM program / drum name
+	if (!isDrum)
 	{
-		// GM Midi Name
-		strcpy(pIns->name, szMidiProgramNames[nProgram]);
-		strcpy(m_szNames[m_nSamples], szMidiProgramNames[nProgram]);
+		strcpy(pIns->name, szMidiProgramNames[program]);
 	} else
 	{
-		strcpy(pIns->name, "Percussions");
-		if ((nNote >= 24) && (nNote <= 84))
-			strcpy(m_szNames[m_nSamples], szMidiPercussionNames[nNote-24]);
+		if (note >= 24 && note <= 84)
+			strcpy(pIns->name, szMidiPercussionNames[note - 24]);
 		else
-			strcpy(m_szNames[m_nSamples], "Percussions");
+			strcpy(pIns->name, "Percussions");
 	}
 	return m_nInstruments;
 }
 
 
-/////////////////////////////////////////////////////////////////
-// Loader Status
-#define MIDIGLOBAL_SONGENDED		0x0001
-#define MIDIGLOBAL_FROZEN			0x0002
-#define MIDIGLOBAL_UPDATETEMPO		0x0004
-#define MIDIGLOBAL_UPDATEMASTERVOL	0x0008
-// Midi Globals
-#define MIDIGLOBAL_GMSYSTEMON		0x0100
-#define MIDIGLOBAL_XGSYSTEMON		0x0200
+struct MThd
+{
+	uint32be headerLength;
+	uint16be format;		// 0 = single-track, 1 = multi-track, 2 = multi-song
+	uint16be numTracks;		// Number of track chunks
+	uint16be division;		// Delta timing value: positive = units/beat; negative = smpte compatible units
+};
+
+MPT_BINARY_STRUCT(MThd, 10);
+
+
+typedef uint32 tick_t;
+
+struct TrackState
+{
+	FileReader track;
+	tick_t nextEvent;
+	uint8 command;
+	bool finished;
+
+	TrackState()
+		: nextEvent(0)
+		, command(0)
+		, finished(false)
+	{ }
+};
+
+struct ModChannelState
+{
+	static const uint8 NOMIDI = 0xFF;	// No MIDI channel assigned.
+
+	tick_t age;				// At which MIDI tick the channel was triggered
+	int32 porta;			// Current portamento position in extra-fine slide units (1/64th of a semitone)
+	uint8 vol;				// MIDI note volume (0...127)
+	uint8 pan;				// MIDI channel panning (0...256)
+	uint8 midiCh;			// MIDI channel that was last played on this channel
+	ModCommand::NOTE note;	// MIDI note that was last played on this channel
+	bool sustained : 1;		// If true, the note was already released by a note-off event, but sustain pedal CC is still active
+
+	ModChannelState()
+		: age(0)
+		, porta(0)
+		, vol(100)
+		, pan(128)
+		, midiCh(NOMIDI)
+		, note(NOTE_NONE)
+		, sustained(false)
+	{ }
+};
+
+struct MidiChannelState
+{
+	int32  pitchbendMod;	// Pre-computed pitchbend in extra-fine slide units (1/64th of a semitone)
+	int16  pitchbend;		// 0...16383
+	uint16 bank;			// 0...16383
+	uint8  program;			// 0...127
+	// -- Controllers ------------- function ---------- CC# --- range  ---- init (midi) ---
+	uint8 pan;             // Channel Panning           10      [0-255]     128  (64)
+	uint8 expression;      // Channel Expression        11      0-128       128  (127)
+	uint8 volume;          // Channel Volume            7       0-128       80   (100)
+	uint16 rpn;            // Currently selected RPN    100/101  n/a
+	uint8 pitchBendRange;  // Pitch Bend Range                              2
+	int8  transpose;       // Channel transpose                             0
+	bool  monoMode : 1;    // Mono/Poly operation       126/127  n/a        Poly
+	bool  sustain : 1;     // Sustain pedal             64       on/off     off
+
+	CHANNELINDEX noteOn[128];	// Value != CHANNELINDEX_INVALID: Note is active and mapped to mod channel in value
+
+	MidiChannelState()
+		: pitchbendMod(0)
+		, pitchbend(MIDIEvents::pitchBendCentre)
+		, bank(0)
+		, program(0)
+		, pan(128)
+		, expression(128)
+		, volume(80)
+		, rpn(0x3FFF)
+		, pitchBendRange(2)
+		, transpose(0)
+		, monoMode(false)
+		, sustain(false)
+	{
+		for(auto &note : noteOn)
+		{
+			note = CHANNELINDEX_INVALID;
+		}
+	}
+
+	void SetPitchbend(uint16 value)
+	{
+		pitchbend = value;
+		// Convert from arbitrary MIDI pitchbend to 64th of semitone
+		pitchbendMod = Util::muldiv(pitchbend - MIDIEvents::pitchBendCentre, pitchBendRange * 64, MIDIEvents::pitchBendCentre);
+	}
+
+	void ResetAllControllers()
+	{
+		expression = 128;
+		pitchBendRange = 2;
+		SetPitchbend(MIDIEvents::pitchBendCentre);
+		transpose = 0;
+		rpn = 0x3FFF;
+		monoMode = false;
+		sustain = false;
+		// Should also reset modulation, pedals (40h-43h), aftertouch
+	}
+
+	void SetRPN(uint8 value)
+	{
+		switch(rpn)
+		{
+		case 0:	// Pitch Bend Range
+			pitchBendRange = std::max(value, uint8(1));
+			SetPitchbend(pitchbend);
+			break;
+		case 2:	// Coarse Tune
+			transpose = static_cast<int8>(value) - 64;
+			break;
+		}
+	}
+
+	uint8 GetRPN() const
+	{
+		switch(rpn)
+		{
+		case 0:	// Pitch Bend Range
+			return pitchBendRange;
+		case 2:	// Coarse Tune
+			return transpose;
+		}
+		return 0;
+	}
+};
+
+
+static CHANNELINDEX FindUnusedChannel(uint8 midiCh, ModCommand::NOTE note, const std::vector<ModChannelState> &channels, bool monoMode, PatternRow patRow)
+{
+	for(size_t i = 0; i < channels.size(); i++)
+	{
+		// Check if this note is already playing, or find any note of the same MIDI channel in case of mono mode
+		if(channels[i].midiCh == midiCh && (channels[i].note == note || (monoMode && channels[i].note != NOTE_NONE)))
+		{
+			return static_cast<CHANNELINDEX>(i);
+		}
+	}
+	
+	CHANNELINDEX anyUnusedChannel = CHANNELINDEX_INVALID;
+	CHANNELINDEX anyFreeChannel = CHANNELINDEX_INVALID;
+
+	CHANNELINDEX oldsetMidiCh = CHANNELINDEX_INVALID;
+	tick_t oldestMidiChAge = Util::MaxValueOfType(oldestMidiChAge);
+
+	CHANNELINDEX oldestAnyCh = 0;
+	tick_t oldestAnyChAge = Util::MaxValueOfType(oldestAnyChAge);
+
+	for(size_t i = 0; i < channels.size(); i++)
+	{
+		if(channels[i].note == NOTE_NONE && !patRow[i].IsNote())
+		{
+			// Recycle channel previously used by the same MIDI channel
+			if(channels[i].midiCh == midiCh)
+				return static_cast<CHANNELINDEX>(i);
+			// If we cannot find a channel that was already used for the same MIDI channel, try a completely unused channel next
+			else if(channels[i].midiCh == ModChannelState::NOMIDI && anyUnusedChannel == CHANNELINDEX_INVALID)
+				anyUnusedChannel = static_cast<CHANNELINDEX>(i);
+			// And if that fails, try any channel that currently doesn't play a note.
+			if(anyFreeChannel == CHANNELINDEX_INVALID)
+				anyFreeChannel = static_cast<CHANNELINDEX>(i);
+		}
+
+		// If we can't find any free channels, look for the oldest channels
+		if(channels[i].midiCh == midiCh && channels[i].age < oldestMidiChAge)
+		{
+			// Oldest channel matching this MIDI channel
+			oldestMidiChAge = channels[i].age;
+			oldsetMidiCh = static_cast<CHANNELINDEX>(i);
+		} else if(channels[i].age < oldestAnyChAge)
+		{
+			// Any oldest channel
+			oldestAnyChAge = channels[i].age;
+			oldestAnyCh = static_cast<CHANNELINDEX>(i);
+		}
+	}
+	if(anyUnusedChannel != CHANNELINDEX_INVALID)
+		return anyUnusedChannel;
+	if(anyFreeChannel != CHANNELINDEX_INVALID)
+		return anyFreeChannel;
+	if(oldsetMidiCh != CHANNELINDEX_INVALID)
+		return oldsetMidiCh;
+	return oldestAnyCh;
+}
+
+
+static void MIDINoteOff(MidiChannelState &midiChn, std::vector<ModChannelState> &modChnStatus, uint8 note, uint8 delay, PatternRow patRow)
+{
+	CHANNELINDEX chn = midiChn.noteOn[note];
+	if(chn == CHANNELINDEX_INVALID)
+		return;
+
+	if(midiChn.sustain)
+	{
+		// Turn this off later
+		modChnStatus[chn].sustained = true;
+		return;
+	}
+
+	uint8 midiCh = modChnStatus[chn].midiCh;
+	modChnStatus[chn].note = NOTE_NONE;
+	midiChn.noteOn[note] = CHANNELINDEX_INVALID;
+	ModCommand &m = patRow[chn];
+	if(m.note == NOTE_NONE)
+	{
+		m.note = NOTE_KEYOFF;
+		if(delay != 0)
+		{
+			m.command = CMD_S3MCMDEX;
+			m.param = 0xD0 | delay;
+		}
+	} else if(m.IsNote() && midiCh != (MIDI_DRUMCHANNEL - 1))
+	{
+		// Only do note cuts for melodic instruments - they sound weird on drums which should fade out naturally.
+		if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xD0)
+		{
+			// Already have a note delay
+			m.command = CMD_DELAYCUT;
+			m.param = (m.param << 4) | (delay - (m.param & 0x0F));
+		} else if(m.command == CMD_NONE || m.command == CMD_PANNING8)
+		{
+			m.command = CMD_S3MCMDEX;
+			m.param = 0xC0 | delay;
+		}
+	}
+}
+
+
+static void EnterMIDIVolume(ModCommand &m, ModChannelState &modChn, const MidiChannelState &midiChn)
+{
+	m.volcmd = VOLCMD_VOLUME;
+
+	int32 vol = CDLSBank::DLSMidiVolumeToLinear(modChn.vol) >> 8;
+	vol = (vol * midiChn.volume * midiChn.expression) >> 13;
+	Limit(vol, 4, 256);
+	m.vol = static_cast<ModCommand::VOL>(vol / 4);
+}
 
 
 bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
-	
+
 	// Microsoft MIDI files
 	if(file.ReadMagic("RIFF"))
 	{
@@ -508,23 +602,25 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags)
 		}
 		do
 		{
-			uint32 id = file.ReadUint32LE();
+			char id[4];
+			file.ReadArray(id);
 			uint32 length = file.ReadUint32LE();
-			if(memcmp(&id, "data", 4))
+			if(memcmp(id, "data", 4))
 			{
 				file.Skip(length);
 			} else
 			{
-				file = file.ReadChunk(length);
 				break;
 			}
-		} while(file.BytesLeft());
+		} while(file.CanRead(8));
 	}
 
-	MIDIFILEHEADER pmfh;
-	if(!file.ReadStruct(pmfh)
-		|| memcmp(pmfh.id, "MThd", 4)
-		|| !file.Seek(8 + BigEndian(pmfh.len)))
+	MThd fileHeader;
+	if(!file.ReadMagic("MThd")
+		|| !file.ReadStruct(fileHeader)
+		|| fileHeader.numTracks == 0
+		|| fileHeader.headerLength < 6
+		|| !file.Skip(fileHeader.headerLength - 6))
 	{
 		return false;
 	} else if(loadFlags == onlyVerifyHeader)
@@ -532,707 +628,767 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags)
 		return true;
 	}
 
-	const FileReader::off_t dwMemLength = file.BytesLeft();
-	const uint8 *lpStream = file.GetRawData<uint8>();
-
-	const MIDITRACKHEADER *pmth;
-	MODCHANNELSTATE chnstate[MAX_BASECHANNELS];
-	MIDICHANNELSTATE midichstate[16];
-	std::vector<MIDITRACK> miditracks;
-	FileReader::off_t dwMemPos = 0;
-	uint32 dwGlobalFlags, tracks, tempo;
-	uint32 row, pat, midimastervol;
-	short int division;
-	int midi_clock, nTempoUsec, nPPQN, nTickMultiplier;
+	InitializeGlobals(MOD_TYPE_MID);
+	InitializeChannels();
 
 #ifdef MODPLUG_TRACKER
-	int importSpeed = TrackerSettings::Instance().midiImportSpeed;
-	ROWINDEX importPatternLen = TrackerSettings::Instance().midiImportPatternLen;
+	const uint32 quantize = Clamp(TrackerSettings::Instance().midiImportQuantize.Get(), 4u, 256u);
+	const ROWINDEX patternLen = Clamp(TrackerSettings::Instance().midiImportPatternLen.Get(), ROWINDEX(1), MAX_PATTERN_ROWS);
+	const uint8 ticksPerRow = Clamp(TrackerSettings::Instance().midiImportTicks.Get(), uint8(2), uint8(16));
 #else
-	int importSpeed = 3;
-	ROWINDEX importPatternLen = 128;
-#endif // MODPLUG_TRACKER
-
-	// Fix import parameters
-	Limit(importSpeed, 2, 6);
-	Limit(importPatternLen, ROWINDEX(1), MAX_PATTERN_ROWS);
-
-	pmth = (MIDITRACKHEADER *)(lpStream+dwMemPos);
-	tracks = BigEndianW(pmfh.wTrks);
-	if ((pmth->id != 0x6B72544D) || (!tracks)) return false;
-	else if(loadFlags == onlyVerifyHeader) return true;
-	miditracks.resize(tracks);
+	const uint32 quantize = 32;		// Must be 4 or higher
+	const ROWINDEX patternLen = 128;
+	const uint8 ticksPerRow = 16;	// Must be in range 2...16
+#endif
+#ifdef MPT_FUZZ_TRACKER
+	// Avoid generating test cases that take overly long to evaluate
+	const ORDERINDEX MPT_MIDI_IMPORT_MAX_ORDERS = 64;
+#else
+	const ORDERINDEX MPT_MIDI_IMPORT_MAX_ORDERS = MAX_ORDERS;
+#endif
 
-	// Reading File...
-	InitializeGlobals(MOD_TYPE_MID);
-	m_nChannels = 32;
+	m_songArtist = MPT_USTRING("MIDI Conversion");
+	m_madeWithTracker = MPT_USTRING("Standard MIDI File");
+	SetMixLevels(mixLevels1_17RC3);
+	m_nTempoMode = tempoModeModern;
 	m_SongFlags = SONG_LINEARSLIDES;
-
-	// MIDI->MOD Tempo Conversion
-	division = BigEndianW(pmfh.wDivision);
-	if (division < 0)
+	m_nDefaultTempo.Set(120);
+	m_nDefaultSpeed = ticksPerRow;
+	m_nChannels = MAX_BASECHANNELS;
+	m_nDefaultRowsPerBeat = quantize / 4;
+	m_nDefaultRowsPerMeasure = 4 * m_nDefaultRowsPerBeat;
+	m_nSamplePreAmp = m_nVSTiVolume = 32;
+	TEMPO tempo = m_nDefaultTempo;
+	uint16 ppqn = fileHeader.division;
+	if(ppqn & 0x8000)
 	{
-		int nFrames = -(division>>8);
-		int nSubFrames = (division & 0xff);
-		nPPQN = nFrames * nSubFrames / 2;
-		if (!nPPQN) nPPQN = 1;
-	} else
-	{
-		nPPQN = (division) ? division : 96;
+		// SMPTE compatible units (approximation)
+		int frames = 256 - (ppqn >> 8), subFrames = (ppqn & 0xFF);
+		ppqn = static_cast<uint16>(frames * subFrames / 2);
 	}
-	nTempoUsec = 500000 / nPPQN;
-	tempo = ConvertMidiTempo(nTempoUsec, nTickMultiplier, importSpeed);
-	m_nDefaultTempo.Set(tempo);
-	m_nDefaultSpeed = importSpeed;
-	m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
-	midimastervol = m_nDefaultGlobalVolume;
-	
-#ifdef MIDI_LOG
-	Log("%d tracks, tempo = %dus, division = %04X TickFactor=%d\n", tracks, nTempoUsec, ((uint32)division) & 0xFFFF, nTickMultiplier);
-#endif
-	// Initializing 
-	Order.resize(MAX_ORDERS, Order.GetInvalidPatIndex());
-	MemsetZero(chnstate);
-	MemsetZero(midichstate);
-	// Initializing Patterns
-	Order[0] = 0;
-	// Initializing Channels
-	for (uint32 ics=0; ics<MAX_BASECHANNELS; ics++)
+	if(!ppqn)
+		ppqn = 96;
+	Order().clear();
+
+	MidiChannelState midiChnStatus[16];
+	const CHANNELINDEX tempoChannel = m_nChannels - 2, globalVolChannel = m_nChannels - 1;
+	const uint16 numTracks = fileHeader.numTracks;
+	std::vector<TrackState> tracks(numTracks);
+	std::vector<ModChannelState> modChnStatus(m_nChannels);
+	std::bitset<16> drumChns;
+	drumChns.set(MIDI_DRUMCHANNEL - 1);
+
+	for(uint16 t = 0; t < numTracks; t++)
 	{
-		// Channel settings
-		ChnSettings[ics].Reset();
-		// Channels state
-		chnstate[ics].pan = 128;
-		chnstate[ics].pitchsrc = 0x2000;
-		chnstate[ics].pitchdest = 0x2000;
+		if(!file.ReadMagic("MTrk"))
+			return false;
+		tracks[t].track = file.ReadChunk(file.ReadUint32BE());
+		tick_t delta = 0;
+		tracks[t].track.ReadVarInt(delta);
+		tracks[t].nextEvent = delta;
 	}
-	// Initializing Track Pointers
-	for (uint32 itrk=0; itrk<tracks; itrk++)
+
+	uint16 finishedTracks = 0;
+	PATTERNINDEX emptyPattern = PATTERNINDEX_INVALID;
+	ORDERINDEX lastOrd = 0;
+	ROWINDEX lastRow = 0;
+	ROWINDEX restartRow = ROWINDEX_INVALID;
+	int8 masterTranspose = 0;
+	bool isXG = false;
+	bool isEMIDI = false;
+	bool isType2 = (fileHeader.format == 2);
+
+	while(finishedTracks < numTracks)
 	{
-		miditracks[itrk].nexteventtime = -1;
-		miditracks[itrk].status = 0x2F;
-		pmth = (MIDITRACKHEADER *)(lpStream+dwMemPos);
-		if (dwMemPos + 8 >= dwMemLength) break;
-		uint32 len = BigEndian(pmth->len);
-		if ((pmth->id == 0x6B72544D) && (len <= dwMemLength - (dwMemPos + 8)))
+		uint16 t = 0;
+		tick_t tick = Util::MaxValueOfType(tick);
+		for(uint16 track = 0; track < numTracks; track++)
 		{
-#ifdef MIDI_DETAILED_LOG
-			Log(" track%d at offset %d len=%d ", itrk, dwMemPos+8, len);
-#endif
-			// Initializing midi tracks
-			miditracks[itrk].ptracks = lpStream+dwMemPos+8;
-			miditracks[itrk].ptrmax = miditracks[itrk].ptracks + len;
-			miditracks[itrk].ptracks += ConvertMIDI2Int(miditracks[itrk].nexteventtime, (uint8 *)miditracks[itrk].ptracks, len);
-#ifdef MIDI_DETAILED_LOG
-			Log(" init time=%d\n", miditracks[itrk].nexteventtime);
-#endif
+			if(!tracks[track].finished && tracks[track].nextEvent < tick)
+			{
+				tick = tracks[track].nextEvent;
+				t = track;
+				if(isType2)
+					break;
+			}
 		}
-		dwMemPos += 8 + len;
-	}
-#ifdef MIDI_LOG
-	Log("\n");
-#endif
-	// Initializing midi channels state
-	for (uint32 imidi=0; imidi<16; imidi++)
-	{
-		midichstate[imidi].pan = 128;			// middle
-		midichstate[imidi].expression = 128;	// no attenuation
-		midichstate[imidi].volume = 80;			// GM specs defaults to 100
-		midichstate[imidi].pitchbend = 0x2000;	// Pitch Bend Amount
-		midichstate[imidi].pitchbendrange = 64;	// Pitch Bend Range: +/- 2 semitones
-	}
-	////////////////////////////////////////////////////////////////////////////
-	// Main Midi Sequencer Loop
-	pat = 0;
-	row = 0;
-	midi_clock = 0;
-	dwGlobalFlags = MIDIGLOBAL_UPDATETEMPO | MIDIGLOBAL_FROZEN;
-	do
-	{
-		// Allocate current pattern if not allocated yet
-		if (!Patterns[pat] && !Patterns.Insert(pat, importPatternLen))
+		FileReader &track = tracks[t].track;
+
+		tick_t modTicks = Util::muldivr_unsigned(tick, quantize * ticksPerRow, ppqn * 4u);
+
+		ORDERINDEX ord = static_cast<ORDERINDEX>((modTicks / ticksPerRow) / patternLen);
+		ROWINDEX row = (modTicks / ticksPerRow) % patternLen;
+		uint8 delay = static_cast<uint8>(modTicks % ticksPerRow);
+
+		if(ord >= Order().GetLength())
 		{
-			break;
+			if(ord > MPT_MIDI_IMPORT_MAX_ORDERS)
+				break;
+			ORDERINDEX curSize = Order().GetLength();
+			// If we need to extend the order list by more than one pattern, this means that we
+			// will be filling in empty patterns. Just recycle one empty pattern for this job.
+			// We read events in chronological order, so it is never possible for the loader to
+			// "jump back" to one of those empty patterns and write into it.
+			if(ord > curSize && emptyPattern == PATTERNINDEX_INVALID)
+			{
+				if((emptyPattern = Patterns.InsertAny(patternLen)) == PATTERNINDEX_INVALID)
+					break;
+			}
+			Order().resize(ord + 1, emptyPattern);
+
+			if((Order()[ord] = Patterns.InsertAny(patternLen)) == PATTERNINDEX_INVALID)
+				break;
 		}
-		dwGlobalFlags |= MIDIGLOBAL_SONGENDED;
-		ModCommand *m = Patterns[pat] + row * m_nChannels;
-		// Parse Tracks
-		for (uint32 trk=0; trk<tracks; trk++) if (miditracks[trk].ptracks)
+
+		// Keep track of position of last event for resizing the last pattern
+		if(ord > lastOrd)
+		{
+			lastOrd = ord;
+			lastRow = row;
+		} else if(ord == lastOrd)
+		{
+			lastRow = std::max(lastRow, row);
+		}
+
+		PATTERNINDEX pat = Order()[ord];
+		PatternRow patRow = Patterns[pat].GetRow(row);
+
+		uint8 data1 = track.ReadUint8();
+		if(data1 == 0xFF)
 		{
-			MIDITRACK *ptrk = &miditracks[trk];
-			dwGlobalFlags &= ~MIDIGLOBAL_SONGENDED;
-			while ((ptrk->ptracks) && (ptrk->nexteventtime >= 0) && (midi_clock+(nTickMultiplier>>2) >= ptrk->nexteventtime))
+			// Meta events
+			data1 = track.ReadUint8();
+			size_t len = 0;
+			track.ReadVarInt(len);
+			FileReader chunk = track.ReadChunk(len);
+
+			switch(data1)
 			{
-				if (ptrk->ptracks[0] & 0x80) ptrk->status = *(ptrk->ptracks++);
-			#ifdef MIDI_DETAILED_LOG
-				Log("status: %02X\n", ptrk->status);
-			#endif
-				switch(ptrk->status)
+			case 1:	// Text
+			case 2:	// Copyright
+				m_songMessage.Read(chunk, len, SongMessage::leAutodetect);
+				break;
+			case 3:	// Track Name
+				if(len > 0)
 				{
-				/////////////////////////////////////////////////////////////////////
-				// End Of Track
-				case 0x2F:
-				// End Of Song
-				case 0xFC:
-#ifdef MIDI_LOG
-					Log("track %d: EOT code 0x%02X\n", trk, ptrk->status);
-#endif
-					ptrk->ptracks = NULL;
-					break;
-
-				/////////////////////////////////////////////////////////////////////
-				// SYSEX messages
-				case 0xF0:
-				case 0xF7:
+					std::string s;
+					chunk.ReadString<mpt::String::maybeNullTerminated>(s, len);
+					if(!m_songMessage.empty())
+						m_songMessage.append(1, SongMessage::InternalLineEnding);
+					m_songMessage += s;
+					if(m_songName.empty())
+						m_songName = s;
+				}
+				break;
+			case 4:	// Instrument
+			case 5:	// Lyric
+				break;
+			case 6:	// Marker
+			case 7:	// Cue point
+				{
+					std::string s;
+					chunk.ReadString<mpt::String::maybeNullTerminated>(s, len);
+					Patterns[pat].SetName(s);
+					if(!mpt::CompareNoCaseAscii(s, "loopStart"))
 					{
-						LONG len;
-						ptrk->ptracks += ConvertMIDI2Int(len, (uint8 *)ptrk->ptracks, (size_t)(ptrk->ptrmax - ptrk->ptracks));
-						if ((len > 1) && (ptrk->ptracks + len <ptrk->ptrmax) && (ptrk->ptracks[len-1] == 0xF7))
-						{
-							uint32 dwSysEx1 = 0, dwSysEx2 = 0;
-							if (len >= 4) dwSysEx1 = (*((uint32 *)(ptrk->ptracks))) & 0x7F7F7F7F;
-							if (len >= 8) dwSysEx2 = (*((uint32 *)(ptrk->ptracks+4))) & 0x7F7F7F7F;
-							// GM System On
-							if ((len == 5) && (dwSysEx1 == 0x01097F7E))
-							{
-								dwGlobalFlags |= MIDIGLOBAL_GMSYSTEMON;
-							} else
-							// XG System On
-							if ((len == 8) && ((dwSysEx1 & 0xFFFFF0FF) == 0x004c1043) && (dwSysEx2 == 0x77007e00))
-							{
-								dwGlobalFlags |= MIDIGLOBAL_XGSYSTEMON;
-							} else
-							// Midi Master Volume
-							if ((len == 7) && (dwSysEx1 == 0x01047F7F))
-							{
-								midimastervol = CDLSBank::DLSMidiVolumeToLinear(ptrk->ptracks[5] & 0x7F) >> 8;
-								if (midimastervol < 16) midimastervol = 16;
-								dwGlobalFlags |= MIDIGLOBAL_UPDATEMASTERVOL;
-							}
-#ifdef MIDI_LOG
-							else
-							{
-								Log("track %d: SYSEX len=%d: F0", trk, len);
-								for (uint32 k=0; k<(uint32)len; k++)
-								{
-									Log(".%02X", ptrk->ptracks[k]);
-									if (k >= 40)
-									{
-										Log("..");
-										break;
-									}
-								}
-								Log("\n");
-							}
-#endif
-						}
-#ifdef MIDI_LOG
-						else Log("Invalid SYSEX received!\n");
-#endif
-						ptrk->ptracks += len;
+						Order().SetRestartPos(ord);
+						restartRow = row;
 					}
-					break;
-				
-				//////////////////////////////////////////////////////////////////////
-				// META-events: FF.code.len.data[len]
-				case 0xFF:
+				}
+				break;
+			case 8:	// Patch name
+			case 9:	// Port name
+				break;
+			case 0x2F:	// End Of Track
+				tracks[t].finished = true;
+				break;
+			case 0x51: // Tempo
+				{
+					uint8 tempoRaw[3];
+					chunk.ReadArray(tempoRaw);
+					uint32 tempoInt = (tempoRaw[0] << 16) | (tempoRaw[1] << 8) | tempoRaw[2];
+					if(tempoInt == 0)
+						break;
+					TEMPO newTempo(60000000.0 / tempoInt);
+					if(!tick)
 					{
-						uint32 i = *(ptrk->ptracks++);
-						LONG len;
-						ptrk->ptracks += ConvertMIDI2Int(len, (uint8 *)ptrk->ptracks, (size_t)(ptrk->ptrmax - ptrk->ptracks));
-						if (ptrk->ptracks+len > ptrk->ptrmax)
-						{
-							// EOF
-							ptrk->ptracks = NULL;
-						} else
-						switch(i)
+						m_nDefaultTempo = newTempo;
+					} else if(newTempo != tempo)
+					{
+						patRow[tempoChannel].command = CMD_TEMPO;
+						patRow[tempoChannel].param = mpt::saturate_cast<ModCommand::PARAM>(std::max(32.0, Util::Round(newTempo.ToDouble())));
+					}
+					tempo = newTempo;
+				}
+				break;
+
+			default:
+				break;
+			}
+		} else
+		{
+			if(data1 & 0x80)
+			{
+				// Command byte (if not present, repeat previous command byte)
+				tracks[t].command = data1;
+				if(data1 < 0xF0)
+					data1 = track.ReadUint8();
+			}
+			uint8 midiCh = tracks[t].command & 0x0F;
+
+			switch(tracks[t].command & 0xF0)
+			{
+			case 0x80: // Note Off
+			case 0x90: // Note On
+				{
+					data1 &= 0x7F;
+					ModCommand::NOTE note = static_cast<ModCommand::NOTE>(Clamp(data1 + NOTE_MIN, NOTE_MIN, NOTE_MAX));
+					uint8 data2 = track.ReadUint8();
+					if(data2 > 0 && (tracks[t].command & 0xF0) == 0x90)
+					{
+						// Note On
+						CHANNELINDEX chn = FindUnusedChannel(midiCh, note, modChnStatus, midiChnStatus[midiCh].monoMode, patRow);
+						if(chn != CHANNELINDEX_INVALID)
 						{
-						// FF.01 [text]: Song Information
-						case 0x01:
-							if (!len) break;
-							if ((len < 32) && m_songName.empty())
+							modChnStatus[chn].age = tick;
+							modChnStatus[chn].note = note;
+							modChnStatus[chn].midiCh = midiCh;
+							modChnStatus[chn].vol = data2;
+							modChnStatus[chn].sustained = false;
+							midiChnStatus[midiCh].noteOn[data1] = chn;
+							int32 pitchOffset = 0;
+							if(midiChnStatus[midiCh].pitchbendMod != 0)
 							{
-								mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, reinterpret_cast<const char*>(ptrk->ptracks), len);
+								pitchOffset = (midiChnStatus[midiCh].pitchbendMod + (midiChnStatus[midiCh].pitchbendMod > 0 ? 32 : -32)) / 64;
+								modChnStatus[chn].porta = pitchOffset * 64;
 							} else
-							if (m_songMessage.empty() && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F))
 							{
-								m_songMessage.Read(ptrk->ptracks, len, SongMessage::leAutodetect);
+								modChnStatus[chn].porta = 0;
 							}
-							break;
-						// FF.02 [text]: Song Copyright
-						case 0x02:
-							if (!len) break;
-							if (m_songMessage.empty() && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F) && (len > 7))
+							patRow[chn].note = static_cast<ModCommand::NOTE>(Clamp(note + pitchOffset + midiChnStatus[midiCh].transpose + masterTranspose, NOTE_MIN, NOTE_MAX));
+							patRow[chn].instr = mpt::saturate_cast<ModCommand::INSTR>(MapMidiInstrument(midiChnStatus[midiCh].program, midiChnStatus[midiCh].bank, midiCh + 1, data1, isXG, drumChns));
+							EnterMIDIVolume(patRow[chn], modChnStatus[chn], midiChnStatus[midiCh]);
+
+							if(patRow[chn].command == CMD_PORTAMENTODOWN || patRow[chn].command == CMD_PORTAMENTOUP)
 							{
-								m_songMessage.Read(ptrk->ptracks, len, SongMessage::leAutodetect);
+								patRow[chn].command = CMD_NONE;
 							}
-							break;
-						// FF.03: Sequence Name
-						case 0x03:
-						// FF.06: Sequence Text (->Pattern names)
-						case 0x06:
-							if ((len > 1) && (!trk))
+							if(delay != 0)
 							{
-								std::string s;
-								mpt::String::Read<mpt::String::maybeNullTerminated>(s, reinterpret_cast<const char*>(ptrk->ptracks), len);
-								if ((!mpt::CompareNoCaseAscii(s.c_str(), "Copyri", 6)) || s.empty()) break;
-								if (i == 0x03)
-								{
-									if(m_songName.empty()) mpt::String::Copy(m_songName, s);
-								} else
-								if (!trk)
-								{
-									Patterns[pat].SetName(s);
-								}
-#ifdef MIDI_LOG
-								Log("Track #%d, META 0x%02X, Pattern %d: ", trk, i, pat);
-								Log("%s\n", (uint32)s);
-#endif
+								patRow[chn].command = CMD_S3MCMDEX;
+								patRow[chn].param = 0xD0 | delay;
 							}
-							break;
-						// FF.07: Cue Point (marker)
-						// FF.20: Channel Prefix
-						// FF.2F: End of Track
-						case 0x2F:
-							ptrk->status = 0x2F;
-							ptrk->ptracks = NULL;
-							break;
-						// FF.51 [tttttt]: Set Tempo
-						case 0x51:
+							if(modChnStatus[chn].pan != midiChnStatus[midiCh].pan && patRow[chn].command == CMD_NONE)
 							{
-								LONG l = ptrk->ptracks[0];
-								l = (l << 8) | ptrk->ptracks[1];
-								l = (l << 8) | ptrk->ptracks[2];
-								if (l <= 0) break;
-								nTempoUsec = l / nPPQN;
-								if (nTempoUsec < 100) nTempoUsec = 100;
-								tempo = ConvertMidiTempo(nTempoUsec, nTickMultiplier, importSpeed);
-								dwGlobalFlags |= MIDIGLOBAL_UPDATETEMPO;
-#ifdef MIDI_LOG
-								Log("META Tempo: %d usec\n", nTempoUsec);
-#endif
+								patRow[chn].command = CMD_PANNING8;
+								patRow[chn].param = midiChnStatus[midiCh].pan;
+								modChnStatus[chn].pan = midiChnStatus[midiCh].pan;
 							}
-							break;
-						// FF.58: Time Signature
-						// FF.7F: Sequencer-Specific
-#ifdef MIDI_LOG
-						default:
-							if ((i != 0x58) && (i != 0x7F))
-								Log("track %d: META %02X len=%d\n", trk, i, len);
-#endif
 						}
-						if (ptrk->ptracks) ptrk->ptracks += len;
+					} else
+					{
+						// Note Off
+						MIDINoteOff(midiChnStatus[midiCh], modChnStatus, data1, delay, patRow);
 					}
-					break;
-
-				//////////////////////////////////////////////////////////////////////////
-				// Regular Voice Events
-				default:
+				}
+				break;
+			case 0xA0: // Note Aftertouch
 				{
-					uint32 midich = (ptrk->status & 0x0F)+1;
-					uint32 midist = ptrk->status & 0xF0;
-					MIDICHANNELSTATE *pmidich = &midichstate[midich-1];
-					uint32 note, velocity;
-
-					switch(midist)
+					track.Skip(1);
+				}
+				break;
+			case 0xB0: // Controller
+				{
+					uint8 data2 = track.ReadUint8();
+					switch(data1)
 					{
-					//////////////////////////////////
-					// Note Off:	80.note.velocity
-					case 0x80:
-					// Note On:		90.note.velocity
-					case 0x90:
-						note = ptrk->ptracks[0] & 0x7F;
-						velocity = (midist == 0x90) ? (ptrk->ptracks[1] & 0x7F) : 0;
-						ptrk->ptracks += 2;
-					#ifdef MIDI_DETAILED_LOG
-						Log("Ch %d: NoteOn(%d,%d)\n", midich, note, velocity);
-					#endif
-						// Note On: 90.note.velocity
-						if (velocity)
+					case MIDIEvents::MIDICC_Panposition_Coarse:
+						midiChnStatus[midiCh].pan = data2 * 2u;
+						for(auto chn : midiChnStatus[midiCh].noteOn)
 						{
-							// Start counting rows
-							dwGlobalFlags &= ~MIDIGLOBAL_FROZEN;
-							// if the note is already playing, we reuse this channel
-							uint32 nchn = pmidich->note_on[note];
-							if ((nchn) && (chnstate[nchn-1].parent != midich)) nchn = 0;
-							// or else, we look for an available child channel
-							if (!nchn)
-							{
-								for (uint32 i=0; i<m_nChannels; i++) if (chnstate[i].parent == midich)
-								{
-									if ((!chnstate[i].note) && ((!m[i].note) || (m[i].note & 0x80)))
-									{
-										// found an available channel
-										nchn = i+1;
-										break;
-									}
-								}
-							}
-							// still nothing? in this case, we try to allocate a new mod channel
-							if (!nchn)
-							{
-								for (uint32 i=0; i<m_nChannels; i++) if (!chnstate[i].parent)
-								{
-									nchn = i+1;
-									chnstate[i].parent = midich;
-									break;
-								}
-							}
-							// still not? we have to steal a voice from another channel
-#ifdef MIDI_LOG
-							if (!nchn)
-							{
-								Log("Not enough voices!\n");
-							}
-#endif
-							// We found our channel: let's do the note on
-							if (nchn)
+							if(chn != CHANNELINDEX_INVALID)
 							{
-								pmidich->note_on[note] = nchn;
-								nchn--;
-								chnstate[nchn].pitchsrc = pmidich->pitchbend;
-								chnstate[nchn].pitchdest = pmidich->pitchbend;
-								chnstate[nchn].flags &= ~CHNSTATE_NOTEOFFPENDING;
-								chnstate[nchn].idlecount = 0;
-								chnstate[nchn].note = note+1;
-								int realnote = note;
-								if (midich != 10)
-								{
-									realnote += (((int)pmidich->pitchbend - 0x2000) * pmidich->pitchbendrange) / (0x2000*32);
-									if (realnote < 0) realnote = 0;
-									if (realnote > 119) realnote = 119;
-								}
-								m[nchn].note = realnote+1;
-								m[nchn].instr = MapMidiInstrument(pmidich->program + ((uint32)pmidich->bank << 7), midich, note);
-								m[nchn].volcmd = VOLCMD_VOLUME;
-								LONG vol = CDLSBank::DLSMidiVolumeToLinear(velocity) >> 8;
-								vol = (vol * (LONG)pmidich->volume * (LONG)pmidich->expression) >> 13;
-								if (vol > 256) vol = 256;
-								if (vol < 4) vol = 4;
-								m[nchn].vol = (uint8)(vol>>2);
-								// Channel Panning
-								if ((!m[nchn].command) && (pmidich->pan != chnstate[nchn].pan))
+								if(Patterns[pat].WriteEffect(EffectWriter(CMD_PANNING8, midiChnStatus[midiCh].pan).Channel(chn).Row(row)))
 								{
-									chnstate[nchn].pan = pmidich->pan;
-									m[nchn].param = pmidich->pan;
-									m[nchn].command = CMD_PANNING8;
+									modChnStatus[chn].pan = midiChnStatus[midiCh].pan;
 								}
 							}
-						} else
-						// Note Off; 90.note.00
-						if (!(dwGlobalFlags & MIDIGLOBAL_FROZEN))
+						}
+						break;
+
+					case MIDIEvents::MIDICC_DataEntry_Coarse:
+						midiChnStatus[midiCh].SetRPN(data2);
+						break;
+
+					case MIDIEvents::MIDICC_Volume_Coarse:
+						midiChnStatus[midiCh].volume = (uint8)(CDLSBank::DLSMidiVolumeToLinear(data2) >> 9);
+						for(auto chn : midiChnStatus[midiCh].noteOn)
 						{
-							uint32 nchn = pmidich->note_on[note];
-							if (nchn)
+							if(chn != CHANNELINDEX_INVALID)
 							{
-								nchn--;
-								chnstate[nchn].flags |= CHNSTATE_NOTEOFFPENDING;
-								chnstate[nchn].note = 0;
-								pmidich->note_on[note] = 0;
-							} else
-							{
-								for (uint32 i=0; i<m_nChannels; i++)
-								{
-									if ((chnstate[i].parent == midich) && (chnstate[i].note == note+1))
-									{
-										chnstate[i].note = 0;
-										chnstate[i].flags |= CHNSTATE_NOTEOFFPENDING;
-									}
-								}
+								EnterMIDIVolume(patRow[chn], modChnStatus[chn], midiChnStatus[midiCh]);
 							}
 						}
 						break;
 
-					///////////////////////////////////
-					// A0.xx.yy: Aftertouch
-					case 0xA0:
+					case MIDIEvents::MIDICC_Expression_Coarse:
+						midiChnStatus[midiCh].expression = (uint8)(CDLSBank::DLSMidiVolumeToLinear(data2) >> 9);
+						for(auto chn : midiChnStatus[midiCh].noteOn)
 						{
-#ifdef MIDI_LOG
-							uint32 a = ptrk->ptracks[0];
-							uint32 b = ptrk->ptracks[1];
-							Log("track %d: %02X %04X\n", trk, midist, a*256+b);
-#endif
-							ptrk->ptracks += 2;
+							if(chn != CHANNELINDEX_INVALID)
+							{
+								EnterMIDIVolume(patRow[chn], modChnStatus[chn], midiChnStatus[midiCh]);
+							}
 						}
 						break;
 
-					///////////////////////////////////
-					// B0: Control Change
-					case 0xB0:
+					case MIDIEvents::MIDICC_BankSelect_Coarse:
+						midiChnStatus[midiCh].bank &= 0x7F;
+						midiChnStatus[midiCh].bank |= (data2 << 7);
+						break;
+
+					case MIDIEvents::MIDICC_BankSelect_Fine:
+						midiChnStatus[midiCh].bank &= (0x7F << 7);
+						midiChnStatus[midiCh].bank |= data2;
+						break;
+
+					case MIDIEvents::MIDICC_HoldPedal_OnOff:
+						midiChnStatus[midiCh].sustain = (data2 >= 0x40);
+						if(data2 < 0x40)
 						{
-							uint32 controller = ptrk->ptracks[0];
-							uint32 value = ptrk->ptracks[1] & 0x7F;
-							ptrk->ptracks += 2;
-							switch(controller)
+							// Release notes that are still being held after note-off
+							for(const auto &chnState : modChnStatus)
 							{
-							// Bn.00.xx: Bank Select MSB (GS)
-							case 0x00:
-								pmidich->bank &= 0x7F;
-								pmidich->bank |= (value << 7);
-								break;
-							// Bn.01.xx: Modulation Depth
-							case 0x01:
-								pmidich->pitchbendrange = value;
-								break;
-							// Bn.07.xx: Volume
-							case 0x07:
-								pmidich->volume = (uint8)(CDLSBank::DLSMidiVolumeToLinear(value) >> 9);
-								break;
-							// Bn.0B.xx: Expression
-							case 0x0B:
-								pmidich->expression = (uint8)(CDLSBank::DLSMidiVolumeToLinear(value) >> 9);
-								break;
-							// Bn.0A.xx: Pan
-							case 0x0A:
-								pmidich->pan = value * 2;
-								break;
-							// Bn.20.xx: Bank Select LSB (GS)
-							case 0x20:
-								pmidich->bank &= (0x7F << 7);
-								pmidich->bank |= value;
-								break;
-							// Bn.79.00: Reset All Controllers (GM)
-							case 0x79:
-								pmidich->modulation = 0;
-								pmidich->expression = 128;
-								pmidich->pitchbend = 0x2000;
-								pmidich->pitchbendrange = 64;
-								// Should also reset pedals (40h-43h), NRP, RPN, aftertouch
-								break;
-							// Bn.78.00: All Sound Off (GS)
-							// Bn.7B.00: All Notes Off (GM)
-							case 0x78:
-							case 0x7B:
-								if (value == 0x00)
+								if(chnState.midiCh == midiCh && chnState.sustained)
 								{
-									// All Notes Off
-									for (uint32 k=0; k<m_nChannels; k++)
-									{
-										if (chnstate[k].note)
-										{
-											chnstate[k].flags |= CHNSTATE_NOTEOFFPENDING;
-											chnstate[k].note = 0;
-										}
-									}
+									MIDINoteOff(midiChnStatus[midiCh], modChnStatus, chnState.note - NOTE_MIN, delay, patRow);
 								}
-								break;
-							////////////////////////////////////
-							// Controller List
-							//
-							// Bn.02.xx: Breath Control
-							// Bn.04.xx: Foot Pedal
-							// Bn.05.xx: Portamento Time (Glissando Time)
-							// Bn.06.xx: Data Entry MSB
-							// Bn.08.xx: Balance
-							// Bn.10-13.xx: GP Control #1-#4
-							// Bn.20-3F.xx: Data LSB for controllers 0-31
-							// Bn.26.xx: Data Entry LSB
-							// Bn.40.xx: Hold Pedal #1
-							// Bn.41.xx: Portamento (GS)
-							// Bn.42.xx: Sostenuto (GS)
-							// Bn.43.xx: Soft Pedal (GS)
-							// Bn.44.xx: Legato Pedal
-							// Bn.45.xx: Hold Pedal #2
-							// Bn.46.xx: Sound Variation
-							// Bn.47.xx: Sound Timbre
-							// Bn.48.xx: Sound Release Time
-							// Bn.49.xx: Sound Attack Time
-							// Bn.4A.xx: Sound Brightness
-							// Bn.4B-4F.xx: Sound Control #6-#10
-							// Bn.50-53.xx: GP Control #5-#8
-							// Bn.54.xx: Portamento Control (GS)
-							// Bn.5B.xx: Reverb Level (GS)
-							// Bn.5C.xx: Tremolo Depth
-							// Bn.5D.xx: Chorus Level (GS)
-							// Bn.5E.xx: Celeste Depth
-							// Bn.5F.xx: Phaser Depth
-							// Bn.60.xx: Data Increment
-							// Bn.61.xx: Data Decrement
-							// Bn.62.xx: Non-RPN Parameter LSB (GS)
-							// Bn.63.xx: Non-RPN Parameter MSB (GS)
-							// Bn.64.xx: RPN Parameter LSB (GM)
-							// Bn.65.xx: RPN Parameter MSB (GM)
-							// Bn.7A.00: Local On/Off
-							// Bn.7C.00: Omni Mode Off
-							// Bn.7D.00: Omni Mode On
-							// Bn.7E.mm: Mono Mode On
-							// Bn.7F.00: Poly Mode On
-#ifdef MIDI_LOG
-							default:
-								Log("Control Change %02X controller %02X = %02X\n", ptrk->status, controller, value);
-#endif
 							}
 						}
 						break;
 
-					////////////////////////////////
-					// C0.pp: Program Change
-					case 0xC0:
+					case MIDIEvents::MIDICC_DataButtonincrement:
+					case MIDIEvents::MIDICC_DataButtondecrement:
+						midiChnStatus[midiCh].SetRPN(midiChnStatus[midiCh].GetRPN() + ((data1 == MIDIEvents::MIDICC_DataButtonincrement) ? 1 : -1));
+						break;
+
+					case MIDIEvents::MIDICC_NonRegisteredParameter_Fine:
+					case MIDIEvents::MIDICC_NonRegisteredParameter_Coarse:
+						midiChnStatus[midiCh].rpn = 0x3FFF;
+						break;
+
+					case MIDIEvents::MIDICC_RegisteredParameter_Fine:
+						midiChnStatus[midiCh].rpn &= (0x7F << 7);
+						midiChnStatus[midiCh].rpn |= data2;
+						break;
+					case MIDIEvents::MIDICC_RegisteredParameter_Coarse:
+						midiChnStatus[midiCh].rpn &= 0x7F;
+						midiChnStatus[midiCh].rpn |= (data2 << 7);
+						break;
+
+					case 110:
+						isEMIDI = true;
+						break;
+
+					case 111:
+						// Non-standard MIDI loop point. May conflict with Apogee EMIDI CCs (110/111), which is why we also check if CC 110 is ever used.
+						if(data2 == 0)
 						{
-							pmidich->program = ptrk->ptracks[0] & 0x7F;
-							ptrk->ptracks++;
-#ifdef MIDI_DETAILED_LOG
-							Log("track %ld, channel %ld: program change %ld\n", trk, midich, pmidich->program);
-#endif
+							Order().SetRestartPos(ord);
+							restartRow = row;
 						}
 						break;
 
-					////////////////////////////////
-					// D0: Channel Aftertouch (Polyphonic Key Pressure)
-					case 0xD0:
+					case MIDIEvents::MIDICC_AllControllersOff:
+						midiChnStatus[midiCh].ResetAllControllers();
+						break;
+
+						// Bn.78.00: All Sound Off (GS)
+						// Bn.7B.00: All Notes Off (GM)
+					case MIDIEvents::MIDICC_AllSoundOff:
+					case MIDIEvents::MIDICC_AllNotesOff:
+						// All Notes Off
+						midiChnStatus[midiCh].sustain = false;
+						for(uint8 note = 0; note < 128; note++)
 						{
-							ptrk->ptracks++;
+							MIDINoteOff(midiChnStatus[midiCh], modChnStatus, note, delay, patRow);
 						}
 						break;
-					
-					////////////////////////////////
-					// E0: Pitch Bend
-					case 0xE0:
+					case MIDIEvents::MIDICC_MonoOperation:
+						if(data2 == 0)
 						{
-							pmidich->pitchbend = (uint16)(((uint32)ptrk->ptracks[1] << 7) + (ptrk->ptracks[0] & 0x7F));
-							for (uint32 i=0; i<128; i++) if (pmidich->note_on[i])
-							{
-								uint32 nchn = pmidich->note_on[i]-1;
-								if (chnstate[nchn].parent == midich)
-								{
-									chnstate[nchn].pitchdest = pmidich->pitchbend;
-								}
-							}
-#ifdef MIDI_DETAILED_LOG
-							Log("channel %ld: pitch bend = 0x%04X\n", midich, pmidich->pitchbend);
-#endif
-							ptrk->ptracks+=2;
+							midiChnStatus[midiCh].monoMode = true;
+						}
+						break;
+					case MIDIEvents::MIDICC_PolyOperation:
+						if(data2 == 0)
+						{
+							midiChnStatus[midiCh].monoMode = false;
 						}
 						break;
-
-					//////////////////////////////////////
-					// F0 & Unsupported commands: skip it
-					default:
-						ptrk->ptracks++;
-#ifdef MIDI_LOG
-						Log("track %d: unknown status byte: 0x%02X\n", trk, ptrk->status);
-#endif
 					}
-				}} // switch+default
-				// Process to next event
-				if (ptrk->ptracks)
-				{
-					LONG inc;
-					ptrk->ptracks += ConvertMIDI2Int(inc, (uint8 *)ptrk->ptracks, (size_t)(ptrk->ptrmax - ptrk->ptracks));
-					ptrk->nexteventtime += inc;
 				}
-				if (ptrk->ptracks >= ptrk->ptrmax) ptrk->ptracks = NULL;
-			}
-			// End reached?
-			if (ptrk->ptracks >= ptrk->ptrmax) ptrk->ptracks = NULL;
-		}
-
-		////////////////////////////////////////////////////////////////////
-		// Move to next row
-		if (!(dwGlobalFlags & MIDIGLOBAL_FROZEN))
-		{
-			// Check MOD channels status
-			for (uint32 ichn=0; ichn<m_nChannels; ichn++)
-			{
-				// Pending Global Effects ?
-				if (!m[ichn].command)
+				break;
+			case 0xC0: // Program Change
+				midiChnStatus[midiCh].program = data1 & 0x7F;
+				break;
+			case 0xD0: // Channel aftertouch
+				break;
+			case 0xE0: // Pitch bend
+				midiChnStatus[midiCh].SetPitchbend(data1 | (track.ReadUint8() << 7));
+				break;
+			case 0xF0: // General / Immediate
+				switch(midiCh)
 				{
-					if ((chnstate[ichn].pitchsrc != chnstate[ichn].pitchdest) && (chnstate[ichn].parent))
+				case MIDIEvents::sysExStart: // SysEx
+				case MIDIEvents::sysExEnd: // SysEx (continued)
 					{
-						int newpitch = chnstate[ichn].pitchdest;
-						int pitchbendrange = midichstate[chnstate[ichn].parent-1].pitchbendrange;
-						// +/- 256 for +/- pitch bend range
-						int slideamount = (newpitch - (int)chnstate[ichn].pitchsrc) / (int)32;
-#ifdef MIDI_DETAILED_LOG
-						Log("chn%2d: portamento: src=%5d dest=%5d ", ichn, chnstate[ichn].pitchsrc, chnstate[ichn].pitchdest);
-						Log("bendamount=%5d range=%d slideamount=%d\n", pitchbendamount, pitchbendrange, slideamount);
-#endif
-						if (slideamount)
+						uint32 len;
+						track.ReadVarInt(len);
+						FileReader sysex = track.ReadChunk(len);
+						if(midiCh == MIDIEvents::sysExEnd)
+							break;
+
+						if(sysex.ReadMagic("\x7F\x7F\x04\x01"))
 						{
-							const int ppdiv = (16 * 128 * (importSpeed - 1));
-							newpitch = (int)chnstate[ichn].pitchsrc + slideamount;
-							if (slideamount < 0)
+							// Master volume
+							uint8 volumeRaw[2];
+							sysex.ReadArray(volumeRaw);
+							uint16 globalVol = volumeRaw[0] | (volumeRaw[1] << 7);
+							if(tick == 0)
 							{
-								int param = (-slideamount * pitchbendrange + ppdiv/2) / ppdiv;
-								if (param >= 0x80) param = 0x80;
-								if (param > 0)
-								{
-									m[ichn].param = (uint8)param;
-									m[ichn].command = CMD_PORTAMENTODOWN;
-								}
+								m_nDefaultGlobalVolume = Util::muldivr_unsigned(globalVol, MAX_GLOBAL_VOLUME, 16383);
 							} else
 							{
-								int param = (slideamount * pitchbendrange + ppdiv/2) / ppdiv;
-								if (param >= 0x80) param = 0x80;
-								if (param > 0)
-								{
-									m[ichn].param = (uint8)param;
-									m[ichn].command = CMD_PORTAMENTOUP;
-								}
+								patRow[globalVolChannel].command = CMD_GLOBALVOLUME;
+								patRow[globalVolChannel].param = static_cast<ModCommand::PARAM>(Util::muldivr_unsigned(globalVol, 128, 16383));
+							}
+						} else
+						{
+							uint8 xg[7];
+							sysex.ReadArray(xg);
+							if(!memcmp(xg, "\x43\x10\x4C\x00\x00\x7E\x00", 7))
+							{
+								// XG System On
+								isXG = true;
+							} else if(!memcmp(xg, "\x43\x10\x4C\x00\x00\x06", 6))
+							{
+								// XG Master Transpose
+								masterTranspose = static_cast<int8>(xg[6]) - 64;
+							} else if(!memcmp(xg, "\x41\x10\x42\x12\x40", 5) && (xg[5] & 0xF0) == 0x10 && xg[6] == 0x15)
+							{
+								// GS Drum Kit
+								uint8 chn = xg[5] & 0x0F;
+								if(chn == 0)
+									chn = 9;
+								else if(chn < 10)
+									chn--;
+								drumChns.set(chn, xg[6] != 0);
 							}
 						}
-						chnstate[ichn].pitchsrc = (uint16)newpitch;
-#ifdef MIDI_DETAILED_LOG
-						Log("  newpitchsrc=%5d newpitchdest=%5d\n", chnstate[ichn].pitchsrc, chnstate[ichn].pitchdest);
-#endif
+					}
+					break;
+				case MIDIEvents::sysQuarterFrame:
+					track.Skip(1);
+					break;
+				case MIDIEvents::sysPositionPointer:
+					track.Skip(2);
+					break;
+				case MIDIEvents::sysSongSelect:
+					track.Skip(1);
+					break;
+				case MIDIEvents::sysTuneRequest:
+				case MIDIEvents::sysMIDIClock:
+				case MIDIEvents::sysMIDITick:
+				case MIDIEvents::sysStart:
+				case MIDIEvents::sysContinue:
+				case MIDIEvents::sysStop:
+				case MIDIEvents::sysActiveSense:
+				case MIDIEvents::sysReset:
+					break;
 
-					} else
-					if (dwGlobalFlags & MIDIGLOBAL_UPDATETEMPO)
-					{
-						m[ichn].command = CMD_TEMPO;
-						m[ichn].param = (uint8)tempo;
-						dwGlobalFlags &= ~MIDIGLOBAL_UPDATETEMPO;
-					} else
-					if (dwGlobalFlags & MIDIGLOBAL_UPDATEMASTERVOL)
+				default:
+					break;
+				}
+				break;
+
+			default:
+				break;
+			}
+		}
+
+		// Pitch bend any channels that haven't reached their target yet
+		// TODO: This is currently not called on any rows without events!
+		for(size_t chn = 0; chn < modChnStatus.size(); chn++)
+		{
+			ModChannelState &chnState = modChnStatus[chn];
+			ModCommand &m = patRow[chn];
+			uint8 midiCh = chnState.midiCh;
+			if(chnState.note == NOTE_NONE || m.command == CMD_S3MCMDEX || m.command == CMD_DELAYCUT || midiCh == ModChannelState::NOMIDI)
+				continue;
+
+			int32 diff = midiChnStatus[midiCh].pitchbendMod - chnState.porta;
+			if(diff == 0)
+				continue;
+
+			if(m.command == CMD_PORTAMENTODOWN || m.command == CMD_PORTAMENTOUP)
+			{
+				// First, undo the effect of an existing portamento command
+				int32 porta = 0;
+				if(m.param < 0xE0)
+					porta = m.param * 4 * (ticksPerRow - 1);
+				else if(m.param < 0xF0)
+					porta = (m.param & 0x0F);
+				else
+					porta = (m.param & 0x0F) * 4;
+
+				if(m.command == CMD_PORTAMENTODOWN)
+					porta = -porta;
+
+				diff += porta;
+				chnState.porta -= porta;
+
+				if(diff == 0)
+				{
+					m.command = CMD_NONE;
+					continue;
+				}
+			}
+
+			m.command = static_cast<ModCommand::COMMAND>(diff < 0 ? CMD_PORTAMENTODOWN : CMD_PORTAMENTOUP);
+			int32 absDiff = mpt::abs(diff);
+			int32 realDiff = 0;
+			if(absDiff < 16)
+			{
+				// Extra-fine slides can do this.
+				m.param = 0xE0 | static_cast<uint8>(absDiff);
+				realDiff = absDiff;
+			} else if(absDiff < 64)
+			{
+				// Fine slides can do this.
+				absDiff = std::min((absDiff + 3) / 4, 0x0F);
+				m.param = 0xF0 | static_cast<uint8>(absDiff);
+				realDiff = absDiff * 4;
+			} else
+			{
+				// Need a normal slide.
+				absDiff /= 4 * (ticksPerRow - 1);
+				LimitMax(absDiff, 0xDF);
+				m.param = static_cast<uint8>(absDiff);
+				realDiff = absDiff * 4 * (ticksPerRow - 1);
+			}
+			chnState.porta += realDiff * sgn(diff);
+		}
+
+		tick_t delta = 0;
+		if(track.ReadVarInt(delta) && track.CanRead(1))
+		{
+			tracks[t].nextEvent += delta;
+		} else
+		{
+			finishedTracks++;
+			tracks[t].nextEvent = Util::MaxValueOfType(delta);
+			tracks[t].finished = true;
+			// Add another sub-song for type-2 files
+			if(isType2 && finishedTracks < numTracks)
+			{
+				if(Order.AddSequence(false) == SEQUENCEINDEX_INVALID)
+					break;
+				Order().clear();
+			}
+		}
+	}
+
+	if(isEMIDI)
+	{
+		Order().SetRestartPos(0);
+	}
+
+	if(Order().IsValidPat(lastOrd))
+	{
+		PATTERNINDEX lastPat = Order()[lastOrd];
+		Patterns[lastPat].Resize(lastRow + 1);
+		if(restartRow != ROWINDEX_INVALID && !isEMIDI)
+		{
+			Patterns[lastPat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, mpt::saturate_cast<ModCommand::PARAM>(restartRow)).Row(lastRow));
+		}
+	}
+	Order.SetSequence(0);
+
+	std::vector<CHANNELINDEX> channels;
+	channels.reserve(m_nChannels);
+	for(CHANNELINDEX i = 0; i < m_nChannels; i++)
+	{
+		if(modChnStatus[i].midiCh != ModChannelState::NOMIDI
+#ifdef MODPLUG_TRACKER
+			|| (GetpModDoc() != nullptr && !GetpModDoc()->IsChannelUnused(i))
+#endif // MODPLUG_TRACKER
+			)
+		{
+			channels.push_back(i);
+			if(modChnStatus[i].midiCh != ModChannelState::NOMIDI)
+				sprintf(ChnSettings[i].szName, "MIDI Ch %u", 1 + modChnStatus[i].midiCh);
+			else if(i == tempoChannel)
+				strcpy(ChnSettings[i].szName, "Tempo");
+			else if(i == globalVolChannel)
+				strcpy(ChnSettings[i].szName, "Global Volume");
+		}
+	}
+	if(channels.empty())
+		return false;
+
+#ifdef MODPLUG_TRACKER
+	if(GetpModDoc() != nullptr)
+	{
+		// Keep MIDI channels in patterns neatly grouped
+		std::sort(channels.begin(), channels.end(), [&modChnStatus] (CHANNELINDEX c1, CHANNELINDEX c2) -> bool
+		{
+			if(modChnStatus[c1].midiCh == modChnStatus[c2].midiCh)
+				return c1 < c2;
+			return modChnStatus[c1].midiCh < modChnStatus[c2].midiCh;
+		});
+		GetpModDoc()->ReArrangeChannels(channels, false);
+		GetpModDoc()->m_ShowSavedialog = true;
+	}
+
+	std::shared_ptr<CDLSBank> pCachedBank, pEmbeddedBank;
+	mpt::PathString cachedBankFile;
+
+	if(CDLSBank::IsDLSBank(file.GetFileName()))
+	{
+		// Soundfont embedded in MIDI file
+		pEmbeddedBank = std::make_shared<CDLSBank>();
+		pEmbeddedBank->Open(file.GetFileName());
+	} else
+	{
+		// Soundfont with same name as MIDI file
+		for(const auto &ext : { MPT_PATHSTRING(".sf2"), MPT_PATHSTRING(".sbk"), MPT_PATHSTRING(".dls") })
+		{
+			mpt::PathString filename = file.GetFileName().ReplaceExt(ext);
+			if(filename.IsFile())
+			{
+				pEmbeddedBank = std::make_shared<CDLSBank>();
+				if(pEmbeddedBank->Open(filename))
+					break;
+			}
+		}
+	}
+	ChangeModTypeTo(MOD_TYPE_MPT);
+	MIDILIBSTRUCT &midiLib = CTrackApp::GetMidiLibrary();
+	// Scan Instruments
+	for (INSTRUMENTINDEX nIns = 1; nIns <= m_nInstruments; nIns++) if (Instruments[nIns])
+	{
+		mpt::PathString pszMidiMapName;
+		ModInstrument *pIns = Instruments[nIns];
+		uint32 nMidiCode;
+		bool embedded = false;
+
+		if (pIns->nMidiChannel == MIDI_DRUMCHANNEL)
+			nMidiCode = 0x80 | (pIns->nMidiDrumKey & 0x7F);
+		else
+			nMidiCode = pIns->nMidiProgram & 0x7F;
+		pszMidiMapName = midiLib.MidiMap[nMidiCode];
+		if (pEmbeddedBank)
+		{
+			uint32 nDlsIns = 0, nDrumRgn = 0;
+			uint32 nProgram = (pIns->nMidiProgram != 0) ? pIns->nMidiProgram - 1 : 0;
+			uint32 dwKey = (nMidiCode < 128) ? 0xFF : (nMidiCode & 0x7F);
+			if ((pEmbeddedBank->FindInstrument(	(nMidiCode >= 128),
+				((pIns->wMidiBank - 1) & 0x3FFF),
+				nProgram, dwKey, &nDlsIns))
+				|| (pEmbeddedBank->FindInstrument(	(nMidiCode >= 128),	0xFFFF,
+				(nMidiCode >= 128) ? 0xFF : nProgram,
+				dwKey, &nDlsIns)))
+			{
+				if (dwKey < 0x80) nDrumRgn = pEmbeddedBank->GetRegionFromKey(nDlsIns, dwKey);
+				if (pEmbeddedBank->ExtractInstrument(*this, nIns, nDlsIns, nDrumRgn))
+				{
+					pIns = Instruments[nIns]; // Reset pIns because ExtractInstrument may delete the previous value.
+					if ((dwKey >= 24) && (dwKey < 24 + MPT_ARRAY_COUNT(szMidiPercussionNames)))
 					{
-						m[ichn].command = CMD_GLOBALVOLUME;
-						m[ichn].param = midimastervol >> 1; // 0-128
-						dwGlobalFlags &= ~MIDIGLOBAL_UPDATEMASTERVOL;
+						mpt::String::CopyN(pIns->name, szMidiPercussionNames[dwKey - 24]);
 					}
+					embedded = true;
 				}
-				// Check pending noteoff events for m[ichn]
-				if (!m[ichn].note)
+				else
+					pIns = Instruments[nIns]; // Reset pIns because ExtractInstrument may delete the previous value.
+			}
+		}
+		if((!pszMidiMapName.empty()) && (!embedded))
+		{
+			// Load From DLS Bank
+			if (CDLSBank::IsDLSBank(pszMidiMapName))
+			{
+				std::shared_ptr<CDLSBank> pDLSBank = nullptr;
+
+				if ((pCachedBank) && (!mpt::PathString::CompareNoCase(cachedBankFile, pszMidiMapName)))
+				{
+					pDLSBank = pCachedBank;
+				} else
+				{
+					pCachedBank = std::make_shared<CDLSBank>();
+					cachedBankFile = pszMidiMapName;
+					if (pCachedBank->Open(pszMidiMapName)) pDLSBank = pCachedBank;
+				}
+				if (pDLSBank)
 				{
-					if (chnstate[ichn].flags & CHNSTATE_NOTEOFFPENDING)
+					uint32 nDlsIns = 0, nDrumRgn = 0;
+					uint32 nProgram = (pIns->nMidiProgram != 0) ? pIns->nMidiProgram - 1 : 0;
+					uint32 dwKey = (nMidiCode < 128) ? 0xFF : (nMidiCode & 0x7F);
+					if ((pDLSBank->FindInstrument(	(nMidiCode >= 128),
+						((pIns->wMidiBank - 1) & 0x3FFF),
+						nProgram, dwKey, &nDlsIns))
+						|| (pDLSBank->FindInstrument(	(nMidiCode >= 128), 0xFFFF,
+						(nMidiCode >= 128) ? 0xFF : nProgram,
+						dwKey, &nDlsIns)))
 					{
-						chnstate[ichn].flags &= ~CHNSTATE_NOTEOFFPENDING;
-						m[ichn].note = 0xFF;
+						if (dwKey < 0x80) nDrumRgn = pDLSBank->GetRegionFromKey(nDlsIns, dwKey);
+						pDLSBank->ExtractInstrument(*this, nIns, nDlsIns, nDrumRgn);
+						pIns = Instruments[nIns]; // Reset pIns because ExtractInstrument may delete the previous value.
+						if ((dwKey >= 24) && (dwKey < 24 + MPT_ARRAY_COUNT(szMidiPercussionNames)))
+						{
+							mpt::String::CopyN(pIns->name, szMidiPercussionNames[dwKey - 24]);
+						}
 					}
-					// Check State of channel
-					chnstate[ichn].idlecount++;
-					if ((chnstate[ichn].note) && (chnstate[ichn].idlecount >= 50))
-					{
-						chnstate[ichn].note = 0;
-						m[ichn].note = 0xFF;	// only if not drum channel ?
-					} else
-					if (chnstate[ichn].idlecount >= 500) // 20secs of inactivity
+				}
+			} else
+			{
+				// Load from Instrument or Sample file
+				InputFile f;
+
+				if(f.Open(pszMidiMapName))
+				{
+					FileReader insFile = GetFileReader(f);
+					if(insFile.IsValid())
 					{
-						chnstate[ichn].idlecount = 0;
-						chnstate[ichn].parent = 0;
+						ReadInstrumentFromFile(nIns, insFile, false);
+						mpt::PathString szName = pszMidiMapName.GetFullFileName();
+						pIns = Instruments[nIns];
+						if (!pIns->filename[0]) mpt::String::Copy(pIns->filename, szName.ToLocale().c_str());
+						if (!pIns->name[0])
+						{
+							if (nMidiCode < 128)
+							{
+								mpt::String::CopyN(pIns->name, szMidiProgramNames[nMidiCode]);
+							} else
+							{
+								uint32 nKey = nMidiCode & 0x7F;
+								if (nKey >= 24)
+									mpt::String::CopyN(pIns->name, szMidiPercussionNames[nKey - 24]);
+							}
+						}
 					}
 				}
 			}
-
-			if ((++row) >= Patterns[pat].GetNumRows())
-			{
-				pat++;
-				if (pat >= MAX_PATTERNS-1) break;
-				Order[pat] = pat;
-				Order[pat+1] = Order.GetInvalidPatIndex();
-				row = 0;
-			}
 		}
+	}
+#endif // MODPLUG_TRACKER
 
-		// Increase midi clock
-		midi_clock += nTickMultiplier;
-	} while (!(dwGlobalFlags & MIDIGLOBAL_SONGENDED));
-#ifdef MIDI_LOG
-	Log("\n------------------ End Of File ---------------------------\n\n");
-#endif
 	return true;
 }
 
-#else // !MODPLUG_TRACKER
+
+#else // !MODPLUG_TRACKER && !MPT_FUZZ_TRACKER
 
 bool CSoundFile::ReadMID(FileReader &/*file*/, ModLoadingFlags /*loadFlags*/)
 {
diff --git a/soundlib/Load_mo3.cpp b/soundlib/Load_mo3.cpp
index 3b3fe1c..10f55e4 100644
--- a/soundlib/Load_mo3.cpp
+++ b/soundlib/Load_mo3.cpp
@@ -2,8 +2,7 @@
  * Load_mo3.cpp
  * ------------
  * Purpose: MO3 module loader.
- * Notes  : OpenMPT has its own built-in decoder (enabled with MPT_ENABLE_MO3_BUILTIN),
- *          but can also make use of the official, closed-source library (unmo3.dll / libunmo3.so).
+ * Notes  : (currently none)
  * Authors: Johannes Schultz / OpenMPT Devs
  *          Based on documentation and the decompression routines from the
  *          open-source UNMO3 project (https://github.com/lclevy/unmo3).
@@ -17,7 +16,6 @@
 #include "Loaders.h"
 #include "../common/ComponentManager.h"
 
-#ifdef MPT_ENABLE_MO3_BUILTIN
 #include "Tables.h"
 #include "../common/version.h"
 
@@ -33,125 +31,22 @@
 
 #if defined(MPT_WITH_VORBISFILE)
 #include <vorbis/vorbisfile.h>
-#include "SampleFormatConverters.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
 #endif
 
 #ifdef MPT_WITH_STBVORBIS
 #include <stb_vorbis/stb_vorbis.c>
-#include "SampleFormatConverters.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
 #endif // MPT_WITH_STBVORBIS
 
-#endif // MPT_ENABLE_MO3_BUILTIN
-
-#if defined(MPT_WITH_UNMO3) || defined(MPT_ENABLE_UNMO3_DYNBIND)
-// unmo3.h
-#if MPT_OS_WINDOWS
-#define UNMO3_API __stdcall
-#else
-#define UNMO3_API
-#endif
-#if !defined(MPT_ENABLE_UNMO3_DYNBIND)
-extern "C" {
-OPENMPT_NAMESPACE::uint32 UNMO3_API UNMO3_GetVersion(void);
-void UNMO3_API UNMO3_Free(const void *data);
-OPENMPT_NAMESPACE::int32 UNMO3_API UNMO3_Decode(const void **data, OPENMPT_NAMESPACE::uint32 *len, OPENMPT_NAMESPACE::uint32 flags);
-}
-#endif // !MPT_ENABLE_UNMO3_DYNBIND
-#endif // MPT_WITH_UNMO3 || MPT_ENABLE_UNMO3_DYNBIND
-
 
 OPENMPT_NAMESPACE_BEGIN
 
 
-#if defined(MPT_WITH_UNMO3) || defined(MPT_ENABLE_UNMO3_DYNBIND)
-
-class ComponentUnMO3
-#if defined(MPT_WITH_UNMO3)
-	: public ComponentBuiltin
-#elif defined(MPT_ENABLE_UNMO3_DYNBIND)
-	: public ComponentLibrary
-#endif
-{
-	MPT_DECLARE_COMPONENT_MEMBERS
-private:
-#if MPT_OS_WINDOWS
-#if defined(MPT_WITH_UNMO3)
-#elif defined(MPT_ENABLE_UNMO3_DYNBIND)
-	mpt::Library MSVCRT;
-#endif // MPT_WITH_UNMO3 || MPT_ENABLE_UNMO3_DYNBIND
-#endif // MPT_OS_WINDOWS
-public:
-	uint32 (UNMO3_API * UNMO3_GetVersion)();
-	// Decode a MO3 file (returns the same "exit codes" as UNMO3.EXE, eg. 0=success)
-	// IN: data/len = MO3 data/len
-	// OUT: data/len = decoded data/len (if successful)
-	// flags & 1: Don't load samples
-	int32 (UNMO3_API * UNMO3_Decode_Old)(const void **data, uint32 *len);
-	int32 (UNMO3_API * UNMO3_Decode_New)(const void **data, uint32 *len, uint32 flags);
-	// Free the data returned by UNMO3_Decode
-	void (UNMO3_API * UNMO3_Free)(const void *data);
-	int32 UNMO3_Decode(const void **data, uint32 *len, uint32 flags)
-	{
-		return (UNMO3_Decode_New ? UNMO3_Decode_New(data, len, flags) : UNMO3_Decode_Old(data, len));
-	}
-public:
-	ComponentUnMO3()
-#if defined(MPT_WITH_UNMO3)
-		: ComponentBuiltin()
-#elif defined(MPT_ENABLE_UNMO3_DYNBIND)
-		: ComponentLibrary(ComponentTypeForeign)
-#endif
-	{
-		return;
-	}
-	bool DoInitialize()
-	{
-#if defined(MPT_WITH_UNMO3)
-		UNMO3_GetVersion = &(::UNMO3_GetVersion);
-		UNMO3_Free = &(::UNMO3_Free);
-		UNMO3_Decode_Old = nullptr;
-		UNMO3_Decode_New = &(::UNMO3_Decode);
-		return true;
-#elif defined(MPT_ENABLE_UNMO3_DYNBIND)
-		#if MPT_OS_WINDOWS
-			// preload MSVCRT.DLL in order to prevent DLL preloading injection attacks from the current working directory.
-			MSVCRT = mpt::Library(mpt::LibraryPath::System(MPT_PATHSTRING("MSVCRT")));
-			#if defined(LIBOPENMPT_BUILD)
-				// require successful dependency loading for libopenmpt
-				if(!MSVCRT.IsValid())
-				{
-					return false;
-				}
-			#endif // LIBOPENMPT_BUILD
-		#endif // MPT_OS_WINDOWS
-		AddLibrary("unmo3", mpt::LibraryPath::App(MPT_PATHSTRING("unmo3")));
-		MPT_COMPONENT_BIND("unmo3", UNMO3_Free);
-		if(MPT_COMPONENT_BIND_OPTIONAL("unmo3", UNMO3_GetVersion))
-		{
-			UNMO3_Decode_Old = nullptr;
-			MPT_COMPONENT_BIND_SYMBOL("unmo3", "UNMO3_Decode", UNMO3_Decode_New);
-		} else
-		{
-			// Old API version: No "flags" parameter.
-			UNMO3_Decode_New = nullptr;
-			MPT_COMPONENT_BIND_SYMBOL("unmo3", "UNMO3_Decode", UNMO3_Decode_Old);
-		}
-		return !HasBindFailed();
-#endif
-	}
-};
-MPT_REGISTERED_COMPONENT(ComponentUnMO3, "UnMO3")
-
-#endif // MPT_WITH_UNMO3 || MPT_ENABLE_UNMO3_DYNBIND
-
-
-#ifdef MPT_ENABLE_MO3_BUILTIN
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
 
-struct PACKED MO3FileHeader
+struct MO3FileHeader
 {
 	enum MO3HeaderFlags
 	{
@@ -174,41 +69,29 @@ struct PACKED MO3FileHeader
 		extFilterRange	= 0x200000,
 	};
 
-	uint8  numChannels;		// 1...64 (limited by channel panning and volume)
-	uint16 numOrders;
-	uint16 restartPos;
-	uint16 numPatterns;
-	uint16 numTracks;
-	uint16 numInstruments;
-	uint16 numSamples;
-	uint8  defaultSpeed;
-	uint8  defaultTempo;
-	uint32 flags;			// See MO3HeaderFlags
-	uint8  globalVol;		// 0...128 in IT, 0...64 in S3M
-	uint8  panSeparation;	// 0...128 in IT
-	int8   sampleVolume;	// Only used in IT
-	uint8  chnVolume[64];	// 0...64
-	uint8  chnPan[64];		// 0...256, 127 = surround
-	uint8  sfxMacros[16];
-	uint8  fixedMacros[128][2];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numOrders);
-		SwapBytesLE(restartPos);
-		SwapBytesLE(numPatterns);
-		SwapBytesLE(numTracks);
-		SwapBytesLE(numInstruments);
-		SwapBytesLE(numSamples);
-		SwapBytesLE(flags);
-	}
+	uint8le  numChannels;	// 1...64 (limited by channel panning and volume)
+	uint16le numOrders;
+	uint16le restartPos;
+	uint16le numPatterns;
+	uint16le numTracks;
+	uint16le numInstruments;
+	uint16le numSamples;
+	uint8le  defaultSpeed;
+	uint8le  defaultTempo;
+	uint32le flags;			// See MO3HeaderFlags
+	uint8le  globalVol;		// 0...128 in IT, 0...64 in S3M
+	uint8le  panSeparation;	// 0...128 in IT
+	int8le   sampleVolume;	// Only used in IT
+	uint8le  chnVolume[64];	// 0...64
+	uint8le  chnPan[64];	// 0...256, 127 = surround
+	uint8le  sfxMacros[16];
+	uint8le  fixedMacros[128][2];
 };
 
-STATIC_ASSERT(sizeof(MO3FileHeader) == 422);
+MPT_BINARY_STRUCT(MO3FileHeader, 422)
 
 
-struct PACKED MO3Envelope
+struct MO3Envelope
 {
 	enum MO3EnvelopeFlags
 	{
@@ -219,23 +102,13 @@ struct PACKED MO3Envelope
 		envCarry	= 0x20,
 	};
 
-	uint8 flags;			// See MO3EnvelopeFlags
-	uint8 numNodes;
-	uint8 sustainStart;
-	uint8 sustainEnd;
-	uint8 loopStart;
-	uint8 loopEnd;
-	int16 points[25][2];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(size_t i = 0; i < CountOf(points); i++)
-		{
-			SwapBytesLE(points[i][0]);
-			SwapBytesLE(points[i][1]);
-		}
-	}
+	uint8le flags;			// See MO3EnvelopeFlags
+	uint8le numNodes;
+	uint8le sustainStart;
+	uint8le sustainEnd;
+	uint8le loopStart;
+	uint8le loopEnd;
+	int16le points[25][2];
 
 	// Convert MO3 envelope data into OpenMPT's internal envelope format
 	void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envShift) const
@@ -260,10 +133,10 @@ struct PACKED MO3Envelope
 	}
 };
 
-STATIC_ASSERT(sizeof(MO3Envelope) == 106);
+MPT_BINARY_STRUCT(MO3Envelope, 106)
 
 
-struct PACKED MO3Instrument
+struct MO3Instrument
 {
 	enum MO3InstrumentFlags
 	{
@@ -271,52 +144,34 @@ struct PACKED MO3Instrument
 		mute		= 0x02,
 	};
 
-	uint32 flags;		// See MO3InstrumentFlags
-	uint16 sampleMap[120][2];
+	uint32le flags;		// See MO3InstrumentFlags
+	uint16le sampleMap[120][2];
 	MO3Envelope volEnv;
 	MO3Envelope panEnv;
 	MO3Envelope pitchEnv;
 	struct XMVibratoSettings
 	{
-		uint8  type;
-		uint8  sweep;
-		uint8  depth;
-		uint8  rate;
+		uint8le  type;
+		uint8le  sweep;
+		uint8le  depth;
+		uint8le  rate;
 	} vibrato;			// Applies to all samples of this instrument (XM)
-	uint16 fadeOut;
-	uint8  midiChannel;
-	uint8  midiBank;
-	uint8  midiPatch;
-	uint8  midiBend;
-	uint8  globalVol;	// 0...128
-	uint16 panning;		// 0...256 if enabled, 0xFFFF otherwise
-	uint8  nna;
-	uint8  pps;
-	uint8  ppc;
-	uint8  dct;
-	uint8  dca;
-	uint16 volSwing;	// 0...100
-	uint16 panSwing;	// 0...256
-	uint8  cutoff;		// 0...127, + 128 if enabled
-	uint8  resonance;	// 0...127, + 128 if enabled
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(size_t i = 0; i < CountOf(sampleMap); i++)
-		{
-			SwapBytesLE(sampleMap[i][0]);
-			SwapBytesLE(sampleMap[i][1]);
-		}
-
-		volEnv.ConvertEndianness();
-		panEnv.ConvertEndianness();
-		pitchEnv.ConvertEndianness();
-		SwapBytesLE(fadeOut);
-		SwapBytesLE(panning);
-		SwapBytesLE(volSwing);
-		SwapBytesLE(panSwing);
-	}
+	uint16le fadeOut;
+	uint8le  midiChannel;
+	uint8le  midiBank;
+	uint8le  midiPatch;
+	uint8le  midiBend;
+	uint8le  globalVol;	// 0...128
+	uint16le panning;	// 0...256 if enabled, 0xFFFF otherwise
+	uint8le  nna;
+	uint8le  pps;
+	uint8le  ppc;
+	uint8le  dct;
+	uint8le  dca;
+	uint16le volSwing;	// 0...100
+	uint16le panSwing;	// 0...256
+	uint8le  cutoff;	// 0...127, + 128 if enabled
+	uint8le  resonance;	// 0...127, + 128 if enabled
 
 	// Convert MO3 instrument data into OpenMPT's internal instrument format
 	void ConvertToMPT(ModInstrument &mptIns, MODTYPE type) const
@@ -349,14 +204,14 @@ struct PACKED MO3Instrument
 			mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
 		} else if(midiChannel > 0 && midiChannel < 17)
 		{
-			// IT with old encoder (yes, channel 0 is represented the same way as "no channel")
+			// IT encoded with MO3 version prior to 2.4.1 (yes, channel 0 is represented the same way as "no channel")
 			mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
 		}
 		mptIns.wMidiBank = midiBank;
 		mptIns.nMidiProgram = midiPatch;
 		mptIns.midiPWD =  midiBend;
 		if(type == MOD_TYPE_IT)
-			mptIns.nGlobalVol = std::min(globalVol, uint8(128)) / 2u;
+			mptIns.nGlobalVol = std::min<uint8>(globalVol, 128) / 2u;
 		if(panning <= 256)
 		{
 			mptIns.nPan = panning;
@@ -367,17 +222,17 @@ struct PACKED MO3Instrument
 		mptIns.nPPC = ppc;
 		mptIns.nDCT = dct;
 		mptIns.nDNA = dca;
-		mptIns.nVolSwing = static_cast<uint8>(std::min(volSwing, uint16(100)));
-		mptIns.nPanSwing = static_cast<uint8>(std::min(panSwing, uint16(256)) / 4u);
+		mptIns.nVolSwing = static_cast<uint8>(std::min<uint16>(volSwing, 100));
+		mptIns.nPanSwing = static_cast<uint8>(std::min<uint16>(panSwing, 256) / 4u);
 		mptIns.SetCutoff(cutoff & 0x7F, (cutoff & 0x80) != 0);
 		mptIns.SetResonance(resonance & 0x7F, (resonance & 0x80) != 0);
 	}
 };
 
-STATIC_ASSERT(sizeof(MO3Instrument) == 826);
+MPT_BINARY_STRUCT(MO3Instrument, 826)
 
 
-struct PACKED MO3Sample
+struct MO3Sample
 {
 	enum MO3SampleFlags
 	{
@@ -395,38 +250,23 @@ struct PACKED MO3Sample
 		smpCompressionMask	= 0x1000 | 0x2000 | 0x4000
 	};
 
-	int32  freqFinetune;	// Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM
-	int8   transpose;
-	uint8  defaultVolume;	// 0...64
-	uint16 panning;			// 0...256 if enabled, 0xFFFF otherwise
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint16 flags;			// See MO3SampleFlags
-	uint8  vibType;
-	uint8  vibSweep;
-	uint8  vibDepth;
-	uint8  vibRate;
-	uint8  globalVol;		// 0...64 in IT, in XM it represents the instrument number
-	uint32 sustainStart;
-	uint32 sustainEnd;
-	int32  compressedSize;
-	uint16 encoderDelay;	// MP3: Ignore first n bytes of decoded output. Ogg: Shared Ogg header size
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(freqFinetune);
-		SwapBytesLE(panning);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(flags);
-		SwapBytesLE(sustainStart);
-		SwapBytesLE(sustainEnd);
-		SwapBytesLE(compressedSize);
-		SwapBytesLE(encoderDelay);
-	}
+	int32le  freqFinetune;	// Frequency in S3M and IT, finetune (0...255) in MOD, MTM, XM
+	int8le   transpose;
+	uint8le  defaultVolume;	// 0...64
+	uint16le panning;		// 0...256 if enabled, 0xFFFF otherwise
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint16le flags;			// See MO3SampleFlags
+	uint8le  vibType;
+	uint8le  vibSweep;
+	uint8le  vibDepth;
+	uint8le  vibRate;
+	uint8le  globalVol;		// 0...64 in IT, in XM it represents the instrument number
+	uint32le sustainStart;
+	uint32le sustainEnd;
+	int32le  compressedSize;
+	uint16le encoderDelay;	// MP3: Ignore first n bytes of decoded output. Ogg: Shared Ogg header size
 
 	// Convert MO3 sample data into OpenMPT's internal instrument format
 	void ConvertToMPT(ModSample &mptSmp, MODTYPE type, bool frequencyIsHertz) const
@@ -444,7 +284,7 @@ struct PACKED MO3Sample
 			if(type != MOD_TYPE_MTM) mptSmp.nFineTune -= 128;
 			mptSmp.RelativeTone = transpose;
 		}
-		mptSmp.nVolume = std::min(defaultVolume, uint8(64)) * 4u;
+		mptSmp.nVolume = std::min<uint8>(defaultVolume, 64) * 4u;
 		if(panning <= 256)
 		{
 			mptSmp.nPan = panning;
@@ -464,18 +304,13 @@ struct PACKED MO3Sample
 		mptSmp.nVibRate = vibRate;
 
 		if(type == MOD_TYPE_IT)
-			mptSmp.nGlobalVol = std::min(globalVol, uint8(64));
+			mptSmp.nGlobalVol = std::min<uint8>(globalVol, 64);
 		mptSmp.nSustainStart = sustainStart;
 		mptSmp.nSustainEnd = sustainEnd;
 	}
 };
 
-STATIC_ASSERT(sizeof(MO3Sample) == 41);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(MO3Sample, 41)
 
 
 // We need all this information for Ogg-compressed samples with shared headers:
@@ -513,7 +348,7 @@ struct MO3SampleChunk
 
 // length coded within control stream:
 // most significant bit is 1
-// than the first bit of each bits pair (noted n1),
+// then the first bit of each bits pair (noted n1),
 // until second bit is 0 (noted n0)
 
 #define DECODE_CTRL_BITS \
@@ -527,7 +362,6 @@ struct MO3SampleChunk
 }
 
 static bool UnpackMO3Data(FileReader &file, uint8 *dst, uint32 size)
-//------------------------------------------------------------------
 {
 	if(!size)
 	{
@@ -557,7 +391,7 @@ static bool UnpackMO3Data(FileReader &file, uint8 *dst, uint32 size)
 		} else
 		{
 			// a 1 ctrl bit means compressed bytes are following
-			ebp = 0; // lenth adjustment
+			ebp = 0; // length adjustment
 			DECODE_CTRL_BITS; // read length, and if strLen > 3 (coded using more than 1 bits pair) also part of the offset value
 			strLen -=3;
 			if(strLen < 0)
@@ -618,7 +452,7 @@ static bool UnpackMO3Data(FileReader &file, uint8 *dst, uint32 size)
 	{
 		*dst++ = 0;
 	}
-#endif
+#endif // MPT_BUILD_FUZZER
 	return (dst - initDst) == static_cast<std::ptrdiff_t>(initSize);
 }
 
@@ -675,7 +509,6 @@ struct MO3Delta16BitParams
 
 template<typename Properties>
 static void UnpackMO3DeltaSample(FileReader &file, typename Properties::sample_t *dst, uint32 length, uint8 numChannels)
-//----------------------------------------------------------------------------------------------------------------------
 {
 	uint8 dh = Properties::dhInit, cl = 0;
 	int8 carry = 0;
@@ -722,7 +555,6 @@ static void UnpackMO3DeltaSample(FileReader &file, typename Properties::sample_t
 
 template<typename Properties>
 static void UnpackMO3DeltaPredictionSample(FileReader &file, typename Properties::sample_t *dst, uint32 length, uint8 numChannels)
-//--------------------------------------------------------------------------------------------------------------------------------
 {
 	uint8 dh = Properties::dhInit, cl = 0;
 	int8 carry;
@@ -856,114 +688,71 @@ static long VorbisfileFilereaderTell(void *datasource)
 #endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE
 
 
+struct MO3ContainerHeader
+{
+	char     magic[3];   // MO3
+	uint8le  version;
+	uint32le musicSize;
+};
 
-#endif // MPT_ENABLE_MO3_BUILTIN
-
+MPT_BINARY_STRUCT(MO3ContainerHeader, 8)
 
 
-bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MO3ContainerHeader &containerHeader)
 {
-	file.Rewind();
-
-	// No valid MO3 file (magic bytes: "MO3")
-	if(!file.CanRead(12) || !file.ReadMagic("MO3"))
+	if(std::memcmp(containerHeader.magic, "MO3", 3))
 	{
 		return false;
 	}
-	const uint8 version = file.ReadUint8();
-	const uint32 musicSize = file.ReadUint32LE();
-	if(musicSize <= 422 /*sizeof(MO3FileHeader)*/)
+	if(containerHeader.musicSize <= sizeof(MO3FileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
-	{
-		return true;
 	}
-
-#if !(defined(MPT_WITH_UNMO3) || defined(MPT_ENABLE_UNMO3_DYNBIND)) && !defined(MPT_ENABLE_MO3_BUILTIN)
-	// As of May 2016, the format revision is 5; Versions > 31 are unlikely to ever exist,
-	// so we will just ignore those if there's no UNMO3 library to tell us if the file is valid or not
-	// (avoid log entry with e.g. .MOD files that have a song name starting with "MO3").
-	if(version > 31)
+	if(containerHeader.version > 5)
 	{
 		return false;
 	}
+	return true;
+}
 
-	AddToLog(LogError, MPT_USTRING("The file appears to be a MO3 file, but this OpenMPT build does not support loading MO3 files."));
-	return false;
-
-#elif defined(MPT_WITH_UNMO3) || defined(MPT_ENABLE_UNMO3_DYNBIND)
-
-	MPT_UNUSED_VARIABLE(version);
-
-	bool shouldUseUnmo3 = true;
-#ifdef MPT_ENABLE_MO3_BUILTIN
-	shouldUseUnmo3 = !CanReadMP3() || !CanReadVorbis();
-#endif // MPT_ENABLE_MO3_BUILTIN
 
-	if(shouldUseUnmo3)
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize)
+{
+	MO3ContainerHeader containerHeader;
+	if(!file.ReadStruct(containerHeader))
 	{
-	// Try to load unmo3 dynamically.
-	ComponentHandle<ComponentUnMO3> unmo3;
-	if(IsComponentAvailable(unmo3))
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(containerHeader))
 	{
-		file.Rewind();
-		FileReader::PinnedRawDataView fileView = file.GetPinnedRawDataView();
-		const void *stream = mpt::void_cast<const void*>(fileView.data());
-		uint32 length = mpt::saturate_cast<uint32>(fileView.size());
-
-		if(unmo3->UNMO3_Decode(&stream, &length, (loadFlags & loadSampleData) ? 0 : 1) != 0)
-		{
-			return false;
-		}
-
-		fileView.invalidate();
-
-		// If decoding was successful, stream and length will keep the new pointers now.
-		FileReader unpackedFile(mpt::as_span(mpt::void_cast<const mpt::byte*>(stream), length));
-
-		bool result = false;	// Result of trying to load the module, false == fail.
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
 
-		result = ReadXM(unpackedFile, loadFlags)
-			|| ReadIT(unpackedFile, loadFlags)
-			|| ReadS3M(unpackedFile, loadFlags)
-			|| ReadMTM(unpackedFile, loadFlags)
-			|| ReadMod(unpackedFile, loadFlags)
-			|| ReadM15(unpackedFile, loadFlags);
-		if(result)
-		{
-			#ifdef MODPLUG_TRACKER
-				AddToLog(LogNotification, MPT_USTRING("Loading MO3 file used Un4seen unmo3."));
-			#else
-				AddToLog(LogWarning, MPT_USTRING("Loading MO3 file used Un4seen unmo3. Un4seen unmo3 support is deprecated in libopenmpt and will be removed in favour of the built-in decoder on 2018-01-01."));
-			#endif
-			m_ContainerType = MOD_CONTAINERTYPE_MO3;
-		}
 
-		unmo3->UNMO3_Free(stream);
+bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
 
-		if(result)
-		{
-			return true;
-		}
-	} else
+	MO3ContainerHeader containerHeader;
+	if(!file.ReadStruct(containerHeader))
 	{
-		#ifndef MPT_ENABLE_MO3_BUILTIN
-			AddToLog(LogError, MPT_USTRING("Loading MO3 file failed because the unmo3 library could not be loaded."));
-			return false;
-		#endif // MPT_ENABLE_MO3_BUILTIN
-	}
+		return false;
 	}
-
-#endif
-
-#ifdef MPT_ENABLE_MO3_BUILTIN
-
-	if(version > 5)
+	if(!ValidateHeader(containerHeader))
 	{
 		return false;
 	}
+	if(loadFlags == onlyVerifyHeader)
+	{
+		return true;
+	}
+
+	const uint8 version = containerHeader.version;
+	const uint32 musicSize = containerHeader.musicSize;
+
 	uint32 compressedSize = uint32_max;
 	if(version >= 5)
 	{
@@ -974,12 +763,12 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		{
 			return false;
 		}
-#endif // MPT_BUILD_FUZZER
+#endif // !MPT_BUILD_FUZZER
 	}
 
 	std::vector<uint8> musicData(musicSize);
 
-	if(!UnpackMO3Data(file, &musicData[0], musicSize))
+	if(!UnpackMO3Data(file, musicData.data(), musicSize))
 	{
 		return false;
 	}
@@ -996,7 +785,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 	musicChunk.ReadNullString(m_songMessage);
 
 	MO3FileHeader fileHeader;
-	if(!musicChunk.ReadConvertEndianness(fileHeader)
+	if(!musicChunk.ReadStruct(fileHeader)
 		|| fileHeader.numChannels == 0 || fileHeader.numChannels > MAX_BASECHANNELS
 		|| fileHeader.numInstruments >= MAX_INSTRUMENTS
 		|| fileHeader.numSamples >= MAX_SAMPLES)
@@ -1005,7 +794,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	m_nChannels = fileHeader.numChannels;
-	Order.SetRestartPos(fileHeader.restartPos);
+	Order().SetRestartPos(fileHeader.restartPos);
 	m_nInstruments = fileHeader.numInstruments;
 	m_nSamples = fileHeader.numSamples;
 	m_nDefaultSpeed = fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6;
@@ -1053,7 +842,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 	for(CHANNELINDEX i = 0; i < headerChannels; i++)
 	{
 		if(m_nType == MOD_TYPE_IT)
-			ChnSettings[i].nVolume = std::min(fileHeader.chnVolume[i], uint8(64));
+			ChnSettings[i].nVolume = std::min<uint8>(fileHeader.chnVolume[i], 64);
 		if(m_nType != MOD_TYPE_XM)
 		{
 			if(fileHeader.chnPan[i] == 127)
@@ -1089,24 +878,23 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		for(uint32 i = 0; i < 128; i++)
 		{
 			if(fileHeader.fixedMacros[i][1])
-				sprintf(m_MidiCfg.szMidiZXXExt[i], "F0F0%02X%02X", fileHeader.fixedMacros[i][1] - 1, fileHeader.fixedMacros[i][0]);
+				sprintf(m_MidiCfg.szMidiZXXExt[i], "F0F0%02X%02X", fileHeader.fixedMacros[i][1] - 1, fileHeader.fixedMacros[i][0].get());
 			else
 				strcpy(m_MidiCfg.szMidiZXXExt[i], "");
 		}
-		m_SongFlags.set(SONG_EMBEDMIDICFG, !m_MidiCfg.IsMacroDefaultSetupUsed());
 	}
 
-	Order.ReadAsByte(musicChunk, fileHeader.numOrders, fileHeader.numOrders, 0xFF, 0xFE);
+	ReadOrderFromFile<uint8>(Order(), musicChunk, fileHeader.numOrders, 0xFF, 0xFE);
 
 	// Track assignments for all patterns
 	FileReader trackChunk = musicChunk.ReadChunk(fileHeader.numPatterns * fileHeader.numChannels * sizeof(uint16));
 	FileReader patLengthChunk = musicChunk.ReadChunk(fileHeader.numPatterns * sizeof(uint16));
 	std::vector<FileReader> tracks(fileHeader.numTracks);
 
-	for(uint32 track = 0; track < fileHeader.numTracks; track++)
+	for(auto &track : tracks)
 	{
 		uint32 len = musicChunk.ReadUint32LE();
-		tracks[track] = musicChunk.ReadChunk(len);
+		track = musicChunk.ReadChunk(len);
 	}
 
 	/*
@@ -1195,6 +983,10 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		noteOffset = 13 + NOTE_MIN;
 	else if(m_nType != MOD_TYPE_IT)
 		noteOffset = 12 + NOTE_MIN;
+	bool onlyAmigaNotes = true;
+
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.numPatterns);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
 	{
 		const ROWINDEX numRows = patLengthChunk.ReadUint16LE();
@@ -1233,6 +1025,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 						else if(m.note == 0xFF) m.note = NOTE_KEYOFF;
 						else if(m.note == 0xFE) m.note = NOTE_NOTECUT;
 						else m.note = NOTE_FADE;
+						if(!m.IsAmigaNote()) onlyAmigaNotes = false;
 						break;
 					case 0x02:
 						// Instrument
@@ -1423,6 +1216,11 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		}
 	}
 
+	if(GetType() == MOD_TYPE_MOD && GetNumChannels() == 4 && onlyAmigaNotes)
+	{
+		m_SongFlags.set(SONG_AMIGALIMITS | SONG_ISAMIGA);
+	}
+
 	const bool isSampleMode = (m_nType != MOD_TYPE_XM && !(fileHeader.flags & MO3FileHeader::instrumentMode));
 	std::vector<MO3Instrument::XMVibratoSettings> instrVibrato(m_nType == MOD_TYPE_XM ? m_nInstruments : 0);
 	for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++)
@@ -1450,7 +1248,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		}
 
 		MO3Instrument insHeader;
-		if(!musicChunk.ReadConvertEndianness(insHeader))
+		if(!musicChunk.ReadStruct(insHeader))
 			break;
 		insHeader.ConvertToMPT(*pIns, m_nType);
 
@@ -1477,7 +1275,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		}
 
 		MO3Sample smpHeader;
-		if(!musicChunk.ReadConvertEndianness(smpHeader))
+		if(!musicChunk.ReadStruct(smpHeader))
 			break;
 		smpHeader.ConvertToMPT(sample, m_nType, frequencyIsHertz);
 
@@ -1633,7 +1431,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 				streamSerials.clear();
 				while(Ogg::ReadPageAndSkipJunk(sharedChunk, oggPageInfo, oggPageData))
 				{
-					std::vector<uint32>::iterator it = std::find(streamSerials.begin(), streamSerials.end(), read_unaligned_field(oggPageInfo.header.bitstream_serial_number));
+					auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number);
 					if(it == streamSerials.end())
 					{
 						streamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
@@ -1648,7 +1446,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 				streamSerials.clear();
 				while(Ogg::ReadPageAndSkipJunk(sampleChunk.chunk, oggPageInfo, oggPageData))
 				{
-					std::vector<uint32>::iterator it = std::find(streamSerials.begin(), streamSerials.end(), read_unaligned_field(oggPageInfo.header.bitstream_serial_number));
+					auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number);
 					if(it == streamSerials.end())
 					{
 						streamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
@@ -1684,10 +1482,10 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 				dataStreamSerials.clear();
 				while(Ogg::ReadPageAndSkipJunk(sampleChunk.chunk, oggPageInfo, oggPageData))
 				{
-					std::vector<uint32>::iterator it = std::find(dataStreamSerials.begin(), dataStreamSerials.end(), read_unaligned_field(oggPageInfo.header.bitstream_serial_number));
+					auto it = std::find(dataStreamSerials.begin(), dataStreamSerials.end(), oggPageInfo.header.bitstream_serial_number);
 					if(it == dataStreamSerials.end())
 					{
-						dataStreamSerials.push_back(read_unaligned_field(oggPageInfo.header.bitstream_serial_number));
+						dataStreamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
 					}
 				}
 
@@ -1695,10 +1493,10 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 				headStreamSerials.clear();
 				while(Ogg::ReadPageAndSkipJunk(sharedChunk, oggPageInfo, oggPageData))
 				{
-					std::vector<uint32>::iterator it = std::find(headStreamSerials.begin(), headStreamSerials.end(), read_unaligned_field(oggPageInfo.header.bitstream_serial_number));
+					auto it = std::find(headStreamSerials.begin(), headStreamSerials.end(), oggPageInfo.header.bitstream_serial_number);
 					if(it == headStreamSerials.end())
 					{
-						headStreamSerials.push_back(read_unaligned_field(oggPageInfo.header.bitstream_serial_number));
+						headStreamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
 						it = headStreamSerials.begin() + (headStreamSerials.size() - 1);
 					}
 					uint32 newSerial = 0;
@@ -1712,7 +1510,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 						std::size_t extraIndex = (it - headStreamSerials.begin()) - dataStreamSerials.size();
 						for(newSerial = 1; newSerial < 0xffffffffu; ++newSerial)
 						{
-							std::vector<uint32>::iterator dss = std::find(dataStreamSerials.begin(), dataStreamSerials.end(), newSerial);
+							auto dss = std::find(dataStreamSerials.begin(), dataStreamSerials.end(), newSerial);
 							if(dss == dataStreamSerials.end())
 							{
 								extraIndex -= 1;
@@ -1758,7 +1556,9 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 
 			FileReader &sampleData = sampleChunk.chunk;
 			FileReader &headerChunk = sharedHeader ? sampleChunks[sharedOggHeader - 1].chunk : sampleData;
+#if defined(MPT_WITH_STBVORBIS)
 			int initialRead = sharedHeader ? sampleChunk.headerSize : headerChunk.GetLength();
+#endif // MPT_WITH_STBVORBIS
 
 #endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE
 
@@ -1968,12 +1768,12 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 				cwtv = chunk.ReadUint16LE();
 				break;
 			case MOD_TYPE_XM:
-				chunk.ReadString<mpt::String::spacePadded>(m_madeWithTracker, std::min(FileReader::off_t(32), chunk.GetLength()));
+				chunk.ReadString<mpt::String::spacePadded>(m_madeWithTracker, mpt::CharsetCP437, std::min(FileReader::off_t(32), chunk.GetLength()));
 				break;
 			case MOD_TYPE_MTM:
 				{
 					uint8 mtmVersion = chunk.ReadUint8();
-					m_madeWithTracker = mpt::String::Print("MultiTracker %1.%2", mtmVersion >> 4, mtmVersion & 0x0F);
+					m_madeWithTracker = mpt::format(MPT_USTRING("MultiTracker %1.%2"))(mtmVersion >> 4, mtmVersion & 0x0F);
 				}
 				break;
 			default:
@@ -2021,7 +1821,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 
 			if(m_dwLastSavedWithVersion)
 			{
-				m_madeWithTracker = "OpenMPT " + MptVersion::ToStr(m_dwLastSavedWithVersion);
+				m_madeWithTracker = MPT_USTRING("OpenMPT ") + MptVersion::ToUString(m_dwLastSavedWithVersion);
 			}
 			break;
 		}
@@ -2032,15 +1832,13 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 		|| (GetType() == MOD_TYPE_S3M && cwtv >= 0x1300 && cwtv < 0x1320))
 	{
 		// Ignore MIDI data in files made with IT older than version 2.14 and old ST3 versions.
-		MemsetZero(m_MidiCfg.szMidiSFXExt);
-		MemsetZero(m_MidiCfg.szMidiZXXExt);
-		m_SongFlags.set(SONG_EMBEDMIDICFG);
+		m_MidiCfg.ClearZxxMacros();
 	}
 
 	if(m_madeWithTracker.empty())
-		m_madeWithTracker = mpt::String::Print("MO3 v%1", version);
+		m_madeWithTracker = mpt::format(MPT_USTRING("MO3 v%1"))(version);
 	else
-		m_madeWithTracker = mpt::String::Print("MO3 v%1 (%2)", version, m_madeWithTracker);
+		m_madeWithTracker = mpt::format(MPT_USTRING("MO3 v%1 (%2)"))(version, m_madeWithTracker);
 
 	if(unsupportedSamples)
 	{
@@ -2048,9 +1846,6 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	return true;
-#else
-	return false;
-#endif // MPT_ENABLE_MO3_BUILTIN
 }
 
 
diff --git a/soundlib/Load_mod.cpp b/soundlib/Load_mod.cpp
index 05dfa28..c8cd8b3 100644
--- a/soundlib/Load_mod.cpp
+++ b/soundlib/Load_mod.cpp
@@ -2,7 +2,8 @@
  * Load_mod.cpp
  * ------------
  * Purpose: MOD / NST (ProTracker / NoiseTracker), M15 / STK (Ultimate Soundtracker / Soundtracker) and ST26 (SoundTracker 2.6 / Ice Tracker) module loader / saver
- * Notes  : (currently none)
+ * Notes  : "2000 LOC for processing MOD files?!" you say? Well, this file also contains loaders for some formats that are almost identical to MOD, and extensive
+ *          heuristics for more or less broken MOD files and files saved with tons of different trackers, to allow for the most optimal playback.
  * Authors: Olivier Lapicque
  *          OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
@@ -15,11 +16,14 @@
 #ifndef MODPLUG_NO_FILESAVE
 #include "../common/mptFileIO.h"
 #endif
+#ifdef MPT_EXTERNAL_SAMPLES
+// For loading external data in Startrekker files
+#include "../common/mptPathString.h"
+#endif // MPT_EXTERNAL_SAMPLES
 
 OPENMPT_NAMESPACE_BEGIN
 
 void CSoundFile::ConvertModCommand(ModCommand &m)
-//-----------------------------------------------
 {
 	switch(m.command)
 	{
@@ -72,7 +76,6 @@ void CSoundFile::ConvertModCommand(ModCommand &m)
 #ifndef MODPLUG_NO_FILESAVE
 
 void CSoundFile::ModSaveCommand(uint8 &command, uint8 &param, bool toXM, bool compatibilityExport) const
-//------------------------------------------------------------------------------------------------------
 {
 	switch(command)
 	{
@@ -198,39 +201,27 @@ void CSoundFile::ModSaveCommand(uint8 &command, uint8 &param, bool toXM, bool co
 
 #endif // MODPLUG_NO_FILESAVE
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 
 // File Header
-struct PACKED MODFileHeader
+struct MODFileHeader
 {
-	uint8 numOrders;
-	uint8 restartPos;
-	uint8 orderList[128];
+	uint8be numOrders;
+	uint8be restartPos;
+	uint8be orderList[128];
 };
 
-STATIC_ASSERT(sizeof(MODFileHeader) == 130);
+MPT_BINARY_STRUCT(MODFileHeader, 130)
 
 
 // Sample Header
-struct PACKED MODSampleHeader
+struct MODSampleHeader
 {
-	char   name[22];
-	uint16 length;
-	uint8  finetune;
-	uint8  volume;
-	uint16 loopStart;
-	uint16 loopLength;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(length);
-		SwapBytesBE(loopStart);
-		SwapBytesBE(loopLength);
-	}
+	char     name[22];
+	uint16be length;
+	uint8be  finetune;
+	uint8be  volume;
+	uint16be loopStart;
+	uint16be loopLength;
 
 	// Convert an MOD sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp, bool is4Chn) const
@@ -238,7 +229,7 @@ struct PACKED MODSampleHeader
 		mptSmp.Initialize(MOD_TYPE_MOD);
 		mptSmp.nLength = length * 2;
 		mptSmp.nFineTune = MOD2XMFineTune(finetune & 0x0F);
-		mptSmp.nVolume = 4 * MIN(volume, 64);
+		mptSmp.nVolume = 4u * std::min<uint8>(volume, 64);
 
 		SmpLength lStart = loopStart * 2;
 		SmpLength lLength = loopLength * 2;
@@ -334,9 +325,117 @@ struct PACKED MODSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(MODSampleHeader) == 30);
+MPT_BINARY_STRUCT(MODSampleHeader, 30)
 
-struct PACKED PT36IffChunk
+// Synthesized StarTrekker instruments
+struct AMInstrument
+{
+	char     am[2];			// "AM"
+	char     zero[4];
+	uint16be startLevel;	// Start level
+	uint16be attack1Level;	// Attack 1 level
+	uint16be attack1Speed;	// Attack 1 speed
+	uint16be attack2Level;	// Attack 2 level
+	uint16be attack2Speed;	// Attack 2 speed
+	uint16be sustainLevel;	// Sustain level
+	uint16be decaySpeed;	// Decay speed
+	uint16be sustainTime;	// Sustain time
+	uint16be nt;			// ?
+	uint16be releaseSpeed;	// Release speed
+	uint16be waveform;		// Waveform
+	int16be  pitchFall;		// Pitch fall
+	uint16be vibAmp;		// Vibrato amplitude
+	uint16be vibSpeed;		// Vibrato speed
+	uint16be octave;		// Base frequency
+
+	void ConvertToMPT(ModSample &sample, ModInstrument &ins, mpt::fast_prng &rng) const
+	{
+		sample.nLength = waveform == 3 ? 1024 : 32;
+		sample.nLoopStart = 0;
+		sample.nLoopEnd = sample.nLength;
+		sample.uFlags.set(CHN_LOOP);
+		sample.nVolume = 256;	// prelude.mod has volume 0 in sample header
+		sample.nVibDepth = mpt::saturate_cast<uint8>(vibAmp * 2);
+		sample.nVibRate = static_cast<uint8>(vibSpeed);
+		sample.nVibType = VIB_SINE;
+		sample.RelativeTone = static_cast<int8>(-12 * octave);
+		if(sample.AllocateSample())
+		{
+			for(SmpLength i = 0; i < sample.nLength; i++)
+			{
+				switch(waveform)
+				{
+				default:
+				case 0: sample.pSample8[i] = ModSinusTable[i * 2];				break;	// Sine
+				case 1: sample.pSample8[i] = static_cast<int8>(-128 + i * 8);	break;	// Saw
+				case 2: sample.pSample8[i] = i < 16 ? -128 : 127;				break;	// Square
+				case 3: sample.pSample8[i] = mpt::random<int8>(rng);			break;	// Noise
+				}
+			}
+		}
+
+		InstrumentEnvelope &volEnv = ins.VolEnv;
+		volEnv.dwFlags.set(ENV_ENABLED);
+		volEnv.reserve(6);
+		volEnv.push_back(0, static_cast<EnvelopeNode::value_t>(startLevel / 4));
+
+		const struct
+		{
+			uint16 level, speed;
+		} points[] = { { startLevel, 0 }, { attack1Level, attack1Speed }, { attack2Level, attack2Speed }, { sustainLevel, decaySpeed }, { sustainLevel, sustainTime }, { 0, releaseSpeed } };
+
+		for(uint8 i = 1; i < CountOf(points); i++)
+		{
+			int duration = std::min(points[i].speed, uint16(256));
+			// Sustain time is already in ticks, no need to compute the segment duration.
+			if(i != 4)
+			{
+				if(duration == 0)
+				{
+					volEnv.dwFlags.set(ENV_LOOP);
+					volEnv.nLoopStart = volEnv.nLoopEnd = static_cast<uint8>(volEnv.size() - 1);
+					break;
+				}
+
+				// Startrekker increments / decrements the envelope level by the stage speed
+				// until it reaches the next stage level.
+				int a, b;
+				if(points[i].level > points[i - 1].level)
+				{
+					a = points[i].level - points[i - 1].level;
+					b = 256 - points[i - 1].level;
+				} else
+				{
+					a = points[i - 1].level - points[i].level;
+					b = points[i - 1].level;
+				}
+				// Release time is again special.
+				if(i == 5)
+					b = 256;
+				else if(b == 0)
+					b = 1;
+				duration = std::max((256 * a) / (duration * b), 1);
+			}
+			if(duration > 0)
+			{
+				volEnv.push_back(volEnv.back().tick + static_cast<EnvelopeNode::tick_t>(duration), static_cast<EnvelopeNode::value_t>(points[i].level / 4));
+			}
+		}
+
+		if(pitchFall)
+		{
+			InstrumentEnvelope &pitchEnv = ins.PitchEnv;
+			pitchEnv.dwFlags.set(ENV_ENABLED);
+			pitchEnv.reserve(2);
+			pitchEnv.push_back(0, ENVELOPE_MID);
+			pitchEnv.push_back(static_cast<EnvelopeNode::tick_t>(1024 / abs(pitchFall)), pitchFall > 0 ? ENVELOPE_MIN : ENVELOPE_MAX);
+		}
+	}
+};
+
+MPT_BINARY_STRUCT(AMInstrument, 36)
+
+struct PT36IffChunk
 {
 	// IFF chunk names
 	enum ChunkIdentifiers
@@ -347,100 +446,66 @@ struct PACKED PT36IffChunk
 		idPTDT	= MAGIC4BE('P','T','D','T'),
 	};
 
-	uint32 signature;	// IFF chunk name
-	uint32 chunksize;	// chunk size without header
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(signature);
-		SwapBytesBE(chunksize);
-	}
+	uint32be signature;	// IFF chunk name
+	uint32be chunksize;	// chunk size without header
 };
 
-STATIC_ASSERT(sizeof(PT36IffChunk) == 8);
+MPT_BINARY_STRUCT(PT36IffChunk, 8)
 
-struct PACKED PT36InfoChunk
+struct PT36InfoChunk
 {
-	char name[32];
-	uint16 numSamples;
-	uint16 numOrders;
-	uint16 numPatterns;
-	uint16 volume;
-	uint16 tempo;
-	uint16 flags;
-	uint16 dateDay;
-	uint16 dateMonth;
-	uint16 dateYear;
-	uint16 dateHour;
-	uint16 dateMinute;
-	uint16 dateSecond;
-	uint16 playtimeHour;
-	uint16 playtimeMinute;
-	uint16 playtimeSecond;
-	uint16 playtimeMsecond;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(numSamples);
-		SwapBytesBE(numOrders);
-		SwapBytesBE(numPatterns);
-		SwapBytesBE(volume);
-		SwapBytesBE(tempo);
-		SwapBytesBE(flags);
-		SwapBytesBE(dateDay);
-		SwapBytesBE(dateMonth);
-		SwapBytesBE(dateYear);
-		SwapBytesBE(dateHour);
-		SwapBytesBE(dateMinute);
-		SwapBytesBE(dateSecond);
-		SwapBytesBE(playtimeHour);
-		SwapBytesBE(playtimeMinute);
-		SwapBytesBE(playtimeSecond);
-		SwapBytesBE(playtimeMsecond);
-	}
+	char     name[32];
+	uint16be numSamples;
+	uint16be numOrders;
+	uint16be numPatterns;
+	uint16be volume;
+	uint16be tempo;
+	uint16be flags;
+	uint16be dateDay;
+	uint16be dateMonth;
+	uint16be dateYear;
+	uint16be dateHour;
+	uint16be dateMinute;
+	uint16be dateSecond;
+	uint16be playtimeHour;
+	uint16be playtimeMinute;
+	uint16be playtimeSecond;
+	uint16be playtimeMsecond;
 };
 
-STATIC_ASSERT(sizeof(PT36InfoChunk) == 64);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(PT36InfoChunk, 64)
 
 
 // Check if header magic equals a given string.
 static bool IsMagic(const char *magic1, const char *magic2)
-//---------------------------------------------------------
 {
 	return std::memcmp(magic1, magic2, 4) == 0;
 }
 
 
 static uint32 ReadSample(FileReader &file, MODSampleHeader &sampleHeader, ModSample &sample, char (&sampleName)[MAX_SAMPLENAME], bool is4Chn)
-//-------------------------------------------------------------------------------------------------------------------------------------------
 {
-	file.ReadConvertEndianness(sampleHeader);
+	file.ReadStruct(sampleHeader);
 	sampleHeader.ConvertToMPT(sample, is4Chn);
 
 	mpt::String::Read<mpt::String::spacePadded>(sampleName, sampleHeader.name);
 	// Get rid of weird characters in sample names.
-	uint32 invalidChars = 0;
-	for(uint32 i = 0; i < CountOf(sampleName); i++)
+	for(auto &c : sampleName)
 	{
-		if(sampleName[i] > 0 && sampleName[i] < ' ')
+		if(c > 0 && c < ' ')
 		{
-			sampleName[i] = ' ';
-			invalidChars++;
+			c = ' ';
 		}
 	}
-	return invalidChars;
+	// Check for invalid values
+	return ((sampleHeader.volume > 64) ? 1 : 0)
+		+ ((sampleHeader.finetune > 15) ? 1 : 0)
+		+ ((sampleHeader.loopStart > sampleHeader.length * 2) ? 1 : 0);
 }
 
 
 // Parse the order list to determine how many patterns are used in the file.
 static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERINDEX numOrders, SmpLength totalSampleLen, CHANNELINDEX &numChannels, bool checkForWOW)
-//-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	PATTERNINDEX numPatterns = 0;			// Total number of patterns in file (determined by going through the whole order list) with pattern number < 128
 	PATTERNINDEX officialPatterns = 0;		// Number of patterns only found in the "official" part of the order list (i.e. order positions < claimed order length)
@@ -463,11 +528,8 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN
 		}
 	}
 
-	// Fill order tail with stop patterns, now that we don't need the garbage in there anymore.
-	for(ORDERINDEX ord = numOrders; ord < 128; ord++)
-	{
-		Order[ord] = Order.GetInvalidPatIndex();
-	}
+	// Remove the garbage patterns past the official order end now that we don't need them anymore.
+	Order.resize(numOrders);
 
 	const size_t patternStartOffset = file.GetPosition();
 	const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset;
@@ -543,7 +605,6 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN
 
 
 void CSoundFile::ReadMODPatternEntry(FileReader &file, ModCommand &m)
-//-------------------------------------------------------------------
 {
 	uint8 data[4];
 	file.ReadArray(data);
@@ -552,7 +613,6 @@ void CSoundFile::ReadMODPatternEntry(FileReader &file, ModCommand &m)
 
 
 void CSoundFile::ReadMODPatternEntry(const uint8 (&data)[4], ModCommand &m)
-//-------------------------------------------------------------------------
 {
 	// Read Period
 	uint16 period = (((static_cast<uint16>(data[0]) & 0x0F) << 8) | data[1]);
@@ -587,83 +647,165 @@ void CSoundFile::ReadMODPatternEntry(const uint8 (&data)[4], ModCommand &m)
 }
 
 
-bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct MODMagicResult
 {
-	char magic[4];
-	if(!file.Seek(1080) || !file.ReadArray(magic))
-	{
-		return false;
-	}
+	CHANNELINDEX m_nChannels       = 4;
+	mpt::ustring m_madeWithTracker = mpt::ustring();
+	bool isNoiseTracker            = false;
+	bool isStartrekker             = false;
+	bool isGenericMultiChannel     = false;
+	bool setMODVBlankTiming        = false;
+};
 
-	InitializeGlobals(MOD_TYPE_MOD);
-	m_nChannels = 4;
-	bool isNoiseTracker = false;
 
-	// Check MOD Magic
+static bool CheckMODMagic(const char magic[4], MODMagicResult *result)
+{
+	MODMagicResult *r = result;
 	if(IsMagic(magic, "M.K.")		// ProTracker and compatible
 		|| IsMagic(magic, "M!K!")	// ProTracker (>64 patterns)
 		|| IsMagic(magic, "PATT")	// ProTracker 3.6
 		|| IsMagic(magic, "NSMS")	// kingdomofpleasure.mod by bee hunter
 		|| IsMagic(magic, "LARD"))	// judgement_day_gvine.mod by 4-mat
 	{
-		m_nChannels = 4;
+		if(r)
+		{
+			r->m_nChannels = 4;
+			r->m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+		}
 	} else if(IsMagic(magic, "M&K!")	// "His Master's Noise" musicdisk
 		|| IsMagic(magic, "FEST")		// "His Master's Noise" musicdisk
 		|| IsMagic(magic, "N.T."))
 	{
-		m_nChannels = 4;
-		m_madeWithTracker = "NoiseTracker";
-		isNoiseTracker = true;
+		if(r)
+		{
+			r->m_nChannels = 4;
+			r->m_madeWithTracker = MPT_USTRING("NoiseTracker");
+			r->isNoiseTracker = true;
+		}
 	} else if(IsMagic(magic, "OKTA")
 		|| IsMagic(magic, "OCTA"))
 	{
 		// Oktalyzer
-		m_nChannels = 8;
-		m_madeWithTracker = "Oktalyzer";
+		if(r)
+		{
+			r->m_nChannels = 8;
+			r->m_madeWithTracker = MPT_USTRING("Oktalyzer");
+		}
 	} else if(IsMagic(magic, "CD81")
 		|| IsMagic(magic, "CD61"))
 	{
 		// Octalyser on Atari STe/Falcon
-		m_nChannels = magic[2] - '0';
-		m_madeWithTracker = "Octalyser (Atari)";
+		if(r)
+		{
+			r->m_nChannels = magic[2] - '0';
+			r->m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+		}
 	} else if(!memcmp(magic, "FA0", 3) && magic[3] >= '4' && magic[3] <= '8')
 	{
 		// Digital Tracker on Atari Falcon
-		m_nChannels = magic[3] - '0';
-		m_madeWithTracker = "Digital Tracker";
+		if(r)
+		{
+			r->m_nChannels = magic[3] - '0';
+			r->m_madeWithTracker = MPT_USTRING("Digital Tracker");
+		}
 	} else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && magic[3] >= '4' && magic[3] <= '9')
 	{
 		// FLTx / EXOx - Startrekker by Exolon / Fairlight
-		m_nChannels = magic[3] - '0';
-		m_madeWithTracker = "Startrekker";
+		if(r)
+		{
+			r->m_nChannels = magic[3] - '0';
+			r->m_madeWithTracker = MPT_USTRING("Startrekker");
+			r->isStartrekker = true;
+			r->setMODVBlankTiming = true;
+		}
 	} else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3))
 	{
 		// xCHN - Many trackers
-		m_nChannels = magic[0] - '0';
+		if(r)
+		{
+			r->m_nChannels = magic[0] - '0';
+			r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+			r->isGenericMultiChannel = true;
+		}
 	} else if(magic[0] >= '1' && magic[0] <= '9' && magic[1]>='0' && magic[1] <= '9'
 		&& (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2)))
 	{
 		// xxCN / xxCH - Many trackers
-		m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
+		if(r)
+		{
+			r->m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
+			r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+			r->isGenericMultiChannel = true;
+		}
 	} else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '4' && magic[3] <= '9')
 	{
 		// TDZx - TakeTracker
-		m_nChannels = magic[3] - '0';
-		m_madeWithTracker = "TakeTracker";
+		if(r)
+		{
+			r->m_nChannels = magic[3] - '0';
+			r->m_madeWithTracker = MPT_USTRING("TakeTracker");
+		}
 	} else
 	{
 		return false;
 	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize)
+{
+	if(!file.CanRead(1080 + 4))
+	{
+		return ProbeWantMoreData;
+	}
+	file.Seek(1080);
+	char magic[4];
+	file.ReadArray(magic);
+	if(!CheckMODMagic(magic, nullptr))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
+{
+	char magic[4];
+	if(!file.Seek(1080) || !file.ReadArray(magic))
+	{
+		return false;
+	}
+
+	InitializeGlobals(MOD_TYPE_MOD);
+
+	MODMagicResult modMagicResult;
+	if(!CheckMODMagic(magic, &modMagicResult))
+	{
+		return false;
+	}
+
 	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
+	m_nChannels = modMagicResult.m_nChannels;
+	m_madeWithTracker = modMagicResult.m_madeWithTracker;
+	bool isNoiseTracker = modMagicResult.isNoiseTracker;
+	bool isStartrekker = modMagicResult.isStartrekker;
+	bool isGenericMultiChannel = modMagicResult.isGenericMultiChannel;
+	if(modMagicResult.setMODVBlankTiming)
+	{
+		m_playBehaviour.set(kMODVBlankTiming);
+	}
+
 	LimitMax(m_nChannels, MAX_BASECHANNELS);
 
 	// Startrekker 8 channel mod (needs special treatment, see below)
-	const bool isFLT8 = IsMagic(magic, "FLT8") || IsMagic(magic, "EXO8");
+	const bool isFLT8 = isStartrekker && m_nChannels == 8;
 	// Only apply VBlank tests to M.K. (ProTracker) modules.
 	const bool isMdKd = IsMagic(magic, "M.K.");
 	// Adjust finetune values for modules saved with "His Master's Noisetracker"
@@ -676,11 +818,11 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 	// Load Sample Headers
 	SmpLength totalSampleLen = 0;
 	m_nSamples = 31;
-	uint32 invalidChars = 0;
+	uint32 invalidBytes = 0;
 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
 	{
 		MODSampleHeader sampleHeader;
-		invalidChars += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], m_nChannels == 4);
+		invalidBytes += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], m_nChannels == 4);
 		totalSampleLen += Samples[smp].nLength;
 
 		if(isHMNT)
@@ -691,8 +833,8 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 			isNoiseTracker = false;
 		}
 	}
-	// If there is too much binary garbage in the sample texts, reject the file.
-	if(invalidChars > 256)
+	// If there is too much binary garbage in the sample headers, reject the file.
+	if(invalidBytes > 40)
 	{
 		return false;
 	}
@@ -702,7 +844,7 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 	file.ReadStruct(fileHeader);
 	file.Skip(4);	// Magic bytes (we already parsed these)
 
-	Order.ReadFromArray(fileHeader.orderList, CountOf(fileHeader.orderList));
+	ReadOrderFromArray(Order(), fileHeader.orderList);
 
 	ORDERINDEX realOrders = fileHeader.numOrders;
 	if(realOrders > 128)
@@ -713,47 +855,45 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		// Is this necessary?
 		realOrders = 128;
-		while(realOrders > 1 && Order[realOrders - 1] == 0)
+		while(realOrders > 1 && Order()[realOrders - 1] == 0)
 		{
 			realOrders--;
 		}
 	}
 
 	// Get number of patterns (including some order list sanity checks)
-	PATTERNINDEX numPatterns = GetNumPatterns(file, Order, realOrders, totalSampleLen, m_nChannels, isMdKd);
+	PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), realOrders, totalSampleLen, m_nChannels, isMdKd);
 	if(isMdKd && GetNumChannels() == 8)
 	{
 		// M.K. with 8 channels = Grave Composer
-		m_madeWithTracker = "Mod's Grave";
+		m_madeWithTracker = MPT_USTRING("Mod's Grave");
 	}
 
 	if(isFLT8)
 	{
 		// FLT8 has only even order items, so divide by two.
-		for(ORDERINDEX ord = 0; ord < Order.GetLength(); ord++)
+		for(auto &pat : Order())
 		{
-			Order[ord] /= 2;
+			pat /= 2u;
 		}
 	}
 	
 	// Restart position sanity checks
 	realOrders--;
-	Order.SetRestartPos(fileHeader.restartPos);
+	Order().SetRestartPos(fileHeader.restartPos);
 
 	// (Ultimate) Soundtracker didn't have a restart position, but instead stored a default tempo in this value.
 	// The default value for this is 0x78 (120 BPM). This is probably the reason why some M.K. modules
 	// have this weird restart position. I think I've read somewhere that NoiseTracker actually writes 0x78 there.
-	// Files that have restart pos == 0x78: action's batman by DJ Uno (M.K.), VALLEY.MOD (M.K.), WormsTDC.MOD (M.K.), ZWARTZ.MOD (M.K.)
+	// M.K. files that have restart pos == 0x78: action's batman by DJ Uno, VALLEY.MOD, WormsTDC.MOD, ZWARTZ.MOD
 	// Files that have an order list longer than 0x78 with restart pos = 0x78: my_shoe_is_barking.mod, papermix.mod
 	// - in both cases it does not appear like the restart position should be used.
 	MPT_ASSERT(fileHeader.restartPos != 0x78 || fileHeader.restartPos + 1u >= realOrders);
 	if(fileHeader.restartPos > realOrders || (fileHeader.restartPos == 0x78 && m_nChannels == 4))
 	{
-		Order.SetRestartPos(0);
+		Order().SetRestartPos(0);
 	}
 
-	// Now we can be pretty sure that this is a valid MOD file. Set up default song settings.
-	m_nInstruments = 0;
 	m_nDefaultSpeed = 6;
 	m_nDefaultTempo.Set(125);
 	m_nMinPeriod = 14 * 4;
@@ -762,7 +902,7 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 	// is the maximum possible sample pre-amp without getting distortion (Compatible mix levels given).
 	// The more channels we have, the less likely it is that all of them are used at the same time, though, so cap at 32...
 	m_nSamplePreAmp = Clamp(256 / m_nChannels, 32, 128);
-	m_SongFlags.reset();
+	m_SongFlags.reset();	// SONG_ISAMIGA will be set conditionally
 
 	// Setup channel pan positions and volume
 	SetupMODPanning();
@@ -787,7 +927,7 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 			{
 				ModCommand m;
 				ReadMODPatternEntry(file, m);
-				if(m.note != NOTE_NONE && (m.note < NOTE_MIDDLEC - 12 || m.note >= NOTE_MIDDLEC + 24))
+				if(!m.IsAmigaNote())
 				{
 					isNoiseTracker = onlyAmigaNotes = false;
 				}
@@ -805,6 +945,9 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 						leftPanning = true;
 					else if(m.param > 0x8F && m.param != 0xA4)
 						extendedPanning = true;
+				} else if(m.command == 0x0E && (m.param & 0xF0) == 0x80)
+				{
+					maxPanning = std::max<uint8>(maxPanning, m.param << 4);
 				}
 			}
 		}
@@ -815,17 +958,20 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 	const CHANNELINDEX readChannels = (isFLT8 ? 4 : m_nChannels); // 4 channels per pattern in FLT8 format.
 	if(isFLT8) numPatterns++; // as one logical pattern consists of two real patterns in FLT8 format, the highest pattern number has to be increased by one.
 	bool hasTempoCommands = false, definitelyCIA = false;	// for detecting VBlank MODs
+	// Heuristic for rejecting E0x commands that are most likely not intended to actually toggle the Amiga LED filter, like in naen_leijasi_ptk.mod by ilmarque
+	bool filterState = false;
+	int filterTransitions = 0;
 
 	// Reading patterns
+	Patterns.ResizeArray(numPatterns);
 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
 	{
-		PATTERNINDEX actualPattern = pat;
 		ModCommand *rowBase = nullptr;
 
 		if(isFLT8)
 		{
 			// FLT8: Only create "even" patterns and either write to channel 1 to 4 (even patterns) or 5 to 8 (odd patterns).
-			actualPattern /= 2;
+			PATTERNINDEX actualPattern = pat / 2u;
 			if((pat % 2u) == 0 && !Patterns.Insert(actualPattern, 64))
 			{
 				break;
@@ -847,7 +993,7 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 
 		// For detecting PT1x mode
 		std::vector<ModCommand::INSTR> lastInstrument(GetNumChannels(), 0);
-		std::vector<int> instrWithoutNoteCount(GetNumChannels(), 0);
+		std::vector<uint8> instrWithoutNoteCount(GetNumChannels(), 0);
 
 		for(ROWINDEX row = 0; row < 64; row++, rowBase += m_nChannels)
 		{
@@ -862,6 +1008,12 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 
 				if(m.command || m.param)
 				{
+					// No support for Startrekker assembly macros
+					if(isStartrekker && m.command == 0x0E)
+					{
+						m.command = CMD_NONE;
+						m.param = 0;
+					}
 					ConvertModCommand(m);
 				}
 
@@ -888,6 +1040,15 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 					{
 						m.param = mpt::saturate_cast<ModCommand::PARAM>(m.param * 2);
 					}
+				} else if(m.command == CMD_MODCMDEX && m.param < 0x10)
+				{
+					// Count LED filter transitions
+					bool newState = !(m.param & 0x01);
+					if(newState != filterState)
+					{
+						filterState = newState;
+						filterTransitions++;
+					}
 				}
 				if(m.note == NOTE_NONE && m.instr > 0 && !isFLT8)
 				{
@@ -919,17 +1080,27 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 		// Need this for professionaltracker.mod by h0ffman (SHA1: 9a7c52cbad73ed2a198ee3fa18d3704ea9f546ff)
 		m_SongFlags.set(SONG_PT_MODE);
 		m_playBehaviour.set(kMODSampleSwap);
+		m_playBehaviour.set(kMODOutOfRangeNoteDelay);
+		m_playBehaviour.set(kMODTempoOnSecondTick);
 		// Arbitrary threshold for deciding that 8xx effects are only used as sync markers
-		// Don't enable these hacks for ScreamTracker modules (restart position = 0x7F), to fix e.g. sample 10 in BASIC001.MOD (SHA1: 11298a5620e677beaa50bd4ed00c3710b75c81af)
-		// Note: restart position = 0x7F can also be found in ProTracker modules, e.g. professionaltracker.mod by h0ffman
-		if(maxPanning < 0x20 && fileHeader.restartPos != 0x7F)
+		if(maxPanning < 0x20)
 		{
-			m_playBehaviour.set(kMODOneShotLoops);
-			if(maxPanning > 0) m_playBehaviour.set(kMODIgnorePanning);
+			m_playBehaviour.set(kMODIgnorePanning);
+			if(fileHeader.restartPos != 0x7F)
+			{
+				// Don't enable these hacks for ScreamTracker modules (restart position = 0x7F), to fix e.g. sample 10 in BASIC001.MOD (SHA1: 11298a5620e677beaa50bd4ed00c3710b75c81af)
+				// Note: restart position = 0x7F can also be found in ProTracker modules, e.g. professionaltracker.mod by h0ffman
+				m_playBehaviour.set(kMODOneShotLoops);
+			}
 		}
 	} else if(!onlyAmigaNotes && fileHeader.restartPos == 0x7F && isMdKd && fileHeader.restartPos + 1u >= realOrders)
 	{
-		m_madeWithTracker = "ScreamTracker";
+		m_madeWithTracker = MPT_USTRING("ScreamTracker");
+	}
+
+	if(onlyAmigaNotes && !isGenericMultiChannel && filterTransitions < 7)
+	{
+		m_SongFlags.set(SONG_ISAMIGA);
 	}
 
 	// Reading samples
@@ -953,7 +1124,7 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 				// ProTracker reads beyond the end of the sample when playing. Normally samples are
 				// adjacent in PT's memory, so we simply read into the next sample in the file.
 				FileReader::off_t nextSample = file.GetPosition() + sampleIO.CalculateEncodedSize(sample.nLength);
-				if(isMdKd)
+				if(isMdKd && onlyAmigaNotes)
 					sample.nLength = std::max(sample.nLength, sample.nLoopEnd);
 
 				sampleIO.ReadSample(sample, file);
@@ -962,6 +1133,73 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 		}
 	}
 
+#if defined(MPT_EXTERNAL_SAMPLES) || defined(MPT_BUILD_FUZZER)
+	// Detect Startrekker files with external synth instruments.
+	// Note: Synthesized AM samples may overwrite existing samples (e.g. sample 1 in fa.worse face.mod),
+	// hence they are loaded here after all regular samples have been loaded.
+	if((loadFlags & loadSampleData) && isStartrekker)
+	{
+#ifdef MPT_EXTERNAL_SAMPLES
+		InputFile amFile;
+		FileReader amData;
+		mpt::PathString filename = file.GetFileName();
+		if(!filename.empty())
+		{
+			// Find instrument definition file
+			const mpt::PathString exts[] = { MPT_PATHSTRING(".nt"), MPT_PATHSTRING(".NT"), MPT_PATHSTRING(".as"), MPT_PATHSTRING(".AS") };
+			for(const auto &ext : exts)
+			{
+				mpt::PathString infoName = filename + ext;
+				char stMagic[16];
+				if(infoName.IsFile() && amFile.Open(infoName) && (amData = GetFileReader(amFile)).IsValid() && amData.ReadArray(stMagic))
+				{
+					if(!memcmp(stMagic, "ST1.2 ModuleINFO", 16))
+						m_madeWithTracker = MPT_USTRING("Startrekker 1.2");
+					else if(!memcmp(stMagic, "ST1.3 ModuleINFO", 16))
+						m_madeWithTracker = MPT_USTRING("Startrekker 1.3");
+					else if(!memcmp(stMagic, "AudioSculpture10", 16))
+						m_madeWithTracker = MPT_USTRING("AudioSculpture 1.0");
+					else
+						continue;
+
+					if(amData.Seek(144))
+					{
+						// Looks like a valid instrument definition file!
+						m_nInstruments = 31;
+						break;
+					}
+				}
+			}
+		}
+#elif defined(MPT_BUILD_FUZZER)
+		// For fuzzing this part of the code, just take random data from patterns
+		FileReader amData = file.GetChunkAt(1084, 31 * 120);
+		m_nInstruments = 31;
+#endif
+
+		for(SAMPLEINDEX smp = 1; smp <= m_nInstruments; smp++)
+		{
+			// For Startrekker AM synthesis, we need instrument envelopes.
+			ModInstrument *ins = AllocateInstrument(smp, smp);
+			if(ins == nullptr)
+			{
+				break;
+			}
+			mpt::String::Copy(ins->name, m_szNames[smp]);
+
+			AMInstrument am;
+			// Allow partial reads for fa.worse face.mod
+			if(amData.ReadStructPartial(am) && !memcmp(am.am, "AM", 2) && am.waveform < 4)
+			{
+				am.ConvertToMPT(Samples[smp], *ins, AccessPRNG());
+			}
+
+			// This extra padding is probably present to have identical block sizes for AM and FM instruments.
+			amData.Skip(120 - sizeof(AMInstrument));
+		}
+	}
+#endif // MPT_EXTERNAL_SAMPLES || MPT_BUILD_FUZZER
+
 	// Fix VBlank MODs. Arbitrary threshold: 10 minutes.
 	// Basically, this just converts all tempo commands into speed commands
 	// for MODs which are supposed to have VBlank timing (instead of CIA timing).
@@ -985,7 +1223,7 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 				m_playBehaviour.reset(kMODVBlankTiming);
 			} else
 			{
-				m_madeWithTracker = "ProTracker (VBlank)";
+				m_madeWithTracker = MPT_USTRING("ProTracker (VBlank)");
 			}
 		}
 	}
@@ -996,15 +1234,13 @@ bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
 
 // Check if a name string is valid (i.e. doesn't contain binary garbage data)
 template<size_t N>
-static uint32 CountInvalidChars(char (&name)[N])
-//----------------------------------------------
+static uint32 CountInvalidChars(const char (&name)[N])
 {
 	uint32 invalidChars = 0;
-	for(size_t i = 0; i < N; i++)
+	for(auto c : name)
 	{
-		int8 c = name[i];
 		// Check for any Extended ASCII and control characters
-		if(c != 0 && c < 32)
+		if(c != 0 && c < ' ')
 			invalidChars++;
 	}
 	return invalidChars;
@@ -1026,25 +1262,125 @@ enum STVersions
 };
 
 
-bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+
+struct M15FileHeaders
 {
-	file.Rewind();
+	char            songname[20];
+	MODSampleHeader sampleHeaders[15];
+	MODFileHeader   fileHeader;
+};
+
+MPT_BINARY_STRUCT(M15FileHeaders, 20 + 15 * 30 + 130)
 
-	char songname[20];
-	file.ReadArray(songname);
 
+static bool ValidateHeader(const M15FileHeaders &fileHeaders)
+{
 	// In theory, sample and song names should only ever contain printable ASCII chars and null.
 	// However, there are quite a few SoundTracker modules in the wild with random
 	// characters. To still be able to distguish them from other formats, we just reject
 	// files with *too* many bogus characters. Arbitrary threshold: 20 bogus characters in total
 	// or more than 5 invalid characters just in the title alone.
-	uint32 invalidChars =  CountInvalidChars(songname);
-	if(invalidChars > 5 || !file.CanRead(sizeof(MODSampleHeader) * 15 + sizeof(MODFileHeader)))
+	uint32 invalidChars = CountInvalidChars(fileHeaders.songname);
+	if(invalidChars > 5)
 	{
 		return false;
 	}
 
+	SmpLength totalSampleLen = 0;
+	uint8 allVolumes = 0;
+
+	for(SAMPLEINDEX smp = 0; smp < 15; smp++)
+	{
+		const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp];
+
+		invalidChars += CountInvalidChars(sampleHeader.name);
+
+		// Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
+		if(invalidChars > 48
+			|| sampleHeader.volume > 64
+			|| sampleHeader.finetune != 0
+			|| sampleHeader.length > 32768)
+		{
+			return false;
+		}
+
+		totalSampleLen += sampleHeader.length;
+		allVolumes |= sampleHeader.volume;
+
+	}
+
+	// Reject any files with no (or only silent) samples at all, as this might just be a random binary file (e.g. ID3 tags with tons of padding)
+	if(totalSampleLen == 0 || allVolumes == 0)
+	{
+		return false;
+	}
+
+	// Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
+	// There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
+	if(fileHeaders.fileHeader.numOrders > 128 || fileHeaders.fileHeader.restartPos > 220)
+	{
+		return false;
+	}
+
+	for(uint8 ord : fileHeaders.fileHeader.orderList)
+	{
+		// Sanity check: 64 patterns max.
+		if(ord > 63)
+		{
+			return false;
+		}
+	}
+	
+	bool allPatternsNull = true;
+	for(uint8 pat : fileHeaders.fileHeader.orderList)
+	{
+		if(pat != 0 && pat < 128)
+		{
+			allPatternsNull = false;
+		}
+	}
+	if(fileHeaders.fileHeader.restartPos == 0 && fileHeaders.fileHeader.numOrders == 0 && allPatternsNull)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize)
+{
+	M15FileHeaders fileHeaders;
+	if(!file.ReadStruct(fileHeaders))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeaders))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+
+	M15FileHeaders fileHeaders;
+	if(!file.ReadStruct(fileHeaders))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeaders))
+	{
+		return false;
+	}
+
+	char songname[20];
+	std::memcpy(songname, fileHeaders.songname, 20);
+
 	InitializeGlobals(MOD_TYPE_MOD);
 	m_playBehaviour.reset(kMODOneShotLoops);
 	m_playBehaviour.set(kMODIgnorePanning);
@@ -1055,26 +1391,15 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 
 	bool hasDiskNames = true;
 	SmpLength totalSampleLen = 0;
-	uint8 allVolumes = 0;
 	m_nSamples = 15;
 
+	file.Seek(20);
 	for(SAMPLEINDEX smp = 1; smp <= 15; smp++)
 	{
 		MODSampleHeader sampleHeader;
 		ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
-		invalidChars += CountInvalidChars(sampleHeader.name);
-
-		// Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
-		if(invalidChars > 48
-			|| sampleHeader.volume > 64
-			|| sampleHeader.finetune != 0
-			|| sampleHeader.length > 32768)
-		{
-			return false;
-		}
 
 		totalSampleLen += Samples[smp].nLength;
-		allVolumes |= sampleHeader.volume;
 
 		if(m_szNames[smp][0] && ((memcmp(m_szNames[smp], "st-", 3) && memcmp(m_szNames[smp], "ST-", 3)) || m_szNames[smp][5] != ':'))
 		{
@@ -1095,36 +1420,22 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 			minVersion = std::max(minVersion, MST1_00);
 	}
 
-	// Reject any files with no (or only silent) samples at all, as this might just be a random binary file (e.g. ID3 tags with tons of padding)
-	if(totalSampleLen == 0 || allVolumes == 0)
-		return false;
-
 	MODFileHeader fileHeader;
 	file.ReadStruct(fileHeader);
 
-	// Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
-	// There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
-	if(fileHeader.numOrders > 128 || fileHeader.restartPos > 220)
-		return false;
+	ReadOrderFromArray(Order(), fileHeader.orderList);
+	PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, false);
 
-	for(ORDERINDEX ord = 0; ord < CountOf(fileHeader.orderList); ord++)
+	// Most likely just a file with lots of NULs at the start
+	if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
 	{
-		// Sanity check: 64 patterns max.
-		if(fileHeader.orderList[ord] > 63)
-			return false;
+		return false;
 	}
 
-	Order.ReadFromArray(fileHeader.orderList);
-	PATTERNINDEX numPatterns = GetNumPatterns(file, Order, fileHeader.numOrders, totalSampleLen, m_nChannels, false);
-
 	// Let's see if the file is too small (including some overhead for broken files like sll7.mod or ghostbus.mod)
 	if(file.BytesLeft() + 65536 < numPatterns * 64u * 4u + totalSampleLen)
 		return false;
 
-	// Most likely just a file with lots of NULs at the start
-	if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
-		return false;
-
 	if(loadFlags == onlyVerifyHeader)
 		return true;
 
@@ -1155,7 +1466,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 	m_nMinPeriod = 14 * 4;
 	m_nMaxPeriod = 3424 * 4;
 	m_nSamplePreAmp = 64;
-	m_SongFlags = SONG_PT_MODE;
+	m_SongFlags.set(SONG_PT_MODE);
 	mpt::String::Read<mpt::String::spacePadded>(m_songName, songname);
 
 	// Setup channel pan positions and volume
@@ -1167,7 +1478,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 	uint32 illegalBytes = 0;
 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
 	{
-		bool patternInUse = std::find(Order.begin(), Order.end(), pat) != Order.end();
+		bool patternInUse = std::find(Order().cbegin(), Order().cend(), pat) != Order().cend();
 		uint8 numDxx = 0;
 		uint8 emptyCmds = 0;
 		for(ROWINDEX row = 0; row < 64; row++)
@@ -1263,6 +1574,8 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 	file.Seek(patOffset);
 
 	// Reading patterns
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(numPatterns);
 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
 	{
 		if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
@@ -1367,25 +1680,25 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 	switch(minVersion)
 	{
 	case UST1_00:
-		m_madeWithTracker = "Ultimate Soundtracker 1.0-1.21";
+		m_madeWithTracker = MPT_USTRING("Ultimate Soundtracker 1.0-1.21");
 		break;
 	case UST1_80:
-		m_madeWithTracker = "Ultimate Soundtracker 1.8-2.0";
+		m_madeWithTracker = MPT_USTRING("Ultimate Soundtracker 1.8-2.0");
 		break;
 	case ST2_00_Exterminator:
-		m_madeWithTracker = "SoundTracker 2.0 / D.O.C. SoundTracker II";
+		m_madeWithTracker = MPT_USTRING("SoundTracker 2.0 / D.O.C. SoundTracker II");
 		break;
 	case ST_III:
-		m_madeWithTracker = "Defjam Soundtracker III / Alpha Flight SoundTracker IV / D.O.C. SoundTracker IV / VI";
+		m_madeWithTracker = MPT_USTRING("Defjam Soundtracker III / Alpha Flight SoundTracker IV / D.O.C. SoundTracker IV / VI");
 		break;
 	case ST_IX:
-		m_madeWithTracker = "D.O.C. SoundTracker IX";
+		m_madeWithTracker = MPT_USTRING("D.O.C. SoundTracker IX");
 		break;
 	case MST1_00:
-		m_madeWithTracker = "Master Soundtracker 1.0";
+		m_madeWithTracker = MPT_USTRING("Master Soundtracker 1.0");
 		break;
 	case ST2_00:
-		m_madeWithTracker = "SoundTracker 2.0 / 2.1 / 2.2";
+		m_madeWithTracker = MPT_USTRING("SoundTracker 2.0 / 2.1 / 2.2");
 		break;
 	}
 
@@ -1408,11 +1721,58 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
 }
 
 
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize)
+{
+	if(!file.CanRead(1464 + 4))
+	{
+		return ProbeWantMoreData;
+	}
+	file.Seek(1464);
+	char magic[4];
+	file.ReadArray(magic);
+	if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10"))
+	{
+		return ProbeFailure;
+	}
+	file.Seek(20);
+	uint32 invalidChars = 0;
+	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
+	{
+		MODSampleHeader sampleHeader;
+		if(!file.ReadStruct(sampleHeader))
+		{
+		return ProbeWantMoreData;
+		}
+		invalidChars += CountInvalidChars(sampleHeader.name);
+	}
+	if(invalidChars > 256)
+	{
+		return ProbeFailure;
+	}
+	const uint8 numOrders = file.ReadUint8();
+	const uint8 numTracks = file.ReadUint8();
+	if(numOrders > 128)
+	{
+		return ProbeFailure;
+	}
+	uint8 tracks[128 * 4];
+	file.ReadArray(tracks);
+	for(auto track : tracks)
+	{
+		if(track > numTracks)
+		{
+			return ProbeFailure;
+		}
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 // SoundTracker 2.6 / Ice Tracker variation of the MOD format
 // The only real difference to other SoundTracker formats is the way patterns are stored:
 // Every pattern consists of four independent, re-usable tracks.
 bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	char magic[4];
 	if(!file.Seek(1464) || !file.ReadArray(magic))
@@ -1426,11 +1786,15 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
 	m_playBehaviour.set(kMODSampleSwap);	// untested
 
 	if(IsMagic(magic, "MTN\0"))
-		m_madeWithTracker = "SoundTracker 2.6";
-	else if(IsMagic(magic, "IT10"))
-		m_madeWithTracker = "Ice Tracker 1.0 / 1.1";
-	else
+	{
+		m_madeWithTracker = MPT_USTRING("SoundTracker 2.6");
+	} else if(IsMagic(magic, "IT10"))
+	{
+		m_madeWithTracker = MPT_USTRING("Ice Tracker 1.0 / 1.1");
+	} else
+	{
 		return false;
+	}
 
 	// Reading song title
 	file.Seek(0);
@@ -1438,13 +1802,13 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
 
 	// Load Samples
 	m_nSamples = 31;
-	uint32 invalidChars = 0;
+	uint32 invalidBytes = 0;
 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
 	{
 		MODSampleHeader sampleHeader;
-		invalidChars += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
+		invalidBytes += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
 	}
-	if(invalidChars > 256)
+	if(invalidBytes > 40)
 	{
 		return false;
 	}
@@ -1452,18 +1816,24 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
 	const uint8 numOrders = file.ReadUint8();
 	const uint8 numTracks = file.ReadUint8();
 	if(numOrders > 128)
+	{
 		return false;
+	}
 
 	uint8 tracks[128 * 4];
 	file.ReadArray(tracks);
-	for(size_t i = 0; i < CountOf(tracks); i++)
+	for(auto track : tracks)
 	{
-		if(tracks[i] > numTracks)
+		if(track > numTracks)
+		{
 			return false;
+		}
 	}
 
 	if(loadFlags == onlyVerifyHeader)
+	{
 		return true;
+	}
 
 	// Now we can be pretty sure that this is a valid MOD file. Set up default song settings.
 	m_nChannels = 4;
@@ -1473,17 +1843,18 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
 	m_nMinPeriod = 14 * 4;
 	m_nMaxPeriod = 3424 * 4;
 	m_nSamplePreAmp = 64;
-	m_SongFlags = SONG_PT_MODE;
+	m_SongFlags.set(SONG_PT_MODE);
 
 	// Setup channel pan positions and volume
 	SetupMODPanning();
 
 	// Reading patterns
-	Order.resize(numOrders);
+	Order().resize(numOrders);
 	uint8 speed[2] = { 0, 0 }, speedPos = 0;
+	Patterns.ResizeArray(numOrders);
 	for(PATTERNINDEX pat = 0; pat < numOrders; pat++)
 	{
-		Order[pat] = pat;
+		Order()[pat] = pat;
 		if(!Patterns.Insert(pat, 64))
 			continue;
 
@@ -1509,7 +1880,7 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
 		}
 
 		// Handle speed command with both nibbles set - this enables auto-swing (alternates between the two nibbles)
-		ModCommand *m = Patterns[pat];
+		auto m = Patterns[pat].begin();
 		for(ROWINDEX row = 0; row < 64; row++)
 		{
 			for(CHANNELINDEX chn = 0; chn < 4; chn++, m++)
@@ -1560,29 +1931,72 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
 
 
 
+struct PT36Header
+{
+	char    magicFORM[4];  // "FORM"
+	uint8be dummy1[4];
+	char    magicMODL[4];  // "MODL"
+};
+
+MPT_BINARY_STRUCT(PT36Header, 12);
+
+
+static bool ValidateHeader(const PT36Header &fileHeader)
+{
+	if(std::memcmp(fileHeader.magicFORM, "FORM", 4))
+	{
+		return false;
+	}
+	if(std::memcmp(fileHeader.magicMODL, "MODL", 4))
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize)
+{
+	PT36Header fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 // ProTracker 3.6 version of the MOD format
 // Basically just a normal ProTracker mod with different magic, wrapped in an IFF file.
 // The "PTDT" chunk is passed to the normal MOD loader.
 bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
-//--------------------------------------------------------------------
 {
 	file.Rewind();
-	if(!file.ReadMagic("FORM")
-		|| !file.Skip(4)
-		|| !file.ReadMagic("MODL"))
+
+	PT36Header fileHeader;
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
 	}
-	
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+
 	bool ok = false, infoOk = false;
 	FileReader commentChunk;
-	std::string version = "3.6";
+	mpt::ustring version;
 	PT36InfoChunk info;
 	MemsetZero(info);
 
 	// Go through IFF chunks...
 	PT36IffChunk iffHead;
-	if(!file.ReadConvertEndianness(iffHead))
+	if(!file.ReadStruct(iffHead))
 	{
 		return false;
 	}
@@ -1610,12 +2024,12 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
 			chunk.Skip(4);
 			if(chunk.ReadMagic("PT") && iffHead.chunksize > 6)
 			{
-				chunk.ReadString<mpt::String::maybeNullTerminated>(version, iffHead.chunksize - 6);
+				chunk.ReadString<mpt::String::maybeNullTerminated>(version, mpt::CharsetISO8859_1, iffHead.chunksize - 6);
 			}
 			break;
 		
 		case PT36IffChunk::idINFO:
-			infoOk = chunk.ReadConvertEndianness(info);
+			infoOk = chunk.ReadStruct(info);
 			break;
 		
 		case PT36IffChunk::idCMNT:
@@ -1626,7 +2040,12 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
 			ok = ReadMod(chunk, loadFlags);
 			break;
 		}
-	} while(file.CanRead(sizeof(PT36IffChunk)) && file.ReadConvertEndianness(iffHead));
+	} while(file.ReadStruct(iffHead));
+
+	if(version.empty())
+	{
+		version = MPT_USTRING("3.6");
+	}
 	
 	// both an info chunk and a module are required
 	if(ok && infoOk)
@@ -1634,7 +2053,7 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
 		bool vblank = (info.flags & 0x100) == 0;
 		m_playBehaviour.set(kMODVBlankTiming, vblank);
 		if(info.volume != 0)
-			m_nSamplePreAmp = std::min(uint16(64), info.volume);
+			m_nSamplePreAmp = std::min<uint16>(64, info.volume);
 		if(info.tempo != 0 && !vblank)
 			m_nDefaultTempo.Set(info.tempo);
 	
@@ -1669,9 +2088,12 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
 			}
 		}
 		
-		m_madeWithTracker = "ProTracker " + version;
+		m_madeWithTracker = MPT_USTRING("ProTracker ") + version;
 	}
+	m_SongFlags.set(SONG_PT_MODE);
 	m_playBehaviour.set(kMODIgnorePanning);
+	m_playBehaviour.set(kMODOneShotLoops);
+	m_playBehaviour.set(kMODSampleSwap);
 	
 	return ok;
 }
@@ -1680,7 +2102,6 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags)
 #ifndef MODPLUG_NO_FILESAVE
 
 bool CSoundFile::SaveMod(const mpt::PathString &filename) const
-//-------------------------------------------------------------
 {
 	FILE *f;
 
@@ -1726,7 +2147,6 @@ bool CSoundFile::SaveMod(const mpt::PathString &filename) const
 		MODSampleHeader sampleHeader;
 		mpt::String::Write<mpt::String::maybeNullTerminated>(sampleHeader.name, m_szNames[sampleSource[smp]]);
 		sampleLength[smp] = sampleHeader.ConvertToMOD(sampleSource[smp] <= GetNumSamples() ? GetSample(sampleSource[smp]) : ModSample(MOD_TYPE_MOD));
-		sampleHeader.ConvertEndianness();
 		fwrite(&sampleHeader, sizeof(sampleHeader), 1, f);
 	}
 
@@ -1735,43 +2155,47 @@ bool CSoundFile::SaveMod(const mpt::PathString &filename) const
 	MemsetZero(fileHeader);
 
 	PATTERNINDEX writePatterns = 0;
-	for(ORDERINDEX ord = 0; ord < Order.GetLength() && fileHeader.numOrders < 128; ord++)
+	uint8 writtenOrders = 0;
+	for(ORDERINDEX ord = 0; ord < Order().GetLength() && writtenOrders < 128; ord++)
 	{
 		// Ignore +++ and --- patterns in order list, as well as high patterns (MOD officially only supports up to 128 patterns)
-		if(Order[ord] < 128)
+		if(ord == Order().GetRestartPos())
 		{
-			fileHeader.orderList[fileHeader.numOrders++] = static_cast<uint8>(Order[ord]);
-			if(writePatterns <= Order[ord])
+			fileHeader.restartPos = writtenOrders;
+		}
+		if(Order()[ord] < 128)
+		{
+			fileHeader.orderList[writtenOrders++] = static_cast<uint8>(Order()[ord]);
+			if(writePatterns <= Order()[ord])
 			{
-				writePatterns = Order[ord] + 1;
+				writePatterns = Order()[ord] + 1;
 			}
 		}
 	}
-
-	if(Order.GetRestartPos() < 128)
-	{
-		fileHeader.restartPos = static_cast<uint8>(Order.GetRestartPos());
-	}
+	fileHeader.numOrders = writtenOrders;
 	fwrite(&fileHeader, sizeof(fileHeader), 1, f);
 
 	// Write magic bytes
-	char modMagic[6];
+	char modMagic[4];
 	CHANNELINDEX writeChannels = std::min(CHANNELINDEX(99), GetNumChannels());
 	if(writeChannels == 4)
 	{
+		// ProTracker may not load files with more than 64 patterns correctly if we do not specify the M!K! magic.
 		if(writePatterns <= 64)
-		{
 			memcpy(modMagic, "M.K.", 4);
-		} else
-		{
-			// More than 64 patterns
+		else
 			memcpy(modMagic, "M!K!", 4);
-		}
+	} else if(writeChannels < 10)
+	{
+		memcpy(modMagic, "0CHN", 4);
+		modMagic[0] += static_cast<char>(writeChannels);
 	} else
 	{
-		sprintf(modMagic, "%uCHN", writeChannels);
+		memcpy(modMagic, "00CH", 4);
+		modMagic[0] += static_cast<char>(writeChannels / 10u);
+		modMagic[1] += static_cast<char>(writeChannels % 10u);
 	}
-	fwrite(&modMagic, 4, 1, f);
+	fwrite(modMagic, 4, 1, f);
 
 	// Write patterns
 	std::vector<uint8> events;
@@ -1781,7 +2205,7 @@ bool CSoundFile::SaveMod(const mpt::PathString &filename) const
 		{
 			// Invent empty pattern
 			events.assign(writeChannels * 64 * 4, 0);
-			fwrite(&events[0], events.size(), 1, f);
+			fwrite(events.data(), events.size(), 1, f);
 			continue;
 		}
 
@@ -1791,7 +2215,7 @@ bool CSoundFile::SaveMod(const mpt::PathString &filename) const
 			{
 				// Invent empty row
 				events.assign(writeChannels * 4, 0);
-				fwrite(&events[0], events.size(), 1, f);
+				fwrite(events.data(), events.size(), 1, f);
 				continue;
 			}
 			PatternRow rowBase = Patterns[pat].GetRow(row);
@@ -1825,7 +2249,7 @@ bool CSoundFile::SaveMod(const mpt::PathString &filename) const
 				events[eventByte++] = ((instr & 0x0F) << 4) | (command & 0x0F);
 				events[eventByte++] = param;
 			}
-			fwrite(&events[0], eventByte, 1, f);
+			fwrite(events.data(), eventByte, 1, f);
 		}
 	}
 
diff --git a/soundlib/Load_mt2.cpp b/soundlib/Load_mt2.cpp
index 6989fce..2d0dca5 100644
--- a/soundlib/Load_mt2.cpp
+++ b/soundlib/Load_mt2.cpp
@@ -21,11 +21,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED MT2FileHeader
+struct MT2FileHeader
 {
 	enum MT2HeaderFlags
 	{
@@ -35,88 +31,49 @@ struct PACKED MT2FileHeader
 		masterAutomation	= 0x10,
 	};
 
-	char   signature[4];	// "MT20"
-	uint32 userID;
-	uint16 version;
-	char   trackerName[32];	// "MadTracker 2.0"
-	char   songName[64];
-	uint16 numOrders;
-	uint16 restartPos;
-	uint16 numPatterns;
-	uint16 numChannels;
-	uint16 samplesPerTick;
-	uint8  ticksPerLine;
-	uint8  linesPerBeat;
-	uint32 flags;			// See HeaderFlags
-	uint16 numInstruments;
-	uint16 numSamples;
-	uint8  Orders[256];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(userID);
-		SwapBytesLE(version);
-		SwapBytesLE(numOrders);
-		SwapBytesLE(restartPos);
-		SwapBytesLE(numPatterns);
-		SwapBytesLE(numChannels);
-		SwapBytesLE(samplesPerTick);
-		SwapBytesLE(numInstruments);
-		SwapBytesLE(numSamples);
-	}
+	char     signature[4];		// "MT20"
+	uint32le userID;
+	uint16le version;
+	char     trackerName[32];	// "MadTracker 2.0"
+	char     songName[64];
+	uint16le numOrders;
+	uint16le restartPos;
+	uint16le numPatterns;
+	uint16le numChannels;
+	uint16le samplesPerTick;
+	uint8le  ticksPerLine;
+	uint8le  linesPerBeat;
+	uint32le flags;				// See HeaderFlags
+	uint16le numInstruments;
+	uint16le numSamples;
 };
 
-STATIC_ASSERT(sizeof(MT2FileHeader) == 382);
+MPT_BINARY_STRUCT(MT2FileHeader, 126)
 
 
-struct PACKED MT2DrumsData
+struct MT2DrumsData
 {
-	uint16 numDrumPatterns;
-	uint16 DrumSamples[8];
-	uint8  DrumPatternOrder[256];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numDrumPatterns);
-		for(size_t i = 0; i < CountOf(DrumSamples); i++)
-		{
-			SwapBytesLE(DrumSamples[i]);
-		}
-	}
+	uint16le numDrumPatterns;
+	uint16le DrumSamples[8];
+	uint8le  DrumPatternOrder[256];
 };
 
-STATIC_ASSERT(sizeof(MT2DrumsData) == 274);
+MPT_BINARY_STRUCT(MT2DrumsData, 274)
 
 
-struct PACKED MT2TrackSettings
+struct MT2TrackSettings
 {
-	uint16 volume;
-	uint8  trackfx;		// Built-in effect type is used
-	uint8  output;
-	uint16 fxID;
-	uint16 trackEffectParam[64][8];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(volume);
-		SwapBytesLE(fxID);
-		for(size_t i = 0; i < CountOf(trackEffectParam); i++)
-		{
-			for(size_t j = 0; j < CountOf(trackEffectParam[0]); j++)
-			{
-				SwapBytesLE(trackEffectParam[i][j]);
-			}
-		}
-	}
+	uint16le volume;
+	uint8le  trackfx;	// Built-in effect type is used
+	uint8le  output;
+	uint16le fxID;
+	uint16le trackEffectParam[64][8];
 };
 
-STATIC_ASSERT(sizeof(MT2TrackSettings) == 1030);
+MPT_BINARY_STRUCT(MT2TrackSettings, 1030)
 
 
-struct PACKED MT2Command
+struct MT2Command
 {
 	uint8 note;	// 0=nothing, 97=note off
 	uint8 instr;
@@ -127,26 +84,19 @@ struct PACKED MT2Command
 	uint8 fxparam2;
 };
 
-STATIC_ASSERT(sizeof(MT2Command) == 7);
+MPT_BINARY_STRUCT(MT2Command, 7)
 
 
-struct PACKED MT2EnvPoint
+struct MT2EnvPoint
 {
-	uint16 x;
-	uint16 y;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(x);
-		SwapBytesLE(y);
-	}
+	uint16le x;
+	uint16le y;
 };
 
-STATIC_ASSERT(sizeof(MT2EnvPoint) == 4);
+MPT_BINARY_STRUCT(MT2EnvPoint, 4)
 
 
-struct PACKED MT2Instrument
+struct MT2Instrument
 {
 	enum EnvTypes
 	{
@@ -156,156 +106,103 @@ struct PACKED MT2Instrument
 		FilterEnv	= 8,
 	};
 
-	uint16 numSamples;
-	uint8  groupMap[96];
-	uint8  vibtype, vibsweep, vibdepth, vibrate;
-	uint16 fadeout;
-	uint16 nna;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numSamples);
-		SwapBytesLE(fadeout);
-		SwapBytesLE(nna);
-	}
+	uint16le numSamples;
+	uint8le  groupMap[96];
+	uint8le  vibtype, vibsweep, vibdepth, vibrate;
+	uint16le fadeout;
+	uint16le nna;
 };
 
-STATIC_ASSERT(sizeof(MT2Instrument) == 106);
+MPT_BINARY_STRUCT(MT2Instrument, 106)
 
 
-struct PACKED MT2IEnvelope
+struct MT2IEnvelope
 {
-	uint8 flags;
-	uint8 numPoints;
-	uint8 sustainPos;
-	uint8 loopStart;
-	uint8 loopEnd;
-	uint8 reserved[3];
+	uint8le flags;
+	uint8le numPoints;
+	uint8le sustainPos;
+	uint8le loopStart;
+	uint8le loopEnd;
+	uint8le reserved[3];
 	MT2EnvPoint points[16];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(size_t i = 0; i < CountOf(points); i++)
-		{
-			points[i].ConvertEndianness();
-		}
-	}
 };
 
-STATIC_ASSERT(sizeof(MT2IEnvelope) == 72);
+MPT_BINARY_STRUCT(MT2IEnvelope, 72)
 
 
 // Note: The order of these fields differs a bit in MTIOModule_MT2.cpp - maybe just typos, I'm not sure.
 // This struct follows the save format of MadTracker 2.6.1.
-struct PACKED MT2InstrSynth
+struct MT2InstrSynth
 {
-	uint8  synthID;
-	uint8  effectID;	// 0 = Lowpass filter, 1 = Highpass filter
-	uint16 cutoff;		// 100...11000 Hz
-	uint8  resonance;	// 0...128
-	uint8  attack;		// 0...128
-	uint8  decay;		// 0...128
-	uint8  midiChannel;	// 0...15
-	int8   device;		// VST slot (positive) or MIDI device (negative)
-	int8   unknown1;	// Missing in MTIOModule_MT2.cpp
-	uint8  volume;		// 0...255
-	int8   finetune;	// -96...96
-	int8   transpose;	// -48...48
-	uint8  unknown2;	// Seems to be equal to instrument number.
-	uint8  unknown3;
-	uint8  midiProgram;
-	uint8  reserved[16];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(cutoff);
-	}
+	uint8le  synthID;
+	uint8le  effectID;		// 0 = Lowpass filter, 1 = Highpass filter
+	uint16le cutoff;		// 100...11000 Hz
+	uint8le  resonance;		// 0...128
+	uint8le  attack;		// 0...128
+	uint8le  decay;			// 0...128
+	uint8le  midiChannel;	// 0...15
+	int8le   device;		// VST slot (positive) or MIDI device (negative)
+	int8le   unknown1;		// Missing in MTIOModule_MT2.cpp
+	uint8le  volume;		// 0...255
+	int8le   finetune;		// -96...96
+	int8le   transpose;		// -48...48
+	uint8le  unknown2;		// Seems to be equal to instrument number.
+	uint8le  unknown3;
+	uint8le  midiProgram;
+	uint8le  reserved[16];
 };
 
-STATIC_ASSERT(sizeof(MT2InstrSynth) == 32);
+MPT_BINARY_STRUCT(MT2InstrSynth, 32)
 
 
-struct PACKED MT2Sample
+struct MT2Sample
 {
-	uint32 length;
-	uint32 frequency;
-	uint8  depth;
-	uint8  channels;
-	uint8  flags;
-	uint8  loopType;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint16 volume;
-	int8   panning;
-	int8   note;
-	int16  spb;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(frequency);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(volume);
-		SwapBytesLE(spb);
-	}
+	uint32le length;
+	uint32le frequency;
+	uint8le  depth;
+	uint8le  channels;
+	uint8le  flags;
+	uint8le  loopType;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint16le volume;
+	int8le   panning;
+	int8le   note;
+	int16le  spb;
 };
 
-STATIC_ASSERT(sizeof(MT2Sample) == 26);
+MPT_BINARY_STRUCT(MT2Sample, 26)
 
 
-struct PACKED MT2Group
+struct MT2Group
 {
-	uint8 sample;
-	uint8 vol;		// 0...128
-	int8  pitch;	// -128...127
-	uint8 reserved[5];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(pitch);
-	}
+	uint8le sample;
+	uint8le vol;		// 0...128
+	int8le  pitch;		// -128...127
+	uint8le reserved[5];
 };
 
-STATIC_ASSERT(sizeof(MT2Group) == 8);
+MPT_BINARY_STRUCT(MT2Group, 8)
 
 
-struct PACKED MT2VST
+struct MT2VST
 {
-	char   dll[64];
-	char   programName[28];
-	uint32 fxID;
-	uint32 fxVersion;
-	uint32 programNr;
-	uint8  useChunks;
-	uint8  track;
-	int8   pan;				// Not imported - could use pan mix mode for D/W ratio, but this is not implemented for instrument plugins!
-	char   reserved[17];
-	uint32 n;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(fxID);
-		SwapBytesLE(fxVersion);
-		SwapBytesLE(programNr);
-	}
+	char     dll[64];
+	char     programName[28];
+	uint32le fxID;
+	uint32le fxVersion;
+	uint32le programNr;
+	uint8le  useChunks;
+	uint8le  track;
+	int8le   pan;				// Not imported - could use pan mix mode for D/W ratio, but this is not implemented for instrument plugins!
+	char     reserved[17];
+	uint32le n;
 };
 
-STATIC_ASSERT(sizeof(MT2VST) == 128);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(MT2VST, 128)
 
 
 static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p)
-//---------------------------------------------------------------------------
 {
 	bool hasLegacyTempo = false;
 
@@ -439,7 +336,7 @@ static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p)
 			break;
 
 		case 0x9D:	// Offset + delay
-			m.volcmd = CMD_OFFSET;
+			m.volcmd = VOLCMD_OFFSET;
 			m.vol = p.fxparam2 >> 3;
 			m.command = CMD_S3MCMDEX;
 			m.param = 0xD0 | std::min(p.fxparam1, uint8(0x0F));
@@ -472,7 +369,6 @@ static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p)
 
 // This doesn't really do anything but skipping the envelope chunk at the moment.
 static void ReadMT2Automation(uint16 version, FileReader &file)
-//-------------------------------------------------------------
 {
 	uint32 flags;
 	uint32 trkfxid;
@@ -497,42 +393,84 @@ static void ReadMT2Automation(uint16 version, FileReader &file)
 }
 
 
-bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MT2FileHeader &fileHeader)
 {
-	file.Rewind();
-	MT2FileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.signature, "MT20", 4)
+	if(std::memcmp(fileHeader.signature, "MT20", 4)
 		|| fileHeader.version < 0x200 || fileHeader.version >= 0x300
 		|| fileHeader.numChannels < 1 || fileHeader.numChannels > 64
 		|| fileHeader.numOrders > 256
 		|| fileHeader.numInstruments >= MAX_INSTRUMENTS
-		|| fileHeader.numSamples >= MAX_SAMPLES)
+		|| fileHeader.numSamples >= MAX_SAMPLES
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MT2FileHeader &fileHeader)
+{
+	MPT_UNREFERENCED_PARAMETER(fileHeader);
+	return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize)
+{
+	MT2FileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+	MT2FileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
 	InitializeGlobals(MOD_TYPE_MT2);
 	InitializeChannels();
-	mpt::String::Read<mpt::String::maybeNullTerminated>(m_madeWithTracker, fileHeader.trackerName);
+	mpt::String::Read<mpt::String::maybeNullTerminated>(m_madeWithTracker, mpt::CharsetWindows1252, fileHeader.trackerName);
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songName);
 	m_nChannels = fileHeader.numChannels;
-	Order.SetRestartPos(fileHeader.restartPos);
-	m_nDefaultSpeed = Clamp(fileHeader.ticksPerLine, uint8(1), uint8(31));
+	m_nDefaultSpeed = Clamp<uint8, uint8>(fileHeader.ticksPerLine, 1, 31);
 	m_nDefaultTempo.Set(125);
 	m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX | SONG_EXFILTERRANGE;
 	m_nInstruments = fileHeader.numInstruments;
 	m_nSamples = fileHeader.numSamples;
-	m_nDefaultRowsPerBeat = Clamp(fileHeader.linesPerBeat, uint8(1), uint8(32));
+	m_nDefaultRowsPerBeat = Clamp<uint8, uint8>(fileHeader.linesPerBeat, 1, 32);
 	m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * 4;
 	m_nVSTiVolume = 48;
 	m_nSamplePreAmp = 48 * 2;	// Double pre-amp because we will halve the volume of all non-drum instruments, because the volume of drum samples can exceed that of normal samples
 
-	Order.ReadFromArray(fileHeader.Orders, fileHeader.numOrders);
+	uint8 orders[256];
+	file.ReadArray(orders);
+	ReadOrderFromArray(Order(), orders, fileHeader.numOrders);
+	Order().SetRestartPos(fileHeader.restartPos);
 
 	FileReader drumData = file.ReadChunk(file.ReadUint16LE());
 	FileReader extraData = file.ReadChunk(file.ReadUint32LE());
@@ -548,6 +486,8 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 	bool hasLegacyTempo = false;
 
 	// Read patterns
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.numPatterns);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
 	{
 		ROWINDEX numRows = file.ReadUint16LE();
@@ -662,7 +602,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			for(CHANNELINDEX c = 0; c < GetNumChannels(); c++)
 			{
 				MT2TrackSettings trackSettings;
-				if(chunk.ReadConvertEndianness(trackSettings))
+				if(chunk.ReadStruct(trackSettings))
 				{
 					ChnSettings[c].nVolume = trackSettings.volume >> 10;	// 32768 is 0dB
 					trackRouting[c] = trackSettings.output;
@@ -727,7 +667,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			for(uint32 i = 0; i < std::min(numVST, uint32(MAX_MIXPLUGINS)); i++)
 			{
 				MT2VST vstHeader;
-				if(chunk.ReadConvertEndianness(vstHeader))
+				if(chunk.ReadStruct(vstHeader))
 				{
 					if(fileHeader.version >= 0x0250)
 						chunk.Skip(16 * 4);	// Parameter automation map for 16 parameters
@@ -769,34 +709,32 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 					}
 
 					// Read plugin settings
+					uint32 dataSize;
 					if(vstHeader.useChunks)
 					{
 						// MT2 only ever calls effGetChunk for programs, and OpenMPT uses the defaultProgram value to determine
 						// whether it should use effSetChunk for programs or banks...
 						mixPlug.defaultProgram = -1;
-						LimitMax(vstHeader.n, Util::MaxValueOfType(mixPlug.nPluginDataSize) - 4);
-						mixPlug.nPluginDataSize = vstHeader.n + 4;
+						LimitMax(vstHeader.n, Util::MaxValueOfType(dataSize) - 4);
+						dataSize = vstHeader.n + 4;
 					} else
 					{
 						mixPlug.defaultProgram = vstHeader.programNr;
-						LimitMax(vstHeader.n, (Util::MaxValueOfType(mixPlug.nPluginDataSize) / 4u) - 1);
-						mixPlug.nPluginDataSize = vstHeader.n * 4 + 4;
+						LimitMax(vstHeader.n, (Util::MaxValueOfType(dataSize) / 4u) - 1);
+						dataSize = vstHeader.n * 4 + 4;
 					}
-					mixPlug.pPluginData = new (std::nothrow) char[mixPlug.nPluginDataSize];
-					if(mixPlug.pPluginData != nullptr)
+					mixPlug.pluginData.resize(dataSize);
+					if(vstHeader.useChunks)
 					{
-						if(vstHeader.useChunks)
-						{
-							memcpy(mixPlug.pPluginData, "fEvN", 4);	// 'NvEf' plugin data type
-							chunk.ReadRaw(mixPlug.pPluginData + 4, vstHeader.n);
-						} else
+						memcpy(mixPlug.pluginData.data(), "fEvN", 4);	// 'NvEf' plugin data type
+						chunk.ReadRaw(mixPlug.pluginData.data() + 4, vstHeader.n);
+					} else
+					{
+						float32 *f = reinterpret_cast<float32 *>(mixPlug.pluginData.data());
+						*(f++) = 0;	// Plugin data type
+						for(uint32 param = 0; param < vstHeader.n; param++, f++)
 						{
-							float32 *f = reinterpret_cast<float32 *>(mixPlug.pPluginData);
-							*(f++) = 0;	// Plugin data type
-							for(uint32 param = 0; param < vstHeader.n; param++, f++)
-							{
-								*f = chunk.ReadFloatLE();
-							}
+							*f = chunk.ReadFloatLE();
 						}
 					}
 				} else
@@ -842,7 +780,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 	if(hasDrumChannels)
 	{
 		MT2DrumsData drumHeader;
-		drumData.ReadConvertEndianness(drumHeader);
+		drumData.ReadStruct(drumHeader);
 
 		// Allocate some instruments to handle the drum samples
 		for(INSTRUMENTINDEX i = 0; i < 8; i++)
@@ -851,7 +789,6 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			drumSample[i] = drumHeader.DrumSamples[i];
 			if(drumMap[i] != INSTRUMENTINDEX_INVALID)
 			{
-				m_nInstruments = drumMap[i];
 				ModInstrument *mptIns = AllocateInstrument(drumMap[i], drumHeader.DrumSamples[i] + 1);
 				if(mptIns != nullptr)
 				{
@@ -875,11 +812,11 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 		std::vector<PATTERNINDEX> patMapping(fileHeader.numPatterns, PATTERNINDEX_INVALID);
 		for(uint32 ord = 0; ord < fileHeader.numOrders; ord++)
 		{
-			if(drumHeader.DrumPatternOrder[ord] >= drumHeader.numDrumPatterns || Order[ord] >= fileHeader.numPatterns)
+			if(drumHeader.DrumPatternOrder[ord] >= drumHeader.numDrumPatterns || Order()[ord] >= fileHeader.numPatterns)
 				continue;
 
 			// Figure out where to write this drum pattern
-			PATTERNINDEX writePat = Order[ord];
+			PATTERNINDEX writePat = Order()[ord];
 			if(patMapping[writePat] == PATTERNINDEX_INVALID)
 			{
 				patMapping[writePat] = drumHeader.DrumPatternOrder[ord];
@@ -890,7 +827,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 				if(newPat != PATTERNINDEX_INVALID)
 				{
 					writePat = newPat;
-					Order[ord] = writePat;
+					Order()[ord] = writePat;
 				}
 			}
 			if(!Patterns.IsValidPat(writePat))
@@ -974,7 +911,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			continue;
 
 		MT2Instrument insHeader;
-		instrChunk.ReadConvertEndianness(insHeader);
+		instrChunk.ReadStruct(insHeader);
 		uint16 flags = 0;
 		if(fileHeader.version >= 0x0201) flags = instrChunk.ReadUint16LE();
 		uint32 envMask = MT2Instrument::VolumeEnv | MT2Instrument::PanningEnv;
@@ -994,7 +931,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			if(envMask & 1)
 			{
 				MT2IEnvelope mt2Env;
-				instrChunk.ReadConvertEndianness(mt2Env);
+				instrChunk.ReadStruct(mt2Env);
 
 				const EnvelopeType envType[4] = { ENV_VOLUME, ENV_PANNING, ENV_PITCH, ENV_PITCH };
 				InstrumentEnvelope &mptEnv = mptIns->GetEnvelope(envType[env]);
@@ -1003,7 +940,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 				mptEnv.dwFlags.set(ENV_ENABLED, (mt2Env.flags & 1) != 0);
 				mptEnv.dwFlags.set(ENV_SUSTAIN, (mt2Env.flags & 2) != 0);
 				mptEnv.dwFlags.set(ENV_LOOP, (mt2Env.flags & 4) != 0);
-				mptEnv.resize(std::min(mt2Env.numPoints, uint8(16)));
+				mptEnv.resize(std::min<uint8>(mt2Env.numPoints, 16));
 				mptEnv.nSustainStart = mptEnv.nSustainEnd = mt2Env.sustainPos;
 				mptEnv.nLoopStart = mt2Env.loopStart;
 				mptEnv.nLoopEnd = mt2Env.loopEnd;
@@ -1011,7 +948,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 				for(uint32 p = 0; p < mptEnv.size(); p++)
 				{
 					mptEnv[p].tick = mt2Env.points[p].x;
-					mptEnv[p].value = static_cast<uint8>(Clamp(mt2Env.points[p].y, uint16(0), uint16(64)));
+					mptEnv[p].value = static_cast<uint8>(Clamp<uint16, uint16>(mt2Env.points[p].y, 0, 64));
 				}
 			}
 			envMask >>= 1;
@@ -1027,14 +964,11 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 		if(flags)
 		{
 			MT2InstrSynth synthData;
-			instrChunk.ReadConvertEndianness(synthData);
+			instrChunk.ReadStruct(synthData);
 
-			// Translate frequency back to extended IT cutoff factor
-			float cutoff = 28.8539f * std::log(0.00764451f * synthData.cutoff);
-			Limit(cutoff, 0.0f, 127.0f);
 			if(flags & 2)
 			{
-				mptIns->SetCutoff(Util::Round<uint8>(cutoff), true);
+				mptIns->SetCutoff(FrequencyToCutOff(synthData.cutoff), true);
 				mptIns->SetResonance(synthData.resonance, true);
 			}
 			mptIns->nFilterMode = synthData.effectID == 1 ? FLTMODE_HIGHPASS : FLTMODE_LOWPASS;
@@ -1084,7 +1018,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			ModSample &mptSmp = Samples[i + 1];
 			mptSmp.Initialize(MOD_TYPE_IT);
 			MT2Sample sampleHeader;
-			sampleChunk.ReadConvertEndianness(sampleHeader);
+			sampleChunk.ReadStruct(sampleHeader);
 
 			mptSmp.nLength = sampleHeader.length;
 			mptSmp.nC5Speed = sampleHeader.frequency;
@@ -1136,13 +1070,10 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			FileReader &chunk = instrChunks[ins];
 			MT2Instrument insHeader;
 			chunk.Rewind();
-			chunk.ReadConvertEndianness(insHeader);
+			chunk.ReadStruct(insHeader);
 
-			std::vector<MT2Group> groups(insHeader.numSamples);
-			for(uint32 grp = 0; grp < insHeader.numSamples; grp++)
-			{
-				file.ReadConvertEndianness(groups[grp]);
-			}
+			std::vector<MT2Group> groups;
+			file.ReadVector(groups, insHeader.numSamples);
 
 			ModInstrument *mptIns = Instruments[ins + 1];
 			// Instruments with plugin assignments never play samples at the same time!
@@ -1189,7 +1120,9 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 	for(SAMPLEINDEX i = 0; i < m_nSamples; i++)
 	{
 		ModSample &mptSmp = Samples[i + 1];
-		const uint32 freq = Util::Round<uint32>(mptSmp.nC5Speed * std::pow(2.0, -(mptSmp.RelativeTone - 49 - (mptSmp.nFineTune / 128.0)) / 12.0));
+		mptSmp.Transpose(-(mptSmp.RelativeTone - 49 - (mptSmp.nFineTune / 128.0)) / 12.0);
+		mptSmp.nFineTune = 0;
+		mptSmp.RelativeTone = 0;
 
 		if(!mptSmp.uFlags[SMP_KEEPONDISK])
 		{
@@ -1208,7 +1141,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 			file.ReadString<mpt::String::maybeNullTerminated>(filename, filenameSize);
 			mpt::String::Copy(mptSmp.filename, filename);
 
-#ifdef MPT_EXTERNAL_SAMPLES
+#if defined(MPT_EXTERNAL_SAMPLES)
 			if(filename.length() >= 2
 				&& filename.at(0) != '\\'	// Relative path on same drive
 				&& filename.at(1) != ':')	// Absolute path
@@ -1217,13 +1150,10 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
 				filename = ".\\" + filename;
 			}
 			SetSamplePath(i + 1, mpt::PathString::FromLocaleSilent(filename));
-#else
-			AddToLog(LogWarning, mpt::String::Print(MPT_USTRING("Loading external sample %1 ('%2') failed: External samples are not supported."), i, mpt::ToUnicode(GetCharsetLocaleOrModule(), filename)));
+#elif !defined(LIBOPENMPT_BUILD_TEST)
+			AddToLog(LogWarning, mpt::format(MPT_USTRING("Loading external sample %1 ('%2') failed: External samples are not supported."))(i, mpt::ToUnicode(GetCharsetFile(), filename)));
 #endif // MPT_EXTERNAL_SAMPLES
 		}
-		mptSmp.nC5Speed = freq;
-		mptSmp.nFineTune = 0;
-		mptSmp.RelativeTone = 0;
 	}
 
 	return true;
diff --git a/soundlib/Load_mtm.cpp b/soundlib/Load_mtm.cpp
index b9179eb..b4cc3e0 100644
--- a/soundlib/Load_mtm.cpp
+++ b/soundlib/Load_mtm.cpp
@@ -14,55 +14,36 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // File Header
-struct PACKED MTMFileHeader
+struct MTMFileHeader
 {
-	char   id[3];			// MTM file marker
-	uint8  version;			// Tracker version
-	char   songName[20];	// ASCIIZ songname
-	uint16 numTracks;		// Number of tracks saved
-	uint8  lastPattern;		// Last pattern number saved
-	uint8  lastOrder;		// Last order number to play (songlength-1)
-	uint16 commentSize;		// Length of comment field
-	uint8  numSamples;		// Number of samples saved
-	uint8  attribute;		// Attribute byte (unused)
-	uint8  beatsPerTrack;	// Numbers of rows in every pattern (MultiTracker itself does not seem to support values != 64)
-	uint8  numChannels;		// Number of channels used
-	uint8  panPos[32];		// Channel pan positions
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numTracks);
-		SwapBytesLE(commentSize);
-	}
+	char     id[3];			// MTM file marker
+	uint8le  version;		// Tracker version
+	char     songName[20];	// ASCIIZ songname
+	uint16le numTracks;		// Number of tracks saved
+	uint8le  lastPattern;	// Last pattern number saved
+	uint8le  lastOrder;		// Last order number to play (songlength-1)
+	uint16le commentSize;	// Length of comment field
+	uint8le  numSamples;	// Number of samples saved
+	uint8le  attribute;		// Attribute byte (unused)
+	uint8le  beatsPerTrack;	// Numbers of rows in every pattern (MultiTracker itself does not seem to support values != 64)
+	uint8le  numChannels;	// Number of channels used
+	uint8le  panPos[32];	// Channel pan positions
 };
 
-STATIC_ASSERT(sizeof(MTMFileHeader) == 66);
+MPT_BINARY_STRUCT(MTMFileHeader, 66)
 
 
 // Sample Header
-struct PACKED MTMSampleHeader
+struct MTMSampleHeader
 {
-	char   samplename[22];
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	int8   finetune;
-	uint8  volume;
-	uint8  attribute;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-	}
+	char     samplename[22];
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	int8le   finetune;
+	uint8le  volume;
+	uint8le  attribute;
 
 	// Convert an MTM sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -91,29 +72,63 @@ struct PACKED MTMSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(MTMSampleHeader) == 37);
+MPT_BINARY_STRUCT(MTMSampleHeader, 37)
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static bool ValidateHeader(const MTMFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.id, "MTM", 3)
+		|| fileHeader.version >= 0x20
+		|| fileHeader.lastOrder > 127
+		|| fileHeader.beatsPerTrack > 64
+		|| fileHeader.numChannels > 32
+		|| fileHeader.numChannels == 0
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MTMFileHeader &fileHeader)
+{
+	return sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	MTMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 	MTMFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.id, "MTM", 3)
-		|| fileHeader.lastOrder > 127
-		|| fileHeader.numChannels > 32
-		|| fileHeader.numChannels == 0
-		|| fileHeader.lastPattern >= MAX_PATTERNS
-		|| !file.CanRead(sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize))
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -122,13 +137,13 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songName);
 	m_nSamples = fileHeader.numSamples;
 	m_nChannels = fileHeader.numChannels;
-	m_madeWithTracker = mpt::String::Print("MultiTracker %1.%2", fileHeader.version >> 4, fileHeader.version & 0x0F);
+	m_madeWithTracker = mpt::format(MPT_USTRING("MultiTracker %1.%2"))(fileHeader.version >> 4, fileHeader.version & 0x0F);
 
 	// Reading instruments
 	for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
 	{
 		MTMSampleHeader sampleHeader;
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		sampleHeader.ConvertToMPT(Samples[smp]);
 		mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp], sampleHeader.samplename);
 	}
@@ -141,13 +156,16 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Reading pattern order
-	const ORDERINDEX readOrders = fileHeader.lastOrder + 1;
-	Order.ReadAsByte(file, 128, readOrders, 0xFF, 0xFE);
+	uint8 orders[128];
+	file.ReadArray(orders);
+	ReadOrderFromArray(Order(), orders, fileHeader.lastOrder + 1, 0xFF, 0xFE);
 
 	// Reading Patterns
-	const ROWINDEX rowsPerPat = fileHeader.beatsPerTrack ? std::min(ROWINDEX(fileHeader.beatsPerTrack), MAX_PATTERN_ROWS) : 64;
+	const ROWINDEX rowsPerPat = fileHeader.beatsPerTrack ? fileHeader.beatsPerTrack : 64;
 	FileReader tracks = file.ReadChunk(192 * fileHeader.numTracks);
 
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.lastPattern + 1);
 	for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPattern; pat++)
 	{
 		if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, rowsPerPat))
diff --git a/soundlib/Load_okt.cpp b/soundlib/Load_okt.cpp
index 2cf8ac1..eed4f9a 100644
--- a/soundlib/Load_okt.cpp
+++ b/soundlib/Load_okt.cpp
@@ -14,11 +14,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED OktIffChunk
+struct OktIffChunk
 {
 	// IFF chunk names
 	enum ChunkIdentifiers
@@ -33,57 +29,36 @@ struct PACKED OktIffChunk
 		idSBOD	= MAGIC4BE('S','B','O','D'),
 	};
 
-	uint32 signature;	// IFF chunk name
-	uint32 chunksize;	// chunk size without header
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(signature);
-		SwapBytesBE(chunksize);
-	}
+	uint32be signature;	// IFF chunk name
+	uint32be chunksize;	// chunk size without header
 };
 
-STATIC_ASSERT(sizeof(OktIffChunk) == 8);
+MPT_BINARY_STRUCT(OktIffChunk, 8)
 
-struct PACKED OktSample
+struct OktSample
 {
-	char   name[20];
-	uint32 length;		// length in bytes
-	uint16 loopStart;	// *2 for real value
-	uint16 loopLength;	// ditto
-	uint16 volume;		// default volume
-	uint16 type;		// 7-/8-bit sample
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(length);
-		SwapBytesBE(loopStart);
-		SwapBytesBE(loopLength);
-		SwapBytesBE(volume);
-		SwapBytesBE(type);
-	}
+	char     name[20];
+	uint32be length;		// length in bytes
+	uint16be loopStart;		// *2 for real value
+	uint16be loopLength;	// ditto
+	uint16be volume;		// default volume
+	uint16be type;			// 7-/8-bit sample
 };
 
-STATIC_ASSERT(sizeof(OktSample) == 32);
+MPT_BINARY_STRUCT(OktSample, 32)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
 // Parse the sample header block
-static void ReadOKTSamples(FileReader &chunk, std::vector<bool> &sample7bit, CSoundFile *pSndFile)
-//------------------------------------------------------------------------------------------------
+static void ReadOKTSamples(FileReader &chunk, std::vector<bool> &sample7bit, CSoundFile &sndFile)
 {
-	pSndFile->m_nSamples = MIN((SAMPLEINDEX)(chunk.BytesLeft() / sizeof(OktSample)), MAX_SAMPLES - 1);	// typically 36
-	sample7bit.resize(pSndFile->GetNumSamples());
+	sndFile.m_nSamples = std::min<SAMPLEINDEX>(static_cast<SAMPLEINDEX>(chunk.BytesLeft() / sizeof(OktSample)), MAX_SAMPLES - 1u);
+	sample7bit.resize(sndFile.GetNumSamples());
 
-	for(SAMPLEINDEX nSmp = 1; nSmp <= pSndFile->GetNumSamples(); nSmp++)
+	for(SAMPLEINDEX smp = 1; smp <= sndFile.GetNumSamples(); smp++)
 	{
-		ModSample &mptSmp = pSndFile->GetSample(nSmp);
+		ModSample &mptSmp = sndFile.GetSample(smp);
 		OktSample oktSmp;
-		chunk.ReadConvertEndianness(oktSmp);
+		chunk.ReadStruct(oktSmp);
 
 		oktSmp.length = oktSmp.length;
 		oktSmp.loopStart = oktSmp.loopStart * 2;
@@ -92,7 +67,7 @@ static void ReadOKTSamples(FileReader &chunk, std::vector<bool> &sample7bit, CSo
 		oktSmp.type = oktSmp.type;
 
 		mptSmp.Initialize();
-		mpt::String::Read<mpt::String::maybeNullTerminated>(pSndFile->m_szNames[nSmp], oktSmp.name);
+		mpt::String::Read<mpt::String::maybeNullTerminated>(sndFile.m_szNames[smp], oktSmp.name);
 
 		mptSmp.nC5Speed = 8287;
 		mptSmp.nGlobalVol = 64;
@@ -108,14 +83,13 @@ static void ReadOKTSamples(FileReader &chunk, std::vector<bool> &sample7bit, CSo
 			else
 				mptSmp.nSustainStart = mptSmp.nSustainEnd = 0;
 		}
-		sample7bit[nSmp - 1] = (oktSmp.type == 0 || oktSmp.type == 2);
+		sample7bit[smp - 1] = (oktSmp.type == 0 || oktSmp.type == 2);
 	}
 }
 
 
 // Parse a pattern block
 static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX nPat, CSoundFile &sndFile)
-//-----------------------------------------------------------------------------------
 {
 	if(!chunk.CanRead(2))
 	{
@@ -260,7 +234,8 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX nPat, CSoundFile &snd
 					break;
 				default:
 					// Junk.
-					m->command = m->param = 0;
+					m->command = CMD_NONE;
+					m->param = 0;
 					break;
 				}
 				break;
@@ -274,7 +249,6 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX nPat, CSoundFile &snd
 
 			default:
 				m->command = m->param = 0;
-				//MPT_ASSERT_NOTREACHED();
 				break;
 			}
 		}
@@ -282,8 +256,35 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX nPat, CSoundFile &snd
 }
 
 
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize)
+{
+	if(!file.CanRead(8))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!file.ReadMagic("OKTASONG"))
+	{
+		return ProbeFailure;
+	}
+	OktIffChunk iffHead;
+	if(!file.ReadStruct(iffHead))
+	{
+		return ProbeWantMoreData;
+	}
+	if(iffHead.chunksize == 0)
+	{
+		return ProbeFailure;
+	}
+	if((iffHead.signature & 0x7f7f7f7fu) != iffHead.signature) // ASCII?
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 	if(!file.ReadMagic("OKTASONG"))
@@ -295,7 +296,7 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
 	std::vector<FileReader> patternChunks;
 	std::vector<FileReader> sampleChunks;
 	std::vector<bool> sample7bit;	// 7-/8-bit sample
-	ORDERINDEX nOrders = 0;
+	ORDERINDEX numOrders = 0;
 
 	InitializeGlobals(MOD_TYPE_OKT);
 
@@ -303,7 +304,7 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
 	while(file.CanRead(sizeof(OktIffChunk)))
 	{
 		OktIffChunk iffHead;
-		if(!file.ReadConvertEndianness(iffHead))
+		if(!file.ReadStruct(iffHead))
 		{
 			break;
 		}
@@ -317,22 +318,22 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
 		switch(iffHead.signature)
 		{
 		case OktIffChunk::idCMOD:
-			// read that weird channel setup table
+			// Read that weird channel setup table
 			if(m_nChannels > 0 || chunk.GetLength() < 8)
 			{
 				break;
 			}
 
-			for(CHANNELINDEX nChn = 0; nChn < 4; nChn++)
+			for(CHANNELINDEX chn = 0; chn < 4; chn++)
 			{
 				uint8 ch1 = chunk.ReadUint8(), ch2 = chunk.ReadUint8();
 				if(ch1 || ch2)
 				{
 					ChnSettings[m_nChannels].Reset();
-					ChnSettings[m_nChannels++].nPan = (((nChn & 3) == 1) || ((nChn & 3) == 2)) ? 0xC0 : 0x40;
+					ChnSettings[m_nChannels++].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40;
 				}
 				ChnSettings[m_nChannels].Reset();
-				ChnSettings[m_nChannels++].nPan = (((nChn & 3) == 1) || ((nChn & 3) == 2)) ? 0xC0 : 0x40;
+				ChnSettings[m_nChannels++].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40;
 			}
 
 			if(loadFlags == onlyVerifyHeader)
@@ -342,16 +343,16 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
 			break;
 
 		case OktIffChunk::idSAMP:
-			// convert sample headers
+			// Convert sample headers
 			if(m_nSamples > 0)
 			{
 				break;
 			}
-			ReadOKTSamples(chunk, sample7bit, this);
+			ReadOKTSamples(chunk, sample7bit, *this);
 			break;
 
 		case OktIffChunk::idSPEE:
-			// read default speed
+			// Read default speed
 			if(chunk.GetLength() >= 2)
 			{
 				m_nDefaultSpeed = Clamp(chunk.ReadUint16BE(), uint16(1), uint16(255));
@@ -359,32 +360,32 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
 			break;
 
 		case OktIffChunk::idSLEN:
-			// number of patterns, we don't need this.
+			// Number of patterns, we don't need this.
 			break;
 
 		case OktIffChunk::idPLEN:
-			// read number of valid orders
+			// Read number of valid orders
 			if(chunk.GetLength() >= 2)
 			{
-				nOrders = chunk.ReadUint16BE();
+				numOrders = chunk.ReadUint16BE();
 			}
 			break;
 
 		case OktIffChunk::idPATT:
-			// read the orderlist
-			Order.ReadAsByte(chunk, chunk.GetLength(), ORDERINDEX_MAX, 0xFF, 0xFE);
+			// Read the orderlist
+			ReadOrderFromFile<uint8>(Order(), chunk, chunk.GetLength(), 0xFF, 0xFE);
 			break;
 
 		case OktIffChunk::idPBOD:
-			// don't read patterns for now, as the number of channels might be unknown at this point.
-			if(patternChunks.size() < MAX_PATTERNS)
+			// Don't read patterns for now, as the number of channels might be unknown at this point.
+			if(patternChunks.size() < 256)
 			{
 				patternChunks.push_back(chunk);
 			}
 			break;
 
 		case OktIffChunk::idSBOD:
-			// sample data - same as with patterns, as we need to know the sample format / length
+			// Sample data - same as with patterns, as we need to know the sample format / length
 			if(sampleChunks.size() < MAX_SAMPLES - 1 && chunk.GetLength() > 0)
 			{
 				sampleChunks.push_back(chunk);
@@ -404,45 +405,43 @@ bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
 	m_nMaxPeriod = 0x358 * 4;
 
 	// Fix orderlist
-	for(ORDERINDEX nOrd = nOrders; nOrd < Order.GetLengthTailTrimmed(); nOrd++)
-	{
-		Order[nOrd] = Order.GetInvalidPatIndex();
-	}
+	Order().resize(numOrders);
 
 	// Read patterns
 	if(loadFlags & loadPatternData)
 	{
-		for(PATTERNINDEX nPat = 0; nPat < patternChunks.size(); nPat++)
+		Patterns.ResizeArray(static_cast<PATTERNINDEX>(patternChunks.size()));
+		for(PATTERNINDEX pat = 0; pat < patternChunks.size(); pat++)
 		{
-			if(patternChunks[nPat].GetLength() > 0)
-				ReadOKTPattern(patternChunks[nPat], nPat, *this);
+			if(patternChunks[pat].GetLength() > 0)
+				ReadOKTPattern(patternChunks[pat], pat, *this);
 			else
-				Patterns.Insert(nPat, 64);	// invent empty pattern
+				Patterns.Insert(pat, 64);	// Invent empty pattern
 		}
 	}
 
 	// Read samples
-	size_t nFileSmp = 0;
-	for(SAMPLEINDEX nSmp = 1; nSmp < m_nSamples; nSmp++)
+	size_t fileSmp = 0;
+	for(SAMPLEINDEX smp = 1; smp < m_nSamples; smp++)
 	{
-		if(nFileSmp >= sampleChunks.size() || !(loadFlags & loadSampleData))
+		if(fileSmp >= sampleChunks.size() || !(loadFlags & loadSampleData))
 			break;
 
-		ModSample &mptSample = Samples[nSmp];
+		ModSample &mptSample = Samples[smp];
 		if(mptSample.nLength == 0)
 			continue;
 
-		// weird stuff?
-		mptSample.nLength = MIN(mptSample.nLength, sampleChunks[nFileSmp].GetLength());
+		// Weird stuff?
+		LimitMax(mptSample.nLength, mpt::saturate_cast<SmpLength>(sampleChunks[fileSmp].GetLength()));
 
 		SampleIO(
 			SampleIO::_8bit,
 			SampleIO::mono,
 			SampleIO::bigEndian,
-			sample7bit[nSmp - 1] ? SampleIO::PCM7to8 : SampleIO::signedPCM)
-			.ReadSample(mptSample, sampleChunks[nFileSmp]);
+			sample7bit[smp - 1] ? SampleIO::PCM7to8 : SampleIO::signedPCM)
+			.ReadSample(mptSample, sampleChunks[fileSmp]);
 
-		nFileSmp++;
+		fileSmp++;
 	}
 
 	return true;
diff --git a/soundlib/Load_plm.cpp b/soundlib/Load_plm.cpp
index de1ad65..963a0eb 100644
--- a/soundlib/Load_plm.cpp
+++ b/soundlib/Load_plm.cpp
@@ -14,38 +14,28 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED PLMFileHeader
+struct PLMFileHeader
 {
-	char   magic[4];		// "PLM\x1A"
-	uint8  headerSize;		// Number of bytes in header, including magic bytes
-	uint8  version;			// version code of file format (0x10)
-	char   songName[48];
-	uint8  numChannels;
-	uint8  flags;			// unused?
-	uint8  maxVol;			// Maximum volume for vol slides, normally 0x40
-	uint8  amplify;			// SoundBlaster amplify, 0x40 = no amplify
-	uint8  tempo;
-	uint8  speed;
-	uint8  panPos[32];		// 0...15
-	uint8  numSamples;
-	uint8  numPatterns;
-	uint16 numOrders;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numOrders);
-	}
+	char     magic[4];		// "PLM\x1A"
+	uint8le  headerSize;	// Number of bytes in header, including magic bytes
+	uint8le  version;		// version code of file format (0x10)
+	char     songName[48];
+	uint8le  numChannels;
+	uint8le  flags;			// unused?
+	uint8le  maxVol;		// Maximum volume for vol slides, normally 0x40
+	uint8le  amplify;		// SoundBlaster amplify, 0x40 = no amplify
+	uint8le  tempo;
+	uint8le  speed;
+	uint8le  panPos[32];	// 0...15
+	uint8le  numSamples;
+	uint8le  numPatterns;
+	uint16le numOrders;
 };
 
-STATIC_ASSERT(sizeof(PLMFileHeader) == 96);
+MPT_BINARY_STRUCT(PLMFileHeader, 96)
 
 
-struct PACKED PLMSampleHeader
+struct PLMSampleHeader
 {
 	enum SampleFlags
 	{
@@ -53,94 +43,112 @@ struct PACKED PLMSampleHeader
 		smpPingPong = 2,
 	};
 
-	char   magic[4];		// "PLS\x1A"
-	uint8  headerSize;		// Number of bytes in header, including magic bytes
-	uint8  version;	
-	char   name[32];
-	char   filename[12];
-	uint8  panning;			// 0...15, 255 = no pan
-	uint8  volume;			// 0...64
-	uint8  flags;			// See SampleFlags
-	uint16 sampleRate;
-	char   unused[4];
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint32 length;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(sampleRate);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(length);
-	}
+	char     magic[4];		// "PLS\x1A"
+	uint8le  headerSize;	// Number of bytes in header, including magic bytes
+	uint8le  version;	
+	char     name[32];
+	char     filename[12];
+	uint8le  panning;		// 0...15, 255 = no pan
+	uint8le  volume;		// 0...64
+	uint8le  flags;			// See SampleFlags
+	uint16le sampleRate;
+	char     unused[4];
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint32le length;
 };
 
-STATIC_ASSERT(sizeof(PLMSampleHeader) == 71);
+MPT_BINARY_STRUCT(PLMSampleHeader, 71)
 
 
-struct PACKED PLMPatternHeader
+struct PLMPatternHeader
 {
-	uint32 size;
-	uint8  numRows;
-	uint8  numChannels;
-	uint8  color;
-	char   name[25];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(size);
-	}
+	uint32le size;
+	uint8le  numRows;
+	uint8le  numChannels;
+	uint8le  color;
+	char     name[25];
 };
 
-STATIC_ASSERT(sizeof(PLMPatternHeader) == 32);
+MPT_BINARY_STRUCT(PLMPatternHeader, 32)
 
 
-struct PACKED PLMOrderItem
+struct PLMOrderItem
 {
-	uint16 x;		// Starting position of pattern
-	uint8  y;		// Number of first channel
-	uint8  pattern;
+	uint16le x;		// Starting position of pattern
+	uint8le  y;		// Number of first channel
+	uint8le  pattern;
+};
+
+MPT_BINARY_STRUCT(PLMOrderItem, 4)
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
+
+static bool ValidateHeader(const PLMFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.magic, "PLM\x1A", 4)
+		|| fileHeader.version != 0x10
+		|| fileHeader.numChannels == 0 || fileHeader.numChannels > 32
+		|| fileHeader.headerSize < sizeof(PLMFileHeader)
+		)
 	{
-		SwapBytesLE(x);
+		return false;
 	}
-};
+	return true;
+}
 
-STATIC_ASSERT(sizeof(PLMOrderItem) == 4);
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static uint64 GetHeaderMinimumAdditionalSize(const PLMFileHeader &fileHeader)
+{
+	return fileHeader.headerSize - sizeof(PLMFileHeader) + 4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	PLMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 
 	PLMFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.magic, "PLM\x1A", 4)
-		|| fileHeader.version != 0x10
-		|| fileHeader.numChannels == 0 || fileHeader.numChannels > 32
-		|| !file.Seek(fileHeader.headerSize)
-		|| !file.CanRead(4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples)))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
+	if(!file.Seek(fileHeader.headerSize))
+	{
+		return false;
+	}
+
 	InitializeGlobals(MOD_TYPE_PLM);
 	InitializeChannels();
 	m_SongFlags = SONG_ITOLDEFFECTS;
-	m_madeWithTracker = "Disorder Tracker 2";
+	m_madeWithTracker = MPT_USTRING("Disorder Tracker 2");
 	// Some PLMs use ASCIIZ, some space-padding strings...weird. Oh, and the file browser stops at 0 bytes in the name, the main GUI doesn't.
 	mpt::String::Read<mpt::String::spacePadded>(m_songName, fileHeader.songName);
 	m_nChannels = fileHeader.numChannels + 1;	// Additional channel for writing pattern breaks
@@ -154,16 +162,11 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 	m_nSamples = fileHeader.numSamples;
 
 	std::vector<PLMOrderItem> order(fileHeader.numOrders);
-	for(uint16 i = 0; i < fileHeader.numOrders; i++)
-	{
-		PLMOrderItem ord;
-		file.ReadConvertEndianness(ord);
-		order[i] = ord;
-	}
+	file.ReadVector(order, fileHeader.numOrders);
 
-	std::vector<uint32> patternPos, samplePos;
-	file.ReadVectorLE(patternPos, fileHeader.numPatterns);
-	file.ReadVectorLE(samplePos, fileHeader.numSamples);
+	std::vector<uint32le> patternPos, samplePos;
+	file.ReadVector(patternPos, fileHeader.numPatterns);
+	file.ReadVector(samplePos, fileHeader.numSamples);
 
 	for(SAMPLEINDEX smp = 0; smp < fileHeader.numSamples; smp++)
 	{
@@ -173,7 +176,7 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 		PLMSampleHeader sampleHeader;
 		if(samplePos[smp] == 0
 			|| !file.Seek(samplePos[smp])
-			|| !file.ReadConvertEndianness(sampleHeader))
+			|| !file.ReadStruct(sampleHeader))
 				continue;
 
 		mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp + 1], sampleHeader.name);
@@ -183,7 +186,7 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 			sample.uFlags.set(CHN_PANNING);
 			sample.nPan = sampleHeader.panning * 0x11;
 		}
-		sample.nGlobalVol = std::min(sampleHeader.volume, uint8(64));
+		sample.nGlobalVol = std::min<uint8>(sampleHeader.volume, 64);
 		sample.nC5Speed = sampleHeader.sampleRate;
 		sample.nLoopStart = sampleHeader.loopStart;
 		sample.nLoopEnd = sampleHeader.loopEnd;
@@ -249,16 +252,15 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 		CMD_OFFSETPERCENTAGE,
 	};
 
-	Order.clear();
-	for(uint16 i = 0; i < fileHeader.numOrders; i++)
+	Order().clear();
+	for(const auto &ord : order)
 	{
-		const PLMOrderItem &ord = order[i];
 		if(ord.pattern >= fileHeader.numPatterns
 			|| ord.y > fileHeader.numChannels
 			|| !file.Seek(patternPos[ord.pattern])) continue;
 
 		PLMPatternHeader patHeader;
-		file.ReadConvertEndianness(patHeader);
+		file.ReadStruct(patHeader);
 		if(!patHeader.numRows) continue;
 
 		STATIC_ASSERT(ORDERINDEX_MAX >= (MPT_MAX_UNSIGNED_VALUE(ord.x) + 255) / rowsPerPat);
@@ -276,13 +278,12 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 				curRow = 0;
 				curOrd++;
 			}
-			if(curOrd >= Order.size())
+			if(curOrd >= Order().size())
 			{
-				PATTERNINDEX pat = Patterns.InsertAny(rowsPerPat);
-				Order.resize(curOrd + 1);
-				Order[curOrd] = pat;
+				Order().resize(curOrd + 1);
+				Order()[curOrd] = Patterns.InsertAny(rowsPerPat);
 			}
-			PATTERNINDEX pat = Order[curOrd];
+			PATTERNINDEX pat = Order()[curOrd];
 			if(!Patterns.IsValidPat(pat)) break;
 
 			ModCommand *m = Patterns[pat].GetpModCommand(curRow, ord.y);
@@ -315,7 +316,7 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 						m->param = 0x30 | (m->param & 0x03);
 						break;
 					case 0x0B:	// Jump to order
-						if(m->param < fileHeader.numOrders)
+						if(m->param < order.size())
 						{
 							uint16 target = order[m->param].x;
 							m->param = static_cast<ModCommand::PARAM>(target / rowsPerPat);
@@ -373,21 +374,21 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
 	// Module ends with the last row of the last order item
 	ROWINDEX endPatSize = maxPos % rowsPerPat;
 	ORDERINDEX endOrder = static_cast<ORDERINDEX>(maxPos / rowsPerPat);
-	if(endPatSize > 0 && Order.IsValidPat(endOrder))
+	if(endPatSize > 0 && Order().IsValidPat(endOrder))
 	{
-		Patterns[Order[endOrder]].Resize(endPatSize, false);
+		Patterns[Order()[endOrder]].Resize(endPatSize, false);
 	}
 	// If there are still any non-existent patterns in our order list, insert some blank patterns.
 	PATTERNINDEX blankPat = PATTERNINDEX_INVALID;
-	for(ORDERINDEX i = 0; i < Order.size(); i++)
+	for(auto &pat : Order())
 	{
-		if(Order[i] == Order.GetInvalidPatIndex())
+		if(pat == Order.GetInvalidPatIndex())
 		{
 			if(blankPat == PATTERNINDEX_INVALID)
 			{
 				blankPat = Patterns.InsertAny(rowsPerPat);
 			}
-			Order[i] = blankPat;
+			pat = blankPat;
 		}
 	}
 
diff --git a/soundlib/Load_psm.cpp b/soundlib/Load_psm.cpp
index 156a0d9..31d68a0 100644
--- a/soundlib/Load_psm.cpp
+++ b/soundlib/Load_psm.cpp
@@ -1,7 +1,7 @@
 /*
  * Load_psm.cpp
  * ------------
- * Purpose: PSM16 and new PSM (ProTracker Studio) module loader
+ * Purpose: PSM16 and new PSM (ProTracker Studio / Epic MegaGames MASI) module loader
  * Notes  : This is partly based on http://www.shikadi.net/moddingwiki/ProTracker_Studio_Module
  *          and partly reverse-engineered. Also thanks to the author of foo_dumb, the source code gave me a few clues. :)
  * Authors: Johannes Schultz
@@ -19,33 +19,23 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 ////////////////////////////////////////////////////////////
 //
 //  New PSM support starts here. PSM16 structs are below.
 //
 
 // PSM File Header
-struct PACKED PSMFileHeader
+struct PSMFileHeader
 {
-	char   formatID[4];		// "PSM " (new format)
-	uint32 fileSize;		// Filesize - 12
-	char   fileInfoID[4];	// "FILE"
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(fileSize);
-	}
+	char     formatID[4];	// "PSM " (new format)
+	uint32le fileSize;		// Filesize - 12
+	char     fileInfoID[4];	// "FILE"
 };
 
-STATIC_ASSERT(sizeof(PSMFileHeader) == 12);
+MPT_BINARY_STRUCT(PSMFileHeader, 12)
 
 // RIFF-style Chunk
-struct PACKED PSMChunk
+struct PSMChunk
 {
 	// 32-Bit chunk identifiers
 	enum ChunkIdentifiers
@@ -62,26 +52,24 @@ struct PACKED PSMChunk
 		idDSMP	= MAGIC4LE('D','S','M','P'),
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint32 id;
-	uint32 length;
+	uint32le id;
+	uint32le length;
 
 	size_t GetLength() const
 	{
-		return SwapBytesReturnLE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(PSMChunk) == 8);
+MPT_BINARY_STRUCT(PSMChunk, 8)
 
 // Song Information
-struct PACKED PSMSongHeader
+struct PSMSongHeader
 {
 	char  songType[9];		// Mostly "MAINSONG " (But not in Extreme Pinball!)
 	uint8 compression;		// 1 - uncompressed
@@ -89,36 +77,26 @@ struct PACKED PSMSongHeader
 
 };
 
-STATIC_ASSERT(sizeof(PSMSongHeader) == 11);
+MPT_BINARY_STRUCT(PSMSongHeader, 11)
 
 // Regular sample header
-struct PACKED PSMSampleHeader
+struct PSMSampleHeader
 {
-	uint8  flags;
-	char   fileName[8];		// Filename of the original module (without extension)
-	char   sampleID[4];		// INS0...INS9 (only last digit of sample ID, i.e. sample 1 and sample 11 are equal)
-	char   sampleName[33];
-	uint8  unknown1[6];		// 00 00 00 00 00 FF
-	uint16 sampleNumber;
-	uint32 sampleLength;
-	uint32 loopStart;
-	uint32 loopEnd;			// FF FF FF FF = end of sample
-	uint8  unknown3;
-	uint8  finetune;		// unused? always 0
-	uint8  defaultVolume;
-	uint32 unknown4;
-	uint32 c5Freq;			// MASI ignores the high 16 bits
-	uint8  padding[19];		// 00 ... 00
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(sampleNumber);
-		SwapBytesLE(sampleLength);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(c5Freq);
-	}
+	uint8le  flags;
+	char     fileName[8];		// Filename of the original module (without extension)
+	char     sampleID[4];		// INS0...INS9 (only last digit of sample ID, i.e. sample 1 and sample 11 are equal)
+	char     sampleName[33];
+	uint8le  unknown1[6];		// 00 00 00 00 00 FF
+	uint16le sampleNumber;
+	uint32le sampleLength;
+	uint32le loopStart;
+	uint32le loopEnd;			// FF FF FF FF = end of sample
+	uint8le  unknown3;
+	uint8le  finetune;		// unused? always 0
+	uint8le  defaultVolume;
+	uint32le unknown4;
+	uint32le c5Freq;			// MASI ignores the high 16 bits
+	char     padding[19];		// 00 ... 00
 
 	// Convert header data to OpenMPT's internal format
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -140,36 +118,26 @@ struct PACKED PSMSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(PSMSampleHeader) == 96);
+MPT_BINARY_STRUCT(PSMSampleHeader, 96)
 
 // Sinaria sample header (and possibly other games)
-struct PACKED PSMSinariaSampleHeader
+struct PSMSinariaSampleHeader
 {
-	uint8  flags;
-	char   fileName[8];		// Filename of the original module (without extension)
-	char   sampleID[8];		// INS0...INS99999
-	char   sampleName[33];
-	uint8  unknown1[6];		// 00 00 00 00 00 FF
-	uint16 sampleNumber;
-	uint32 sampleLength;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint16 unknown3;
-	uint8  finetune;		// Possibly finetune like in PSM16, but sounds even worse than just ignoring it
-	uint8  defaultVolume;
-	uint32 unknown4;
-	uint16 c5Freq;
-	char   padding[16];		// 00 ... 00
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(sampleNumber);
-		SwapBytesLE(sampleLength);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(c5Freq);
-	}
+	uint8le  flags;
+	char     fileName[8];		// Filename of the original module (without extension)
+	char     sampleID[8];		// INS0...INS99999
+	char     sampleName[33];
+	uint8le  unknown1[6];		// 00 00 00 00 00 FF
+	uint16le sampleNumber;
+	uint32le sampleLength;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint16le unknown3;
+	uint8le  finetune;		// Possibly finetune like in PSM16, but sounds even worse than just ignoring it
+	uint8le  defaultVolume;
+	uint32le unknown4;
+	uint16le c5Freq;
+	char     padding[16];		// 00 ... 00
 
 	// Convert header data to OpenMPT's internal format
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -188,11 +156,7 @@ struct PACKED PSMSinariaSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(PSMSinariaSampleHeader) == 96);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(PSMSinariaSampleHeader, 96)
 
 
 struct PSMSubSong // For internal use (pattern conversion)
@@ -200,7 +164,7 @@ struct PSMSubSong // For internal use (pattern conversion)
 	std::vector<uint8> channelPanning, channelVolume;
 	std::vector<bool> channelSurround;
 	uint8 defaultTempo, defaultSpeed;
-	char  songName[10];
+	char songName[10];
 	ORDERINDEX startOrder, endOrder, restartPos;
 
 	PSMSubSong()
@@ -219,7 +183,6 @@ struct PSMSubSong // For internal use (pattern conversion)
 
 // Portamento effect conversion (depending on format version)
 static uint8 ConvertPSMPorta(uint8 param, bool sinariaFormat)
-//-----------------------------------------------------------
 {
 	if(sinariaFormat)
 		return param;
@@ -232,7 +195,6 @@ static uint8 ConvertPSMPorta(uint8 param, bool sinariaFormat)
 
 // Read a Pattern ID (something like "P0  " or "P13 " in the old format, or "PATT0   " in Sinaria)
 static PATTERNINDEX ReadPSMPatternIndex(FileReader &file, bool &sinariaFormat)
-//----------------------------------------------------------------------------
 {
 	char patternID[5];
 	uint8 offset = 1;
@@ -244,16 +206,54 @@ static PATTERNINDEX ReadPSMPatternIndex(FileReader &file, bool &sinariaFormat)
 		offset = 0;
 	}
 	return ConvertStrTo<uint16>(&patternID[offset]);
+}
+
+
+static bool ValidateHeader(const PSMFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.formatID, "PSM ", 4)
+		|| std::memcmp(fileHeader.fileInfoID, "FILE", 4))
+	{
+		return false;
+	}
+	return true;
+}
+
 
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	PSMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	PSMChunk chunkHeader;
+	if(!file.ReadStruct(chunkHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(chunkHeader.length == 0)
+	{
+		return ProbeFailure;
+	}
+	if((chunkHeader.id & 0x7f7f7f7fu) != chunkHeader.id) // ASCII?
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
 }
 
 
 bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 	PSMFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
 	}
@@ -268,20 +268,19 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 			return true;
 		file.Rewind();
 		decrypted.resize(file.GetLength());
-		file.ReadRaw(&decrypted[0], decrypted.size());
+		file.ReadRaw(decrypted.data(), decrypted.size());
 		uint8 i = 0;
-		for(std::vector<mpt::byte>::iterator c = decrypted.begin(); c != decrypted.end(); c++)
+		for(auto &c : decrypted)
 		{
-			*c -= ++i;
+			c -= ++i;
 		}
 		file = FileReader(mpt::as_span(decrypted));
-		file.ReadConvertEndianness(fileHeader);
+		file.ReadStruct(fileHeader);
 	}
 #endif // MPT_PSM_DECRYPT
 
 	// Check header
-	if(memcmp(fileHeader.formatID, "PSM ", 4)
-		|| memcmp(fileHeader.fileInfoID, "FILE", 4))
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
 	}
@@ -307,17 +306,16 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 	FileReader titleChunk = chunks.GetChunk(PSMChunk::idTITL);
 	titleChunk.ReadString<mpt::String::spacePadded>(m_songName, titleChunk.GetLength());
 
-	Order.clear();
+	Order().clear();
 	// Subsong setup
 	std::vector<PSMSubSong> subsongs;
 	bool subsongPanningDiffers = false; // Do we have subsongs with different panning positions?
 	bool sinariaFormat = false; // The game "Sinaria" uses a slightly modified PSM structure - in some ways it's more like PSM16 (e.g. effects).
 
 	// "SONG" - Subsong information (channel count etc)
-	std::vector<FileReader> songChunks = chunks.GetAllChunks(PSMChunk::idSONG);
-	for(std::vector<FileReader>::iterator subsongIter = songChunks.begin(); subsongIter != songChunks.end(); subsongIter++)
+	auto songChunks = chunks.GetAllChunks(PSMChunk::idSONG);
+	for(ChunkReader chunk : songChunks)
 	{
-		ChunkReader chunk(*subsongIter);
 		PSMSongHeader songHeader;
 		if(!chunk.ReadStruct(songHeader)
 			|| songHeader.compression != 0x01)	// No compression for PSM files
@@ -331,22 +329,21 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 		mpt::String::Read<mpt::String::nullTerminated>(subsong.songName, songHeader.songType);
 
 #ifdef MPT_PSM_USE_REAL_SUBSONGS
-		if(Order.GetLength() != 0)
+		if(!Order().empty())
 		{
 			// Add a new sequence for this subsong
 			if(Order.AddSequence(false) == SEQUENCEINDEX_INVALID)
 				break;
-			Order.clear();
 		}
-		Order.SetName(subsong.songName);
+		Order().SetName(subsong.songName);
 #endif // MPT_PSM_USE_REAL_SUBSONGS
 
 		// Read "Sub chunks"
-		ChunkReader::ChunkList<PSMChunk> subChunks = chunk.ReadChunks<PSMChunk>(1);
-		for(ChunkReader::ChunkList<PSMChunk>::iterator subChunkIter = subChunks.begin(); subChunkIter != subChunks.end(); subChunkIter++)
+		auto subChunks = chunk.ReadChunks<PSMChunk>(1);
+		for(const auto &subChunkIter : subChunks)
 		{
-			FileReader subChunk(subChunkIter->GetData());
-			PSMChunk subChunkHead = subChunkIter->GetHeader();
+			FileReader subChunk(subChunkIter.GetData());
+			PSMChunk subChunkHead = subChunkIter.GetHeader();
 			
 			switch(subChunkHead.GetID())
 			{
@@ -395,14 +392,14 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 						case 0x01: // Play order list item
 							{
 								if(subsong.startOrder == ORDERINDEX_INVALID)
-									subsong.startOrder = Order.size();
-								subsong.endOrder = Order.size();
+									subsong.startOrder = Order().GetLength();
+								subsong.endOrder = Order().GetLength();
 								PATTERNINDEX pat = ReadPSMPatternIndex(subChunk, sinariaFormat);
 								if(pat == 0xFF)
 									pat = Order.GetInvalidPatIndex();
 								else if(pat == 0xFE)
 									pat = Order.GetIgnoreIndex();
-								Order.Append(pat);
+								Order().push_back(pat);
 								// Decide whether this is the first order chunk or not (for finding out the correct restart position)
 								if(firstOrderChunk == uint16_max)
 									firstOrderChunk = chunkCount;
@@ -417,7 +414,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 								uint16 restartChunk = subChunk.ReadUint16LE();
 								if(restartChunk >= firstOrderChunk)
 									subsong.restartPos = static_cast<ORDERINDEX>(restartChunk - firstOrderChunk);	// Close enough - we assume that order list is continuous (like in any real-world PSM)
-								Order.SetRestartPos(subsong.restartPos);
+								Order().SetRestartPos(subsong.restartPos);
 							}
 							break;
 
@@ -553,7 +550,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 		if(subsong.startOrder != ORDERINDEX_INVALID && subsong.endOrder != ORDERINDEX_INVALID)
 		{
 			// Separate subsongs by "---" patterns
-			Order.Append();
+			Order().push_back();
 			subsongs.push_back(subsong);
 		}
 	}
@@ -568,16 +565,15 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 	// DSMP - Samples
 	if(loadFlags & loadSampleData)
 	{
-		std::vector<FileReader> sampleChunks = chunks.GetAllChunks(PSMChunk::idDSMP);
-		for(std::vector<FileReader>::iterator sampleIter = sampleChunks.begin(); sampleIter != sampleChunks.end(); sampleIter++)
+		auto sampleChunks = chunks.GetAllChunks(PSMChunk::idDSMP);
+		for(auto &chunk : sampleChunks)
 		{
-			FileReader &chunk(*sampleIter);
 			SAMPLEINDEX smp;
 			if(!sinariaFormat)
 			{
 				// Original header
 				PSMSampleHeader sampleHeader;
-				if(!chunk.ReadConvertEndianness(sampleHeader))
+				if(!chunk.ReadStruct(sampleHeader))
 				{
 					continue;
 				}
@@ -594,7 +590,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 			{
 				// Sinaria uses a slightly different sample header
 				PSMSinariaSampleHeader sampleHeader;
-				if(!chunk.ReadConvertEndianness(sampleHeader))
+				if(!chunk.ReadStruct(sampleHeader))
 				{
 					continue;
 				}
@@ -622,7 +618,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 	// Make the default variables of the first subsong global
 	m_nDefaultSpeed = subsongs[0].defaultSpeed;
 	m_nDefaultTempo.Set(subsongs[0].defaultTempo);
-	Order.SetRestartPos(subsongs[0].restartPos);
+	Order().SetRestartPos(subsongs[0].restartPos);
 	for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
 	{
 		ChnSettings[chn].Reset();
@@ -631,7 +627,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 		ChnSettings[chn].dwFlags.set(CHN_SURROUND, subsongs[0].channelSurround[chn]);
 	}
 
-	m_madeWithTracker = sinariaFormat ? "Epic MegaGames MASI (New Version / Sinaria)" : "Epic MegaGames MASI (New Version)";
+	m_madeWithTracker = sinariaFormat ? MPT_USTRING("Epic MegaGames MASI (New Version / Sinaria)") : MPT_USTRING("Epic MegaGames MASI (New Version)");
 
 	if(!(loadFlags & loadPatternData) || m_nChannels == 0)
 	{
@@ -640,10 +636,10 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 
 	// "PBOD" - Pattern data of a single pattern
 	// Now that we know the number of channels, we can go through all the patterns.
-	std::vector<FileReader> pattChunks = chunks.GetAllChunks(PSMChunk::idPBOD);
-	for(std::vector<FileReader>::iterator patternIter = pattChunks.begin(); patternIter != pattChunks.end(); patternIter++)
+	auto pattChunks = chunks.GetAllChunks(PSMChunk::idPBOD);
+	Patterns.ResizeArray(static_cast<PATTERNINDEX>(pattChunks.size()));
+	for(auto &chunk : pattChunks)
 	{
-		FileReader &chunk(*patternIter);
 		if(chunk.GetLength() != chunk.ReadUint32LE()	// Same value twice
 			|| !chunk.LengthIsAtLeast(8))
 		{
@@ -887,9 +883,9 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 		for(size_t i = 0; i < subsongs.size(); i++)
 		{
 #ifdef MPT_PSM_USE_REAL_SUBSONGS
-			ModSequence &order = Order.GetSequence(static_cast<SEQUENCEINDEX>(i));
+			ModSequence &order = Order(static_cast<SEQUENCEINDEX>(i));
 #else
-			ModSequence &order = Order;
+			ModSequence &order = Order();
 #endif // MPT_PSM_USE_REAL_SUBSONGS
 			const PSMSubSong &subsong = subsongs[i];
 			PATTERNINDEX startPattern = order[subsong.startOrder];
@@ -903,14 +899,14 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 					for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
 					{
 						if(subsong.channelSurround[chn])
-							Patterns[startPattern].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x91).Row(0).Channel(chn).Retry(EffectWriter::rmTryNextRow));
+							Patterns[startPattern].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x91).Row(0).Channel(chn).RetryNextRow());
 						else
-							Patterns[startPattern].WriteEffect(EffectWriter(CMD_PANNING8, subsong.channelPanning[chn]).Row(0).Channel(chn).Retry(EffectWriter::rmTryNextRow));
+							Patterns[startPattern].WriteEffect(EffectWriter(CMD_PANNING8, subsong.channelPanning[chn]).Row(0).Channel(chn).RetryNextRow());
 					}
 				}
 				// Write default tempo/speed to pattern
-				Patterns[startPattern].WriteEffect(EffectWriter(CMD_SPEED, subsong.defaultSpeed).Row(0).Retry(EffectWriter::rmTryNextRow));
-				Patterns[startPattern].WriteEffect(EffectWriter(CMD_TEMPO, subsong.defaultTempo).Row(0).Retry(EffectWriter::rmTryNextRow));
+				Patterns[startPattern].WriteEffect(EffectWriter(CMD_SPEED, subsong.defaultSpeed).Row(0).RetryNextRow());
+				Patterns[startPattern].WriteEffect(EffectWriter(CMD_TEMPO, subsong.defaultTempo).Row(0).RetryNextRow());
 			}
 
 #ifndef MPT_PSM_USE_REAL_SUBSONGS
@@ -920,8 +916,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 			{
 				endPattern = order.EnsureUnique(subsong.endOrder);
 				ROWINDEX lastRow = Patterns[endPattern].GetNumRows() - 1;
-				ModCommand *m;
-				m = Patterns[endPattern];
+				auto m = Patterns[endPattern].cbegin();
 				for(uint32 cell = 0; cell < m_nChannels * Patterns[endPattern].GetNumRows(); cell++, m++)
 				{
 					if(m->command == CMD_PATTERNBREAK || m->command == CMD_POSITIONJUMP)
@@ -930,7 +925,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 						break;
 					}
 				}
-				Patterns[endPattern].WriteEffect(EffectWriter(CMD_POSITIONJUMP, mpt::saturate_cast<ModCommand::PARAM>(subsong.startOrder + subsong.restartPos)).Row(lastRow).Retry(EffectWriter::rmTryPreviousRow));
+				Patterns[endPattern].WriteEffect(EffectWriter(CMD_POSITIONJUMP, mpt::saturate_cast<ModCommand::PARAM>(subsong.startOrder + subsong.restartPos)).Row(lastRow).RetryPreviousRow());
 			}
 
 			// Set the subsong name to all pattern names
@@ -951,65 +946,35 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
 //  PSM16 support starts here.
 //
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED PSM16FileHeader
+struct PSM16FileHeader
 {
-	// 32-Bit chunk identifiers
-	enum PSM16Magic
-	{
-		idPORD	= MAGIC4LE('P','O','R','D'),
-		idPPAN	= MAGIC4LE('P','P','A','N'),
-		idPSAH	= MAGIC4LE('P','S','A','H'),
-		idPPAT	= MAGIC4LE('P','P','A','T'),
-	};
-
-	char   formatID[4];		// "PSM\xFE" (PSM16)
-	char   songName[59];	// Song title, padded with nulls
-	uint8  lineEnd;			// $1A
-	uint8  songType;		// Song Type bitfield
-	uint8  formatVersion;	// $10
-	uint8  patternVersion;  // 0 or 1
-	uint8  songSpeed;		// 1 ... 255
-	uint8  songTempo;		// 32 ... 255
-	uint8  masterVolume;	// 0 ... 255
-	uint16 songLength;		// 0 ... 255 (number of patterns to play in the song)
-	uint16 songOrders;		// 0 ... 255 (same as previous value as no subsongs are present)
-	uint16 numPatterns;		// 1 ... 255
-	uint16 numSamples;		// 1 ... 255
-	uint16 numChannelsPlay;	// 0 ... 32 (max. number of channels to play)
-	uint16 numChannelsReal;	// 0 ... 32 (max. number of channels to process)
-	uint32 orderOffset;		// Pointer to order list
-	uint32 panOffset;		// Pointer to pan table
-	uint32 patOffset;		// Pointer to pattern data
-	uint32 smpOffset;		// Pointer to sample headers
-	uint32 commentsOffset;	// Pointer to song comment
-	uint32 patSize;			// Size of all patterns
-	uint8  filler[40];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(songLength);
-		SwapBytesLE(songOrders);
-		SwapBytesLE(numPatterns);
-		SwapBytesLE(numSamples);
-		SwapBytesLE(numChannelsPlay);
-		SwapBytesLE(numChannelsReal);
-		SwapBytesLE(orderOffset);
-		SwapBytesLE(panOffset);
-		SwapBytesLE(patOffset);
-		SwapBytesLE(smpOffset);
-		SwapBytesLE(commentsOffset);
-		SwapBytesLE(patSize);
-	}
+	char     formatID[4];		// "PSM\xFE" (PSM16)
+	char     songName[59];		// Song title, padded with nulls
+	uint8le  lineEnd;			// $1A
+	uint8le  songType;			// Song Type bitfield
+	uint8le  formatVersion;		// $10
+	uint8le  patternVersion;	// 0 or 1
+	uint8le  songSpeed;			// 1 ... 255
+	uint8le  songTempo;			// 32 ... 255
+	uint8le  masterVolume;		// 0 ... 255
+	uint16le songLength;		// 0 ... 255 (number of patterns to play in the song)
+	uint16le songOrders;		// 0 ... 255 (same as previous value as no subsongs are present)
+	uint16le numPatterns;		// 1 ... 255
+	uint16le numSamples;		// 1 ... 255
+	uint16le numChannelsPlay;	// 0 ... 32 (max. number of channels to play)
+	uint16le numChannelsReal;	// 0 ... 32 (max. number of channels to process)
+	uint32le orderOffset;		// Pointer to order list
+	uint32le panOffset;			// Pointer to pan table
+	uint32le patOffset;			// Pointer to pattern data
+	uint32le smpOffset;			// Pointer to sample headers
+	uint32le commentsOffset;	// Pointer to song comment
+	uint32le patSize;			// Size of all patterns
+	char     filler[40];
 };
 
-STATIC_ASSERT(sizeof(PSM16FileHeader) == 146);
+MPT_BINARY_STRUCT(PSM16FileHeader, 146)
 
-struct PACKED PSM16SampleHeader
+struct PSM16SampleHeader
 {
 	enum SampleFlags
 	{
@@ -1021,30 +986,18 @@ struct PACKED PSM16SampleHeader
 		smpLoop		= 0x80,
 	};
 
-	char   filename[13];	// null-terminated
-	char   name[24];		// ditto
-	uint32 offset;			// in file
-	uint32 memoffset;		// not used
-	uint16 sampleNumber;	// 1 ... 255
-	uint8  flags;			// sample flag bitfield
-	uint32 length;			// in bytes
-	uint32 loopStart;		// in samples?
-	uint32 loopEnd;			// in samples?
-	uint8  finetune;		// Low nibble = MOD finetune, high nibble = transpose (7 = center)
-	uint8  volume;			// default volume
-	uint16 c2freq;			// Middle-C frequency, which has to be combined with the finetune and transpose.
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(offset);
-		SwapBytesLE(memoffset);
-		SwapBytesLE(sampleNumber);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(c2freq);
-	}
+	char     filename[13];	// null-terminated
+	char     name[24];		// ditto
+	uint32le offset;		// in file
+	uint32le memoffset;		// not used
+	uint16le sampleNumber;	// 1 ... 255
+	uint8le  flags;			// sample flag bitfield
+	uint32le length;		// in bytes
+	uint32le loopStart;		// in samples?
+	uint32le loopEnd;		// in samples?
+	uint8le  finetune;		// Low nibble = MOD finetune, high nibble = transpose (7 = center)
+	uint8le  volume;		// default volume
+	uint16le c2freq;		// Middle-C frequency, which has to be combined with the finetune and transpose.
 
 	// Convert sample header to OpenMPT's internal format
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -1057,15 +1010,16 @@ struct PACKED PSM16SampleHeader
 		mptSmp.nLoopEnd = loopEnd;
 		// It seems like that finetune and transpose are added to the already given c2freq... That's a double WTF!
 		// Why on earth would you want to use both systems at the same time?
-		mptSmp.nC5Speed = Util::Round<uint32>(c2freq * std::pow(2.0, ((finetune ^ 0x08) - 0x78) / (12.0 * 16.0))); // ModSample::TransposeToFrequency(mptSmp.RelativeTone + (finetune >> 4) - 7, MOD2XMFineTune(finetune & 0x0F));
+		mptSmp.nC5Speed = c2freq;
+		mptSmp.Transpose(((finetune ^ 0x08) - 0x78) / (12.0 * 16.0));
 
-		mptSmp.nVolume = std::min<uint8>(volume, 64) * 4;
+		mptSmp.nVolume = std::min<uint8>(volume, 64u) * 4u;
 
 		mptSmp.uFlags.reset();
 		if(flags & PSM16SampleHeader::smp16Bit)
 		{
 			mptSmp.uFlags.set(CHN_16BIT);
-			mptSmp.nLength /= 2;
+			mptSmp.nLength /= 2u;
 		}
 		if(flags & PSM16SampleHeader::smpPingPong)
 		{
@@ -1098,53 +1052,73 @@ struct PACKED PSM16SampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(PSM16SampleHeader) == 64);
+MPT_BINARY_STRUCT(PSM16SampleHeader, 64)
 
-struct PACKED PSM16PatternHeader
+struct PSM16PatternHeader
 {
-	uint16 size;		// includes header bytes
-	uint8  numRows;		// 1 ... 64
-	uint8  numChans;	// 1 ... 32
+	uint16le size;		// includes header bytes
+	uint8le  numRows;	// 1 ... 64
+	uint8le  numChans;	// 1 ... 32
+};
+
+MPT_BINARY_STRUCT(PSM16PatternHeader, 4)
+
 
-	void ConvertEndianness()
+static bool ValidateHeader(const PSM16FileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.formatID, "PSM\xFE", 4)
+		|| fileHeader.lineEnd != 0x1A
+		|| (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01?
+		|| fileHeader.patternVersion != 0 // 255ch pattern version not supported (did anyone use this?)
+		|| (fileHeader.songType & 3) != 0
+		|| fileHeader.numChannelsPlay > MAX_BASECHANNELS
+		|| fileHeader.numChannelsReal > MAX_BASECHANNELS
+		|| std::max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0)
 	{
-		SwapBytesLE(size);
+		return false;
 	}
-};
+	return true;
+}
 
-STATIC_ASSERT(sizeof(PSM16PatternHeader) == 4);
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize)
+{
+	PSM16FileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
 
 
 bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
-//---------------------------------------------------------------------
 {
 	file.Rewind();
 
 	// Is it a valid PSM16 file?
 	PSM16FileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.formatID, "PSM\xFE", 4)
-		|| fileHeader.lineEnd != 0x1A
-		|| (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01?
-		|| fileHeader.patternVersion != 0 // 255ch pattern version not supported (did anyone use this?)
-		|| (fileHeader.songType & 3) != 0
-		|| fileHeader.numChannelsPlay > MAX_BASECHANNELS
-		|| fileHeader.numChannelsReal > MAX_BASECHANNELS
-		|| std::max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0)
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
 
 	// Seems to be valid!
 	InitializeGlobals(MOD_TYPE_PSM);
-	m_madeWithTracker = "Epic MegaGames MASI (Old Version)";
+	m_madeWithTracker = MPT_USTRING("Epic MegaGames MASI (Old Version)");
 	m_nChannels = Clamp(CHANNELINDEX(fileHeader.numChannelsPlay), CHANNELINDEX(fileHeader.numChannelsReal), MAX_BASECHANNELS);
 	m_nSamplePreAmp = fileHeader.masterVolume;
 	if(m_nSamplePreAmp == 255)
@@ -1158,13 +1132,13 @@ bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
 	mpt::String::Read<mpt::String::spacePadded>(m_songName, fileHeader.songName);
 
 	// Read orders
-	if(fileHeader.orderOffset > 4 && file.Seek(fileHeader.orderOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPORD)
+	if(fileHeader.orderOffset > 4 && file.Seek(fileHeader.orderOffset - 4) && file.ReadMagic("PORD"))
 	{
-		Order.ReadAsByte(file, fileHeader.songOrders);
+		ReadOrderFromFile<uint8>(Order(), file, fileHeader.songOrders);
 	}
 
 	// Read pan positions
-	if(fileHeader.panOffset > 4 && file.Seek(fileHeader.panOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPPAN)
+	if(fileHeader.panOffset > 4 && file.Seek(fileHeader.panOffset - 4) && file.ReadMagic("PPAN"))
 	{
 		for(CHANNELINDEX i = 0; i < 32; i++)
 		{
@@ -1175,14 +1149,14 @@ bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Read samples
-	if(fileHeader.smpOffset > 4 && file.Seek(fileHeader.smpOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPSAH)
+	if(fileHeader.smpOffset > 4 && file.Seek(fileHeader.smpOffset - 4) && file.ReadMagic("PSAH"))
 	{
 		FileReader sampleChunk = file.ReadChunk(fileHeader.numSamples * sizeof(PSM16SampleHeader));
 
 		for(SAMPLEINDEX fileSample = 0; fileSample < fileHeader.numSamples; fileSample++)
 		{
 			PSM16SampleHeader sampleHeader;
-			if(!sampleChunk.ReadConvertEndianness(sampleHeader))
+			if(!sampleChunk.ReadStruct(sampleHeader))
 			{
 				break;
 			}
@@ -1209,12 +1183,13 @@ bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		return true;
 	}
-	if(fileHeader.patOffset > 4 && file.Seek(fileHeader.patOffset - 4) && file.ReadUint32LE() == PSM16FileHeader::idPPAT)
+	if(fileHeader.patOffset > 4 && file.Seek(fileHeader.patOffset - 4) && file.ReadMagic("PPAT"))
 	{
+		Patterns.ResizeArray(fileHeader.numPatterns);
 		for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
 		{
 			PSM16PatternHeader patternHeader;
-			if(!file.ReadConvertEndianness(patternHeader))
+			if(!file.ReadStruct(patternHeader))
 			{
 				break;
 			}
@@ -1426,7 +1401,7 @@ bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
 			// Pattern break for short patterns (so saving the modules as S3M won't break it)
 			if(patternHeader.numRows != 64)
 			{
-				Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(patternHeader.numRows - 1).Retry(EffectWriter::rmTryNextRow));
+				Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(patternHeader.numRows - 1).RetryNextRow());
 			}
 		}
 	}
diff --git a/soundlib/Load_ptm.cpp b/soundlib/Load_ptm.cpp
index 495ee2f..8af92ea 100644
--- a/soundlib/Load_ptm.cpp
+++ b/soundlib/Load_ptm.cpp
@@ -14,47 +14,29 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED PTMFileHeader
+struct PTMFileHeader
 {
-	char   songname[28];	// Name of song, asciiz string
-	uint8  dosEOF;			// 26
-	uint8  versionLo;		// 03 version of file, currently 0203h
-	uint8  versionHi;		// 02
-	uint8  reserved1;		// Reserved, set to 0
-	uint16 numOrders;		// Number of orders (0..256)
-	uint16 numSamples;		// Number of instruments (1..255)
-	uint16 numPatterns;		// Number of patterns (1..128)
-	uint16 numChannels;		// Number of channels (voices) used (1..32)
-	uint16 flags;			// Set to 0
-	uint8  reserved2[2];	// Reserved, set to 0
-	char   magic[4];		// Song identification, 'PTMF'
-	uint8  reserved3[16];	// Reserved, set to 0
-	uint8  chnPan[32];		// Channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
-	uint8  orders[256];		// Order list, valid entries 0..nOrders-1
-	uint16 patOffsets[128];	// Pattern offsets (*16)
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numOrders);
-		SwapBytesLE(numSamples);
-		SwapBytesLE(numPatterns);
-		SwapBytesLE(numChannels);
-		SwapBytesLE(flags);
-		for(std::size_t i = 0; i < CountOf(patOffsets); i++)
-		{
-			SwapBytesLE(patOffsets[i]);
-		}
-	}
+	char     songname[28];		// Name of song, asciiz string
+	uint8le  dosEOF;			// 26
+	uint8le  versionLo;			// 03 version of file, currently 0203h
+	uint8le  versionHi;			// 02
+	uint8le  reserved1;			// Reserved, set to 0
+	uint16le numOrders;			// Number of orders (0..256)
+	uint16le numSamples;		// Number of instruments (1..255)
+	uint16le numPatterns;		// Number of patterns (1..128)
+	uint16le numChannels;		// Number of channels (voices) used (1..32)
+	uint16le flags;				// Set to 0
+	uint8le  reserved2[2];		// Reserved, set to 0
+	char     magic[4];			// Song identification, 'PTMF'
+	uint8le  reserved3[16];		// Reserved, set to 0
+	uint8le  chnPan[32];		// Channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
+	uint8le  orders[256];		// Order list, valid entries 0..nOrders-1
+	uint16le patOffsets[128];	// Pattern offsets (*16)
 };
 
-STATIC_ASSERT(sizeof(PTMFileHeader) == 608);
+MPT_BINARY_STRUCT(PTMFileHeader, 608)
 
-struct PACKED PTMSampleHeader
+struct PTMSampleHeader
 {
 	enum SampleFlags
 	{
@@ -66,34 +48,24 @@ struct PACKED PTMSampleHeader
 		smp16Bit	= 0x10,
 	};
 
-	uint8  flags;			// Sample type (see SampleFlags)
-	char   filename[12];	// Name of external sample file
-	uint8  volume;			// Default volume
-	uint16 c4speed;			// C-4 speed (yep, not C-5)
-	uint8  smpSegment[2];	// Sample segment (used internally)
-	uint32 dataOffset;		// Offset of sample data
-	uint32 length;			// Sample size (in bytes)
-	uint32 loopStart;		// Start of loop
-	uint32 loopEnd;			// End of loop
-	uint8  gusdata[14];
-	char   samplename[28];	// Name of sample, ASCIIZ
-	char   magic[4];		// Sample identification, 'PTMS'
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(c4speed);
-		SwapBytesLE(dataOffset);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-	}
+	uint8le  flags;				// Sample type (see SampleFlags)
+	char     filename[12];		// Name of external sample file
+	uint8le  volume;			// Default volume
+	uint16le c4speed;			// C-4 speed (yep, not C-5)
+	uint8le  smpSegment[2];		// Sample segment (used internally)
+	uint32le dataOffset;		// Offset of sample data
+	uint32le length;			// Sample size (in bytes)
+	uint32le loopStart;			// Start of loop
+	uint32le loopEnd;			// End of loop
+	uint8le  gusdata[14];
+	char     samplename[28];	// Name of sample, ASCIIZ
+	char     magic[4];			// Sample identification, 'PTMS'
 
 	// Convert an PTM sample header to OpenMPT's internal sample header.
 	SampleIO ConvertToMPT(ModSample &mptSmp) const
 	{
 		mptSmp.Initialize(MOD_TYPE_S3M);
-		mptSmp.nVolume = std::min(volume, uint8(64)) * 4;
+		mptSmp.nVolume = std::min<uint8>(volume, 64) * 4;
 		mptSmp.nC5Speed = c4speed * 2;
 
 		mpt::String::Read<mpt::String::maybeNullTerminated>(mptSmp.filename, filename);
@@ -129,21 +101,12 @@ struct PACKED PTMSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(PTMSampleHeader) == 80);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(PTMSampleHeader, 80)
 
 
-bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const PTMFileHeader &fileHeader)
 {
-	file.Rewind();
-
-	PTMFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.magic, "PTMF", 4)
+	if(std::memcmp(fileHeader.magic, "PTMF", 4)
 		|| fileHeader.dosEOF != 26
 		|| fileHeader.versionHi > 2
 		|| fileHeader.flags != 0
@@ -152,10 +115,53 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
 		|| !fileHeader.numOrders || fileHeader.numOrders > 256
 		|| !fileHeader.numSamples || fileHeader.numSamples > 255
 		|| !fileHeader.numPatterns || fileHeader.numPatterns > 128
-		|| !file.CanRead(fileHeader.numSamples * sizeof(PTMSampleHeader)))
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PTMFileHeader &fileHeader)
+{
+	return fileHeader.numSamples * sizeof(PTMSampleHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	PTMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+
+	PTMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -164,11 +170,11 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
 
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songname);
 
-	m_madeWithTracker = mpt::String::Print("PolyTracker %1.%2", fileHeader.versionHi, mpt::fmt::hex0<2>(fileHeader.versionLo));
+	m_madeWithTracker = mpt::format(MPT_USTRING("PolyTracker %1.%2"))(fileHeader.versionHi.get(), mpt::ufmt::hex0<2>(fileHeader.versionLo.get()));
 	m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS;
 	m_nChannels = fileHeader.numChannels;
 	m_nSamples = std::min<SAMPLEINDEX>(fileHeader.numSamples, MAX_SAMPLES - 1);
-	Order.ReadFromArray(fileHeader.orders, fileHeader.numOrders, 0xFF, 0xFE);
+	ReadOrderFromArray(Order(), fileHeader.orders, fileHeader.numOrders, 0xFF, 0xFE);
 
 	// Reading channel panning
 	for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
@@ -182,7 +188,7 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
 	for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++)
 	{
 		PTMSampleHeader sampleHeader;
-		sampleHeaderChunk.ReadConvertEndianness(sampleHeader);
+		sampleHeaderChunk.ReadStruct(sampleHeader);
 
 		ModSample &sample = Samples[smp + 1];
 		mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp + 1], sampleHeader.samplename);
@@ -200,6 +206,7 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
 		return true;
 	}
 
+	Patterns.ResizeArray(fileHeader.numPatterns);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
 	{
 		if(!Patterns.Insert(pat, 64)
@@ -209,7 +216,7 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
 			continue;
 		}
 
-		ModCommand *rowBase = Patterns[pat];
+		ModCommand *rowBase = Patterns[pat].GetpModCommand(0, 0);
 		ROWINDEX row = 0;
 		while(row < 64 && file.CanRead(1))
 		{
@@ -239,7 +246,7 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
 				m.command = file.ReadUint8();
 				m.param = file.ReadUint8();
 
-				const ModCommand::COMMAND effTrans[] = { CMD_GLOBALVOLUME, CMD_RETRIG, CMD_FINEVIBRATO, CMD_NOTESLIDEUP, CMD_NOTESLIDEDOWN, CMD_NOTESLIDEUPRETRIG, CMD_NOTESLIDEDOWNRETRIG, CMD_REVERSEOFFSET };
+				static const EffectCommand effTrans[] = { CMD_GLOBALVOLUME, CMD_RETRIG, CMD_FINEVIBRATO, CMD_NOTESLIDEUP, CMD_NOTESLIDEDOWN, CMD_NOTESLIDEUPRETRIG, CMD_NOTESLIDEDOWNRETRIG, CMD_REVERSEOFFSET };
 				if(m.command < 0x10)
 				{
 					// Beware: Effect letters are as in MOD, but portamento and volume slides behave like in S3M (i.e. fine slides share the same effect letters)
diff --git a/soundlib/Load_s3m.cpp b/soundlib/Load_s3m.cpp
index 5c44d10..2064017 100644
--- a/soundlib/Load_s3m.cpp
+++ b/soundlib/Load_s3m.cpp
@@ -13,7 +13,10 @@
 #include "S3MTools.h"
 #ifndef MODPLUG_NO_FILESAVE
 #include "../common/mptFileIO.h"
-#endif
+#ifdef MODPLUG_TRACKER
+#include "../mptrack/TrackerSettings.h"
+#endif // MODPLUG_TRACKER
+#endif // MODPLUG_NO_FILESAVE
 #include "../common/version.h"
 
 
@@ -21,7 +24,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 void CSoundFile::S3MConvert(ModCommand &m, bool fromIT)
-//-----------------------------------------------------
 {
 	switch(m.command | 0x40)
 	{
@@ -61,7 +63,6 @@ void CSoundFile::S3MConvert(ModCommand &m, bool fromIT)
 
 
 void CSoundFile::S3MSaveConvert(uint8 &command, uint8 &param, bool toIT, bool compatibilityExport) const
-//------------------------------------------------------------------------------------------------------
 {
 	switch(command)
 	{
@@ -169,36 +170,59 @@ enum S3MPattern
 };
 
 
-// Functor for fixing PixPlay 4-Bit Zxx panning commands
-struct FixPixPlayPanning
-//======================
+static bool ValidateHeader(const S3MFileHeader &fileHeader)
 {
-	void operator()(ModCommand& m)
+	if(std::memcmp(fileHeader.magic, "SCRM", 4)
+		|| fileHeader.fileType != S3MFileHeader::idS3MType
+		|| (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion)
+		)
 	{
-		if(m.command == CMD_MIDI)
-		{
-			m.command = CMD_S3MCMDEX;
-			m.param |= 0x80;
-		}
+		return false;
 	}
-};
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const S3MFileHeader &fileHeader)
+{
+	return fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize)
+{
+	S3MFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 
 	// Is it a valid S3M file?
 	S3MFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| !file.CanRead(fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2)
-		|| memcmp(fileHeader.magic, "SCRM", 4)
-		|| fileHeader.fileType != S3MFileHeader::idS3MType
-		|| (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion))
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -210,7 +234,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 	// ST3 ignored Zxx commands, so if we find that a file was made with ST3, we should erase all MIDI macros.
 	bool keepMidiMacros = false;
 
-	std::string trackerStr;
+	mpt::ustring trackerStr;
 	bool nonCompatTracker = false;
 	bool isST3 = false;
 	switch(fileHeader.cwtv & S3MFileHeader::trackerMask)
@@ -220,35 +244,35 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 		{
 			// MPT 1.16 and older versions of OpenMPT - Simply keep default (filter) MIDI macros
 			m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00);
-			m_madeWithTracker = "ModPlug Tracker / OpenMPT";
+			m_madeWithTracker = MPT_USTRING("ModPlug Tracker / OpenMPT");
 			keepMidiMacros = true;
 			nonCompatTracker = true;
 			m_playBehaviour.set(kST3LimitPeriod);
 		} else if(fileHeader.cwtv == S3MFileHeader::trkST3_20 && fileHeader.special == 0 && fileHeader.ultraClicks == 0 && fileHeader.flags == 0 && fileHeader.usePanningTable == 0)
 		{
-			m_madeWithTracker = "Velvet Studio";
+			m_madeWithTracker = MPT_USTRING("Velvet Studio");
 		} else
 		{
-			trackerStr = "Scream Tracker";
+			trackerStr = MPT_USTRING("Scream Tracker");
 			isST3 = true;
 		}
 		break;
 	case S3MFileHeader::trkImagoOrpheus:
-		trackerStr = "Imago Orpheus";
+		trackerStr = MPT_USTRING("Imago Orpheus");
 		nonCompatTracker = true;
 		break;
 	case S3MFileHeader::trkImpulseTracker:
 		if(fileHeader.cwtv <= S3MFileHeader::trkIT2_14)
-			trackerStr = "Impulse Tracker";
+			trackerStr = MPT_USTRING("Impulse Tracker");
 		else
-			m_madeWithTracker = mpt::String::Print("Impulse Tracker 2.14p%1", fileHeader.cwtv - S3MFileHeader::trkIT2_14);
+			m_madeWithTracker = mpt::format(MPT_USTRING("Impulse Tracker 2.14p%1"))(fileHeader.cwtv - S3MFileHeader::trkIT2_14);
 		nonCompatTracker = true;
 		m_nMinPeriod = 1;
 		break;
 	case S3MFileHeader::trkSchismTracker:
 		if(fileHeader.cwtv == S3MFileHeader::trkBeRoTrackerOld)
 		{
-			m_madeWithTracker = "BeRoTracker";
+			m_madeWithTracker = MPT_USTRING("BeRoTracker");
 			m_playBehaviour.set(kST3LimitPeriod);
 		} else
 		{
@@ -258,20 +282,20 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 		nonCompatTracker = true;
 		break;
 	case S3MFileHeader::trkOpenMPT:
-		trackerStr = "OpenMPT";
+		trackerStr = MPT_USTRING("OpenMPT");
 		m_dwLastSavedWithVersion = (fileHeader.cwtv & S3MFileHeader::versionMask) << 16;
 		break; 
 	case S3MFileHeader::trkBeRoTracker:
-		m_madeWithTracker = "BeRoTracker";
+		m_madeWithTracker = MPT_USTRING("BeRoTracker");
 		m_playBehaviour.set(kST3LimitPeriod);
 		break;
 	case S3MFileHeader::trkCreamTracker:
-		m_madeWithTracker = "CreamTracker";
+		m_madeWithTracker = MPT_USTRING("CreamTracker");
 		break;
 	}
 	if(!trackerStr.empty())
 	{
-		m_madeWithTracker = mpt::String::Print("%1 %2.%3", trackerStr, (fileHeader.cwtv & 0xF00) >> 8, mpt::fmt::hex0<2>(fileHeader.cwtv & 0xFF));
+		m_madeWithTracker = mpt::format(MPT_USTRING("%1 %2.%3"))(trackerStr, (fileHeader.cwtv & 0xF00) >> 8, mpt::ufmt::hex0<2>(fileHeader.cwtv & 0xFF));
 	}
 	if(nonCompatTracker)
 	{
@@ -279,6 +303,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 		m_playBehaviour.reset(kST3EffectMemory);
 		m_playBehaviour.reset(kST3PortaSampleChange);
 		m_playBehaviour.reset(kST3VibratoMemory);
+		m_playBehaviour.reset(KST3PortaAfterArpeggio);
 	}
 
 	if((fileHeader.cwtv & S3MFileHeader::trackerMask) > S3MFileHeader::trkScreamTracker)
@@ -295,8 +320,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 	if(!keepMidiMacros)
 	{
 		// Remove macros so they don't interfere with tunes made in trackers that don't support Zxx
-		MemsetZero(m_MidiCfg.szMidiSFXExt);
-		MemsetZero(m_MidiCfg.szMidiZXXExt);
+		m_MidiCfg.ClearZxxMacros();
 	}
 
 	mpt::String::Read<mpt::String::nullTerminated>(m_songName, fileHeader.name);
@@ -361,21 +385,14 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 		m_nChannels = 1;
 	}
 
-	Order.ReadAsByte(file, fileHeader.ordNum, fileHeader.ordNum, 0xFF, 0xFE);
+	ReadOrderFromFile<uint8>(Order(), file, fileHeader.ordNum, 0xFF, 0xFE);
 
 	// Read sample header offsets
-	std::vector<uint16> sampleOffsets(fileHeader.smpNum);
-	for(size_t i = 0; i < fileHeader.smpNum; i++)
-	{
-		sampleOffsets[i] = file.ReadUint16LE();
-	}
-
+	std::vector<uint16le> sampleOffsets;
+	file.ReadVector(sampleOffsets, fileHeader.smpNum);
 	// Read pattern offsets
-	std::vector<uint16> patternOffsets(fileHeader.patNum);
-	for(size_t i = 0; i < fileHeader.patNum; i++)
-	{
-		patternOffsets[i] = file.ReadUint16LE();
-	}
+	std::vector<uint16le> patternOffsets;
+	file.ReadVector(patternOffsets, fileHeader.patNum);
 
 	// Read extended channel panning
 	if(fileHeader.usePanningTable == S3MFileHeader::idPanning)
@@ -399,7 +416,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		S3MSampleHeader sampleHeader;
 
-		if(!file.Seek(sampleOffsets[smp] * 16) || !file.ReadConvertEndianness(sampleHeader))
+		if(!file.Seek(sampleOffsets[smp] * 16) || !file.ReadStruct(sampleHeader))
 		{
 			continue;
 		}
@@ -440,7 +457,9 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		return true;
 	}
-	const PATTERNINDEX readPatterns = std::min<PATTERNINDEX>(fileHeader.patNum, MAX_PATTERNS);
+	// Order list cannot contain pattern indices > 255, so do not even try to load higher patterns
+	const PATTERNINDEX readPatterns = std::min<PATTERNINDEX>(fileHeader.patNum, uint8_max);
+	Patterns.ResizeArray(readPatterns);
 	for(PATTERNINDEX pat = 0; pat < readPatterns; pat++)
 	{
 		// A zero parapointer indicates an empty pattern.
@@ -552,7 +571,14 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 	if(pixPlayPanning && zxxCountLeft + zxxCountRight >= m_nChannels && (-zxxCountLeft + zxxCountRight) < static_cast<int>(m_nChannels))
 	{
 		// There are enough Zxx commands, so let's assume this was made to be played with PixPlay
-		Patterns.ForEachModCommand(FixPixPlayPanning());
+		Patterns.ForEachModCommand([](ModCommand &m)
+		{
+			if(m.command == CMD_MIDI)
+			{
+				m.command = CMD_S3MCMDEX;
+				m.param |= 0x80;
+			}
+		});
 	}
 
 	return true;
@@ -562,7 +588,6 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
 #ifndef MODPLUG_NO_FILESAVE
 
 bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
-//-------------------------------------------------------------
 {
 	static const uint8 filler[16] =
 	{
@@ -582,7 +607,7 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 	fileHeader.fileType = S3MFileHeader::idS3MType;
 
 	// Orders
-	ORDERINDEX writeOrders = Order.GetLengthTailTrimmed();
+	ORDERINDEX writeOrders = Order().GetLengthTailTrimmed();
 	if(writeOrders < 2)
 	{
 		writeOrders = 2;
@@ -651,6 +676,9 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 			{
 				ch += 8 - midCh;
 			}
+#ifdef MODPLUG_TRACKER
+			if(TrackerSettings::Instance().MiscSaveChannelMuteStatus)
+#endif
 			if(ChnSettings[chn].dwFlags[CHN_MUTE])
 			{
 				ch |= 0x80;
@@ -662,9 +690,8 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 		}
 	}
 
-	fileHeader.ConvertEndianness();
 	fwrite(&fileHeader, sizeof(fileHeader), 1, f);
-	Order.WriteAsByte(f, writeOrders);
+	Order().WriteAsByte(f, writeOrders);
 
 	// Comment about parapointers stolen from Schism Tracker:
 	// The sample data parapointers are 24+4 bits, whereas pattern data and sample headers are only 16+4
@@ -679,27 +706,26 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 	// ...which must be a multiple of 16, because parapointers omit the lowest 4 bits.
 	sampleHeaderOffset = (sampleHeaderOffset + 15) & ~15;
 
-	std::vector<uint16> sampleOffsets(writeSamples);
+	std::vector<uint16le> sampleOffsets(writeSamples);
 	for(SAMPLEINDEX smp = 0; smp < writeSamples; smp++)
 	{
 		STATIC_ASSERT((sizeof(S3MSampleHeader) % 16) == 0);
 		sampleOffsets[smp] = static_cast<uint16>((sampleHeaderOffset + smp * sizeof(S3MSampleHeader)) / 16);
-		SwapBytesLE(sampleOffsets[smp]);
 	}
 
 	if(writeSamples != 0)
 	{
-		fwrite(&sampleOffsets[0], 2, writeSamples, f);
+		fwrite(sampleOffsets.data(), 2, writeSamples, f);
 	}
 
 	size_t patternPointerOffset = ftell(f);
 	size_t firstPatternOffset = sampleHeaderOffset + writeSamples * sizeof(S3MSampleHeader);
-	std::vector<uint16> patternOffsets(writePatterns);
+	std::vector<uint16le> patternOffsets(writePatterns);
 
 	// Need to calculate the real offsets later.
 	if(writePatterns != 0)
 	{
-		fwrite(&patternOffsets[0], 2, writePatterns, f);
+		fwrite(patternOffsets.data(), 2, writePatterns, f);
 	}
 
 	// Write channel panning
@@ -736,12 +762,11 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 		long patOffset = ftell(f);
 		if(patOffset > 0xFFFF0)
 		{
-			AddToLog(LogError, mpt::String::Print(MPT_USTRING("Too much pattern data! Writing patterns failed starting from pattern %1."), pat));
+			AddToLog(LogError, mpt::format(MPT_USTRING("Too much pattern data! Writing patterns failed starting from pattern %1."))(pat));
 			break;
 		}
 		MPT_ASSERT((patOffset % 16) == 0);
 		patternOffsets[pat] = static_cast<uint16>(patOffset / 16);
-		SwapBytesLE(patternOffsets[pat]);
 
 		std::vector<uint8> buffer;
 		buffer.reserve(5 * 1024);
@@ -764,7 +789,7 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 				CHANNELINDEX writeChannels = MIN(32, GetNumChannels());
 				for(CHANNELINDEX chn = 0; chn < writeChannels; chn++)
 				{
-					ModCommand &m = rowBase[chn];
+					const ModCommand &m = rowBase[chn];
 
 					uint8 info = static_cast<uint8>(chn);
 					uint8 note = m.note;
@@ -859,7 +884,7 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 			buffer.insert(buffer.end(), 16 - (buffer.size() % 16u), 0);
 		}
 
-		fwrite(&buffer[0], buffer.size(), 1, f);
+		fwrite(buffer.data(), buffer.size(), 1, f);
 	}
 
 	size_t sampleDataOffset = ftell(f);
@@ -897,7 +922,7 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 			// Write sample data
 			if(sampleDataOffset > 0xFFFFFF0)
 			{
-				AddToLog(LogError, mpt::String::Print(MPT_USTRING("Too much sample data! Writing samples failed starting from sample %1."), realSmp));
+				AddToLog(LogError, mpt::format(MPT_USTRING("Too much sample data! Writing samples failed starting from sample %1."))(realSmp));
 				break;
 			}
 
@@ -914,22 +939,20 @@ bool CSoundFile::SaveS3M(const mpt::PathString &filename) const
 				sampleDataOffset += fillSize;
 			}
 		}
-
-		sampleHeader[smp].ConvertEndianness();
 	}
 
 	// Now we know where the patterns are.
 	if(writePatterns != 0)
 	{
 		fseek(f, patternPointerOffset, SEEK_SET);
-		fwrite(&patternOffsets[0], 2, writePatterns, f);
+		fwrite(patternOffsets.data(), 2, writePatterns, f);
 	}
 
 	// And we can finally write the sample headers.
 	if(writeSamples != 0)
 	{
 		fseek(f, sampleHeaderOffset, SEEK_SET);
-		fwrite(&sampleHeader[0], sizeof(sampleHeader[0]), writeSamples, f);
+		fwrite(sampleHeader.data(), sizeof(sampleHeader[0]), writeSamples, f);
 	}
 
 	fclose(f);
diff --git a/soundlib/Load_sfx.cpp b/soundlib/Load_sfx.cpp
index a474aea..f0a643e 100644
--- a/soundlib/Load_sfx.cpp
+++ b/soundlib/Load_sfx.cpp
@@ -14,36 +14,25 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // File Header
-struct PACKED SFXFileHeader
+struct SFXFileHeader
 {
-	uint8 numOrders;
-	uint8 restartPos;
-	uint8 orderList[128];
+	uint8be numOrders;
+	uint8be restartPos;
+	uint8be orderList[128];
 };
 
-STATIC_ASSERT(sizeof(SFXFileHeader) == 130);
+MPT_BINARY_STRUCT(SFXFileHeader, 130)
 
 // Sample Header
-struct PACKED SFXSampleHeader
+struct SFXSampleHeader
 {
-	char   name[22];
-	char   dummy[2];	// Supposedly sample length, but almost always incorrect
-	uint8  finetune;
-	uint8  volume;
-	uint16 loopStart;
-	uint16 loopLength;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(loopStart);
-		SwapBytesBE(loopLength);
-	}
+	char     name[22];
+	char     dummy[2];	// Supposedly sample length, but almost always incorrect
+	uint8be  finetune;
+	uint8be  volume;
+	uint16be loopStart;
+	uint16be loopLength;
 
 	// Convert an MOD sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp, uint32 length) const
@@ -51,7 +40,7 @@ struct PACKED SFXSampleHeader
 		mptSmp.Initialize(MOD_TYPE_MOD);
 		mptSmp.nLength = length;
 		mptSmp.nFineTune = MOD2XMFineTune(finetune);
-		mptSmp.nVolume = 4u * std::min(volume, uint8(64));
+		mptSmp.nVolume = 4u * std::min<uint8>(volume, 64);
 
 		SmpLength lStart = loopStart;
 		SmpLength lLength = loopLength * 2u;
@@ -83,13 +72,9 @@ struct PACKED SFXSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(SFXSampleHeader) == 30);
+MPT_BINARY_STRUCT(SFXSampleHeader, 30)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 static uint8 ClampSlideParam(uint8 value, uint8 lowNote, uint8 highNote)
-//----------------------------------------------------------------------
 {
 	uint16 lowPeriod, highPeriod;
 
@@ -110,8 +95,86 @@ static uint8 ClampSlideParam(uint8 value, uint8 lowNote, uint8 highNote)
 	return 0;
 }
 
+
+static bool ValidateHeader(const SFXFileHeader &fileHeader)
+{
+	if(fileHeader.numOrders > 128)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize)
+{
+	SAMPLEINDEX numSamples = 0;
+	if(numSamples == 0)
+	{
+		file.Rewind();
+		if(!file.CanRead(0x40))
+		{
+			return ProbeWantMoreData;
+		}
+		if(file.Seek(0x3c) && file.ReadMagic("SONG"))
+		{
+			numSamples = 15;
+		}
+	}
+	if(numSamples == 0)
+	{
+		file.Rewind();
+		if(!file.CanRead(0x80))
+		{
+			return ProbeWantMoreData;
+		}
+		if(file.Seek(0x7c) && file.ReadMagic("SO31"))
+		{
+			numSamples = 31;
+		}
+	}
+	if(numSamples == 0)
+	{
+		return ProbeFailure;
+	}
+	file.Rewind();
+	for(SAMPLEINDEX smp = 0; smp < numSamples; smp++)
+	{
+		if(file.ReadUint32BE() > 131072)
+		{
+			return ProbeFailure;
+		}
+	}
+	file.Skip(4);
+	if(!file.CanRead(2))
+	{
+		return ProbeWantMoreData;
+	}
+	uint16 speed = file.ReadUint16BE();
+	if(speed < 178)
+	{
+		return ProbeFailure;
+	}
+	if(!file.CanRead(sizeof(SFXSampleHeader) * numSamples))
+	{
+		return ProbeWantMoreData;
+	}
+	file.Skip(sizeof(SFXSampleHeader) * numSamples);
+	SFXFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	if(file.Seek(0x3C), file.ReadMagic("SONG"))
 	{
@@ -142,7 +205,6 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
 	m_nMinPeriod = 14 * 4;
 	m_nMaxPeriod = 3424 * 4;
 	m_nSamplePreAmp = 64;
-	m_SongFlags.reset();
 
 	// Setup channel pan positions and volume
 	SetupMODPanning(true);
@@ -161,7 +223,7 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		SFXSampleHeader sampleHeader;
 
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		sampleHeader.ConvertToMPT(Samples[smp], sampleLen[smp - 1]);
 
 		// Get rid of weird characters in sample names.
@@ -179,12 +241,18 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	SFXFileHeader fileHeader;
-	file.ReadStruct(fileHeader);
-
-	if(fileHeader.numOrders > 128)
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
 		return false;
+	}
 	if(loadFlags == onlyVerifyHeader)
+	{
 		return true;
+	}
 
 	PATTERNINDEX numPatterns = 0;
 	for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++)
@@ -193,11 +261,11 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	if(fileHeader.restartPos < fileHeader.numOrders)
-		Order.SetRestartPos(fileHeader.restartPos);
+		Order().SetRestartPos(fileHeader.restartPos);
 	else
-		Order.SetRestartPos(0);
+		Order().SetRestartPos(0);
 
-	Order.ReadFromArray(fileHeader.orderList, fileHeader.numOrders);
+	ReadOrderFromArray(Order(), fileHeader.orderList, fileHeader.numOrders);
 
 	// SFX v2 / MMS modules have 4 extra bytes here for some reason
 	if(m_nSamples == 31)
@@ -208,6 +276,8 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
 	uint8 slideRate[4] = {0};
 
 	// Reading patterns
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(numPatterns);
 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
 	{
 		if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
diff --git a/soundlib/Load_stm.cpp b/soundlib/Load_stm.cpp
index 48dd305..8ae75b7 100644
--- a/soundlib/Load_stm.cpp
+++ b/soundlib/Load_stm.cpp
@@ -14,25 +14,20 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-
 // STM sample header struct
-struct PACKED STMSampleHeader
+struct STMSampleHeader
 {
-	char   filename[12];	// Can't have long comments - just filename comments :)
-	uint8  zero;
-	uint8  disk;			// A blast from the past
-	uint16 offset;			// 20-bit offset in file (lower 4 bits are zero)
-	uint16 length;			// Sample length
-	uint16 loopStart;		// Loop start point
-	uint16 loopEnd;			// Loop end point
-	uint8  volume;			// Volume
-	uint8  reserved2;
-	uint16 sampleRate;
-	uint8  reserved3[6];
+	char     filename[12];	// Can't have long comments - just filename comments :)
+	uint8le  zero;
+	uint8le  disk;			// A blast from the past
+	uint16le offset;		// 20-bit offset in file (lower 4 bits are zero)
+	uint16le length;		// Sample length
+	uint16le loopStart;		// Loop start point
+	uint16le loopEnd;		// Loop end point
+	uint8le  volume;		// Volume
+	uint8le  reserved2;
+	uint16le sampleRate;
+	uint8le  reserved3[6];
 
 	// Convert an STM sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -56,23 +51,13 @@ struct PACKED STMSampleHeader
 			mptSmp.nLoopEnd = std::min(mptSmp.nLoopEnd, mptSmp.nLength);
 		}
 	}
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(offset);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sampleRate);
-	}
 };
 
-STATIC_ASSERT(sizeof(STMSampleHeader) == 32);
+MPT_BINARY_STRUCT(STMSampleHeader, 32)
 
 
 // STM file header
-struct PACKED STMFileHeader
+struct STMFileHeader
 {
 	char  songname[20];
 	char  trackername[8];	// !Scream! for ST 2.xx
@@ -80,42 +65,76 @@ struct PACKED STMFileHeader
 	uint8 filetype;			// 1=song, 2=module (only 2 is supported, of course) :)
 	uint8 verMajor;
 	uint8 verMinor;
-	uint8 initTempo;				// Ticks per row. Keep in mind that effects are only updated on every 16th tick.
-	uint8 numPatterns;				// number of patterns
+	uint8 initTempo;		// Ticks per row. Keep in mind that effects are only updated on every 16th tick.
+	uint8 numPatterns;		// number of patterns
 	uint8 globalVolume;
 	uint8 reserved[13];
 };
 
-STATIC_ASSERT(sizeof(STMFileHeader) == 48);
+MPT_BINARY_STRUCT(STMFileHeader, 48)
 
 
 // Pattern note entry
-struct PACKED STMPatternEntry
+struct STMPatternEntry
 {
-	uint8 note;
-	uint8 insvol;
-	uint8 volcmd;
-	uint8 cmdinf;
+	uint8le note;
+	uint8le insvol;
+	uint8le volcmd;
+	uint8le cmdinf;
 };
 
-STATIC_ASSERT(sizeof(STMPatternEntry) == 4);
+MPT_BINARY_STRUCT(STMPatternEntry, 4)
 
 
-struct PACKED STMPatternData
+struct STMPatternData
 {
 	STMPatternEntry entry[64 * 4];
 };
 
-STATIC_ASSERT(sizeof(STMPatternData) == 4*64*4);
+MPT_BINARY_STRUCT(STMPatternData, 4*64*4)
+
+
+static bool ValidateHeader(const STMFileHeader &fileHeader)
+{
+	if(fileHeader.filetype != 2
+		|| (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2)	// ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
+		|| fileHeader.verMajor != 2
+		|| fileHeader.verMinor > 21	// ST3 only accepts 0, 10, 20 and 21
+		|| fileHeader.globalVolume > 64
+		|| (std::memcmp(fileHeader.trackername, "!Scream!", 8)
+			&& std::memcmp(fileHeader.trackername, "BMOD2STM", 8)
+			&& std::memcmp(fileHeader.trackername, "WUZAMOD!", 8))
+		)
+	{
+		return false;
+	}
+	return true;
+}
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static uint64 GetHeaderMinimumAdditionalSize(const STMFileHeader &fileHeader)
+{
+	MPT_UNREFERENCED_PARAMETER(fileHeader);
+	return 31 * sizeof(STMSampleHeader) + 128;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	STMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
 
 
 bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 
@@ -125,19 +144,19 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 	// After reviewing all STM files on ModLand and ModArchive, it was found that the
 	// case-insensitive comparison is most likely not necessary for any files in the wild.
 	STMFileHeader fileHeader;
-	if(!file.ReadStruct(fileHeader)
-		|| fileHeader.filetype != 2
-		|| (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2)	// ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
-		|| fileHeader.verMajor != 2
-		|| fileHeader.verMinor > 21	// ST3 only accepts 0, 10, 20 and 21
-		|| fileHeader.globalVolume > 64
-		|| (memcmp(fileHeader.trackername, "!Scream!", 8)
-			&& memcmp(fileHeader.trackername, "BMOD2STM", 8)
-			&& memcmp(fileHeader.trackername, "WUZAMOD!", 8))
-		|| !file.CanRead(31 * sizeof(STMSampleHeader) + 128))
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -147,7 +166,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songname);
 
 	// Read STM header
-	m_madeWithTracker = mpt::String::Print("Scream Tracker %1.%2", fileHeader.verMajor, mpt::fmt::dec0<2>(fileHeader.verMinor));
+	m_madeWithTracker = mpt::format(MPT_USTRING("Scream Tracker %1.%2"))(fileHeader.verMajor, mpt::ufmt::dec0<2>(fileHeader.verMinor));
 	m_nSamples = 31;
 	m_nChannels = 4;
 	m_nMinPeriod = 64;
@@ -174,7 +193,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 	for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
 	{
 		STMSampleHeader sampleHeader;
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		if(sampleHeader.zero != 0 && sampleHeader.zero != 46)	// putup10.stm has zero = 46
 			return false;
 		sampleHeader.ConvertToMPT(Samples[smp]);
@@ -183,15 +202,17 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 	}
 
 	// Read order list
-	Order.ReadAsByte(file, 128);
-	for(ORDERINDEX ord = 0; ord < 128; ord++)
+	ReadOrderFromFile<uint8>(Order(), file, 128);
+	for(auto &pat : Order())
 	{
-		if(Order[ord] == 99 || Order[ord] == 255)	// 99 is regular, sometimes a single 255 entry can be found too
-			Order[ord] = Order.GetInvalidPatIndex();
-		else if(Order[ord] > 99)
+		if(pat == 99 || pat == 255)	// 99 is regular, sometimes a single 255 entry can be found too
+			pat = Order.GetInvalidPatIndex();
+		else if(pat > 99)
 			return false;
 	}
 
+	if(loadFlags & loadPatternData)
+		Patterns.ResizeArray(fileHeader.numPatterns);
 	for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
 	{
 		STMPatternData patternData;
@@ -202,7 +223,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 			continue;
 		}
 
-		ModCommand *m = Patterns[pat];
+		auto m = Patterns[pat].begin();
 		ORDERINDEX breakPos = ORDERINDEX_INVALID;
 		ROWINDEX breakRow = 63;	// Candidate row for inserting pattern break
 	
@@ -231,7 +252,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 				m->vol = vol;
 			}
 
-			static const uint8 stmEffects[] =
+			static const EffectCommand stmEffects[] =
 			{
 				CMD_NONE, CMD_SPEED, CMD_POSITIONJUMP, CMD_PATTERNBREAK,					// .ABC
 				CMD_VOLUMESLIDE, CMD_PORTAMENTODOWN, CMD_PORTAMENTOUP, CMD_TONEPORTAMENTO,	// DEFG
@@ -302,7 +323,7 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 
 		if(breakPos != ORDERINDEX_INVALID)
 		{
-			Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(breakPos)).Row(breakRow).Retry(EffectWriter::rmTryPreviousRow));
+			Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(breakPos)).Row(breakRow).RetryPreviousRow());
 		}
 	}
 
@@ -318,12 +339,13 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
 		for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
 		{
 			ModSample &sample = Samples[smp];
-			if(sample.nLength)
+			// ST2 just plays random noise for samples with a default volume of 0
+			if(sample.nLength && sample.nVolume > 0)
 			{
 				FileReader::off_t sampleOffset = sampleOffsets[smp - 1] << 4;
-				if(sampleOffset > sizeof(STMPatternEntry) && sampleOffset < file.GetLength())
+				// acidlamb.stm has some bogus samples with sample offsets past EOF
+				if(sampleOffset > sizeof(STMFileHeader) && file.Seek(sampleOffset))
 				{
-					file.Seek(sampleOffset);
 					sampleIO.ReadSample(sample, file);
 				}
 			}
diff --git a/soundlib/Load_stp.cpp b/soundlib/Load_stp.cpp
new file mode 100644
index 0000000..9088554
--- /dev/null
+++ b/soundlib/Load_stp.cpp
@@ -0,0 +1,877 @@
+/*
+ * Load_stp.cpp
+ * ------------
+ * Purpose: STP (Soundtracker Pro II) module loader
+ * Notes  : A few exotic effects aren't supported.
+ *          Multiple sample loops are supported, but only the first 10 can be used as cue points
+ *          (with 16xx and 18xx).
+ *          Fractional speed values and combined auto effects are handled whenever possible,
+ *          but some effects may be omitted (and there may be tempo accuracy issues).
+ * Authors: Devin Acker
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ *
+ * Wisdom from the Soundtracker Pro II manual:
+ * "To create shorter patterns, simply create shorter patterns."
+ */
+
+#include "stdafx.h"
+#include "Loaders.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+// File header (except for "STP3" magic)
+struct STPFileHeader
+{
+	char     magic[4];
+	uint16be version;
+	uint8be  numOrders;
+	uint8be  patternLength;
+	uint8be  orderList[128];
+	uint16be speed;
+	uint16be speedFrac;
+	uint16be timerCount;
+	uint16be flags;
+	uint32be reserved;
+	uint16be midiCount; // always 50
+	uint8be  midi[50];
+	uint16be numSamples;
+	uint16be sampleStructSize;
+};
+
+MPT_BINARY_STRUCT(STPFileHeader, 204);
+
+
+// Sample header (common part between all versions)
+struct STPSampleHeader
+{
+	uint32be length;
+	uint8be  volume;
+	uint8be  reserved1;
+	uint32be loopStart;
+	uint32be loopLength;
+	uint16be defaultCommand;	// Default command to put next to note when editing patterns; not relevant for playback
+	// The following 4 bytes are reserved in version 0 and 1.
+	uint16be defaultPeriod;
+	uint8be  finetune;
+	uint8be  reserved2;
+
+	void ConvertToMPT(ModSample &mptSmp) const
+	{
+		mptSmp.nLength = length;
+		mptSmp.nVolume = 4u * std::min<uint16>(volume, 64);
+
+		mptSmp.nLoopStart = loopStart;
+		mptSmp.nLoopEnd = loopStart + loopLength;
+
+		if(mptSmp.nLoopStart >= mptSmp.nLength)
+		{
+			mptSmp.nLoopStart = mptSmp.nLength - 1;
+		}
+		if(mptSmp.nLoopEnd > mptSmp.nLength)
+		{
+			mptSmp.nLoopEnd = mptSmp.nLength;
+		}
+
+		if(mptSmp.nLoopStart > mptSmp.nLoopEnd)
+		{
+			mptSmp.nLoopStart = 0;
+			mptSmp.nLoopEnd = 0;
+		} else if(mptSmp.nLoopEnd > mptSmp.nLoopStart)
+		{
+			mptSmp.uFlags.set(CHN_LOOP);
+			mptSmp.cues[0] = mptSmp.nLoopStart;
+		}
+	}
+};
+
+MPT_BINARY_STRUCT(STPSampleHeader, 20);
+
+
+struct STPLoopInfo
+{
+	SmpLength loopStart;
+	SmpLength loopLength;
+	SAMPLEINDEX looped;
+	SAMPLEINDEX nonLooped;
+};
+
+typedef std::vector<STPLoopInfo> STPLoopList;
+
+
+static TEMPO ConvertTempo(uint16 ciaSpeed)
+{
+	// 3546 is the resulting CIA timer value when using 4F7D (tempo 125 bpm) command in STProII
+	return TEMPO((125.0 * 3546.0) / ciaSpeed);
+}
+
+
+static void ConvertLoopSlice(ModSample &src, ModSample &dest, SmpLength start, SmpLength len, bool loop)
+{
+	if(!src.HasSampleData()) return;
+
+	dest.FreeSample();
+
+	dest = src;
+	dest.nLength = len;
+	dest.pSample = nullptr;
+
+	if(!dest.AllocateSample())
+	{
+		return;
+	}
+
+	// only preserve cue points if the target sample length is the same
+	if(len != src.nLength)
+		MemsetZero(dest.cues);
+
+	std::memcpy(dest.pSample8, src.pSample8 + start, len);
+	dest.uFlags.set(CHN_LOOP, loop);
+	if(loop)
+	{
+		dest.nLoopStart = 0;
+		dest.nLoopEnd = len;
+	} else
+	{
+		dest.nLoopStart = 0;
+		dest.nLoopEnd = 0;
+	}
+}
+
+static void ConvertLoopSequence(ModSample &smp, STPLoopList &loopList)
+{
+	// This should only modify a sample if it has more than one loop
+	// (otherwise, it behaves like a normal sample loop)
+	if(!smp.HasSampleData() || loopList.size() < 2) return;
+
+	ModSample newSmp = smp;
+	newSmp.nLength = 0;
+	newSmp.pSample = nullptr;
+
+	size_t numLoops = loopList.size();
+
+	// get the total length of the sample after combining all looped sections
+	for(size_t i = 0; i < numLoops; i++)
+	{
+		STPLoopInfo &info = loopList[i];
+
+		// if adding this loop would cause the sample length to exceed maximum,
+		// then limit and bail out
+		if((newSmp.nLength + info.loopLength > MAX_SAMPLE_LENGTH) ||
+		   (info.loopLength > MAX_SAMPLE_LENGTH) ||
+		   (info.loopStart + info.loopLength > smp.nLength))
+		{
+			numLoops = i;
+			break;
+		}
+
+		newSmp.nLength += info.loopLength;
+	}
+
+	if(!newSmp.AllocateSample())
+	{
+		return;
+	}
+
+	// start copying the looped sample data parts
+	SmpLength start = 0;
+
+	for(size_t i = 0; i < numLoops; i++)
+	{
+		STPLoopInfo &info = loopList[i];
+
+		memcpy(newSmp.pSample8 + start, smp.pSample8 + info.loopStart, info.loopLength);
+
+		// update loop info based on position in edited sample
+		info.loopStart = start;
+		if(i > 0 && i <= mpt::size(newSmp.cues))
+		{
+			newSmp.cues[i - 1] = start;
+		}
+		start += info.loopLength;
+	}
+
+	// replace old sample with new one
+	smp.FreeSample();
+	smp = newSmp;
+
+	smp.nLoopStart = 0;
+	smp.nLoopEnd = smp.nLength;
+	smp.uFlags.set(CHN_LOOP);
+}
+
+
+static bool ValidateHeader(const STPFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.magic, "STP3", 4)
+		|| fileHeader.version > 2
+		|| fileHeader.numOrders > 128
+		|| fileHeader.numSamples >= MAX_SAMPLES
+		|| fileHeader.timerCount == 0
+		|| fileHeader.midiCount != 50)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize)
+{
+	STPFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+
+	STPFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
+	{
+		return true;
+	}
+
+	InitializeGlobals(MOD_TYPE_STP);
+
+	m_nChannels = 4;
+	m_nSamples = 0;
+
+	m_nDefaultSpeed = fileHeader.speed;
+	m_nDefaultTempo = ConvertTempo(fileHeader.timerCount);
+
+	m_nMinPeriod = 14 * 4;
+	m_nMaxPeriod = 3424 * 4;
+
+	ReadOrderFromArray(Order(), fileHeader.orderList, fileHeader.numOrders);
+
+	std::vector<STPLoopList> loopInfo;
+	// non-looped versions of samples with loops (when needed)
+	std::vector<SAMPLEINDEX> nonLooped;
+
+	// Load sample headers
+	SAMPLEINDEX samplesInFile = 0;
+
+	for(SAMPLEINDEX smp = 0; smp < fileHeader.numSamples; smp++)
+	{
+		SAMPLEINDEX actualSmp = file.ReadUint16BE();
+		if(actualSmp == 0 || actualSmp >= MAX_SAMPLES)
+			return false;
+		uint32 chunkSize = fileHeader.sampleStructSize;
+		if(fileHeader.version == 2)
+			chunkSize = file.ReadUint32BE() - 2;
+		FileReader chunk = file.ReadChunk(chunkSize);
+
+		samplesInFile = m_nSamples = std::max(m_nSamples, actualSmp);
+
+		ModSample &mptSmp = Samples[actualSmp];
+		mptSmp.Initialize(MOD_TYPE_MOD);
+
+		if(fileHeader.version < 2)
+		{
+			// Read path
+			chunk.ReadString<mpt::String::maybeNullTerminated>(mptSmp.filename, 31);
+			// Ignore flags, they are all not relevant for us
+			chunk.Skip(1);
+			// Read filename / sample text
+			chunk.ReadString<mpt::String::maybeNullTerminated>(m_szNames[actualSmp], 30);
+		} else
+		{
+			std::string str;
+			// Read path
+			chunk.ReadNullString(str, 257);
+			mpt::String::Copy(mptSmp.filename, str);
+			// Ignore flags, they are all not relevant for us
+			chunk.Skip(1);
+			// Read filename / sample text
+			chunk.ReadNullString(str, 31);
+			mpt::String::Copy(m_szNames[actualSmp], str);
+			// Seek to even boundary
+			if(chunk.GetPosition() % 2u)
+				chunk.Skip(1);
+		}
+
+		STPSampleHeader sampleHeader;
+		chunk.ReadStruct(sampleHeader);
+		sampleHeader.ConvertToMPT(mptSmp);
+
+		if(fileHeader.version == 2)
+		{
+			mptSmp.nFineTune = static_cast<int8>(sampleHeader.finetune << 3);
+		}
+
+		if(fileHeader.version >= 1)
+		{
+			nonLooped.resize(samplesInFile);
+			loopInfo.resize(samplesInFile);
+			STPLoopList &loopList = loopInfo[actualSmp - 1];
+			loopList.clear();
+
+			uint16 numLoops = file.ReadUint16BE();
+			loopList.reserve(numLoops);
+
+			STPLoopInfo loop;
+			loop.looped = loop.nonLooped = 0;
+
+			if(numLoops == 0 && mptSmp.uFlags[CHN_LOOP])
+			{
+				loop.loopStart  = mptSmp.nLoopStart;
+				loop.loopLength = mptSmp.nLoopEnd - mptSmp.nLoopStart;
+				loopList.push_back(loop);
+			} else for(uint16 i = 0; i < numLoops; i++)
+			{
+				loop.loopStart  = file.ReadUint32BE();
+				loop.loopLength = file.ReadUint32BE();
+				loopList.push_back(loop);
+			}
+		}
+	}
+
+	// Load patterns
+	uint16 numPatterns = 128;
+	if(fileHeader.version == 0)
+		numPatterns = file.ReadUint16BE();
+
+	uint16 patternLength = fileHeader.patternLength;
+	CHANNELINDEX channels = 4;
+	if(fileHeader.version > 0)
+	{
+		// Scan for total number of channels
+		FileReader::off_t patOffset = file.GetPosition();
+		for(uint16 pat = 0; pat < numPatterns; pat++)
+		{
+			PATTERNINDEX actualPat = file.ReadUint16BE();
+			if(actualPat == 0xFFFF)
+				break;
+
+			patternLength = file.ReadUint16BE();
+			channels = file.ReadUint16BE();
+			m_nChannels = std::max(m_nChannels, channels);
+
+			file.Skip(channels * patternLength * 4u);
+		}
+		file.Seek(patOffset);
+		if(m_nChannels > MAX_BASECHANNELS)
+			return false;
+	}
+
+	struct ChannelMemory
+	{
+		uint8 autoFinePorta, autoPortaUp, autoPortaDown, autoVolSlide, autoVibrato;
+		uint8 vibratoMem, autoTremolo, autoTonePorta, tonePortaMem;
+	};
+	std::vector<ChannelMemory> channelMemory(m_nChannels);
+	uint8 globalVolSlide = 0;
+
+	for(uint16 pat = 0; pat < numPatterns; pat++)
+	{
+		PATTERNINDEX actualPat = pat;
+
+		if(fileHeader.version > 0)
+		{
+			actualPat = file.ReadUint16BE();
+			if(actualPat == 0xFFFF)
+				break;
+
+			patternLength = file.ReadUint16BE();
+			channels = file.ReadUint16BE();
+		}
+
+		if(!(loadFlags & loadPatternData) || !Patterns.Insert(actualPat, patternLength))
+		{
+			file.Skip(channels * patternLength * 4u);
+			continue;
+		}
+
+		for(ROWINDEX row = 0; row < patternLength; row++)
+		{
+			auto rowBase = Patterns[actualPat].GetRow(row);
+
+			bool didGlobalVolSlide = false;
+
+			// if a fractional speed value is in use then determine if we should stick a fine pattern delay somewhere
+			bool shouldDelay;
+			switch(fileHeader.speedFrac & 3)
+			{
+			default: shouldDelay = false; break;
+			// 1/4
+			case 1: shouldDelay = (row & 3) == 0; break;
+			// 1/2
+			case 2: shouldDelay = (row & 1) == 0; break;
+			// 3/4
+			case 3: shouldDelay = (row & 3) != 3; break;
+			}
+
+			for(CHANNELINDEX chn = 0; chn < channels; chn++)
+			{
+				ChannelMemory &chnMem = channelMemory[chn];
+				ModCommand &m = rowBase[chn];
+				uint8 data[4];
+				file.ReadArray(data);
+
+				m.instr   = data[0];
+				m.note    = data[1];
+				m.command = data[2];
+				m.param   = data[3];
+
+				if(m.note)
+				{
+					m.note += 24 + NOTE_MIN;
+					chnMem = ChannelMemory();
+				}
+
+				// this is a nibble-swapped param value used for auto fine volside
+				// and auto global fine volside
+				uint8 swapped = (m.param >> 4) | (m.param << 4);
+
+				if((m.command & 0xF0) == 0xF0)
+				{
+					// 12-bit CIA tempo
+					uint16 ciaTempo = (static_cast<uint16>(m.command & 0x0F) << 8) | m.param;
+					if(ciaTempo)
+					{
+						m.param = mpt::saturate_cast<ModCommand::PARAM>(Util::Round(ConvertTempo(ciaTempo).ToDouble()));
+						m.command = CMD_TEMPO;
+					} else
+					{
+						m.command = CMD_NONE;
+					}
+				} else switch(m.command)
+				{
+				case 0x00: // arpeggio
+					if(m.param)
+						m.command = CMD_ARPEGGIO;
+					break;
+
+				case 0x01: // portamento up
+					m.command = CMD_PORTAMENTOUP;
+					break;
+
+				case 0x02: // portamento down
+					m.command = CMD_PORTAMENTODOWN;
+					break;
+
+				case 0x03: // auto fine portamento up
+					chnMem.autoFinePorta = 0x10 | std::min(m.param, ModCommand::PARAM(15));
+					chnMem.autoPortaUp = 0;
+					chnMem.autoPortaDown = 0;
+					chnMem.autoTonePorta = 0;
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x04: // auto fine portamento down
+					chnMem.autoFinePorta = 0x20 | std::min(m.param, ModCommand::PARAM(15));
+					chnMem.autoPortaUp = 0;
+					chnMem.autoPortaDown = 0;
+					chnMem.autoTonePorta = 0;
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x05: // auto portamento up
+					chnMem.autoFinePorta = 0;
+					chnMem.autoPortaUp = m.param;
+					chnMem.autoPortaDown = 0;
+					chnMem.autoTonePorta = 0;
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x06: // auto portamento down
+					chnMem.autoFinePorta = 0;
+					chnMem.autoPortaUp = 0;
+					chnMem.autoPortaDown = m.param;
+					chnMem.autoTonePorta = 0;
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x07: // set global volume
+					m.command = CMD_GLOBALVOLUME;
+					globalVolSlide = 0;
+					break;
+
+				case 0x08: // auto global fine volume slide
+					globalVolSlide = swapped;
+					m.command = m.param = 0;
+					break;
+
+				case 0x09: // fine portamento up
+					m.command = CMD_MODCMDEX;
+					m.param = 0x10 | std::min(m.param, ModCommand::PARAM(15));
+					break;
+
+				case 0x0A: // fine portamento down
+					m.command = CMD_MODCMDEX;
+					m.param = 0x20 | std::min(m.param, ModCommand::PARAM(15));
+					break;
+
+				case 0x0B: // auto fine volume slide
+					chnMem.autoVolSlide = swapped;
+					m.command = m.param = 0;
+					break;
+
+				case 0x0C: // set volume
+					m.volcmd = VOLCMD_VOLUME;
+					m.vol = m.param;
+					chnMem.autoVolSlide = 0;
+					m.command = m.param = 0;
+					break;
+
+				case 0x0D: // volume slide (param is swapped compared to .mod)
+					if(m.param & 0xF0)
+					{
+						m.volcmd = VOLCMD_VOLSLIDEDOWN;
+						m.vol = m.param >> 4;
+					} else if(m.param & 0x0F)
+					{
+						m.volcmd = VOLCMD_VOLSLIDEUP;
+						m.vol = m.param & 0xF;
+					}
+					chnMem.autoVolSlide = 0;
+					m.command = m.param = 0;
+					break;
+
+				case 0x0E: // set filter (also uses opposite value compared to .mod)
+					m.command = CMD_MODCMDEX;
+					m.param = 1 ^ (m.param ? 1 : 0);
+					break;
+
+				case 0x0F: // set speed
+					m.command = CMD_SPEED;
+					fileHeader.speedFrac = m.param & 0xF;
+					m.param >>= 4;
+					break;
+
+				case 0x10: // auto vibrato
+					chnMem.autoVibrato = m.param;
+					chnMem.vibratoMem = 0;
+					m.command = m.param = 0;
+					break;
+
+				case 0x11: // auto tremolo
+					if(m.param & 0xF)
+						chnMem.autoTremolo = m.param;
+					else
+						chnMem.autoTremolo = 0;
+					m.command = m.param = 0;
+					break;
+
+				case 0x12: // pattern break
+					m.command = CMD_PATTERNBREAK;
+					break;
+
+				case 0x13: // auto tone portamento
+					chnMem.autoFinePorta = 0;
+					chnMem.autoPortaUp = 0;
+					chnMem.autoPortaDown = 0;
+					chnMem.autoTonePorta = m.param;
+
+					chnMem.tonePortaMem = 0;
+					m.command = m.param = 0;
+					break;
+
+				case 0x14: // position jump
+					m.command = CMD_POSITIONJUMP;
+					break;
+
+				case 0x16: // start loop sequence
+					if(m.instr && m.instr <= loopInfo.size())
+					{
+						STPLoopList &loopList = loopInfo[m.instr - 1];
+
+						m.param--;
+						if(m.param < std::min(mpt::size(ModSample().cues), loopList.size()))
+						{
+							m.volcmd = VOLCMD_OFFSET;
+							m.vol = m.param;
+						}
+					}
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x17: // play only loop nn
+					if(m.instr && m.instr <= loopInfo.size())
+					{
+						STPLoopList &loopList = loopInfo[m.instr - 1];
+
+						m.param--;
+						if(m.param < loopList.size())
+						{
+							if(!loopList[m.param].looped && m_nSamples < MAX_SAMPLES - 1)
+								loopList[m.param].looped = ++m_nSamples;
+							m.instr = static_cast<ModCommand::INSTR>(loopList[m.param].looped);
+						}
+					}
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x18: // play sequence without loop
+					if(m.instr && m.instr <= loopInfo.size())
+					{
+						STPLoopList &loopList = loopInfo[m.instr - 1];
+
+						m.param--;
+						if(m.param < std::min(mpt::size(ModSample().cues), loopList.size()))
+						{
+							m.volcmd = VOLCMD_OFFSET;
+							m.vol = m.param;
+						}
+						// switch to non-looped version of sample and create it if needed
+						if(!nonLooped[m.instr - 1] && m_nSamples < MAX_SAMPLES - 1)
+							nonLooped[m.instr - 1] = ++m_nSamples;
+						m.instr = static_cast<ModCommand::INSTR>(nonLooped[m.instr - 1]);
+					}
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x19: // play only loop nn without loop
+					if(m.instr && m.instr <= loopInfo.size())
+					{
+						STPLoopList &loopList = loopInfo[m.instr - 1];
+
+						m.param--;
+						if(m.param < loopList.size())
+						{
+							if(!loopList[m.param].nonLooped && m_nSamples < MAX_SAMPLES-1)
+								loopList[m.param].nonLooped = ++m_nSamples;
+							m.instr = static_cast<ModCommand::INSTR>(loopList[m.param].nonLooped);
+						}
+					}
+
+					m.command = m.param = 0;
+					break;
+
+				case 0x1D: // fine volume slide (nibble order also swapped)
+					m.command = CMD_VOLUMESLIDE;
+					m.param = swapped;
+					if(m.param & 0xF0) // slide down
+						m.param |= 0x0F;
+					else if(m.param & 0x0F)
+						m.param |= 0xF0;
+					break;
+
+				case 0x20: // "delayed fade"
+					// just behave like either a normal fade or a notecut
+					// depending on the speed
+					if(m.param & 0xF0)
+					{
+						chnMem.autoVolSlide = m.param >> 4;
+						m.command = m.param = 0;
+					} else
+					{
+						m.command = CMD_MODCMDEX;
+						m.param = 0xC0 | (m.param & 0xF);
+					}
+					break;
+
+				case 0x21: // note delay
+					m.command = CMD_MODCMDEX;
+					m.param = 0xD0 | std::min(m.param, ModCommand::PARAM(15));
+					break;
+
+				case 0x22: // retrigger note
+					m.command = CMD_MODCMDEX;
+					m.param = 0x90 | std::min(m.param, ModCommand::PARAM(15));
+					break;
+
+				case 0x49: // set sample offset
+					m.command = CMD_OFFSET;
+					break;
+
+				case 0x4E: // other protracker commands (pattern loop / delay)
+					if((m.param & 0xF0) == 0x60 || (m.param & 0xF0) == 0xE0)
+						m.command = CMD_MODCMDEX;
+					else
+						m.command = m.param = 0;
+					break;
+
+				case 0x4F: // set speed/tempo
+					if(m.param < 0x20)
+					{
+						m.command = CMD_SPEED;
+						fileHeader.speedFrac = 0;
+					} else
+					{
+						m.command = CMD_TEMPO;
+					}
+					break;
+
+				default:
+					m.command = CMD_NONE;
+					break;
+				}
+
+				bool didVolSlide = false;
+
+				// try to put volume slide in volume command
+				if(chnMem.autoVolSlide && !m.volcmd)
+				{
+					if(chnMem.autoVolSlide & 0xF0)
+					{
+						m.volcmd = VOLCMD_FINEVOLUP;
+						m.vol = chnMem.autoVolSlide >> 4;
+					} else
+					{
+						m.volcmd = VOLCMD_FINEVOLDOWN;
+						m.vol = chnMem.autoVolSlide & 0xF;
+					}
+					didVolSlide = true;
+				}
+
+				// try to place/combine all remaining running effects.
+				if(m.command == CMD_NONE)
+				{
+					if(chnMem.autoPortaUp)
+					{
+						m.command = CMD_PORTAMENTOUP;
+						m.param = chnMem.autoPortaUp;
+
+					} else if(chnMem.autoPortaDown)
+					{
+						m.command = CMD_PORTAMENTODOWN;
+						m.param = chnMem.autoPortaDown;
+					} else if(chnMem.autoFinePorta)
+					{
+						m.command = CMD_MODCMDEX;
+						m.param = chnMem.autoFinePorta;
+
+					} else if(chnMem.autoTonePorta)
+					{
+						m.command = CMD_TONEPORTAMENTO;
+						m.param = chnMem.tonePortaMem = chnMem.autoTonePorta;
+
+					} else if(chnMem.autoVibrato)
+					{
+						m.command = CMD_VIBRATO;
+						m.param = chnMem.vibratoMem = chnMem.autoVibrato;
+
+					} else if(!didVolSlide && chnMem.autoVolSlide)
+					{
+						m.command = CMD_VOLUMESLIDE;
+						m.param = chnMem.autoVolSlide;
+						// convert to a "fine" value by setting the other nibble to 0xF
+						if(m.param & 0x0F)
+							m.param |= 0xF0;
+						else if(m.param & 0xF0)
+							m.param |= 0x0F;
+						didVolSlide = true;
+
+					} else if(chnMem.autoTremolo)
+					{
+						m.command = CMD_TREMOLO;
+						m.param = chnMem.autoTremolo;
+
+					} else if(shouldDelay)
+					{
+						// insert a fine pattern delay here
+						m.command = CMD_S3MCMDEX;
+						m.param = 0x61;
+						shouldDelay = false;
+
+					} else if(!didGlobalVolSlide && globalVolSlide)
+					{
+						m.command = CMD_GLOBALVOLSLIDE;
+						m.param = globalVolSlide;
+						// convert to a "fine" value by setting the other nibble to 0xF
+						if(m.param & 0x0F)
+							m.param |= 0xF0;
+						else if(m.param & 0xF0)
+							m.param |= 0x0F;
+
+						didGlobalVolSlide = true;
+					}
+				}
+			}
+
+			// TODO: create/use extra channels for global volslide/delay if needed
+		}
+	}
+
+	// after we know how many channels there really are...
+	m_nSamplePreAmp = 256 / m_nChannels;
+	// Setup channel pan positions and volume
+	SetupMODPanning(true);
+
+	// Skip over scripts and drumpad info
+	if(fileHeader.version > 0)
+	{
+		while(file.CanRead(2))
+		{
+			uint16 scriptNum = file.ReadUint16BE();
+			if(scriptNum == 0xFFFF)
+				break;
+
+			file.Skip(2);
+			uint32 length = file.ReadUint32BE();
+			file.Skip(length);
+		}
+
+		// Skip drumpad stuff
+		file.Skip(17 * 2);
+	}
+
+	// Reading samples
+	if(loadFlags & loadSampleData)
+	{
+		for(SAMPLEINDEX smp = 1; smp <= samplesInFile; smp++) if(Samples[smp].nLength)
+		{
+			SampleIO(
+				SampleIO::_8bit,
+				SampleIO::mono,
+				SampleIO::littleEndian,
+				SampleIO::signedPCM)
+				.ReadSample(Samples[smp], file);
+
+			if(smp > loopInfo.size())
+				continue;
+
+			ConvertLoopSequence(Samples[smp], loopInfo[smp - 1]);
+
+			// make a non-looping duplicate of this sample if needed
+			if(nonLooped[smp - 1])
+			{
+				ConvertLoopSlice(Samples[smp], Samples[nonLooped[smp - 1]], 0, Samples[smp].nLength, false);
+			}
+
+			for(const auto &info : loopInfo[smp - 1])
+			{
+				// make duplicate samples for this individual section if needed
+				if(info.looped)
+				{
+					ConvertLoopSlice(Samples[smp], Samples[info.looped], info.loopStart, info.loopLength, true);
+				}
+				if(info.nonLooped)
+				{
+					ConvertLoopSlice(Samples[smp], Samples[info.nonLooped], info.loopStart, info.loopLength, false);
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/Load_uax.cpp b/soundlib/Load_uax.cpp
new file mode 100644
index 0000000..46758c4
--- /dev/null
+++ b/soundlib/Load_uax.cpp
@@ -0,0 +1,183 @@
+/*
+ * Load_uax.cpp
+ * ------------
+ * Purpose: UAX (Unreal Sounds) module ripper
+ * Notes  : The sounds are read into module sample slots.
+ * Authors: Johannes Schultz (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format)
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Loaders.h"
+#include "UMXTools.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+bool CSoundFile::ReadUAX(FileReader &file, ModLoadingFlags loadFlags)
+{
+	file.Rewind();
+	UMXFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader)
+		|| memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
+		|| fileHeader.nameCount == 0
+		|| fileHeader.exportCount == 0
+		|| fileHeader.importCount == 0
+		)
+	{
+		return false;
+	}
+
+	// Note that this can be a false positive, e.g. Unreal maps will have music and sound
+	// in their name table because they usually import such files. However, it spares us
+	// from wildly seeking through the file, as the name table is usually right at the
+	// start of the file, so it is hopefully a good enough heuristic for our purposes.
+	if(!FindUMXNameTableEntry(file, fileHeader, "sound"))
+	{
+		return false;
+	}
+
+	if(loadFlags == onlyVerifyHeader)
+	{
+		return true;
+	}
+
+	// Read name table
+	std::vector<std::string> names = ReadUMXNameTable(file, fileHeader);
+
+	// Read import table
+	if(!file.Seek(fileHeader.importOffset))
+	{
+		return false;
+	}
+
+	std::vector<int32> classes;
+	classes.reserve(fileHeader.importCount);
+	for(uint32 i = 0; i < fileHeader.importCount && file.CanRead(4); i++)
+	{
+		int32 objName = ReadUMXImportTableEntry(file, fileHeader.packageVersion);
+		if(static_cast<size_t>(objName) < names.size())
+		{
+			classes.push_back(objName);
+		}
+	}
+
+	// Read export table
+	if(!file.Seek(fileHeader.exportOffset))
+	{
+		return false;
+	}
+
+	// Now we can be pretty sure that we're doing the right thing.
+	InitializeGlobals();
+	m_madeWithTracker = mpt::format(MPT_USTRING("Unreal Package v%1"))(fileHeader.packageVersion);
+	
+	for(uint32 i = 0; i < fileHeader.exportCount && file.CanRead(4); i++)
+	{
+		int32 objClass, objOffset, objSize, objName;
+		ReadUMXExportTableEntry(file, objClass, objOffset, objSize, objName, fileHeader.packageVersion);
+
+		if(objSize <= 0 || objClass >= 0)
+		{
+			continue;
+		}
+
+		// Look up object class name (we only want sounds).
+		objClass = -objClass - 1;
+		bool isSound = false;
+		if(static_cast<size_t>(objClass) < classes.size())
+		{
+			isSound = (names[classes[objClass]] == "sound");
+		}
+		if(!isSound)
+		{
+			continue;
+		}
+
+		FileReader chunk = file.GetChunkAt(objOffset, objSize);
+
+		if(chunk.IsValid())
+		{
+			if(fileHeader.packageVersion < 40)
+			{
+				chunk.Skip(8); // 00 00 00 00 00 00 00 00
+			}
+			if(fileHeader.packageVersion < 60)
+			{
+				chunk.Skip(16); // 81 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00
+			}
+			// Read object properties
+#if 0
+			size_t propertyName = static_cast<size_t>(ReadUMXIndex(chunk));
+			if(propertyName >= names.size() || names[propertyName] != "none")
+			{
+				// Can't bother to implement property reading, as no UMX files I've seen so far use properties for the relevant objects,
+				// and only the UAX files in the Unreal 1997/98 beta seem to use this and still load just fine when ignoring it.
+				// If it should be necessary to implement this, check CUnProperty.cpp in http://ut-files.com/index.php?dir=Utilities/&file=utcms_source.zip
+				MPT_ASSERT_NOTREACHED();
+				continue;
+			}
+#else
+			ReadUMXIndex(chunk);
+#endif
+
+			if(fileHeader.packageVersion >= 120)
+			{
+				// UT2003 Packages
+				ReadUMXIndex(chunk);
+				chunk.Skip(8);
+			} else if(fileHeader.packageVersion >= 100)
+			{
+				// AAO Packages
+				chunk.Skip(4);
+				ReadUMXIndex(chunk);
+				chunk.Skip(4);
+			} else if(fileHeader.packageVersion >= 62)
+			{
+				// UT Packages
+				// Mech8.umx and a few other UT tunes have packageVersion = 62.
+				// In CUnSound.cpp, the condition above reads "packageVersion >= 63" but if that is used, those tunes won't load properly.
+				ReadUMXIndex(chunk);
+				chunk.Skip(4);
+			} else
+			{
+				// Old Unreal Packagaes
+				ReadUMXIndex(chunk);
+			}
+			int32 size = ReadUMXIndex(chunk);
+
+			FileReader fileChunk = chunk.ReadChunk(size);
+
+			if(GetNumSamples() < MAX_SAMPLES - 1)
+			{
+				// Read as sample
+				if(ReadSampleFromFile(GetNumSamples() + 1, fileChunk, true))
+				{
+					if(static_cast<size_t>(objName) < names.size())
+					{
+						mpt::String::Copy(m_szNames[GetNumSamples()], names[objName]);
+					}
+				}
+			}
+		}
+	}
+
+	if(m_nSamples != 0)
+	{
+		InitializeChannels();
+		SetType(MOD_TYPE_MPT);
+		m_ContainerType = MOD_CONTAINERTYPE_UAX;
+		m_nChannels = 4;
+		Patterns.Insert(0, 64);
+		Order().assign(1, 0);
+		return true;
+	} else
+	{
+		return false;
+	}
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/Load_ult.cpp b/soundlib/Load_ult.cpp
index 0feec48..37417c5 100644
--- a/soundlib/Load_ult.cpp
+++ b/soundlib/Load_ult.cpp
@@ -14,11 +14,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED UltFileHeader
+struct UltFileHeader
 {
 	char  signature[14];		// "MAS_UTrack_V00"
 	uint8 version;				// '1'...'4'
@@ -26,10 +22,10 @@ struct PACKED UltFileHeader
 	uint8 messageLength;		// Number of Lines
 };
 
-STATIC_ASSERT(sizeof(UltFileHeader) == 48);
+MPT_BINARY_STRUCT(UltFileHeader, 48)
 
 
-struct PACKED UltSample
+struct UltSample
 {
 	enum UltSampleFlags
 	{
@@ -38,27 +34,16 @@ struct PACKED UltSample
 		ULT_PINGPONGLOOP = 16,
 	};
 
-	char   name[32];
-	char   filename[12];
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint32 sizeStart;
-	uint32 sizeEnd;
-	uint8  volume;		// 0-255, apparently prior to 1.4 this was logarithmic?
-	uint8  flags;		// above
-	uint16 speed;		// only exists for 1.4+
-	int16  finetune;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sizeStart);
-		SwapBytesLE(sizeEnd);
-		SwapBytesLE(speed);
-		SwapBytesLE(finetune);
-	}
+	char     name[32];
+	char     filename[12];
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint32le sizeStart;
+	uint32le sizeEnd;
+	uint8le  volume;	// 0-255, apparently prior to 1.4 this was logarithmic?
+	uint8le  flags;		// above
+	uint16le speed;		// only exists for 1.4+
+	int16le  finetune;
 
 	// Convert an ULT sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const
@@ -80,7 +65,7 @@ struct PACKED UltSample
 		mptSmp.nC5Speed = speed;
 		if(finetune)
 		{
-			mptSmp.nC5Speed = Util::Round<uint32>(mptSmp.nC5Speed * pow(2.0, finetune / (12.0 * 32768.0)));
+			mptSmp.Transpose(finetune / (12.0 * 32768.0));
 		}
 
 		if(flags & ULT_LOOP)
@@ -97,11 +82,8 @@ struct PACKED UltSample
 	}
 };
 
-STATIC_ASSERT(sizeof(UltSample) == 66);
+MPT_BINARY_STRUCT(UltSample, 66)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
 /* Unhandled effects:
 5x1 - do not loop sample (x is unused)
@@ -115,7 +97,6 @@ convert them. */
 
 
 static void TranslateULTCommands(uint8 &effect, uint8 &param, uint8 version)
-//--------------------------------------------------------------------------
 {
 
 	static const uint8 ultEffTrans[] =
@@ -222,7 +203,6 @@ static void TranslateULTCommands(uint8 &effect, uint8 &param, uint8 version)
 
 
 static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version)
-//---------------------------------------------------------------------
 {
 	uint8 b, repeat = 1;
 	uint8 cmd1, cmd2;	// 1 = vol col, 2 = fx col in the original schismtracker code
@@ -286,7 +266,6 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version)
 
 // Functor for postfixing ULT patterns (this is easier than just remembering everything WHILE we're reading the pattern events)
 struct PostFixUltCommands
-//=======================
 {
 	PostFixUltCommands(CHANNELINDEX numChannels)
 	{
@@ -349,25 +328,54 @@ struct PostFixUltCommands
 	}
 
 	std::vector<bool> isPortaActive;
-	bool writeT125;
 	CHANNELINDEX numChannels, curChannel;
+	bool writeT125;
 };
 
 
+static bool ValidateHeader(const UltFileHeader &fileHeader)
+{
+	if(fileHeader.version < '1'
+		|| fileHeader.version > '4'
+		|| std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature))
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize)
+{
+	UltFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
-	UltFileHeader fileHeader;
 
-	// Tracker ID
-	if(!file.ReadStruct(fileHeader)
-		|| fileHeader.version < '1'
-		|| fileHeader.version > '4'
-		|| memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature)) != 0)
+	UltFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -375,8 +383,8 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
 	InitializeGlobals(MOD_TYPE_ULT);
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songName);
 
-	const char *versions[] = {"<1.4", "1.4", "1.5", "1.6"};
-	m_madeWithTracker = "UltraTracker ";
+	const MPT_UCHAR_TYPE *versions[] = {MPT_ULITERAL("<1.4"), MPT_ULITERAL("1.4"), MPT_ULITERAL("1.5"), MPT_ULITERAL("1.6")};
+	m_madeWithTracker = MPT_USTRING("UltraTracker ");
 	m_madeWithTracker += versions[fileHeader.version - '1'];
 
 	m_SongFlags = SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS;	// this will be converted to IT format by MPT.
@@ -395,11 +403,10 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
 		// Annoying: v4 added a field before the end of the struct
 		if(fileHeader.version >= '4')
 		{
-			file.ReadConvertEndianness(sampleHeader);
+			file.ReadStruct(sampleHeader);
 		} else
 		{
 			file.ReadStructPartial(sampleHeader, 64);
-			sampleHeader.ConvertEndianness();
 			sampleHeader.finetune = sampleHeader.speed;
 			sampleHeader.speed = 8363;
 		}
@@ -408,12 +415,12 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
 		mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp], sampleHeader.name);
 	}
 
-	Order.ReadAsByte(file, 256, 256, 0xFF, 0xFE);
+	ReadOrderFromFile<uint8>(Order(), file, 256, 0xFF, 0xFE);
 
 	m_nChannels = file.ReadUint8() + 1;
 	PATTERNINDEX numPats = file.ReadUint8() + 1;
 
-	if(GetNumChannels() > MAX_BASECHANNELS || numPats > MAX_PATTERNS)
+	if(GetNumChannels() > MAX_BASECHANNELS)
 		return false;
 
 	for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
@@ -425,6 +432,7 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
 			ChnSettings[chn].nPan = (chn & 1) ? 192 : 64;
 	}
 
+	Patterns.ResizeArray(numPats);
 	for(PATTERNINDEX pat = 0; pat < numPats; pat++)
 	{
 		if(!Patterns.Insert(pat, 64))
@@ -439,7 +447,7 @@ bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
 
 		for(PATTERNINDEX pat = 0; pat < numPats; pat++)
 		{
-			note = Patterns[pat] + chn;
+			note = Patterns[pat].GetpModCommand(0, chn);
 			ROWINDEX row = 0;
 			while(row < 64)
 			{
diff --git a/soundlib/Load_umx.cpp b/soundlib/Load_umx.cpp
deleted file mode 100644
index c8eaab0..0000000
--- a/soundlib/Load_umx.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Load_umx.cpp
- * ------------
- * Purpose: UMX (Unreal Music) and UAX (Unreal Sounds) module ripper
- * Notes  : Obviously, this code only rips modules from older Unreal Engine games, such as Unreal 1, Unreal Tournament 1 and Deus Ex.
- *          For UAX sound packages, the sounds are read into module sample slots.
- * Authors: Johannes Schultz (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format)
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
-
-
-#include "stdafx.h"
-#include "Loaders.h"
-
-OPENMPT_NAMESPACE_BEGIN
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-// UMX File Header
-struct PACKED UMXFileHeader
-{
-	// Magic Bytes
-	static const uint32 magicBytes = 0x9E2A83C1u;
-
-	uint32 magic;
-	uint16 packageVersion;
-	uint16 licenseMode;
-	uint32 flags;
-	uint32 nameCount;
-	uint32 nameOffset;
-	uint32 exportCount;
-	uint32 exportOffset;
-	uint32 importCount;
-	uint32 importOffset;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(magic);
-		SwapBytesLE(packageVersion);
-		// Don't need the rest.
-		SwapBytesLE(nameCount);
-		SwapBytesLE(nameOffset);
-		SwapBytesLE(exportCount);
-		SwapBytesLE(exportOffset);
-		SwapBytesLE(importCount);
-		SwapBytesLE(importOffset);
-	}
-};
-
-STATIC_ASSERT(sizeof(UMXFileHeader) == 36);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
-#ifdef MODPLUG_TRACKER
-#define MPT_IMPORT_UAX	// Support loading of sound files (load sounds into sample slots)
-#endif // MODPLUG_TRACKER
-
-
-// Read compressed unreal integers - similar to MIDI integers, but signed values are possible.
-static int32 ReadUMXIndex(FileReader &chunk)
-//------------------------------------------
-{
-	enum
-	{
-		signMask		= 0x80,	// Highest bit of first byte indicates if value is signed
-		valueMask1		= 0x3F,	// Low 6 bits of first byte are actual value
-		continueMask1	= 0x40,	// Second-highest bit of first byte indicates if further bytes follow
-		valueMask		= 0x7F,	// Low 7 bits of following bytes are actual value
-		continueMask	= 0x80,	// Highest bit of following bytes indicates if further bytes follow
-	};
-
-	// Read first byte
-	uint8 b = chunk.ReadUint8();
-	bool isSigned = (b & signMask) != 0;
-	int32 result = (b & valueMask1);
-	int shift = 6;
-
-	if(b & continueMask1)
-	{
-		// Read remaining bytes
-		do
-		{
-			b = chunk.ReadUint8();
-			int32 data = static_cast<int32>(b) & valueMask;
-			data <<= shift;
-			result |= data;
-			shift += 7;
-		} while((b & continueMask) != 0 && (shift < 32));
-	}
-
-	if(isSigned)
-	{
-		result = -result;
-	}
-	return result;
-}
-
-
-// Read an entry from the name table.
-static std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion)
-//--------------------------------------------------------------------------------
-{
-	std::string name;
-	if(packageVersion >= 64)
-	{
-		// String length
-		int32 length = ReadUMXIndex(chunk);
-		if(length <= 0)
-		{
-			return "";
-		}
-		name.reserve(length);
-	}
-
-	// Simple zero-terminated string
-	uint8 chr;
-	while((chr = chunk.ReadUint8()) != 0)
-	{
-		// Convert string to lower case
-		if(chr >= 'A' && chr <= 'Z')
-		{
-			chr = chr - 'A' + 'a';
-		}
-		name.append(1, static_cast<char>(chr));
-	}
-
-	chunk.Skip(4);	// Object flags
-	return name;
-}
-
-
-// Read an entry from the import table.
-static int32 ReadUMXImportTableEntry(FileReader &chunk, uint16 packageVersion)
-//----------------------------------------------------------------------------
-{
-	ReadUMXIndex(chunk);		// Class package
-	ReadUMXIndex(chunk);		// Class name
-	if(packageVersion >= 60)
-	{
-		chunk.Skip(4); // Package
-	} else
-	{
-		ReadUMXIndex(chunk); // ??
-	}
-	return ReadUMXIndex(chunk);	// Object name (offset into the name table)
-}
-
-
-// Read an entry from the export table.
-static void ReadUMXExportTableEntry(FileReader &chunk, int32 &objClass, int32 &objOffset, int32 &objSize, int32 &objName, uint16 packageVersion)
-//----------------------------------------------------------------------------------------------------------------------------------------------
-{
-	objClass = ReadUMXIndex(chunk);	// Object class
-	ReadUMXIndex(chunk);			// Object parent
-	if(packageVersion >= 60)
-	{
-		chunk.Skip(4);				// Internal package / group of the object
-	}
-	objName = ReadUMXIndex(chunk);	// Object name (offset into the name table)
-	chunk.Skip(4);					// Object flags
-	objSize = ReadUMXIndex(chunk);
-	if(objSize > 0)
-	{
-		objOffset = ReadUMXIndex(chunk);
-	}
-}
-
-
-bool CSoundFile::ReadUMX(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
-{
-	file.Rewind();
-	UMXFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| fileHeader.magic != UMXFileHeader::magicBytes
-		|| !file.Seek(fileHeader.nameOffset))
-	{
-		return false;
-	}
-
-	// Read name table
-	std::vector<std::string> names;
-	names.reserve(fileHeader.nameCount);
-	bool hasContent = false;
-	for(uint32 i = 0; i < fileHeader.nameCount && file.CanRead(4); i++)
-	{
-		names.push_back(ReadUMXNameTableEntry(file, fileHeader.packageVersion));
-		if(names.back() == "music"
-#ifdef MPT_IMPORT_UAX
-			|| names.back() == "sound"
-#endif // MPT_IMPORT_UAX
-			)
-		{
-			// Note that this can be a false positive, e.g. Unreal maps will have music and sound
-			// in their name table because they usually import such files. However, it spares us
-			// from wildly seeking through the file, as the name table is usually right at the
-			// start of the file, so it is hopefully a good enough heuristic for our purposes.
-			if(loadFlags == onlyVerifyHeader)
-			{
-				return true;
-			}
-			hasContent = true;
-		}
-	}
-
-	// No music or sounds in this file
-	if(!hasContent)
-	{
-		return false;
-	}
-
-	// Read import table
-	if(!file.Seek(fileHeader.importOffset))
-	{
-		return false;
-	}
-
-	std::vector<int32> classes;
-	classes.reserve(fileHeader.importCount);
-	for(uint32 i = 0; i < fileHeader.importCount && file.CanRead(4); i++)
-	{
-		int32 objName = ReadUMXImportTableEntry(file, fileHeader.packageVersion);
-		if(static_cast<size_t>(objName) < names.size())
-		{
-			classes.push_back(objName);
-		}
-	}
-
-	// Read export table
-	if(!file.Seek(fileHeader.exportOffset))
-	{
-		return false;
-	}
-
-	// Now we can be pretty sure that we're doing the right thing.
-	InitializeGlobals();
-	m_madeWithTracker = mpt::String::Print("Unreal Package v%1", fileHeader.packageVersion);
-	
-	for(uint32 i = 0; i < fileHeader.exportCount && file.CanRead(4); i++)
-	{
-		int32 objClass, objOffset, objSize, objName;
-		ReadUMXExportTableEntry(file, objClass, objOffset, objSize, objName, fileHeader.packageVersion);
-
-		if(objSize <= 0 || objClass >= 0)
-		{
-			continue;
-		}
-
-		// Look up object class name (we only want music and sounds).
-		objClass = -objClass - 1;
-		bool isMusic = false;
-#ifdef MPT_IMPORT_UAX
-		bool isSound = false;
-#endif // MPT_IMPORT_UAX
-		if(static_cast<size_t>(objClass) < classes.size())
-		{
-			const char *objClassName = names[classes[objClass]].c_str();
-			isMusic = !strcmp(objClassName, "music");
-#ifdef MPT_IMPORT_UAX
-			isSound = !strcmp(objClassName, "sound");
-#endif // MPT_IMPORT_UAX
-		}
-		if(!isMusic
-#ifdef MPT_IMPORT_UAX
-			&& !isSound
-#endif // MPT_IMPORT_UAX
-			)
-		{
-			continue;
-		}
-
-		FileReader chunk = file.GetChunkAt(objOffset, objSize);
-
-		if(chunk.IsValid())
-		{
-			if(fileHeader.packageVersion < 40)
-			{
-				chunk.Skip(8); // 00 00 00 00 00 00 00 00
-			}
-			if(fileHeader.packageVersion < 60)
-			{
-				chunk.Skip(16); // 81 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00
-			}
-			// Read object properties
-#if 0
-			size_t propertyName = static_cast<size_t>(ReadUMXIndex(chunk));
-			if(propertyName >= names.size() || names[propertyName] != "none")
-			{
-				// Can't bother to implement property reading, as no UMX files I've seen so far use properties for the relevant objects,
-				// and only the UAX files in the Unreal 1997/98 beta seem to use this and still load just fine when ignoring it.
-				// If it should be necessary to implement this, check CUnProperty.cpp in http://ut-files.com/index.php?dir=Utilities/&file=utcms_source.zip
-				MPT_ASSERT_NOTREACHED();
-				continue;
-			}
-#else
-			ReadUMXIndex(chunk);
-#endif
-
-			if(fileHeader.packageVersion >= 120)
-			{
-				// UT2003 Packages
-				ReadUMXIndex(chunk);
-				chunk.Skip(8);
-			} else if(fileHeader.packageVersion >= 100)
-			{
-				// AAO Packages
-				chunk.Skip(4);
-				ReadUMXIndex(chunk);
-				chunk.Skip(4);
-			} else if(fileHeader.packageVersion >= 62)
-			{
-				// UT Packages
-				// Mech8.umx and a few other UT tunes have packageVersion = 62.
-				// In CUnSound.cpp, the condition above reads "packageVersion >= 63" but if that is used, those tunes won't load properly.
-				ReadUMXIndex(chunk);
-				chunk.Skip(4);
-			} else
-			{
-				// Old Unreal Packagaes
-				ReadUMXIndex(chunk);
-			}
-			int32 size = ReadUMXIndex(chunk);
-
-			FileReader fileChunk = chunk.ReadChunk(size);
-
-			if(isMusic)
-			{
-				// Read as module
-				if(ReadIT(fileChunk, loadFlags)
-					|| ReadXM(fileChunk, loadFlags)
-					|| ReadS3M(fileChunk, loadFlags)
-					|| ReadWav(fileChunk, loadFlags)
-					|| ReadSTM(fileChunk, loadFlags)
-					|| Read669(fileChunk, loadFlags)
-					|| ReadFAR(fileChunk, loadFlags)
-					|| ReadMod(fileChunk, loadFlags)
-					|| ReadM15(fileChunk, loadFlags))
-				{
-					m_ContainerType = MOD_CONTAINERTYPE_UMX;
-					return true;
-				}
-#ifdef MPT_IMPORT_UAX
-			} else if(isSound && GetNumSamples() < MAX_SAMPLES - 1)
-			{
-				// Read as sample
-				if(ReadSampleFromFile(GetNumSamples() + 1, fileChunk, true))
-				{
-					if(static_cast<size_t>(objName) < names.size())
-					{
-						mpt::String::Copy(m_szNames[GetNumSamples()], names[objName]);
-					}
-				}
-#endif // MPT_IMPORT_UAX
-			}
-		}
-	}
-
-#ifdef MPT_IMPORT_UAX
-	if(m_nSamples != 0)
-	{
-		InitializeChannels();
-		SetType(MOD_TYPE_UAX);
-		m_nChannels = 4;
-		Patterns.Insert(0, 64);
-		Order[0] = 0;
-		return true;
-	} else
-#endif // MPT_IMPORT_UAX
-	{
-		return false;
-	}
-}
-
-
-OPENMPT_NAMESPACE_END
diff --git a/soundlib/Load_wav.cpp b/soundlib/Load_wav.cpp
index daac768..9e589fb 100644
--- a/soundlib/Load_wav.cpp
+++ b/soundlib/Load_wav.cpp
@@ -12,7 +12,8 @@
 #include "stdafx.h"
 #include "Loaders.h"
 #include "WAVTools.h"
-#include "SampleFormatConverters.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
@@ -24,7 +25,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 template <typename SampleConversion>
 bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelIndex, size_t numChannels, SampleConversion conv = SampleConversion())
-//-------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	MPT_ASSERT(sample.GetNumChannels() == 1);
 	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
@@ -43,7 +43,6 @@ bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelInd
 
 
 bool CSoundFile::ReadWav(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 	WAVReader wavFile(file);
 
@@ -60,8 +59,10 @@ bool CSoundFile::ReadWav(FileReader &file, ModLoadingFlags loadFlags)
 		return true;
 	}
 
-	InitializeGlobals(MOD_TYPE_WAV);
+	InitializeGlobals(MOD_TYPE_MPT);
+	m_ContainerType = MOD_CONTAINERTYPE_WAV;
 	m_nChannels = std::max(wavFile.GetNumChannels(), uint16(2));
+	Patterns.ResizeArray(2);
 	if(!Patterns.Insert(0, 64) || !Patterns.Insert(1, 64))
 	{
 		return false;
@@ -75,20 +76,14 @@ bool CSoundFile::ReadWav(FileReader &file, ModLoadingFlags loadFlags)
 	const uint32 sampleTicks = mpt::saturate_cast<uint32>(((sampleLength * 50) / sampleRate) + 1);
 	uint32 ticksPerRow = std::max((sampleTicks + 63u) / 63u, 1u);
 
-	Order.clear();
-	Order.Append(0);
+	Order().assign(1, 0);
 	ORDERINDEX numOrders = 1;
-	while(ticksPerRow >= 32)
+	while(ticksPerRow >= 32 && numOrders < MAX_ORDERS)
 	{
-		Order.Append(1);
-
 		numOrders++;
 		ticksPerRow = (sampleTicks + (64 * numOrders - 1)) / (64 * numOrders);
-		if(numOrders == MAX_ORDERS)
-		{
-			break;
-		}
 	}
+	Order().resize(numOrders, 1);
 
 	m_nSamples = wavFile.GetNumChannels();
 	m_nInstruments = 0;
diff --git a/soundlib/Load_xm.cpp b/soundlib/Load_xm.cpp
index 6607572..4394ed9 100644
--- a/soundlib/Load_xm.cpp
+++ b/soundlib/Load_xm.cpp
@@ -28,11 +28,11 @@ OPENMPT_NAMESPACE_BEGIN
 
 // Allocate samples for an instrument
 static std::vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEINDEX numSamples)
-//--------------------------------------------------------------------------------------------
 {
 	LimitMax(numSamples, SAMPLEINDEX(32));
 
 	std::vector<SAMPLEINDEX> foundSlots;
+	foundSlots.reserve(numSamples);
 
 	for(SAMPLEINDEX i = 0; i < numSamples; i++)
 	{
@@ -60,11 +60,11 @@ static std::vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEIND
 						{
 							continue;
 						}
-						for(size_t k = 0; k < CountOf(sndFile.Instruments[ins]->Keyboard); k++)
+						for(auto &sample : sndFile.Instruments[ins]->Keyboard)
 						{
-							if(sndFile.Instruments[ins]->Keyboard[k] == candidateSlot)
+							if(sample == candidateSlot)
 							{
-								sndFile.Instruments[ins]->Keyboard[k] = 0;
+								sample = 0;
 							}
 						}
 					}
@@ -89,11 +89,11 @@ static std::vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEIND
 					{
 						continue;
 					}
-					for(size_t k = 0; k < CountOf(sndFile.Instruments[ins]->Keyboard); k++)
+					for(auto &sample : sndFile.Instruments[ins]->Keyboard)
 					{
-						if(sndFile.Instruments[ins]->Keyboard[k] < usedSamples.size() && !usedSamples[sndFile.Instruments[ins]->Keyboard[k]])
+						if(sample < usedSamples.size() && !usedSamples[sample])
 						{
-							sndFile.Instruments[ins]->Keyboard[k] = 0;
+							sample = 0;
 						}
 					}
 				}
@@ -123,7 +123,6 @@ static std::vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEIND
 
 // Read .XM patterns
 static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSoundFile &sndFile)
-//-----------------------------------------------------------------------------------------------
 {
 	// Reading patterns
 	sndFile.Patterns.ResizeArray(fileHeader.patterns);
@@ -171,8 +170,7 @@ static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSo
 			paramPresent	= 0x10,
 		};
 
-		ModCommand *m = sndFile.Patterns[pat];
-		for(size_t numCommands = numRows * fileHeader.channels; numCommands != 0; numCommands--, m++)
+		for(auto &m : sndFile.Patterns[pat])
 		{
 			uint8 info = patternChunk.ReadUint8();
 
@@ -180,47 +178,47 @@ static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSo
 			if(info & isPackByte)
 			{
 				// Interpret byte as flag set.
-				if(info & notePresent) m->note = patternChunk.ReadUint8();
+				if(info & notePresent) m.note = patternChunk.ReadUint8();
 			} else
 			{
 				// Interpret byte as note, read all other pattern fields as well.
-				m->note = info;
+				m.note = info;
 				info = allFlags;
 			}
 
-			if(info & instrPresent) m->instr = patternChunk.ReadUint8();
+			if(info & instrPresent) m.instr = patternChunk.ReadUint8();
 			if(info & volPresent) vol = patternChunk.ReadUint8();
-			if(info & commandPresent) m->command = patternChunk.ReadUint8();
-			if(info & paramPresent) m->param = patternChunk.ReadUint8();
+			if(info & commandPresent) m.command = patternChunk.ReadUint8();
+			if(info & paramPresent) m.param = patternChunk.ReadUint8();
 
-			if(m->note == 97)
+			if(m.note == 97)
 			{
-				m->note = NOTE_KEYOFF;
-			} else if(m->note > 0 && m->note < 97)
+				m.note = NOTE_KEYOFF;
+			} else if(m.note > 0 && m.note < 97)
 			{
-				m->note += 12;
+				m.note += 12;
 			} else
 			{
-				m->note = NOTE_NONE;
+				m.note = NOTE_NONE;
 			}
 
-			if(m->command | m->param)
+			if(m.command | m.param)
 			{
-				CSoundFile::ConvertModCommand(*m);
+				CSoundFile::ConvertModCommand(m);
 			} else
 			{
-				m->command = CMD_NONE;
+				m.command = CMD_NONE;
 			}
 
-			if(m->instr == 0xFF)
+			if(m.instr == 0xFF)
 			{
-				m->instr = 0;
+				m.instr = 0;
 			}
 
 			if(vol >= 0x10 && vol <= 0x50)
 			{
-				m->volcmd = VOLCMD_VOLUME;
-				m->vol = vol - 0x10;
+				m.volcmd = VOLCMD_VOLUME;
+				m.vol = vol - 0x10;
 			} else if (vol >= 0x60)
 			{
 				// Volume commands 6-F translation.
@@ -231,12 +229,12 @@ static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSo
 					VOLCMD_PANSLIDERIGHT, VOLCMD_TONEPORTAMENTO,
 				};
 
-				m->volcmd = volEffTrans[(vol - 0x60) >> 4];
-				m->vol = vol & 0x0F;
+				m.volcmd = volEffTrans[(vol - 0x60) >> 4];
+				m.vol = vol & 0x0F;
 
-				if(m->volcmd == VOLCMD_PANNING)
+				if(m.volcmd == VOLCMD_PANNING)
 				{
-					m->vol *= 4;	// FT2 does indeed not scale panning symmetrically.
+					m.vol *= 4;	// FT2 does indeed not scale panning symmetrically.
 				}
 			}
 		}
@@ -262,17 +260,54 @@ enum TrackerVersions
 DECLARE_FLAGSET(TrackerVersions)
 
 
+static bool ValidateHeader(const XMFileHeader &fileHeader)
+{
+	if(fileHeader.channels == 0
+		|| fileHeader.channels > MAX_BASECHANNELS
+		|| std::memcmp(fileHeader.signature, "Extended Module: ", 17)
+		)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const XMFileHeader &fileHeader)
+{
+	return fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	XMFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
 bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
-//------------------------------------------------------------------
 {
 	file.Rewind();
 
 	XMFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
-		|| fileHeader.channels == 0
-		|| fileHeader.channels > MAX_BASECHANNELS
-		|| mpt::CompareNoCaseAscii(fileHeader.signature, "Extended Module: ", 17)
-		|| !file.CanRead(fileHeader.orders))
+	if(!file.ReadStruct(fileHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
 	{
 		return false;
 	} else if(loadFlags == onlyVerifyHeader)
@@ -305,14 +340,14 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 		{
 			// ???
 			madeWith.set(verConfirmed);
-			m_madeWithTracker = "FastTracker Clone";
+			m_madeWithTracker = MPT_USTRING("FastTracker Clone");
 		}
 	} else
 	{
 		// Something else!
 		madeWith = verUnknown | verConfirmed;
 
-		mpt::String::Read<mpt::String::spacePadded>(m_madeWithTracker, fileHeader.trackerName);
+		mpt::String::Read<mpt::String::spacePadded>(m_madeWithTracker, mpt::CharsetCP437, fileHeader.trackerName);
 
 		if(!memcmp(fileHeader.trackerName, "MilkyTracker ", 12))
 		{
@@ -342,13 +377,13 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 	m_nMinPeriod = 1;
 	m_nMaxPeriod = 31999;
 
-	Order.SetRestartPos(fileHeader.restartPos);
+	Order().SetRestartPos(fileHeader.restartPos);
 	m_nChannels = fileHeader.channels;
-	m_nInstruments = std::min(fileHeader.instruments, uint16(MAX_INSTRUMENTS - 1));
+	m_nInstruments = std::min<uint16>(fileHeader.instruments, MAX_INSTRUMENTS - 1u);
 	if(fileHeader.speed)
 		m_nDefaultSpeed = fileHeader.speed;
 	if(fileHeader.tempo)
-		m_nDefaultTempo.Set(Clamp(fileHeader.tempo, uint16(32), uint16(512)));
+		m_nDefaultTempo.Set(Clamp<uint16, uint16>(fileHeader.tempo, 32, 512));
 
 	m_SongFlags.reset();
 	m_SongFlags.set(SONG_LINEARSLIDES, (fileHeader.flags & XMFileHeader::linearSlides) != 0);
@@ -358,12 +393,11 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 		madeWith = verFT2Clone | verNewModPlug | verConfirmed;
 	}
 
-	Order.ReadAsByte(file, fileHeader.orders);
+	ReadOrderFromFile<uint8>(Order(), file, fileHeader.orders);
 	if(fileHeader.orders == 0 && madeWith[verFT2Generic])
 	{
 		// Fix lamb_-_dark_lighthouse.xm, which only contains one pattern and an empty order list
-		Order.resize(1);
-		Order[0] = 0;
+		Order().assign(1, 0);
 	}
 	file.Seek(fileHeader.size + 60);
 
@@ -391,7 +425,6 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 		file.SkipBack(4);
 		XMInstrumentHeader instrHeader;
 		file.ReadStructPartial(instrHeader, headerSize);
-		instrHeader.ConvertEndianness();
 
 		// Time for some version detection stuff.
 		if(madeWith == verOldModPlug)
@@ -401,12 +434,12 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 			{
 				// ModPlug Tracker Alpha
 				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 00, 00, A5);
-				m_madeWithTracker = "ModPlug Tracker 1.0 alpha";
+				m_madeWithTracker = MPT_USTRING("ModPlug Tracker 1.0 alpha");
 			} else if(instrHeader.size == 263)
 			{
 				// ModPlug Tracker Beta (Beta 1 still behaves like Alpha, but Beta 3.3 does it this way)
 				m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 00, 00, B3);
-				m_madeWithTracker = "ModPlug Tracker 1.0 beta";
+				m_madeWithTracker = MPT_USTRING("ModPlug Tracker 1.0 beta");
 			} else
 			{
 				// WTF?
@@ -424,6 +457,7 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 				// Sure isn't FT2.
 				// Note: FT2 NORMALLY writes shdr=40 for all samples, but sometimes it
 				// just happens to write random garbage there instead. Surprise!
+				// Note: 4-mat's eternity.xm has an instrument header size of 29.
 				madeWith = verUnknown;
 			}
 		}
@@ -481,7 +515,7 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 			for(SAMPLEINDEX sample = 0; sample < instrHeader.numSamples; sample++)
 			{
 				XMSample sampleHeader;
-				file.ReadConvertEndianness(sampleHeader);
+				file.ReadStruct(sampleHeader);
 
 				sampleFlags.push_back(sampleHeader.GetSampleFormat());
 				sampleSize[sample] = sampleHeader.length;
@@ -552,11 +586,12 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 	}
 	
 	// Read midi config: "MIDI"
+	bool hasMidiConfig = false;
 	if(file.ReadMagic("MIDI"))
 	{
-		file.ReadStructPartial(m_MidiCfg, file.ReadUint32LE());
+		file.ReadStructPartial<MIDIMacroConfigData>(m_MidiCfg, file.ReadUint32LE());
 		m_MidiCfg.Sanitize();
-		m_SongFlags |= SONG_EMBEDMIDICFG;
+		hasMidiConfig = true;
 		madeWith.set(verConfirmed);
 	}
 
@@ -601,11 +636,11 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 		if(madeWith[verModPlug1_09])
 		{
 			m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 09, 00, 00);
-			m_madeWithTracker = "ModPlug Tracker 1.09";
+			m_madeWithTracker = MPT_USTRING("ModPlug Tracker 1.09");
 		} else if(madeWith[verNewModPlug])
 		{
 			m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00);
-			m_madeWithTracker = "ModPlug Tracker 1.10 - 1.16";
+			m_madeWithTracker = MPT_USTRING("ModPlug Tracker 1.10 - 1.16");
 		}
 	}
 
@@ -632,12 +667,11 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		m_nMixLevels = mixLevelsCompatibleFT2;
 
-		if(!m_SongFlags[SONG_EMBEDMIDICFG])
+		if(!hasMidiConfig)
 		{
 			// FT2 allows typing in arbitrary unsupported effect letters such as Zxx.
 			// Prevent these commands from being interpreted as filter commands by erasing the default MIDI Config.
-			MemsetZero(m_MidiCfg.szMidiSFXExt);
-			MemsetZero(m_MidiCfg.szMidiZXXExt);
+			m_MidiCfg.ClearZxxMacros();
 		}
 
 		if(fileHeader.version >= 0x0104	// Old versions of FT2 didn't have (smooth) ramping. Disable it for those versions where we can be sure that there should be no ramping.
@@ -655,13 +689,13 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		if(madeWith[verDigiTrakker] && sampleReserved == 0 && (instrType ? instrType : -1) == -1)
 		{
-			m_madeWithTracker = "DigiTrakker";
+			m_madeWithTracker = MPT_USTRING("DigiTrakker");
 		} else if(madeWith[verFT2Generic])
 		{
-			m_madeWithTracker = "FastTracker 2 or compatible";
+			m_madeWithTracker = MPT_USTRING("FastTracker 2 or compatible");
 		} else
 		{
-			m_madeWithTracker = "Unknown";
+			m_madeWithTracker = MPT_USTRING("Unknown");
 		}
 	}
 
@@ -685,16 +719,16 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 
 	if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 17, 00, 00))
 	{
-		m_madeWithTracker = "OpenMPT " + MptVersion::ToStr(m_dwLastSavedWithVersion);
+		m_madeWithTracker = MPT_USTRING("OpenMPT ") + MptVersion::ToUString(m_dwLastSavedWithVersion);
 	}
 
 	// We no longer allow any --- or +++ items in the order list now.
 	if(m_dwLastSavedWithVersion && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 02, 02))
 	{
 		if(!Patterns.IsValidPat(0xFE))
-			Order.RemovePattern(0xFE);
+			Order().RemovePattern(0xFE);
 		if(!Patterns.IsValidPat(0xFF))
-			Order.Replace(0xFF, Order.GetInvalidPatIndex());
+			Order().Replace(0xFF, Order.GetInvalidPatIndex());
 	}
 
 	return true;
@@ -708,10 +742,13 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
 
 
 bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExport)
-//--------------------------------------------------------------------------------
 {
-	FILE *f;
-	if(filename.empty() || (f = mpt_fopen(filename, "wb")) == nullptr)
+	if(filename.empty())
+	{
+		return false;
+	}
+	FILE *f = mpt_fopen(filename, "wb");
+	if(!f)
 	{
 		return false;
 	}
@@ -730,7 +767,7 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 	// Writing song header
 	fileHeader.version = 0x0104;					// XM Format v1.04
 	fileHeader.size = sizeof(XMFileHeader) - 60;	// minus everything before this field
-	fileHeader.restartPos = Order.GetRestartPos();
+	fileHeader.restartPos = Order().GetRestartPos();
 
 	fileHeader.channels = m_nChannels;
 	if((m_nChannels % 2u) && m_nChannels < 32)
@@ -745,28 +782,35 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 
 	// Find out number of orders and patterns used.
 	// +++ and --- patterns are not taken into consideration as FastTracker does not support them.
-	ORDERINDEX maxOrders = 0;
+	
+	const ORDERINDEX trimmedLength = Order().GetLengthTailTrimmed();
+	std::vector<uint8> orderList(trimmedLength);
+	const ORDERINDEX orderLimit = compatibilityExport ? 256 : uint16_max;
+	ORDERINDEX numOrders = 0;
 	PATTERNINDEX numPatterns = Patterns.GetNumPatterns();
 	bool changeOrderList = false;
-	for(ORDERINDEX ord = 0; ord < Order.GetLengthTailTrimmed(); ord++)
+	for(ORDERINDEX ord = 0; ord < trimmedLength; ord++)
 	{
-		if(Order[ord] == Order.GetIgnoreIndex() || Order[ord] == Order.GetInvalidPatIndex())
+		PATTERNINDEX pat = Order()[ord];
+		if(pat == Order.GetIgnoreIndex() || pat == Order.GetInvalidPatIndex() || pat > uint8_max)
 		{
 			changeOrderList = true;
-		} else
+		} else if(numOrders < orderLimit)
 		{
-			maxOrders++;
-			if(Order[ord] >= numPatterns) numPatterns = Order[ord] + 1;
+			orderList[numOrders++] = static_cast<uint8>(pat);
+			if(pat >= numPatterns)
+				numPatterns = pat + 1;
 		}
 	}
 	if(changeOrderList)
 	{
 		AddToLog("Skip and stop order list items (+++ and ---) are not saved in XM files.");
 	}
+	orderList.resize(compatibilityExport ? 256 : numOrders);
 
-	fileHeader.orders = maxOrders;
+	fileHeader.orders = numOrders;
 	fileHeader.patterns = numPatterns;
-	fileHeader.size = fileHeader.size + (compatibilityExport ? 256 : maxOrders);
+	fileHeader.size += static_cast<uint32>(orderList.size());
 
 	uint16 writeInstruments;
 	if(m_nInstruments > 0)
@@ -779,36 +823,13 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 	fileHeader.flags = fileHeader.flags;
 
 	// Fasttracker 2 will happily accept any tempo faster than 255 BPM. XMPlay does also support this, great!
-	fileHeader.tempo = static_cast<uint16>(m_nDefaultTempo.GetInt());
+	fileHeader.tempo = mpt::saturate_cast<uint16>(m_nDefaultTempo.GetInt());
 	fileHeader.speed = static_cast<uint16>(Clamp(m_nDefaultSpeed, 1u, 31u));
 
-	fileHeader.ConvertEndianness();
-	fwrite(&fileHeader, 1, sizeof(fileHeader), f);
+	mpt::IO::Write(f, fileHeader);
 
-	// write order list (without +++ and ---, explained above)
-	ORDERINDEX writtenOrders = 0;
-	for(ORDERINDEX ord = 0; ord < Order.GetLengthTailTrimmed(); ord++)
-	{
-		if(compatibilityExport && (writtenOrders >= 256))
-		{
-			break;
-		}
-		if(Order[ord] != Order.GetIgnoreIndex() && Order[ord] != Order.GetInvalidPatIndex())
-		{
-			uint8 ordItem = static_cast<uint8>(Order[ord]);
-			fwrite(&ordItem, 1, 1, f);
-			writtenOrders++;
-		}
-	}
-	if(compatibilityExport)
-	{
-		while(writtenOrders < 256)
-		{
-			uint8 ordItem = 0;
-			fwrite(&ordItem, 1, 1, f);
-			writtenOrders++;
-		}
-	}
+	// Write processed order list
+	mpt::IO::WriteRaw(f, orderList.data(), orderList.size());
 
 	// Writing patterns
 
@@ -819,27 +840,27 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 
 	for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
 	{
-		uint8 patHead[9];
-		MemsetZero(patHead);
+		uint8 patHead[9] = { 0 };
 		patHead[0] = 9;
 
 		if(!Patterns.IsValidPat(pat))
 		{
 			// There's nothing to write... chicken out.
 			patHead[5] = 64;
-			fwrite(patHead, 1, 9, f);
+			mpt::IO::Write(f, patHead);
 			continue;
 		}
 
-		patHead[5] = static_cast<uint8>(Patterns[pat].GetNumRows() & 0xFF);
-		patHead[6] = static_cast<uint8>(Patterns[pat].GetNumRows() >> 8);
+		const uint16 numRows = mpt::saturate_cast<uint16>(Patterns[pat].GetNumRows());
+		patHead[5] = static_cast<uint8>(numRows & 0xFF);
+		patHead[6] = static_cast<uint8>(numRows >> 8);
 
-		const ModCommand *p = Patterns[pat];
+		auto p = Patterns[pat].cbegin();
 		size_t len = 0;
 		// Empty patterns are always loaded as 64-row patterns in FT2, regardless of their real size...
 		bool emptyPattern = true;
 
-		for(size_t j = m_nChannels * Patterns[pat].GetNumRows(); j > 0; j--, p++)
+		for(size_t j = m_nChannels * numRows; j > 0; j--, p++)
 		{
 			// Don't write more than 32 channels
 			if(compatibilityExport && m_nChannels - ((j - 1) % m_nChannels) > 32) continue;
@@ -892,7 +913,7 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 
 			// Apparently, completely empty patterns are loaded as empty 64-row patterns in FT2, regardless of their original size.
 			// We have to avoid this, so we add a "break to row 0" command in the last row.
-			if(j == 1 && emptyPattern && Patterns[pat].GetNumRows() != 64)
+			if(j == 1 && emptyPattern && numRows != 64)
 			{
 				command = 0x0D;
 				param = 0;
@@ -930,7 +951,7 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 			ASSERT_CAN_WRITE(5);
 		}
 
-		if(emptyPattern && Patterns[pat].GetNumRows() == 64)
+		if(emptyPattern && numRows == 64)
 		{
 			// Be smart when saving empty patterns!
 			len = 0;
@@ -939,14 +960,14 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 		// Reaching the limits of file format?
 		if(len > uint16_max)
 		{
-			AddToLog(mpt::String::Print("%1 (%2 %3)", str_tooMuchPatternData, str_pattern, pat));
+			AddToLog(mpt::format("%1 (%2 %3)")(str_tooMuchPatternData, str_pattern, pat));
 			len = uint16_max;
 		}
 
 		patHead[7] = static_cast<uint8>(len & 0xFF);
 		patHead[8] = static_cast<uint8>(len >> 8);
-		fwrite(patHead, 1, 9, f);
-		if(len) fwrite(&s[0], len, 1, f);
+		mpt::IO::Write(f, patHead);
+		if(len) mpt::IO::WriteRaw(f, s.data(), len);
 	}
 
 #undef ASSERT_CAN_WRITE
@@ -988,9 +1009,8 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 				// e.g. sample 1 is assigned to instrument 1 and samples 2 to 10 aren't assigned to any instrument,
 				// we will assign those to sample 1. Any samples before the first referenced sample are going to be lost,
 				// but hey, I wrote this mostly for preserving instrument texts in existing modules, where we shouldn't encounter this situation...
-				for(std::vector<SAMPLEINDEX>::const_iterator sample = samples.begin(); sample != samples.end(); sample++)
+				for(auto smp : samples)
 				{
-					SAMPLEINDEX smp = *sample;
 					while(++smp <= GetNumSamples()
 						&& !sampleAssigned[smp]
 						&& insHeader.numSamples < (compatibilityExport ? 16 : 32))
@@ -1017,8 +1037,7 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 
 		insHeader.Finalise();
 		size_t insHeaderSize = insHeader.size;
-		insHeader.ConvertEndianness();
-		fwrite(&insHeader, 1, insHeaderSize, f);
+		mpt::IO::WritePartial(f, insHeader, insHeaderSize);
 
 		std::vector<SampleIO> sampleFlags(samples.size());
 
@@ -1037,8 +1056,7 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 
 			mpt::String::Write<mpt::String::spacePadded>(xmSample.name, m_szNames[samples[smp]]);
 
-			xmSample.ConvertEndianness();
-			fwrite(&xmSample, 1, sizeof(xmSample), f);
+			mpt::IO::Write(f, xmSample);
 		}
 
 		// Write Sample Data
@@ -1054,48 +1072,31 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 	if(!compatibilityExport)
 	{
 		// Writing song comments
-		char magic[4];
-		int32 size;
 		if(!m_songMessage.empty())
 		{
-			memcpy(magic, "text", 4);
-			fwrite(magic, 1, 4, f);
-
-			size = m_songMessage.length();
-			SwapBytesLE(size);
-			fwrite(&size, 1, 4, f);
-
-			fwrite(m_songMessage.c_str(), 1, m_songMessage.length(), f);
+			uint32 size = mpt::saturate_cast<uint32>(m_songMessage.length());
+			mpt::IO::WriteRaw(f, "text", 4);
+			mpt::IO::WriteIntLE<uint32>(f, size);
+			mpt::IO::WriteRaw(f, m_songMessage.c_str(), size);
 		}
 		// Writing midi cfg
-		if(m_SongFlags[SONG_EMBEDMIDICFG])
+		if(!m_MidiCfg.IsMacroDefaultSetupUsed())
 		{
-			memcpy(magic, "MIDI", 4);
-			fwrite(magic, 1, 4, f);
-
-			size = sizeof(MIDIMacroConfigData);
-			SwapBytesLE(size);
-			fwrite(&size, 1, 4, f);
-
-			fwrite(static_cast<MIDIMacroConfigData*>(&m_MidiCfg), 1, sizeof(MIDIMacroConfigData), f);
+			mpt::IO::WriteRaw(f, "MIDI", 4);
+			mpt::IO::WriteIntLE<uint32>(f, sizeof(MIDIMacroConfigData));
+			mpt::IO::Write(f, static_cast<MIDIMacroConfigData &>(m_MidiCfg));
 		}
 		// Writing Pattern Names
 		const PATTERNINDEX numNamedPats = Patterns.GetNumNamedPatterns();
 		if(numNamedPats > 0)
 		{
-			memcpy(magic, "PNAM", 4);
-			fwrite(magic, 1, 4, f);
-
-			size = numNamedPats * MAX_PATTERNNAME;
-			SwapBytesLE(size);
-			fwrite(&size, 1, 4, f);
-
+			mpt::IO::WriteRaw(f, "PNAM", 4);
+			mpt::IO::WriteIntLE<uint32>(f, numNamedPats * MAX_PATTERNNAME);
 			for(PATTERNINDEX pat = 0; pat < numNamedPats; pat++)
 			{
 				char name[MAX_PATTERNNAME];
-				MemsetZero(name);
-				Patterns[pat].GetName(name);
-				fwrite(name, 1, MAX_PATTERNNAME, f);
+				mpt::String::Write<mpt::String::maybeNullTerminated>(name, Patterns[pat].GetName());
+				mpt::IO::Write(f, name);
 			}
 		}
 		// Writing Channel Names
@@ -1108,16 +1109,13 @@ bool CSoundFile::SaveXM(const mpt::PathString &filename, bool compatibilityExpor
 			// Do it!
 			if(numNamedChannels)
 			{
-				memcpy(magic, "CNAM", 4);
-				fwrite(magic, 1, 4, f);
-
-				size = numNamedChannels * MAX_CHANNELNAME;
-				SwapBytesLE(size);
-				fwrite(&size, 1, 4, f);
-
+				mpt::IO::WriteRaw(f, "CNAM", 4);
+				mpt::IO::WriteIntLE<uint32>(f, numNamedChannels * MAX_CHANNELNAME);
 				for(CHANNELINDEX chn = 0; chn < numNamedChannels; chn++)
 				{
-					fwrite(ChnSettings[chn].szName, 1, MAX_CHANNELNAME, f);
+					char name[MAX_CHANNELNAME];
+					mpt::String::Write<mpt::String::maybeNullTerminated>(name, ChnSettings[chn].szName);
+					mpt::IO::Write(f, name);
 				}
 			}
 		}
diff --git a/soundlib/Loaders.h b/soundlib/Loaders.h
index 2706363..8b68a5e 100644
--- a/soundlib/Loaders.h
+++ b/soundlib/Loaders.h
@@ -23,4 +23,50 @@ OPENMPT_NAMESPACE_BEGIN
 #define MAGIC4BE(a, b, c, d)	static_cast<uint32>((static_cast<uint8>(a) << 24) | (static_cast<uint8>(b) << 16) | (static_cast<uint8>(c) << 8) | static_cast<uint8>(d))
 #define MAGIC2BE(a, b)		static_cast<uint16>((static_cast<uint8>(a) << 8) | static_cast<uint8>(b))
 
+
+// Read 'howMany' order items from an array.
+// 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass ORDERINDEX_INVALID.
+template<typename T, size_t arraySize>
+bool ReadOrderFromArray(ModSequence &order, const T(&orders)[arraySize], size_t howMany = arraySize, uint16 stopIndex = ORDERINDEX_INVALID, uint16 ignoreIndex = ORDERINDEX_INVALID)
+{
+	STATIC_ASSERT(mpt::is_binary_safe<T>::value);
+	LimitMax(howMany, arraySize);
+	LimitMax(howMany, MAX_ORDERS);
+	ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany);
+
+	order.resize(readEntries);
+	for(int i = 0; i < readEntries; i++)
+	{
+		PATTERNINDEX pat = static_cast<PATTERNINDEX>(orders[i]);
+		if(pat == stopIndex) pat = order.GetInvalidPatIndex();
+		else if(pat == ignoreIndex) pat = order.GetIgnoreIndex();
+		order.at(i) = pat;
+	}
+	return true;
+}
+
+
+// Read 'howMany' order items as integers with defined endianness from a file.
+// 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass ORDERINDEX_INVALID.
+template<typename T>
+bool ReadOrderFromFile(ModSequence &order, FileReader &file, size_t howMany, uint16 stopIndex = ORDERINDEX_INVALID, uint16 ignoreIndex = ORDERINDEX_INVALID)
+{
+	STATIC_ASSERT(mpt::is_binary_safe<T>::value);
+	if(!file.CanRead(howMany * sizeof(T)))
+		return false;
+	LimitMax(howMany, MAX_ORDERS);
+	ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany);
+
+	order.resize(readEntries);
+	T patF;
+	for(auto &pat : order)
+	{
+		file.ReadStruct(patF);
+		pat = static_cast<PATTERNINDEX>(patF);
+		if(pat == stopIndex) pat = order.GetInvalidPatIndex();
+		else if(pat == ignoreIndex) pat = order.GetIgnoreIndex();
+	}
+	return true;
+}
+
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/MIDIEvents.cpp b/soundlib/MIDIEvents.cpp
index 9a4bb63..6ef8b81 100644
--- a/soundlib/MIDIEvents.cpp
+++ b/soundlib/MIDIEvents.cpp
@@ -18,7 +18,6 @@ namespace MIDIEvents
 
 // Build a generic MIDI event
 uint32 Event(EventType eventType, uint8 midiChannel, uint8 dataByte1, uint8 dataByte2)
-//------------------------------------------------------------------------------------
 {
 	return (eventType << 4) | (midiChannel & 0x0F) | (dataByte1 << 8) | (dataByte2 << 16);
 }
@@ -26,7 +25,6 @@ uint32 Event(EventType eventType, uint8 midiChannel, uint8 dataByte1, uint8 data
 
 // Build a MIDI CC event
 uint32 CC(MidiCC midiCC, uint8 midiChannel, uint8 param)
-//------------------------------------------------------
 {
 	return Event(evControllerChange, midiChannel, static_cast<uint8>(midiCC), param);
 }
@@ -34,7 +32,6 @@ uint32 CC(MidiCC midiCC, uint8 midiChannel, uint8 param)
 
 // Build a MIDI Pitchbend event
 uint32 PitchBend(uint8 midiChannel, uint16 bendAmount)
-//----------------------------------------------------
 {
 	return Event(evPitchBend, midiChannel, static_cast<uint8>(bendAmount & 0x7F), static_cast<uint8>(bendAmount >> 7));
 }
@@ -42,7 +39,6 @@ uint32 PitchBend(uint8 midiChannel, uint16 bendAmount)
 
 // Build a MIDI Program Change event
 uint32 ProgramChange(uint8 midiChannel, uint8 program)
-//----------------------------------------------------
 {
 	return Event(evProgramChange, midiChannel, program, 0);
 }
@@ -50,7 +46,6 @@ uint32 ProgramChange(uint8 midiChannel, uint8 program)
 
 // Build a MIDI Note Off event
 uint32 NoteOff(uint8 midiChannel, uint8 note, uint8 velocity)
-//-----------------------------------------------------------
 {
 	return Event(evNoteOff, midiChannel, note, velocity);
 }
@@ -58,7 +53,6 @@ uint32 NoteOff(uint8 midiChannel, uint8 note, uint8 velocity)
 
 // Build a MIDI Note On event
 uint32 NoteOn(uint8 midiChannel, uint8 note, uint8 velocity)
-//----------------------------------------------------------
 {
 	return Event(evNoteOn, midiChannel, note, velocity);
 }
@@ -66,7 +60,6 @@ uint32 NoteOn(uint8 midiChannel, uint8 note, uint8 velocity)
 
 // Build a MIDI System Event
 uint8 System(SystemEvent eventType)
-//---------------------------------
 {
 	return static_cast<uint8>((evSystem << 4) | eventType);
 }
@@ -74,7 +67,6 @@ uint8 System(SystemEvent eventType)
 
 // Get MIDI channel from a MIDI event
 uint8 GetChannelFromEvent(uint32 midiMsg)
-//---------------------------------------
 {
 	return static_cast<uint8>((midiMsg & 0xF));
 }
@@ -82,7 +74,6 @@ uint8 GetChannelFromEvent(uint32 midiMsg)
 
 // Get MIDI Event type from a MIDI event
 EventType GetTypeFromEvent(uint32 midiMsg)
-//----------------------------------------
 {
 	return static_cast<EventType>(((midiMsg >> 4) & 0xF));
 }
@@ -90,7 +81,6 @@ EventType GetTypeFromEvent(uint32 midiMsg)
 
 // Get first data byte from a MIDI event
 uint8 GetDataByte1FromEvent(uint32 midiMsg)
-//-----------------------------------------
 {
 	return static_cast<uint8>(((midiMsg >> 8) & 0xFF));
 }
@@ -98,7 +88,6 @@ uint8 GetDataByte1FromEvent(uint32 midiMsg)
 
 // Get second data byte from a MIDI event
 uint8 GetDataByte2FromEvent(uint32 midiMsg)
-//-----------------------------------------
 {
 	return static_cast<uint8>(((midiMsg >> 16) & 0xFF));
 }
@@ -106,7 +95,6 @@ uint8 GetDataByte2FromEvent(uint32 midiMsg)
 
 // Get the length of a MIDI event in bytes
 uint8 GetEventLength(uint8 firstByte)
-//-----------------------------------
 {
 	uint8 msgSize = 3;
 	switch(firstByte & 0xF0)
diff --git a/soundlib/MIDIMacros.cpp b/soundlib/MIDIMacros.cpp
index e215801..a022811 100644
--- a/soundlib/MIDIMacros.cpp
+++ b/soundlib/MIDIMacros.cpp
@@ -22,7 +22,6 @@
 OPENMPT_NAMESPACE_BEGIN
 
 parameteredMacroType MIDIMacroConfig::GetParameteredMacroType(uint32 macroIndex) const
-//------------------------------------------------------------------------------------
 {
 	const std::string macro = GetSafeMacro(szMidiSFXExt[macroIndex]);
 
@@ -47,7 +46,6 @@ parameteredMacroType MIDIMacroConfig::GetParameteredMacroType(uint32 macroIndex)
 
 // Retrieve Zxx (Z80-ZFF) type from current macro configuration
 fixedMacroType MIDIMacroConfig::GetFixedMacroType() const
-//-------------------------------------------------------
 {
 	// Compare with all possible preset patterns
 	for(uint32 i = 0; i < zxx_max; i++)
@@ -76,7 +74,6 @@ fixedMacroType MIDIMacroConfig::GetFixedMacroType() const
 
 
 void MIDIMacroConfig::CreateParameteredMacro(char (&parameteredMacro)[MACRO_LENGTH], parameteredMacroType macroType, int subType) const
-//-------------------------------------------------------------------------------------------------------------------------------------
 {
 	switch(macroType)
 	{
@@ -111,8 +108,6 @@ void MIDIMacroConfig::CreateParameteredMacro(char (&parameteredMacro)[MACRO_LENG
 		strcpy(parameteredMacro, "Ec00z");
 		break;
 	case sfx_custom:
-		MPT_ASSERT_NOTREACHED();
-		break;
 	default:
 		MPT_ASSERT_NOTREACHED();
 		break;
@@ -122,7 +117,6 @@ void MIDIMacroConfig::CreateParameteredMacro(char (&parameteredMacro)[MACRO_LENG
 
 // Create Zxx (Z80 - ZFF) from one out of five presets
 void MIDIMacroConfig::CreateFixedMacro(char (&fixedMacros)[128][MACRO_LENGTH], fixedMacroType macroType) const
-//------------------------------------------------------------------------------------------------------------
 {
 	for(uint32 i = 0; i < 128; i++)
 	{
@@ -176,8 +170,6 @@ void MIDIMacroConfig::CreateFixedMacro(char (&fixedMacros)[128][MACRO_LENGTH], f
 			break;
 
 		case zxx_custom:
-			MPT_ASSERT_NOTREACHED();
-			break;
 		default:
 			MPT_ASSERT_NOTREACHED();
 			break;
@@ -188,9 +180,29 @@ void MIDIMacroConfig::CreateFixedMacro(char (&fixedMacros)[128][MACRO_LENGTH], f
 
 #ifdef MODPLUG_TRACKER
 
+bool MIDIMacroConfig::operator== (const MIDIMacroConfig &other) const
+{
+	for(uint32 i = 0; i < CountOf(szMidiGlb); i++)
+	{
+		if(strncmp(szMidiGlb[i], other.szMidiGlb[i], MACRO_LENGTH))
+			return false;
+	}
+	for(uint32 i = 0; i < CountOf(szMidiSFXExt); i++)
+	{
+		if(strncmp(szMidiSFXExt[i], other.szMidiSFXExt[i], MACRO_LENGTH))
+			return false;
+	}
+	for(uint32 i = 0; i < CountOf(szMidiZXXExt); i++)
+	{
+		if(strncmp(szMidiZXXExt[i], other.szMidiZXXExt[i], MACRO_LENGTH))
+			return false;
+	}
+	return true;
+}
+
+
 // Returns macro description including plugin parameter / MIDI CC information
 CString MIDIMacroConfig::GetParameteredMacroName(uint32 macroIndex, IMixPlugin *plugin) const
-//-------------------------------------------------------------------------------------------
 {
 	const parameteredMacroType macroType = GetParameteredMacroType(macroIndex);
 
@@ -234,7 +246,6 @@ CString MIDIMacroConfig::GetParameteredMacroName(uint32 macroIndex, IMixPlugin *
 
 // Returns generic macro description.
 CString MIDIMacroConfig::GetParameteredMacroName(parameteredMacroType macroType) const
-//------------------------------------------------------------------------------------
 {
 	switch(macroType)
 	{
@@ -267,7 +278,6 @@ CString MIDIMacroConfig::GetParameteredMacroName(parameteredMacroType macroType)
 
 // Returns generic macro description.
 CString MIDIMacroConfig::GetFixedMacroName(fixedMacroType macroType) const
-//------------------------------------------------------------------------
 {
 	switch(macroType)
 	{
@@ -297,7 +307,6 @@ CString MIDIMacroConfig::GetFixedMacroName(fixedMacroType macroType) const
 
 
 int MIDIMacroConfig::MacroToPlugParam(uint32 macroIndex) const
-//------------------------------------------------------------
 {
 	const std::string macro = GetSafeMacro(szMidiSFXExt[macroIndex]);
 
@@ -317,7 +326,6 @@ int MIDIMacroConfig::MacroToPlugParam(uint32 macroIndex) const
 
 
 int MIDIMacroConfig::MacroToMidiCC(uint32 macroIndex) const
-//---------------------------------------------------------
 {
 	const std::string macro = GetSafeMacro(szMidiSFXExt[macroIndex]);
 
@@ -334,7 +342,6 @@ int MIDIMacroConfig::MacroToMidiCC(uint32 macroIndex) const
 
 
 int MIDIMacroConfig::FindMacroForParam(PlugParamIndex param) const
-//----------------------------------------------------------------
 {
 	for(int macroIndex = 0; macroIndex < NUM_MACROS; macroIndex++)
 	{
@@ -353,7 +360,6 @@ int MIDIMacroConfig::FindMacroForParam(PlugParamIndex param) const
 // Check if the MIDI Macro configuration used is the default one,
 // i.e. the configuration that is assumed when loading a file that has no macros embedded.
 bool MIDIMacroConfig::IsMacroDefaultSetupUsed() const
-//---------------------------------------------------
 {
 	const MIDIMacroConfig defaultConfig;
 
@@ -380,7 +386,6 @@ bool MIDIMacroConfig::IsMacroDefaultSetupUsed() const
 
 // Reset MIDI macro config to default values.
 void MIDIMacroConfig::Reset()
-//---------------------------
 {
 	MemsetZero(szMidiGlb);
 	MemsetZero(szMidiSFXExt);
@@ -398,9 +403,16 @@ void MIDIMacroConfig::Reset()
 }
 
 
+// Clear all Zxx macros so that they do nothing.
+void MIDIMacroConfig::ClearZxxMacros()
+{
+	MemsetZero(szMidiSFXExt);
+	MemsetZero(szMidiZXXExt);
+}
+
+
 // Sanitize all macro config strings.
 void MIDIMacroConfig::Sanitize()
-//------------------------------
 {
 	for(uint32 i = 0; i < CountOf(szMidiGlb); i++)
 	{
@@ -419,7 +431,6 @@ void MIDIMacroConfig::Sanitize()
 
 // Helper function for UpgradeMacros()
 void MIDIMacroConfig::UpgradeMacroString(char *macro) const
-//---------------------------------------------------------
 {
 	for(uint32 i = 0; i < MACRO_LENGTH; i++)
 	{
@@ -439,7 +450,6 @@ void MIDIMacroConfig::UpgradeMacroString(char *macro) const
 
 // Fix old-format (not conforming to IT's MIDI macro definitions) MIDI config strings.
 void MIDIMacroConfig::UpgradeMacros()
-//-----------------------------------
 {
 	for(uint32 i = 0; i < CountOf(szMidiSFXExt); i++)
 	{
@@ -454,7 +464,6 @@ void MIDIMacroConfig::UpgradeMacros()
 
 // Normalize by removing blanks and other unwanted characters from macro strings for internal usage.
 std::string MIDIMacroConfig::GetSafeMacro(const char *macro) const
-//----------------------------------------------------------------
 {
 	std::string sanitizedMacro = macro;
 
diff --git a/soundlib/MIDIMacros.h b/soundlib/MIDIMacros.h
index cafa6f5..005736b 100644
--- a/soundlib/MIDIMacros.h
+++ b/soundlib/MIDIMacros.h
@@ -74,23 +74,17 @@ enum
 };
 
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED MIDIMacroConfigData
+struct MIDIMacroConfigData
 {
-	char szMidiGlb[9][MACRO_LENGTH];		// Global MIDI macros
-	char szMidiSFXExt[16][MACRO_LENGTH];	// Parametric MIDI macros
-	char szMidiZXXExt[128][MACRO_LENGTH];	// Fixed MIDI macros
+	// encoding is ASCII
+	char szMidiGlb[9][MACRO_LENGTH];       // Global MIDI macros
+	char szMidiSFXExt[16][MACRO_LENGTH];   // Parametric MIDI macros
+	char szMidiZXXExt[128][MACRO_LENGTH];  // Fixed MIDI macros
 };
 
-STATIC_ASSERT(sizeof(MIDIMacroConfigData) == 4896); // this is directly written to files, so the size must be correct!
+MPT_BINARY_STRUCT(MIDIMacroConfigData, 4896) // this is directly written to files, so the size must be correct!
 
-//=======================================================
-class PACKED MIDIMacroConfig : public MIDIMacroConfigData
-//=======================================================
+class MIDIMacroConfig : public MIDIMacroConfigData
 {
 
 public:
@@ -126,6 +120,9 @@ public:
 
 #ifdef MODPLUG_TRACKER
 
+	bool operator== (const MIDIMacroConfig &other) const;
+	bool operator!= (const MIDIMacroConfig &other) const { return !(*this == other); }
+
 	// Translate macro type or macro string to macro name
 	CString GetParameteredMacroName(uint32 macroIndex, IMixPlugin *plugin = nullptr) const;
 	CString GetParameteredMacroName(parameteredMacroType macroType) const;
@@ -146,6 +143,9 @@ public:
 	// Reset MIDI macro config to default values.
 	void Reset();
 
+	// Clear all Zxx macros so that they do nothing.
+	void ClearZxxMacros();
+
 	// Sanitize all macro config strings.
 	void Sanitize();
 
@@ -164,8 +164,5 @@ protected:
 
 STATIC_ASSERT(sizeof(MIDIMacroConfig) == sizeof(MIDIMacroConfigData)); // this is directly written to files, so the size must be correct!
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/MPEGFrame.cpp b/soundlib/MPEGFrame.cpp
index 4f92f7a..925c296 100644
--- a/soundlib/MPEGFrame.cpp
+++ b/soundlib/MPEGFrame.cpp
@@ -59,7 +59,6 @@ static const uint8 sideInfoSize[2][2] =
 
 
 bool MPEGFrame::IsMPEGHeader(const uint8 (&header)[3])
-//----------------------------------------------------
 {
 	return header[0] == 0xFF && (header[1] & 0xE0) == 0xE0	// Sync
 		&& (header[1] & 0x18) != 0x08	// Invalid MPEG version
@@ -74,7 +73,6 @@ MPEGFrame::MPEGFrame(FileReader &file)
 	, numSamples(0)
 	, isValid(false)
 	, isLAME(false)
-//------------------------------------
 {
 	uint8 header[4];
 	file.ReadArray(header);
diff --git a/soundlib/MPEGFrame.h b/soundlib/MPEGFrame.h
index c8aa9a4..e4d41b4 100644
--- a/soundlib/MPEGFrame.h
+++ b/soundlib/MPEGFrame.h
@@ -10,9 +10,9 @@
 
 #pragma once
 
-OPENMPT_NAMESPACE_BEGIN
+#include "../common/FileReaderFwd.h"
 
-class FileReader;
+OPENMPT_NAMESPACE_BEGIN
 
 class MPEGFrame
 {
diff --git a/soundlib/Message.cpp b/soundlib/Message.cpp
index e53917d..7f64676 100644
--- a/soundlib/Message.cpp
+++ b/soundlib/Message.cpp
@@ -25,7 +25,6 @@ OPENMPT_NAMESPACE_BEGIN
 // [in]  lineEnding: line ending formatting of the text in memory.
 // [out] returns true on success.
 bool SongMessage::Read(const mpt::byte *data, size_t length, LineEnding lineEnding)
-//---------------------------------------------------------------------------------
 {
 	const char *str = mpt::byte_cast<const char *>(data);
 	while(length != 0 && str[length - 1] == '\0')
@@ -107,7 +106,6 @@ bool SongMessage::Read(const mpt::byte *data, size_t length, LineEnding lineEndi
 
 
 bool SongMessage::Read(FileReader &file, const size_t length, LineEnding lineEnding)
-//----------------------------------------------------------------------------------
 {
 	FileReader::off_t readLength = std::min(static_cast<FileReader::off_t>(length), file.BytesLeft());
 	FileReader::PinnedRawDataView fileView = file.ReadPinnedRawDataView(readLength);
@@ -123,43 +121,41 @@ bool SongMessage::Read(FileReader &file, const size_t length, LineEnding lineEnd
 // [in]  lineEndingLength: The padding space between two fixed lines. (there could for example be a null char after every line)
 // [out] returns true on success.
 bool SongMessage::ReadFixedLineLength(const mpt::byte *data, const size_t length, const size_t lineLength, const size_t lineEndingLength)
-//---------------------------------------------------------------------------------------------------------------------------------------
 {
-	const char *str = mpt::byte_cast<const char *>(data);
 	if(lineLength == 0)
 		return false;
-
-	const size_t totalLineLength = lineLength + lineEndingLength;
-	const size_t numLines = (length + totalLineLength - 1) / totalLineLength;
-	const size_t finalLength = numLines * (lineLength + 1);
 	clear();
-	reserve(finalLength);
+	reserve(length);
 
-	for(size_t line = 0, fpos = 0, cpos = 0; line < numLines; line++, fpos += totalLineLength, cpos += (lineLength + 1))
+	size_t readPos = 0, writePos = 0;
+	while(readPos < length)
 	{
-		append(str + fpos, std::min(lineLength, length - fpos));
+		size_t thisLineLength = std::min(lineLength, length - readPos);
+		append(mpt::byte_cast<const char *>(data) + readPos, thisLineLength);
 		append(1, InternalLineEnding);
 
-		// fix weird chars
-		for(size_t lpos = 0; lpos < lineLength; lpos++)
+		// Fix weird chars
+		for(size_t pos = writePos; pos < writePos + thisLineLength; pos++)
 		{
-			switch(at(cpos + lpos))
+			switch(at(pos))
 			{
 			case '\0':
 			case '\n':
 			case '\r':
-				at(cpos + lpos) = ' ';
+				at(pos) = ' ';
 				break;
 			}
 
 		}
+
+		readPos += thisLineLength + std::min(lineEndingLength, length - readPos - thisLineLength);
+		writePos += thisLineLength + 1;
 	}
 	return true;
 }
 
 
 bool SongMessage::ReadFixedLineLength(FileReader &file, const size_t length, const size_t lineLength, const size_t lineEndingLength)
-//----------------------------------------------------------------------------------------------------------------------------------
 {
 	FileReader::off_t readLength = std::min(static_cast<FileReader::off_t>(length), file.BytesLeft());
 	FileReader::PinnedRawDataView fileView = file.ReadPinnedRawDataView(readLength);
@@ -172,16 +168,12 @@ bool SongMessage::ReadFixedLineLength(FileReader &file, const size_t length, con
 // [in]  lineEnding: line ending formatting of the text in memory.
 // [out] returns formatted song message.
 std::string SongMessage::GetFormatted(const LineEnding lineEnding) const
-//----------------------------------------------------------------------
 {
 	std::string comments;
-
-	const size_t len = length();
-	comments.reserve(len);
-
-	for(size_t i = 0; i < len; i++)
+	comments.reserve(length());
+	for(auto c : *this)
 	{
-		if(at(i) == InternalLineEnding)
+		if(c == InternalLineEnding)
 		{
 			switch(lineEnding)
 			{
@@ -201,11 +193,38 @@ std::string SongMessage::GetFormatted(const LineEnding lineEnding) const
 			}
 		} else
 		{
-			comments.push_back(at(i));
+			comments.push_back(c);
 		}
 	}
 	return comments;
 }
 
 
+bool SongMessage::SetFormatted(std::string message, LineEnding lineEnding)
+{
+	MPT_ASSERT(lineEnding == leLF || lineEnding == leCR || lineEnding == leCRLF);
+	switch (lineEnding)
+	{
+	case leLF:
+		message = mpt::String::Replace(message, "\n", std::string(1, InternalLineEnding));
+		break;
+	case leCR:
+		message = mpt::String::Replace(message, "\r", std::string(1, InternalLineEnding));
+		break;
+	case leCRLF:
+		message = mpt::String::Replace(message, "\r\n", std::string(1, InternalLineEnding));
+		break;
+	default:
+		MPT_ASSERT_NOTREACHED();
+		break;
+	}
+	if(message == *this)
+	{
+		return false;
+	}
+	assign(message);
+	return true;
+}
+
+
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/Message.h b/soundlib/Message.h
index 6a779a5..5cd945b 100644
--- a/soundlib/Message.h
+++ b/soundlib/Message.h
@@ -12,13 +12,11 @@
 
 #include <string>
 
-OPENMPT_NAMESPACE_BEGIN
+#include "../common/FileReaderFwd.h"
 
-class FileReader;
+OPENMPT_NAMESPACE_BEGIN
 
-//====================================
 class SongMessage : public std::string
-//====================================
 {
 public:
 
@@ -58,6 +56,12 @@ public:
 	// [in]  lineEnding: line ending formatting of the text in memory.
 	// [out] returns formatted song message.
 	std::string GetFormatted(const LineEnding lineEnding) const;
+
+	// Set song message.
+	// [in]  lineEnding: line ending formatting of the text in memory. Must be leCR or leLF or leCRLF,
+	// [out] returns true if the message has been changed.
+	bool SetFormatted(std::string message, LineEnding lineEnding);
+
 };
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/MixFuncTable.cpp b/soundlib/MixFuncTable.cpp
index d46ba30..52388f4 100644
--- a/soundlib/MixFuncTable.cpp
+++ b/soundlib/MixFuncTable.cpp
@@ -57,13 +57,14 @@ namespace MixFuncTable
 	BuildMixFuncTableFilter(resampling, NoFilter), \
 	BuildMixFuncTableFilter(resampling, ResonantFilter)
 
-const MixFuncInterface Functions[5 * 16] =
+const MixFuncInterface Functions[6 * 16] =
 {
 	BuildMixFuncTable(NoInterpolation),			// No SRC
 	BuildMixFuncTable(LinearInterpolation),		// Linear SRC
 	BuildMixFuncTable(FastSincInterpolation),	// Fast Sinc (Cubic Spline) SRC
 	BuildMixFuncTable(PolyphaseInterpolation),	// Kaiser SRC
 	BuildMixFuncTable(FIRFilterInterpolation),	// FIR SRC
+	BuildMixFuncTable(AmigaBlepInterpolation),	// Amiga emulation
 };
 
 
@@ -73,7 +74,6 @@ const MixFuncInterface Functions[5 * 16] =
 
 
 ResamplingIndex ResamplingModeToMixFlags(ResamplingMode resamplingMode)
-//---------------------------------------------------------------------
 {
 	switch(resamplingMode)
 	{
@@ -82,6 +82,7 @@ ResamplingIndex ResamplingModeToMixFlags(ResamplingMode resamplingMode)
 	case SRCMODE_SPLINE:    return ndxFastSinc;
 	case SRCMODE_POLYPHASE: return ndxKaiser;
 	case SRCMODE_FIRFILTER: return ndxFIRFilter;
+	case SRCMODE_AMIGA:     return ndxAmigaBlep;
 	default:                MPT_ASSERT_NOTREACHED();
 	}
 	return ndxNoInterpolation;
diff --git a/soundlib/MixFuncTable.h b/soundlib/MixFuncTable.h
index 5baeebb..27fbb4a 100644
--- a/soundlib/MixFuncTable.h
+++ b/soundlib/MixFuncTable.h
@@ -39,9 +39,10 @@ namespace MixFuncTable
 		ndxFastSinc			= 0x20,
 		ndxKaiser			= 0x30,
 		ndxFIRFilter		= 0x40,
+		ndxAmigaBlep		= 0x50,
 	};
 
-	extern const MixFuncInterface Functions[5 * 16];
+	extern const MixFuncInterface Functions[6 * 16];
 
 	ResamplingIndex ResamplingModeToMixFlags(ResamplingMode resamplingMode);
 }
diff --git a/soundlib/Mixer.h b/soundlib/Mixer.h
index 40d5d84..a1813a7 100644
--- a/soundlib/Mixer.h
+++ b/soundlib/Mixer.h
@@ -16,7 +16,7 @@ OPENMPT_NAMESPACE_BEGIN
 
 #ifdef MPT_INTMIXER
 typedef int32 mixsample_t;
-enum { MIXING_FILTER_PRECISION = 13 };	// Fixed point resonant filter bits
+enum { MIXING_FILTER_PRECISION = 16 };	// Fixed point resonant filter bits
 #else
 typedef float mixsample_t;
 #endif
@@ -38,8 +38,9 @@ const float MIXING_SCALEF = static_cast<float>(1 << MIXING_FRACTIONAL_BITS);
 
 // The absolute maximum number of sampling points any interpolation algorithm is going to look at in any direction from the current sampling point
 // Currently, the maximum is 4 sampling points forwards and 3 sampling points backwards (Polyphase / FIR algorithms).
-// Note that choosing a higher value (e.g. 16) will drastically reduce CPU usage when using many extremely short (length < 16) samples.
-#define InterpolationMaxLookahead	4u
+// Hence, this value must be at least 4.
+// Note that choosing a higher value (e.g. 16) will reduce CPU usage when using many extremely short (length < 16) samples.
+#define InterpolationMaxLookahead	16u
 
 // Maximum size of a sampling point of a sample, in bytes.
 // The biggest sampling point size is currently 16-bit stereo = 2 * 2 bytes.
diff --git a/soundlib/MixerInterface.h b/soundlib/MixerInterface.h
index 68d5866..c70cbad 100644
--- a/soundlib/MixerInterface.h
+++ b/soundlib/MixerInterface.h
@@ -29,7 +29,7 @@ struct MixerTraits
 	typedef in input_t;								// Input buffer sample type
 	typedef out outbuf_t[channelsOut];				// Output buffer sampling point type
 	// To perform sample conversion, add a function with the following signature to your derived classes:
-	// static forceinline output_t Convert(const input_t x)
+	// static MPT_CONSTEXPR11_FUN output_t Convert(const input_t x)
 };
 
 
@@ -39,10 +39,10 @@ struct MixerTraits
 template<class Traits>
 struct NoInterpolation
 {
-	forceinline void Start(const ModChannel &, const CResampler &) { }
-	forceinline void End(const ModChannel &) { }
+	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
+	MPT_FORCEINLINE void End(const ModChannel &) { }
 
-	forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32)
+	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32)
 	{
 		static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels");
 
@@ -65,12 +65,10 @@ struct NoInterpolation
 // FilterFunc: Functor for applying the resonant filter
 // MixFunc: Functor for mixing the computed sample data into the output buffer
 template<class Traits, class InterpolationFunc, class FilterFunc, class MixFunc>
-static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Traits::output_t * MPT_RESTRICT outBuffer, int numSamples)
+static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Traits::output_t * MPT_RESTRICT outBuffer, unsigned int numSamples)
 {
 	ModChannel &c = chn;
-	const typename Traits::input_t * MPT_RESTRICT inSample = static_cast<const typename Traits::input_t *>(c.pCurrentSample) + c.nPos * Traits::numChannelsIn;
-
-	int32 smpPos = c.nPosLo;	// 16.16 sample position relative to c.nPos
+	const typename Traits::input_t * MPT_RESTRICT inSample = static_cast<const typename Traits::input_t *>(c.pCurrentSample);
 
 	InterpolationFunc interpolate;
 	FilterFunc filter;
@@ -81,27 +79,29 @@ static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Tr
 	filter.Start(c);
 	mix.Start(c);
 
-	int samples = numSamples;
+	unsigned int samples = numSamples;
+	SamplePosition smpPos = c.position;	// Fixed-point sample position
+	const SamplePosition increment = c.increment;	// Fixed-point sample increment
+
 	while(samples--)
 	{
 		typename Traits::outbuf_t outSample;
-		interpolate(outSample, inSample + (smpPos >> 16) * Traits::numChannelsIn, (smpPos & 0xFFFF));
+		interpolate(outSample, inSample + smpPos.GetInt() * Traits::numChannelsIn, smpPos.GetFract());
 		filter(outSample, c);
 		mix(outSample, c, outBuffer);
 		outBuffer += Traits::numChannelsOut;
 
-		smpPos += c.nInc;
+		smpPos += increment;
 	}
 
 	mix.End(c);
 	filter.End(c);
 	interpolate.End(c);
 
-	c.nPos += smpPos >> 16;
-	c.nPosLo = smpPos & 0xFFFF;
+	c.position = smpPos;
 }
 
 // Type of the SampleLoop function above
-typedef void (*MixFuncInterface)(ModChannel &, const CResampler &, mixsample_t *, int);
+typedef void (*MixFuncInterface)(ModChannel &, const CResampler &, mixsample_t *, unsigned int);
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/MixerLoops.cpp b/soundlib/MixerLoops.cpp
index 0ba1ebe..722496d 100644
--- a/soundlib/MixerLoops.cpp
+++ b/soundlib/MixerLoops.cpp
@@ -33,7 +33,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 // Convert integer mix to floating-point
 static void AMD_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc)
-//---------------------------------------------------------------------------------------------------------------
 {
 	_asm {
 	movd mm0, _i2fc
@@ -66,7 +65,6 @@ mainloop:
 }
 
 static void AMD_FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 nCount, const float _f2ic)
-//-------------------------------------------------------------------------------------------------------------------
 {
 	_asm {
 	movd mm0, _f2ic
@@ -101,7 +99,6 @@ mainloop:
 
 
 static void AMD_FloatToMonoMix(const float *pIn, int32 *pOut, uint32 nCount, const float _f2ic)
-//---------------------------------------------------------------------------------------------
 {
 	_asm {
 	movd mm0, _f2ic
@@ -131,7 +128,6 @@ mainloop:
 
 
 static void AMD_MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 nCount, const float _i2fc)
-//----------------------------------------------------------------------------------------------
 {
 	_asm {
 	movd mm0, _i2fc
@@ -169,7 +165,6 @@ mainloop:
 #include <emmintrin.h>
 
 static void SSE2_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc)
-//----------------------------------------------------------------------------------------------------------------
 {
 	__m128 i2fc = _mm_load_ps1(&_i2fc);
 	const __m128i *in = reinterpret_cast<const __m128i *>(pSrc);
@@ -196,7 +191,6 @@ static void SSE2_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2,
 
 
 static void SSE2_FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 nCount, const float _f2ic)
-//--------------------------------------------------------------------------------------------------------------------
 {
 	__m128 f2ic = _mm_load_ps1(&_f2ic);
 	__m128i *out = reinterpret_cast<__m128i *>(pOut);
@@ -227,7 +221,6 @@ static void SSE2_FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *p
 #ifdef ENABLE_SSE
 
 static void SSE_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc)
-//---------------------------------------------------------------------------------------------------------------
 {
 	_asm {
 	movss xmm0, _i2fc
@@ -258,7 +251,6 @@ mainloop:
 
 
 static void SSE_MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 nCount, const float _i2fc)
-//----------------------------------------------------------------------------------------------
 {
 	_asm {
 	movss xmm0, _i2fc
@@ -292,7 +284,6 @@ mainloop:
 // Convert floating-point mix to integer
 
 static void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 nCount, const float _f2ic)
-//-------------------------------------------------------------------------------------------------------------------
 {
 	_asm {
 	mov esi, pIn1
@@ -320,7 +311,6 @@ mainloop:
 // Convert integer mix to floating-point
 
 static void X86_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc)
-//---------------------------------------------------------------------------------------------------------------
 {
 	_asm {
 	mov esi, pSrc
@@ -346,7 +336,6 @@ mainloop:
 
 
 static void X86_FloatToMonoMix(const float *pIn, int32 *pOut, uint32 nCount, const float _f2ic)
-//---------------------------------------------------------------------------------------------
 {
 	_asm {
 	mov edx, pIn
@@ -368,7 +357,6 @@ R2I_Loop:
 
 
 static void X86_MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 nCount, const float _i2fc)
-//----------------------------------------------------------------------------------------------
 {
 	_asm {
 	mov edx, pOut
@@ -393,7 +381,6 @@ I2R_Loop:
 
 
 static void C_FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 nCount, const float _f2ic)
-//-----------------------------------------------------------------------------------------------------------------
 {
 	for(uint32 i=0; i<nCount; ++i)
 	{
@@ -404,7 +391,6 @@ static void C_FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut
 
 
 static void C_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc)
-//-------------------------------------------------------------------------------------------------------------
 {
 	for(uint32 i=0; i<nCount; ++i)
 	{
@@ -415,7 +401,6 @@ static void C_StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, ui
 
 
 static void C_FloatToMonoMix(const float *pIn, int32 *pOut, uint32 nCount, const float _f2ic)
-//-------------------------------------------------------------------------------------------
 {
 	for(uint32 i=0; i<nCount; ++i)
 	{
@@ -425,7 +410,6 @@ static void C_FloatToMonoMix(const float *pIn, int32 *pOut, uint32 nCount, const
 
 
 static void C_MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 nCount, const float _i2fc)
-//--------------------------------------------------------------------------------------------
 {
 	for(uint32 i=0; i<nCount; ++i)
 	{
@@ -436,7 +420,6 @@ static void C_MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 nCount, cons
 
 
 void StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc)
-//----------------------------------------------------------------------------------------------------
 {
 
 	#ifdef ENABLE_SSE2
@@ -471,7 +454,6 @@ void StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCou
 
 
 void FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 nCount, const float _f2ic)
-//--------------------------------------------------------------------------------------------------------
 {
 	#ifdef ENABLE_SSE2
 	if(GetProcSupport() & PROCSUPPORT_SSE2)
@@ -498,7 +480,6 @@ void FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32
 
 
 void MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 nCount, const float _i2fc)
-//-----------------------------------------------------------------------------------
 {
 
 	#ifdef ENABLE_SSE
@@ -550,7 +531,6 @@ void FloatToMonoMix(const float *pIn, int *pOut, uint32 nCount, const float _f2i
 
 
 void InitMixBuffer(mixsample_t *pBuffer, uint32 nSamples)
-//-------------------------------------------------------
 {
 	memset(pBuffer, 0, nSamples * sizeof(mixsample_t));
 }
@@ -561,7 +541,6 @@ void InitMixBuffer(mixsample_t *pBuffer, uint32 nSamples)
 
 #ifdef ENABLE_X86
 static void X86_InterleaveFrontRear(int32 *pFrontBuf, int32 *pRearBuf, uint32 nFrames)
-//------------------------------------------------------------------------------------
 {
 	_asm {
 	mov ecx, nFrames	// ecx = framecount
@@ -591,7 +570,6 @@ interleaveloop:
 #endif
 
 static void C_InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf, uint32 nFrames)
-//----------------------------------------------------------------------------------------------
 {
 	// copy backwards as we are writing back into FrontBuf
 	for(int i=nFrames-1; i>=0; i--)
@@ -604,7 +582,6 @@ static void C_InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf,
 }
 
 void InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf, uint32 nFrames)
-//-------------------------------------------------------------------------------------
 {
 	#if defined(ENABLE_X86) && defined(MPT_INTMIXER)
 		X86_InterleaveFrontRear(pFrontBuf, pRearBuf, nFrames);
@@ -616,7 +593,6 @@ void InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf, uint32 n
 
 #ifdef ENABLE_X86
 static void X86_MonoFromStereo(int32 *pMixBuf, uint32 nSamples)
-//-------------------------------------------------------------
 {
 	_asm {
 	mov ecx, nSamples
@@ -637,7 +613,6 @@ stloop:
 #endif
 
 static void C_MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples)
-//-----------------------------------------------------------------
 {
 	for(uint32 i=0; i<nSamples; ++i)
 	{
@@ -646,7 +621,6 @@ static void C_MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples)
 }
 
 void MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples)
-//--------------------------------------------------------
 {
 	#if defined(ENABLE_X86) && defined(MPT_INTMIXER)
 		X86_MonoFromStereo(pMixBuf, nSamples);
@@ -663,7 +637,6 @@ void MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples)
 
 #ifdef ENABLE_X86
 static void X86_StereoFill(int32 *pBuffer, uint32 nSamples, int32 *lpROfs, int32 *lpLOfs)
-//---------------------------------------------------------------------------------------
 {
 	_asm {
 	mov edi, pBuffer
@@ -737,7 +710,6 @@ done:
 
 // c implementation taken from libmodplug
 static void C_StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rofs, mixsample_t &lofs)
-//---------------------------------------------------------------------------------------------------
 {
 	if ((!rofs) && (!lofs))
 	{
@@ -768,7 +740,6 @@ static void C_StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rof
 
 
 void StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rofs, mixsample_t &lofs)
-//------------------------------------------------------------------------------------------
 {
 	#if defined(ENABLE_X86) && defined(MPT_INTMIXER)
 		X86_StereoFill(pBuffer, nSamples, &rofs, &lofs);
@@ -781,7 +752,6 @@ void StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rofs, mixsam
 #ifdef ENABLE_X86
 typedef ModChannel ModChannel_;
 static void X86_EndChannelOfs(ModChannel *pChannel, int32 *pBuffer, uint32 nSamples)
-//----------------------------------------------------------------------------------
 {
 	_asm {
 	mov esi, pChannel
@@ -824,7 +794,6 @@ brkloop:
 
 // c implementation taken from libmodplug
 static void C_EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples)
-//---------------------------------------------------------------------------------
 {
 
 	mixsample_t rofs = chn.nROfs;
@@ -846,8 +815,8 @@ static void C_EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSampl
 		pBuffer[i*2+1] += x_l;
 	}
 #ifndef MPT_INTMIXER
-	if(fabs(rofs) < OFSTHRESHOLD) rofs = 0;
-	if(fabs(lofs) < OFSTHRESHOLD) lofs = 0;
+	if(mpt::abs(rofs) < OFSTHRESHOLD) rofs = 0;
+	if(mpt::abs(lofs) < OFSTHRESHOLD) lofs = 0;
 #endif
 
 	chn.nROfs = rofs;
@@ -855,7 +824,6 @@ static void C_EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSampl
 }
 
 void EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples)
-//------------------------------------------------------------------------
 {
 	#if defined(ENABLE_X86) && defined(MPT_INTMIXER)
 		X86_EndChannelOfs(&chn, pBuffer, nSamples);
@@ -866,7 +834,6 @@ void EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples)
 
 
 void InterleaveStereo(const mixsample_t * MPT_RESTRICT inputL, const mixsample_t * MPT_RESTRICT inputR, mixsample_t * MPT_RESTRICT output, size_t numSamples)
-//-----------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	while(numSamples--)
 	{
@@ -877,7 +844,6 @@ void InterleaveStereo(const mixsample_t * MPT_RESTRICT inputL, const mixsample_t
 
 
 void DeinterleaveStereo(const mixsample_t * MPT_RESTRICT input, mixsample_t * MPT_RESTRICT outputL, mixsample_t * MPT_RESTRICT outputR, size_t numSamples)
-//--------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	while(numSamples--)
 	{
@@ -890,7 +856,6 @@ void DeinterleaveStereo(const mixsample_t * MPT_RESTRICT input, mixsample_t * MP
 #ifndef MODPLUG_TRACKER
 
 void ApplyGain(int32 *soundBuffer, std::size_t channels, std::size_t countChunk, int32 gainFactor16_16)
-//-----------------------------------------------------------------------------------------------------
 {
 	if(gainFactor16_16 == (1<<16))
 	{
@@ -907,7 +872,6 @@ void ApplyGain(int32 *soundBuffer, std::size_t channels, std::size_t countChunk,
 }
 
 static void ApplyGain(float *beg, float *end, float factor)
-//---------------------------------------------------------
 {
 	for(float *it = beg; it != end; ++it)
 	{
@@ -916,7 +880,6 @@ static void ApplyGain(float *beg, float *end, float factor)
 }
 
 void ApplyGain(float * outputBuffer, float * const *outputBuffers, std::size_t offset, std::size_t channels, std::size_t countChunk, float gainFactor)
-//----------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	if(gainFactor == 1.0f)
 	{
diff --git a/soundlib/Mmcmp.cpp b/soundlib/Mmcmp.cpp
deleted file mode 100644
index 48b772c..0000000
--- a/soundlib/Mmcmp.cpp
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * mmcmp.cpp
- * ---------
- * Purpose: Handling of compressed modules (MMCMP, XPK, PowerPack PP20)
- * Notes  : (currently none)
- * Authors: Olivier Lapicque
- *          OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
-
-
-#include "stdafx.h"
-#include "Sndfile.h"
-#include "../common/FileReader.h"
-
-#include <stdexcept>
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-//#define MMCMP_LOG
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED MMCMPFILEHEADER
-{
-	char id[8];	// "ziRCONia"
-	uint16 hdrsize;
-	void ConvertEndianness();
-};
-
-STATIC_ASSERT(sizeof(MMCMPFILEHEADER) == 10);
-
-struct PACKED MMCMPHEADER
-{
-	uint16 version;
-	uint16 nblocks;
-	uint32 filesize;
-	uint32 blktable;
-	uint8 glb_comp;
-	uint8 fmt_comp;
-	void ConvertEndianness();
-};
-
-STATIC_ASSERT(sizeof(MMCMPHEADER) == 14);
-
-struct PACKED MMCMPBLOCK
-{
-	uint32 unpk_size;
-	uint32 pk_size;
-	uint32 xor_chk;
-	uint16 sub_blk;
-	uint16 flags;
-	uint16 tt_entries;
-	uint16 num_bits;
-	void ConvertEndianness();
-};
-
-STATIC_ASSERT(sizeof(MMCMPBLOCK) == 20);
-
-struct PACKED MMCMPSUBBLOCK
-{
-	uint32 unpk_pos;
-	uint32 unpk_size;
-	void ConvertEndianness();
-};
-
-STATIC_ASSERT(sizeof(MMCMPSUBBLOCK) == 8);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
-void MMCMPFILEHEADER::ConvertEndianness()
-//---------------------------------------
-{
-	SwapBytesLE(hdrsize);
-}
-
-void MMCMPHEADER::ConvertEndianness()
-//-----------------------------------
-{
-	SwapBytesLE(version);
-	SwapBytesLE(nblocks);
-	SwapBytesLE(filesize);
-	SwapBytesLE(blktable);
-	SwapBytesLE(glb_comp);
-	SwapBytesLE(fmt_comp);
-}
-
-void MMCMPBLOCK::ConvertEndianness()
-//----------------------------------
-{
-	SwapBytesLE(unpk_size);
-	SwapBytesLE(pk_size);
-	SwapBytesLE(xor_chk);
-	SwapBytesLE(sub_blk);
-	SwapBytesLE(flags);
-	SwapBytesLE(tt_entries);
-	SwapBytesLE(num_bits);
-}
-
-void MMCMPSUBBLOCK::ConvertEndianness()
-//-------------------------------------
-{
-	SwapBytesLE(unpk_pos);
-	SwapBytesLE(unpk_size);
-}
-
-
-#define MMCMP_COMP		0x0001
-#define MMCMP_DELTA		0x0002
-#define MMCMP_16BIT		0x0004
-#define MMCMP_STEREO	0x0100
-#define MMCMP_ABS16		0x0200
-#define MMCMP_ENDIAN	0x0400
-
-struct MMCMPBITBUFFER
-{
-	uint32 bitcount;
-	uint32 bitbuffer;
-	const uint8 *pSrc;
-	uint32 bytesLeft;
-
-	uint32 GetBits(uint32 nBits);
-};
-
-
-uint32 MMCMPBITBUFFER::GetBits(uint32 nBits)
-//------------------------------------------
-{
-	uint32 d;
-	if (!nBits) return 0;
-	while (bitcount < 24)
-	{
-		if(bytesLeft)
-		{
-			bitbuffer |= *pSrc << bitcount;
-			pSrc++;
-			bytesLeft--;
-		}
-		bitcount += 8;
-	}
-	d = bitbuffer & ((1 << nBits) - 1);
-	bitbuffer >>= nBits;
-	bitcount -= nBits;
-	return d;
-}
-
-static const uint32 MMCMP8BitCommands[8] =
-{
-	0x01, 0x03,	0x07, 0x0F,	0x1E, 0x3C,	0x78, 0xF8
-};
-
-static const uint32 MMCMP8BitFetch[8] =
-{
-	3, 3, 3, 3, 2, 1, 0, 0
-};
-
-static const uint32 MMCMP16BitCommands[16] =
-{
-	0x01, 0x03,	0x07, 0x0F,	0x1E, 0x3C,	0x78, 0xF0,
-	0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
-};
-
-static const uint32 MMCMP16BitFetch[16] =
-{
-	4, 4, 4, 4, 3, 2, 1, 0,
-	0, 0, 0, 0, 0, 0, 0, 0
-};
-
-
-static bool MMCMP_IsDstBlockValid(const std::vector<char> &unpackedData, uint32 pos, uint32 len)
-//----------------------------------------------------------------------------------------------
-{
-	if(pos >= unpackedData.size()) return false;
-	if(len > unpackedData.size()) return false;
-	if(len > unpackedData.size() - pos) return false;
-	return true;
-}
-
-
-static bool MMCMP_IsDstBlockValid(const std::vector<char> &unpackedData, const MMCMPSUBBLOCK &subblk)
-//---------------------------------------------------------------------------------------------------
-{
-	return MMCMP_IsDstBlockValid(unpackedData, subblk.unpk_pos, subblk.unpk_size);
-}
-
-
-bool UnpackMMCMP(std::vector<char> &unpackedData, FileReader &file)
-//-----------------------------------------------------------------
-{
-	file.Rewind();
-	unpackedData.clear();
-
-	MMCMPFILEHEADER mfh;
-	if(!file.ReadConvertEndianness(mfh)) return false;
-	if(std::memcmp(mfh.id, "ziRCONia", 8) != 0) return false;
-	if(mfh.hdrsize != sizeof(MMCMPHEADER)) return false;
-	MMCMPHEADER mmh;
-	if(!file.ReadConvertEndianness(mmh)) return false;
-	if(mmh.nblocks == 0) return false;
-	if(mmh.filesize == 0) return false;
-	if(mmh.filesize > 0x80000000) return false;
-	if(mmh.blktable > file.GetLength()) return false;
-	if(mmh.blktable + 4 * mmh.nblocks > file.GetLength()) return false;
-
-	unpackedData.resize(mmh.filesize);
-	// 8-bit deltas
-	uint8 ptable[256] = { 0 };
-
-	for (uint32 nBlock=0; nBlock<mmh.nblocks; nBlock++)
-	{
-		if(!file.Seek(mmh.blktable + 4*nBlock)) return false;
-		if(!file.CanRead(4)) return false;
-		uint32 blkPos = file.ReadUint32LE();
-		if(!file.Seek(blkPos)) return false;
-		MMCMPBLOCK blk;
-		if(!file.ReadConvertEndianness(blk)) return false;
-		std::vector<MMCMPSUBBLOCK> subblks(blk.sub_blk);
-		for(uint32 i=0; i<blk.sub_blk; ++i)
-		{
-			if(!file.ReadConvertEndianness(subblks[i])) return false;
-		}
-		MMCMPSUBBLOCK *psubblk = blk.sub_blk > 0 ? &(subblks[0]) : nullptr;
-
-		if(blkPos + sizeof(MMCMPBLOCK) + blk.sub_blk * sizeof(MMCMPSUBBLOCK) >= file.GetLength()) return false;
-		uint32 memPos = blkPos + sizeof(MMCMPBLOCK) + blk.sub_blk * sizeof(MMCMPSUBBLOCK);
-
-#ifdef MMCMP_LOG
-		Log("block %d: flags=%04X sub_blocks=%d", nBlock, (uint32)pblk->flags, (uint32)pblk->sub_blk);
-		Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size);
-		Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits);
-#endif
-		// Data is not packed
-		if (!(blk.flags & MMCMP_COMP))
-		{
-			for (uint32 i=0; i<blk.sub_blk; i++)
-			{
-				if(!psubblk) return false;
-				if(!MMCMP_IsDstBlockValid(unpackedData, *psubblk)) return false;
-#ifdef MMCMP_LOG
-				Log("  Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size);
-#endif
-				if(!file.Seek(memPos)) return false;
-				if(file.ReadRaw(&(unpackedData[psubblk->unpk_pos]), psubblk->unpk_size) != psubblk->unpk_size) return false;
-				psubblk++;
-			}
-		} else
-		// Data is 16-bit packed
-		if (blk.flags & MMCMP_16BIT)
-		{
-			MMCMPBITBUFFER bb;
-			uint32 subblk = 0;
-			if(!psubblk) return false;
-			if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
-			char *pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
-			uint32 dwSize = psubblk[subblk].unpk_size >> 1;
-			uint32 dwPos = 0;
-			uint32 numbits = blk.num_bits;
-			uint32 oldval = 0;
-
-#ifdef MMCMP_LOG
-			Log("  16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size);
-			if (pblk->flags & MMCMP_DELTA) Log("DELTA ");
-			if (pblk->flags & MMCMP_ABS16) Log("ABS16 ");
-			Log("\n");
-#endif
-			bb.bitcount = 0;
-			bb.bitbuffer = 0;
-			if(!file.Seek(memPos + blk.tt_entries)) return false;
-			if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false;
-			bb.pSrc = file.GetRawData<uint8>();
-			bb.bytesLeft = blk.pk_size - blk.tt_entries;
-			while (subblk < blk.sub_blk)
-			{
-				uint32 newval = 0x10000;
-				uint32 d = bb.GetBits(numbits+1);
-
-				uint32 command = MMCMP16BitCommands[numbits & 0x0F];
-				if (d >= command)
-				{
-					uint32 nFetch = MMCMP16BitFetch[numbits & 0x0F];
-					uint32 newbits = bb.GetBits(nFetch) + ((d - command) << nFetch);
-					if (newbits != numbits)
-					{
-						numbits = newbits & 0x0F;
-					} else
-					{
-						if ((d = bb.GetBits(4)) == 0x0F)
-						{
-							if (bb.GetBits(1)) break;
-							newval = 0xFFFF;
-						} else
-						{
-							newval = 0xFFF0 + d;
-						}
-					}
-				} else
-				{
-					newval = d;
-				}
-				if (newval < 0x10000)
-				{
-					newval = (newval & 1) ? (uint32)(-(int32)((newval+1) >> 1)) : (uint32)(newval >> 1);
-					if (blk.flags & MMCMP_DELTA)
-					{
-						newval += oldval;
-						oldval = newval;
-					} else
-					if (!(blk.flags & MMCMP_ABS16))
-					{
-						newval ^= 0x8000;
-					}
-					pDest[dwPos*2 + 0] = (uint8)(((uint16)newval) & 0xff);
-					pDest[dwPos*2 + 1] = (uint8)(((uint16)newval) >> 8);
-					dwPos++;
-				}
-				if (dwPos >= dwSize)
-				{
-					subblk++;
-					dwPos = 0;
-					if(!(subblk < blk.sub_blk)) break;
-					if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
-					dwSize = psubblk[subblk].unpk_size >> 1;
-					pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
-				}
-			}
-		} else
-		// Data is 8-bit packed
-		{
-			MMCMPBITBUFFER bb;
-			uint32 subblk = 0;
-			if(!psubblk) return false;
-			if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
-			char *pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
-			uint32 dwSize = psubblk[subblk].unpk_size;
-			uint32 dwPos = 0;
-			uint32 numbits = blk.num_bits;
-			uint32 oldval = 0;
-			if(blk.tt_entries > sizeof(ptable)
-				|| !file.Seek(memPos)
-				|| file.ReadRaw(ptable, blk.tt_entries) < blk.tt_entries)
-				return false;
-
-			bb.bitcount = 0;
-			bb.bitbuffer = 0;
-			if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false;
-			bb.pSrc = file.GetRawData<uint8>();
-			bb.bytesLeft = blk.pk_size - blk.tt_entries;
-			while (subblk < blk.sub_blk)
-			{
-				uint32 newval = 0x100;
-				uint32 d = bb.GetBits(numbits+1);
-
-				uint32 command = MMCMP8BitCommands[numbits & 0x07];
-				if (d >= command)
-				{
-					uint32 nFetch = MMCMP8BitFetch[numbits & 0x07];
-					uint32 newbits = bb.GetBits(nFetch) + ((d - command) << nFetch);
-					if (newbits != numbits)
-					{
-						numbits = newbits & 0x07;
-					} else
-					{
-						if ((d = bb.GetBits(3)) == 7)
-						{
-							if (bb.GetBits(1)) break;
-							newval = 0xFF;
-						} else
-						{
-							newval = 0xF8 + d;
-						}
-					}
-				} else
-				{
-					newval = d;
-				}
-				if (newval < sizeof(ptable))
-				{
-					int n = ptable[newval];
-					if (blk.flags & MMCMP_DELTA)
-					{
-						n += oldval;
-						oldval = n;
-					}
-					pDest[dwPos++] = (uint8)n;
-				}
-				if (dwPos >= dwSize)
-				{
-					subblk++;
-					dwPos = 0;
-					if(!(subblk < blk.sub_blk)) break;
-					if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false;
-					dwSize = psubblk[subblk].unpk_size;
-					pDest = &(unpackedData[psubblk[subblk].unpk_pos]);
-				}
-			}
-		}
-	}
-
-	return true;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// XPK unpacker
-//
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED XPKFILEHEADER
-{
-	char   XPKF[4];
-	uint32 SrcLen;
-	char   SQSH[4];
-	uint32 DstLen;
-	char   Name[16];
-	uint32 Reserved;
-	void ConvertEndianness();
-};
-
-STATIC_ASSERT(sizeof(XPKFILEHEADER) == 36);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
-
-void XPKFILEHEADER::ConvertEndianness()
-//-------------------------------------
-{
-	SwapBytesBE(SrcLen);
-	SwapBytesBE(DstLen);
-	SwapBytesBE(Reserved);
-}
-
-struct XPK_error : public std::range_error
-{
-	XPK_error() : std::range_error("invalid XPK data") { }
-};
-
-struct XPK_BufferBounds
-{
-	const uint8 *pSrcBeg;
-	std::size_t SrcSize;
-	uint8 *pDstBeg;
-	std::size_t DstSize;
-
-	inline uint8 SrcRead(std::size_t index)
-	{
-		if(index >= SrcSize) throw XPK_error();
-		return pSrcBeg[index];
-	}
-	inline void DstWrite(std::size_t index, uint8 value)
-	{
-		if(index >= DstSize) throw XPK_error();
-		pDstBeg[index] = value;
-	}
-	inline uint8 DstRead(std::size_t index)
-	{
-		if(index >= DstSize) throw XPK_error();
-		return pDstBeg[index];
-	}
-};
-
-static int32 bfextu(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
-//----------------------------------------------------------------------------
-{
-	int32 r;
-
-	p += bo / 8;
-	r = bufs.SrcRead(p); p++;
-	r <<= 8;
-	r |= bufs.SrcRead(p); p++;
-	r <<= 8;
-	r |= bufs.SrcRead(p);
-	r <<= bo % 8;
-	r &= 0xffffff;
-	r >>= 24 - bc;
-
-	return r;
-}
-
-static int32 bfexts(std::size_t p, int32 bo, int32 bc, XPK_BufferBounds &bufs)
-//----------------------------------------------------------------------------
-{
-	int32 r;
-
-	p += bo / 8;
-	r = bufs.SrcRead(p); p++;
-	r <<= 8;
-	r |= bufs.SrcRead(p); p++;
-	r <<= 8;
-	r |= bufs.SrcRead(p);
-	r <<= (bo % 8) + 8;
-	r >>= 32 - bc;
-
-	return r;
-}
-
-
-static uint8 XPK_ReadTable(int32 index)
-//-------------------------------------
-{
-	static const uint8 xpk_table[] = {
-		2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,2,6,7,8,0,5,4,6,2,3,7,8,0,6,5,7,2,3,4,8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0
-	};
-	if(index < 0) throw XPK_error();
-	if(static_cast<std::size_t>(index) >= static_cast<std::size_t>(CountOf(xpk_table))) throw XPK_error();
-	return xpk_table[index];
-}
-
-static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, uint8 *dst_, int32 len)
-//--------------------------------------------------------------------------------
-{
-	if(len <= 0) return false;
-	int32 d0,d1,d2,d3,d4,d5,d6,a2,a5;
-	int32 cp, cup1, type;
-	std::size_t c;
-	std::size_t src;
-	std::size_t dst;
-
-	std::size_t phist = 0;
-	std::size_t dstmax = len;
-
-	XPK_BufferBounds bufs;
-	bufs.pSrcBeg = src_;
-	bufs.SrcSize = srcLen;
-	bufs.pDstBeg = dst_;
-	bufs.DstSize = len;
-
-	src = 0;
-	dst = 0;
-	c = src;
-	while (len > 0)
-	{
-		type = bufs.SrcRead(c+0);
-		cp = (bufs.SrcRead(c+4)<<8) | (bufs.SrcRead(c+5)); // packed
-		cup1 = (bufs.SrcRead(c+6)<<8) | (bufs.SrcRead(c+7)); // unpacked
-		//Log("  packed=%6d unpacked=%6d bytes left=%d dst=%08X(%d)\n", cp, cup1, len, dst, dst);
-		c += 8;
-		src = c+2;
-		if (type == 0)
-		{
-			// RAW chunk
-			if(cp < 0) throw XPK_error();
-			for(int32 i = 0; i < cp; ++i)
-			{
-				bufs.DstWrite(dst + i, bufs.SrcRead(c + i));
-			}
-			dst+=cp;
-			c+=cp;
-			len -= cp;
-			continue;
-		}
-
-		if (type != 1)
-		{
-		#ifdef MMCMP_LOG
-			Log("Invalid XPK type! (%d bytes left)\n", len);
-		#endif
-			break;
-		}
-		len -= cup1;
-		cp = (cp + 3) & 0xfffc;
-		c += cp;
-
-		d0 = d1 = d2 = a2 = 0;
-		d3 = bufs.SrcRead(src); src++;
-		bufs.DstWrite(dst, (uint8)d3);
-		if (dst < dstmax) dst++;
-		cup1--;
-
-		while (cup1 > 0)
-		{
-			if (d1 >= 8) goto l6dc;
-			if (bfextu(src,d0,1,bufs)) goto l75a;
-			d0 += 1;
-			d5 = 0;
-			d6 = 8;
-			goto l734;
-
-		l6dc:
-			if (bfextu(src,d0,1,bufs)) goto l726;
-			d0 += 1;
-			if (! bfextu(src,d0,1,bufs)) goto l75a;
-			d0 += 1;
-			if (bfextu(src,d0,1,bufs)) goto l6f6;
-			d6 = 2;
-			goto l708;
-
-		l6f6:
-			d0 += 1;
-			if (!bfextu(src,d0,1,bufs)) goto l706;
-			d6 = bfextu(src,d0,3,bufs);
-			d0 += 3;
-			goto l70a;
-
-		l706:
-			d6 = 3;
-		l708:
-			d0 += 1;
-		l70a:
-			d6 = XPK_ReadTable((8*a2) + d6 -17);
-			if (d6 != 8) goto l730;
-		l718:
-			if (d2 >= 20)
-			{
-				d5 = 1;
-				goto l732;
-			}
-			d5 = 0;
-			goto l734;
-
-		l726:
-			d0 += 1;
-			d6 = 8;
-			if (d6 == a2) goto l718;
-			d6 = a2;
-		l730:
-			d5 = 4;
-		l732:
-			d2 += 8;
-		l734:
-			while ((d5 >= 0) && (cup1 > 0))
-			{
-				d4 = bfexts(src,d0,d6,bufs);
-				d0 += d6;
-				d3 -= d4;
-				bufs.DstWrite(dst, (uint8)d3);
-				if (dst < dstmax) dst++;
-				cup1--;
-				d5--;
-			}
-			if (d1 != 31) d1++;
-			a2 = d6;
-		l74c:
-			d6 = d2;
-			d6 >>= 3;
-			d2 -= d6;
-		}
-	}
-	return true;
-
-l75a:
-	d0 += 1;
-	if (bfextu(src,d0,1,bufs)) goto l766;
-	d4 = 2;
-	goto l79e;
-
-l766:
-	d0 += 1;
-	if (bfextu(src,d0,1,bufs)) goto l772;
-	d4 = 4;
-	goto l79e;
-
-l772:
-	d0 += 1;
-	if (bfextu(src,d0,1,bufs)) goto l77e;
-	d4 = 6;
-	goto l79e;
-
-l77e:
-	d0 += 1;
-	if (bfextu(src,d0,1,bufs)) goto l792;
-	d0 += 1;
-	d6 = bfextu(src,d0,3,bufs);
-	d0 += 3;
-	d6 += 8;
-	goto l7a8;
-
-l792:
-	d0 += 1;
-	d6 = bfextu(src,d0,5,bufs);
-	d0 += 5;
-	d4 = 16;
-	goto l7a6;
-
-l79e:
-	d0 += 1;
-	d6 = bfextu(src,d0,1,bufs);
-	d0 += 1;
-l7a6:
-	d6 += d4;
-l7a8:
-	if (bfextu(src,d0,1,bufs)) goto l7c4;
-	d0 += 1;
-	if (bfextu(src,d0,1,bufs)) goto l7bc;
-	d5 = 8;
-	a5 = 0;
-	goto l7ca;
-
-l7bc:
-	d5 = 14;
-	a5 = -0x1100;
-	goto l7ca;
-
-l7c4:
-	d5 = 12;
-	a5 = -0x100;
-l7ca:
-	d0 += 1;
-	d4 = bfextu(src,d0,d5,bufs);
-	d0 += d5;
-	d6 -= 3;
-	if (d6 >= 0)
-	{
-		if (d6 > 0) d1 -= 1;
-		d1 -= 1;
-		if (d1 < 0) d1 = 0;
-	}
-	d6 += 2;
-	phist = dst + a5 - d4 - 1;
-
-	while ((d6 >= 0) && (cup1 > 0))
-	{
-		d3 = bufs.DstRead(phist); phist++;
-		bufs.DstWrite(dst, (uint8)d3);
-		if (dst < dstmax) dst++;
-		cup1--;
-		d6--;
-	}
-	goto l74c;
-}
-
-
-bool UnpackXPK(std::vector<char> &unpackedData, FileReader &file)
-//---------------------------------------------------------------
-{
-	file.Rewind();
-	unpackedData.clear();
-
-	XPKFILEHEADER header;
-	if(!file.ReadConvertEndianness(header)) return false;
-	if(std::memcmp(header.XPKF, "XPKF", 4) != 0) return false;
-	if(std::memcmp(header.SQSH, "SQSH", 4) != 0) return false;
-	if(header.SrcLen == 0) return false;
-	if(header.DstLen == 0) return false;
-	STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
-	if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8)) return false;
-	if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8))) return false;
-
-#ifdef MMCMP_LOG
-	Log("XPK detected (SrcLen=%d DstLen=%d) filesize=%d\n", header.SrcLen, header.DstLen, file.GetLength());
-#endif
-	bool result = false;
-	try
-	{
-		unpackedData.resize(header.DstLen);
-		result = XPK_DoUnpack(file.GetRawData<uint8>(), header.SrcLen - (sizeof(XPKFILEHEADER) - 8), reinterpret_cast<uint8 *>(&(unpackedData[0])), header.DstLen);
-	} catch(MPTMemoryException)
-	{
-		return false;
-	} catch(const XPK_error &)
-	{
-		return false;
-	}
-
-	return result;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// PowerPack PP20 Unpacker
-//
-
-
-struct PPBITBUFFER
-{
-	uint32 bitcount;
-	uint32 bitbuffer;
-	const uint8 *pStart;
-	const uint8 *pSrc;
-
-	uint32 GetBits(uint32 n);
-};
-
-
-uint32 PPBITBUFFER::GetBits(uint32 n)
-//-----------------------------------
-{
-	uint32 result = 0;
-
-	for (uint32 i=0; i<n; i++)
-	{
-		if (!bitcount)
-		{
-			bitcount = 8;
-			if (pSrc != pStart) pSrc--;
-			bitbuffer = *pSrc;
-		}
-		result = (result<<1) | (bitbuffer&1);
-		bitbuffer >>= 1;
-		bitcount--;
-	}
-	return result;
-}
-
-
-static bool PP20_DoUnpack(const uint8 *pSrc, uint32 nSrcLen, uint8 *pDst, uint32 nDstLen)
-//---------------------------------------------------------------------------------------
-{
-	PPBITBUFFER BitBuffer;
-	uint32 nBytesLeft;
-
-	BitBuffer.pStart = pSrc;
-	BitBuffer.pSrc = pSrc + nSrcLen - 4;
-	BitBuffer.bitbuffer = 0;
-	BitBuffer.bitcount = 0;
-	BitBuffer.GetBits(pSrc[nSrcLen-1]);
-	nBytesLeft = nDstLen;
-	while (nBytesLeft > 0)
-	{
-		if (!BitBuffer.GetBits(1))
-		{
-			uint32 n = 1;
-			while (n < nBytesLeft)
-			{
-				uint32 code = BitBuffer.GetBits(2);
-				n += code;
-				if (code != 3) break;
-			}
-			LimitMax(n, nBytesLeft);
-			for (uint32 i=0; i<n; i++)
-			{
-				pDst[--nBytesLeft] = (uint8)BitBuffer.GetBits(8);
-			}
-			if (!nBytesLeft) break;
-		}
-		{
-			uint32 n = BitBuffer.GetBits(2)+1;
-			if(n < 1 || n-1 >= nSrcLen) return false;
-			uint32 nbits = pSrc[n-1];
-			uint32 nofs;
-			if (n==4)
-			{
-				nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 );
-				while (n < nBytesLeft)
-				{
-					uint32 code = BitBuffer.GetBits(3);
-					n += code;
-					if (code != 7) break;
-				}
-			} else
-			{
-				nofs = BitBuffer.GetBits(nbits);
-			}
-			LimitMax(n, nBytesLeft);
-			for (uint32 i=0; i<=n; i++)
-			{
-				pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0;
-				if (!--nBytesLeft) break;
-			}
-		}
-	}
-	return true;
-}
-
-
-bool UnpackPP20(std::vector<char> &unpackedData, FileReader &file)
-//----------------------------------------------------------------
-{
-	file.Rewind();
-	unpackedData.clear();
-
-	if(!file.ReadMagic("PP20")) return false;
-	if(!file.CanRead(8)) return false;
-	uint8 efficiency[4];
-	file.ReadArray(efficiency);
-	if(efficiency[0] < 9 || efficiency[0] > 15
-		|| efficiency[1] < 9 || efficiency[1] > 15
-		|| efficiency[2] < 9 || efficiency[2] > 15
-		|| efficiency[3] < 9 || efficiency[3] > 15)
-		return false;
-	FileReader::off_t length = file.GetLength();
-	if(!Util::TypeCanHoldValue<uint32>(length)) return false;
-	// Length word must be aligned
-	if((length % 2u) != 0)
-		return false;
-
-	file.Seek(length - 4);
-	uint32 dstLen = 0;
-	dstLen |= file.ReadUint8() << 16;
-	dstLen |= file.ReadUint8() << 8;
-	dstLen |= file.ReadUint8() << 0;
-	if(dstLen == 0) return false;
-	try
-	{
-		unpackedData.resize(dstLen);
-	} catch(MPTMemoryException)
-	{
-		return false;
-	}
-	file.Seek(4);
-	bool result = PP20_DoUnpack(file.GetRawData<uint8>(), static_cast<uint32>(length - 4), reinterpret_cast<uint8 *>(&(unpackedData[0])), dstLen);
-
-	return result;
-}
-
-
-OPENMPT_NAMESPACE_END
diff --git a/soundlib/ModChannel.cpp b/soundlib/ModChannel.cpp
index e4c9990..f2ccb84 100644
--- a/soundlib/ModChannel.cpp
+++ b/soundlib/ModChannel.cpp
@@ -15,7 +15,6 @@
 OPENMPT_NAMESPACE_BEGIN
 
 void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel)
-//-------------------------------------------------------------------------------------------------
 {
 	if(resetMask & resetSetPosBasic)
 	{
@@ -46,8 +45,7 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
 	if(resetMask & resetSetPosAdvanced)
 	{
 		nPeriod = 0;
-		nPos = 0;
-		nPosLo = 0;
+		position.Set(0);
 		nLength = 0;
 		nLoopStart = 0;
 		nLoopEnd = 0;
@@ -60,9 +58,10 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
 		rightVol = leftVol = 0;
 		newRightVol = newLeftVol = 0;
 		rightRamp = leftRamp = 0;
-		nVolume = 256;
+		nVolume = 0;	// Needs to be 0 for SMP_NODEFAULTVOLUME flag
 		nVibratoPos = nTremoloPos = nPanbrelloPos = 0;
 		nOldHiOffset = 0;
+		nLeftVU = nRightVU = 0;
 
 		//-->Custom tuning related
 		m_ReCalculateFreqOnFirstTick = false;
@@ -70,7 +69,6 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
 		m_PortamentoFineSteps = 0;
 		m_PortamentoTickSlide = 0;
 		m_Freq = 0;
-		m_VibratoDepth = 0;
 		//<--Custom tuning related.
 	}
 
@@ -96,15 +94,40 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI
 
 
 void ModChannel::Stop()
-//---------------------
 {
 	nPeriod = 0;
-	nInc = 0;
-	nPos = nPosLo = 0;
+	increment.Set(0);
+	position.Set(0);
 	nLeftVU = nRightVU = 0;
 	nVolume = 0;
 	pCurrentSample = nullptr;
-	nInc = 0;
+}
+
+
+void ModChannel::UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins)
+{
+	nInsVol = 64;
+	if(smp != nullptr)
+		nInsVol = smp->nGlobalVol;
+	if(ins != nullptr)
+		nInsVol = (nInsVol * ins->nGlobalVol) / 64;
+}
+
+
+ModCommand::NOTE ModChannel::GetPluginNote(bool realNoteMapping) const
+{
+	if(nArpeggioLastNote != NOTE_NONE)
+	{
+		// If an arpeggio is playing, this definitely the last playing note, which may be different from the arpeggio base note stored in nNote.
+		return nArpeggioLastNote;
+	}
+	ModCommand::NOTE plugNote = nNote;
+	// Caution: When in compatible mode, ModChannel::nNote stores the "real" note, not the mapped note!
+	if(realNoteMapping && pModInstrument != nullptr && plugNote >= NOTE_MIN && plugNote < (MPT_ARRAY_COUNT(pModInstrument->NoteMap) + NOTE_MIN))
+	{
+		plugNote = pModInstrument->NoteMap[plugNote - NOTE_MIN];
+	}
+	return plugNote;
 }
 
 
diff --git a/soundlib/ModChannel.h b/soundlib/ModChannel.h
index 3d016ba..e86f90f 100644
--- a/soundlib/ModChannel.h
+++ b/soundlib/ModChannel.h
@@ -13,6 +13,7 @@
 #include "ModSample.h"
 #include "ModInstrument.h"
 #include "modcommand.h"
+#include "Paula.h"
 
 OPENMPT_NAMESPACE_BEGIN
 
@@ -36,22 +37,18 @@ struct ModChannel
 	};
 
 	// Information used in the mixer (should be kept tight for better caching)
-	// Byte sizes are for 32-bit builds and 32-bit integer / float mixer
+	SamplePosition position;	// Current play position (fixed point)
+	SamplePosition increment;	// Sample speed relative to mixing frequency (fixed point)
 	const void *pCurrentSample;	// Currently playing sample (nullptr if no sample is playing)
-	uint32 nPos;			// Current play position
-	uint32 nPosLo;			// 16-bit fractional part of play position
-	int32 nInc;				// 16.16 fixed point sample speed relative to mixing frequency (0x10000 = one sample per output sample, 0x20000 = two samples per output sample, etc...)
 	int32 leftVol;			// 0...4096 (12 bits, since 16 bits + 12 bits = 28 bits = 0dB in integer mixer, see MIXING_ATTENUATION)
 	int32 rightVol;			// Ditto
 	int32 leftRamp;			// Ramping delta, 20.12 fixed point (see VOLUMERAMPPRECISION)
 	int32 rightRamp;		// Ditto
-	// Up to here: 32 bytes
 	int32 rampLeftVol;		// Current ramping volume, 20.12 fixed point (see VOLUMERAMPPRECISION)
 	int32 rampRightVol;		// Ditto
 	mixsample_t nFilter_Y[2][2];					// Filter memory - two history items per sample channel
 	mixsample_t nFilter_A0, nFilter_B0, nFilter_B1;	// Filter coeffs
 	mixsample_t nFilter_HP;
-	// Up to here: 72 bytes
 
 	SmpLength nLength;
 	SmpLength nLoopStart;
@@ -59,9 +56,9 @@ struct ModChannel
 	FlagSet<ChannelFlags> dwFlags;
 	mixsample_t nROfs, nLOfs;
 	uint32 nRampLength;
-	// Up to here: 100 bytes
 
 	const ModSample *pModSample;			// Currently assigned sample slot (may already be stopped)
+	Paula::State paulaState;
 
 	// Information not used in the mixer
 	const ModInstrument *pModInstrument;	// Currently assigned instrument slot
@@ -79,12 +76,11 @@ struct ModChannel
 	int32 nInsVol;		// Sample / Instrument volume (SV * IV in ITTECH.TXT)
 	int32 nFineTune, nTranspose;
 	int32 nPortamentoSlide, nAutoVibDepth;
-	uint32 nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos;
-	int32 nVolSwing, nPanSwing;
-	int32 nCutSwing, nResSwing;
-	int32 nRestorePanOnNewNote; //If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from panswing.
 	uint32 nEFxOffset; // offset memory for Invert Loop (EFx, .MOD only)
-	int32 nRetrigCount, nRetrigParam;
+	int16 nVolSwing, nPanSwing;
+	int16 nCutSwing, nResSwing;
+	int16 nRestorePanOnNewNote; //If > 0, nPan should be set to nRestorePanOnNewNote - 1 on new note. Used to recover from panswing.
+	int16 nRetrigCount, nRetrigParam;
 	ROWINDEX nPatternLoop;
 	CHANNELINDEX nMasterChn;
 	ModCommand rowCommand;
@@ -97,9 +93,10 @@ struct ModChannel
 	uint8 nArpeggioLastNote, nArpeggioBaseNote;	// For plugin arpeggio
 	uint8 nNewNote, nNewIns, nOldIns, nCommand, nArpeggio;
 	uint8 nOldVolumeSlide, nOldFineVolUpDown;
-	uint8 nOldPortaUpDown, nOldFinePortaUpDown, nOldExtraFinePortaUpDown;
+	uint8 nOldPortaUp, nOldPortaDown, nOldFinePortaUpDown, nOldExtraFinePortaUpDown;
 	uint8 nOldPanSlide, nOldChnVolSlide;
 	uint8 nOldGlobalVolSlide;
+	uint8 nAutoVibPos, nVibratoPos, nTremoloPos, nPanbrelloPos;
 	uint8 nVibratoType, nVibratoSpeed, nVibratoDepth;
 	uint8 nTremoloType, nTremoloSpeed, nTremoloDepth;
 	uint8 nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth;
@@ -128,7 +125,6 @@ struct ModChannel
 	int32 m_PortamentoFineSteps, m_PortamentoTickSlide;
 
 	uint32 m_Freq;
-	float m_VibratoDepth;
 	//<----
 
 	//NOTE_PCs memory.
@@ -155,7 +151,7 @@ struct ModChannel
 
 	EnvInfo &GetEnvelope(EnvelopeType envType)
 	{
-		return const_cast<EnvInfo &>(static_cast<const ModChannel &>(*this).GetEnvelope(envType));
+		return const_cast<EnvInfo &>(static_cast<const ModChannel *>(this)->GetEnvelope(envType));
 	}
 
 	void ResetEnvelopes()
@@ -177,8 +173,11 @@ struct ModChannel
 	void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel);
 	void Stop();
 
-	typedef uint32 volume_t;
-	volume_t GetVSTVolume() { return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume; }
+	bool IsSamplePlaying() const { return !increment.IsZero(); }
+
+	uint32 GetVSTVolume() { return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume; }
+
+	ModCommand::NOTE GetPluginNote(bool realNoteMapping) const;
 
 	// Check if the channel has a valid MIDI output. This function guarantees that pModInstrument != nullptr.
 	bool HasMIDIOutput() const { return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); }
@@ -186,11 +185,7 @@ struct ModChannel
 	// Check if currently processed loop is a sustain loop. pModSample is not checked for validity!
 	bool InSustainLoop() const { return (dwFlags & (CHN_LOOP | CHN_KEYOFF)) == CHN_LOOP && pModSample->uFlags[CHN_SUSTAINLOOP]; }
 
-	ModChannel()
-	{
-		memset(this, 0, sizeof(*this));
-	}
-
+	void UpdateInstrumentVolume(const ModSample *smp, const ModInstrument *ins);
 };
 
 
diff --git a/soundlib/ModInstrument.cpp b/soundlib/ModInstrument.cpp
index 8f28a9d..6b6099c 100644
--- a/soundlib/ModInstrument.cpp
+++ b/soundlib/ModInstrument.cpp
@@ -18,7 +18,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 // Convert envelope data between various formats.
 void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType)
-//----------------------------------------------------------------
 {
 	if(!(fromType & MOD_TYPE_XM) && (toType & MOD_TYPE_XM))
 	{
@@ -49,8 +48,8 @@ void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType)
 			if(at(nLoopEnd).tick - 1 > at(nLoopEnd - 1).tick)
 			{
 				// Insert an interpolated point just before the loop point.
-				uint16 tick = at(nLoopEnd).tick - 1;
-				uint8 interpolatedValue = static_cast<uint8>(GetValueFromPosition(tick, 64));
+				EnvelopeNode::tick_t tick = at(nLoopEnd).tick - 1u;
+				auto interpolatedValue = static_cast<EnvelopeNode::value_t>(GetValueFromPosition(tick, 64));
 				insert(begin() + nLoopEnd, EnvelopeNode(tick, interpolatedValue));
 			} else
 			{
@@ -65,7 +64,6 @@ void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType)
 // Get envelope value at a given tick. Assumes that the envelope data is in rage [0, rangeIn],
 // returns value in range [0, rangeOut].
 int32 InstrumentEnvelope::GetValueFromPosition(int position, int32 rangeOut, int32 rangeIn) const
-//-----------------------------------------------------------------------------------------------
 {
 	uint32 pt = size() - 1u;
 	const int32 ENV_PRECISION = 1 << 16;
@@ -113,7 +111,6 @@ int32 InstrumentEnvelope::GetValueFromPosition(int position, int32 rangeOut, int
 
 
 void InstrumentEnvelope::Sanitize(uint8 maxValue)
-//-----------------------------------------------
 {
 	if(!empty())
 	{
@@ -125,18 +122,16 @@ void InstrumentEnvelope::Sanitize(uint8 maxValue)
 			LimitMax(it->value, maxValue);
 		}
 	}
-	STATIC_ASSERT(MAX_ENVPOINTS <= 255);
-	LimitMax(nLoopEnd, static_cast<uint8>(size() - 1));
+	LimitMax(nLoopEnd, static_cast<decltype(nLoopEnd)>(size() - 1));
 	LimitMax(nLoopStart, nLoopEnd);
-	LimitMax(nSustainEnd, static_cast<uint8>(size() - 1));
+	LimitMax(nSustainEnd, static_cast<decltype(nSustainEnd)>(size() - 1));
 	LimitMax(nSustainStart, nSustainEnd);
 	if(nReleaseNode != ENV_RELEASE_NODE_UNSET)
-		LimitMax(nReleaseNode, static_cast<uint8>(size() - 1));
+		LimitMax(nReleaseNode, static_cast<decltype(nReleaseNode)>(size() - 1));
 }
 
 
 ModInstrument::ModInstrument(SAMPLEINDEX sample)
-//----------------------------------------------
 {
 	nFadeOut = 256;
 	dwFlags.reset();
@@ -183,7 +178,6 @@ ModInstrument::ModInstrument(SAMPLEINDEX sample)
 
 // Translate instrument properties between two given formats.
 void ModInstrument::Convert(MODTYPE fromType, MODTYPE toType)
-//-----------------------------------------------------------
 {
 	MPT_UNREFERENCED_PARAMETER(fromType);
 
@@ -262,7 +256,6 @@ void ModInstrument::Convert(MODTYPE fromType, MODTYPE toType)
 
 // Get a set of all samples referenced by this instrument
 std::set<SAMPLEINDEX> ModInstrument::GetSamples() const
-//-----------------------------------------------------
 {
 	std::set<SAMPLEINDEX> referencedSamples;
 
@@ -282,7 +275,6 @@ std::set<SAMPLEINDEX> ModInstrument::GetSamples() const
 // Write sample references into a bool vector. If a sample is referenced by this instrument, true is written.
 // The caller has to initialize the vector.
 void ModInstrument::GetSamples(std::vector<bool> &referencedSamples) const
-//------------------------------------------------------------------------
 {
 	for(size_t i = 0; i < CountOf(Keyboard); i++)
 	{
@@ -296,7 +288,6 @@ void ModInstrument::GetSamples(std::vector<bool> &referencedSamples) const
 
 
 void ModInstrument::Sanitize(MODTYPE modType)
-//-------------------------------------------
 {
 	LimitMax(nFadeOut, 65536u);
 	LimitMax(nGlobalVol, 64u);
diff --git a/soundlib/ModInstrument.h b/soundlib/ModInstrument.h
index e40ad53..be95a00 100644
--- a/soundlib/ModInstrument.h
+++ b/soundlib/ModInstrument.h
@@ -10,7 +10,7 @@
 
 #pragma once
 
-#include "tuning.h"
+#include "tuningbase.h"
 #include "Snd_defs.h"
 #include "../common/FlagSet.h"
 #include "../common/misc_util.h"
@@ -21,11 +21,16 @@ OPENMPT_NAMESPACE_BEGIN
 // Instrument Nodes
 struct EnvelopeNode
 {
-	uint16 tick;	// Envelope node position (x axis)
-	uint8 value;	// Envelope node value (y axis)
+	typedef uint16 tick_t;
+	typedef uint8 value_t;
+
+	tick_t tick;	// Envelope node position (x axis)
+	value_t value;	// Envelope node value (y axis)
 
 	EnvelopeNode() : tick(0), value(0) { }
-	EnvelopeNode(uint16 tick, uint8 value) : tick(tick), value(value) { }
+	EnvelopeNode(tick_t tick, value_t value) : tick(tick), value(value) { }
+
+	bool operator== (const EnvelopeNode &other) const { return tick == other.tick && value == other.value; }
 };
 
 // Instrument Envelopes
@@ -56,6 +61,9 @@ struct InstrumentEnvelope : public std::vector<EnvelopeNode>
 	void Sanitize(uint8 maxValue = ENVELOPE_MAX);
 
 	uint32 size() const { return static_cast<uint32>(std::vector<EnvelopeNode>::size()); }
+
+	using std::vector<EnvelopeNode>::push_back;
+	void push_back(EnvelopeNode::tick_t tick, EnvelopeNode::value_t value) { push_back(EnvelopeNode(tick, value)); }
 };
 
 // Instrument Struct
diff --git a/soundlib/ModSample.cpp b/soundlib/ModSample.cpp
index 48e0f1b..687f719 100644
--- a/soundlib/ModSample.cpp
+++ b/soundlib/ModSample.cpp
@@ -21,7 +21,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 // Translate sample properties between two given formats.
 void ModSample::Convert(MODTYPE fromType, MODTYPE toType)
-//-------------------------------------------------------
 {
 	// Convert between frequency and transpose values if necessary.
 	if((!(toType & (MOD_TYPE_MOD | MOD_TYPE_XM))) && (fromType & (MOD_TYPE_MOD | MOD_TYPE_XM)))
@@ -90,7 +89,7 @@ void ModSample::Convert(MODTYPE fromType, MODTYPE toType)
 		if(nVibRate != 0 && nVibDepth != 0)
 		{
 			if(nVibSweep != 0)
-				nVibSweep = mpt::saturate_cast<uint8>(Util::muldivr_unsigned(nVibDepth, 256, nVibSweep));
+				nVibSweep = mpt::saturate_cast<decltype(nVibSweep)>(Util::muldivr_unsigned(nVibDepth, 256, nVibSweep));
 			else
 				nVibSweep = 255;
 		}
@@ -114,7 +113,6 @@ void ModSample::Convert(MODTYPE fromType, MODTYPE toType)
 
 // Initialize sample slot with default values.
 void ModSample::Initialize(MODTYPE type)
-//--------------------------------------
 {
 	nLength = 0;
 	nLoopStart = nLoopEnd = 0;
@@ -134,6 +132,7 @@ void ModSample::Initialize(MODTYPE type)
 	nVibSweep = 0;
 	nVibDepth = 0;
 	nVibRate = 0;
+	rootNote = 0;
 	filename[0] = '\0';
 
 	// Default cues compatible with old-style volume column offset
@@ -146,10 +145,9 @@ void ModSample::Initialize(MODTYPE type)
 
 // Returns sample rate of the sample.
 uint32 ModSample::GetSampleRate(const MODTYPE type) const
-//-------------------------------------------------------
 {
 	uint32 rate;
-	if(type & (MOD_TYPE_MOD | MOD_TYPE_XM))
+	if(CSoundFile::UseFinetuneAndTranspose(type))
 		rate = TransposeToFrequency(RelativeTone, nFineTune);
 	else
 		rate = nC5Speed;
@@ -163,7 +161,6 @@ uint32 ModSample::GetSampleRate(const MODTYPE type) const
 // Allocate sample based on a ModSample's properties.
 // Returns number of bytes allocated, 0 on failure.
 size_t ModSample::AllocateSample()
-//--------------------------------
 {
 	FreeSample();
 
@@ -180,7 +177,6 @@ size_t ModSample::AllocateSample()
 // Allocate sample memory. On sucess, a pointer to the silenced sample buffer is returned. On failure, nullptr is returned.
 // numSamples must contain the sample length, bytesPerSample the size of a sampling point multiplied with the number of channels.
 void *ModSample::AllocateSample(SmpLength numSamples, size_t bytesPerSample)
-//--------------------------------------------------------------------------
 {
 	const size_t allocSize = GetRealSampleBufferSize(numSamples, bytesPerSample);
 
@@ -199,17 +195,16 @@ void *ModSample::AllocateSample(SmpLength numSamples, size_t bytesPerSample)
 
 // Compute sample buffer size in bytes, including any overhead introduced by pre-computed loops and such. Returns 0 if sample is too big.
 size_t ModSample::GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerSample)
-//------------------------------------------------------------------------------------
 {
 	// Number of required lookahead samples:
-	// * 1x InterpolationMaxLookahead samples before the actual sample start. NOTE: This is currently hardcoded to 16!
+	// * 1x InterpolationMaxLookahead samples before the actual sample start. This is set to MaxSamplingPointSize due to the way AllocateSample/FreeSample currently work.
 	// * 1x InterpolationMaxLookahead samples of silence after the sample end (if normal loop end == sample end, this can be optimized out).
 	// * 2x InterpolationMaxLookahead before the loop point (because we start at InterpolationMaxLookahead before the loop point and will look backwards from there as well)
 	// * 2x InterpolationMaxLookahead after the loop point (for wrap-around)
 	// * 4x InterpolationMaxLookahead for the sustain loop (same as the two points above)
 	
 	const SmpLength maxSize = Util::MaxValueOfType(numSamples);
-	const SmpLength lookaheadBufferSize = 16 + (1 + 4 + 4) * InterpolationMaxLookahead;
+	const SmpLength lookaheadBufferSize = (MaxSamplingPointSize + 1 + 4 + 4) * InterpolationMaxLookahead;
 
 	if(numSamples > MAX_SAMPLE_LENGTH || lookaheadBufferSize > maxSize - numSamples)
 	{
@@ -227,7 +222,6 @@ size_t ModSample::GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerS
 
 
 void ModSample::FreeSample()
-//--------------------------
 {
 	FreeSample(pSample);
 	pSample = nullptr;
@@ -235,7 +229,6 @@ void ModSample::FreeSample()
 
 
 void ModSample::FreeSample(void *samplePtr)
-//-----------------------------------------
 {
 	if(samplePtr)
 	{
@@ -246,7 +239,6 @@ void ModSample::FreeSample(void *samplePtr)
 
 // Set loop points and update loop wrap-around buffer
 void ModSample::SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile)
-//------------------------------------------------------------------------------------------------------
 {
 	nLoopStart = start;
 	nLoopEnd = end;
@@ -266,7 +258,6 @@ void ModSample::SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpo
 
 // Set sustain loop points and update loop wrap-around buffer
 void ModSample::SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile)
-//-------------------------------------------------------------------------------------------------------------
 {
 	nSustainStart = start;
 	nSustainEnd = end;
@@ -285,7 +276,6 @@ void ModSample::SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool
 
 
 void ModSample::PrecomputeLoops(CSoundFile &sndFile, bool updateChannels)
-//-----------------------------------------------------------------------
 {
 	ctrlSmp::PrecomputeLoops(*this, sndFile, updateChannels);
 }
@@ -293,7 +283,6 @@ void ModSample::PrecomputeLoops(CSoundFile &sndFile, bool updateChannels)
 
 // Remove loop points if they're invalid.
 void ModSample::SanitizeLoops()
-//-----------------------------
 {
 	LimitMax(nSustainEnd, nLength);
 	LimitMax(nLoopEnd, nLength);
@@ -314,14 +303,12 @@ void ModSample::SanitizeLoops()
 // Transpose <-> Frequency conversions
 
 uint32 ModSample::TransposeToFrequency(int transpose, int finetune)
-//-----------------------------------------------------------------
 {
 	return Util::Round<uint32>(std::pow(2.0, (transpose * 128.0 + finetune) * (1.0 / (12.0 * 128.0))) * 8363.0);
 }
 
 
 void ModSample::TransposeToFrequency()
-//------------------------------------
 {
 	nC5Speed = TransposeToFrequency(RelativeTone, nFineTune);
 }
@@ -329,14 +316,12 @@ void ModSample::TransposeToFrequency()
 
 // Return tranpose.finetune as 25.7 fixed point value.
 int ModSample::FrequencyToTranspose(uint32 freq)
-//----------------------------------------------
 {
 	return Util::Round<int>(std::log(freq * (1.0 / 8363.0)) * (12.0 * 128.0 * (1.0 / M_LN2)));
 }
 
 
 void ModSample::FrequencyToTranspose()
-//------------------------------------
 {
 	int f2t;
 	if(nC5Speed)
@@ -350,15 +335,21 @@ void ModSample::FrequencyToTranspose()
 		transpose++;
 		finetune -= 128;
 	}
-	Limit(transpose, -127, 127);
+	Limit(transpose, -127, 128);
 	RelativeTone = static_cast<int8>(transpose);
 	nFineTune = static_cast<int8>(finetune);
 }
 
 
+// Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up)
+void ModSample::Transpose(double amount)
+{
+	nC5Speed = Util::Round<uint32>(nC5Speed * std::pow(2.0, amount));
+}
+
+
 // Check if the sample's cue points are the default cue point set.
 bool ModSample::HasCustomCuePoints() const
-//----------------------------------------
 {
 	for(SmpLength i = 0; i < CountOf(cues); i++)
 	{
diff --git a/soundlib/ModSample.h b/soundlib/ModSample.h
index 3d778b8..6b24e55 100644
--- a/soundlib/ModSample.h
+++ b/soundlib/ModSample.h
@@ -17,7 +17,7 @@ class CSoundFile;
 // Sample Struct
 struct ModSample
 {
-	SmpLength nLength;						// In samples, not bytes
+	SmpLength nLength;						// In frames
 	SmpLength nLoopStart, nLoopEnd;			// Ditto
 	SmpLength nSustainStart, nSustainEnd;	// Ditto
 	union
@@ -28,7 +28,7 @@ struct ModSample
 	};
 	uint32 nC5Speed;						// Frequency of middle-C, in Hz (for IT/S3M/MPTM)
 	uint16 nPan;							// Default sample panning (if pan flag is set), 0...256
-	uint16 nVolume;							// Default volume, 0...256
+	uint16 nVolume;							// Default volume, 0...256 (ignored if uFlags[SMP_NODEFAULTVOLUME] is set)
 	uint16 nGlobalVol;						// Global volume (sample volume is multiplied by this), 0...64
 	SampleFlags uFlags;						// Sample flags (see ChannelFlags enum)
 	int8   RelativeTone;					// Relative note to middle c (for MOD/XM)
@@ -37,7 +37,9 @@ struct ModSample
 	uint8  nVibSweep;						// Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full strength)
 	uint8  nVibDepth;						// Auto vibrato depth
 	uint8  nVibRate;						// Auto vibrato rate (speed)
-	//char name[MAX_SAMPLENAME];			// Maybe it would be nicer to have sample names here, but that would require some refactoring. Also, the current structure size is 64 Bytes - would adding the sample name here slow down the mixer (cache misses)?
+	uint8  rootNote;						// For multisample import
+
+	//char name[MAX_SAMPLENAME];			// Maybe it would be nicer to have sample names here, but that would require some refactoring.
 	char filename [MAX_SAMPLEFILENAME];
 	SmpLength cues[9];
 
@@ -55,7 +57,7 @@ struct ModSample
 	// Return the number of channels in the sample.
 	uint8 GetNumChannels() const { return (uFlags & CHN_STEREO) ? 2 : 1; }
 
-	// Return the number of bytes per sampling point. (Channels * Elementary Sample Size)
+	// Return the number of bytes per frame (Channels * Elementary Sample Size)
 	uint8 GetBytesPerSample() const { return GetElementarySampleSize() * GetNumChannels(); }
 
 	// Return the size which pSample is at least.
@@ -98,6 +100,9 @@ struct ModSample
 	static int FrequencyToTranspose(uint32 freq);
 	void FrequencyToTranspose();
 
+	// Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up)
+	void Transpose(double amount);
+
 	// Check if the sample's cue points are the default cue point set.
 	bool HasCustomCuePoints() const;
 };
diff --git a/soundlib/ModSampleCopy.h b/soundlib/ModSampleCopy.h
new file mode 100644
index 0000000..2741f23
--- /dev/null
+++ b/soundlib/ModSampleCopy.h
@@ -0,0 +1,155 @@
+/*
+ * ModSampleCopy.h
+ * ---------------
+ * Purpose: Functions for copying ModSample data.
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+
+#include "../soundbase/SampleFormatCopy.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+struct ModSample;
+
+// Copy a mono sample data buffer.
+template <typename SampleConversion, typename Tbyte>
+size_t CopyMonoSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion())
+{
+	MPT_ASSERT(sample.GetNumChannels() == 1);
+	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
+
+	const size_t frameSize =  SampleConversion::input_inc;
+	const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength);
+	size_t numFrames = countFrames;
+	SampleConversion sampleConv(conv);
+	const mpt::byte * MPT_RESTRICT inBuf = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
+	typename SampleConversion::output_t * MPT_RESTRICT outBuf = static_cast<typename SampleConversion::output_t *>(sample.pSample);
+	while(numFrames--)
+	{
+		*outBuf = sampleConv(inBuf);
+		inBuf += SampleConversion::input_inc;
+		outBuf++;
+	}
+	return frameSize * countFrames;
+}
+
+
+// Copy a stereo interleaved sample data buffer.
+template <typename SampleConversion, typename Tbyte>
+size_t CopyStereoInterleavedSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion())
+{
+	MPT_ASSERT(sample.GetNumChannels() == 2);
+	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
+
+	const size_t frameSize = 2 * SampleConversion::input_inc;
+	const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength);
+	size_t numFrames = countFrames;
+	SampleConversion sampleConvLeft(conv);
+	SampleConversion sampleConvRight(conv);
+	const mpt::byte * MPT_RESTRICT inBuf = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
+	typename SampleConversion::output_t * MPT_RESTRICT outBuf = static_cast<typename SampleConversion::output_t *>(sample.pSample);
+	while(numFrames--)
+	{
+		*outBuf = sampleConvLeft(inBuf);
+		inBuf += SampleConversion::input_inc;
+		outBuf++;
+		*outBuf = sampleConvRight(inBuf);
+		inBuf += SampleConversion::input_inc;
+		outBuf++;
+	}
+	return frameSize * countFrames;
+}
+
+
+// Copy a stereo split sample data buffer.
+template <typename SampleConversion, typename Tbyte>
+size_t CopyStereoSplitSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion())
+{
+	MPT_ASSERT(sample.GetNumChannels() == 2);
+	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
+
+	const size_t sampleSize = SampleConversion::input_inc;
+	const size_t sourceSizeLeft = std::min<size_t>(sample.nLength * SampleConversion::input_inc, sourceSize);
+	const size_t sourceSizeRight = std::min<size_t>(sample.nLength * SampleConversion::input_inc, sourceSize - sourceSizeLeft);
+	const size_t countSamplesLeft = sourceSizeLeft / sampleSize;
+	const size_t countSamplesRight = sourceSizeRight / sampleSize;
+
+	size_t numSamplesLeft = countSamplesLeft;
+	SampleConversion sampleConvLeft(conv);
+	const mpt::byte * MPT_RESTRICT inBufLeft = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
+	typename SampleConversion::output_t * MPT_RESTRICT outBufLeft = static_cast<typename SampleConversion::output_t *>(sample.pSample);
+	while(numSamplesLeft--)
+	{
+		*outBufLeft = sampleConvLeft(inBufLeft);
+		inBufLeft += SampleConversion::input_inc;
+		outBufLeft += 2;
+	}
+
+	size_t numSamplesRight = countSamplesRight;
+	SampleConversion sampleConvRight(conv);
+	const mpt::byte * MPT_RESTRICT inBufRight = mpt::byte_cast<const mpt::byte*>(sourceBuffer) + sample.nLength * SampleConversion::input_inc;
+	typename SampleConversion::output_t * MPT_RESTRICT outBufRight = static_cast<typename SampleConversion::output_t *>(sample.pSample) + 1;
+	while(numSamplesRight--)
+	{
+		*outBufRight = sampleConvRight(inBufRight);
+		inBufRight += SampleConversion::input_inc;
+		outBufRight += 2;
+	}
+
+	return (countSamplesLeft + countSamplesRight) * sampleSize;
+}
+
+
+// Copy a sample data buffer and normalize it. Requires slightly advanced sample conversion functor.
+template <typename SampleConversion, typename Tbyte>
+size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, typename SampleConversion::peak_t *srcPeak = nullptr, SampleConversion conv = SampleConversion())
+{
+	const size_t inSize = sizeof(typename SampleConversion::input_t);
+
+	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
+
+	size_t numSamples = sample.nLength * sample.GetNumChannels();
+	LimitMax(numSamples, sourceSize / inSize);
+
+	const mpt::byte * inBuf = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
+	// Finding max value
+	SampleConversion sampleConv(conv);
+	for(size_t i = numSamples; i != 0; i--)
+	{
+		sampleConv.FindMax(inBuf);
+		inBuf += SampleConversion::input_inc;
+	}
+
+	// If buffer is silent (maximum is 0), don't bother normalizing the sample - just keep the already silent buffer.
+	if(!sampleConv.IsSilent())
+	{
+		inBuf = sourceBuffer;
+		// Copying buffer.
+		typename SampleConversion::output_t *outBuf = static_cast<typename SampleConversion::output_t *>(sample.pSample);
+
+		for(size_t i = numSamples; i != 0; i--)
+		{
+			*outBuf = sampleConv(inBuf);
+			outBuf++;
+			inBuf += SampleConversion::input_inc;
+		}
+	}
+
+	if(srcPeak)
+	{
+		*srcPeak = sampleConv.GetSrcPeak();
+	}
+
+	return numSamples * inSize;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/ModSequence.cpp b/soundlib/ModSequence.cpp
index 20fafd7..430d7f1 100644
--- a/soundlib/ModSequence.cpp
+++ b/soundlib/ModSequence.cpp
@@ -9,120 +9,77 @@
 
 
 #include "stdafx.h"
-#include "Sndfile.h"
 #include "ModSequence.h"
+#include "Sndfile.h"
 #include "mod_specifications.h"
 #ifdef MODPLUG_TRACKER
 #include "../mptrack/Reporting.h"
 #endif // MODPLUG_TRACKER
 #include "../common/version.h"
 #include "../common/serialization_utils.h"
-#include "../common/FileReader.h"
-#include <functional>
-
-#if defined(MODPLUG_TRACKER)
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-#endif // MODPLUG_TRACKER
 
 OPENMPT_NAMESPACE_BEGIN
 
 #define str_SequenceTruncationNote ("Module has sequence of length %1; it will be truncated to maximum supported length, %2.")
 
 
-const ORDERINDEX ModSequenceSet::s_nCacheSize = MAX_ORDERS;
-
-
-ModSequence::ModSequence(CSoundFile &rSf,
-						 PATTERNINDEX* pArray,
-						 ORDERINDEX nSize,
-						 ORDERINDEX nCapacity,
-						 ORDERINDEX restartPos,
-						 const bool bDeletableArray) :
-		m_sndFile(rSf),
-		m_pArray(pArray),
-		m_nSize(nSize),
-		m_nCapacity(nCapacity),
-		m_restartPos(restartPos),
-		m_bDeletableArray(bDeletableArray)
-//-------------------------------------------------------
-{}
-
-
-ModSequence::ModSequence(CSoundFile& rSf, ORDERINDEX nSize) :
-	m_sndFile(rSf),
-	m_restartPos(0),
-	m_bDeletableArray(true)
-//------------------------------------------------------------
+ModSequence::ModSequence(CSoundFile &sndFile)
+	: m_sndFile(sndFile)
+	, m_restartPos(0)
 {
-	m_nSize = nSize;
-	m_nCapacity = m_nSize;
-	m_pArray = new PATTERNINDEX[m_nCapacity];
-	std::fill(begin(), end(), GetInvalidPatIndex());
 }
 
 
-ModSequence::ModSequence(const ModSequence& seq) :
-	m_sndFile(seq.m_sndFile),
-	m_pArray(nullptr),
-	m_nSize(0),
-	m_nCapacity(0),
-	m_restartPos(seq.m_restartPos),
-	m_bDeletableArray(false)
-//------------------------------------------
+ModSequence& ModSequence::operator=(const ModSequence &other)
 {
-	*this = seq;
+	if(&other == this)
+		return *this;
+	std::vector<PATTERNINDEX>::assign(other.begin(), other.end());
+	m_name = other.m_name;
+	m_restartPos = other.m_restartPos;
+	return *this;
 }
 
 
-bool ModSequence::NeedsExtraDatafield() const
-//-------------------------------------------
+bool ModSequence::operator== (const ModSequence &other) const
 {
-	return (m_sndFile.GetType() == MOD_TYPE_MPT && m_sndFile.Patterns.Size() > 0xFD);
+	return static_cast<const std::vector<PATTERNINDEX> &>(*this) == other
+		&& m_name == other.m_name
+		&& m_restartPos == other.m_restartPos;
 }
 
-namespace
+
+bool ModSequence::NeedsExtraDatafield() const
 {
-	// Functor for detecting non-valid patterns from sequence.
-	struct IsNotValidPat
-	{
-		IsNotValidPat(const CSoundFile &sf) : sndFile(sf) { }
-		bool operator() (PATTERNINDEX i) { return !sndFile.Patterns.IsValidPat(i); }
-		const CSoundFile &sndFile;
-	};
+	return (m_sndFile.GetType() == MOD_TYPE_MPT && m_sndFile.Patterns.GetNumPatterns() > 0xFD);
 }
 
 
 void ModSequence::AdjustToNewModType(const MODTYPE oldtype)
-//---------------------------------------------------------
 {
-	const CModSpecifications specs = m_sndFile.GetModSpecifications();
+	auto &specs = m_sndFile.GetModSpecifications();
 
 	if(oldtype != MOD_TYPE_NONE)
 	{
 		// If not supported, remove "+++" separator order items.
-		if(specs.hasIgnoreIndex == false)
+		if(!specs.hasIgnoreIndex)
 		{
 			RemovePattern(GetIgnoreIndex());
 		}
 		// If not supported, remove "---" items between patterns.
-		if(specs.hasStopIndex == false)
+		if(!specs.hasStopIndex)
 		{
 			RemovePattern(GetInvalidPatIndex());
 		}
 	}
 
 	//Resize orderlist if needed.
-	if(specs.ordersMax < GetLength())
+	if(specs.ordersMax < size())
 	{
-		// Order list too long? -> remove unnecessary order items first.
+		// Order list too long? Remove "unnecessary" order items first.
 		if(oldtype != MOD_TYPE_NONE && specs.ordersMax < GetLengthTailTrimmed())
 		{
-			iterator iter = std::remove_if(begin(), end(), IsNotValidPat(m_sndFile));
-			std::fill(iter, end(), GetInvalidPatIndex());
+			erase(std::remove_if(begin(), end(), [&] (PATTERNINDEX pat) { return !m_sndFile.Patterns.IsValidPat(pat); }), end());
 			if(GetLengthTailTrimmed() > specs.ordersMax)
 			{
 				m_sndFile.AddToLog("WARNING: Order list has been trimmed!");
@@ -134,259 +91,161 @@ void ModSequence::AdjustToNewModType(const MODTYPE oldtype)
 
 
 ORDERINDEX ModSequence::GetLengthTailTrimmed() const
-//--------------------------------------------------
 {
-	ORDERINDEX nEnd = GetLength();
-	if(nEnd == 0) return 0;
-	nEnd--;
-	const PATTERNINDEX iInvalid = GetInvalidPatIndex();
-	while(nEnd > 0 && (*this)[nEnd] == iInvalid)
-		nEnd--;
-	return ((*this)[nEnd] == iInvalid) ? 0 : nEnd+1;
+	if(empty())
+		return 0;
+	auto last = std::find_if(rbegin(), rend(), [] (PATTERNINDEX pat) { return pat != GetInvalidPatIndex(); });
+	return static_cast<ORDERINDEX>(std::distance(begin(), last.base()));
 }
 
 
 ORDERINDEX ModSequence::GetLengthFirstEmpty() const
-//-------------------------------------------------
 {
-	return static_cast<ORDERINDEX>(std::find(begin(), end(), GetInvalidPatIndex()) - begin());
+	return static_cast<ORDERINDEX>(std::distance(begin(), std::find(begin(), end(), GetInvalidPatIndex())));
 }
 
 
 ORDERINDEX ModSequence::GetNextOrderIgnoringSkips(const ORDERINDEX start) const
-//-----------------------------------------------------------------------------
 {
-	const ORDERINDEX nLength = GetLength();
-	if(nLength == 0) return 0;
-	ORDERINDEX next = std::min(ORDERINDEX(nLength - 1), ORDERINDEX(start + 1));
-	while(next+1 < nLength && (*this)[next] == GetIgnoreIndex()) next++;
+	if(empty())
+		return 0;
+	auto length = GetLength();
+	ORDERINDEX next = std::min(ORDERINDEX(length - 1), ORDERINDEX(start + 1));
+	while(next + 1 < length && at(next) == GetIgnoreIndex()) next++;
 	return next;
 }
 
 
 ORDERINDEX ModSequence::GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const
-//---------------------------------------------------------------------------------
 {
-	const ORDERINDEX nLength = GetLength();
-	if(start == 0 || nLength == 0) return 0;
-	ORDERINDEX prev = std::min(ORDERINDEX(start - 1), ORDERINDEX(nLength - 1));
-	while(prev > 0 && (*this)[prev] == GetIgnoreIndex()) prev--;
+	const ORDERINDEX last = GetLastIndex();
+	if(start == 0 || last == 0) return 0;
+	ORDERINDEX prev = std::min(ORDERINDEX(start - 1), last);
+	while(prev > 0 && at(prev) == GetIgnoreIndex()) prev--;
 	return prev;
 }
 
 
-void ModSequence::Init()
-//----------------------
+void ModSequence::Remove(ORDERINDEX posBegin, ORDERINDEX posEnd)
 {
-	resize(MAX_ORDERS);
-	std::fill(begin(), end(), GetInvalidPatIndex());
-}
-
-
-void ModSequence::Remove(ORDERINDEX nPosBegin, ORDERINDEX nPosEnd)
-//----------------------------------------------------------------
-{
-	const ORDERINDEX nLengthTt = GetLengthTailTrimmed();
-	if (nPosEnd < nPosBegin || nPosEnd >= nLengthTt)
+	if(posEnd < posBegin || posEnd >= size())
 		return;
-	const ORDERINDEX nMoveCount = nLengthTt - (nPosEnd + 1);
-	// Move orders left.
-	if (nMoveCount > 0)
-		memmove(m_pArray + nPosBegin, m_pArray + nPosEnd + 1, sizeof(PATTERNINDEX) * nMoveCount);
-	// Clear tail orders.
-	std::fill(m_pArray + nPosBegin + nMoveCount, m_pArray + nLengthTt, GetInvalidPatIndex());
+	erase(begin() + posBegin, begin() + posEnd + 1);
 }
 
 
-// Functor for fixing jump commands to moved order items
-struct FixJumpCommands
-//====================
+// Remove all references to a given pattern index from the order list. Jump commands are updated accordingly.
+void ModSequence::RemovePattern(PATTERNINDEX pat)
 {
-	FixJumpCommands(const std::vector<ORDERINDEX> &offsets) : jumpOffset(offsets) {};
-
-	void operator()(ModCommand& m)
+	// First, calculate the offset that needs to be applied to jump commands
+	const ORDERINDEX orderLength = GetLengthTailTrimmed();
+	std::vector<ORDERINDEX> jumpOffset(orderLength, 0);
+	ORDERINDEX maxJump = 0;
+	for(ORDERINDEX i = 0; i < orderLength; i++)
 	{
-		if(m.command == CMD_POSITIONJUMP && m.param < jumpOffset.size())
+		jumpOffset[i] = i - maxJump;
+		if(at(i) == pat)
 		{
-			m.param = ModCommand::PARAM(int(m.param) - jumpOffset[m.param]);
+			maxJump++;
 		}
 	}
+	if(!maxJump)
+	{
+		return;
+	}
 
-	const std::vector<ORDERINDEX> jumpOffset;
-};
-
-
-// Remove all references to a given pattern index from the order list. Jump commands are updated accordingly.
-void ModSequence::RemovePattern(PATTERNINDEX which)
-//-------------------------------------------------
-{
-	const ORDERINDEX orderLength = GetLengthTailTrimmed();
-	ORDERINDEX currentLength = orderLength;
-
-	// Associate order item index with jump offset (i.e. how much it moved forwards)
-	std::vector<ORDERINDEX> jumpOffset(orderLength, 0);
-	ORDERINDEX maxJump = 0;
+	erase(std::remove_if(begin(), end(), [pat](PATTERNINDEX p) { return p == pat; }), end());
 
-	for(ORDERINDEX i = 0; i < currentLength; i++)
+	// Only apply to patterns actually found in this sequence
+	for(auto p : *this) if(m_sndFile.Patterns.IsValidPat(p))
 	{
-		if(At(i) == which)
+		for(auto &m : m_sndFile.Patterns[p])
 		{
-			maxJump++;
-			// Move order list forwards, update jump counters
-			for(ORDERINDEX j = i + 1; j < orderLength; j++)
+			if(m.command == CMD_POSITIONJUMP && m.param < jumpOffset.size())
 			{
-				At(j - 1) = At(j);
-				jumpOffset[j] = maxJump;
+				m.param = static_cast<ModCommand::PARAM>(jumpOffset[m.param]);
 			}
-			At(--currentLength) = GetInvalidPatIndex();
 		}
 	}
-
-	m_sndFile.Patterns.ForEachModCommand(FixJumpCommands(jumpOffset));
 	if(m_restartPos < jumpOffset.size())
 	{
-		m_restartPos -= jumpOffset[m_restartPos];
+		m_restartPos = jumpOffset[m_restartPos];
 	}
 }
 
 
-ORDERINDEX ModSequence::Insert(ORDERINDEX nPos, ORDERINDEX nCount, PATTERNINDEX nFill)
-//------------------------------------------------------------------------------------
-{
-	if (nPos >= m_sndFile.GetModSpecifications().ordersMax || nCount == 0)
-		return 0;
-	const ORDERINDEX nLengthTt = GetLengthTailTrimmed();
-	// Limit number of orders to be inserted.
-	LimitMax(nCount, ORDERINDEX(m_sndFile.GetModSpecifications().ordersMax - nPos));
-	// Calculate new length.
-	const ORDERINDEX nNewLength = std::min<ORDERINDEX>(nLengthTt + nCount, m_sndFile.GetModSpecifications().ordersMax);
-	// Resize if needed.
-	if (nNewLength > GetLength())
-		resize(nNewLength);
-	// Calculate how many orders would need to be moved(nNeededSpace) and how many can actually
-	// be moved(nFreeSpace).
-	const ORDERINDEX nNeededSpace = nLengthTt - nPos;
-	const ORDERINDEX nFreeSpace = GetLength() - (nPos + nCount);
-	// Move orders nCount steps right starting from nPos.
-	if (nPos < nLengthTt)
-		memmove(m_pArray + nPos + nCount, m_pArray + nPos, MIN(nFreeSpace, nNeededSpace) * sizeof(PATTERNINDEX));
-	// Set nFill to new orders.
-	std::fill(begin() + nPos, begin() + nPos + nCount, nFill);
-	return nCount;
-}
-
-
-void ModSequence::Append(PATTERNINDEX nPat)
-//-----------------------------------------
+void ModSequence::assign(ORDERINDEX newSize, PATTERNINDEX pat)
 {
-	resize(m_nSize + 1, nPat);
+	LimitMax(newSize, m_sndFile.GetModSpecifications().ordersMax);
+	std::vector<PATTERNINDEX>::assign(newSize, pat);
 }
 
 
-void ModSequence::resize(ORDERINDEX nNewSize, PATTERNINDEX nFill)
-//---------------------------------------------------------------
+ORDERINDEX ModSequence::insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill)
 {
-	if (nNewSize == m_nSize) return;
-	if (nNewSize <= m_nCapacity)
-	{
-		if (nNewSize > m_nSize)
-			std::fill(begin() + m_nSize, begin() + nNewSize, nFill);
-		m_nSize = nNewSize;
-	} else
-	{
-		const PATTERNINDEX* const pOld = m_pArray;
-		if(nNewSize < Util::MaxValueOfType(m_nCapacity) - 100)
-			m_nCapacity = nNewSize + 100;
-		else
-			m_nCapacity = Util::MaxValueOfType(m_nCapacity);
-		m_pArray = new PATTERNINDEX[m_nCapacity];
-		std::copy(pOld, pOld + m_nSize, m_pArray);
-		std::fill(m_pArray + m_nSize, m_pArray + nNewSize, nFill);
-		m_nSize = nNewSize;
-		if (m_bDeletableArray)
-			delete[] pOld;
-		m_bDeletableArray = true;
-	}
+	if (pos >= m_sndFile.GetModSpecifications().ordersMax || count == 0)
+		return 0;
+	// Limit number of orders to be inserted so that we don't exceed the format limit.
+	LimitMax(count, ORDERINDEX(m_sndFile.GetModSpecifications().ordersMax - pos));
+	reserve(pos + count);
+	// Inserting past the end of the container?
+	if(pos > size())
+		resize(pos);
+	std::vector<PATTERNINDEX>::insert(begin() + pos, count, fill);
+	// Did we overgrow? Remove patterns at end.
+	if(size() > m_sndFile.GetModSpecifications().ordersMax)
+		resize(m_sndFile.GetModSpecifications().ordersMax);
+	return count;
 }
 
 
-bool ModSequence::IsValidPat(ORDERINDEX ord)
-//------------------------------------------
+bool ModSequence::IsValidPat(ORDERINDEX ord) const
 {
 	if(ord < size())
-		return m_sndFile.Patterns.IsValidPat(At(ord));
+		return m_sndFile.Patterns.IsValidPat(at(ord));
 	return false;
 }
 
 
-void ModSequence::clear()
-//-----------------------
-{
-	m_nSize = 0;
-}
-
-
-ModSequence& ModSequence::operator=(const ModSequence& seq)
-//---------------------------------------------------------
+ORDERINDEX ModSequence::FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt, bool searchForward) const
 {
-	if (&seq == this)
-		return *this;
-	if(seq.GetLength() > 0)
+	const ORDERINDEX length = GetLength();
+	ORDERINDEX ord = startSearchAt;
+	for(ORDERINDEX p = 0; p < length; p++)
 	{
-		resize(seq.GetLength());
-		std::copy(seq.begin(), seq.end(), begin());
-	}
-	m_sName = seq.m_sName;
-	m_restartPos = seq.m_restartPos;
-	return *this;
-}
-
-
-ORDERINDEX ModSequence::FindOrder(PATTERNINDEX nPat, ORDERINDEX startFromOrder, bool searchForward) const
-//-------------------------------------------------------------------------------------------------------
-{
-	const ORDERINDEX maxOrder = GetLength();
-	ORDERINDEX foundAtOrder = ORDERINDEX_INVALID;
-	ORDERINDEX candidateOrder = 0;
-
-	for (ORDERINDEX p = 0; p < maxOrder; p++)
-	{
-		if (searchForward)
+		if(at(ord) == pat)
 		{
-			candidateOrder = (startFromOrder + p) % maxOrder;				// wrap around MAX_ORDERS
-		} else
-		{
-			candidateOrder = (startFromOrder - p + maxOrder) % maxOrder;	// wrap around 0 and MAX_ORDERS
+			return ord;
 		}
-		if ((*this)[candidateOrder] == nPat)
+		if(searchForward)
+		{
+			if(++ord >= length)
+				ord = 0;
+		} else
 		{
-			foundAtOrder = candidateOrder;
-			break;
+			if(ord-- == 0)
+				ord = length - 1;
 		}
 	}
-
-	return foundAtOrder;
+	return ORDERINDEX_INVALID;
 }
 
 
 PATTERNINDEX ModSequence::EnsureUnique(ORDERINDEX ord)
-//----------------------------------------------------
 {
-	PATTERNINDEX pat = At(ord);
-	SEQUENCEINDEX seqs = m_sndFile.Order.GetNumSequences();
-	for(SEQUENCEINDEX s = 0; s < seqs; s++)
+	PATTERNINDEX pat = at(ord);
+	for(const auto &sequence : m_sndFile.Order)
 	{
-		ModSequence &sequence = m_sndFile.Order.GetSequence(s);
 		ORDERINDEX ords = sequence.GetLength();
 		for(ORDERINDEX o = 0; o < ords; o++)
 		{
 			if(sequence[o] == pat && (o != ord || &sequence != this))
 			{
 				// Found duplicate usage.
-				ORDERINDEX newPat = m_sndFile.Patterns.Duplicate(pat);
+				PATTERNINDEX newPat = m_sndFile.Patterns.Duplicate(pat);
 				if(newPat != PATTERNINDEX_INVALID)
 				{
-					At(ord) = newPat;
+					at(ord) = newPat;
 					return newPat;
 				}
 			}
@@ -401,86 +260,38 @@ PATTERNINDEX ModSequence::EnsureUnique(ORDERINDEX ord)
 /////////////////////////////////////
 
 
-ModSequenceSet::ModSequenceSet(CSoundFile& sndFile)
-	: ModSequence(sndFile, m_Cache, s_nCacheSize, s_nCacheSize, 0, false),
-	  m_nCurrentSeq(0)
-//--------------------------------------------------------------
-{
-	std::fill(m_Cache, m_Cache + s_nCacheSize, GetInvalidPatIndex());
-	m_Sequences.push_back(ModSequence(sndFile, s_nCacheSize));
-}
-
-
-const ModSequence& ModSequenceSet::GetSequence(SEQUENCEINDEX nSeq) const
-//----------------------------------------------------------------------
+ModSequenceSet::ModSequenceSet(CSoundFile &sndFile)
+	: m_sndFile(sndFile)
 {
-	if(nSeq == GetCurrentSequenceIndex())
-		return *this;
-	else
-		return m_Sequences[nSeq];
-}
-
-
-ModSequence& ModSequenceSet::GetSequence(SEQUENCEINDEX nSeq)
-//----------------------------------------------------------
-{
-	if(nSeq == GetCurrentSequenceIndex())
-		return *this;
-	else
-		return m_Sequences[nSeq];
+	Initialize();
 }
 
 
-void ModSequenceSet::CopyCacheToStorage()
-//---------------------------------------
+void ModSequenceSet::Initialize()
 {
-	m_Sequences[m_nCurrentSeq] = *this;
-}
-
-
-void ModSequenceSet::CopyStorageToCache()
-//---------------------------------------
-{
-	const ModSequence& rSeq = m_Sequences[m_nCurrentSeq];
-	if(rSeq.GetLength() <= s_nCacheSize)
-	{
-		PATTERNINDEX* pOld = m_pArray;
-		m_pArray = m_Cache;
-		m_nSize = rSeq.GetLength();
-		m_nCapacity = s_nCacheSize;
-		m_sName = rSeq.m_sName;
-		m_restartPos = rSeq.m_restartPos;
-		std::copy(rSeq.m_pArray, rSeq.m_pArray+m_nSize, m_pArray);
-		if (m_bDeletableArray)
-			delete[] pOld;
-		m_bDeletableArray = false;
-	}
-	else
-		ModSequence::operator=(rSeq);
+	m_currentSeq = 0;
+	m_Sequences.assign(1, ModSequence(m_sndFile));
 }
 
 
 void ModSequenceSet::SetSequence(SEQUENCEINDEX n)
-//-----------------------------------------------
 {
-	if(n >= m_Sequences.size())
-		return;
-	CopyCacheToStorage();
-	m_nCurrentSeq = n;
-	CopyStorageToCache();
+	if(n < m_Sequences.size())
+		m_currentSeq = n;
 }
 
 
-SEQUENCEINDEX ModSequenceSet::AddSequence(bool bDuplicate)
-//--------------------------------------------------------
+SEQUENCEINDEX ModSequenceSet::AddSequence(bool duplicate)
 {
 	if(GetNumSequences() == MAX_SEQUENCES)
 		return SEQUENCEINDEX_INVALID;
-	m_Sequences.push_back(ModSequence(m_sndFile, s_nCacheSize));
-	if (bDuplicate)
+	if(duplicate)
+	{
+		m_Sequences.push_back(m_Sequences[m_currentSeq]);
+		m_Sequences.back().m_name.clear();	// Don't copy sequence name.
+	} else
 	{
-		m_Sequences.back() = *this;
-		m_Sequences.back().m_sName = ""; // Don't copy sequence name.
+		m_Sequences.push_back(ModSequence(m_sndFile));
 	}
 	SetSequence(GetNumSequences() - 1);
 	return GetNumSequences() - 1;
@@ -488,117 +299,89 @@ SEQUENCEINDEX ModSequenceSet::AddSequence(bool bDuplicate)
 
 
 void ModSequenceSet::RemoveSequence(SEQUENCEINDEX i)
-//--------------------------------------------------
 {
 	// Do nothing if index is invalid or if there's only one sequence left.
-	if(i >= m_Sequences.size() || m_Sequences.size() <= 1) 
+	if(i >= m_Sequences.size() || m_Sequences.size() <= 1)
 		return;
-	const bool bSequenceChanges = (i == m_nCurrentSeq);
 	m_Sequences.erase(m_Sequences.begin() + i);
-	if(i < m_nCurrentSeq || m_nCurrentSeq >= GetNumSequences())
-		m_nCurrentSeq--;
-	if(bSequenceChanges)
-		CopyStorageToCache();
+	if(i < m_currentSeq || m_currentSeq >= GetNumSequences())
+		m_currentSeq--;
 }
 
 
 #ifdef MODPLUG_TRACKER
 
-void ModSequenceSet::OnModTypeChanged(const MODTYPE oldtype)
-//----------------------------------------------------------
+void ModSequenceSet::OnModTypeChanged(MODTYPE oldType)
 {
-	const SEQUENCEINDEX nSeqs = GetNumSequences();
-	for(SEQUENCEINDEX n = 0; n < nSeqs; n++)
+	for(auto &seq : m_Sequences)
 	{
-		GetSequence(n).AdjustToNewModType(oldtype);
+		seq.AdjustToNewModType(oldType);
 	}
 	// Multisequences not suppported by other formats
-	if(oldtype != MOD_TYPE_NONE && m_sndFile.GetModSpecifications().sequencesMax <= 1)
+	if(oldType != MOD_TYPE_NONE && m_sndFile.GetModSpecifications().sequencesMax <= 1)
 		MergeSequences();
 
 	// Convert sequence with separator patterns into multiple sequences?
-	if(oldtype != MOD_TYPE_NONE && m_sndFile.GetModSpecifications().sequencesMax > 1 && GetNumSequences() == 1)
+	if(oldType != MOD_TYPE_NONE && m_sndFile.GetModSpecifications().sequencesMax > 1 && GetNumSequences() == 1)
 		ConvertSubsongsToMultipleSequences();
 }
 
 
 bool ModSequenceSet::ConvertSubsongsToMultipleSequences()
-//-------------------------------------------------------
 {
 	// Allow conversion only if there's only one sequence.
 	if(GetNumSequences() != 1 || m_sndFile.GetModSpecifications().sequencesMax <= 1)
 		return false;
 
-	bool hasSepPatterns = false;
-	const ORDERINDEX nLengthTt = GetLengthTailTrimmed();
-	for(ORDERINDEX nOrd = 0; nOrd < nLengthTt; nOrd++)
-	{
-		if(!IsValidPat(nOrd) && At(nOrd) != GetIgnoreIndex())
-		{
-			hasSepPatterns = true;
-			break;
-		}
-	}
+	m_Sequences[0].Shrink();
+	bool hasSepPatterns = std::find_if(m_Sequences[0].begin(), m_Sequences[0].end(),
+		[&] (PATTERNINDEX pat) { return pat != GetIgnoreIndex() && !m_sndFile.Patterns.IsValidPat(pat); }) != m_Sequences[0].end();
 	bool modified = false;
 
 	if(hasSepPatterns &&
 		Reporting::Confirm("The order list contains separator items.\nThe new format supports multiple sequences, do you want to convert those separate tracks into multiple song sequences?",
 		"Order list conversion", false, true) == cnfYes)
 	{
-
-		SetSequence(0);
-		for(ORDERINDEX nOrd = 0; nOrd < GetLengthTailTrimmed(); nOrd++)
+		ORDERINDEX length = m_Sequences[0].GetLengthTailTrimmed();
+		for(ORDERINDEX ord = 0; ord < length; ord++)
 		{
-			// end of subsong?
-			if(!IsValidPat(nOrd) && At(nOrd) != GetIgnoreIndex())
+			// End of subsong?
+			if(!m_Sequences[0].IsValidPat(ord) && m_Sequences[0][ord] != GetIgnoreIndex())
 			{
-				ORDERINDEX oldLength = GetLengthTailTrimmed();
 				// remove all separator patterns between current and next subsong first
-				while(nOrd < oldLength && (!m_sndFile.Patterns.IsValidIndex(At(nOrd))))
+				while(ord < length && !m_sndFile.Patterns.IsValidIndex(m_Sequences[0][ord]))
 				{
-					At(nOrd) = GetInvalidPatIndex();
-					nOrd++;
+					m_Sequences[0][ord] = GetInvalidPatIndex();
+					ord++;
 					modified = true;
 				}
-				if(nOrd >= oldLength) break;
-				ORDERINDEX startOrd = nOrd;
+				if(ord >= length) break;
+				ORDERINDEX startOrd = ord;
 				modified = true;
 
 				SEQUENCEINDEX newSeq = AddSequence(false);
-				SetSequence(newSeq);
-
-				// resize new seqeuence if necessary
-				if(GetLength() < oldLength - startOrd)
-				{
-					resize(oldLength - startOrd);
-				}
+				m_Sequences[newSeq].reserve(length - startOrd);
 
 				// now, move all following orders to the new sequence
-				while(nOrd < oldLength)
+				while(ord < length && m_Sequences[0][ord] != GetInvalidPatIndex())
 				{
-					PATTERNINDEX copyPat = GetSequence(newSeq - 1)[nOrd];
-					At(nOrd - startOrd) = copyPat;
-					nOrd++;
+					PATTERNINDEX copyPat = m_Sequences[0][ord];
+					m_Sequences[newSeq].push_back(copyPat);
+					m_Sequences[0][ord] = GetInvalidPatIndex();
+					ord++;
 
 					// is this a valid pattern? adjust pattern jump commands, if necessary.
 					if(m_sndFile.Patterns.IsValidPat(copyPat))
 					{
-						ModCommand *m = m_sndFile.Patterns[copyPat];
-						for(size_t len = m_sndFile.Patterns[copyPat].GetNumRows() * m_sndFile.m_nChannels; len; m++, len--)
+						for(auto &m : m_sndFile.Patterns[copyPat])
 						{
-							if(m->command == CMD_POSITIONJUMP && m->param >= startOrd)
+							if(m.command == CMD_POSITIONJUMP && m.param >= startOrd)
 							{
-								m->param = static_cast<ModCommand::PARAM>(m->param - startOrd);
+								m.param = static_cast<ModCommand::PARAM>(m.param - startOrd);
 							}
 						}
 					}
 				}
-				SetSequence(newSeq - 1);
-				Remove(startOrd, oldLength - 1);
-				SetSequence(newSeq);
-				// start from beginning...
-				nOrd = 0;
-				if(GetLengthTailTrimmed() == 0 || !m_sndFile.Patterns.IsValidIndex(At(nOrd))) break;
 			}
 		}
 		SetSequence(0);
@@ -609,20 +392,19 @@ bool ModSequenceSet::ConvertSubsongsToMultipleSequences()
 
 // Convert the sequence's restart position information to a pattern command.
 bool ModSequenceSet::RestartPosToPattern(SEQUENCEINDEX seq)
-//---------------------------------------------------------
 {
 	bool result = false;
-	std::vector<GetLengthType> length = m_sndFile.GetLength(eNoAdjust, GetLengthTarget(true).StartPos(seq, 0, 0));
-	ModSequence &order = GetSequence(seq);
-	for(std::vector<GetLengthType>::const_iterator it = length.begin(); it != length.end(); it++)
+	auto length = m_sndFile.GetLength(eNoAdjust, GetLengthTarget(true).StartPos(seq, 0, 0));
+	ModSequence &order = m_Sequences[seq];
+	for(const auto &subSong : length)
 	{
-		if(it->endOrder != ORDERINDEX_INVALID && it->endRow != ROWINDEX_INVALID)
+		if(subSong.endOrder != ORDERINDEX_INVALID && subSong.endRow != ROWINDEX_INVALID)
 		{
 			if(Util::TypeCanHoldValue<ModCommand::PARAM>(order.GetRestartPos()))
 			{
-				PATTERNINDEX writePat = order.EnsureUnique(it->endOrder);
+				PATTERNINDEX writePat = order.EnsureUnique(subSong.endOrder);
 				result = m_sndFile.Patterns[writePat].WriteEffect(
-					EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(order.GetRestartPos())).Row(it->endRow).Retry(EffectWriter::rmTryNextRow));
+					EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(order.GetRestartPos())).Row(subSong.endRow).RetryNextRow());
 			} else
 			{
 				result = false;
@@ -635,91 +417,77 @@ bool ModSequenceSet::RestartPosToPattern(SEQUENCEINDEX seq)
 
 
 bool ModSequenceSet::MergeSequences()
-//-----------------------------------
 {
 	if(GetNumSequences() <= 1)
 		return false;
 
-	SetSequence(0);
-	resize(GetLengthTailTrimmed());
-	SEQUENCEINDEX removedSequences = 0; // sequence count
-	std::vector <SEQUENCEINDEX> patternsFixed; // pattern fixed by other sequence already?
-	patternsFixed.resize(m_sndFile.Patterns.Size(), SEQUENCEINDEX_INVALID);
-	// Set up vector
-	for(ORDERINDEX nOrd = 0; nOrd < GetLengthTailTrimmed(); nOrd++)
+	ModSequence &firstSeq = m_Sequences[0];
+	firstSeq.resize(firstSeq.GetLengthTailTrimmed());
+	std::vector<SEQUENCEINDEX> patternsFixed(m_sndFile.Patterns.Size(), SEQUENCEINDEX_INVALID); // pattern fixed by other sequence already?
+	// Mark patterns handled in first sequence
+	for(auto pat : firstSeq)
 	{
-		PATTERNINDEX nPat = At(nOrd);
-		if(!m_sndFile.Patterns.IsValidPat(nPat)) continue;
-		patternsFixed[nPat] = 0;
+		if(m_sndFile.Patterns.IsValidPat(pat))
+			patternsFixed[pat] = 0;
 	}
 
-	while(GetNumSequences() > 1)
+	for(SEQUENCEINDEX seqNum = 1; seqNum < GetNumSequences(); seqNum++)
 	{
-		removedSequences++;
-		const ORDERINDEX nFirstOrder = GetLengthTailTrimmed() + 1; // +1 for separator item
-		if(nFirstOrder + GetSequence(1).GetLengthTailTrimmed() > m_sndFile.GetModSpecifications().ordersMax)
+		ModSequence &seq = m_Sequences[seqNum];
+		const ORDERINDEX firstOrder = firstSeq.GetLength() + 1; // +1 for separator item
+		const ORDERINDEX lengthTrimmed = seq.GetLengthTailTrimmed();
+		if(firstOrder + lengthTrimmed > m_sndFile.GetModSpecifications().ordersMax)
 		{
-			m_sndFile.AddToLog(mpt::String::Print("WARNING: Cannot merge Sequence %1 (too long!)", removedSequences));
-			RemoveSequence(1);
+			m_sndFile.AddToLog(mpt::format("WARNING: Cannot merge Sequence %1 (too long!)")(seqNum));
 			continue;
 		}
-		Append(GetInvalidPatIndex()); // Separator item
-		RestartPosToPattern(1);
-		const ORDERINDEX lengthTrimmed = GetSequence(1).GetLengthTailTrimmed();
-		for(ORDERINDEX nOrd = 0; nOrd < lengthTrimmed; nOrd++)
+		firstSeq.reserve(firstOrder + lengthTrimmed);
+		firstSeq.push_back(); // Separator item
+		RestartPosToPattern(seqNum);
+		for(ORDERINDEX ord = 0; ord < lengthTrimmed; ord++)
 		{
-			PATTERNINDEX nPat = GetSequence(1)[nOrd];
-			Append(nPat);
+			PATTERNINDEX pat = seq[ord];
+			firstSeq.push_back(pat);
 
-			// Try to fix patterns (Bxx commands)
-			if(!m_sndFile.Patterns.IsValidPat(nPat)) continue;
+			// Try to fix pattern jump commands
+			if(!m_sndFile.Patterns.IsValidPat(pat)) continue;
 
-			ModCommand *m = m_sndFile.Patterns[nPat];
-			for(size_t len = 0; len < m_sndFile.Patterns[nPat].GetNumRows() * m_sndFile.m_nChannels; m++, len++)
+			auto m = m_sndFile.Patterns[pat].begin();
+			for(size_t len = 0; len < m_sndFile.Patterns[pat].GetNumRows() * m_sndFile.m_nChannels; m++, len++)
 			{
 				if(m->command == CMD_POSITIONJUMP)
 				{
-					if(patternsFixed[nPat] != SEQUENCEINDEX_INVALID && patternsFixed[nPat] != removedSequences)
+					if(patternsFixed[pat] != SEQUENCEINDEX_INVALID && patternsFixed[pat] != seqNum)
 					{
 						// Oops, some other sequence uses this pattern already.
-						const PATTERNINDEX newPat = m_sndFile.Patterns.InsertAny(m_sndFile.Patterns[nPat].GetNumRows(), true);
+						const PATTERNINDEX newPat = m_sndFile.Patterns.Duplicate(pat, true);
 						if(newPat != PATTERNINDEX_INVALID)
 						{
-							// could create new pattern - copy data over and continue from here.
-							At(nFirstOrder + nOrd) = newPat;
-							ModCommand *pSrc = m_sndFile.Patterns[nPat];
-							ModCommand *pDest = m_sndFile.Patterns[newPat];
-							memcpy(pDest, pSrc, m_sndFile.Patterns[nPat].GetNumRows() * m_sndFile.m_nChannels * sizeof(ModCommand));
-							m = pDest + len;
-							patternsFixed.resize(MAX(newPat + 1, (PATTERNINDEX)patternsFixed.size()), SEQUENCEINDEX_INVALID);
-							nPat = newPat;
+							// Could create new pattern - copy data over and continue from here.
+							firstSeq[firstOrder + ord] = newPat;
+							m = m_sndFile.Patterns[newPat].begin() + len;
+							if(newPat >= patternsFixed.size())
+								patternsFixed.resize(newPat + 1, SEQUENCEINDEX_INVALID);
+							pat = newPat;
 						} else
 						{
-							// cannot create new pattern: notify the user
-							m_sndFile.AddToLog(mpt::String::Print("CONFLICT: Pattern break commands in Pattern %1 might be broken since it has been used in several sequences!", nPat));
+							// Cannot create new pattern: notify the user
+							m_sndFile.AddToLog(mpt::format("CONFLICT: Pattern break commands in Pattern %1 might be broken since it has been used in several sequences!")(pat));
 						}
 					}
-					m->param  = static_cast<ModCommand::PARAM>(m->param + nFirstOrder);
-					patternsFixed[nPat] = removedSequences;
+					m->param = static_cast<ModCommand::PARAM>(m->param + firstOrder);
+					patternsFixed[pat] = seqNum;
 				}
 			}
-
 		}
-		RemoveSequence(1);
 	}
-	// Remove order name + fill up with empty patterns.
-	m_sName = "";
-	const ORDERINDEX CacheSize = s_nCacheSize; // work-around reference to static const member problem
-	const ORDERINDEX nMinLength = std::min(CacheSize, m_sndFile.GetModSpecifications().ordersMax);
-	if(GetLength() < nMinLength)
-		resize(nMinLength);
+	m_Sequences.erase(m_Sequences.begin() + 1, m_Sequences.end());
 	return true;
 }
 
 
 // Check if a playback position is currently locked (inaccessible)
 bool ModSequence::IsPositionLocked(ORDERINDEX position) const
-//-----------------------------------------------------------
 {
 	return(m_sndFile.m_lockOrderStart != ORDERINDEX_INVALID
 		&& (position < m_sndFile.m_lockOrderStart || position > m_sndFile.m_lockOrderEnd));
@@ -732,130 +500,66 @@ bool ModSequence::IsPositionLocked(ORDERINDEX position) const
 /////////////////////////////////////
 
 
-bool ModSequence::Deserialize(FileReader &file)
-//---------------------------------------------
-{
-	if(!file.CanRead(2 + 4)) return false;
-
-	uint16 version = file.ReadUint16LE();
-	if(version != 0) return false;
-
-	uint32 s = file.ReadUint32LE();
-	if(s > 65000 || !file.CanRead(s * 4)) return false;
-
-	const FileReader::off_t endPos = file.GetPosition() + s * 4;
-	LimitMax(s, ModSpecs::mptm.ordersMax);
-
-	resize(static_cast<ORDERINDEX>(s));
-	for(size_t i = 0; i < s; i++)
-	{
-		(*this)[i] = static_cast<PATTERNINDEX>(file.ReadUint32LE());
-	}
-	file.Seek(endPos);
-	return true;
-}
-
-
-size_t ModSequence::WriteAsByte(FILE* f, const ORDERINDEX count, uint8 stopIndex, uint8 ignoreIndex) const
-//--------------------------------------------------------------------------------------------------------
+size_t ModSequence::WriteAsByte(FILE *f, const ORDERINDEX count, uint8 stopIndex, uint8 ignoreIndex) const
 {
 	const size_t limit = std::min(count, GetLength());
 
-	size_t i = 0;
-	
-	for(i = 0; i < limit; i++)
+	for(size_t i = 0; i < limit; i++)
 	{
-		const PATTERNINDEX pat = (*this)[i];
-		uint8 temp = static_cast<uint8>((*this)[i]);
+		const PATTERNINDEX pat = at(i);
+		uint8 temp = static_cast<uint8>(pat);
 
 		if(pat == GetInvalidPatIndex()) temp = stopIndex;
 		else if(pat == GetIgnoreIndex() || pat > 0xFF) temp = ignoreIndex;
 		fwrite(&temp, 1, 1, f);
 	}
 	// Fill non-existing order items with stop indices
-	for(i = limit; i < count; i++)
+	for(size_t i = limit; i < count; i++)
 	{
 		fwrite(&stopIndex, 1, 1, f);
 	}
-	return i; //Returns the number of bytes written.
-}
-
-
-bool ModSequence::ReadAsByte(FileReader &file, size_t howMany, size_t readEntries, uint16 stopIndex, uint16 ignoreIndex)
-//----------------------------------------------------------------------------------------------------------------------
-{
-	if(!file.CanRead(howMany))
-	{
-		return false;
-	}
-	LimitMax(readEntries, howMany);
-	LimitMax(readEntries, ORDERINDEX_MAX);
-
-	if(GetLength() < readEntries)
-	{
-		resize((ORDERINDEX)readEntries);
-	}
-
-	for(size_t i = 0; i < readEntries; i++)
-	{
-		PATTERNINDEX pat = file.ReadUint8();
-		if(pat == stopIndex) pat = GetInvalidPatIndex();
-		if(pat == ignoreIndex) pat = GetIgnoreIndex();
-		(*this)[i] = pat;
-	}
-	std::fill(begin() + readEntries, end(), GetInvalidPatIndex());
-
-	file.Skip(howMany - readEntries);
-	return true;
+	return count; //Returns the number of bytes written.
 }
 
 
 void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t)
-//-----------------------------------------------------------------------------
 {
 	uint16 size;
 	mpt::IO::ReadIntLE<uint16>(iStrm, size);
 	if(size > ModSpecs::mptm.ordersMax)
 	{
-		seq.m_sndFile.AddToLog(mpt::String::Print(str_SequenceTruncationNote, size, ModSpecs::mptm.ordersMax));
+		seq.m_sndFile.AddToLog(mpt::format(str_SequenceTruncationNote)(size, ModSpecs::mptm.ordersMax));
 		size = ModSpecs::mptm.ordersMax;
 	}
-	seq.resize(MAX(size, MAX_ORDERS));
-	if(size == 0)
-		{ seq.Init(); return; }
-
-	for(size_t i = 0; i < size; i++)
+	seq(0).resize(size);
+	for(auto &pat : seq(0))
 	{
 		uint16 temp;
 		mpt::IO::ReadIntLE<uint16>(iStrm, temp);
-		seq[i] = temp;
+		pat = temp;
 	}
 }
 
 
 void WriteModSequenceOld(std::ostream& oStrm, const ModSequenceSet& seq)
-//----------------------------------------------------------------------
 {
-	const uint16 size = seq.GetLength();
+	const uint16 size = seq().GetLength();
 	mpt::IO::WriteIntLE<uint16>(oStrm, size);
-	const ModSequenceSet::const_iterator endIter = seq.end();
-	for(ModSequenceSet::const_iterator citer = seq.begin(); citer != endIter; citer++)
+	for(auto pat : seq())
 	{
-		const uint16 temp = static_cast<uint16>(*citer);
-		mpt::IO::WriteIntLE<uint16>(oStrm, temp);
+		mpt::IO::WriteIntLE<uint16>(oStrm, static_cast<uint16>(pat));
 	}
 }
 
 
 void WriteModSequence(std::ostream& oStrm, const ModSequence& seq)
-//----------------------------------------------------------------
 {
 	srlztn::SsbWrite ssb(oStrm);
 	ssb.BeginWrite(FileIdSequence, MptVersion::num);
-	ssb.WriteItem(seq.m_sName, "n");
-	const uint16 nLength = seq.GetLengthTailTrimmed();
-	ssb.WriteItem<uint16>(nLength, "l");
-	ssb.WriteItem(seq.m_pArray, "a", srlztn::ArrayWriter<uint16>(nLength));
+	ssb.WriteItem(seq.GetName(), "n");
+	const uint16 length = seq.GetLengthTailTrimmed();
+	ssb.WriteItem<uint16>(length, "l");
+	ssb.WriteItem(seq, "a", srlztn::VectorWriter<uint16>(length));
 	if(seq.GetRestartPos() > 0)
 		ssb.WriteItem<uint16>(seq.GetRestartPos(), "r");
 	ssb.FinishWrite();
@@ -863,7 +567,6 @@ void WriteModSequence(std::ostream& oStrm, const ModSequence& seq)
 
 
 void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t)
-//-----------------------------------------------------------------------
 {
 	srlztn::SsbRead ssb(iStrm);
 	ssb.BeginRead(FileIdSequence, MptVersion::num);
@@ -871,12 +574,11 @@ void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t)
 		return;
 	std::string str;
 	ssb.ReadItem(str, "n");
-	seq.m_sName = str;
-	ORDERINDEX nSize = MAX_ORDERS;
+	seq.SetName(str);
+	ORDERINDEX nSize = 0;
 	ssb.ReadItem(nSize, "l");
 	LimitMax(nSize, ModSpecs::mptm.ordersMax);
-	seq.resize(std::max(nSize, ModSequenceSet::s_nCacheSize));
-	ssb.ReadItem(seq.m_pArray, "a", srlztn::ArrayReader<uint16>(nSize));
+	ssb.ReadItem(seq, "a", srlztn::VectorReader<uint16>(nSize));
 
 	ORDERINDEX restartPos = ORDERINDEX_INVALID;
 	if(ssb.ReadItem(restartPos, "r") != srlztn::SsbRead::EntryNotFound && restartPos < nSize)
@@ -885,7 +587,6 @@ void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t)
 
 
 void WriteModSequences(std::ostream& oStrm, const ModSequenceSet& seq)
-//--------------------------------------------------------------------
 {
 	srlztn::SsbWrite ssb(oStrm);
 	ssb.BeginWrite(FileIdSequences, MptVersion::num);
@@ -895,42 +596,37 @@ void WriteModSequences(std::ostream& oStrm, const ModSequenceSet& seq)
 	ssb.WriteItem(nCurrent, "c");
 	for(uint8 i = 0; i < nSeqs; i++)
 	{
-		if (i == seq.GetCurrentSequenceIndex())
-			ssb.WriteItem(seq, srlztn::ID::FromInt<uint8>(i), &WriteModSequence);
-		else
-			ssb.WriteItem(seq.m_Sequences[i], srlztn::ID::FromInt<uint8>(i), &WriteModSequence);
+		ssb.WriteItem(seq(i), srlztn::ID::FromInt<uint8>(i), &WriteModSequence);
 	}
 	ssb.FinishWrite();
 }
 
 
 void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t)
-//---------------------------------------------------------------------------
 {
 	srlztn::SsbRead ssb(iStrm);
 	ssb.BeginRead(FileIdSequences, MptVersion::num);
 	if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0)
 		return;
-	uint8 nSeqs = 0;
-	uint8 nCurrent = 0;
-	ssb.ReadItem(nSeqs, "n");
-	if (nSeqs == 0)
+	SEQUENCEINDEX seqs = 0;
+	uint8 currentSeq = 0;
+	ssb.ReadItem(seqs, "n");
+	if (seqs == 0)
 		return;
-	LimitMax(nSeqs, MAX_SEQUENCES);
-	ssb.ReadItem(nCurrent, "c");
-	if (seq.GetNumSequences() < nSeqs)
-		seq.m_Sequences.resize(nSeqs, ModSequence(seq.m_sndFile, seq.s_nCacheSize));
+	LimitMax(seqs, MAX_SEQUENCES);
+	ssb.ReadItem(currentSeq, "c");
+	if (seq.GetNumSequences() < seqs)
+		seq.m_Sequences.resize(seqs, ModSequence(seq.m_sndFile));
 
 	// There used to be only one restart position for all sequences
-	ORDERINDEX legacyRestartPos = seq.GetRestartPos();
+	ORDERINDEX legacyRestartPos = seq(0).GetRestartPos();
 
-	for(uint8 i = 0; i < nSeqs; i++)
+	for(SEQUENCEINDEX i = 0; i < seqs; i++)
 	{
-		seq.m_Sequences[i].SetRestartPos(legacyRestartPos);
-		ssb.ReadItem(seq.m_Sequences[i], srlztn::ID::FromInt<uint8>(i), &ReadModSequence);
+		seq(i).SetRestartPos(legacyRestartPos);
+		ssb.ReadItem(seq(i), srlztn::ID::FromInt<uint8>(i), &ReadModSequence);
 	}
-	seq.m_nCurrentSeq = (nCurrent < seq.GetNumSequences()) ? nCurrent : 0;
-	seq.CopyStorageToCache();
+	seq.m_currentSeq = (currentSeq < seq.GetNumSequences()) ? currentSeq : 0;
 }
 
 
diff --git a/soundlib/ModSequence.h b/soundlib/ModSequence.h
index 89658a1..8ebf602 100644
--- a/soundlib/ModSequence.h
+++ b/soundlib/ModSequence.h
@@ -12,112 +12,91 @@
 
 #include <algorithm>
 #include <vector>
+#include "Snd_defs.h"
 
 OPENMPT_NAMESPACE_BEGIN
 
 class CSoundFile;
 class ModSequenceSet;
-class FileReader;
 
-class ModSequence
-//===============
+class ModSequence: public std::vector<PATTERNINDEX>
 {
-public:
 	friend class ModSequenceSet;
-	typedef PATTERNINDEX* iterator;
-	typedef const PATTERNINDEX* const_iterator;
-	
-	friend void WriteModSequence(std::ostream& oStrm, const ModSequence& seq);
-	friend void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t);
 
-	virtual ~ModSequence() {if (m_bDeletableArray) delete[] m_pArray;}
-	ModSequence(const ModSequence&);
-	ModSequence(CSoundFile& rSf, ORDERINDEX nSize);
-	ModSequence(CSoundFile& rSf, PATTERNINDEX* pArray, ORDERINDEX nSize, ORDERINDEX nCapacity, ORDERINDEX restartPos, bool bDeletableArray);
+protected:
+	std::string m_name;			// Sequence name.
+	CSoundFile &m_sndFile;		// Associated CSoundFile.
+	ORDERINDEX m_restartPos;	// Restart position when playback of this order ended
 
-	// Initialize default sized sequence.
-	void Init();
+public:
+	ModSequence(CSoundFile &sndFile);
+	ModSequence(ModSequence &&) noexcept = default;
+	ModSequence(const ModSequence &) = default;
+	ModSequence& operator=(const ModSequence &other);
 
-	PATTERNINDEX& operator[](const size_t i) {MPT_ASSERT(i < m_nSize); return m_pArray[i];}
-	const PATTERNINDEX& operator[](const size_t i) const {MPT_ASSERT(i < m_nSize); return m_pArray[i];}
-	PATTERNINDEX& At(const size_t i) {return (*this)[i];}
-	const PATTERNINDEX& At(const size_t i) const {return (*this)[i];}
+	bool operator==(const ModSequence &other) const;
+	bool operator!=(const ModSequence &other) const { return !(*this == other); }
 
-	PATTERNINDEX& Last() {MPT_ASSERT(m_nSize > 0); return m_pArray[m_nSize-1];}
-	const PATTERNINDEX& Last() const {MPT_ASSERT(m_nSize > 0); return m_pArray[m_nSize-1];}
+	ORDERINDEX GetLength() const { return mpt::saturate_cast<ORDERINDEX>(size()); }
+	// Returns last accessible index, i.e. GetLength() - 1, or 0 if the order list is empty.
+	ORDERINDEX GetLastIndex() const { return std::max(ORDERINDEX(1), GetLength()) - 1u; }
+	// Returns length of sequence without counting trailing '---' items.
+	ORDERINDEX GetLengthTailTrimmed() const;
+	// Returns length of sequence stopping counting on first '---' (or at the end of sequence).
+	ORDERINDEX GetLengthFirstEmpty() const;
 
-	// Returns last accessible index, i.e. GetLength() - 1. Behaviour is undefined if length is zero.
-	ORDERINDEX GetLastIndex() const {return m_nSize - 1;}
+	// Replaces order list with 'newSize' copies of 'pat'.
+	void assign(ORDERINDEX newSize, PATTERNINDEX pat);
 
-	void Append() {Append(GetInvalidPatIndex());}	// Appends InvalidPatIndex.
-	void Append(PATTERNINDEX nPat);					// Appends given patindex.
+	// Inserts 'count' orders starting from 'pos' using 'fill' as the pattern index for all inserted orders.
+	// Sequence will automatically grow if needed and if it can't grow enough, some tail orders will be discarded.
+	// Return: Number of orders inserted (up to 'count' many).
+	ORDERINDEX insert(ORDERINDEX pos, ORDERINDEX count) { return insert(pos, count, GetInvalidPatIndex()); }
+	ORDERINDEX insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill);
 
-	// Inserts nCount orders starting from nPos using nFill as the pattern index for all inserted orders.
-	// Sequence will automatically grow if needed and if it can't grow enough, some tail 
-	// orders will be discarded.
-	// Return: Number of orders inserted.
-	ORDERINDEX Insert(ORDERINDEX nPos, ORDERINDEX nCount) { return Insert(nPos, nCount, GetInvalidPatIndex()); }
-	ORDERINDEX Insert(ORDERINDEX nPos, ORDERINDEX nCount, PATTERNINDEX nFill);
+	void push_back() { push_back(GetInvalidPatIndex()); }
+	void push_back(PATTERNINDEX pat) { if(GetLength() < MAX_ORDERS) std::vector<PATTERNINDEX>::push_back(pat); }
 
-	// Removes orders from range [nPosBegin, nPosEnd].
-	void Remove(ORDERINDEX nPosBegin, ORDERINDEX nPosEnd);
+	void resize(ORDERINDEX newSize) { resize(newSize, GetInvalidPatIndex()); }
+	void resize(ORDERINDEX newSize, PATTERNINDEX pat) { std::vector<PATTERNINDEX>::resize(std::min(MAX_ORDERS, newSize), pat); }
 
-	// Remove all references to a given pattern index from the order list. Jump commands are updated accordingly.
-	void RemovePattern(PATTERNINDEX which);
+	// Removes orders from range [posBegin, posEnd].
+	void Remove(ORDERINDEX posBegin, ORDERINDEX posEnd);
 
-	// Check if pattern at sequence position ord is valid.
-	bool IsValidPat(ORDERINDEX ord);
-
-	void clear();
-	void resize(ORDERINDEX nNewSize) {resize(nNewSize, GetInvalidPatIndex());}
-	void resize(ORDERINDEX nNewSize, PATTERNINDEX nFill);
-	
-	// Replaces all occurences of nOld with nNew.
-	void Replace(PATTERNINDEX nOld, PATTERNINDEX nNew) {if (nOld != nNew) std::replace(begin(), end(), nOld, nNew);}
+	// Remove all references to a given pattern index from the order list. Jump commands are updated accordingly.
+	void RemovePattern(PATTERNINDEX pat);
 
-	void AdjustToNewModType(const MODTYPE oldtype);
+	// Replaces all occurences of oldPat with newPat.
+	void Replace(PATTERNINDEX oldPat, PATTERNINDEX newPat) { if(oldPat != newPat) std::replace(begin(), end(), oldPat, newPat); }
 
-	ORDERINDEX size() const {return GetLength();}
-	ORDERINDEX GetLength() const {return m_nSize;}
+	// Removes any "---" patterns at the end of the list.
+	void Shrink() { resize(GetLengthTailTrimmed()); }
 
-	// Returns length of sequence without counting trailing '---' items.
-	ORDERINDEX GetLengthTailTrimmed() const;
+	// Check if pattern at sequence position ord is valid.
+	bool IsValidPat(ORDERINDEX ord) const;
 
-	// Returns length of sequence stopping counting on first '---' (or at the end of sequence).
-	ORDERINDEX GetLengthFirstEmpty() const;
+	void AdjustToNewModType(const MODTYPE oldtype);
 
 	// Returns the internal representation of a stop '---' index
 	static PATTERNINDEX GetInvalidPatIndex() { return uint16_max; }
 	// Returns the internal representation of an ignore '+++' index
-	static PATTERNINDEX GetIgnoreIndex() {return uint16_max - 1; }
+	static PATTERNINDEX GetIgnoreIndex() { return uint16_max - 1; }
 
-	// Returns the previous/next order ignoring skip indices(+++).
+	// Returns the previous/next order ignoring skip indices (+++).
 	// If no previous/next order exists, return first/last order, and zero
 	// when orderlist is empty.
 	ORDERINDEX GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const;
 	ORDERINDEX GetNextOrderIgnoringSkips(const ORDERINDEX start) const;
 
 	// Find an order item that contains a given pattern number.
-	ORDERINDEX FindOrder(PATTERNINDEX nPat, ORDERINDEX startFromOrder = 0, bool searchForward = true) const;
+	ORDERINDEX FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt = 0, bool searchForward = true) const;
 
 	// Ensures that the pattern at the specified order position is used only once (across all sequences).
 	// If another usage is found, the pattern is replaced by a copy and the new index is returned.
 	PATTERNINDEX EnsureUnique(ORDERINDEX ord);
 
-	ModSequence& operator=(const ModSequence& seq);
-
 	// Write order items as bytes. '---' is written as stopIndex, '+++' is written as ignoreIndex
-	size_t WriteAsByte(FILE* f, const ORDERINDEX count, uint8 stopIndex = 0xFF, uint8 ignoreIndex = 0xFE) const;
-	// Read order items as bytes from a file. 'howMany' bytes are read from the file, optionally only the first 'readEntries' of them are actually processed.
-	// 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass a parameter that does not fit into a byte.
-	bool ReadAsByte(FileReader &file, size_t howMany, size_t readEntries = ORDERINDEX_MAX, uint16 stopIndex = ORDERINDEX_INVALID, uint16 ignoreIndex = ORDERINDEX_INVALID);
-	template<typename T, size_t arraySize>
-	// Read order items from an array. Only the first 'howMany' entries are actually processed.
-	// 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass ORDERINDEX_INVALID.
-	bool ReadFromArray(const T (&orders)[arraySize], size_t howMany = arraySize, uint16 stopIndex = ORDERINDEX_INVALID, uint16 ignoreIndex = ORDERINDEX_INVALID);
-
-	// Deprecated function used for MPTm files created with OpenMPT 1.17.02.46 - 1.17.02.48.
-	bool Deserialize(FileReader &file);
+	size_t WriteAsByte(FILE *f, const ORDERINDEX count, uint8 stopIndex = 0xFF, uint8 ignoreIndex = 0xFE) const;
 
 	// Returns true if the IT orderlist datafield is not sufficient to store orderlist information.
 	bool NeedsExtraDatafield() const;
@@ -128,84 +107,60 @@ public:
 #endif // MODPLUG_TRACKER
 
 	// Sequence name setter / getter
-	inline void SetName(const std::string &newName) { m_sName = newName;}
-	inline std::string GetName() const { return m_sName; }
+	inline void SetName(const std::string &newName) { m_name = newName;}
+	inline std::string GetName() const { return m_name; }
 
 	// Restart position setter / getter
 	inline void SetRestartPos(ORDERINDEX restartPos) { m_restartPos = restartPos; }
 	inline ORDERINDEX GetRestartPos() const { return m_restartPos; }
-
-
-public:
-	iterator begin() {return m_pArray;}
-	const_iterator begin() const {return m_pArray;}
-	iterator end() {return m_pArray + m_nSize;}
-	const_iterator end() const {return m_pArray + m_nSize;}
-
-protected:
-	std::string m_sName;			// Sequence name.
-
-	CSoundFile &m_sndFile;			// Pointer to associated CSoundFile.
-	PATTERNINDEX *m_pArray;			// Pointer to sequence array.
-	ORDERINDEX m_nSize;				// Sequence length.
-	ORDERINDEX m_nCapacity;			// Capacity in m_pArray.
-	ORDERINDEX m_restartPos;		// Restart position when playback of this order ended
-	bool m_bDeletableArray;			// True if m_pArray points the deletable(with delete[]) array.
 };
 
 
-template<typename T, size_t arraySize>
-bool ModSequence::ReadFromArray(const T (&orders)[arraySize], size_t howMany, uint16 stopIndex, uint16 ignoreIndex)
-//-----------------------------------------------------------------------------------------------------------------
+class ModSequenceSet
 {
-	STATIC_ASSERT(arraySize < ORDERINDEX_MAX);
-	LimitMax(howMany, arraySize);
-	ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany);
-
-	if(GetLength() < readEntries)
-	{
-		resize(readEntries);
-	}
-
-	for(int i = 0; i < readEntries; i++)
-	{
-		PATTERNINDEX pat = static_cast<PATTERNINDEX>(orders[i]);
-		if(pat == stopIndex) pat = GetInvalidPatIndex();
-		if(pat == ignoreIndex) pat = GetIgnoreIndex();
-		(*this)[i] = pat;
-	}
-	return true;
-}
-
-//=======================================
-class ModSequenceSet : public ModSequence
-//=======================================
-{
-	friend void WriteModSequenceOld(std::ostream& oStrm, const ModSequenceSet& seq);
 	friend void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t);
-	friend void WriteModSequences(std::ostream& oStrm, const ModSequenceSet& seq);
 	friend void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t);
-	friend void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t);
 
-public:
-	ModSequenceSet(CSoundFile& sndFile);
+protected:
+	std::vector<ModSequence> m_Sequences;	// Array of sequences.
+	CSoundFile &m_sndFile;
+	SEQUENCEINDEX m_currentSeq;				// Index of current sequence.
 
-	const ModSequence& GetSequence() {return GetSequence(GetCurrentSequenceIndex());}
-	const ModSequence& GetSequence(SEQUENCEINDEX nSeq) const;
-	ModSequence& GetSequence(SEQUENCEINDEX nSeq);
-	SEQUENCEINDEX GetNumSequences() const {return static_cast<SEQUENCEINDEX>(m_Sequences.size());}
-	void SetSequence(SEQUENCEINDEX);			// Sets working sequence.
-	SEQUENCEINDEX AddSequence(bool bDuplicate = true);	// Adds new sequence. If bDuplicate is true, new sequence is a duplicate of the old one. Returns the ID of the new sequence.
-	void RemoveSequence() {RemoveSequence(GetCurrentSequenceIndex());}
-	void RemoveSequence(SEQUENCEINDEX);		// Removes given sequence
-	SEQUENCEINDEX GetCurrentSequenceIndex() const {return m_nCurrentSeq;}
+public:
+	ModSequenceSet(CSoundFile &sndFile);
+	ModSequenceSet(ModSequenceSet &&) noexcept = default;
+
+	// Remove all sequences and initialize default sequence
+	void Initialize();
+
+	// Get the working sequence
+	ModSequence& operator() () { return m_Sequences[m_currentSeq]; }
+	const ModSequence& operator() () const { return m_Sequences[m_currentSeq]; }
+	// Get an arbitrary sequence
+	ModSequence& operator() (SEQUENCEINDEX seq) { return m_Sequences[seq]; }
+	const ModSequence& operator() (SEQUENCEINDEX seq) const { return m_Sequences[seq]; }
+
+	SEQUENCEINDEX GetNumSequences() const { return static_cast<SEQUENCEINDEX>(m_Sequences.size()); }
+	SEQUENCEINDEX GetCurrentSequenceIndex() const { return m_currentSeq; }
+
+	// Sets working sequence.
+	void SetSequence(SEQUENCEINDEX);
+	// Add new sequence.
+	// If duplicate is true, new sequence is a duplicate of the current sequence.
+	// Returns the ID of the new sequence, or SEQUENCEINDEX_INVALID on failure.
+	SEQUENCEINDEX AddSequence(bool duplicate = true);
+	// Removes given sequence.
+	void RemoveSequence(SEQUENCEINDEX);
 
-	ModSequenceSet& operator=(const ModSequence& seq) {ModSequence::operator=(seq); return *this;}
+	// Returns the internal representation of a stop '---' index
+	static PATTERNINDEX GetInvalidPatIndex() { return ModSequence::GetInvalidPatIndex(); }
+	// Returns the internal representation of an ignore '+++' index
+	static PATTERNINDEX GetIgnoreIndex() { return ModSequence::GetIgnoreIndex(); }
 
 #ifdef MODPLUG_TRACKER
 	// Adjust sequence when converting between module formats
-	void OnModTypeChanged(const MODTYPE oldtype);
-	// If there are subsongs (separated by "---" or "+++" patterns) in the module,
+	void OnModTypeChanged(MODTYPE oldType);
+	// If there are subsongs (separated by "---" patterns) in the module,
 	// asks user whether to convert these into multiple sequences (given that the 
 	// modformat supports multiple sequences).
 	// Returns true if sequences were modified, false otherwise.
@@ -218,21 +173,12 @@ public:
 	bool MergeSequences();
 #endif // MODPLUG_TRACKER
 
-	static const ORDERINDEX s_nCacheSize;
-
-private:
-	void CopyCacheToStorage();
-	void CopyStorageToCache();
-
-	// Array size should be s_nCacheSize.
-	// s_nCacheSize is defined out of line, because taking references to
-	// static const members is problematic for some clang and GCC versions
-	// otherwise.
-	// Defining s_nCacheSize out of line makes it unavailable for declaring
-	// an array.
-	PATTERNINDEX m_Cache[MAX_ORDERS];		// Local cache array.
-	std::vector<ModSequence> m_Sequences;	// Array of sequences.
-	SEQUENCEINDEX m_nCurrentSeq;			// Index of current sequence.
+	std::vector<ModSequence>::iterator begin() { return m_Sequences.begin(); }
+	std::vector<ModSequence>::const_iterator begin() const { return m_Sequences.begin(); }
+	std::vector<ModSequence>::const_iterator cbegin() const { return m_Sequences.cbegin(); }
+	std::vector<ModSequence>::iterator end() { return m_Sequences.end(); }
+	std::vector<ModSequence>::const_iterator end() const { return m_Sequences.end(); }
+	std::vector<ModSequence>::const_iterator cend() const { return m_Sequences.cend(); }
 };
 
 
diff --git a/soundlib/OggStream.cpp b/soundlib/OggStream.cpp
index 3b4f6dd..b42a5c8 100644
--- a/soundlib/OggStream.cpp
+++ b/soundlib/OggStream.cpp
@@ -80,7 +80,7 @@ bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector<uint8> &pageData
 	}
 	file.SkipBack(4);
 	FileReader filePageReader = file; // do not modify original file read position
-	if(!filePageReader.ReadConvertEndianness(pageInfo.header))
+	if(!filePageReader.ReadStruct(pageInfo.header))
 	{
 		return false;
 	}
@@ -98,13 +98,13 @@ bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector<uint8> &pageData
 	{
 		return false;
 	}
-	filePageReader.ReadVectorLE(pageData, pageDataSize);
+	filePageReader.ReadVector(pageData, pageDataSize);
 	filePageReader.SkipBack(pageInfo.GetPagePhysicalSize());
 	{
 		mpt::crc32_ogg calculatedCRC;
 		uint8 rawHeader[sizeof(PageHeader)];
 		MemsetZero(rawHeader);
-		filePageReader.ReadArrayLE(rawHeader);
+		filePageReader.ReadArray(rawHeader);
 		std::memset(rawHeader + 22, 0, 4); // clear out old crc
 		calculatedCRC.process(rawHeader, rawHeader + sizeof(rawHeader));
 		calculatedCRC.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments);
@@ -157,10 +157,8 @@ bool UpdatePageCRC(PageInfo &pageInfo, const std::vector<uint8> &pageData)
 	}
 	mpt::crc32_ogg crc;
 	pageInfo.header.CRC_checksum = 0;
-	pageInfo.header.ConvertEndianness();
 	char rawHeader[sizeof(PageHeader)];
 	std::memcpy(rawHeader, &pageInfo.header, sizeof(PageHeader));
-	pageInfo.header.ConvertEndianness();
 	crc.process(rawHeader, rawHeader + sizeof(PageHeader));
 	crc.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments);
 	crc.process(pageData);
diff --git a/soundlib/OggStream.h b/soundlib/OggStream.h
index 6ec0283..d484907 100644
--- a/soundlib/OggStream.h
+++ b/soundlib/OggStream.h
@@ -11,47 +11,30 @@
 #include "../common/Endianness.h"
 #include "../common/mptIO.h"
 
-
-OPENMPT_NAMESPACE_BEGIN
+#include "../common/FileReaderFwd.h"
 
 
-class FileReader;
+OPENMPT_NAMESPACE_BEGIN
 
 
 namespace Ogg
 {
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED PageHeader
+struct PageHeader
 {
-	char   capture_pattern[4]; // "OggS"
-	uint8  version;
-	uint8  header_type;
-	uint64 granule_position;
-	uint32 bitstream_serial_number;
-	uint32 page_seqauence_number;
-	uint32 CRC_checksum;
-	uint8  page_segments;
-
-	void ConvertEndianness()
-	{
-		SwapBytesLE(granule_position);
-		SwapBytesLE(bitstream_serial_number);
-		SwapBytesLE(page_seqauence_number);
-		SwapBytesLE(CRC_checksum);
-	}
-
+	char     capture_pattern[4]; // "OggS"
+	uint8le  version;
+	uint8le  header_type;
+	uint64le granule_position;
+	uint32le bitstream_serial_number;
+	uint32le page_seqauence_number;
+	uint32le CRC_checksum;
+	uint8le  page_segments;
 };
 
-STATIC_ASSERT(sizeof(PageHeader) == 27);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+} // namespace Ogg
+MPT_BINARY_STRUCT(Ogg::PageHeader, 27)
+namespace Ogg {
 
 
 struct PageInfo
@@ -80,9 +63,9 @@ bool UpdatePageCRC(PageInfo &pageInfo, const std::vector<uint8> &pageData);
 
 
 template <typename Tfile>
-bool WritePage(Tfile & f, PageInfo &pageInfo, const std::vector<uint8> &pageData)
+bool WritePage(Tfile & f, const PageInfo &pageInfo, const std::vector<uint8> &pageData)
 {
-	if(!mpt::IO::WriteConvertEndianness(f, pageInfo.header))
+	if(!mpt::IO::Write(f, pageInfo.header))
 	{
 		return false;
 	}
@@ -90,7 +73,7 @@ bool WritePage(Tfile & f, PageInfo &pageInfo, const std::vector<uint8> &pageData
 	{
 		return false;
 	}
-	if(!mpt::IO::WriteRaw(f, &pageData[0], pageData.size()))
+	if(!mpt::IO::WriteRaw(f, pageData.data(), pageData.size()))
 	{
 		return false;
 	}
diff --git a/soundlib/Paula.cpp b/soundlib/Paula.cpp
new file mode 100644
index 0000000..8d98b64
--- /dev/null
+++ b/soundlib/Paula.cpp
@@ -0,0 +1,341 @@
+/*
+* Paula.cpp
+* ---------
+* Purpose: Emulating the Amiga's sound chip, Paula, by implementing resampling using band-limited steps (BLEPs)
+* Notes  : (currently none)
+* Authors: OpenMPT Devs
+*          Antti S. Lankila
+* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+*/
+
+#include "stdafx.h"
+#include "Paula.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+namespace Paula
+{
+
+// Tables are: A500 (filter off), A500 (filter on)
+static constexpr int32 WinSincIntegral[2][2048] =
+{
+	{
+	131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,
+	131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131071,131071,
+	131071,131071,131071,131071,131071,131071,131071,131071,131071,131070,131070,131070,
+	131070,131070,131069,131069,131069,131068,131068,131068,131067,131067,131066,131066,
+	131065,131065,131064,131063,131063,131062,131061,131060,131059,131058,131056,131055,
+	131054,131052,131050,131049,131047,131045,131043,131040,131038,131035,131033,131030,
+	131026,131023,131020,131016,131012,131008,131003,130998,130993,130988,130982,130976,
+	130970,130963,130956,130949,130941,130932,130924,130914,130905,130895,130884,130872,
+	130861,130848,130835,130821,130807,130792,130776,130759,130742,130724,130705,130685,
+	130664,130642,130620,130596,130571,130545,130518,130490,130461,130430,130398,130365,
+	130331,130295,130257,130219,130178,130136,130093,130047,130000,129951,129901,129848,
+	129794,129737,129679,129618,129555,129490,129423,129353,129281,129207,129130,129050,
+	128968,128883,128795,128704,128611,128514,128415,128312,128206,128097,127985,127869,
+	127750,127627,127501,127371,127237,127100,126959,126813,126664,126510,126353,126191,
+	126025,125854,125679,125499,125315,125126,124933,124734,124531,124323,124110,123891,
+	123668,123439,123205,122965,122720,122470,122214,121952,121685,121412,121133,120849,
+	120558,120261,119959,119650,119335,119014,118687,118354,118014,117668,117315,116956,
+	116591,116219,115840,115455,115063,114665,114260,113849,113430,113005,112574,112135,
+	111690,111239,110780,110315,109843,109364,108879,108387,107888,107383,106871,106352,
+	105827,105295,104757,104212,103661,103104,102540,101970,101394,100812,100223,99629,
+	99028,98422,97810,97192,96568,95939,95305,94665,94020,93370,92714,92054,91389,90719,
+	90045,89366,88682,87995,87303,86607,85908,85205,84498,83788,83075,82358,81639,80916,
+	80191,79464,78734,78002,77268,76533,75795,75056,74316,73575,72833,72090,71346,70602,
+	69858,69114,68370,67626,66883,66140,65399,64658,63919,63181,62445,61711,60979,60249,
+	59521,58796,58074,57355,56639,55926,55217,54512,53810,53113,52419,51731,51046,50367,
+	49693,49023,48359,47701,47048,46400,45759,45124,44495,43872,43256,42646,42043,41447,
+	40858,40276,39702,39134,38575,38023,37478,36941,36413,35892,35379,34874,34378,33890,
+	33410,32938,32475,32020,31574,31137,30708,30288,29876,29473,29079,28693,28317,27948,
+	27589,27238,26896,26562,26238,25921,25613,25314,25023,24740,24466,24200,23942,23692,
+	23451,23217,22991,22773,22562,22359,22164,21975,21794,21621,21454,21294,21140,20994,
+	20853,20719,20592,20470,20354,20244,20139,20040,19946,19857,19774,19694,19620,19550,
+	19484,19422,19364,19310,19260,19213,19169,19128,19090,19054,19022,18991,18963,18936,
+	18912,18889,18867,18847,18828,18810,18792,18776,18759,18743,18727,18711,18695,18679,
+	18662,18644,18626,18607,18587,18565,18542,18518,18492,18465,18436,18404,18371,18336,
+	18298,18259,18216,18172,18124,18074,18022,17966,17908,17847,17783,17716,17646,17572,
+	17496,17416,17334,17248,17159,17066,16971,16872,16770,16664,16556,16444,16329,16211,
+	16090,15966,15839,15709,15576,15440,15301,15159,15015,14868,14718,14566,14412,14255,
+	14096,13935,13771,13606,13439,13270,13099,12927,12753,12578,12401,12224,12045,11866,
+	11685,11504,11322,11140,10958,10775,10592,10409,10226,10044,9862,9680,9499,9319,9139,
+	8961,8783,8607,8432,8258,8086,7915,7747,7580,7415,7252,7091,6932,6776,6622,6471,
+	6322,6176,6032,5892,5754,5619,5488,5359,5234,5111,4992,4877,4764,4655,4550,4448,
+	4349,4254,4163,4075,3990,3910,3832,3759,3689,3622,3560,3500,3445,3393,3344,3299,
+	3257,3219,3184,3153,3124,3099,3078,3059,3044,3031,3022,3015,3011,3010,3012,3016,
+	3023,3033,3044,3058,3075,3093,3113,3136,3160,3186,3213,3242,3273,3305,3338,3372,
+	3408,3444,3481,3520,3558,3597,3637,3677,3718,3758,3799,3839,3880,3920,3960,4000,
+	4039,4077,4115,4152,4188,4224,4258,4291,4323,4354,4384,4412,4439,4464,4488,4510,
+	4530,4549,4566,4581,4594,4606,4615,4623,4628,4631,4633,4632,4629,4624,4617,4608,
+	4597,4583,4568,4550,4530,4508,4484,4458,4429,4399,4366,4332,4296,4257,4217,4175,
+	4130,4085,4037,3988,3937,3884,3830,3774,3717,3658,3598,3537,3475,3411,3347,3281,
+	3215,3147,3079,3010,2940,2870,2799,2728,2657,2585,2513,2440,2368,2296,2224,2151,
+	2080,2008,1937,1866,1796,1726,1657,1589,1521,1454,1389,1324,1260,1197,1135,1075,
+	1016,958,901,846,792,740,689,640,592,546,502,459,419,379,342,307,273,241,211,183,
+	156,132,109,88,69,52,37,24,12,2,-5,-11,-16,-18,-19,-18,-16,-11,-6,2,11,21,33,47,61,
+	77,95,113,133,154,176,200,224,249,275,302,329,358,387,416,447,477,508,540,572,604,
+	636,669,702,734,767,800,832,864,896,928,960,991,1021,1051,1081,1110,1138,1166,1193,
+	1219,1245,1270,1293,1316,1338,1359,1379,1398,1416,1433,1448,1463,1476,1488,1499,
+	1509,1518,1525,1531,1536,1540,1542,1543,1543,1542,1539,1536,1530,1524,1517,1508,
+	1498,1487,1475,1462,1447,1432,1415,1397,1379,1359,1338,1317,1294,1271,1247,1222,
+	1196,1170,1143,1115,1086,1057,1028,998,967,936,905,874,842,809,777,744,712,679,646,
+	613,581,548,515,483,450,418,387,355,324,293,263,233,204,175,147,119,92,66,40,15,
+	-10,-33,-56,-78,-99,-120,-139,-158,-176,-193,-209,-224,-238,-252,-264,-275,-286,
+	-295,-304,-311,-318,-324,-329,-332,-335,-337,-338,-338,-338,-336,-333,-330,-326,
+	-321,-315,-308,-301,-293,-284,-274,-264,-253,-242,-229,-217,-203,-190,-175,-161,
+	-145,-130,-114,-98,-81,-64,-47,-29,-11,6,24,42,61,79,97,115,134,152,170,188,206,223,
+	241,258,275,291,308,324,340,355,370,384,399,412,425,438,450,462,473,484,494,503,
+	512,521,529,536,542,548,553,558,562,566,568,570,572,573,573,573,572,570,568,565,
+	562,558,553,548,543,537,530,523,515,507,498,489,479,469,459,448,437,426,414,402,
+	389,377,364,351,337,324,310,296,282,268,254,239,225,211,196,182,168,153,139,125,
+	111,97,83,70,56,43,30,17,5,-7,-19,-31,-42,-53,-64,-75,-85,-94,-104,-113,-121,-129,
+	-137,-144,-151,-158,-164,-170,-175,-180,-184,-188,-192,-195,-198,-200,-202,-203,
+	-204,-205,-205,-204,-204,-203,-201,-199,-197,-195,-192,-188,-185,-181,-176,-172,
+	-167,-162,-156,-151,-145,-139,-132,-126,-119,-112,-104,-97,-90,-82,-74,-66,-59,-51,
+	-42,-34,-26,-18,-10,-2,7,15,23,31,39,47,54,62,70,77,85,92,99,106,112,119,125,131,
+	137,143,148,154,159,163,168,172,176,180,183,187,190,192,195,197,199,201,202,203,
+	204,205,205,205,205,204,203,202,201,200,198,196,194,192,189,186,183,180,177,173,
+	169,165,161,157,153,148,143,139,134,129,124,119,113,108,103,97,92,86,81,75,70,64,
+	59,53,48,42,37,32,26,21,16,11,6,1,-4,-9,-13,-18,-22,-26,-30,-34,-38,-42,-46,-49,
+	-52,-55,-58,-61,-64,-66,-69,-71,-73,-74,-76,-78,-79,-80,-81,-82,-82,-83,-83,-83,
+	-83,-83,-83,-82,-82,-81,-80,-79,-78,-77,-75,-74,-72,-70,-68,-66,-64,-62,-60,-57,
+	-55,-52,-50,-47,-44,-42,-39,-36,-33,-30,-27,-24,-21,-18,-15,-12,-9,-6,-3,0,3,6,8,
+	11,14,17,20,22,25,27,30,32,35,37,39,41,43,45,47,49,50,52,54,55,56,58,59,60,61,61,
+	62,63,63,64,64,65,65,65,65,65,64,64,64,63,63,62,61,61,60,59,58,57,56,55,53,52,51,
+	49,48,46,45,43,41,40,38,36,35,33,31,29,28,26,24,22,20,19,17,15,13,11,10,8,6,5,3,1,
+	0,-2,-3,-5,-6,-8,-9,-10,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-23,
+	-24,-24,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-24,
+	-24,-23,-23,-22,-21,-21,-20,-19,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-10,-9,
+	-8,-7,-6,-5,-4,-3,-2,-1,0,1,1,2,3,4,5,6,6,7,8,9,9,10,11,11,12,12,13,14,14,15,15,
+	15,16,16,16,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,16,16,
+	16,16,15,15,14,14,14,13,13,12,12,11,11,11,10,10,9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1,
+	1,0,0,-1,-1,-1,-2,-2,-3,-3,-3,-4,-4,-4,-4,-5,-5,-5,-5,-6,-6,-6,-6,-6,-6,-6,-7,-7,
+	-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-6,-6,-6,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-4,-4,-4,
+	-4,-4,-3,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,3,3,3,
+	3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,
+	3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,
+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+	},
+	{
+	131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,
+	131072,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,
+	131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,
+	131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,
+	131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131069,131069,
+	131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,131069,
+	131069,131068,131068,131068,131068,131068,131068,131068,131068,131068,131068,131067,
+	131067,131067,131067,131067,131067,131067,131066,131066,131066,131066,131066,131065,
+	131065,131065,131065,131064,131064,131064,131064,131063,131063,131062,131062,131062,
+	131061,131061,131060,131060,131059,131059,131058,131058,131057,131056,131056,131055,
+	131054,131053,131052,131052,131051,131050,131049,131048,131046,131045,131044,131043,
+	131041,131040,131038,131037,131035,131034,131032,131030,131028,131026,131024,131022,
+	131020,131017,131015,131012,131010,131007,131004,131001,130998,130994,130991,130987,
+	130984,130980,130976,130972,130968,130963,130959,130954,130949,130944,130938,130933,
+	130927,130921,130915,130909,130902,130895,130888,130881,130873,130865,130857,130849,
+	130840,130831,130822,130813,130803,130793,130782,130771,130760,130749,130737,130725,
+	130712,130699,130685,130672,130657,130643,130628,130612,130596,130580,130563,130545,
+	130528,130509,130490,130471,130451,130430,130409,130388,130365,130343,130319,130295,
+	130270,130245,130219,130193,130165,130137,130109,130079,130049,130018,129987,129954,
+	129921,129887,129853,129817,129781,129744,129706,129667,129627,129587,129545,129503,
+	129459,129415,129370,129324,129276,129228,129179,129129,129078,129026,128972,128918,
+	128862,128806,128748,128690,128630,128569,128507,128443,128379,128313,128246,128178,
+	128109,128038,127966,127893,127819,127743,127667,127588,127509,127428,127346,127262,
+	127177,127091,127004,126915,126824,126732,126639,126545,126449,126351,126252,126152,
+	126050,125947,125842,125736,125628,125519,125408,125296,125182,125067,124950,124832,
+	124712,124591,124468,124344,124218,124090,123961,123830,123698,123564,123429,123292,
+	123154,123014,122872,122729,122585,122438,122291,122141,121990,121838,121684,121528,
+	121371,121212,121052,120891,120727,120562,120396,120228,120059,119888,119715,119541,
+	119366,119189,119011,118831,118649,118467,118282,118097,117909,117721,117531,117339,
+	117146,116952,116757,116560,116361,116161,115960,115758,115554,115349,115143,114935,
+	114726,114516,114305,114092,113878,113663,113447,113229,113011,112791,112570,112348,
+	112124,111900,111675,111448,111220,110992,110762,110531,110300,110067,109833,109598,
+	109363,109126,108889,108650,108411,108171,107930,107688,107445,107201,106957,106712,
+	106466,106219,105972,105723,105474,105225,104974,104723,104471,104219,103966,103712,
+	103458,103203,102948,102692,102435,102178,101920,101662,101403,101144,100885,100624,
+	100364,100103,99841,99579,99317,99054,98791,98527,98264,97999,97735,97470,97204,96939,
+	96673,96407,96140,95873,95606,95339,95071,94804,94536,94267,93999,93730,93461,93192,
+	92923,92653,92383,92114,91844,91573,91303,91033,90762,90491,90220,89949,89678,89407,
+	89136,88865,88593,88321,88050,87778,87506,87234,86962,86690,86418,86146,85874,85602,
+	85330,85057,84785,84513,84240,83968,83696,83423,83151,82878,82606,82333,82061,81789,
+	81516,81244,80971,80699,80427,80154,79882,79610,79337,79065,78793,78521,78249,77977,
+	77705,77433,77161,76889,76617,76345,76074,75802,75531,75259,74988,74717,74446,74175,
+	73904,73633,73362,73092,72821,72551,72280,72010,71740,71470,71201,70931,70661,70392,
+	70123,69854,69585,69317,69048,68780,68512,68244,67976,67709,67441,67174,66907,66641,
+	66374,66108,65842,65576,65311,65046,64781,64516,64252,63988,63724,63460,63197,62934,
+	62672,62409,62147,61886,61624,61363,61103,60843,60583,60323,60064,59805,59547,59289,
+	59031,58774,58517,58261,58005,57749,57494,57239,56985,56731,56478,56225,55973,55721,
+	55470,55219,54968,54718,54469,54220,53971,53724,53476,53229,52983,52737,52492,52247,
+	52003,51759,51516,51274,51032,50791,50550,50310,50070,49831,49593,49355,49118,48881,
+	48645,48410,48175,47941,47707,47474,47242,47010,46779,46549,46319,46090,45861,45633,
+	45406,45179,44953,44728,44503,44279,44056,43833,43611,43389,43168,42948,42728,42510,
+	42291,42074,41857,41640,41425,41210,40995,40782,40568,40356,40144,39933,39723,39513,
+	39304,39095,38887,38680,38473,38267,38062,37857,37653,37449,37247,37044,36843,36642,
+	36442,36242,36043,35845,35647,35450,35253,35057,34862,34667,34473,34280,34087,33894,
+	33703,33512,33321,33132,32942,32754,32566,32378,32192,32006,31820,31635,31451,31267,
+	31084,30901,30719,30538,30357,30177,29997,29818,29640,29462,29285,29108,28932,28756,
+	28581,28407,28233,28060,27888,27716,27545,27374,27204,27034,26865,26697,26529,26362,
+	26195,26029,25863,25699,25534,25371,25207,25045,24883,24722,24561,24401,24241,24082,
+	23924,23766,23609,23453,23297,23142,22987,22833,22679,22526,22374,22222,22071,21921,
+	21771,21622,21473,21325,21177,21031,20884,20739,20594,20449,20306,20162,20020,19878,
+	19737,19596,19456,19316,19178,19039,18902,18765,18628,18493,18358,18223,18089,17956,
+	17823,17691,17560,17429,17299,17169,17040,16912,16784,16657,16531,16405,16280,16155,
+	16031,15908,15785,15663,15541,15420,15300,15180,15061,14942,14824,14707,14590,14474,
+	14358,14243,14129,14015,13901,13789,13677,13565,13454,13344,13234,13125,13016,12908,
+	12801,12694,12588,12482,12377,12272,12168,12064,11961,11859,11757,11655,11554,11454,
+	11354,11255,11156,11058,10960,10863,10766,10670,10575,10480,10385,10291,10197,10104,
+	10012,9920,9828,9737,9646,9556,9466,9377,9289,9200,9113,9025,8939,8852,8766,8681,
+	8596,8512,8428,8344,8261,8178,8096,8014,7933,7852,7772,7692,7612,7533,7455,7376,
+	7299,7221,7144,7068,6992,6916,6841,6766,6692,6618,6544,6471,6398,6326,6254,6182,
+	6111,6041,5970,5901,5831,5762,5693,5625,5557,5490,5423,5356,5290,5224,5159,5093,
+	5029,4965,4901,4837,4774,4711,4649,4587,4525,4464,4404,4343,4283,4224,4164,4105,
+	4047,3989,3931,3874,3817,3760,3704,3648,3593,3538,3483,3429,3375,3321,3268,3215,
+	3163,3111,3059,3008,2957,2906,2856,2806,2756,2707,2658,2610,2562,2514,2466,2419,
+	2373,2326,2280,2235,2189,2144,2100,2056,2012,1968,1925,1882,1839,1797,1755,1714,
+	1672,1631,1591,1551,1511,1471,1432,1393,1354,1316,1278,1240,1203,1165,1129,1092,
+	1056,1020,984,949,914,879,845,811,777,743,710,677,644,612,580,548,516,485,454,423,
+	393,362,332,303,273,244,215,186,158,129,101,74,46,19,-8,-35,-61,-88,-114,-140,-165,
+	-191,-216,-241,-265,-290,-314,-338,-362,-386,-409,-432,-455,-478,-501,-523,-545,
+	-567,-589,-610,-632,-653,-674,-694,-715,-735,-756,-775,-795,-815,-834,-853,-872,
+	-891,-910,-928,-947,-965,-983,-1000,-1018,-1035,-1052,-1069,-1086,-1103,-1119,-1136,
+	-1152,-1168,-1184,-1199,-1215,-1230,-1245,-1260,-1275,-1289,-1304,-1318,-1332,-1346,
+	-1360,-1373,-1387,-1400,-1413,-1426,-1439,-1452,-1464,-1477,-1489,-1501,-1513,-1524,
+	-1536,-1547,-1558,-1570,-1581,-1591,-1602,-1612,-1623,-1633,-1643,-1653,-1663,-1672,
+	-1682,-1691,-1700,-1709,-1718,-1727,-1735,-1744,-1752,-1760,-1768,-1776,-1784,-1792,
+	-1799,-1807,-1814,-1821,-1828,-1835,-1842,-1848,-1855,-1861,-1867,-1873,-1879,-1885,
+	-1891,-1896,-1902,-1907,-1913,-1918,-1923,-1928,-1932,-1937,-1942,-1946,-1950,-1955,
+	-1959,-1963,-1967,-1971,-1974,-1978,-1981,-1985,-1988,-1991,-1994,-1997,-2000,-2003,
+	-2006,-2009,-2011,-2013,-2016,-2018,-2020,-2022,-2024,-2026,-2028,-2030,-2032,-2033,
+	-2035,-2036,-2037,-2039,-2040,-2041,-2042,-2043,-2044,-2045,-2045,-2046,-2047,-2047,
+	-2048,-2048,-2048,-2049,-2049,-2049,-2049,-2049,-2049,-2049,-2049,-2048,-2048,-2048,
+	-2047,-2047,-2046,-2046,-2045,-2044,-2043,-2043,-2042,-2041,-2040,-2039,-2038,-2036,
+	-2035,-2034,-2033,-2031,-2030,-2028,-2027,-2025,-2024,-2022,-2020,-2019,-2017,-2015,
+	-2013,-2011,-2009,-2007,-2005,-2003,-2001,-1998,-1996,-1994,-1992,-1989,-1987,-1984,
+	-1982,-1979,-1977,-1974,-1971,-1969,-1966,-1963,-1960,-1957,-1954,-1952,-1949,-1946,
+	-1942,-1939,-1936,-1933,-1930,-1927,-1923,-1920,-1917,-1913,-1910,-1906,-1903,-1899,
+	-1896,-1892,-1889,-1885,-1881,-1878,-1874,-1870,-1866,-1863,-1859,-1855,-1851,-1847,
+	-1843,-1839,-1835,-1831,-1827,-1823,-1819,-1814,-1810,-1806,-1802,-1798,-1793,-1789,
+	-1785,-1780,-1776,-1771,-1767,-1763,-1758,-1754,-1749,-1745,-1740,-1736,-1731,-1726,
+	-1722,-1717,-1713,-1708,-1703,-1698,-1694,-1689,-1684,-1680,-1675,-1670,-1665,-1660,
+	-1656,-1651,-1646,-1641,-1636,-1631,-1626,-1622,-1617,-1612,-1607,-1602,-1597,-1592,
+	-1587,-1582,-1577,-1572,-1567,-1562,-1557,-1552,-1547,-1542,-1537,-1532,-1527,-1522,
+	-1517,-1512,-1507,-1502,-1497,-1492,-1487,-1482,-1477,-1471,-1466,-1461,-1456,-1451,
+	-1446,-1441,-1436,-1431,-1426,-1421,-1416,-1411,-1406,-1401,-1395,-1390,-1385,-1380,
+	-1375,-1370,-1365,-1360,-1355,-1350,-1345,-1340,-1335,-1330,-1325,-1320,-1315,-1310,
+	-1305,-1300,-1295,-1290,-1285,-1280,-1275,-1270,-1265,-1260,-1255,-1250,-1245,-1240,
+	-1235,-1230,-1225,-1220,-1215,-1210,-1205,-1200,-1195,-1190,-1185,-1180,-1175,-1171,
+	-1166,-1161,-1156,-1151,-1146,-1141,-1136,-1131,-1127,-1122,-1117,-1112,-1107,-1102,
+	-1098,-1093,-1088,-1083,-1078,-1074,-1069,-1064,-1059,-1055,-1050,-1045,-1040,-1036,
+	-1031,-1026,-1022,-1017,-1012,-1007,-1003,-998,-994,-989,-984,-980,-975,-970,-966,
+	-961,-957,-952,-948,-943,-938,-934,-929,-925,-920,-916,-911,-907,-902,-898,-894,
+	-889,-885,-880,-876,-872,-867,-863,-858,-854,-850,-845,-841,-837,-833,-828,-824,
+	-820,-816,-811,-807,-803,-799,-795,-790,-786,-782,-778,-774,-770,-766,-762,-757,
+	-753,-749,-745,-741,-737,-733,-729,-725,-721,-717,-714,-710,-706,-702,-698,-694,
+	-690,-686,-683,-679,-675,-671,-667,-664,-660,-656,-652,-649,-645,-641,-638,-634,
+	-630,-627,-623,-620,-616,-612,-609,-605,-602,-598,-595,-591,-588,-584,-581,-577,
+	-574,-571,-567,-564,-560,-557,-554,-550,-547,-544,-540,-537,-534,-530,-527,-524,
+	-521,-518,-514,-511,-508,-505,-502,-499,-495,-492,-489,-486,-483,-480,-477,-474,
+	-471,-468,-465,-462,-459,-456,-453,-450,-447,-444,-441,-438,-435,-433,-430,-427,
+	-424,-421,-418,-416,-413,-410,-407,-405,-402,-399,-396,-394,-391,-388,-386,-383,
+	-380,-378,-375,-373,-370,-367,-365,-362,-360,-357,-355,-352,-350,-347,-345,-342,
+	-340,-337,-335,-333,-330,-328,-325,-323,-321,-318,-316,-314,-311,-309,-307,-305,
+	-302,-300,-298,-296,-293,-291,-289,-287,-285,-282,-280,-278,-276,-274,-272,-270,
+	-268,-266,-264,-261,-259,-257,-255,-253,-251,-249,-247,-246,-244,-242,-240,-238,
+	-236,-234,-232,-230,-228,-227,-225,-223,-221,-219,-217,-216,-214,-212,-210,-209,
+	-207,-205,-203,-202,-200,-198,-197,-195,-193,-192,-190,-188,-187,-185,-184,-182,
+	-180,-179,-177,-176,-174,-173,-171,-170,-168,-167,-165,-164,-162,-161,-159,-158,
+	-156,-155,-154,-152,-151,-149,-148,-147,-145,-144,-143,-141,-140,-139,-137,-136,
+	-135,-133,-132,-131,-130,-128,-127,-126,-125,-123,-122,-121,-120,-119,-117,-116,
+	-115,-114,-113,-112,-111,-109,-108,-107,-106,-105,-104,-103,-102,-101,-100,-99,-98,
+	-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-84,-83,-82,-81,-80,-79,-78,
+	-78,-77,-76,-75,-74,-73,-72,-71,-71,-70,-69,-68,-67,-67,-66,-65,-64,-63,-63,-62,
+	-61,-60,-60,-59,-58,-58,-57,-56,-55,-55,-54,-53,-53,-52,-51,-51,-50,-49,-49,-48,
+	-47,-47,-46,-45,-45,-44,-44,-43,-42,-42,-41,-41,-40,-40,-39,-38,-38,-37,-37,-36,
+	-36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-28,-28,-28,-27,-27,
+	-26,-26,-25,-25,-25,-24,-24,-23,-23,-23,-22,-22,-21,-21,-21,-20,-20,-20,-19,-19,
+	-19,-18,-18,-17,-17,-17,-17,-16,-16,-16,-15,-15,-15,-14,-14,-14,-13,-13,-13,-13,
+	-12,-12,-12,-12,-11,-11,-11,-11,-10,-10,-10,-10,-9,-9,-9,-9,-9,-8,-8,-8,-8,-7,-7,
+	-7,-7,-7,-7,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,-4,-4,-3,-3,-3,-3,
+	-3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+	-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+	}
+};
+
+
+State::State(uint32 sampleRate)
+{
+	double amigaClocksPerSample = static_cast<double>(PAULA_HZ) / sampleRate;
+	numSteps = static_cast<int>(amigaClocksPerSample / MINIMUM_INTERVAL);
+	stepRemainder = SamplePosition::FromDouble(amigaClocksPerSample - numSteps * MINIMUM_INTERVAL);
+	remainder = SamplePosition(0);
+	activeBleps = 0;
+	globalOutputLevel = 0;
+}
+
+
+void State::Reset()
+{
+	remainder = SamplePosition(0);
+	activeBleps = 0;
+	globalOutputLevel = 0;
+}
+
+
+void State::InputSample(int16 sample)
+{
+	if(sample != globalOutputLevel)
+	{
+		LimitMax(activeBleps, static_cast<uint16>(mpt::size(blepState) - 1));
+
+		// Make room for new blep in the sorted list
+		std::move_backward(blepState, blepState + activeBleps, blepState + activeBleps + 1);
+
+		// Start a new blep: level is the difference, age (or phase) is 0 clocks.
+		activeBleps++;
+		blepState[0].age = 0;
+		blepState[0].level = sample - globalOutputLevel;
+		globalOutputLevel = sample;
+	}
+}
+
+
+// Return output simulated as series of bleps
+int State::OutputSample(bool filter)
+{
+	int output = globalOutputLevel * (1 << Paula::BLEP_SCALE);
+	for(uint16 i = 0; i < activeBleps; i++)
+	{
+		const auto &blep = blepState[i];
+		output -= WinSincIntegral[filter][blep.age] * blep.level;
+	}
+	output /= (1 << (Paula::BLEP_SCALE - 2));	// - 2 to compensate for the fact that we reduced the input sample bit depth
+
+	return output;
+}
+
+
+// Advance the simulation by given number of clock ticks
+void State::Clock(int cycles)
+{
+	for(uint16 i = 0; i < activeBleps; i++)
+	{
+		blepState[i].age += static_cast<uint16>(cycles);
+		if(blepState[i].age >= mpt::size(WinSincIntegral[0]))
+		{
+			activeBleps = i;
+			return;
+		}
+	}
+}
+
+}
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/Paula.h b/soundlib/Paula.h
new file mode 100644
index 0000000..360c1ca
--- /dev/null
+++ b/soundlib/Paula.h
@@ -0,0 +1,53 @@
+/*
+* Paula.h
+* -------
+* Purpose: Emulating the Amiga's sound chip, Paula, by implementing resampling using band-limited steps (BLEPs)
+* Notes  : (currently none)
+* Authors: OpenMPT Devs
+*          Antti S. Lankila
+* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+*/
+
+#pragma once
+
+#include "Snd_defs.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+namespace Paula
+{
+
+const int PAULA_HZ = 3546895;
+const int MINIMUM_INTERVAL = 16;
+const int BLEP_SCALE = 17;
+const int BLEP_SIZE = 2048;
+const int MAX_BLEPS = (BLEP_SIZE / MINIMUM_INTERVAL);
+
+class State
+{
+	struct Blep
+	{
+		int16 level;
+		uint16 age;
+	};
+
+public:
+	SamplePosition remainder, stepRemainder;
+	int numSteps;				// Number of full-length steps
+private:
+	uint16 activeBleps;			// Count of simultaneous bleps to keep track of
+	int16 globalOutputLevel;	// The instantenous value of Paula output
+	Blep blepState[MAX_BLEPS];
+
+public:
+	State(uint32 sampleRate = 48000);
+
+	void Reset();
+	void InputSample(int16 sample);
+	int OutputSample(bool filter);
+	void Clock(int cycles);
+};
+
+}
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/Resampler.h b/soundlib/Resampler.h
index 14afb79..0f470bc 100644
--- a/soundlib/Resampler.h
+++ b/soundlib/Resampler.h
@@ -51,32 +51,30 @@ typedef mixsample_t SINC_TYPE;
 STATIC_ASSERT((SINC_MASK & 0xffff) == SINC_MASK); // exceeding fractional freq
 
 
-//======================
 class CResamplerSettings
-//======================
 {
 public:
 	ResamplingMode SrcMode;
 	double gdWFIRCutoff;
 	uint8 gbWFIRType;
+	bool emulateAmiga;
 public:
 	CResamplerSettings()
 	{
 		SrcMode = SRCMODE_POLYPHASE;
 		gdWFIRCutoff = 0.97;
 		gbWFIRType = WFIR_KAISER4T;
+		emulateAmiga = false;
 	}
 	bool operator == (const CResamplerSettings &cmp) const
 	{
-		return SrcMode == cmp.SrcMode && gdWFIRCutoff == cmp.gdWFIRCutoff && gbWFIRType == cmp.gbWFIRType;
+		return SrcMode == cmp.SrcMode && gdWFIRCutoff == cmp.gdWFIRCutoff && gbWFIRType == cmp.gbWFIRType && emulateAmiga == cmp.emulateAmiga;
 	}
 	bool operator != (const CResamplerSettings &cmp) const { return !(*this == cmp); }
 };
 
 
-//==============
 class CResampler
-//==============
 {
 public:
 	CResamplerSettings m_Settings;
diff --git a/soundlib/RowVisitor.cpp b/soundlib/RowVisitor.cpp
index 0e4d396..121dd21 100644
--- a/soundlib/RowVisitor.cpp
+++ b/soundlib/RowVisitor.cpp
@@ -27,44 +27,49 @@
 OPENMPT_NAMESPACE_BEGIN
 
 RowVisitor::RowVisitor(const CSoundFile &sf, SEQUENCEINDEX sequence)
-	: sndFile(sf)
-	, currentOrder(0)
+	: m_sndFile(sf)
+	, m_currentOrder(0)
+	, m_sequence(sequence)
 {
-	if(sequence < sndFile.Order.GetNumSequences())
-		Order = &sndFile.Order.GetSequence(sequence);
-	else
-		Order = &sndFile.Order;
 	Initialize(true);
 }
 
 
+const ModSequence &RowVisitor::Order() const
+{
+	if(m_sequence >= m_sndFile.Order.GetNumSequences())
+		return m_sndFile.Order();
+	else
+		return m_sndFile.Order(m_sequence);
+}
+
 
 // Resize / Clear the row vector.
 // If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset).
 void RowVisitor::Initialize(bool reset)
-//-------------------------------------
 {
-	const ORDERINDEX endOrder = Order->GetLengthTailTrimmed();
-	visitedRows.resize(endOrder);
+	auto &order = Order();
+	const ORDERINDEX endOrder = order.GetLengthTailTrimmed();
+	m_visitedRows.resize(endOrder);
 	if(reset)
 	{
-		visitOrder.clear();
+		m_visitOrder.clear();
 		// Pre-allocate maximum amount of memory most likely needed for keeping track of visited rows in a pattern
-		if(visitOrder.capacity() < MAX_PATTERN_ROWS)
+		if(m_visitOrder.capacity() < MAX_PATTERN_ROWS)
 		{
 			ROWINDEX maxRows = 0;
-			for(PATTERNINDEX pat = 0; pat < sndFile.Patterns.Size(); pat++)
+			for(PATTERNINDEX pat = 0; pat < m_sndFile.Patterns.Size(); pat++)
 			{
-				maxRows = std::max(maxRows, sndFile.Patterns[pat].GetNumRows());
+				maxRows = std::max(maxRows, m_sndFile.Patterns[pat].GetNumRows());
 			}
-			visitOrder.reserve(maxRows);
+			m_visitOrder.reserve(maxRows);
 		}
 	}
 
-	for(ORDERINDEX order = 0; order < endOrder; order++)
+	for(ORDERINDEX ord = 0; ord < endOrder; ord++)
 	{
-		VisitedRowsBaseType &row = visitedRows[order];
-		const size_t size = GetVisitedRowsVectorSize(Order->At(order));
+		auto &row = m_visitedRows[ord];
+		const size_t size = GetVisitedRowsVectorSize(order[ord]);
 		if(reset)
 		{
 			// If we want to reset the vectors completely, we overwrite existing items with false.
@@ -80,25 +85,29 @@ void RowVisitor::Initialize(bool reset)
 // (Un)sets a given row as visited.
 // order, row - which row should be (un)set
 // If visited is true, the row will be set as visited.
-void RowVisitor::SetVisited(ORDERINDEX order, ROWINDEX row, bool visited)
-//-----------------------------------------------------------------------
+void RowVisitor::SetVisited(ORDERINDEX ord, ROWINDEX row, bool visited)
 {
-	const ORDERINDEX endOrder = Order->GetLengthTailTrimmed();
-	if(order >= endOrder || row >= GetVisitedRowsVectorSize(Order->At(order)))
+	auto &order = Order();
+	if(ord >= order.size() || row >= GetVisitedRowsVectorSize(order[ord]))
 	{
 		return;
 	}
 
 	// The module might have been edited in the meantime - so we have to extend this a bit.
-	if(order >= visitedRows.size() || row >= visitedRows[order].size())
+	if(ord >= m_visitedRows.size() || row >= m_visitedRows[ord].size())
 	{
 		Initialize(false);
+		// If it's still past the end of the vector, this means that ord >= order.GetLengthTailTrimmed(), i.e. we are trying to play an empty order.
+		if(ord >= m_visitedRows.size())
+		{
+			return;
+		}
 	}
 
-	visitedRows[order][row] = visited;
+	m_visitedRows[ord][row] = visited;
 	if(visited)
 	{
-		AddVisitedRow(order, row);
+		AddVisitedRow(ord, row);
 	}
 }
 
@@ -106,33 +115,31 @@ void RowVisitor::SetVisited(ORDERINDEX order, ROWINDEX row, bool visited)
 // Returns whether a given row has been visited yet.
 // If autoSet is true, the queried row will automatically be marked as visited.
 // Use this parameter instead of consecutive IsRowVisited / SetRowVisited calls.
-bool RowVisitor::IsVisited(ORDERINDEX order, ROWINDEX row, bool autoSet)
-//----------------------------------------------------------------------
+bool RowVisitor::IsVisited(ORDERINDEX ord, ROWINDEX row, bool autoSet)
 {
-	const ORDERINDEX endOrder = Order->GetLengthTailTrimmed();
-	if(order >= endOrder)
+	if(ord >= Order().size())
 	{
 		return false;
 	}
 
 	// The row slot for this row has not been assigned yet - Just return false, as this means that the program has not played the row yet.
-	if(order >= visitedRows.size() || row >= visitedRows[order].size())
+	if(ord >= m_visitedRows.size() || row >= m_visitedRows[ord].size())
 	{
 		if(autoSet)
 		{
-			SetVisited(order, row, true);
+			SetVisited(ord, row, true);
 		}
 		return false;
 	}
 
-	if(visitedRows[order][row])
+	if(m_visitedRows[ord][row])
 	{
 		// We visited this row already - this module must be looping.
 		return true;
 	} else if(autoSet)
 	{
-		visitedRows[order][row] = true;
-		AddVisitedRow(order, row);
+		m_visitedRows[ord][row] = true;
+		AddVisitedRow(ord, row);
 	}
 
 	return false;
@@ -141,11 +148,10 @@ bool RowVisitor::IsVisited(ORDERINDEX order, ROWINDEX row, bool autoSet)
 
 // Get the needed vector size for pattern nPat.
 size_t RowVisitor::GetVisitedRowsVectorSize(PATTERNINDEX pattern) const
-//---------------------------------------------------------------------
 {
-	if(sndFile.Patterns.IsValidPat(pattern))
+	if(m_sndFile.Patterns.IsValidPat(pattern))
 	{
-		return static_cast<size_t>(sndFile.Patterns[pattern].GetNumRows());
+		return static_cast<size_t>(m_sndFile.Patterns[pattern].GetNumRows());
 	} else
 	{
 		// Invalid patterns consist of a "fake" row.
@@ -158,28 +164,28 @@ size_t RowVisitor::GetVisitedRowsVectorSize(PATTERNINDEX pattern) const
 // The order and row is stored in the order and row variables on success, on failure they contain invalid values.
 // If fastSearch is true (default), only the first row of each pattern is looked at, otherwise every row is examined.
 // Function returns true on success.
-bool RowVisitor::GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fastSearch) const
-//--------------------------------------------------------------------------------------------
+bool RowVisitor::GetFirstUnvisitedRow(ORDERINDEX &ord, ROWINDEX &row, bool fastSearch) const
 {
-	const ORDERINDEX endOrder = Order->GetLengthTailTrimmed();
-	for(order = 0; order < endOrder; order++)
+	auto &order = Order();
+	const ORDERINDEX endOrder = order.GetLengthTailTrimmed();
+	for(ord = 0; ord < endOrder; ord++)
 	{
-		const PATTERNINDEX pattern = Order->At(order);
-		if(!sndFile.Patterns.IsValidPat(pattern))
+		const PATTERNINDEX pattern = order[ord];
+		if(!m_sndFile.Patterns.IsValidPat(pattern))
 		{
 			continue;
 		}
 
-		if(order >= visitedRows.size())
+		if(ord >= m_visitedRows.size())
 		{
 			// Not yet initialized => unvisited
 			return true;
 		}
 
-		const ROWINDEX endRow = (fastSearch ? 1 : sndFile.Patterns[pattern].GetNumRows());
+		const ROWINDEX endRow = (fastSearch ? 1 : m_sndFile.Patterns[pattern].GetNumRows());
 		for(row = 0; row < endRow; row++)
 		{
-			if(row >= visitedRows[order].size() || visitedRows[order][row] == false)
+			if(row >= m_visitedRows[ord].size() || m_visitedRows[ord][row] == false)
 			{
 				// Not yet initialized, or unvisited
 				return true;
@@ -188,45 +194,42 @@ bool RowVisitor::GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fas
 	}
 
 	// Didn't find anything :(
-	order = ORDERINDEX_INVALID;
+	ord = ORDERINDEX_INVALID;
 	row = ROWINDEX_INVALID;
 	return false;
 }
 
 
 // Set all rows of a previous pattern loop as unvisited.
-void RowVisitor::ResetPatternLoop(ORDERINDEX order, ROWINDEX startRow)
-//--------------------------------------------------------------------
+void RowVisitor::ResetPatternLoop(ORDERINDEX ord, ROWINDEX startRow)
 {
-	MPT_ASSERT(order == currentOrder);	// Shouldn't trigger, unless we're jumping around in the GUI during a pattern loop.
-	
+	MPT_ASSERT(ord == m_currentOrder);	// Shouldn't trigger, unless we're jumping around in the GUI during a pattern loop.
+
 	// Unvisit all rows that are in the visited row buffer, until we hit the start row for this pattern loop.
 	ROWINDEX row = ROWINDEX_INVALID;
-	std::vector<ROWINDEX>::reverse_iterator iter = visitOrder.rbegin();
-	while(iter != visitOrder.rend() && row != startRow)
+	for(auto iter = m_visitOrder.crbegin(); iter != m_visitOrder.crend() && row != startRow; iter++)
 	{
-		row = *(iter++);
-		Unvisit(order, row);
+		row = *iter;
+		Unvisit(ord, row);
 	}
 }
 
 
 // Add a row to the visited row memory for this pattern.
-void RowVisitor::AddVisitedRow(ORDERINDEX order, ROWINDEX row)
-//------------------------------------------------------------
+void RowVisitor::AddVisitedRow(ORDERINDEX ord, ROWINDEX row)
 {
-	if(order != currentOrder)
+	if(ord != m_currentOrder)
 	{
 		// We're in a new pattern! Forget about which rows we previously visited...
-		visitOrder.clear();
-		currentOrder = order;
+		m_visitOrder.clear();
+		m_currentOrder = ord;
 	}
-	if(visitOrder.empty())
+	if(m_visitOrder.empty())
 	{
-		visitOrder.reserve(GetVisitedRowsVectorSize(Order->At(order)));
+		m_visitOrder.reserve(GetVisitedRowsVectorSize(Order()[ord]));
 	}
 	// And now add the played row to our memory.
-	visitOrder.push_back(row);
+	m_visitOrder.push_back(row);
 }
 
 
diff --git a/soundlib/RowVisitor.h b/soundlib/RowVisitor.h
index f9d0885..3eb8518 100644
--- a/soundlib/RowVisitor.h
+++ b/soundlib/RowVisitor.h
@@ -18,51 +18,41 @@ OPENMPT_NAMESPACE_BEGIN
 class CSoundFile;
 class ModSequence;
 
-//==============
 class RowVisitor
-//==============
 {
 protected:
-
-	// Data type for the visited rows.
-	typedef std::vector<bool> VisitedRowsBaseType;
-	typedef std::vector<VisitedRowsBaseType> VisitedRowsType;
-
-	const CSoundFile &sndFile;
-	const ModSequence *Order;
-
 	// Memory for every row in the module if it has been visited or not.
-	VisitedRowsType visitedRows;
+	std::vector<std::vector<bool>> m_visitedRows;
 	// Memory of visited rows (including their order) to reset pattern loops.
-	std::vector<ROWINDEX> visitOrder;
-	ORDERINDEX currentOrder;
+	std::vector<ROWINDEX> m_visitOrder;
 
-public:
+	const CSoundFile &m_sndFile;
+	ORDERINDEX m_currentOrder;
+	SEQUENCEINDEX m_sequence;
 
+public:
 	RowVisitor(const CSoundFile &sf, SEQUENCEINDEX sequence = SEQUENCEINDEX_INVALID);
 
-	RowVisitor(const RowVisitor &other) : sndFile(other.sndFile), Order(other.Order), visitedRows(other.visitedRows), visitOrder(other.visitOrder), currentOrder(other.currentOrder) { };
-
 	// Resize / Clear the row vector.
 	// If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset).
 	void Initialize(bool reset);
 
 	// Mark a row as visited.
-	void Visit(ORDERINDEX order, ROWINDEX row)
+	void Visit(ORDERINDEX ord, ROWINDEX row)
 	{
-		SetVisited(order, row, true);
+		SetVisited(ord, row, true);
 	};
 
 	// Mark a row as not visited.
-	void Unvisit(ORDERINDEX order, ROWINDEX row)
+	void Unvisit(ORDERINDEX ord, ROWINDEX row)
 	{
-		SetVisited(order, row, false);
+		SetVisited(ord, row, false);
 	};
 
 	// Returns whether a given row has been visited yet.
 	// If autoSet is true, the queried row will automatically be marked as visited.
 	// Use this parameter instead of consecutive IsRowVisited / SetRowVisited calls.
-	bool IsVisited(ORDERINDEX order, ROWINDEX row, bool autoSet);
+	bool IsVisited(ORDERINDEX ord, ROWINDEX row, bool autoSet);
 
 	// Get the needed vector size for a given pattern.
 	size_t GetVisitedRowsVectorSize(PATTERNINDEX pattern) const;
@@ -76,22 +66,23 @@ public:
 	// Retrieve visited rows vector from another RowVisitor object.
 	void Set(const RowVisitor &other)
 	{
-		visitedRows = other.visitedRows;
+		m_visitedRows = other.m_visitedRows;
 	}
 
 	// Set all rows of a previous pattern loop as unvisited.
-	void ResetPatternLoop(ORDERINDEX order, ROWINDEX startRow);
+	void ResetPatternLoop(ORDERINDEX ord, ROWINDEX startRow);
 
 protected:
 
 	// (Un)sets a given row as visited.
 	// order, row - which row should be (un)set
 	// If visited is true, the row will be set as visited.
-	void SetVisited(ORDERINDEX order, ROWINDEX row, bool visited);
+	void SetVisited(ORDERINDEX ord, ROWINDEX row, bool visited);
 
 	// Add a row to the visited row memory for this pattern.
-	void AddVisitedRow(ORDERINDEX order, ROWINDEX row);
+	void AddVisitedRow(ORDERINDEX ord, ROWINDEX row);
 
+	const ModSequence &Order() const;
 };
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/S3MTools.cpp b/soundlib/S3MTools.cpp
index 0413dbc..4d2d987 100644
--- a/soundlib/S3MTools.cpp
+++ b/soundlib/S3MTools.cpp
@@ -17,33 +17,8 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void S3MFileHeader::ConvertEndianness()
-//-------------------------------------
-{
-	SwapBytesLE(ordNum);
-	SwapBytesLE(smpNum);
-	SwapBytesLE(patNum);
-	SwapBytesLE(flags);
-	SwapBytesLE(cwtv);
-	SwapBytesLE(formatVersion);
-}
-
-
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void S3MSampleHeader::ConvertEndianness()
-//---------------------------------------
-{
-	SwapBytesLE(length);
-	SwapBytesLE(loopStart);
-	SwapBytesLE(loopEnd);
-	SwapBytesLE(c5speed);
-}
-
-
 // Convert an S3M sample header to OpenMPT's internal sample header.
 void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const
-//---------------------------------------------------------
 {
 	mptSmp.Initialize(MOD_TYPE_S3M);
 	mpt::String::Read<mpt::String::maybeNullTerminated>(mptSmp.filename, filename);
@@ -83,7 +58,6 @@ void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const
 
 // Convert OpenMPT's internal sample header to an S3M sample header.
 SmpLength S3MSampleHeader::ConvertToS3M(const ModSample &mptSmp)
-//--------------------------------------------------------------
 {
 	SmpLength smpLength = 0;
 	mpt::String::Write<mpt::String::maybeNullTerminated>(filename, mptSmp.filename);
@@ -127,7 +101,6 @@ SmpLength S3MSampleHeader::ConvertToS3M(const ModSample &mptSmp)
 
 // Retrieve the internal sample format flags for this sample.
 SampleIO S3MSampleHeader::GetSampleFormat(bool signedSamples) const
-//-----------------------------------------------------------------
 {
 	if(pack == S3MSampleHeader::pADPCM && !(flags & S3MSampleHeader::smp16Bit) && !(flags & S3MSampleHeader::smpStereo))
 	{
diff --git a/soundlib/S3MTools.h b/soundlib/S3MTools.h
index d3f3ce0..d9dfa88 100644
--- a/soundlib/S3MTools.h
+++ b/soundlib/S3MTools.h
@@ -16,13 +16,8 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // S3M File Header
-struct PACKED S3MFileHeader
+struct S3MFileHeader
 {
 	// Magic Bytes
 	enum S3MMagic
@@ -67,36 +62,33 @@ struct PACKED S3MFileHeader
 		newVersion			= 0x02,	// New Version, unsigned samples
 	};
 
-	char   name[28];		// Song Title
-	uint8  dosEof;			// Supposed to be 0x1A, but even ST3 seems to ignore this sometimes (see STRSHINE.S3M by Purple Motion)
-	uint8  fileType;		// File Type, 0x10 = ST3 module
-	char   reserved1[2];	// Reserved
-	uint16 ordNum;			// Number of order items
-	uint16 smpNum;			// Number of sample parapointers
-	uint16 patNum;			// Number of pattern parapointers
-	uint16 flags;			// Flags, see S3MHeaderFlags
-	uint16 cwtv;			// "Made With" Tracker ID, see S3MTrackerVersions
-	uint16 formatVersion;	// Format Version, see S3MFormatVersion
-	char   magic[4];		// "SCRM" magic bytes
-	uint8  globalVol;		// Default Global Volume (0...64)
-	uint8  speed;			// Default Speed (1...254)
-	uint8  tempo;			// Default Tempo (33...255)
-	uint8  masterVolume;	// Sample Volume (0...127, stereo if high bit is set)
-	uint8  ultraClicks;		// Number of channels used for ultra click removal
-	uint8  usePanningTable;	// 0xFC => read extended panning table
-	char   reserved2[8];	// More reserved bytes
-	uint16 special;			// Pointer to special custom data (unused)
-	uint8  channels[32];	// Channel setup
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	char     name[28];			// Song Title
+	uint8le  dosEof;			// Supposed to be 0x1A, but even ST3 seems to ignore this sometimes (see STRSHINE.S3M by Purple Motion)
+	uint8le  fileType;			// File Type, 0x10 = ST3 module
+	char     reserved1[2];		// Reserved
+	uint16le ordNum;			// Number of order items
+	uint16le smpNum;			// Number of sample parapointers
+	uint16le patNum;			// Number of pattern parapointers
+	uint16le flags;				// Flags, see S3MHeaderFlags
+	uint16le cwtv;				// "Made With" Tracker ID, see S3MTrackerVersions
+	uint16le formatVersion;		// Format Version, see S3MFormatVersion
+	char     magic[4];			// "SCRM" magic bytes
+	uint8le  globalVol;			// Default Global Volume (0...64)
+	uint8le  speed;				// Default Speed (1...254)
+	uint8le  tempo;				// Default Tempo (33...255)
+	uint8le  masterVolume;		// Sample Volume (0...127, stereo if high bit is set)
+	uint8le  ultraClicks;		// Number of channels used for ultra click removal
+	uint8le  usePanningTable;	// 0xFC => read extended panning table
+	char     reserved2[8];		// More reserved bytes
+	uint16le special;			// Pointer to special custom data (unused)
+	uint8le  channels[32];		// Channel setup
 };
 
-STATIC_ASSERT(sizeof(S3MFileHeader) == 96);
+MPT_BINARY_STRUCT(S3MFileHeader, 96)
 
 
 // S3M Sample Header
-struct PACKED S3MSampleHeader
+struct S3MSampleHeader
 {
 	enum SampleType
 	{
@@ -119,23 +111,21 @@ struct PACKED S3MSampleHeader
 		pADPCM		= 0x04,	// MODPlugin ADPCM :(
 	};
 
-	uint8  sampleType;			// Sample type, see SampleType
-	char   filename[12];		// Sample filename
-	uint8  dataPointer[3];		// Pointer to sample data (divided by 16)
-	uint32 length;				// Sample length, in samples
-	uint32 loopStart;			// Loop start, in samples
-	uint32 loopEnd;				// Loop end, in samples
-	uint8  defaultVolume;		// Default volume (0...64)
-	char   reserved1;			// Reserved
-	uint8  pack;				// Packing algorithm, SamplePacking
-	uint8  flags;				// Sample flags
-	uint32 c5speed;				// Middle-C frequency
-	char   reserved2[12];		// Reserved + Internal ST3 stuff
-	char   name[28];			// Sample name
-	char   magic[4];			// "SCRS" magic bytes ("SCRI" for Adlib instruments)
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	uint8le  sampleType;		// Sample type, see SampleType
+	char     filename[12];		// Sample filename
+	uint8le  dataPointer[3];	// Pointer to sample data (divided by 16)
+	uint32le length;			// Sample length, in samples
+	uint32le loopStart;			// Loop start, in samples
+	uint32le loopEnd;			// Loop end, in samples
+	uint8le  defaultVolume;		// Default volume (0...64)
+	char     reserved1;			// Reserved
+	uint8le  pack;				// Packing algorithm, SamplePacking
+	uint8le  flags;				// Sample flags
+	uint32le c5speed;			// Middle-C frequency
+	char     reserved2[12];		// Reserved + Internal ST3 stuff
+	char     name[28];			// Sample name
+	char     magic[4];			// "SCRS" magic bytes ("SCRI" for Adlib instruments)
+
 	// Convert an S3M sample header to OpenMPT's internal sample header.
 	void ConvertToMPT(ModSample &mptSmp) const;
 	// Convert OpenMPT's internal sample header to an S3M sample header.
@@ -144,12 +134,7 @@ struct PACKED S3MSampleHeader
 	SampleIO GetSampleFormat(bool signedSamples) const;
 };
 
-STATIC_ASSERT(sizeof(S3MSampleHeader) == 80);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(S3MSampleHeader, 80)
 
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormat.h b/soundlib/SampleFormat.h
deleted file mode 100644
index d057bc3..0000000
--- a/soundlib/SampleFormat.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * SampleFormat.h
- * ---------------
- * Purpose: Utility enum and funcion to describe sample formats.
- * Notes  : (currently none)
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
-
-#pragma once
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-enum SampleFormatEnum
-{
-	SampleFormatUnsigned8 =  8,       // do not change value (for compatibility with old configuration settings)
-	SampleFormatInt16     = 16,       // do not change value (for compatibility with old configuration settings)
-	SampleFormatInt24     = 24,       // do not change value (for compatibility with old configuration settings)
-	SampleFormatInt32     = 32,       // do not change value (for compatibility with old configuration settings)
-	SampleFormatFloat32   = 32 + 128, // do not change value (for compatibility with old configuration settings)
-	SampleFormatInvalid   =  0
-};
-
-template<typename Tsample> struct SampleFormatTraits;
-template<> struct SampleFormatTraits<uint8>     { static const SampleFormatEnum sampleFormat = SampleFormatUnsigned8; };
-template<> struct SampleFormatTraits<int16>     { static const SampleFormatEnum sampleFormat = SampleFormatInt16;     };
-template<> struct SampleFormatTraits<int24>     { static const SampleFormatEnum sampleFormat = SampleFormatInt24;     };
-template<> struct SampleFormatTraits<int32>     { static const SampleFormatEnum sampleFormat = SampleFormatInt32;     };
-template<> struct SampleFormatTraits<float>     { static const SampleFormatEnum sampleFormat = SampleFormatFloat32;   };
-
-template<SampleFormatEnum sampleFormat> struct SampleFormatToType;
-template<> struct SampleFormatToType<SampleFormatUnsigned8> { typedef uint8     type; };
-template<> struct SampleFormatToType<SampleFormatInt16>     { typedef int16     type; };
-template<> struct SampleFormatToType<SampleFormatInt24>     { typedef int24     type; };
-template<> struct SampleFormatToType<SampleFormatInt32>     { typedef int32     type; };
-template<> struct SampleFormatToType<SampleFormatFloat32>   { typedef float     type; };
-
-
-struct SampleFormat
-{
-	SampleFormatEnum value;
-	SampleFormat(SampleFormatEnum v = SampleFormatInvalid) : value(v) { }
-	bool operator == (SampleFormat other) const { return value == other.value; }
-	bool operator != (SampleFormat other) const { return value != other.value; }
-	bool operator == (SampleFormatEnum other) const { return value == other; }
-	bool operator != (SampleFormatEnum other) const { return value != other; }
-	operator SampleFormatEnum () const
-	{
-		return value;
-	}
-	bool IsValid() const
-	{
-		return value != SampleFormatInvalid;
-	}
-	bool IsUnsigned() const
-	{
-		if(!IsValid()) return false;
-		return value == SampleFormatUnsigned8;
-	}
-	bool IsFloat() const
-	{
-		if(!IsValid()) return false;
-		return value == SampleFormatFloat32;
-	}
-	bool IsInt() const
-	{
-		if(!IsValid()) return false;
-		return value != SampleFormatFloat32;
-	}
-	uint8 GetBitsPerSample() const
-	{
-		if(!IsValid()) return 0;
-		switch(value)
-		{
-		case SampleFormatUnsigned8:
-			return 8;
-			break;
-		case SampleFormatInt16:
-			return 16;
-			break;
-		case SampleFormatInt24:
-			return 24;
-			break;
-		case SampleFormatInt32:
-			return 32;
-			break;
-		case SampleFormatFloat32:
-			return 32;
-			break;
-		default:
-			return 0;
-			break;
-		}
-	}
-
-	// backward compatibility, conversion to/from integers
-	operator int () const { return value; }
-	SampleFormat(int v) : value(SampleFormatEnum(v)) { }
-	operator long () const { return value; }
-	SampleFormat(long v) : value(SampleFormatEnum(v)) { }
-	operator unsigned int () const { return value; }
-	SampleFormat(unsigned int v) : value(SampleFormatEnum(v)) { }
-	operator unsigned long () const { return value; }
-	SampleFormat(unsigned long v) : value(SampleFormatEnum(v)) { }
-};
-
-
-OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormatConverters.h b/soundlib/SampleFormatConverters.h
deleted file mode 100644
index 4422102..0000000
--- a/soundlib/SampleFormatConverters.h
+++ /dev/null
@@ -1,1218 +0,0 @@
-/*
- * SampleFormatConverters.h
- * ------------------------
- * Purpose: Functions and functors for reading and converting pretty much any uncompressed sample format supported by OpenMPT.
- * Notes  : (currently none)
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
-
-
-#pragma once
-
-
-#include "../common/Endianness.h"
-
-
-OPENMPT_NAMESPACE_BEGIN
-
-
-// Byte offsets, from lowest significant to highest significant byte (for various functor template parameters)
-#define littleEndian64 0, 1, 2, 3, 4, 5, 6, 7
-#define littleEndian32 0, 1, 2, 3
-#define littleEndian24 0, 1, 2
-#define littleEndian16 0, 1
-
-#define bigEndian64 7, 6, 5, 4, 3, 2, 1, 0
-#define bigEndian32 3, 2, 1, 0
-#define bigEndian24 2, 1, 0
-#define bigEndian16 1, 0
-
-
-
-namespace SC { // SC = _S_ample_C_onversion
-
-
-
-
-// Every sample decoding functor has to typedef its input_t and output_t
-// and has to provide a static const input_inc member
-// which describes by how many input_t elements inBuf has to be incremented between invocations.
-// input_inc is normally 1 except when decoding e.g. bigger sample values
-// from multiple mpt::byte values.
-
-
-// decodes signed 7bit values stored as signed int8
-struct DecodeInt7
-{
-	typedef mpt::byte input_t;
-	typedef int8 output_t;
-	static const int input_inc = 1;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return Clamp(static_cast<int8>(*inBuf), static_cast<int8>(-64), static_cast<int8>(63)) * 2;
-	}
-};
-
-struct DecodeInt8
-{
-	typedef mpt::byte input_t;
-	typedef int8 output_t;
-	static const int input_inc = 1;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return static_cast<int8>(*inBuf);
-	}
-};
-
-struct DecodeUint8
-{
-	typedef mpt::byte input_t;
-	typedef int8 output_t;
-	static const int input_inc = 1;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return static_cast<int8>(int(static_cast<uint8>(*inBuf)) - 128);
-	}
-};
-
-struct DecodeInt8Delta
-{
-	typedef mpt::byte input_t;
-	typedef int8 output_t;
-	static const int input_inc = 1;
-	uint8 delta;
-	DecodeInt8Delta() : delta(0) { }
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		delta += static_cast<uint8>(*inBuf);
-		return static_cast<int8>(delta);
-	}
-};
-
-template <uint16 offset, size_t loByteIndex, size_t hiByteIndex>
-struct DecodeInt16
-{
-	typedef mpt::byte input_t;
-	typedef int16 output_t;
-	static const int input_inc = 2;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return (static_cast<uint8>(inBuf[loByteIndex]) | (static_cast<uint8>(inBuf[hiByteIndex]) << 8)) - offset;
-	}
-};
-
-template <size_t loByteIndex, size_t hiByteIndex>
-struct DecodeInt16Delta
-{
-	typedef mpt::byte input_t;
-	typedef int16 output_t;
-	static const int input_inc = 2;
-	uint16 delta;
-	DecodeInt16Delta() : delta(0) { }
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		delta += static_cast<uint8>(inBuf[loByteIndex]) | (static_cast<uint8>(inBuf[hiByteIndex]) << 8);
-		return static_cast<int16>(delta);
-	}
-};
-
-struct DecodeInt16Delta8
-{
-	typedef mpt::byte input_t;
-	typedef int16 output_t;
-	static const int input_inc = 2;
-	uint16 delta;
-	DecodeInt16Delta8() : delta(0) { }
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		delta += static_cast<uint8>(inBuf[0]);
-		int16 result = delta & 0xFF;
-		delta += static_cast<uint8>(inBuf[1]);
-		result |= (delta << 8);
-		return result;
-	}
-};
-
-template <uint32 offset, size_t loByteIndex, size_t midByteIndex, size_t hiByteIndex>
-struct DecodeInt24
-{
-	typedef mpt::byte input_t;
-	typedef int32 output_t;
-	static const int input_inc = 3;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return ((static_cast<uint8>(inBuf[loByteIndex]) << 8) | (static_cast<uint8>(inBuf[midByteIndex]) << 16) | (static_cast<uint8>(inBuf[hiByteIndex]) << 24)) - offset;
-	}
-};
-
-template <uint32 offset, size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex>
-struct DecodeInt32
-{
-	typedef mpt::byte input_t;
-	typedef int32 output_t;
-	static const int input_inc = 4;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return (static_cast<uint8>(inBuf[loLoByteIndex]) | (static_cast<uint8>(inBuf[loHiByteIndex]) << 8) | (static_cast<uint8>(inBuf[hiLoByteIndex]) << 16) | (static_cast<uint8>(inBuf[hiHiByteIndex]) << 24)) - offset;
-	}
-};
-
-template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex>
-struct DecodeFloat32
-{
-	typedef mpt::byte input_t;
-	typedef float32 output_t;
-	static const int input_inc = 4;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return IEEE754binary32LE(static_cast<uint8>(inBuf[loLoByteIndex]), static_cast<uint8>(inBuf[loHiByteIndex]), static_cast<uint8>(inBuf[hiLoByteIndex]), static_cast<uint8>(inBuf[hiHiByteIndex]));
-	}
-};
-
-template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex>
-struct DecodeScaledFloat32
-{
-	typedef mpt::byte input_t;
-	typedef float32 output_t;
-	static const int input_inc = 4;
-	float factor;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return factor * IEEE754binary32LE(static_cast<uint8>(inBuf[loLoByteIndex]), static_cast<uint8>(inBuf[loHiByteIndex]), static_cast<uint8>(inBuf[hiLoByteIndex]), static_cast<uint8>(inBuf[hiHiByteIndex]));
-	}
-	forceinline DecodeScaledFloat32(float scaleFactor)
-		: factor(scaleFactor)
-	{
-		return;
-	}
-};
-
-template <size_t b0, size_t b1, size_t b2, size_t b3, size_t b4, size_t b5, size_t b6, size_t b7>
-struct DecodeFloat64
-{
-	typedef mpt::byte input_t;
-	typedef float64 output_t;
-	static const int input_inc = 8;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return IEEE754binary64LE(uint8(inBuf[b0]), uint8(inBuf[b1]), uint8(inBuf[b2]), uint8(inBuf[b3]), uint8(inBuf[b4]), uint8(inBuf[b5]), uint8(inBuf[b6]), uint8(inBuf[b7]));
-	}
-};
-
-template <typename Tsample>
-struct DecodeIdentity
-{
-	typedef Tsample input_t;
-	typedef Tsample output_t;
-	static const int input_inc = 1;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return *inBuf;
-	}
-};
-
-
-
-// Shift input_t down by shift and saturate to output_t.
-template <typename Tdst, typename Tsrc, int shift>
-struct ConvertShift
-{
-	typedef Tsrc input_t;
-	typedef Tdst output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return mpt::saturate_cast<output_t>(val >> shift);
-	}
-};
-
-
-
-// Shift input_t up by shift and saturate to output_t.
-template <typename Tdst, typename Tsrc, int shift>
-struct ConvertShiftUp
-{
-	typedef Tsrc input_t;
-	typedef Tdst output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return mpt::saturate_cast<output_t>(val << shift);
-	}
-};
-
-
-
-
-// Every sample conversion functor has to typedef its input_t and output_t.
-// The input_t argument is taken by value because we only deal with per-single-sample conversions here.
-
-
-// straight forward type conversions, clamping when converting from floating point.
-template <typename Tdst, typename Tsrc>
-struct Convert;
-
-template <typename Tid>
-struct Convert<Tid, Tid>
-{
-	typedef Tid input_t;
-	typedef Tid output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val;
-	}
-};
-
-template <>
-struct Convert<int8, int16>
-{
-	typedef int16 input_t;
-	typedef int8 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int8>(val >> 8);
-	}
-};
-
-template <>
-struct Convert<int8, int24>
-{
-	typedef int24 input_t;
-	typedef int8 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int8>(val >> 16);
-	}
-};
-
-template <>
-struct Convert<int8, int32>
-{
-	typedef int32 input_t;
-	typedef int8 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int8>(val >> 24);
-	}
-};
-
-template <>
-struct Convert<int8, float32>
-{
-	typedef float32 input_t;
-	typedef int8 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		Limit(val, -1.0f, 1.0f);
-		val *= 128.0f;
-		// MSVC with x87 floating point math calls floor for the more intuitive version
-		// return mpt::saturate_cast<int8>(static_cast<int>(std::floor(val + 0.5f)));
-		return mpt::saturate_cast<int8>(static_cast<int>(val * 2.0f + 1.0f) >> 1);
-	}
-};
-
-template <>
-struct Convert<int16, int8>
-{
-	typedef int8 input_t;
-	typedef int16 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int16>(val << 8);
-	}
-};
-
-template <>
-struct Convert<int16, int24>
-{
-	typedef int24 input_t;
-	typedef int16 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int16>(val >> 8);
-	}
-};
-
-template <>
-struct Convert<int16, int32>
-{
-	typedef int32 input_t;
-	typedef int16 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int16>(val >> 16);
-	}
-};
-
-template <>
-struct Convert<int16, float32>
-{
-	typedef float32 input_t;
-	typedef int16 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		Limit(val, -1.0f, 1.0f);
-		val *= 32768.0f;
-		// MSVC with x87 floating point math calls floor for the more intuitive version
-		// return mpt::saturate_cast<int16>(static_cast<int>(std::floor(val + 0.5f)));
-		return mpt::saturate_cast<int16>(static_cast<int>(val * 2.0f + 1.0f) >> 1);
-	}
-};
-
-template <>
-struct Convert<int8, double>
-{
-	typedef double input_t;
-	typedef int8 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		Limit(val, -1.0, 1.0);
-		val *= 128.0;
-		// MSVC with x87 floating point math calls floor for the more intuitive version
-		// return mpt::saturate_cast<int16>(static_cast<int>(std::floor(val + 0.5)));
-		return mpt::saturate_cast<int8>(static_cast<int>(val * 2.0 + 1.0) >> 1);
-	}
-};
-
-template <>
-struct Convert<int16, double>
-{
-	typedef double input_t;
-	typedef int16 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		Limit(val, -1.0, 1.0);
-		val *= 32768.0;
-		// MSVC with x87 floating point math calls floor for the more intuitive version
-		// return mpt::saturate_cast<int16>(static_cast<int>(std::floor(val + 0.5)));
-		return mpt::saturate_cast<int16>(static_cast<int>(val * 2.0 + 1.0) >> 1);
-	}
-};
-
-template <>
-struct Convert<int24, int8>
-{
-	typedef int8 input_t;
-	typedef int24 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int24>(val << 16);
-	}
-};
-
-template <>
-struct Convert<int24, int16>
-{
-	typedef int16 input_t;
-	typedef int24 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int24>(val << 8);
-	}
-};
-
-template <>
-struct Convert<int24, int32>
-{
-	typedef int32 input_t;
-	typedef int24 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int24>(val >> 8);
-	}
-};
-
-template <>
-struct Convert<int32, int8>
-{
-	typedef int8 input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int32>(val << 24);
-	}
-};
-
-template <>
-struct Convert<int32, int16>
-{
-	typedef int16 input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int32>(val << 16);
-	}
-};
-
-template <>
-struct Convert<int32, int24>
-{
-	typedef int24 input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<int32>(val << 8);
-	}
-};
-
-template <>
-struct Convert<int32, float32>
-{
-	typedef float32 input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		Limit(val, -1.0f, 1.0f);
-		val *= 2147483648.0f;
-		// MSVC with x87 floating point math calls floor for the more intuitive version
-		// return mpt::saturate_cast<int32>(static_cast<int64>(std::floor(val + 0.5f)));
-		return mpt::saturate_cast<int32>(static_cast<int64>(val * 2.0f + 1.0f) >> 1);
-	}
-};
-
-template <>
-struct Convert<int32, double>
-{
-	typedef double input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		Limit(val, -1.0, 1.0);
-		val *= 2147483648.0;
-		// MSVC with x87 floating point math calls floor for the more intuitive version
-		// return mpt::saturate_cast<int32>(static_cast<int64>(std::floor(val + 0.5)));
-		return mpt::saturate_cast<int32>(static_cast<int64>(val * 2.0 + 1.0) >> 1);
-	}
-};
-
-template <>
-struct Convert<float32, int8>
-{
-	typedef int8 input_t;
-	typedef float32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1)<<7));
-	}
-};
-
-template <>
-struct Convert<float32, int16>
-{
-	typedef int16 input_t;
-	typedef float32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1)<<15));
-	}
-};
-
-template <>
-struct Convert<float32, int32>
-{
-	typedef int32 input_t;
-	typedef float32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val * (1.0f / static_cast<float>(static_cast<unsigned int>(1)<<31));
-	}
-};
-
-template <>
-struct Convert<double, int8>
-{
-	typedef int8 input_t;
-	typedef double output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1)<<7));
-	}
-};
-
-template <>
-struct Convert<double, int16>
-{
-	typedef int16 input_t;
-	typedef double output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1)<<15));
-	}
-};
-
-template <>
-struct Convert<double, int32>
-{
-	typedef int32 input_t;
-	typedef double output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val * (1.0 / static_cast<double>(static_cast<unsigned int>(1)<<31));
-	}
-};
-
-template <>
-struct Convert<double, float>
-{
-	typedef float input_t;
-	typedef double output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return val;
-	}
-};
-
-template <>
-struct Convert<float, double>
-{
-	typedef double input_t;
-	typedef float output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		return static_cast<float>(val);
-	}
-};
-
-
-template <typename Tdst, typename Tsrc, int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint;
-
-template <int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint<uint8, int32, fractionalBits, clipOutput>
-{
-	typedef int32 input_t;
-	typedef uint8 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		val = (val + (1<<(shiftBits-1))) >> shiftBits; // round
-		if(val < int8_min) val = int8_min;
-		if(val > int8_max) val = int8_max;
-		return static_cast<uint8>(val+0x80); // unsigned
-	}
-};
-
-template <int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint<int8, int32, fractionalBits, clipOutput>
-{
-	typedef int32 input_t;
-	typedef int8 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		val = (val + (1<<(shiftBits-1))) >> shiftBits; // round
-		if(val < int8_min) val = int8_min;
-		if(val > int8_max) val = int8_max;
-		return static_cast<int8>(val);
-	}
-};
-
-template <int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint<int16, int32, fractionalBits, clipOutput>
-{
-	typedef int32 input_t;
-	typedef int16 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		val = (val + (1<<(shiftBits-1))) >> shiftBits; // round
-		if(val < int16_min) val = int16_min;
-		if(val > int16_max) val = int16_max;
-		return static_cast<int16>(val);
-	}
-};
-
-template <int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint<int24, int32, fractionalBits, clipOutput>
-{
-	typedef int32 input_t;
-	typedef int24 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(output_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		val = (val + (1<<(shiftBits-1))) >> shiftBits; // round
-		if(val < int24_min) val = int24_min;
-		if(val > int24_max) val = int24_max;
-		return static_cast<int24>(val);
-	}
-};
-
-template <int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint<int32, int32, fractionalBits, clipOutput>
-{
-	typedef int32 input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		return static_cast<int32>(Clamp(val, static_cast<int>(-((1<<fractionalBits)-1)), static_cast<int>(1<<fractionalBits)-1)) << (sizeof(input_t)*8-1-fractionalBits);
-	}
-};
-
-template <int fractionalBits, bool clipOutput>
-struct ConvertFixedPoint<float32, int32, fractionalBits, clipOutput>
-{
-	typedef int32 input_t;
-	typedef float32 output_t;
-	const float factor;
-	forceinline ConvertFixedPoint()
-		: factor( 1.0f / static_cast<float>(1 << fractionalBits) )
-	{
-		return;
-	}
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		MPT_CONSTANT_IF(clipOutput)
-		{
-			float32 out = val * factor;
-			if(out < -1.0f) out = -1.0f;
-			if(out > 1.0f) out = 1.0f;
-			return out;
-		} else
-		{
-			return val * factor;
-		}
-	}
-};
-
-
-template <typename Tdst, typename Tsrc, int fractionalBits>
-struct ConvertToFixedPoint;
-
-template <int fractionalBits>
-struct ConvertToFixedPoint<int32, uint8, fractionalBits>
-{
-	typedef uint8 input_t;
-	typedef int32 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		return static_cast<output_t>(static_cast<int>(val)-0x80) << shiftBits;
-	}
-};
-
-template <int fractionalBits>
-struct ConvertToFixedPoint<int32, int16, fractionalBits>
-{
-	typedef int16 input_t;
-	typedef int32 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		return static_cast<output_t>(val) << shiftBits;
-	}
-};
-
-template <int fractionalBits>
-struct ConvertToFixedPoint<int32, int24, fractionalBits>
-{
-	typedef int24 input_t;
-	typedef int32 output_t;
-	static const int shiftBits = fractionalBits + 1 - sizeof(input_t) * 8;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
-		STATIC_ASSERT(shiftBits >= 1);
-		return static_cast<output_t>(val) << shiftBits;
-	}
-};
-
-template <int fractionalBits>
-struct ConvertToFixedPoint<int32, int32, fractionalBits>
-{
-	typedef int32 input_t;
-	typedef int32 output_t;
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(output_t)*8-1);
-		return static_cast<output_t>(val) >> (sizeof(input_t)*8-1-fractionalBits);
-	}
-};
-
-template <int fractionalBits>
-struct ConvertToFixedPoint<int32, float32, fractionalBits>
-{
-	typedef float32 input_t;
-	typedef int32 output_t;
-	const float factor;
-	forceinline ConvertToFixedPoint()
-		: factor( static_cast<float>(1 << fractionalBits) )
-	{
-		return;
-	}
-	forceinline output_t operator() (input_t val)
-	{
-		STATIC_ASSERT(fractionalBits >= 0 && fractionalBits <= sizeof(input_t)*8-1);
-		return mpt::saturate_cast<output_t>(std::floor(val * factor + 0.5f));
-	}
-};
-
-
-
-// Reads sample data with Func and passes it directly to Func2.
-// Func1::output_t and Func2::input_t must be identical
-template <typename Func2, typename Func1>
-struct ConversionChain
-{
-	typedef typename Func1::input_t input_t;
-	typedef typename Func2::output_t output_t;
-	static const int input_inc = Func1::input_inc;
-	Func1 func1;
-	Func2 func2;
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return func2(func1(inBuf));
-	}
-	forceinline ConversionChain(Func2 f2 = Func2(), Func1 f1 = Func1())
-		: func1(f1)
-		, func2(f2)
-	{
-		return;
-	}
-};
-
-
-
-
-template <typename Tsample>
-struct Normalize;
-
-template <>
-struct Normalize<int32>
-{
-	typedef int32 input_t;
-	typedef int32 output_t;
-	typedef uint32 peak_t;
-	uint32 maxVal;
-	forceinline Normalize() : maxVal(0) { }
-	forceinline void FindMax(input_t val)
-	{
-		if(val < 0)
-		{
-			if(val == int32_min)
-			{
-				maxVal = static_cast<uint32>(-static_cast<int64>(int32_min));
-				return;
-			}
-			val = -val;
-		}
-		if(static_cast<uint32>(val) > maxVal)
-		{
-			maxVal = static_cast<uint32>(val);
-		}
-	}
-	forceinline bool IsSilent() const
-	{
-		return maxVal == 0;
-	}
-	forceinline output_t operator() (input_t val)
-	{
-		return Util::muldivrfloor(val, static_cast<uint32>(1) << 31, maxVal);
-	}
-	forceinline peak_t GetSrcPeak() const
-	{
-		return maxVal;
-	}
-};
-
-template <>
-struct Normalize<float32>
-{
-	typedef float32 input_t;
-	typedef float32 output_t;
-	typedef float32 peak_t;
-	float maxVal;
-	float maxValInv;
-	forceinline Normalize() : maxVal(0.0f), maxValInv(1.0f) { }
-	forceinline void FindMax(input_t val)
-	{
-		float absval = std::fabs(val);
-		if(absval > maxVal)
-		{
-			maxVal = absval;
-		}
-	}
-	forceinline bool IsSilent()
-	{
-		if(maxVal == 0.0f)
-		{
-			maxValInv = 1.0f;
-			return true;
-		} else
-		{
-			maxValInv = 1.0f / maxVal;
-			return false;
-		}
-	}
-	forceinline output_t operator() (input_t val)
-	{
-		return val * maxValInv;
-	}
-	forceinline peak_t GetSrcPeak() const
-	{
-		return maxVal;
-	}
-};
-
-template <>
-struct Normalize<float64>
-{
-	typedef float64 input_t;
-	typedef float64 output_t;
-	typedef float64 peak_t;
-	double maxVal;
-	double maxValInv;
-	forceinline Normalize() : maxVal(0.0), maxValInv(1.0) { }
-	forceinline void FindMax(input_t val)
-	{
-		double absval = std::fabs(val);
-		if(absval > maxVal)
-		{
-			maxVal = absval;
-		}
-	}
-	forceinline bool IsSilent()
-	{
-		if(maxVal == 0.0)
-		{
-			maxValInv = 1.0;
-			return true;
-		} else
-		{
-			maxValInv = 1.0 / maxVal;
-			return false;
-		}
-	}
-	forceinline output_t operator() (input_t val)
-	{
-		return val * maxValInv;
-	}
-	forceinline peak_t GetSrcPeak() const
-	{
-		return maxVal;
-	}
-};
-
-
-// Reads sample data with Func1, then normalizes the sample data, and then converts it with Func2.
-// Func1::output_t and Func2::input_t must be identical.
-// Func1 can also be the identity decode (DecodeIdentity<T>).
-// Func2 can also be the identity conversion (Convert<T,T>).
-template <typename Func2, typename Func1>
-struct NormalizationChain
-{
-	typedef typename Func1::input_t input_t;
-	typedef typename Func1::output_t normalize_t;
-	typedef typename Normalize<normalize_t>::peak_t peak_t;
-	typedef typename Func2::output_t output_t;
-	static const int input_inc = Func1::input_inc;
-	Func1 func1;
-	Normalize<normalize_t> normalize;
-	Func2 func2;
-	forceinline void FindMax(const input_t *inBuf)
-	{
-		normalize.FindMax(func1(inBuf));
-	}
-	forceinline bool IsSilent()
-	{
-		return normalize.IsSilent();
-	}
-	forceinline output_t operator() (const input_t *inBuf)
-	{
-		return func2(normalize(func1(inBuf)));
-	}
-	forceinline peak_t GetSrcPeak() const
-	{
-		return normalize.GetSrcPeak();
-	}
-	forceinline NormalizationChain(Func2 f2 = Func2(), Func1 f1 = Func1())
-		: func1(f1)
-		, func2(f2)
-	{
-		return;
-	}
-};
-
-
-
-
-} // namespace SC
-
-
-
-#if defined(LIBOPENMPT_BUILD) || (defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT))
-
-struct ModSample;
-
-//////////////////////////////////////////////////////
-// Actual sample conversion functions
-
-// Copy a sample data buffer.
-// targetBuffer: Buffer in which the sample should be copied into.
-// numSamples: Number of samples of size T that should be copied. targetBuffer is expected to be able to hold "numSamples * incTarget" samples.
-// incTarget: Number of samples by which the target data pointer is increased each time.
-// sourceBuffer: Buffer from which the samples should be read.
-// sourceSize: Size of source buffer, in bytes.
-// incSource: Number of samples by which the source data pointer is increased each time.
-//
-// Template arguments:
-// SampleConversion: Functor of type SampleConversionFunctor to apply sample conversion (see above for existing functors).
-template <typename SampleConversion>
-size_t CopySample(typename SampleConversion::output_t * MPT_RESTRICT outBuf, size_t numSamples, size_t incTarget, const typename SampleConversion::input_t * MPT_RESTRICT inBuf, size_t sourceSize, size_t incSource, SampleConversion conv = SampleConversion())
-//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	const size_t sampleSize = incSource * SampleConversion::input_inc * sizeof(typename SampleConversion::input_t);
-	LimitMax(numSamples, sourceSize / sampleSize);
-	const size_t copySize = numSamples * sampleSize;
-
-	SampleConversion sampleConv(conv);
-	while(numSamples--)
-	{
-		*outBuf = sampleConv(inBuf);
-		outBuf += incTarget;
-		inBuf += incSource * SampleConversion::input_inc;
-	}
-
-	return copySize;
-}
-
-
-// Copy numChannels interleaved sample streams.
-template <typename SampleConversion>
-void CopyInterleavedSampleStreams(typename SampleConversion::output_t * MPT_RESTRICT outBuf, const typename SampleConversion::input_t * MPT_RESTRICT inBuf, size_t numFrames, size_t numChannels, SampleConversion *conv)
-//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	while(numFrames--)
-	{
-		for(size_t channel = 0; channel < numChannels; ++channel)
-		{
-			*outBuf = conv[channel](*inBuf);
-			inBuf++;
-			outBuf++;
-		}
-	}
-}
-
-
-// Copy numChannels interleaved sample streams.
-template <typename SampleConversion>
-void CopyInterleavedSampleStreams(typename SampleConversion::output_t * MPT_RESTRICT outBuf, const typename SampleConversion::input_t * MPT_RESTRICT inBuf, size_t numFrames, size_t numChannels, std::vector<SampleConversion> &conv)
-//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	MPT_ASSERT(conv.size() >= numChannels);
-	CopyInterleavedSampleStreams(outBuf, inBuf, numFrames, numChannels, &(conv[0]));
-}
-
-
-// Copy a mono sample data buffer.
-template <typename SampleConversion, typename Tbyte>
-size_t CopyMonoSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion())
-//-------------------------------------------------------------------------------------------------------------------------------
-{
-	MPT_ASSERT(sample.GetNumChannels() == 1);
-	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
-
-	const size_t frameSize =  SampleConversion::input_inc;
-	const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength);
-	size_t numFrames = countFrames;
-	SampleConversion sampleConv(conv);
-	const mpt::byte * MPT_RESTRICT inBuf = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
-	typename SampleConversion::output_t * MPT_RESTRICT outBuf = static_cast<typename SampleConversion::output_t *>(sample.pSample);
-	while(numFrames--)
-	{
-		*outBuf = sampleConv(inBuf);
-		inBuf += SampleConversion::input_inc;
-		outBuf++;
-	}
-	return frameSize * countFrames;
-}
-
-
-// Copy a stereo interleaved sample data buffer.
-template <typename SampleConversion, typename Tbyte>
-size_t CopyStereoInterleavedSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion())
-//--------------------------------------------------------------------------------------------------------------------------------------------
-{
-	MPT_ASSERT(sample.GetNumChannels() == 2);
-	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
-
-	const size_t frameSize = 2 * SampleConversion::input_inc;
-	const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength);
-	size_t numFrames = countFrames;
-	SampleConversion sampleConvLeft(conv);
-	SampleConversion sampleConvRight(conv);
-	const mpt::byte * MPT_RESTRICT inBuf = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
-	typename SampleConversion::output_t * MPT_RESTRICT outBuf = static_cast<typename SampleConversion::output_t *>(sample.pSample);
-	while(numFrames--)
-	{
-		*outBuf = sampleConvLeft(inBuf);
-		inBuf += SampleConversion::input_inc;
-		outBuf++;
-		*outBuf = sampleConvRight(inBuf);
-		inBuf += SampleConversion::input_inc;
-		outBuf++;
-	}
-	return frameSize * countFrames;
-}
-
-
-// Copy a stereo split sample data buffer.
-template <typename SampleConversion, typename Tbyte>
-size_t CopyStereoSplitSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion())
-//--------------------------------------------------------------------------------------------------------------------------------------
-{
-	MPT_ASSERT(sample.GetNumChannels() == 2);
-	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
-
-	const size_t sampleSize = SampleConversion::input_inc;
-	const size_t sourceSizeLeft = std::min<size_t>(sample.nLength * SampleConversion::input_inc, sourceSize);
-	const size_t sourceSizeRight = std::min<size_t>(sample.nLength * SampleConversion::input_inc, sourceSize - sourceSizeLeft);
-	const size_t countSamplesLeft = sourceSizeLeft / sampleSize;
-	const size_t countSamplesRight = sourceSizeRight / sampleSize;
-
-	size_t numSamplesLeft = countSamplesLeft;
-	SampleConversion sampleConvLeft(conv);
-	const mpt::byte * MPT_RESTRICT inBufLeft = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
-	typename SampleConversion::output_t * MPT_RESTRICT outBufLeft = static_cast<typename SampleConversion::output_t *>(sample.pSample);
-	while(numSamplesLeft--)
-	{
-		*outBufLeft = sampleConvLeft(inBufLeft);
-		inBufLeft += SampleConversion::input_inc;
-		outBufLeft += 2;
-	}
-
-	size_t numSamplesRight = countSamplesRight;
-	SampleConversion sampleConvRight(conv);
-	const mpt::byte * MPT_RESTRICT inBufRight = mpt::byte_cast<const mpt::byte*>(sourceBuffer) + sample.nLength * SampleConversion::input_inc;
-	typename SampleConversion::output_t * MPT_RESTRICT outBufRight = static_cast<typename SampleConversion::output_t *>(sample.pSample) + 1;
-	while(numSamplesRight--)
-	{
-		*outBufRight = sampleConvRight(inBufRight);
-		inBufRight += SampleConversion::input_inc;
-		outBufRight += 2;
-	}
-
-	return (countSamplesLeft + countSamplesRight) * sampleSize;
-}
-
-
-// Copy a sample data buffer and normalize it. Requires slightly advanced sample conversion functor.
-template <typename SampleConversion, typename Tbyte>
-size_t CopyAndNormalizeSample(ModSample &sample, const Tbyte *sourceBuffer, size_t sourceSize, typename SampleConversion::peak_t *srcPeak = nullptr, SampleConversion conv = SampleConversion())
-//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	const size_t inSize = sizeof(typename SampleConversion::input_t);
-
-	MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
-
-	size_t numSamples = sample.nLength * sample.GetNumChannels();
-	LimitMax(numSamples, sourceSize / inSize);
-
-	const mpt::byte * inBuf = mpt::byte_cast<const mpt::byte*>(sourceBuffer);
-	// Finding max value
-	SampleConversion sampleConv(conv);
-	for(size_t i = numSamples; i != 0; i--)
-	{
-		sampleConv.FindMax(inBuf);
-		inBuf += SampleConversion::input_inc;
-	}
-
-	// If buffer is silent (maximum is 0), don't bother normalizing the sample - just keep the already silent buffer.
-	if(!sampleConv.IsSilent())
-	{
-		inBuf = sourceBuffer;
-		// Copying buffer.
-		typename SampleConversion::output_t *outBuf = static_cast<typename SampleConversion::output_t *>(sample.pSample);
-
-		for(size_t i = numSamples; i != 0; i--)
-		{
-			*outBuf = sampleConv(inBuf);
-			outBuf++;
-			inBuf += SampleConversion::input_inc;
-		}
-	}
-
-	if(srcPeak)
-	{
-		*srcPeak = sampleConv.GetSrcPeak();
-	}
-
-	return numSamples * inSize;
-}
-
-#endif
-
-
-template<int fractionalBits, bool clipOutput, typename Tsample, typename Tfixed>
-void ConvertInterleavedFixedPointToInterleaved(Tsample * MPT_RESTRICT p, const Tfixed * MPT_RESTRICT mixbuffer, std::size_t channels, std::size_t count)
-//------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	SC::ConvertFixedPoint<Tsample, int, fractionalBits, clipOutput> conv;
-	count *= channels;
-	for(std::size_t i = 0; i < count; ++i)
-	{
-		p[i] = conv(mixbuffer[i]);
-	}
-}
-
-template<int fractionalBits, bool clipOutput, typename Tsample, typename Tfixed>
-void ConvertInterleavedFixedPointToNonInterleaved(Tsample * const * const MPT_RESTRICT buffers, const Tfixed * MPT_RESTRICT mixbuffer, std::size_t channels, std::size_t count)
-//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	SC::ConvertFixedPoint<Tsample, int, fractionalBits, clipOutput> conv;
-	for(std::size_t i = 0; i < count; ++i)
-	{
-		for(std::size_t channel = 0; channel < channels; ++channel)
-		{
-			buffers[channel][i] = conv(*mixbuffer);
-			mixbuffer++;
-		}
-	}
-}
-
-
-// Copy from an interleaed buffer of #channels.
-template <typename SampleConversion>
-void CopyInterleavedToChannel(typename SampleConversion::output_t * MPT_RESTRICT dst, const typename SampleConversion::input_t * MPT_RESTRICT src, std::size_t channels, std::size_t countChunk, std::size_t channel, SampleConversion conv = SampleConversion())
-//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	SampleConversion sampleConv(conv);
-	src += channel;
-	for(std::size_t i = 0; i < countChunk; ++i)
-	{
-		*dst = sampleConv(*src);
-		src += channels;
-		dst++;
-	}
-}
-
-
-// Copy buffer to an interleaed buffer of #channels.
-template <typename SampleConversion>
-void CopyChannelToInterleaved(typename SampleConversion::output_t * MPT_RESTRICT dst, const typename SampleConversion::input_t * MPT_RESTRICT src, std::size_t channels, std::size_t countChunk, std::size_t channel, SampleConversion conv = SampleConversion())
-//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	SampleConversion sampleConv(conv);
-	dst += channel;
-	for(std::size_t i = 0; i < countChunk; ++i)
-	{
-		*dst = sampleConv(*src);
-		src++;
-		dst += channels;
-	}
-}
-
-
-OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormatFLAC.cpp b/soundlib/SampleFormatFLAC.cpp
new file mode 100644
index 0000000..10c0df9
--- /dev/null
+++ b/soundlib/SampleFormatFLAC.cpp
@@ -0,0 +1,671 @@
+/*
+ * SampleFormatFLAC.cpp
+ * --------------------
+ * Purpose: FLAC sample import.
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Sndfile.h"
+#ifdef MODPLUG_TRACKER
+#include "../mptrack/TrackerSettings.h"
+#endif //MODPLUG_TRACKER
+#ifndef MODPLUG_NO_FILESAVE
+#include "../common/mptFileIO.h"
+#endif
+#include "../common/misc_util.h"
+#include "Tagging.h"
+#include "Loaders.h"
+#include "WAVTools.h"
+#include "ChunkReader.h"
+#include "modsmp_ctrl.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
+//#include "../common/mptCRC.h"
+#include "OggStream.h"
+#ifdef MPT_WITH_OGG
+#include <ogg/ogg.h>
+#endif // MPT_WITH_OGG
+#ifdef MPT_WITH_FLAC
+#include <FLAC/stream_decoder.h>
+#include <FLAC/stream_encoder.h>
+#include <FLAC/metadata.h>
+#endif // MPT_WITH_FLAC
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// FLAC Samples
+
+#ifdef MPT_WITH_FLAC
+
+struct FLACDecoder
+{
+	FileReader &file;
+	CSoundFile &sndFile;
+	SAMPLEINDEX sample;
+	bool ready;
+
+	FLACDecoder(FileReader &f, CSoundFile &sf, SAMPLEINDEX smp) : file(f), sndFile(sf), sample(smp), ready(false) { }
+
+	static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *client_data)
+	{
+		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
+		if(*bytes > 0)
+		{
+			FileReader::off_t readBytes = *bytes;
+			LimitMax(readBytes, file.BytesLeft());
+			file.ReadRaw(buffer, readBytes);
+			*bytes = readBytes;
+			if(*bytes == 0)
+				return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+			else
+				return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+		} else
+		{
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		}
+	}
+
+	static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *, FLAC__uint64 absolute_byte_offset, void *client_data)
+	{
+		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
+		if(!file.Seek(static_cast<FileReader::off_t>(absolute_byte_offset)))
+			return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+		else
+			return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+	}
+
+	static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *, FLAC__uint64 *absolute_byte_offset, void *client_data)
+	{
+		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
+		*absolute_byte_offset = file.GetPosition();
+		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+
+	static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data)
+	{
+		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
+		*stream_length = file.GetLength();
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+
+	static FLAC__bool eof_cb(const FLAC__StreamDecoder *, void *client_data)
+	{
+		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
+		return file.NoBytesLeft();
+	}
+
+	static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
+	{
+		FLACDecoder &client = *static_cast<FLACDecoder *>(client_data);
+		ModSample &sample = client.sndFile.GetSample(client.sample);
+
+		if(frame->header.number.sample_number >= sample.nLength || !client.ready)
+		{
+			// We're reading beyond the sample size already, or we aren't even ready to decode yet!
+			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+
+		// Number of samples to be copied in this call
+		const SmpLength copySamples = std::min(static_cast<SmpLength>(frame->header.blocksize), static_cast<SmpLength>(sample.nLength - frame->header.number.sample_number));
+		// Number of target channels
+		const uint8 modChannels = sample.GetNumChannels();
+		// Offset (in samples) into target data
+		const size_t offset = static_cast<size_t>(frame->header.number.sample_number) * modChannels;
+		// Source size in bytes
+		const size_t srcSize = frame->header.blocksize * 4;
+		// Source bit depth
+		const unsigned int bps = frame->header.bits_per_sample;
+
+		int8 *sampleData8 = sample.pSample8 + offset;
+		int16 *sampleData16 = sample.pSample16 + offset;
+
+		MPT_ASSERT((bps <= 8 && sample.GetElementarySampleSize() == 1) || (bps > 8 && sample.GetElementarySampleSize() == 2));
+		MPT_ASSERT(modChannels <= FLAC__stream_decoder_get_channels(decoder));
+		MPT_ASSERT(bps == FLAC__stream_decoder_get_bits_per_sample(decoder));
+		MPT_UNREFERENCED_PARAMETER(decoder); // decoder is unused if ASSERTs are compiled out
+
+		// Do the sample conversion
+		for(uint8 chn = 0; chn < modChannels; chn++)
+		{
+			if(bps <= 8)
+			{
+				CopySample<SC::ConversionChain<SC::ConvertShift< int8, int32,  0>, SC::DecodeIdentity<int32> > >(sampleData8  + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
+			} else if(bps <= 16)
+			{
+				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32,  0>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
+			} else if(bps <= 24)
+			{
+				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32,  8>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
+			} else if(bps <= 32)
+			{
+				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32, 16>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
+			}
+		}
+
+		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+	}
+
+	static void metadata_cb(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data)
+	{
+		FLACDecoder &client = *static_cast<FLACDecoder *>(client_data);
+		if(client.sample > client.sndFile.GetNumSamples())
+		{
+			client.sndFile.m_nSamples = client.sample;
+		}
+		ModSample &sample = client.sndFile.GetSample(client.sample);
+
+		if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0)
+		{
+			// Init sample information
+			client.sndFile.DestroySampleThreadsafe(client.sample);
+			strcpy(client.sndFile.m_szNames[client.sample], "");
+			sample.Initialize();
+			sample.uFlags.set(CHN_16BIT, metadata->data.stream_info.bits_per_sample > 8);
+			sample.uFlags.set(CHN_STEREO, metadata->data.stream_info.channels > 1);
+			sample.nLength = mpt::saturate_cast<SmpLength>(metadata->data.stream_info.total_samples);
+			sample.nC5Speed = metadata->data.stream_info.sample_rate;
+			client.ready = (sample.AllocateSample() != 0);
+		} else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4) && client.ready)
+		{
+			// Try reading RIFF loop points and other sample information
+			ChunkReader data(mpt::as_span(metadata->data.application.data, metadata->length));
+			ChunkReader::ChunkList<RIFFChunk> chunks = data.ReadChunks<RIFFChunk>(2);
+
+			// We're not really going to read a WAV file here because there will be only one RIFF chunk per metadata event, but we can still re-use the code for parsing RIFF metadata...
+			WAVReader riffReader(data);
+			riffReader.FindMetadataChunks(chunks);
+			riffReader.ApplySampleSettings(sample, client.sndFile.m_szNames[client.sample]);
+		} else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && client.ready)
+		{
+			// Try reading Vorbis Comments for sample title, sample rate and loop points
+			SmpLength loopStart = 0, loopLength = 0;
+			for(FLAC__uint32 i = 0; i < metadata->data.vorbis_comment.num_comments; i++)
+			{
+				const char *tag = mpt::byte_cast<const char *>(metadata->data.vorbis_comment.comments[i].entry);
+				const FLAC__uint32 length = metadata->data.vorbis_comment.comments[i].length;
+				if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6))
+				{
+					mpt::String::Read<mpt::String::maybeNullTerminated>(client.sndFile.m_szNames[client.sample], tag + 6, length - 6);
+				} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11))
+				{
+					uint32 sampleRate = ConvertStrTo<uint32>(tag + 11);
+					if(sampleRate > 0) sample.nC5Speed = sampleRate;
+				} else if(length > 10 && !mpt::CompareNoCaseAscii(tag, "LOOPSTART=", 10))
+				{
+					loopStart = ConvertStrTo<SmpLength>(tag + 10);
+				} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "LOOPLENGTH=", 11))
+				{
+					loopLength = ConvertStrTo<SmpLength>(tag + 11);
+				}
+			}
+			if(loopLength > 0)
+			{
+				sample.nLoopStart = loopStart;
+				sample.nLoopEnd = loopStart + loopLength;
+				sample.uFlags.set(CHN_LOOP);
+				sample.SanitizeLoops();
+			}
+		}
+	}
+
+	static void error_cb(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *)
+	{
+	}
+};
+
+#endif // MPT_WITH_FLAC
+
+
+bool CSoundFile::ReadFLACSample(SAMPLEINDEX sample, FileReader &file)
+{
+#ifdef MPT_WITH_FLAC
+	file.Rewind();
+	bool isOgg = false;
+#ifdef MPT_WITH_OGG
+	uint32 oggFlacBitstreamSerial = 0;
+#endif
+	// Check whether we are dealing with native FLAC, OggFlac or no FLAC at all.
+	if(file.ReadMagic("fLaC"))
+	{ // ok
+		isOgg = false;
+#ifdef MPT_WITH_OGG
+	} else if(file.ReadMagic("OggS"))
+	{ // use libogg to find the first OggFlac stream header
+		file.Rewind();
+		bool oggOK = false;
+		bool needMoreData = true;
+		static const long bufsize = 65536;
+		std::size_t readSize = 0;
+		char *buf = nullptr;
+		ogg_sync_state oy;
+		MemsetZero(oy);
+		ogg_page og;
+		MemsetZero(og);
+		std::map<uint32, ogg_stream_state*> oggStreams;
+		ogg_packet op;
+		MemsetZero(op);
+		if(ogg_sync_init(&oy) != 0)
+		{
+			return false;
+		}
+		while(needMoreData)
+		{
+			if(file.NoBytesLeft())
+			{ // stop at EOF
+				oggOK = false;
+				needMoreData = false;
+				break;
+			}
+			buf = ogg_sync_buffer(&oy, bufsize);
+			if(!buf)
+			{
+				oggOK = false;
+				needMoreData = false;
+				break;
+			}
+			readSize = file.ReadRaw(buf, bufsize);
+			if(ogg_sync_wrote(&oy, static_cast<long>(readSize)) != 0)
+			{
+				oggOK = false;
+				needMoreData = false;
+				break;
+			}
+			while(ogg_sync_pageout(&oy, &og) == 1)
+			{
+				if(!ogg_page_bos(&og))
+				{ // we stop scanning when seeing the first noo-begin-of-stream page
+					oggOK = false;
+					needMoreData = false;
+					break;
+				}
+				uint32 serial = ogg_page_serialno(&og);
+				if(!oggStreams[serial])
+				{ // previously unseen stream serial
+					oggStreams[serial] = new ogg_stream_state();
+					MemsetZero(*(oggStreams[serial]));
+					if(ogg_stream_init(oggStreams[serial], serial) != 0)
+					{
+						delete oggStreams[serial];
+						oggStreams.erase(serial);
+						oggOK = false;
+						needMoreData = false;
+						break;
+					}
+				}
+				if(ogg_stream_pagein(oggStreams[serial], &og) != 0)
+				{ // invalid page
+					oggOK = false;
+					needMoreData = false;
+					break;
+				}
+				if(ogg_stream_packetout(oggStreams[serial], &op) != 1)
+				{ // partial or broken packet, continue with more data
+					continue;
+				}
+				if(op.packetno != 0)
+				{ // non-begin-of-stream packet.
+					// This should not appear on first page for any known ogg codec,
+					// but deal gracefully with badly mused streams in that regard.
+					continue;
+				}
+				FileReader packet(mpt::as_span(op.packet, op.bytes));
+				if(packet.ReadIntLE<uint8>() == 0x7f && packet.ReadMagic("FLAC"))
+				{ // looks like OggFlac
+					oggOK = true;
+					oggFlacBitstreamSerial = serial;
+					needMoreData = false;
+					break;
+				}
+			}
+		}
+		while(oggStreams.size() > 0)
+		{
+			uint32 serial = oggStreams.begin()->first;
+			ogg_stream_clear(oggStreams[serial]);
+			delete oggStreams[serial];
+			oggStreams.erase(serial);
+		}
+		ogg_sync_clear(&oy);
+		if(!oggOK)
+		{
+			return false;
+		}
+		isOgg = true;
+#else // !MPT_WITH_OGG
+	} else if(file.CanRead(78) && file.ReadMagic("OggS"))
+	{ // first OggFlac page is exactly 78 bytes long
+		// only support plain OggFlac here with the FLAC logical bitstream being the first one
+		uint8 oggPageVersion = file.ReadIntLE<uint8>();
+		uint8 oggPageHeaderType = file.ReadIntLE<uint8>();
+		uint64 oggPageGranulePosition = file.ReadIntLE<uint64>();
+		uint32 oggPageBitstreamSerialNumber = file.ReadIntLE<uint32>();
+		uint32 oggPageSequenceNumber = file.ReadIntLE<uint32>();
+		uint32 oggPageChecksum = file.ReadIntLE<uint32>();
+		uint8 oggPageSegments = file.ReadIntLE<uint8>();
+		uint8 oggPageSegmentLength = file.ReadIntLE<uint8>();
+		if(oggPageVersion != 0)
+		{ // unknown Ogg version
+			return false;
+		}
+		if(!(oggPageHeaderType & 0x02) || (oggPageHeaderType& 0x01))
+		{ // not BOS or continuation
+			return false;
+		}
+		if(oggPageGranulePosition != 0)
+		{ // not starting position
+			return false;
+		}
+		if(oggPageSequenceNumber != 0)
+		{ // not first page
+			return false;
+		}
+		// skip CRC check for now
+		if(oggPageSegments != 1)
+		{ // first OggFlac page must contain exactly 1 segment
+			return false;
+		}
+		if(oggPageSegmentLength != 51)
+		{ // segment length must be 51 bytes in OggFlac mapping
+			return false;
+		}
+		if(file.ReadIntLE<uint8>() != 0x7f)
+		{ // OggFlac mapping demands 0x7f packet type
+			return false;
+		}
+		if(!file.ReadMagic("FLAC"))
+		{ // OggFlac magic
+			return false;
+		}
+		if(file.ReadIntLE<uint8>() != 0x01)
+		{ // OggFlac major version
+			return false;
+		}
+		// by now, we are pretty confident that we are not parsing random junk
+		isOgg = true;
+#endif // MPT_WITH_OGG
+	} else
+	{
+		return false;
+	}
+	file.Rewind();
+
+	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+	if(decoder == nullptr)
+	{
+		return false;
+	}
+
+#ifdef MPT_WITH_OGG
+	if(isOgg)
+	{
+		// force flac decoding of the logical bitstream that actually is OggFlac
+		if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, oggFlacBitstreamSerial))
+		{
+			FLAC__stream_decoder_delete(decoder);
+			return false;
+		}
+	}
+#endif
+
+	// Give me all the metadata!
+	FLAC__stream_decoder_set_metadata_respond_all(decoder);
+
+	FLACDecoder client(file, *this, sample);
+
+	// Init decoder
+	FLAC__StreamDecoderInitStatus initStatus = isOgg ?
+		FLAC__stream_decoder_init_ogg_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client)
+		:
+		FLAC__stream_decoder_init_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client)
+		;
+	if(initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+	{
+		FLAC__stream_decoder_delete(decoder);
+		return false;
+	}
+
+	// Decode file
+	FLAC__stream_decoder_process_until_end_of_stream(decoder);
+	FLAC__stream_decoder_finish(decoder);
+	FLAC__stream_decoder_delete(decoder);
+
+	if(client.ready && Samples[sample].pSample != nullptr)
+	{
+		Samples[sample].Convert(MOD_TYPE_IT, GetType());
+		Samples[sample].PrecomputeLoops(*this, false);
+		return true;
+	}
+#else
+	MPT_UNREFERENCED_PARAMETER(sample);
+	MPT_UNREFERENCED_PARAMETER(file);
+#endif // MPT_WITH_FLAC
+	return false;
+}
+
+
+#ifdef MPT_WITH_FLAC
+// Helper function for copying OpenMPT's sample data to FLAC's int32 buffer.
+template<typename T>
+inline static void SampleToFLAC32(FLAC__int32 *dst, const T *src, SmpLength numSamples)
+{
+	for(SmpLength i = 0; i < numSamples; i++)
+	{
+		dst[i] = src[i];
+	}
+};
+
+// RAII-style helper struct for FLAC encoder
+struct FLAC__StreamEncoder_RAII
+{
+	FLAC__StreamEncoder *encoder;
+	FILE *f;
+
+	operator FLAC__StreamEncoder *() { return encoder; }
+
+	FLAC__StreamEncoder_RAII() : encoder(FLAC__stream_encoder_new()), f(nullptr) { }
+	~FLAC__StreamEncoder_RAII()
+	{
+		FLAC__stream_encoder_delete(encoder);
+		if(f != nullptr) fclose(f);
+	}
+};
+
+#endif
+
+
+#ifndef MODPLUG_NO_FILESAVE
+bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, const mpt::PathString &filename) const
+{
+#ifdef MPT_WITH_FLAC
+	FLAC__StreamEncoder_RAII encoder;
+	if(encoder == nullptr)
+	{
+		return false;
+	}
+
+	const ModSample &sample = Samples[nSample];
+	uint32 sampleRate = sample.GetSampleRate(GetType());
+
+	// First off, set up all the metadata...
+	FLAC__StreamMetadata *metadata[] =
+	{
+		FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT),
+		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// MPT sample information
+		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// Loop points
+		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// Cue points
+	};
+
+	unsigned numBlocks = 2;
+	if(metadata[0])
+	{
+		// Store sample name
+		FLAC__StreamMetadata_VorbisComment_Entry entry;
+		FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", m_szNames[nSample]);
+		FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
+		FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ENCODER", MptVersion::GetOpenMPTVersionStr().c_str());
+		FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
+		if(sampleRate > FLAC__MAX_SAMPLE_RATE)
+		{
+			// FLAC only supports a sample rate of up to 655350 Hz.
+			// Store the real sample rate in a custom Vorbis comment.
+			FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "SAMPLERATE", mpt::fmt::val(sampleRate).c_str());
+			FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
+		}
+	}
+	if(metadata[1])
+	{
+		// Write MPT sample information
+		memcpy(metadata[1]->data.application.id, "riff", 4);
+
+		struct
+		{
+			RIFFChunk header;
+			WAVExtraChunk mptInfo;
+		} chunk;
+
+		chunk.header.id = RIFFChunk::idxtra;
+		chunk.header.length = sizeof(WAVExtraChunk);
+
+		chunk.mptInfo.ConvertToWAV(sample, GetType());
+
+		const uint32 length = sizeof(RIFFChunk) + sizeof(WAVExtraChunk);
+
+		FLAC__metadata_object_application_set_data(metadata[1], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
+	}
+	if(metadata[numBlocks] && (sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP] || ModCommand::IsNote(sample.rootNote)))
+	{
+		// Store loop points / root note information
+		memcpy(metadata[numBlocks]->data.application.id, "riff", 4);
+
+		struct
+		{
+			RIFFChunk header;
+			WAVSampleInfoChunk info;
+			WAVSampleLoop loops[2];
+		} chunk;
+
+		chunk.header.id = RIFFChunk::idsmpl;
+		chunk.header.length = sizeof(WAVSampleInfoChunk);
+
+		chunk.info.ConvertToWAV(sample.GetSampleRate(GetType()), sample.rootNote);
+
+		if(sample.uFlags[CHN_SUSTAINLOOP])
+		{
+			chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nSustainStart, sample.nSustainEnd, sample.uFlags[CHN_PINGPONGSUSTAIN]);
+			chunk.header.length += sizeof(WAVSampleLoop);
+		}
+		if(sample.uFlags[CHN_LOOP])
+		{
+			chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nLoopStart, sample.nLoopEnd, sample.uFlags[CHN_PINGPONGLOOP]);
+			chunk.header.length += sizeof(WAVSampleLoop);
+		}
+
+		const uint32 length = sizeof(RIFFChunk) + chunk.header.length;
+
+		FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
+		numBlocks++;
+	}
+	if(metadata[numBlocks] && sample.HasCustomCuePoints())
+	{
+		// Store cue points
+		memcpy(metadata[numBlocks]->data.application.id, "riff", 4);
+
+		struct
+		{
+			RIFFChunk header;
+			uint32le numPoints;
+			WAVCuePoint cues[CountOf(sample.cues)];
+		} chunk;
+
+		chunk.header.id = RIFFChunk::idcue_;
+		chunk.header.length = 4 + sizeof(chunk.cues);
+		chunk.numPoints = CountOf(sample.cues);
+
+		for(uint32 i = 0; i < CountOf(sample.cues); i++)
+		{
+			chunk.cues[i].ConvertToWAV(i, sample.cues[i]);
+		}
+
+		const uint32 length = sizeof(RIFFChunk) + chunk.header.length;
+
+		FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
+		numBlocks++;
+	}
+
+	// FLAC allows a maximum sample rate of 655350 Hz.
+	// If the real rate is higher, we store it in a Vorbis comment above.
+	LimitMax(sampleRate, FLAC__MAX_SAMPLE_RATE);
+	if(!FLAC__format_sample_rate_is_subset(sampleRate))
+	{
+		// FLAC only supports 10 Hz granularity for frequencies above 65535 Hz if the streamable subset is chosen.
+		FLAC__stream_encoder_set_streamable_subset(encoder, false);
+	}
+	FLAC__stream_encoder_set_channels(encoder, sample.GetNumChannels());
+	FLAC__stream_encoder_set_bits_per_sample(encoder, sample.GetElementarySampleSize() * 8);
+	FLAC__stream_encoder_set_sample_rate(encoder, sampleRate);
+	FLAC__stream_encoder_set_total_samples_estimate(encoder, sample.nLength);
+	FLAC__stream_encoder_set_metadata(encoder, metadata, numBlocks);
+#ifdef MODPLUG_TRACKER
+	FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel);
+#endif // MODPLUG_TRACKER
+
+	bool result = false;
+	FLAC__int32 *sampleData = nullptr;
+
+	encoder.f = mpt_fopen(filename, "wb");
+	if(encoder.f == nullptr || FLAC__stream_encoder_init_FILE(encoder, encoder.f, nullptr, nullptr) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+	{
+		goto fail;
+	}
+
+	// Convert sample data to signed 32-Bit integer array.
+	const SmpLength numSamples = sample.nLength * sample.GetNumChannels();
+	sampleData = new (std::nothrow) FLAC__int32[numSamples];
+	if(sampleData == nullptr)
+	{
+		goto fail;
+	}
+
+	if(sample.GetElementarySampleSize() == 1)
+	{
+		SampleToFLAC32(sampleData, sample.pSample8, numSamples);
+	} else if(sample.GetElementarySampleSize() == 2)
+	{
+		SampleToFLAC32(sampleData, sample.pSample16, numSamples);
+	} else
+	{
+		MPT_ASSERT_NOTREACHED();
+	}
+
+	// Do the actual conversion.
+	FLAC__stream_encoder_process_interleaved(encoder, sampleData, sample.nLength);
+	result = true;
+
+fail:
+	FLAC__stream_encoder_finish(encoder);
+
+	delete[] sampleData;
+	for(auto m : metadata)
+	{
+		FLAC__metadata_object_delete(m);
+	}
+
+	return result;
+#else
+	MPT_UNREFERENCED_PARAMETER(nSample);
+	MPT_UNREFERENCED_PARAMETER(filename);
+	return false;
+#endif // MPT_WITH_FLAC
+}
+#endif // MODPLUG_NO_FILESAVE
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormatMP3.cpp b/soundlib/SampleFormatMP3.cpp
new file mode 100644
index 0000000..ecb7600
--- /dev/null
+++ b/soundlib/SampleFormatMP3.cpp
@@ -0,0 +1,384 @@
+/*
+ * SampleFormatMP3.cpp
+ * -------------------
+ * Purpose: MP3 sample import.
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Sndfile.h"
+#ifndef MODPLUG_NO_FILESAVE
+#include "../common/mptFileIO.h"
+#endif
+#include "../common/misc_util.h"
+#include "Tagging.h"
+#include "Loaders.h"
+#include "ChunkReader.h"
+#include "modsmp_ctrl.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
+#include "../common/ComponentManager.h"
+#ifdef MPT_ENABLE_MP3_SAMPLES
+#include "MPEGFrame.h"
+#endif // MPT_ENABLE_MP3_SAMPLES
+#if defined(MPT_WITH_MINIMP3)
+extern "C" {
+#include <minimp3/minimp3.h>
+}
+#endif // MPT_WITH_MINIMP3
+
+// mpg123 must be last because of mpg123 large file support insanity
+#if defined(MPT_WITH_MPG123)
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <mpg123.h>
+
+#endif
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// MP3 Samples
+
+#if defined(MPT_WITH_MPG123)
+
+#if MPT_COMPILER_MSVCCLANGC2
+typedef _off_t mpg123_off_t;
+#else // !MPT_COMPILER_MSVCCLANGC2
+typedef off_t mpg123_off_t;
+#endif // MPT_COMPILER_MSVCCLANGC2
+
+typedef size_t mpg123_size_t;
+
+typedef ssize_t mpg123_ssize_t;
+
+class ComponentMPG123
+#if defined(MPT_BUILD_MSVC_STATIC) && !MPT_OS_WINDOWS_WINRT
+	: public ComponentBundledDLL
+#else
+	: public ComponentBuiltin
+#endif
+{
+	MPT_DECLARE_COMPONENT_MEMBERS
+
+public:
+
+	static mpg123_ssize_t FileReaderRead(void *fp, void *buf, mpg123_size_t count)
+	{
+		FileReader &file = *static_cast<FileReader *>(fp);
+		size_t readBytes = std::min(count, static_cast<size_t>(file.BytesLeft()));
+		file.ReadRaw(static_cast<char *>(buf), readBytes);
+		return readBytes;
+	}
+	static mpg123_off_t FileReaderLSeek(void *fp, mpg123_off_t offset, int whence)
+	{
+		FileReader &file = *static_cast<FileReader *>(fp);
+		FileReader::off_t oldpos = file.GetPosition();
+		if(whence == SEEK_CUR) file.Seek(file.GetPosition() + offset);
+		else if(whence == SEEK_END) file.Seek(file.GetLength() + offset);
+		else file.Seek(offset);
+		MPT_MAYBE_CONSTANT_IF(!Util::TypeCanHoldValue<mpg123_off_t>(file.GetPosition()))
+		{
+			file.Seek(oldpos);
+			return static_cast<mpg123_off_t>(-1);
+		}
+		return static_cast<mpg123_off_t>(file.GetPosition());
+	}
+
+public:
+	ComponentMPG123()
+#if defined(MPT_BUILD_MSVC_STATIC) && !MPT_OS_WINDOWS_WINRT
+		: ComponentBundledDLL(MPT_PATHSTRING("openmpt-mpg123"))
+#else
+		: ComponentBuiltin()
+#endif
+	{
+		return;
+	}
+	bool DoInitialize()
+	{
+#if defined(MPT_BUILD_MSVC_STATIC) && !MPT_OS_WINDOWS_WINRT
+		if(!ComponentBundledDLL::DoInitialize())
+		{
+			return false;
+		}
+#endif
+		if(mpg123_init() != 0)
+		{
+			return false;
+		}
+		return true;
+	}
+	virtual ~ComponentMPG123()
+	{
+		if(IsAvailable())
+		{
+			mpg123_exit();
+		}
+	}
+};
+MPT_REGISTERED_COMPONENT(ComponentMPG123, "Mpg123")
+
+#endif // MPT_WITH_MPG123
+
+
+bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode)
+{
+#if defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3)
+
+	// Check file for validity, or else mpg123 will happily munch many files that start looking vaguely resemble an MPEG stream mid-file.
+	file.Rewind();
+	while(file.CanRead(4))
+	{
+		uint8 magic[3];
+		file.ReadArray(magic);
+
+		if(!memcmp(magic, "ID3", 3))
+		{
+			// Skip ID3 tags
+			uint8 header[7];
+			file.ReadArray(header);
+
+			uint32 size = 0;
+			for(int i = 3; i < 7; i++)
+			{
+				if(header[i] & 0x80)
+					return false;
+				size = (size << 7) | header[i];
+			}
+			file.Skip(size);
+		} else if(!memcmp(magic, "APE", 3) && file.ReadMagic("TAGEX"))
+		{
+			// Skip APE tags
+			uint32 size = file.ReadUint32LE();
+			file.Skip(16 + size);
+		} else if(!memcmp(magic, "\x00\x00\x00", 3) || !memcmp(magic, "\xFF\x00\x00", 3))
+		{
+			// Some MP3 files are padded with zeroes...
+		} else if(magic[0] == 0)
+		{
+			// This might be some padding, followed by an MPEG header, so try again.
+			file.SkipBack(2);
+		} else if(MPEGFrame::IsMPEGHeader(magic))
+		{
+			// This is what we want!
+			break;
+		} else
+		{
+			// This, on the other hand, isn't.
+			return false;
+		}
+	}
+
+#endif // MPT_WITH_MPG123 || MPT_WITH_MINIMP3
+
+#if defined(MPT_WITH_MPG123)
+
+	ComponentHandle<ComponentMPG123> mpg123;
+	if(!IsComponentAvailable(mpg123))
+	{
+		return false;
+	}
+
+	mpg123_handle *mh;
+	int err;
+	if((mh = mpg123_new(0, &err)) == nullptr)
+	{
+		return false;
+	}
+	file.Rewind();
+
+	long rate; int nchannels, encoding;
+	SmpLength length;
+	// Set up decoder...
+	if(mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0))
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+	if(mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0))
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+	if(mpg123_open_handle(mh, &file))
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+	if(mpg123_scan(mh))
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+	if(mpg123_getformat(mh, &rate, &nchannels, &encoding))
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+	if(!nchannels || nchannels > 2 || (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED))
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+	length = mpg123_length(mh);
+	if(length == 0)
+	{
+		mpg123_delete(mh);
+		return false;
+	}
+
+	DestroySampleThreadsafe(sample);
+	if(!mo3Decode)
+	{
+		strcpy(m_szNames[sample], "");
+		Samples[sample].Initialize();
+		Samples[sample].nC5Speed = rate;
+	}
+	Samples[sample].nLength = length;
+
+	Samples[sample].uFlags.set(CHN_16BIT);
+	Samples[sample].uFlags.set(CHN_STEREO, nchannels == 2);
+	Samples[sample].AllocateSample();
+
+	if(Samples[sample].pSample != nullptr)
+	{
+		mpg123_size_t ndecoded = 0;
+		mpg123_read(mh, static_cast<unsigned char *>(Samples[sample].pSample), Samples[sample].GetSampleSizeInBytes(), &ndecoded);
+	}
+	mpg123_delete(mh);
+
+	if(!mo3Decode)
+	{
+		Samples[sample].Convert(MOD_TYPE_IT, GetType());
+		Samples[sample].PrecomputeLoops(*this, false);
+	}
+	return Samples[sample].pSample != nullptr;
+
+#elif defined(MPT_WITH_MINIMP3)
+
+	file.Rewind();
+	FileReader::PinnedRawDataView rawDataView = file.GetPinnedRawDataView();
+	int64 bytes_left = rawDataView.size();
+	const uint8 *stream_pos = mpt::byte_cast<const uint8 *>(rawDataView.data());
+
+	std::vector<int16> raw_sample_data;
+
+	mp3_decoder_t *mp3 = mp3_create();
+	
+	int rate = 0;
+	int channels = 0;
+
+	mp3_info_t info;
+	int frame_size = 0;
+	do
+	{
+		int16 sample_buf[MP3_MAX_SAMPLES_PER_FRAME];
+		frame_size = mp3_decode(mp3, const_cast<uint8 *>(stream_pos), mpt::saturate_cast<int>(bytes_left), sample_buf, &info); // workaround lack of const qualifier in mp3_decode (all internal functions have the required const correctness)
+		if(rate != 0 && rate != info.sample_rate) break; // inconsistent stream
+		if(channels != 0 && channels != info.channels) break; // inconsistent stream
+		rate = info.sample_rate;
+		channels = info.channels;
+		if(rate <= 0) break; // broken stream
+		if(channels != 1 && channels != 2) break; // broken stream
+		stream_pos += frame_size;
+		bytes_left -= frame_size;
+		if(info.audio_bytes >= 0)
+		{
+			try
+			{
+				raw_sample_data.insert(raw_sample_data.end(), sample_buf, sample_buf + (info.audio_bytes / sizeof(int16)));
+			} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+			{
+				MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+				break;
+			}
+		}
+	} while((bytes_left >= 0) && (frame_size > 0));
+
+	mp3_free(mp3);
+
+	if(rate == 0 || channels == 0 || raw_sample_data.empty())
+	{
+		return false;
+	}
+
+	DestroySampleThreadsafe(sample);
+	if(!mo3Decode)
+	{
+		strcpy(m_szNames[sample], "");
+		Samples[sample].Initialize();
+		Samples[sample].nC5Speed = rate;
+	}
+	Samples[sample].nLength = raw_sample_data.size() / channels;
+
+	Samples[sample].uFlags.set(CHN_16BIT);
+	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
+	Samples[sample].AllocateSample();
+
+	if(Samples[sample].pSample != nullptr)
+	{
+		std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);
+	}
+
+	if(!mo3Decode)
+	{
+		Samples[sample].Convert(MOD_TYPE_IT, GetType());
+		Samples[sample].PrecomputeLoops(*this, false);
+	}
+	return Samples[sample].pSample != nullptr;
+
+#else
+
+	MPT_UNREFERENCED_PARAMETER(sample);
+	MPT_UNREFERENCED_PARAMETER(file);
+	MPT_UNREFERENCED_PARAMETER(mo3Decode);
+
+#endif // MPT_WITH_MPG123 || MPT_WITH_MINIMP3
+
+	return false;
+}
+
+
+bool CSoundFile::CanReadMP3()
+{
+	bool result = false;
+	#if defined(MPT_WITH_MPG123)
+		if(!result)
+		{
+			ComponentHandle<ComponentMPG123> mpg123;
+			if(IsComponentAvailable(mpg123))
+			{
+				result = true;
+			}
+		}
+	#endif
+	#if defined(MPT_WITH_MINIMP3)
+		if(!result)
+		{
+			result = true;
+		}
+	#endif
+	#if defined(MPT_WITH_MEDIAFOUNDATION)
+		if(!result)
+		{
+			if(CanReadMediaFoundation())
+			{
+				result = true;
+			}
+		}
+	#endif
+	return result;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormatMediaFoundation.cpp b/soundlib/SampleFormatMediaFoundation.cpp
new file mode 100644
index 0000000..ad1e076
--- /dev/null
+++ b/soundlib/SampleFormatMediaFoundation.cpp
@@ -0,0 +1,492 @@
+/*
+ * SampleFormatMediaSoundation.cpp
+ * -------------------------------
+ * Purpose: MediaFoundation sample import.
+ * Notes  :
+ * Authors: Joern Heusipp
+ *          OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Sndfile.h"
+#ifndef MODPLUG_NO_FILESAVE
+#include "../common/mptFileIO.h"
+#endif
+#include "../common/misc_util.h"
+#include "Tagging.h"
+#include "Loaders.h"
+#include "ChunkReader.h"
+#include "modsmp_ctrl.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
+#include "../common/ComponentManager.h"
+#if defined(MPT_WITH_MEDIAFOUNDATION)
+#include <windows.h>
+#include <mfapi.h>
+#include <mfidl.h>
+#include <mfreadwrite.h>
+#include <mferror.h>
+#include <Propvarutil.h>
+#endif // MPT_WITH_MEDIAFOUNDATION
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#if defined(MPT_WITH_MEDIAFOUNDATION)
+
+template <typename T>
+static void mptMFSafeRelease(T **ppT)
+{
+	if(*ppT)
+	{
+		(*ppT)->Release();
+		*ppT = NULL;
+	}
+}
+
+#define MPT_MF_CHECKED(x) MPT_DO { \
+	HRESULT hr = (x); \
+	if(!SUCCEEDED(hr)) \
+	{ \
+		goto fail; \
+	} \
+} MPT_WHILE_0
+
+// Implementing IMFByteStream is apparently not enough to stream raw bytes
+// data to MediaFoundation.
+// Additionally, one has to also implement a custom IMFAsyncResult for the
+// BeginRead/EndRead interface which allows transferring the number of read
+// bytes around.
+// To make things even worse, MediaFoundation fails to detect some AAC and MPEG
+// files if a non-file-based or read-only stream is used for opening.
+// The only sane option which remains if we do not have an on-disk filename
+// available:
+//  1 - write a temporary file
+//  2 - close it
+//  3 - open it using MediaFoundation.
+// We use FILE_ATTRIBUTE_TEMPORARY which will try to keep the file data in
+// memory just like regular allocated memory and reduce the overhead basically
+// to memcpy.
+
+static FileTags ReadMFMetadata(IMFMediaSource *mediaSource)
+{
+
+	FileTags tags;
+
+	IMFPresentationDescriptor *presentationDescriptor = NULL;
+	DWORD streams = 0;
+	IMFMetadataProvider *metadataProvider = NULL;
+	IMFMetadata *metadata = NULL;
+	PROPVARIANT varPropNames;
+	PropVariantInit(&varPropNames);
+
+	MPT_MF_CHECKED(mediaSource->CreatePresentationDescriptor(&presentationDescriptor));
+	MPT_MF_CHECKED(presentationDescriptor->GetStreamDescriptorCount(&streams));
+	MPT_MF_CHECKED(MFGetService(mediaSource, MF_METADATA_PROVIDER_SERVICE, IID_IMFMetadataProvider, (void**)&metadataProvider));
+	MPT_MF_CHECKED(metadataProvider->GetMFMetadata(presentationDescriptor, 0, 0, &metadata));
+
+	MPT_MF_CHECKED(metadata->GetAllPropertyNames(&varPropNames));
+	for(DWORD propIndex = 0; propIndex < varPropNames.calpwstr.cElems; ++propIndex)
+	{
+
+		PROPVARIANT propVal;
+		PropVariantInit(&propVal);
+
+		LPWSTR propName = varPropNames.calpwstr.pElems[propIndex];
+		if(S_OK != metadata->GetProperty(propName, &propVal))
+		{
+			PropVariantClear(&propVal);
+			break;
+		}
+
+		std::wstring stringVal;
+		std::vector<WCHAR> wcharVal(256);
+#if !MPT_OS_WINDOWS_WINRT
+		// WTF, no PropVariantToString() in WinRT 
+		for(;;)
+		{
+			HRESULT hrToString = PropVariantToString(propVal, wcharVal.data(), mpt::saturate_cast<UINT>(wcharVal.size()));
+			if(hrToString == S_OK)
+			{
+				stringVal = wcharVal.data();
+				break;
+			} else if(hrToString == ERROR_INSUFFICIENT_BUFFER)
+			{
+				wcharVal.resize(wcharVal.size() * 2);
+			} else
+			{
+				break;
+			}
+		}
+#endif // !MPT_OS_WINDOWS_WINRT
+
+		PropVariantClear(&propVal);
+
+		if(stringVal.length() > 0)
+		{
+			if(propName == std::wstring(L"Author")) tags.artist = mpt::ToUnicode(stringVal);
+			if(propName == std::wstring(L"Title")) tags.title = mpt::ToUnicode(stringVal);
+			if(propName == std::wstring(L"WM/AlbumTitle")) tags.album = mpt::ToUnicode(stringVal);
+			if(propName == std::wstring(L"WM/Track")) tags.trackno = mpt::ToUnicode(stringVal);
+			if(propName == std::wstring(L"WM/Year")) tags.year = mpt::ToUnicode(stringVal);
+			if(propName == std::wstring(L"WM/Genre")) tags.genre = mpt::ToUnicode(stringVal);
+		}
+	}
+
+fail:
+
+	PropVariantClear(&varPropNames);
+	mptMFSafeRelease(&metadata);
+	mptMFSafeRelease(&metadataProvider);
+	mptMFSafeRelease(&presentationDescriptor);
+
+	return tags;
+
+}
+
+
+class ComponentMediaFoundation : public ComponentLibrary
+{
+	MPT_DECLARE_COMPONENT_MEMBERS
+public:
+	ComponentMediaFoundation()
+		: ComponentLibrary(ComponentTypeSystem)
+	{
+		return;
+	}
+	virtual bool DoInitialize()
+	{
+		if(!mpt::Windows::Version::Current().IsAtLeast(mpt::Windows::Version::Win7))
+		{
+			return false;
+		}
+#if !MPT_OS_WINDOWS_WINRT
+		if(!(true
+			&& AddLibrary("mf", mpt::LibraryPath::System(MPT_PATHSTRING("mf")))
+			&& AddLibrary("mfplat", mpt::LibraryPath::System(MPT_PATHSTRING("mfplat")))
+			&& AddLibrary("mfreadwrite", mpt::LibraryPath::System(MPT_PATHSTRING("mfreadwrite")))
+			&& AddLibrary("propsys", mpt::LibraryPath::System(MPT_PATHSTRING("propsys")))
+			))
+		{
+			return false;
+		}
+#endif // !MPT_OS_WINDOWS_WINRT
+		if(!SUCCEEDED(MFStartup(MF_VERSION)))
+		{
+			return false;
+		}
+		return true;
+	}
+	virtual ~ComponentMediaFoundation()
+	{
+		if(IsAvailable())
+		{
+			MFShutdown();
+		}
+	}
+};
+MPT_REGISTERED_COMPONENT(ComponentMediaFoundation, "MediaFoundation")
+
+#endif // MPT_WITH_MEDIAFOUNDATION
+
+
+#ifdef MODPLUG_TRACKER
+std::vector<FileType> CSoundFile::GetMediaFoundationFileTypes()
+{
+	std::vector<FileType> result;
+
+#if defined(MPT_WITH_MEDIAFOUNDATION)
+
+	ComponentHandle<ComponentMediaFoundation> mf;
+	if(!IsComponentAvailable(mf))
+	{
+		return result;
+	}
+
+	std::map<std::wstring, FileType> guidMap;
+
+	HKEY hkHandlers = NULL;
+	LSTATUS regResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers", 0, KEY_READ, &hkHandlers);
+	if(regResult != ERROR_SUCCESS)
+	{
+		return result;
+	}
+
+	for(DWORD handlerIndex = 0; ; ++handlerIndex)
+	{
+
+		WCHAR handlerTypeBuf[256];
+		MemsetZero(handlerTypeBuf);
+		regResult = RegEnumKeyW(hkHandlers, handlerIndex, handlerTypeBuf, 256);
+		if(regResult != ERROR_SUCCESS)
+		{
+			break;
+		}
+
+		std::wstring handlerType = handlerTypeBuf;
+
+		if(handlerType.length() < 1)
+		{
+			continue;
+		}
+
+		HKEY hkHandler = NULL;
+		regResult = RegOpenKeyExW(hkHandlers, handlerTypeBuf, 0, KEY_READ, &hkHandler);
+		if(regResult != ERROR_SUCCESS)
+		{
+			continue;
+		}
+
+		for(DWORD valueIndex = 0; ; ++valueIndex)
+		{
+			WCHAR valueNameBuf[16384];
+			MemsetZero(valueNameBuf);
+			DWORD valueNameBufLen = 16384;
+			DWORD valueType = 0;
+			BYTE valueData[16384];
+			MemsetZero(valueData);
+			DWORD valueDataLen = 16384;
+			regResult = RegEnumValueW(hkHandler, valueIndex, valueNameBuf, &valueNameBufLen, NULL, &valueType, valueData, &valueDataLen);
+			if(regResult != ERROR_SUCCESS)
+			{
+				break;
+			}
+			if(valueNameBufLen <= 0 || valueType != REG_SZ || valueDataLen <= 0)
+			{
+				continue;
+			}
+
+			std::wstring guid = std::wstring(valueNameBuf);
+
+			mpt::ustring description = mpt::ToUnicode(std::wstring(reinterpret_cast<WCHAR*>(valueData)));
+			description = mpt::String::Replace(description, MPT_USTRING("Byte Stream Handler"), MPT_USTRING("Files"));
+			description = mpt::String::Replace(description, MPT_USTRING("ByteStreamHandler"), MPT_USTRING("Files"));
+
+			guidMap[guid]
+				.ShortName(MPT_USTRING("mf"))
+				.Description(description)
+				;
+
+			if(handlerType[0] == L'.')
+			{
+				guidMap[guid].AddExtension(mpt::PathString::FromWide(handlerType.substr(1)));
+			} else
+			{
+				guidMap[guid].AddMimeType(mpt::ToCharset(mpt::CharsetASCII, handlerType));
+			}
+
+		}
+
+		RegCloseKey(hkHandler);
+		hkHandler = NULL;
+
+	}
+
+	RegCloseKey(hkHandlers);
+	hkHandlers = NULL;
+
+	for(const auto &it : guidMap)
+	{
+		result.push_back(it.second);
+	}
+
+#endif // MPT_WITH_MEDIAFOUNDATION
+
+	return result;
+}
+#endif // MODPLUG_TRACKER
+
+
+bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode)
+{
+
+#if !defined(MPT_WITH_MEDIAFOUNDATION)
+
+	MPT_UNREFERENCED_PARAMETER(sample);
+	MPT_UNREFERENCED_PARAMETER(file);
+	MPT_UNREFERENCED_PARAMETER(mo3Decode);
+	return false;
+
+#else
+
+	ComponentHandle<ComponentMediaFoundation> mf;
+	if(!IsComponentAvailable(mf))
+	{
+		return false;
+	}
+
+	file.Rewind();
+	// When using MF to decode MP3 samples in MO3 files, we need the mp3 file extension
+	// for some of them or otherwise MF refuses to recognize them.
+	mpt::PathString tmpfileExtension = (mo3Decode ? MPT_PATHSTRING("mp3") : MPT_PATHSTRING("tmp"));
+	OnDiskFileWrapper diskfile(file, tmpfileExtension);
+	if(!diskfile.IsValid())
+	{
+		return false;
+	}
+
+	bool result = false;
+
+	std::vector<char> rawData;
+	FileTags tags;
+	std::string sampleName;
+
+	IMFSourceResolver *sourceResolver = NULL;
+	MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID;
+	IUnknown *unknownMediaSource = NULL;
+	IMFMediaSource *mediaSource = NULL;
+	IMFSourceReader *sourceReader = NULL;
+	IMFMediaType *uncompressedAudioType = NULL;
+	IMFMediaType *partialType = NULL;
+	UINT32 numChannels = 0;
+	UINT32 samplesPerSecond = 0;
+	UINT32 bitsPerSample = 0;
+
+	IMFSample *mfSample = NULL;
+	DWORD mfSampleFlags = 0;
+	IMFMediaBuffer *buffer = NULL;
+
+	SmpLength length = 0;
+
+	MPT_MF_CHECKED(MFCreateSourceResolver(&sourceResolver));
+	MPT_MF_CHECKED(sourceResolver->CreateObjectFromURL(diskfile.GetFilename().AsNative().c_str(), MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ, NULL, &objectType, &unknownMediaSource));
+	if(objectType != MF_OBJECT_MEDIASOURCE) goto fail;
+	MPT_MF_CHECKED(unknownMediaSource->QueryInterface(&mediaSource));
+
+	tags = ReadMFMetadata(mediaSource);
+
+	MPT_MF_CHECKED(MFCreateSourceReaderFromMediaSource(mediaSource, NULL, &sourceReader));
+	MPT_MF_CHECKED(MFCreateMediaType(&partialType));
+	MPT_MF_CHECKED(partialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
+	MPT_MF_CHECKED(partialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM));
+	MPT_MF_CHECKED(sourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, partialType));
+	MPT_MF_CHECKED(sourceReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &uncompressedAudioType));
+	MPT_MF_CHECKED(sourceReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE));
+	MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &numChannels));
+	MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond));
+	MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample));
+	if(numChannels <= 0 || numChannels > 2) goto fail;
+	if(samplesPerSecond <= 0) goto fail;
+	if(bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) goto fail;
+
+	for(;;)
+	{
+		mfSampleFlags = 0;
+		MPT_MF_CHECKED(sourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &mfSampleFlags, NULL, &mfSample));
+		if(mfSampleFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
+		{
+			break;
+		}
+		if(mfSampleFlags & MF_SOURCE_READERF_ENDOFSTREAM)
+		{
+			break;
+		}
+		MPT_MF_CHECKED(mfSample->ConvertToContiguousBuffer(&buffer));
+		{
+			BYTE *data = NULL;
+			DWORD dataSize = 0;
+			MPT_MF_CHECKED(buffer->Lock(&data, NULL, &dataSize));
+			rawData.insert(rawData.end(), mpt::byte_cast<char*>(data), mpt::byte_cast<char*>(data + dataSize));
+			MPT_MF_CHECKED(buffer->Unlock());
+		}
+		mptMFSafeRelease(&buffer);
+		mptMFSafeRelease(&mfSample);
+	}
+
+	mptMFSafeRelease(&uncompressedAudioType);
+	mptMFSafeRelease(&partialType);
+	mptMFSafeRelease(&sourceReader);
+
+	sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(tags));
+
+	if(rawData.size() / numChannels / (bitsPerSample / 8) > MAX_SAMPLE_LENGTH)
+	{
+		result = false;
+		goto fail;
+	}
+
+	length = static_cast<SmpLength>(rawData.size() / numChannels / (bitsPerSample/8));
+
+	DestroySampleThreadsafe(sample);
+	if(!mo3Decode)
+	{
+		mpt::String::Copy(m_szNames[sample], sampleName);
+		Samples[sample].Initialize();
+		Samples[sample].nC5Speed = samplesPerSecond;
+	}
+	Samples[sample].nLength = length;
+	Samples[sample].uFlags.set(CHN_16BIT, bitsPerSample >= 16);
+	Samples[sample].uFlags.set(CHN_STEREO, numChannels == 2);
+	Samples[sample].AllocateSample();
+	if(Samples[sample].pSample == nullptr)
+	{
+		result = false;
+		goto fail;
+	}
+
+	if(bitsPerSample == 24)
+	{
+		if(numChannels == 2)
+		{
+			CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(Samples[sample], rawData.data(), rawData.size());
+		} else
+		{
+			CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(Samples[sample], rawData.data(), rawData.size());
+		}
+	} else if(bitsPerSample == 32)
+	{
+		if(numChannels == 2)
+		{
+			CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(Samples[sample], rawData.data(), rawData.size());
+		} else
+		{
+			CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(Samples[sample], rawData.data(), rawData.size());
+		}
+	} else
+	{
+		// just copy
+		std::copy(rawData.data(), rawData.data() + rawData.size(), mpt::void_cast<char*>(Samples[sample].pSample));
+	}
+
+	result = true;
+
+fail:
+
+	mptMFSafeRelease(&buffer);
+	mptMFSafeRelease(&mfSample);
+	mptMFSafeRelease(&uncompressedAudioType);
+	mptMFSafeRelease(&partialType);
+	mptMFSafeRelease(&sourceReader);
+	mptMFSafeRelease(&mediaSource);
+	mptMFSafeRelease(&unknownMediaSource);
+	mptMFSafeRelease(&sourceResolver);
+
+	return result;
+
+#endif
+
+}
+
+
+bool CSoundFile::CanReadMediaFoundation()
+{
+	bool result = false;
+	#if defined(MPT_WITH_MEDIAFOUNDATION)
+		if(!result)
+		{
+			ComponentHandle<ComponentMediaFoundation> mf;
+			if(IsComponentAvailable(mf))
+			{
+				result = true;
+			}
+		}
+	#endif
+	return result;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormatOpus.cpp b/soundlib/SampleFormatOpus.cpp
new file mode 100644
index 0000000..5c92849
--- /dev/null
+++ b/soundlib/SampleFormatOpus.cpp
@@ -0,0 +1,183 @@
+/*
+ * SampleFormatOpus.cpp
+ * --------------------
+ * Purpose: Opus sample import.
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Sndfile.h"
+#ifndef MODPLUG_NO_FILESAVE
+#include "../common/mptFileIO.h"
+#endif
+#include "../common/misc_util.h"
+#include "Tagging.h"
+#include "Loaders.h"
+#include "ChunkReader.h"
+#include "modsmp_ctrl.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
+//#include "../common/mptCRC.h"
+#include "OggStream.h"
+#ifdef MPT_WITH_OGG
+#include <ogg/ogg.h>
+#endif // MPT_WITH_OGG
+#if defined(MPT_WITH_OPUSFILE)
+#include <opusfile.h>
+#endif
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Opus
+
+#if defined(MPT_WITH_OPUSFILE)
+
+static mpt::ustring UStringFromOpus(const char *str)
+{
+	return str ? mpt::ToUnicode(mpt::CharsetUTF8, str) : mpt::ustring();
+}
+
+static FileTags GetOpusFileTags(OggOpusFile *of)
+{
+	FileTags tags;
+	const OpusTags *ot = op_tags(of, -1);
+	if(!ot)
+	{
+		return tags;
+	}
+	tags.encoder = UStringFromOpus(opus_tags_query(ot, "ENCODER", 0));
+	tags.title = UStringFromOpus(opus_tags_query(ot, "TITLE", 0));
+	tags.comments = UStringFromOpus(opus_tags_query(ot, "DESCRIPTION", 0));
+	tags.bpm = UStringFromOpus(opus_tags_query(ot, "BPM", 0)); // non-standard
+	tags.artist = UStringFromOpus(opus_tags_query(ot, "ARTIST", 0));
+	tags.album = UStringFromOpus(opus_tags_query(ot, "ALBUM", 0));
+	tags.trackno = UStringFromOpus(opus_tags_query(ot, "TRACKNUMBER", 0));
+	tags.year = UStringFromOpus(opus_tags_query(ot, "DATE", 0));
+	tags.url = UStringFromOpus(opus_tags_query(ot, "CONTACT", 0));
+	tags.genre = UStringFromOpus(opus_tags_query(ot, "GENRE", 0));
+	return tags;
+}
+
+#endif // MPT_WITH_OPUSFILE
+
+bool CSoundFile::ReadOpusSample(SAMPLEINDEX sample, FileReader &file)
+{
+	file.Rewind();
+
+#if defined(MPT_WITH_OPUSFILE)
+
+	int rate = 0;
+	int channels = 0;
+	std::vector<int16> raw_sample_data;
+
+	FileReader initial = file.GetChunk(65536); // 512 is recommended by libopusfile
+	if(op_test(NULL, initial.GetRawData<unsigned char>(), initial.GetLength()) != 0)
+	{
+		return false;
+	}
+
+	OggOpusFile *of = op_open_memory(file.GetRawData<unsigned char>(), file.GetLength(), NULL);
+	if(!of)
+	{
+		return false;
+	}
+
+	rate = 48000;
+	channels = op_channel_count(of, -1);
+	if(rate <= 0 || channels <= 0)
+	{
+		op_free(of);
+		of = NULL;
+		return false;
+	}
+	if(channels > 2 || op_link_count(of) != 1)
+	{
+		// We downmix multichannel to stereo as recommended by Opus specification in
+		// case we are not able to handle > 2 channels.
+		// We also decode chained files as stereo even if they start with a mono
+		// stream, which simplifies handling of link boundaries for us.
+		channels = 2;
+	}
+
+	std::vector<int16> decodeBuf(120 * 48000 / 1000); // 120ms (max Opus packet), 48kHz
+	bool eof = false;
+	while(!eof)
+	{
+		int framesRead = 0;
+		if(channels == 2)
+		{
+			framesRead = op_read_stereo(of, &(decodeBuf[0]), static_cast<int>(decodeBuf.size()));
+		} else if(channels == 1)
+		{
+			framesRead = op_read(of, &(decodeBuf[0]), static_cast<int>(decodeBuf.size()), NULL);
+		}
+		if(framesRead > 0)
+		{
+			raw_sample_data.insert(raw_sample_data.end(), decodeBuf.begin(), decodeBuf.begin() + (framesRead * channels));
+		} else if(framesRead == 0)
+		{
+			eof = true;
+		} else if(framesRead == OP_HOLE)
+		{
+			// continue
+		} else
+		{
+			// other errors are fatal, stop decoding
+			eof = true;
+		}
+	}
+
+	op_free(of);
+	of = NULL;
+
+	if(raw_sample_data.empty())
+	{
+		return false;
+	}
+
+	if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH)
+	{
+		return false;
+	}
+
+	DestroySampleThreadsafe(sample);
+	strcpy(m_szNames[sample], "");
+	Samples[sample].Initialize();
+	Samples[sample].nC5Speed = rate;
+	Samples[sample].nLength = mpt::saturate_cast<SmpLength>(raw_sample_data.size() / channels);
+
+	Samples[sample].uFlags.set(CHN_16BIT);
+	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
+
+	if(!Samples[sample].AllocateSample())
+	{
+		return false;
+	}
+
+	std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);
+
+	Samples[sample].Convert(MOD_TYPE_IT, GetType());
+	Samples[sample].PrecomputeLoops(*this, false);
+
+	return true;
+
+#else // !MPT_WITH_OPUSFILE
+
+	MPT_UNREFERENCED_PARAMETER(sample);
+	MPT_UNREFERENCED_PARAMETER(file);
+
+	return false;
+
+#endif // MPT_WITH_OPUSFILE
+
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormatVorbis.cpp b/soundlib/SampleFormatVorbis.cpp
new file mode 100644
index 0000000..f97c25d
--- /dev/null
+++ b/soundlib/SampleFormatVorbis.cpp
@@ -0,0 +1,355 @@
+/*
+ * SampleFormatVorbis.cpp
+ * ----------------------
+ * Purpose: Vorbis sample import
+ * Notes  :
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Sndfile.h"
+#ifndef MODPLUG_NO_FILESAVE
+#include "../common/mptFileIO.h"
+#endif
+#include "../common/misc_util.h"
+#include "Tagging.h"
+#include "Loaders.h"
+#include "ChunkReader.h"
+#include "modsmp_ctrl.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
+//#include "../common/mptCRC.h"
+#include "OggStream.h"
+#ifdef MPT_WITH_OGG
+#include <ogg/ogg.h>
+#endif // MPT_WITH_OGG
+#if defined(MPT_WITH_VORBIS)
+#include <vorbis/codec.h>
+#endif
+#if defined(MPT_WITH_VORBISFILE)
+#include <vorbis/vorbisfile.h>
+#endif
+#ifdef MPT_WITH_STBVORBIS
+#include <stb_vorbis/stb_vorbis.c>
+#endif // MPT_WITH_STBVORBIS
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Vorbis
+
+#if defined(MPT_WITH_VORBISFILE)
+
+static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+	FileReader &file = *reinterpret_cast<FileReader*>(datasource);
+	return file.ReadRaw(mpt::void_cast<mpt::byte*>(ptr), size * nmemb) / size;
+}
+
+static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence)
+{
+	FileReader &file = *reinterpret_cast<FileReader*>(datasource);
+	switch(whence)
+	{
+	case SEEK_SET:
+		{
+			if(!Util::TypeCanHoldValue<FileReader::off_t>(offset))
+			{
+				return -1;
+			}
+			return file.Seek(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
+		}
+		break;
+	case SEEK_CUR:
+		{
+			if(offset < 0)
+			{
+				if(offset == std::numeric_limits<ogg_int64_t>::min())
+				{
+					return -1;
+				}
+				if(!Util::TypeCanHoldValue<FileReader::off_t>(0-offset))
+				{
+					return -1;
+				}
+				return file.SkipBack(mpt::saturate_cast<FileReader::off_t>(0 - offset)) ? 0 : -1;
+			} else
+			{
+				if(!Util::TypeCanHoldValue<FileReader::off_t>(offset))
+				{
+					return -1;
+				}
+				return file.Skip(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
+			}
+		}
+		break;
+	case SEEK_END:
+		{
+			if(!Util::TypeCanHoldValue<FileReader::off_t>(offset))
+			{
+				return -1;
+			}
+			if(!Util::TypeCanHoldValue<FileReader::off_t>(file.GetLength() + offset))
+			{
+				return -1;
+			}
+			return file.Seek(mpt::saturate_cast<FileReader::off_t>(file.GetLength() + offset)) ? 0 : -1;
+		}
+		break;
+	default:
+		return -1;
+	}
+}
+
+static long VorbisfileFilereaderTell(void *datasource)
+{
+	FileReader &file = *reinterpret_cast<FileReader*>(datasource);
+	MPT_MAYBE_CONSTANT_IF(!Util::TypeCanHoldValue<long>(file.GetPosition()))
+	{
+		return -1;
+	}
+	return static_cast<long>(file.GetPosition());
+}
+
+#if defined(MPT_WITH_VORBIS)
+static mpt::ustring UStringFromVorbis(const char *str)
+{
+	return str ? mpt::ToUnicode(mpt::CharsetUTF8, str) : mpt::ustring();
+}
+#endif // MPT_WITH_VORBIS
+
+static FileTags GetVorbisFileTags(OggVorbis_File &vf)
+{
+	FileTags tags;
+	#if defined(MPT_WITH_VORBIS)
+		vorbis_comment *vc = ov_comment(&vf, -1);
+		if(!vc)
+		{
+			return tags;
+		}
+		tags.encoder = UStringFromVorbis(vorbis_comment_query(vc, "ENCODER", 0));
+		tags.title = UStringFromVorbis(vorbis_comment_query(vc, "TITLE", 0));
+		tags.comments = UStringFromVorbis(vorbis_comment_query(vc, "DESCRIPTION", 0));
+		tags.bpm = UStringFromVorbis(vorbis_comment_query(vc, "BPM", 0)); // non-standard
+		tags.artist = UStringFromVorbis(vorbis_comment_query(vc, "ARTIST", 0));
+		tags.album = UStringFromVorbis(vorbis_comment_query(vc, "ALBUM", 0));
+		tags.trackno = UStringFromVorbis(vorbis_comment_query(vc, "TRACKNUMBER", 0));
+		tags.year = UStringFromVorbis(vorbis_comment_query(vc, "DATE", 0));
+		tags.url = UStringFromVorbis(vorbis_comment_query(vc, "CONTACT", 0));
+		tags.genre = UStringFromVorbis(vorbis_comment_query(vc, "GENRE", 0));
+	#else // !MPT_WITH_VORBIS
+		MPT_UNREFERENCED_PARAMETER(vf);
+	#endif // MPT_WITH_VORBIS
+	return tags;
+}
+
+#endif // MPT_WITH_VORBISFILE
+
+bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file)
+{
+
+#if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS)
+
+	file.Rewind();
+
+	int rate = 0;
+	int channels = 0;
+	std::vector<int16> raw_sample_data;
+
+	std::string sampleName;
+
+#endif // VORBIS
+
+#if defined(MPT_WITH_VORBISFILE)
+
+	bool unsupportedSample = false;
+
+	ov_callbacks callbacks = {
+		&VorbisfileFilereaderRead,
+		&VorbisfileFilereaderSeek,
+		NULL,
+		&VorbisfileFilereaderTell
+	};
+	OggVorbis_File vf;
+	MemsetZero(vf);
+	if(ov_open_callbacks(&file, &vf, NULL, 0, callbacks) == 0)
+	{
+		if(ov_streams(&vf) == 1)
+		{ // we do not support chained vorbis samples
+			vorbis_info *vi = ov_info(&vf, -1);
+			if(vi && vi->rate > 0 && vi->channels > 0)
+			{
+				sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(GetVorbisFileTags(vf)));
+				rate = vi->rate;
+				channels = vi->channels;
+				std::size_t offset = 0;
+				int current_section = 0;
+				long decodedSamples = 0;
+				bool eof = false;
+				while(!eof)
+				{
+					float **output = nullptr;
+					long ret = ov_read_float(&vf, &output, 1024, &current_section);
+					if(ret == 0)
+					{
+						eof = true;
+					} else if(ret < 0)
+					{
+						// stream error, just try to continue
+					} else
+					{
+						decodedSamples = ret;
+						if(decodedSamples > 0 && (channels == 1 || channels == 2))
+						{
+							raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples));
+							for(int chn = 0; chn < channels; chn++)
+							{
+								CopyChannelToInterleaved<SC::Convert<int16, float> >(&(raw_sample_data[0]) + offset * channels, output[chn], channels, decodedSamples, chn);
+							}
+							offset += decodedSamples;
+						}
+					}
+				}
+			} else
+			{
+				unsupportedSample = true;
+			}
+		} else
+		{
+			unsupportedSample = true;
+		}
+		ov_clear(&vf);
+	} else
+	{
+		unsupportedSample = true;
+	}
+
+	if(unsupportedSample)
+	{
+		return false;
+	}
+
+#elif defined(MPT_WITH_STBVORBIS)
+
+	// NOTE/TODO: stb_vorbis does not handle inferred negative PCM sample position
+	// at stream start. (See
+	// <https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-132000A.2>). This
+	// means that, for remuxed and re-aligned/cutted (at stream start) Vorbis
+	// files, stb_vorbis will include superfluous samples at the beginning.
+
+	FileReader::PinnedRawDataView fileView = file.GetPinnedRawDataView();
+	const mpt::byte* data = fileView.data();
+	std::size_t dataLeft = fileView.size();
+
+	std::size_t offset = 0;
+	int consumed = 0;
+	int error = 0;
+	stb_vorbis *vorb = stb_vorbis_open_pushdata(data, mpt::saturate_cast<int>(dataLeft), &consumed, &error, nullptr);
+	file.Skip(consumed);
+	data += consumed;
+	dataLeft -= consumed;
+	if(!vorb)
+	{
+		return false;
+	}
+	rate = stb_vorbis_get_info(vorb).sample_rate;
+	channels = stb_vorbis_get_info(vorb).channels;
+	if(rate <= 0 || channels <= 0)
+	{
+		return false;
+	}
+	while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0)))
+	{
+		int frame_channels = 0;
+		int decodedSamples = 0;
+		float **output = nullptr;
+		consumed = stb_vorbis_decode_frame_pushdata(vorb, data, mpt::saturate_cast<int>(dataLeft), &frame_channels, &output, &decodedSamples);
+		file.Skip(consumed);
+		data += consumed;
+		dataLeft -= consumed;
+		LimitMax(frame_channels, channels);
+		if(decodedSamples > 0 && (frame_channels == 1 || frame_channels == 2))
+		{
+			raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples));
+			for(int chn = 0; chn < frame_channels; chn++)
+			{
+				CopyChannelToInterleaved<SC::Convert<int16, float> >(&(raw_sample_data[0]) + offset * channels, output[chn], channels, decodedSamples, chn);
+			}
+			offset += decodedSamples;
+		}
+		error = stb_vorbis_get_error(vorb);
+	}
+	stb_vorbis_close(vorb);
+
+#endif // VORBIS
+
+#if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS)
+
+	if(rate <= 0 || channels <= 0 || raw_sample_data.empty())
+	{
+		return false;
+	}
+
+	if((raw_sample_data.size() / channels) > MAX_SAMPLE_LENGTH)
+	{
+		return false;
+	}
+
+	DestroySampleThreadsafe(sample);
+	mpt::String::Copy(m_szNames[sample], sampleName);
+	Samples[sample].Initialize();
+	Samples[sample].nC5Speed = rate;
+	Samples[sample].nLength = mpt::saturate_cast<SmpLength>(raw_sample_data.size() / channels);
+
+	Samples[sample].uFlags.set(CHN_16BIT);
+	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
+
+	if(!Samples[sample].AllocateSample())
+	{
+		return false;
+	}
+
+	std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);
+
+	Samples[sample].Convert(MOD_TYPE_IT, GetType());
+	Samples[sample].PrecomputeLoops(*this, false);
+
+	return true;
+
+#else // !VORBIS
+
+	MPT_UNREFERENCED_PARAMETER(sample);
+	MPT_UNREFERENCED_PARAMETER(file);
+
+	return false;
+
+#endif // VORBIS
+
+}
+
+
+bool CSoundFile::CanReadVorbis()
+{
+	bool result = false;
+	#if defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
+		if(!result)
+		{
+			result = true;
+		}
+	#endif
+	#if defined(MPT_WITH_STBVORBIS)
+		if(!result)
+		{
+			result = true;
+		}
+	#endif
+	return result;
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleFormats.cpp b/soundlib/SampleFormats.cpp
index cd9267e..58b10cc 100644
--- a/soundlib/SampleFormats.cpp
+++ b/soundlib/SampleFormats.cpp
@@ -2,9 +2,8 @@
  * SampleFormats.cpp
  * -----------------
  * Purpose: Code for loading various more or less common sample and instrument formats.
- * Notes  : Needs a lot of rewriting.
- * Authors: Olivier Lapicque
- *          OpenMPT Devs
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  */
 
@@ -30,238 +29,16 @@
 #include "../common/version.h"
 #include "Loaders.h"
 #include "ChunkReader.h"
-#include "SampleFormatConverters.h"
-#include "../common/ComponentManager.h"
-#ifdef MPT_ENABLE_MP3_SAMPLES
-#include "MPEGFrame.h"
-#endif // MPT_ENABLE_MP3_SAMPLES
-//#include "../common/mptCRC.h"
-#include "OggStream.h"
-#ifdef MPT_WITH_OGG
-#include <ogg/ogg.h>
-#endif // MPT_WITH_OGG
-#ifdef MPT_WITH_FLAC
-#include <FLAC/stream_decoder.h>
-#include <FLAC/stream_encoder.h>
-#include <FLAC/metadata.h>
-#endif // MPT_WITH_FLAC
-#if defined(MPT_WITH_OPUSFILE)
-#include <opusfile.h>
-#endif
-#if defined(MPT_WITH_VORBIS)
-#include <vorbis/codec.h>
-#endif
-#if defined(MPT_WITH_VORBISFILE)
-#include <vorbis/vorbisfile.h>
-#endif
-#ifdef MPT_WITH_STBVORBIS
-#include <stb_vorbis/stb_vorbis.c>
-#endif // MPT_WITH_STBVORBIS
-#if defined(MPT_WITH_MINIMP3)
-extern "C" {
-#include <minimp3/minimp3.h>
-}
-#endif // MPT_WITH_MINIMP3
-#if defined(MPT_WITH_MEDIAFOUNDATION)
-#include <windows.h>
-#include <mfapi.h>
-#include <mfidl.h>
-#include <mfreadwrite.h>
-#include <mferror.h>
-#include <Propvarutil.h>
-#endif // MPT_WITH_MEDIAFOUNDATION
-
-// mpg123 must be last because of mpg123 largfile support insanity
-#if defined(MPT_WITH_MPG123)
-
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <mpg123.h>
-
-// check for utterly weird mpg123 largefile support
-
-#if !defined(MPG123_API_VERSION)
-#error "libmpg123 API version unknown. Assuming too old."
-#else
-
-#if (MPG123_API_VERSION < 11)
-#error "libmpg123 API version too old."
-
-#elif (MPG123_API_VERSION < 23)
-// OK
-
-#elif (MPG123_API_VERSION < 25) // < 1.12.0
-#if MPT_COMPILER_MSVC
-#pragma message("libmpg123 API version with split largefile support detected. This has not been tested at all.")
-#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
-#warning "libmpg123 API version with split largefile support detected. This has not been tested at all."
-#else
-// There is no portable way to display a warning.
-// Try to provoke a warning with an unused function.
-static void OpenMPT_libmpg123_API_version_with_split_largefile_support_detected__This_has_not_been_tested_at_all_() { }
-#endif
-
-#elif (MPG123_API_VERSION == 25) // == 1.12.x and some later
-// 1.12.2 introduced dumb wrappers for suffixed _32 and _64 functions.
-// We cannot detect whether it's one of the broken versions 1.12.0 or 1.12.1,
-// and thus have to implement a work-around for all of them (does not hurt though).
-#if defined(MPT_ARCH_BITS)
-#define MPT_LIBMPG123_WORKAROUND_LARGEFILE_SUFFIX
-#else // !MPT_ARCH_BITS
-#error message("libmpg123 API version largefile work-around requires MPT_ARCH_BITS to be defined. Please edit common/CompilerDetect.h and add support for your compiler.")
-#endif // MPT_ARCH_BITS
-
-#else // modern
-// OK
-
-#endif // MPG123_API_VERSION
-#endif // MPG123_API_VERSION
-
-#if defined(MPT_LIBMPG123_WORKAROUND_LARGEFILE_SUFFIX)
-
-#if !MPT_COMPILER_MSVC
-#if defined(_FILE_OFFSET_BITS) && !defined(MPG123_LARGESUFFIX)
-#if defined(MPT_ARCH_BITS)
-#if MPT_ARCH_BITS_64
-
-// We are always compiling with _FILE_OFFSET_BITS==64, even on 64 bit platforms.
-// libmpg123 does not provide the suffixed _64 versions in this case.
-// Thus, on 64 bit, #undef all the wrapper macros.
-
-extern "C" {
-
-#ifdef mpg123_open
-#undef mpg123_open
-#endif
-EXPORT int mpg123_open(mpg123_handle *mh, const char *path);
-
-#ifdef mpg123_open_fd
-#undef mpg123_open_fd
-#endif
-EXPORT int mpg123_open_fd(mpg123_handle *mh, int fd);
-
-#ifdef mpg123_open_handle
-#undef mpg123_open_handle
-#endif
-EXPORT int mpg123_open_handle(mpg123_handle *mh, void *iohandle);
-
-#ifdef mpg123_framebyframe_decode
-#undef mpg123_framebyframe_decode
-#endif
-EXPORT int mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes);
-
-#ifdef mpg123_decode_frame
-#undef mpg123_decode_frame
-#endif
-EXPORT int mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes);
-
-#ifdef mpg123_tell
-#undef mpg123_tell
-#endif
-EXPORT off_t mpg123_tell(mpg123_handle *mh);
-
-#ifdef mpg123_tellframe
-#undef mpg123_tellframe
-#endif
-EXPORT off_t mpg123_tellframe(mpg123_handle *mh);
-
-#ifdef mpg123_tell_stream
-#undef mpg123_tell_stream
-#endif
-EXPORT off_t mpg123_tell_stream(mpg123_handle *mh);
-
-#ifdef mpg123_seek
-#undef mpg123_seek
-#endif
-EXPORT off_t mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence);
-
-#ifdef mpg123_feedseek
-#undef mpg123_feedseek
-#endif
-EXPORT off_t mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset);
-
-#ifdef mpg123_seek_frame
-#undef mpg123_seek_frame
-#endif
-EXPORT off_t mpg123_seek_frame(mpg123_handle *mh, off_t frameoff, int whence);
-
-#ifdef mpg123_timeframe
-#undef mpg123_timeframe
-#endif
-EXPORT off_t mpg123_timeframe(mpg123_handle *mh, double sec);
-
-#ifdef mpg123_index
-#undef mpg123_index
-#endif
-EXPORT int mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill);
-
-#ifdef mpg123_set_index
-#undef mpg123_set_index
-#endif
-EXPORT int mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill);
-
-#ifdef mpg123_position
-#undef mpg123_position
-#endif
-EXPORT int mpg123_position( mpg123_handle *mh, off_t frame_offset, off_t buffered_bytes, off_t *current_frame, off_t *frames_left, double *current_seconds, double *seconds_left);
-
-#ifdef mpg123_length
-#undef mpg123_length
-#endif
-EXPORT off_t mpg123_length(mpg123_handle *mh);
-
-#ifdef mpg123_set_filesize
-#undef mpg123_set_filesize
-#endif
-EXPORT int mpg123_set_filesize(mpg123_handle *mh, off_t size);
-
-#ifdef mpg123_replace_reader
-#undef mpg123_replace_reader
-#endif
-EXPORT int mpg123_replace_reader(mpg123_handle *mh, ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int));
-
-#ifdef mpg123_replace_reader_handle
-#undef mpg123_replace_reader_handle
-#endif
-EXPORT int mpg123_replace_reader_handle(mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*));
-
-} // extern "C"
-
-#endif
-#endif
-#endif
-#endif
-
-#endif // MPT_LIBMPG123_WORKAROUND_LARGEFILE_SUFFIX
-
-#endif // MPT_WITH_MPG123
+#include "modsmp_ctrl.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
 
 
-#if defined(MPT_WITH_MEDIAFOUNDATION) || defined(MPT_WITH_OPUSFILE) || defined(MPT_WITH_VORBISFILE)
-
-static mpt::ustring GetSampleNameFromTags(const FileTags &tags)
-//-------------------------------------------------------------
-{
-	mpt::ustring result;
-	if(tags.artist.empty())
-	{
-		result = tags.title;
-	} else
-	{
-		result = mpt::String::Print(MPT_USTRING("%1 (by %2)"), tags.title, tags.artist);
-	}
-	return result;
-}
-
-#endif // MPT_WITH_MEDIAFOUNDATION || MPT_WITH_OPUSFILE || MPT_WITH_VORBISFILE
-
-
 bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize, bool includeInstrumentFormats)
-//--------------------------------------------------------------------------------------------------------------------------
 {
 	if(!nSample || nSample >= MAX_SAMPLES) return false;
 	if(!ReadWAVSample(nSample, file, mayNormalize)
@@ -292,12 +69,12 @@ bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool
 
 
 bool CSoundFile::ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize)
-//--------------------------------------------------------------------------------------------------
 {
 	if ((!nInstr) || (nInstr >= MAX_INSTRUMENTS)) return false;
 	if(!ReadITIInstrument(nInstr, file)
 		&& !ReadXIInstrument(nInstr, file)
 		&& !ReadPATInstrument(nInstr, file)
+		&& !ReadSFZInstrument(nInstr, file)
 		// Generic read
 		&& !ReadSampleAsInstrument(nInstr, file, mayNormalize))
 	{
@@ -318,7 +95,6 @@ bool CSoundFile::ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, FileReader &file
 
 
 bool CSoundFile::ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize)
-//--------------------------------------------------------------------------------------------------
 {
 	// Scanning free sample
 	SAMPLEINDEX nSample = GetNextFreeSample(nInstr); // may also return samples which are only referenced by the current instrument
@@ -355,7 +131,6 @@ bool CSoundFile::ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file
 
 
 bool CSoundFile::DestroyInstrument(INSTRUMENTINDEX nInstr, deleteInstrumentSamples removeSamples)
-//-----------------------------------------------------------------------------------------------
 {
 	if(nInstr == 0 || nInstr >= MAX_INSTRUMENTS || !Instruments[nInstr]) return true;
 
@@ -368,12 +143,10 @@ bool CSoundFile::DestroyInstrument(INSTRUMENTINDEX nInstr, deleteInstrumentSampl
 
 	ModInstrument *pIns = Instruments[nInstr];
 	Instruments[nInstr] = nullptr;
-	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+	for(auto &chn : m_PlayState.Chn)
 	{
-		if (m_PlayState.Chn[i].pModInstrument == pIns)
-		{
-			m_PlayState.Chn[i].pModInstrument = nullptr;
-		}
+		if(chn.pModInstrument == pIns)
+			chn.pModInstrument = nullptr;
 	}
 	delete pIns;
 	return true;
@@ -382,7 +155,6 @@ bool CSoundFile::DestroyInstrument(INSTRUMENTINDEX nInstr, deleteInstrumentSampl
 
 // Remove all unused samples from the given nInstr and keep keepSample if provided
 bool CSoundFile::RemoveInstrumentSamples(INSTRUMENTINDEX nInstr, SAMPLEINDEX keepSample)
-//--------------------------------------------------------------------------------------
 {
 	if(Instruments[nInstr] == nullptr)
 	{
@@ -392,12 +164,12 @@ bool CSoundFile::RemoveInstrumentSamples(INSTRUMENTINDEX nInstr, SAMPLEINDEX kee
 	std::vector<bool> keepSamples(GetNumSamples() + 1, true);
 
 	// Check which samples are used by the instrument we are going to nuke.
-	std::set<SAMPLEINDEX> referencedSamples = Instruments[nInstr]->GetSamples();
-	for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++)
+	auto referencedSamples = Instruments[nInstr]->GetSamples();
+	for(auto sample : referencedSamples)
 	{
-		if((*sample) <= GetNumSamples())
+		if(sample <= GetNumSamples())
 		{
-			keepSamples[*sample] = false;
+			keepSamples[sample] = false;
 		}
 	}
 
@@ -427,7 +199,6 @@ bool CSoundFile::RemoveInstrumentSamples(INSTRUMENTINDEX nInstr, SAMPLEINDEX kee
 //
 
 bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoundFile &srcSong, INSTRUMENTINDEX sourceInstr)
-//--------------------------------------------------------------------------------------------------------------------------
 {
 	if ((!sourceInstr) || (sourceInstr > srcSong.GetNumInstruments())
 		|| (targetInstr >= MAX_INSTRUMENTS) || (!srcSong.Instruments[sourceInstr]))
@@ -451,12 +222,12 @@ bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoun
 	std::vector<SAMPLEINDEX> targetSample;	// Sample index in target song
 	SAMPLEINDEX targetIndex = 0;		// Next index for inserting sample
 
-	for(size_t i = 0; i < CountOf(pIns->Keyboard); i++)
+	for(auto &sample : pIns->Keyboard)
 	{
-		const SAMPLEINDEX sourceIndex = pIns->Keyboard[i];
+		const SAMPLEINDEX sourceIndex = sample;
 		if(sourceIndex > 0 && sourceIndex <= srcSong.GetNumSamples())
 		{
-			const std::vector<SAMPLEINDEX>::const_iterator entry = std::find(sourceSample.begin(), sourceSample.end(), sourceIndex);
+			const auto entry = std::find(sourceSample.cbegin(), sourceSample.cend(), sourceIndex);
 			if(entry == sourceSample.end())
 			{
 				// Didn't consider this sample yet, so add it to our map.
@@ -465,20 +236,20 @@ bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoun
 				{
 					sourceSample.push_back(sourceIndex);
 					targetSample.push_back(targetIndex);
-					pIns->Keyboard[i] = targetIndex;
+					sample = targetIndex;
 				} else
 				{
-					pIns->Keyboard[i] = 0;
+					sample = 0;
 				}
 			} else
 			{
 				// Sample reference has already been created, so only need to update the sample map.
-				pIns->Keyboard[i] = *(entry - sourceSample.begin() + targetSample.begin());
+				sample = *(entry - sourceSample.begin() + targetSample.begin());
 			}
 		} else
 		{
 			// Invalid or no source sample
-			pIns->Keyboard[i] = 0;
+			sample = 0;
 		}
 	}
 
@@ -495,7 +266,6 @@ bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoun
 
 
 bool CSoundFile::ReadSampleFromSong(SAMPLEINDEX targetSample, const CSoundFile &srcSong, SAMPLEINDEX sourceSample)
-//----------------------------------------------------------------------------------------------------------------
 {
 	if(!sourceSample
 		|| sourceSample > srcSong.GetNumSamples()
@@ -539,7 +309,6 @@ bool CSoundFile::ReadSampleFromSong(SAMPLEINDEX targetSample, const CSoundFile &
 
 
 static bool IMAADPCMUnpack16(int16 *target, SmpLength sampleLen, FileReader file, uint16 blockAlign, uint32 numChannels)
-//----------------------------------------------------------------------------------------------------------------------
 {
 	static const int32 IMAIndexTab[8] =  { -1, -1, -1, -1, 2, 4, 6, 8 };
 	static const int32 IMAUnpackTable[90] =
@@ -619,7 +388,6 @@ static bool IMAADPCMUnpack16(int16 *target, SmpLength sampleLen, FileReader file
 // WAV Open
 
 bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize, FileReader *wsmpChunk)
-//-------------------------------------------------------------------------------------------------------------
 {
 	WAVReader wavFile(file);
 
@@ -627,8 +395,7 @@ bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNo
 		|| wavFile.GetNumChannels() == 0
 		|| wavFile.GetNumChannels() > 2
 		|| (wavFile.GetBitsPerSample() == 0 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3)
-		|| (wavFile.GetBitsPerSample() > 32 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat)
-		|| (wavFile.GetBitsPerSample() > 64 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
+		|| (wavFile.GetBitsPerSample() > 64)
 		|| (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtALaw && wavFile.GetSampleFormat() != WAVFormatChunk::fmtULaw))
 	{
 		return false;
@@ -737,7 +504,6 @@ bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNo
 
 #ifndef MODPLUG_NO_FILESAVE
 bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, const mpt::PathString &filename) const
-//----------------------------------------------------------------------------------------
 {
 	mpt::ofstream f(filename, std::ios::binary);
 	if(!f)
@@ -772,7 +538,7 @@ bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, const mpt::PathString &filen
 	}
 
 	FileTags tags;
-	tags.title = mpt::ToUnicode(GetCharsetLocaleOrModule(), m_szNames[nSample]);
+	tags.title = mpt::ToUnicode(GetCharsetInternal(), m_szNames[nSample]);
 	tags.encoder = mpt::ToUnicode(mpt::CharsetUTF8, MptVersion::GetOpenMPTVersionStr());
 	file.WriteMetatags(tags);
 
@@ -788,7 +554,6 @@ bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, const mpt::PathString &filen
 // Save RAW
 
 bool CSoundFile::SaveRAWSample(SAMPLEINDEX nSample, const mpt::PathString &filename) const
-//----------------------------------------------------------------------------------------
 {
 	mpt::ofstream f(filename, std::ios::binary);
 	if(!f)
@@ -812,93 +577,58 @@ bool CSoundFile::SaveRAWSample(SAMPLEINDEX nSample, const mpt::PathString &filen
 /////////////////////////////////////////////////////////////
 // GUS Patches
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-
-struct PACKED GF1PatchFileHeader
-{
-	char   magic[8];		// "GF1PATCH"
-	char   version[4];		// "100", or "110"
-	char   id[10];			// "ID#000002"
-	char   copyright[60];	// Copyright
-	uint8  numInstr;		// Number of instruments in patch
-	uint8  voices;			// Number of voices, usually 14
-	uint8  channels;		// Number of wav channels that can be played concurently to the patch
-	uint16 numSamples;		// Total number of waveforms for all the .PAT
-	uint16 volume;			// Master volume
-	uint32 dataSize;
-	char   reserved2[36];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(numSamples);
-		SwapBytesLE(volume);
-		SwapBytesLE(dataSize);
-	}
+struct GF1PatchFileHeader
+{
+	char     magic[8];		// "GF1PATCH"
+	char     version[4];	// "100", or "110"
+	char     id[10];		// "ID#000002"
+	char     copyright[60];	// Copyright
+	uint8le  numInstr;		// Number of instruments in patch
+	uint8le  voices;		// Number of voices, usually 14
+	uint8le  channels;		// Number of wav channels that can be played concurently to the patch
+	uint16le numSamples;	// Total number of waveforms for all the .PAT
+	uint16le volume;		// Master volume
+	uint32le dataSize;
+	char     reserved2[36];
 };
 
-STATIC_ASSERT(sizeof(GF1PatchFileHeader) == 129);
+MPT_BINARY_STRUCT(GF1PatchFileHeader, 129)
 
 
-struct PACKED GF1Instrument
+struct GF1Instrument
 {
-	uint16 id;				// Instrument id: 0-65535
-	char   name[16];		// Name of instrument. Gravis doesn't seem to use it
-	uint32 size;			// Number of bytes for the instrument with header. (To skip to next instrument)
-	uint8  layers;			// Number of layers in instrument: 1-4
-	char   reserved[40];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(id);
-		SwapBytesLE(size);
-	}
+	uint16le id;			// Instrument id: 0-65535
+	char     name[16];		// Name of instrument. Gravis doesn't seem to use it
+	uint32le size;			// Number of bytes for the instrument with header. (To skip to next instrument)
+	uint8    layers;		// Number of layers in instrument: 1-4
+	char     reserved[40];
 };
 
-STATIC_ASSERT(sizeof(GF1Instrument) == 63);
-
-
-struct PACKED GF1SampleHeader
-{
-	char name[7];			// null terminated string. name of the wave.
-	uint8  fractions;		// Start loop point fraction in 4 bits + End loop point fraction in the 4 other bits.
-	uint32 length;			// total size of wavesample. limited to 65535 now by the drivers, not the card.
-	uint32 loopstart;		// start loop position in the wavesample
-	uint32 loopend;			// end loop position in the wavesample
-	uint16 freq;			// Rate at which the wavesample has been sampled
-	uint32 low_freq, high_freq, root_freq;	// check note.h for the correspondance.
-	int16  finetune;		// fine tune. -512 to +512, EXCLUDING 0 cause it is a multiplier. 512 is one octave off, and 1 is a neutral value
-	uint8  balance;			// Balance: 0-15. 0=full left, 15 = full right
-	uint8  env_rate[6];		// attack rates
-	uint8  env_volume[6];	// attack volumes
-	uint8  tremolo_sweep, tremolo_rate, tremolo_depth;
-	uint8  vibrato_sweep, vibrato_rate, vibrato_depth;
-	uint8  flags;
-	int16  scale_frequency;
-	uint16 scale_factor;
-	char reserved[36];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(length);
-		SwapBytesLE(loopstart);
-		SwapBytesLE(loopend);
-		SwapBytesLE(freq);
-		SwapBytesLE(low_freq);
-		SwapBytesLE(high_freq);
-		SwapBytesLE(root_freq);
-		SwapBytesLE(finetune);
-		SwapBytesLE(scale_frequency);
-		SwapBytesLE(scale_factor);
-	}
+MPT_BINARY_STRUCT(GF1Instrument, 63)
+
+
+struct GF1SampleHeader
+{
+	char     name[7];		// null terminated string. name of the wave.
+	uint8le  fractions;		// Start loop point fraction in 4 bits + End loop point fraction in the 4 other bits.
+	uint32le length;		// total size of wavesample. limited to 65535 now by the drivers, not the card.
+	uint32le loopstart;		// start loop position in the wavesample
+	uint32le loopend;		// end loop position in the wavesample
+	uint16le freq;			// Rate at which the wavesample has been sampled
+	uint32le low_freq, high_freq, root_freq;	// check note.h for the correspondance.
+	int16le  finetune;		// fine tune. -512 to +512, EXCLUDING 0 cause it is a multiplier. 512 is one octave off, and 1 is a neutral value
+	uint8le  balance;		// Balance: 0-15. 0=full left, 15 = full right
+	uint8le  env_rate[6];	// attack rates
+	uint8le  env_volume[6];	// attack volumes
+	uint8le  tremolo_sweep, tremolo_rate, tremolo_depth;
+	uint8le  vibrato_sweep, vibrato_rate, vibrato_depth;
+	uint8le  flags;
+	int16le  scale_frequency;	// Note
+	uint16le scale_factor;		// 0...2048 (1024 is normal) or 0...2
+	char     reserved[36];
 };
 
-STATIC_ASSERT(sizeof(GF1SampleHeader) == 96);
+MPT_BINARY_STRUCT(GF1SampleHeader, 96)
 
 // -- GF1 Envelopes --
 //
@@ -931,47 +661,40 @@ STATIC_ASSERT(sizeof(GF1SampleHeader) == 96);
 // bit 7: off/on clamped release (6th point, env)
 
 
-struct PACKED GF1Layer
+struct GF1Layer
 {
-	uint8  previous;		// If !=0 the wavesample to use is from the previous layer. The waveheader is still needed
-	uint8  id;				// Layer id: 0-3
-	uint32 size;			// data size in bytes in the layer, without the header. to skip to next layer for example:
-	uint8  samples;			// number of wavesamples
-	char   reserved[40];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(size);
-	}
+	uint8le  previous;		// If !=0 the wavesample to use is from the previous layer. The waveheader is still needed
+	uint8le  id;			// Layer id: 0-3
+	uint32le size;			// data size in bytes in the layer, without the header. to skip to next layer for example:
+	uint8le  samples;		// number of wavesamples
+	char     reserved[40];
 };
 
-STATIC_ASSERT(sizeof(GF1Layer) == 47);
+MPT_BINARY_STRUCT(GF1Layer, 47)
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+static double PatchFreqToNote(uint32 nFreq)
+{
+	return std::log(nFreq / 2044.0) * (12.0 * 1.44269504088896340736);	// 1.0/std::log(2.0)
+}
+
 
-static int32 PatchFreqToNote(uint32 nFreq)
-//----------------------------------------
+static int32 PatchFreqToNoteInt(uint32 nFreq)
 {
-	const float inv_log_2 = 1.44269504089f; // 1.0f/std::log(2.0f)
-	const float base = 1.0f / 2044.0f;
-	return Util::Round<int32>(std::log(nFreq * base) * (12.0f * inv_log_2));
+	return Util::Round<int32>(PatchFreqToNote(nFreq));
 }
 
 
 static void PatchToSample(CSoundFile *that, SAMPLEINDEX nSample, GF1SampleHeader &sampleHeader, FileReader &file)
-//---------------------------------------------------------------------------------------------------------------
 {
 	ModSample &sample = that->GetSample(nSample);
 
-	file.ReadConvertEndianness(sampleHeader);
+	file.ReadStruct(sampleHeader);
 
 	sample.Initialize();
 	if(sampleHeader.flags & 4) sample.uFlags.set(CHN_LOOP);
 	if(sampleHeader.flags & 8) sample.uFlags.set(CHN_PINGPONGLOOP);
+	if(sampleHeader.flags & 16) sample.uFlags.set(CHN_REVERSE);
 	sample.nLength = sampleHeader.length;
 	sample.nLoopStart = sampleHeader.loopstart;
 	sample.nLoopEnd = sampleHeader.loopend;
@@ -985,10 +708,7 @@ static void PatchToSample(CSoundFile *that, SAMPLEINDEX nSample, GF1SampleHeader
 	sample.nVibRate = sampleHeader.vibrato_rate / 4;
 	if(sampleHeader.scale_factor)
 	{
-		sample.FrequencyToTranspose();
-		sample.RelativeTone += static_cast<int8>(84 - PatchFreqToNote(sampleHeader.root_freq));
-		sample.RelativeTone = static_cast<uint8>(sample.RelativeTone - (sampleHeader.scale_frequency - 60));
-		sample.TransposeToFrequency();
+		sample.Transpose((84.0 - PatchFreqToNote(sampleHeader.root_freq)) / 12.0);
 	}
 
 	SampleIO sampleIO(
@@ -1013,20 +733,19 @@ static void PatchToSample(CSoundFile *that, SAMPLEINDEX nSample, GF1SampleHeader
 
 
 bool CSoundFile::ReadPATSample(SAMPLEINDEX nSample, FileReader &file)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 	GF1PatchFileHeader fileHeader;
 	GF1Instrument instrHeader;	// We only support one instrument
 	GF1Layer layerHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
+	if(!file.ReadStruct(fileHeader)
 		|| memcmp(fileHeader.magic, "GF1PATCH", 8)
 		|| (memcmp(fileHeader.version, "110\0", 4) && memcmp(fileHeader.version, "100\0", 4))
 		|| memcmp(fileHeader.id, "ID#000002\0", 10)
 		|| !fileHeader.numInstr || !fileHeader.numSamples
-		|| !file.ReadConvertEndianness(instrHeader)
+		|| !file.ReadStruct(instrHeader)
 		//|| !instrHeader.layers	// DOO.PAT has 0 layers
-		|| !file.ReadConvertEndianness(layerHeader)
+		|| !file.ReadStruct(layerHeader)
 		|| !layerHeader.samples)
 	{
 		return false;
@@ -1046,20 +765,19 @@ bool CSoundFile::ReadPATSample(SAMPLEINDEX nSample, FileReader &file)
 
 // PAT Instrument
 bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
-//--------------------------------------------------------------------------
 {
 	file.Rewind();
 	GF1PatchFileHeader fileHeader;
 	GF1Instrument instrHeader;	// We only support one instrument
 	GF1Layer layerHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
+	if(!file.ReadStruct(fileHeader)
 		|| memcmp(fileHeader.magic, "GF1PATCH", 8)
 		|| (memcmp(fileHeader.version, "110\0", 4) && memcmp(fileHeader.version, "100\0", 4))
 		|| memcmp(fileHeader.id, "ID#000002\0", 10)
 		|| !fileHeader.numInstr || !fileHeader.numSamples
-		|| !file.ReadConvertEndianness(instrHeader)
+		|| !file.ReadStruct(instrHeader)
 		//|| !instrHeader.layers	// DOO.PAT has 0 layers
-		|| !file.ReadConvertEndianness(layerHeader)
+		|| !file.ReadStruct(layerHeader)
 		|| !layerHeader.samples)
 	{
 		return false;
@@ -1096,9 +814,9 @@ bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 		// Load it
 		GF1SampleHeader sampleHeader;
 		PatchToSample(this, nextSample, sampleHeader, file);
-		int32 nMinNote = (sampleHeader.low_freq > 100) ? PatchFreqToNote(sampleHeader.low_freq) : 0;
-		int32 nMaxNote = (sampleHeader.high_freq > 100) ? PatchFreqToNote(sampleHeader.high_freq) : NOTE_MAX;
-		int32 nBaseNote = (sampleHeader.root_freq > 100) ? PatchFreqToNote(sampleHeader.root_freq) : -1;
+		int32 nMinNote = (sampleHeader.low_freq > 100) ? PatchFreqToNoteInt(sampleHeader.low_freq) : 0;
+		int32 nMaxNote = (sampleHeader.high_freq > 100) ? PatchFreqToNoteInt(sampleHeader.high_freq) : NOTE_MAX;
+		int32 nBaseNote = (sampleHeader.root_freq > 100) ? PatchFreqToNoteInt(sampleHeader.root_freq) : -1;
 		if(!sampleHeader.scale_factor && layerHeader.samples == 1) { nMinNote = 0; nMaxNote = NOTE_MAX; }
 		// Fill Note Map
 		for(int32 k = 0; k < NOTE_MAX; k++)
@@ -1133,6 +851,7 @@ bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 		}
 	}
 
+	pIns->Sanitize(MOD_TYPE_IT);
 	pIns->Convert(MOD_TYPE_IT, GetType());
 	return true;
 }
@@ -1143,12 +862,11 @@ bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 
 
 bool CSoundFile::ReadS3ISample(SAMPLEINDEX nSample, FileReader &file)
-//-------------------------------------------------------------------
 {
 	file.Rewind();
 
 	S3MSampleHeader sampleHeader;
-	if(!file.ReadConvertEndianness(sampleHeader)
+	if(!file.ReadStruct(sampleHeader)
 		|| sampleHeader.sampleType != S3MSampleHeader::typePCM
 		|| memcmp(sampleHeader.magic, "SCRS", 4)
 		|| !file.Seek((sampleHeader.dataPointer[1] << 4) | (sampleHeader.dataPointer[2] << 12) | (sampleHeader.dataPointer[0] << 20)))
@@ -1173,12 +891,11 @@ bool CSoundFile::ReadS3ISample(SAMPLEINDEX nSample, FileReader &file)
 
 
 bool CSoundFile::ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
-//-------------------------------------------------------------------------
 {
 	file.Rewind();
 
 	XIInstrumentHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
+	if(!file.ReadStruct(fileHeader)
 		|| memcmp(fileHeader.signature, "Extended Instrument: ", 21)
 		|| fileHeader.version != XIInstrumentHeader::fileVersion
 		|| fileHeader.eof != 0x1A)
@@ -1235,7 +952,7 @@ bool CSoundFile::ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 	for(SAMPLEINDEX i = 0; i < fileHeader.numSamples; i++)
 	{
 		XMSample sampleHeader;
-		if(!file.ReadConvertEndianness(sampleHeader)
+		if(!file.ReadStruct(sampleHeader)
 			|| !sampleMap[i])
 		{
 			continue;
@@ -1279,7 +996,6 @@ bool CSoundFile::ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 #ifndef MODPLUG_NO_FILESAVE
 
 bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString &filename) const
-//----------------------------------------------------------------------------------------------
 {
 	ModInstrument *pIns = Instruments[nInstr];
 	if(pIns == nullptr || filename.empty())
@@ -1304,7 +1020,6 @@ bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 		header.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType());
 	}
 
-	header.ConvertEndianness();
 	fwrite(&header, 1, sizeof(XIInstrumentHeader), f);
 
 	std::vector<SampleIO> sampleFlags(samples.size());
@@ -1324,7 +1039,6 @@ bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 
 		mpt::String::Write<mpt::String::spacePadded>(xmSample.name, m_szNames[samples[i]]);
 
-		xmSample.ConvertEndianness();
 		fwrite(&xmSample, 1, sizeof(xmSample), f);
 	}
 
@@ -1337,8 +1051,10 @@ bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 		}
 	}
 
-	int32 code = MAGIC4BE('M','P','T','X');
-	fwrite(&code, 1, sizeof(int32), f);		// Write extension tag
+	// Write 'MPTX' extension tag
+	char code[4];
+	memcpy(code, "XTPM", 4);
+	fwrite(code, 1, 4, f);
 	WriteInstrumentHeaderStructOrField(pIns, f);	// Write full extended header.
 
 	fclose(f);
@@ -1350,12 +1066,11 @@ bool CSoundFile::SaveXIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 
 // Read first sample from XI file into a sample slot
 bool CSoundFile::ReadXISample(SAMPLEINDEX nSample, FileReader &file)
-//------------------------------------------------------------------
 {
 	file.Rewind();
 
 	XIInstrumentHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
+	if(!file.ReadStruct(fileHeader)
 		|| !file.CanRead(sizeof(XMSample))
 		|| memcmp(fileHeader.signature, "Extended Instrument: ", 21)
 		|| fileHeader.version != XIInstrumentHeader::fileVersion
@@ -1373,13 +1088,13 @@ bool CSoundFile::ReadXISample(SAMPLEINDEX nSample, FileReader &file)
 	uint16 numSamples = fileHeader.numSamples;
 	FileReader::off_t samplePos = sizeof(XIInstrumentHeader) + numSamples * sizeof(XMSample);
 	// Preferrably read the middle-C sample
-	uint8 sample = fileHeader.instrument.sampleMap[48];
+	auto sample = fileHeader.instrument.sampleMap[48];
 	if(sample >= fileHeader.numSamples)
 		sample = 0;
 	XMSample sampleHeader;
 	while(sample--)
 	{
-		file.ReadConvertEndianness(sampleHeader);
+		file.ReadStruct(sampleHeader);
 		samplePos += sampleHeader.length;
 	}
 	file.ReadStruct(sampleHeader);
@@ -1410,219 +1125,857 @@ bool CSoundFile::ReadXISample(SAMPLEINDEX nSample, FileReader &file)
 
 
 /////////////////////////////////////////////////////////////////////////////////////////
-// AIFF File I/O
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
+// SFZ Instrument
 
+#ifdef MPT_EXTERNAL_SAMPLES
 
-// AIFF header
-struct PACKED AIFFHeader
+struct SFZControl
 {
-	char   magic[4];	// FORM
-	uint32 length;		// Size of the file, not including magic and length
-	char   type[4];		// AIFF or AIFC
+	std::string defaultPath;
+	int8 octaveOffset, noteOffset;
+
+	SFZControl()
+		: octaveOffset(0), noteOffset(0)
+	{ }
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
+	void Parse(const std::string &key, const std::string &value)
 	{
-		//SwapBytesBE(length);	// We ignore this field
+		if(key == "default_path")
+			defaultPath = value;
+		else if(key == "octave_offset")
+			octaveOffset = ConvertStrTo<int8>(value);
+		else if(key == "note_offset")
+			noteOffset = ConvertStrTo<int8>(value);
 	}
 };
 
-STATIC_ASSERT(sizeof(AIFFHeader) == 12);
-
-
-// General IFF Chunk header
-struct PACKED AIFFChunk
+struct SFZEnvelope
 {
-	// 32-Bit chunk identifiers
-	enum ChunkIdentifiers
-	{
-		idCOMM	= 0x434F4D4D,
-		idSSND	= 0x53534E44,
-		idINST	= 0x494E5354,
-		idMARK	= 0x4D41524B,
-		idNAME	= 0x4E414D45,
-	};
-
-	typedef ChunkIdentifiers id_type;
+	float startLevel, delay, attack, hold, decay, sustainLevel, release, depth;
+	SFZEnvelope()
+		: startLevel(0), delay(0), attack(0), hold(0), decay(0), sustainLevel(100), release(0), depth(0)
+	{ }
 
-	uint32 id;		// See ChunkIdentifiers
-	uint32 length;	// Chunk size without header
-
-	size_t GetLength() const
+	void Parse(std::string key, const std::string &value)
 	{
-		return SwapBytesReturnBE(length);
+		key.erase(0, key.find('_') + 1);
+		float v = ConvertStrTo<float>(value);
+		if(key == "depth")
+			Limit(v, -12000.0f, 12000.0f);
+		else if(key == "start" || key == "sustain")
+			Limit(v, -100.0f, 100.0f);
+		else
+			Limit(v, 0.0f, 100.0f);
+
+		if(key == "start")
+			startLevel = v;
+		else if(key == "delay")
+			delay = v;
+		else if(key == "attack")
+			attack = v;
+		else if(key == "hold")
+			hold = v;
+		else if(key == "decay")
+			decay = v;
+		else if(key == "sustain")
+			sustainLevel = v;
+		else if(key == "release")
+			release = v;
+		else if(key == "depth")
+			depth = v;
 	}
 
-	id_type GetID() const
+	static EnvelopeNode::tick_t ToTicks(float duration, float tickDuration)
 	{
-		return static_cast<id_type>(SwapBytesReturnBE(id));
+		return std::max(EnvelopeNode::tick_t(1), Util::Round<EnvelopeNode::tick_t>(duration / tickDuration));
 	}
-};
-
-STATIC_ASSERT(sizeof(AIFFChunk) == 8);
-
-
-// "Common" chunk (in AIFC, a compression ID and compression name follows this header, but apart from that it's identical)
-struct PACKED AIFFCommonChunk
-{
-	uint16 numChannels;
-	uint32 numSampleFrames;
-	uint16 sampleSize;
-	uint8  sampleRate[10];		// Sample rate in 80-Bit floating point
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
+	EnvelopeNode::value_t ToValue(float value, EnvelopeType envType) const
 	{
-		SwapBytesBE(numChannels);
-		SwapBytesBE(numSampleFrames);
-		SwapBytesBE(sampleSize);
+		value *= (ENVELOPE_MAX / 100.0f);
+		if(envType == ENV_PITCH)
+		{
+			value *= depth / 3200.0f;
+			value += ENVELOPE_MID;
+		}
+		Limit<float, float>(value, ENVELOPE_MIN, ENVELOPE_MAX);
+		return Util::Round<EnvelopeNode::value_t>(value);
 	}
 
-	// Convert sample rate to integer
-	uint32 GetSampleRate() const
+	void ConvertToMPT(ModInstrument *ins, const CSoundFile &sndFile, EnvelopeType envType) const
 	{
-		uint32 mantissa = (sampleRate[2] << 24) | (sampleRate[3] << 16) | (sampleRate[4] << 8) | (sampleRate[5] << 0);
-		uint32 last = 0;
-		uint8 exp = 30 - sampleRate[1];
-
-		while(exp--)
+		auto &env = ins->GetEnvelope(envType);
+		float tickDuration = sndFile.m_PlayState.m_nSamplesPerTick / static_cast<float>(sndFile.GetSampleRate());
+		if(tickDuration <= 0)
+			return;
+		env.clear();
+		if(envType != ENV_VOLUME && attack == 0 && delay == 0 && hold == 0 && decay == 0 && sustainLevel == 100 && release == 0 && depth == 0)
 		{
-			last = mantissa;
-			mantissa >>= 1;
+			env.dwFlags.reset(ENV_SUSTAIN | ENV_ENABLED);
+			return;
 		}
-		if(last & 1) mantissa++;
-		return mantissa;
+		if(attack > 0 || delay > 0)
+		{
+			env.push_back(0, ToValue(startLevel, envType));
+			if(delay > 0)
+				env.push_back(ToTicks(delay, tickDuration), env.back().value);
+			env.push_back(env.back().tick + ToTicks(attack, tickDuration), ToValue(100, envType));
+		}
+		if(hold > 0)
+		{
+			if(env.empty())
+				env.push_back(0, ToValue(100, envType));
+			env.push_back(env.back().tick + ToTicks(hold, tickDuration), env.back().value);
+		}
+		if(env.empty())
+			env.push_back(0, ToValue(100, envType));
+		auto sustain = ToValue(sustainLevel, envType);
+		if(env.back().value != sustain)
+			env.push_back(env.back().tick + ToTicks(decay, tickDuration), sustain);
+		env.nSustainStart = env.nSustainEnd = static_cast<uint8>(env.size() - 1);
+		if(sustainLevel != 0)
+		{
+			env.push_back(env.back().tick + ToTicks(release, tickDuration), ToValue(0, envType));
+			env.dwFlags.set(ENV_SUSTAIN);
+		}
+		env.dwFlags.set(ENV_ENABLED);
 	}
 };
 
-STATIC_ASSERT(sizeof(AIFFCommonChunk) == 18);
-
-
-// Sound chunk
-struct PACKED AIFFSoundChunk
+struct SFZRegion
 {
-	uint32 offset;
-	uint32 blockSize;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
+	enum class LoopMode
 	{
-		SwapBytesBE(offset);
-		SwapBytesBE(blockSize);
-	}
-};
-
-STATIC_ASSERT(sizeof(AIFFSoundChunk) == 8);
+		kUnspecified,
+		kContinuous,
+		kOneShot,
+		kSustain,
+		kNoLoop
+	};
 
+	enum class LoopType
+	{
+		kUnspecified,
+		kForward,
+		kBackward,
+		kAlternate,
+	};
 
-// Marker
-struct PACKED AIFFMarker
-{
-	uint16 id;
-	uint32 position;		// Position in sample
-	uint8  nameLength;		// Not counting eventually existing padding byte in name string
+	std::string filename;
+	SFZEnvelope ampEnv, pitchEnv, filterEnv;
+	SmpLength loopStart, loopEnd, end, offset;
+	LoopMode loopMode;
+	LoopType loopType;
+	int32 cutoff;			// in Hz
+	int32 filterRandom;		// 0...9600 cents
+	int16 volume;			// -144dB...+6dB
+	int16 pitchBend;		// -9600...9600 cents
+	float pitchLfoFade;		// 0...100 seconds
+	int16 pitchLfoDepth;	// -1200...12000
+	uint8 pitchLfoFreq;		// 0...20 Hz
+	int8 panning;			// -100...+100
+	int8 transpose;
+	int8 finetune;
+	uint8 keyLo, keyHi, keyRoot;
+	uint8 resonance;		// 0...40dB
+	uint8 filterType;
+	uint8 polyphony;
+	bool useSampleKeyRoot : 1;
+	bool invertPhase : 1;
+
+	SFZRegion()
+		: loopStart(0), loopEnd(0), end(MAX_SAMPLE_LENGTH), offset(0)
+		, loopMode(LoopMode::kUnspecified)
+		, loopType(LoopType::kUnspecified)
+		, cutoff(0)
+		, filterRandom(0)
+		, volume(0)
+		, pitchBend(200)
+		, pitchLfoFade(0)
+		, pitchLfoDepth(0)
+		, pitchLfoFreq(0)
+		, panning(-128)
+		, transpose(0)
+		, finetune(0)
+		, keyLo(0), keyHi(127), keyRoot(60)
+		, resonance(0)
+		, filterType(FLTMODE_UNCHANGED)
+		, polyphony(255)
+		, useSampleKeyRoot(false)
+		, invertPhase(false)
+	{ }
+
+	template<typename T, typename Tc>
+	static void Read(const std::string &valueStr, T &value, Tc valueMin = std::numeric_limits<T>::min(), Tc valueMax = std::numeric_limits<T>::max())
+	{
+		double valueF = ConvertStrTo<double>(valueStr);
+		MPT_CONSTANT_IF(std::numeric_limits<T>::is_integer)
+		{
+			valueF = Util::Round(valueF);
+		}
+		Limit(valueF, static_cast<double>(valueMin), static_cast<double>(valueMax));
+		value = static_cast<T>(valueF);
+	}
+
+	static uint8 ReadKey(const std::string &value, const SFZControl &control)
+	{
+		if(value.empty())
+			return 0;
+
+		int key = 0;
+		if(value[0] >= '0' && value[0] <= '9')
+		{
+			// MIDI key
+			key = ConvertStrTo<uint8>(value);
+		} else if(value.length() < 2)
+		{
+			return 0;
+		} else
+		{
+			// Scientific pitch
+			static const int8 keys[] = { 9, 11, 0, 2, 4, 5, 7 };
+			STATIC_ASSERT(CountOf(keys) == 'g' - 'a' + 1);
+			auto keyC = value[0];
+			if(keyC >= 'A' && keyC <= 'G')
+				key = keys[keyC - 'A'];
+			if(keyC >= 'a' && keyC <= 'g')
+				key = keys[keyC - 'a'];
+			else
+				return 0;
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(id);
-		SwapBytesBE(position);
-	}};
+			uint8 octaveOffset = 1;
+			if(value[1] == '#')
+			{
+				key++;
+				octaveOffset = 2;
+			} else if(value[1] == 'b' || value[1] == 'B')
+			{
+				key--;
+				octaveOffset = 2;
+			}
+			if(octaveOffset >= value.length())
+				return 0;
 
-STATIC_ASSERT(sizeof(AIFFMarker) == 7);
+			int8 octave = ConvertStrTo<int8>(value.c_str() + octaveOffset);
+			key += (octave + 1) * 12;
+		}
+		key += control.octaveOffset * 12 + control.noteOffset;
+		return static_cast<uint8>(Clamp(key, 0, 127));
+}
 
+	void Parse(const std::string &key, const std::string &value, const SFZControl &control)
+	{
+		if(key == "sample")
+			filename = control.defaultPath + value;
+		else if(key == "lokey")
+			keyLo = ReadKey(value, control);
+		else if(key == "hikey")
+			keyHi = ReadKey(value, control);
+		else if(key == "pitch_keycenter")
+		{
+			keyRoot = ReadKey(value, control);
+			useSampleKeyRoot = (value == "sample");
+		}
+		else if(key == "key")
+		{
+			keyLo = keyHi = keyRoot = ReadKey(value, control);
+			useSampleKeyRoot = false;
+		}
+		else if(key == "bend_up" || key == "bendup")
+			Read(value, pitchBend, -9600, 9600);
+		else if(key == "pitchlfo_fade")
+			Read(value, pitchLfoFade, 0.0f, 100.0f);
+		else if(key == "pitchlfo_depth")
+			Read(value, pitchLfoDepth, -12000, 12000);
+		else if(key == "pitchlfo_freq")
+			Read(value, pitchLfoFreq, 0, 20);
+		else if(key == "volume")
+			Read(value, volume, -144, 6);
+		else if(key == "pan")
+			Read(value, panning, -100, 100);
+		else if(key == "transpose")
+			Read(value, transpose, -127, 127);
+		else if(key == "tune")
+			Read(value, finetune, -100, 100);
+		else if(key == "end")
+			Read(value, end, SmpLength(0), MAX_SAMPLE_LENGTH);
+		else if(key == "offset")
+			Read(value, offset, SmpLength(0), MAX_SAMPLE_LENGTH);
+		else if(key == "loop_start" || key == "loopstart")
+			Read(value, loopStart, SmpLength(0), MAX_SAMPLE_LENGTH);
+		else if(key == "loop_end" || key == "loopend")
+			Read(value, loopEnd, SmpLength(0), MAX_SAMPLE_LENGTH);
+		else if(key == "loop_mode" || key == "loopmode")
+		{
+			if(value == "loop_continuous")
+				loopMode = LoopMode::kContinuous;
+			else if(value == "one_shot")
+				loopMode = LoopMode::kOneShot;
+			else if(value == "loop_sustain")
+				loopMode = LoopMode::kSustain;
+			else if(value == "no_loop")
+				loopMode = LoopMode::kNoLoop;
+		}
+		else if(key == "loop_type" || key == "looptype")
+		{
+			if(value == "forward")
+				loopType = LoopType::kForward;
+			else if(value == "backward")
+				loopType = LoopType::kBackward;
+			else if(value == "alternate")
+				loopType = LoopType::kAlternate;
+		}
+		else if(key == "cutoff")
+			Read(value, cutoff, 0, 96000);
+		else if(key == "fil_random")
+			Read(value, filterRandom, 0, 9600);
+		else if(key == "resonance")
+			Read(value, resonance, 0u, 40u);
+		else if(key == "polyphony")
+			Read(value, polyphony, 0u, 255u);
+		else if(key == "phase")
+			invertPhase = (value == "invert");
+		else if(key == "fil_type" || key == "filtype")
+		{
+			if(value == "lpf_1p" || value == "lpf_2p" || value == "lpf_4p" || value == "lpf_6p")
+				filterType = FLTMODE_LOWPASS;
+			else if(value == "hpf_1p" || value == "hpf_2p" || value == "hpf_4p" || value == "hpf_6p")
+				filterType = FLTMODE_HIGHPASS;
+			// Alternatives: bpf_2p, brf_2p
+		}
+		else if(key.substr(0, 6) == "ampeg_")
+			ampEnv.Parse(key, value);
+		else if(key.substr(0, 6) == "fileg_")
+			filterEnv.Parse(key, value);
+		else if(key.substr(0, 8) == "pitcheg_")
+			pitchEnv.Parse(key, value);
+	}
+};
 
-// Instrument loop
-struct PACKED AIFFInstrumentLoop
+bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 {
-	enum PlayModes
-	{
-		noLoop		= 0,
-		loopNormal	= 1,
-		loopBidi	= 2,
-	};
+	file.Rewind();
 
-	uint16 playMode;
-	uint16 beginLoop;		// Marker index
-	uint16 endLoop;			// Marker index
+	enum { kNone, kGlobal, kMaster, kGroup, kRegion, kControl, kUnknown } section = kNone;
+	SFZControl control;
+	SFZRegion group, master, globals;
+	std::vector<SFZRegion> regions;
+	std::map<std::string, std::string> macros;
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
+	std::string s;
+	while(file.ReadLine(s, 1024))
 	{
-		SwapBytesBE(playMode);
-		SwapBytesBE(beginLoop);
-		SwapBytesBE(endLoop);
-	}
-};
-
-STATIC_ASSERT(sizeof(AIFFInstrumentLoop) == 6);
+		// First, terminate line at the start of a comment block
+		auto commentPos = s.find("//");
+		if(commentPos != std::string::npos)
+		{
+			s.resize(commentPos);
+		}
 
+		// Now, read the tokens.
+		// This format is so funky that no general tokenizer approach seems to work here...
+		// Consider this jolly good example found at https://stackoverflow.com/questions/5923895/tokenizing-a-custom-text-file-format-file-using-c-sharp
+		// <region>sample=piano C3.wav key=48 ampeg_release=0.7 // a comment here
+		// <region>key = 49 sample = piano Db3.wav
+		// <region>
+		// group=1
+		// key = 48
+		//     sample = piano D3.ogg
+		// The original sfz specification claims that spaces around = are not allowed, but a quick look into the real world tells us otherwise.
 
-struct PACKED AIFFInstrumentChunk
-{
-	uint8  baseNote;
-	uint8  detune;
-	uint8  lowNote;
-	uint8  highNote;
-	uint8  lowVelocity;
-	uint8  highVelocity;
-	uint16 gain;
-	AIFFInstrumentLoop sustainLoop;
-	AIFFInstrumentLoop releaseLoop;
+		while(!s.empty())
+		{
+			s.erase(0, s.find_first_not_of(" \t"));
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		sustainLoop.ConvertEndianness();
-		releaseLoop.ConvertEndianness();
-	}
-};
+			// Replace macros
+			for(const auto &m : macros)
+			{
+				auto &oldStr = m.first;
+				auto &newStr = m.second;
+				std::string::size_type pos = 0;
+				while((pos = s.find(oldStr, pos)) != std::string::npos)
+				{
+					s.replace(pos, oldStr.length(), newStr);
+					pos += newStr.length();
+				}
+			}
 
-STATIC_ASSERT(sizeof(AIFFInstrumentChunk) == 20);
+			if(s.empty())
+			{
+				break;
+			}
 
+			std::string::size_type charsRead = 0;
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+			if(s[0] == '<' && (charsRead = s.find('>')) != std::string::npos)
+			{
+				// Section header
+				std::string sec = s.substr(1, charsRead - 1);
+				section = kUnknown;
+				if(sec == "global")
+				{
+					section = kGlobal;
+					// Reset global parameters
+					globals = SFZRegion();
+				} else if(sec == "master")
+				{
+					section = kMaster;
+					// Reset master parameters
+					master = globals;
+				} else if(sec == "group")
+				{
+					section = kGroup;
+					// Reset group parameters
+					group = master;
+				} else if(sec == "region")
+				{
+					section = kRegion;
+					regions.push_back(group);
+				} else if(sec == "control")
+				{
+					section = kControl;
+				}
+				charsRead++;
+			} else if(s.substr(0, 8) == "#define " || s.substr(0, 8) == "#define\t")
+			{
+				// Macro definition
+				auto keyStart = s.find_first_not_of(" \t", 8);
+				auto keyEnd = s.find_first_of(" \t", keyStart);
+				auto valueStart = s.find_first_not_of(" \t", keyEnd);
+				std::string key = s.substr(keyStart, keyEnd - keyStart);
+				if(valueStart != std::string::npos && key.length() > 1 && key[0] == '$')
+				{
+					charsRead = s.find_first_of(" \t", valueStart);
+					macros[key] = s.substr(valueStart, charsRead - valueStart);
+				}
+			} else if(s.substr(0, 9) == "#include " || s.substr(0, 9) == "#include\t")
+			{
+				AddToLog(LogWarning, MPT_USTRING("#include directive is not supported."));
+				auto fileStart = s.find("\"", 9);	// Yes, there can be arbitrary characters before the opening quote, at least that's how sforzando does it.
+				auto fileEnd = s.find("\"", fileStart + 1);
+				if(fileStart != std::string::npos && fileEnd != std::string::npos)
+				{
+					charsRead = fileEnd + 1;
+				} else
+				{
+					return false;
+				}
+			} else if(section == kNone)
+			{
+				// Garbage before any section, probably not an sfz file
+				return false;
+			} else if(s.find('=') != std::string::npos)
+			{
+				// Read key=value pair
+				auto keyEnd = s.find_first_of(" \t=");
+				auto valueStart = s.find_first_not_of(" \t=", keyEnd);
+				std::string key = mpt::ToLowerCaseAscii(s.substr(0, keyEnd));
+				if(key == "sample" || key == "default_path" || key.substr(0, 8) == "label_cc")
+				{
+					// Sample / CC name may contain spaces...
+					charsRead = s.find_first_of("=\t<", valueStart);
+					if(charsRead != std::string::npos && s[charsRead] == '=')
+					{
+						// Backtrack to end of key
+						while(charsRead > valueStart && s[charsRead] == ' ')
+							charsRead--;
+						// Backtrack to start of key
+						while(charsRead > valueStart && s[charsRead] != ' ')
+							charsRead--;
+					}
+				} else
+				{
+					charsRead = s.find_first_of(" \t<", valueStart);
+				}
+				std::string value = s.substr(valueStart, charsRead - valueStart);
 
+				switch(section)
+				{
+				case kGlobal:
+					globals.Parse(key, value, control);
+					MPT_FALLTHROUGH;
+				case kMaster:
+					master.Parse(key, value, control);
+					MPT_FALLTHROUGH;
+				case kGroup:
+					group.Parse(key, value, control);
+					break;
+				case kRegion:
+					regions.back().Parse(key, value, control);
+					break;
+				case kControl:
+					control.Parse(key, value);
+					break;
+				}
+			} else
+			{
+				// Garbage, probably not an sfz file
+				MPT_ASSERT(false);
+				return false;
+			}
 
-bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize)
-//---------------------------------------------------------------------------------------
-{
-	file.Rewind();
-	ChunkReader chunkFile(file);
+			// Remove the token(s) we just read
+			s.erase(0, charsRead);
+		}
+	}
 
-	// Verify header
-	AIFFHeader fileHeader;
-	if(!chunkFile.ReadConvertEndianness(fileHeader)
-		|| memcmp(fileHeader.magic, "FORM", 4)
-		|| (memcmp(fileHeader.type, "AIFF", 4) && memcmp(fileHeader.type, "AIFC", 4)))
+	if(regions.empty())
 	{
 		return false;
 	}
 
-	ChunkReader::ChunkList<AIFFChunk> chunks = chunkFile.ReadChunks<AIFFChunk>(2);
 
-	// Read COMM chunk
-	FileReader commChunk(chunks.GetChunk(AIFFChunk::idCOMM));
-	AIFFCommonChunk sampleInfo;
-	if(!commChunk.ReadConvertEndianness(sampleInfo))
+	ModInstrument *pIns = new (std::nothrow) ModInstrument();
+	if(pIns == nullptr)
 	{
 		return false;
 	}
 
-	// Is this a proper sample?
-	if(sampleInfo.numSampleFrames == 0
-		|| sampleInfo.numChannels < 1 || sampleInfo.numChannels > 2
-		|| sampleInfo.sampleSize < 1 || sampleInfo.sampleSize > 64)
+	RecalculateSamplesPerTick();
+	DestroyInstrument(nInstr, deleteAssociatedSamples);
+	if(nInstr > m_nInstruments) m_nInstruments = nInstr;
+	Instruments[nInstr] = pIns;
+
+	SAMPLEINDEX prevSmp = 0;
+	for(auto &region : regions)
 	{
-		return false;
-	}
+		uint8 keyLo = region.keyLo, keyHi = region.keyHi;
+		if(keyLo > keyHi)
+			continue;
+		Clamp<uint8, uint8>(keyLo, 0, NOTE_MAX - NOTE_MIN);
+		Clamp<uint8, uint8>(keyHi, 0, NOTE_MAX - NOTE_MIN);
+		SAMPLEINDEX smp = GetNextFreeSample(nInstr, prevSmp + 1);
+		if(smp == SAMPLEINDEX_INVALID)
+			break;
+		prevSmp = smp;
+
+		ModSample &sample = Samples[smp];
+		mpt::PathString filename = mpt::PathString::FromUTF8(region.filename);
+		if(!filename.empty())
+		{
+			if(region.filename.find(':') == std::string::npos)
+			{
+				filename = file.GetFileName().GetPath() + filename;
+			}
+			SetSamplePath(smp, filename);
+			InputFile f(filename);
+			FileReader smpFile = GetFileReader(f);
+			if(!ReadSampleFromFile(smp, smpFile, false))
+			{
+				AddToLog(LogWarning, MPT_USTRING("Unable to load sample: ") + filename.ToUnicode());
+				prevSmp--;
+				continue;
+			}
+			if(!m_szNames[smp][0])
+			{
+				mpt::String::Copy(m_szNames[smp], filename.GetFileName().ToLocale());
+			}
+		}
+		sample.uFlags.set(SMP_KEEPONDISK, sample.pSample != nullptr);
+
+		if(region.useSampleKeyRoot)
+		{
+			if(sample.rootNote != NOTE_NONE)
+				region.keyRoot = sample.rootNote - NOTE_MIN;
+			else
+				region.keyRoot = 60;
+		}
+
+		int8 transp = region.transpose + (60 - region.keyRoot);
+		for(uint8 i = keyLo; i <= keyHi; i++)
+		{
+			pIns->Keyboard[i] = smp;
+			if(GetType() != MOD_TYPE_XM)
+				pIns->NoteMap[i] = NOTE_MIN + i + transp;
+		}
+		if(GetType() == MOD_TYPE_XM)
+			sample.Transpose(transp / 12.0);
+
+		pIns->nFilterMode = region.filterType;
+		if(region.cutoff != 0)
+			pIns->SetCutoff(FrequencyToCutOff(region.cutoff), true);
+		if(region.resonance != 0)
+			pIns->SetResonance(mpt::saturate_cast<uint8>(Util::muldivr(region.resonance, 128, 24)), true);
+		pIns->nCutSwing = mpt::saturate_cast<uint8>(Util::muldivr(region.filterRandom, m_SongFlags[SONG_EXFILTERRANGE] ? 20 : 24, 1200));
+		pIns->midiPWD = static_cast<int8>(region.pitchBend / 100);
+
+		pIns->nNNA = NNA_NOTEOFF;
+		if(region.polyphony == 1)
+		{
+			pIns->nDNA = NNA_NOTECUT;
+			pIns->nDCT = DCT_SAMPLE;
+		}
+		region.ampEnv.ConvertToMPT(pIns, *this, ENV_VOLUME);
+		region.pitchEnv.ConvertToMPT(pIns, *this, ENV_PITCH);
+		//region.filterEnv.ConvertToMPT(pIns, *this, ENV_PITCH);
+
+		sample.rootNote = region.keyRoot + NOTE_MIN;
+		sample.nGlobalVol = Util::Round<decltype(sample.nGlobalVol)>(64 * std::pow(10.0, region.volume / 20.0));
+		if(region.panning != -128)
+		{
+			sample.nPan = static_cast<decltype(sample.nPan)>(Util::muldivr_unsigned(region.panning + 100, 256, 200));
+			sample.uFlags.set(CHN_PANNING);
+		}
+		sample.Transpose(region.finetune / 1200.0);
+
+		if(region.pitchLfoDepth && region.pitchLfoFreq)
+		{
+			sample.nVibSweep = 255;
+			if(region.pitchLfoFade > 0)
+				sample.nVibSweep = Util::Round<uint8>(255 / region.pitchLfoFade);
+			sample.nVibDepth = static_cast<uint8>(Util::muldivr(region.pitchLfoDepth, 32, 100));
+			sample.nVibRate = region.pitchLfoFreq * 4;
+		}
+
+		if(region.loopMode != SFZRegion::LoopMode::kUnspecified)
+		{
+			switch(region.loopMode)
+			{
+			case SFZRegion::LoopMode::kContinuous:
+			case SFZRegion::LoopMode::kOneShot:
+				sample.uFlags.set(CHN_LOOP);
+				break;
+			case SFZRegion::LoopMode::kSustain:
+				sample.uFlags.set(CHN_SUSTAINLOOP);
+				break;
+			case SFZRegion::LoopMode::kNoLoop:
+				sample.uFlags.reset(CHN_LOOP | CHN_SUSTAINLOOP);
+			}
+		}
+		if(region.loopEnd > region.loopStart)
+		{
+			// Loop may also be defined in file, in which case loopStart and loopEnd are unset.
+			if(region.loopMode == SFZRegion::LoopMode::kSustain)
+			{
+				sample.nSustainStart = region.loopStart;
+				sample.nSustainEnd = region.loopEnd + 1;
+			} else if(region.loopMode == SFZRegion::LoopMode::kContinuous || region.loopMode == SFZRegion::LoopMode::kOneShot)
+			{
+				sample.nLoopStart = region.loopStart;
+				sample.nLoopEnd = region.loopEnd + 1;
+			}
+		} else if(sample.nLoopEnd <= sample.nLoopStart && region.loopMode != SFZRegion::LoopMode::kUnspecified && region.loopMode != SFZRegion::LoopMode::kNoLoop)
+		{
+			sample.nLoopEnd = sample.nLength;
+		}
+		switch(region.loopType)
+		{
+		case SFZRegion::LoopType::kUnspecified:
+			break;
+		case SFZRegion::LoopType::kForward:
+			sample.uFlags.reset(CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN | CHN_REVERSE);
+			break;
+		case SFZRegion::LoopType::kBackward:
+			sample.uFlags.set(CHN_REVERSE);
+			break;
+		case SFZRegion::LoopType::kAlternate:
+			sample.uFlags.set(CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN);
+			break;
+		default:
+			break;
+		}
+		if(sample.nSustainEnd <= sample.nSustainStart && sample.nLoopEnd > sample.nLoopStart && region.loopMode == SFZRegion::LoopMode::kSustain)
+		{
+			// Turn normal loop (imported from sample) into sustain loop
+			std::swap(sample.nSustainStart, sample.nLoopStart);
+			std::swap(sample.nSustainEnd, sample.nLoopEnd);
+			sample.uFlags.set(CHN_SUSTAINLOOP);
+			sample.uFlags.set(CHN_PINGPONGSUSTAIN, sample.uFlags[CHN_PINGPONGLOOP]);
+			sample.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP);
+		}
+		if(region.offset && region.offset < sample.nLength)
+		{
+			auto offset = region.offset * sample.GetBytesPerSample();
+			memmove(sample.pSample8, sample.pSample8 + offset, sample.nLength * sample.GetBytesPerSample() - offset);
+			if(region.end > region.offset)
+				region.end -= region.offset;
+			sample.nLength -= region.offset;
+			sample.nLoopStart -= region.offset;
+			sample.nLoopEnd -= region.offset;
+			sample.uFlags.set(SMP_MODIFIED);
+		}
+		LimitMax(sample.nLength, region.end);
+
+		if(region.invertPhase)
+		{
+			ctrlSmp::InvertSample(sample, 0, sample.nLength, *this);
+			sample.uFlags.set(SMP_MODIFIED);
+		}
+
+		sample.PrecomputeLoops(*this, false);
+		sample.Convert(MOD_TYPE_MPT, GetType());
+	}
+
+	pIns->Sanitize(MOD_TYPE_MPT);
+	pIns->Convert(MOD_TYPE_MPT, GetType());
+	return true;
+}
+#else
+bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX, FileReader &)
+{
+	return false;
+}
+#endif // MPT_EXTERNAL_SAMPLES
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// AIFF File I/O
+
+// AIFF header
+struct AIFFHeader
+{
+	char     magic[4];	// FORM
+	uint32be length;	// Size of the file, not including magic and length
+	char     type[4];	// AIFF or AIFC
+};
+
+MPT_BINARY_STRUCT(AIFFHeader, 12)
+
+
+// General IFF Chunk header
+struct AIFFChunk
+{
+	// 32-Bit chunk identifiers
+	enum ChunkIdentifiers
+	{
+		idCOMM	= MAGIC4BE('C','O','M','M'),
+		idSSND	= MAGIC4BE('S','S','N','D'),
+		idINST	= MAGIC4BE('I','N','S','T'),
+		idMARK	= MAGIC4BE('M','A','R','K'),
+		idNAME	= MAGIC4BE('N','A','M','E'),
+	};
+
+	uint32be id;		// See ChunkIdentifiers
+	uint32be length;	// Chunk size without header
+
+	size_t GetLength() const
+	{
+		return length;
+	}
+
+	ChunkIdentifiers GetID() const
+	{
+		return static_cast<ChunkIdentifiers>(id.get());
+	}
+};
+
+MPT_BINARY_STRUCT(AIFFChunk, 8)
+
+
+// "Common" chunk (in AIFC, a compression ID and compression name follows this header, but apart from that it's identical)
+struct AIFFCommonChunk
+{
+	uint16be numChannels;
+	uint32be numSampleFrames;
+	uint16be sampleSize;
+	uint8be  sampleRate[10];		// Sample rate in 80-Bit floating point
+
+	// Convert sample rate to integer
+	uint32 GetSampleRate() const
+	{
+		uint32 mantissa = (sampleRate[2] << 24) | (sampleRate[3] << 16) | (sampleRate[4] << 8) | (sampleRate[5] << 0);
+		uint32 last = 0;
+		uint8 exp = 30 - sampleRate[1];
+
+		while(exp--)
+		{
+			last = mantissa;
+			mantissa >>= 1;
+		}
+		if(last & 1) mantissa++;
+		return mantissa;
+	}
+};
+
+MPT_BINARY_STRUCT(AIFFCommonChunk, 18)
+
+
+// Sound chunk
+struct AIFFSoundChunk
+{
+	uint32be offset;
+	uint32be blockSize;
+};
+
+MPT_BINARY_STRUCT(AIFFSoundChunk, 8)
+
+
+// Marker
+struct AIFFMarker
+{
+	uint16be id;
+	uint32be position;		// Position in sample
+	uint8be  nameLength;	// Not counting eventually existing padding byte in name string
+};
+
+MPT_BINARY_STRUCT(AIFFMarker, 7)
+
+
+// Instrument loop
+struct AIFFInstrumentLoop
+{
+	enum PlayModes
+	{
+		noLoop		= 0,
+		loopNormal	= 1,
+		loopBidi	= 2,
+	};
+
+	uint16be playMode;
+	uint16be beginLoop;	// Marker index
+	uint16be endLoop;	// Marker index
+};
+
+MPT_BINARY_STRUCT(AIFFInstrumentLoop, 6)
+
+
+struct AIFFInstrumentChunk
+{
+	uint8be  baseNote;
+	uint8be  detune;
+	uint8be  lowNote;
+	uint8be  highNote;
+	uint8be  lowVelocity;
+	uint8be  highVelocity;
+	uint16be gain;
+	AIFFInstrumentLoop sustainLoop;
+	AIFFInstrumentLoop releaseLoop;
+};
+
+MPT_BINARY_STRUCT(AIFFInstrumentChunk, 20)
+
+
+bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize)
+{
+	file.Rewind();
+	ChunkReader chunkFile(file);
+
+	// Verify header
+	AIFFHeader fileHeader;
+	if(!chunkFile.ReadStruct(fileHeader)
+		|| memcmp(fileHeader.magic, "FORM", 4)
+		|| (memcmp(fileHeader.type, "AIFF", 4) && memcmp(fileHeader.type, "AIFC", 4)))
+	{
+		return false;
+	}
+
+	auto chunks = chunkFile.ReadChunks<AIFFChunk>(2);
+
+	// Read COMM chunk
+	FileReader commChunk(chunks.GetChunk(AIFFChunk::idCOMM));
+	AIFFCommonChunk sampleInfo;
+	if(!commChunk.ReadStruct(sampleInfo))
+	{
+		return false;
+	}
+
+	// Is this a proper sample?
+	if(sampleInfo.numSampleFrames == 0
+		|| sampleInfo.numChannels < 1 || sampleInfo.numChannels > 2
+		|| sampleInfo.sampleSize < 1 || sampleInfo.sampleSize > 64)
+	{
+		return false;
+	}
 
 	// Read compression type in AIFF-C files.
 	uint8 compression[4] = { 'N', 'O', 'N', 'E' };
@@ -1642,7 +1995,7 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN
 	// Read SSND chunk
 	FileReader soundChunk(chunks.GetChunk(AIFFChunk::idSSND));
 	AIFFSoundChunk sampleHeader;
-	if(!soundChunk.ReadConvertEndianness(sampleHeader)
+	if(!soundChunk.ReadStruct(sampleHeader)
 		|| !soundChunk.CanRead(sampleHeader.offset))
 	{
 		return false;
@@ -1675,10 +2028,6 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN
 	{
 		sampleIO |= SampleIO::uLaw;
 		sampleIO |= SampleIO::_16bit;
-	} else if(sampleInfo.sampleSize > 32)
-	{
-		// Double-precision floating point is the only 64-bit type supported at the moment.
-		return false;
 	}
 
 	if(mayNormalize)
@@ -1699,7 +2048,7 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN
 	// Read MARK and INST chunk to extract sample loops
 	FileReader markerChunk(chunks.GetChunk(AIFFChunk::idMARK));
 	AIFFInstrumentChunk instrHeader;
-	if(markerChunk.IsValid() && chunks.GetChunk(AIFFChunk::idINST).ReadConvertEndianness(instrHeader))
+	if(markerChunk.IsValid() && chunks.GetChunk(AIFFChunk::idINST).ReadStruct(instrHeader))
 	{
 		uint16 numMarkers = markerChunk.ReadUint16BE();
 
@@ -1708,7 +2057,7 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN
 		for(size_t i = 0; i < numMarkers; i++)
 		{
 			AIFFMarker marker;
-			if(!markerChunk.ReadConvertEndianness(marker))
+			if(!markerChunk.ReadStruct(marker))
 			{
 				break;
 			}
@@ -1729,24 +2078,16 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN
 		}
 
 		// Read markers
-		for(std::vector<AIFFMarker>::iterator iter = markers.begin(); iter != markers.end(); iter++)
+		for(const auto &m : markers)
 		{
-			if(iter->id == instrHeader.sustainLoop.beginLoop)
-			{
-				mptSample.nSustainStart = iter->position;
-			}
-			if(iter->id == instrHeader.sustainLoop.endLoop)
-			{
-				mptSample.nSustainEnd = iter->position;
-			}
-			if(iter->id == instrHeader.releaseLoop.beginLoop)
-			{
-				mptSample.nLoopStart = iter->position;
-			}
-			if(iter->id == instrHeader.releaseLoop.endLoop)
-			{
-				mptSample.nLoopEnd = iter->position;
-			}
+			if(m.id == instrHeader.sustainLoop.beginLoop)
+				mptSample.nSustainStart = m.position;
+			if(m.id == instrHeader.sustainLoop.endLoop)
+				mptSample.nSustainEnd = m.position;
+			if(m.id == instrHeader.releaseLoop.beginLoop)
+				mptSample.nLoopStart = m.position;
+			if(m.id == instrHeader.releaseLoop.endLoop)
+				mptSample.nLoopEnd = m.position;
 		}
 		mptSample.SanitizeLoops();
 	}
@@ -1768,7 +2109,6 @@ bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayN
 
 
 bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize)
-//-------------------------------------------------------------------------------------
 {
 	file.Rewind();
 
@@ -1789,17 +2129,19 @@ bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNor
 	switch(encoding)
 	{
 	case 1: sampleIO |= SampleIO::_16bit;			// u-law
-	        sampleIO |= SampleIO::uLaw; break;
+		sampleIO |= SampleIO::uLaw; break;
 	case 2: break;									// 8-bit linear PCM
 	case 3: sampleIO |= SampleIO::_16bit; break;	// 16-bit linear PCM
 	case 4: sampleIO |= SampleIO::_24bit; break;	// 24-bit linear PCM
 	case 5: sampleIO |= SampleIO::_32bit; break;	// 32-bit linear PCM
 	case 6: sampleIO |= SampleIO::_32bit;			// 32-bit IEEE floating point
-	        sampleIO |= SampleIO::floatPCM; break;
+		sampleIO |= SampleIO::floatPCM;
+		break;
 	case 7: sampleIO |= SampleIO::_64bit;			// 64-bit IEEE floating point
-	        sampleIO |= SampleIO::floatPCM; break;
+		sampleIO |= SampleIO::floatPCM;
+		break;
 	case 27: sampleIO |= SampleIO::_16bit;			// a-law
-	        sampleIO |= SampleIO::aLaw; break;
+		sampleIO |= SampleIO::aLaw; break;
 	default: return false;
 	}
 
@@ -1809,7 +2151,10 @@ bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNor
 	ModSample &mptSample = Samples[nSample];
 	DestroySampleThreadsafe(nSample);
 	mptSample.Initialize();
-	mptSample.nLength = (std::min<FileReader::off_t>(file.BytesLeft(), dataSize) * 8u) / (sampleIO.GetEncodedBitsPerSample() * channels);
+	SmpLength length = mpt::saturate_cast<SmpLength>(file.BytesLeft());
+	if(dataSize != 0xFFFFFFFF)
+		LimitMax(length, dataSize);
+	mptSample.nLength = (length * 8u) / (sampleIO.GetEncodedBitsPerSample() * channels);
 	mptSample.nC5Speed = sampleRate;
 	strcpy(m_szNames[nSample], "");
 
@@ -1831,7 +2176,6 @@ bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNor
 
 
 bool CSoundFile::ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewind)
-//--------------------------------------------------------------------------------
 {
 	if(rewind)
 	{
@@ -1839,7 +2183,7 @@ bool CSoundFile::ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewin
 	}
 
 	ITSample sampleHeader;
-	if(!file.ReadConvertEndianness(sampleHeader)
+	if(!file.ReadStruct(sampleHeader)
 		|| memcmp(sampleHeader.id, "IMPS", 4))
 	{
 		return false;
@@ -1889,12 +2233,11 @@ bool CSoundFile::ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewin
 
 
 bool CSoundFile::ReadITISample(SAMPLEINDEX nSample, FileReader &file)
-//-------------------------------------------------------------------
 {
 	ITInstrument instrumentHeader;
 
 	file.Rewind();
-	if(!file.ReadConvertEndianness(instrumentHeader)
+	if(!file.ReadStruct(instrumentHeader)
 		|| memcmp(instrumentHeader.id, "IMPI", 4))
 	{
 		return false;
@@ -1912,7 +2255,7 @@ bool CSoundFile::ReadITISample(SAMPLEINDEX nSample, FileReader &file)
 		return false;
 
 	// Preferrably read the middle-C sample
-	SAMPLEINDEX sample = dummy.Keyboard[NOTE_MIDDLEC - NOTE_MIN];
+	auto sample = dummy.Keyboard[NOTE_MIDDLEC - NOTE_MIN];
 	if(sample > 0 && sample <= instrumentHeader.nos)
 		sample--;
 	else
@@ -1923,13 +2266,12 @@ bool CSoundFile::ReadITISample(SAMPLEINDEX nSample, FileReader &file)
 
 
 bool CSoundFile::ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
-//--------------------------------------------------------------------------
 {
 	ITInstrument instrumentHeader;
 	SAMPLEINDEX smp = 0;
 
 	file.Rewind();
-	if(!file.ReadConvertEndianness(instrumentHeader)
+	if(!file.ReadStruct(instrumentHeader)
 		|| memcmp(instrumentHeader.id, "IMPI", 4))
 	{
 		return false;
@@ -1998,7 +2340,6 @@ bool CSoundFile::ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
 #ifndef MODPLUG_NO_FILESAVE
 
 bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString &filename, bool compress, bool allowExternal) const
-//----------------------------------------------------------------------------------------------------------------------------------
 {
 	ITInstrument iti;
 	ModInstrument *pIns = Instruments[nInstr];
@@ -2007,7 +2348,7 @@ bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 	if((!pIns) || filename.empty()) return false;
 	if((f = mpt_fopen(filename, "wb")) == nullptr) return false;
 
-	size_t instSize = iti.ConvertToIT(*pIns, false, *this);
+	auto instSize = iti.ConvertToIT(*pIns, false, *this);
 
 	// Create sample assignment table
 	std::vector<SAMPLEINDEX> smptable;
@@ -2033,23 +2374,21 @@ bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 	smpmap.clear();
 
 	uint32 filePos = instSize;
-	iti.ConvertEndianness();
 	fwrite(&iti, 1, instSize, f);
 
 	filePos += mpt::saturate_cast<uint32>(smptable.size() * sizeof(ITSample));
 
 	// Writing sample headers + data
 	std::vector<SampleIO> sampleFlags;
-	for(std::vector<SAMPLEINDEX>::iterator iter = smptable.begin(); iter != smptable.end(); iter++)
+	for(auto smp : smptable)
 	{
 		ITSample itss;
-		itss.ConvertToIT(Samples[*iter], GetType(), compress, compress, allowExternal);
+		itss.ConvertToIT(Samples[smp], GetType(), compress, compress, allowExternal);
 		const bool isExternal = itss.cvt == ITSample::cvtExternalSample;
 
-		mpt::String::Write<mpt::String::nullTerminated>(itss.name, m_szNames[*iter]);
+		mpt::String::Write<mpt::String::nullTerminated>(itss.name, m_szNames[smp]);
 
 		itss.samplepointer = filePos;
-		itss.ConvertEndianness();
 		fwrite(&itss, 1, sizeof(itss), f);
 
 		// Write sample
@@ -2057,17 +2396,17 @@ bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 		fseek(f, filePos, SEEK_SET);
 		if(!isExternal)
 		{
-			filePos += mpt::saturate_cast<uint32>(itss.GetSampleFormat(0x0214).WriteSample(f, Samples[*iter]));
+			filePos += mpt::saturate_cast<uint32>(itss.GetSampleFormat(0x0214).WriteSample(f, Samples[smp]));
 		} else
 		{
 #ifdef MPT_EXTERNAL_SAMPLES
-			const std::string filenameU8 = GetSamplePath(*iter).AbsolutePathToRelative(filename.GetPath()).ToUTF8();
+			const std::string filenameU8 = GetSamplePath(smp).AbsolutePathToRelative(filename.GetPath()).ToUTF8();
 			const size_t strSize = mpt::saturate_cast<uint16>(filenameU8.size());
 			size_t intBytes = 0;
 			if(mpt::IO::WriteVarInt(f, strSize, &intBytes))
 			{
 				filePos += intBytes + strSize;
-				mpt::IO::WriteRaw(f, &filenameU8[0], strSize);
+				mpt::IO::WriteRaw(f, filenameU8.data(), strSize);
 			}
 #endif // MPT_EXTERNAL_SAMPLES
 		}
@@ -2075,9 +2414,10 @@ bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 	}
 
 	fseek(f, 0, SEEK_END);
-	int32 code = MAGIC4BE('M','P','T','X');
-	SwapBytesLE(code);
-	fwrite(&code, 1, sizeof(int32), f);		// Write extension tag
+	// Write 'MPTX' extension tag
+	char code[4];
+	memcpy(code, "XTPM", 4);
+	fwrite(&code, 1, 4, f);
 	WriteInstrumentHeaderStructOrField(pIns, f);	// Write full extended header.
 
 	fclose(f);
@@ -2090,94 +2430,67 @@ bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // 8SVX / 16SVX Samples
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // IFF File Header
-struct PACKED IFFHeader
+struct IFFHeader
 {
-	char   form[4];		// "FORM"
-	uint32 size;
-	char   magic[4];	// "8SVX" or "16SV"
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(size);
-	}
+	char     form[4];	// "FORM"
+	uint32be size;
+	char     magic[4];	// "8SVX" or "16SV"
 };
 
-STATIC_ASSERT(sizeof(IFFHeader) == 12);
+MPT_BINARY_STRUCT(IFFHeader, 12)
 
 
 // General IFF Chunk header
-struct PACKED IFFChunk
+struct IFFChunk
 {
 	// 32-Bit chunk identifiers
 	enum ChunkIdentifiers
 	{
-		idVHDR	= 0x52444856,
-		idBODY	= 0x59444F42,
-		idNAME	= 0x454D414E,
+		idVHDR	= MAGIC4BE('V','H','D','R'),
+		idBODY	= MAGIC4BE('B','O','D','Y'),
+		idNAME	= MAGIC4BE('N','A','M','E'),
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint32 id;		// See ChunkIdentifiers
-	uint32 length;	// Chunk size without header
+	uint32be id;		// See ChunkIdentifiers
+	uint32be length;	// Chunk size without header
 
 	size_t GetLength() const
 	{
 		if(length == 0)	// Broken files
 			return std::numeric_limits<size_t>::max();
-		return SwapBytesReturnBE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(IFFChunk) == 8);
+MPT_BINARY_STRUCT(IFFChunk, 8)
 
 
-struct PACKED IFFSampleHeader
+struct IFFSampleHeader
 {
-	uint32 oneShotHiSamples;	// Samples in the high octave 1-shot part
-	uint32 repeatHiSamples;		// Samples in the high octave repeat part
-	uint32 samplesPerHiCycle;	// Samples/cycle in high octave, else 0
-	uint16 samplesPerSec;		// Data sampling rate
-	uint8  octave;				// Octaves of waveforms
-	uint8  compression;			// Data compression technique used
-	uint32 volume;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesBE(oneShotHiSamples);
-		SwapBytesBE(repeatHiSamples);
-		SwapBytesBE(samplesPerHiCycle);
-		SwapBytesBE(samplesPerSec);
-		SwapBytesBE(volume);
-	}
+	uint32be oneShotHiSamples;	// Samples in the high octave 1-shot part
+	uint32be repeatHiSamples;	// Samples in the high octave repeat part
+	uint32be samplesPerHiCycle;	// Samples/cycle in high octave, else 0
+	uint16be samplesPerSec;		// Data sampling rate
+	uint8be  octave;			// Octaves of waveforms
+	uint8be  compression;		// Data compression technique used
+	uint32be volume;
 };
 
-STATIC_ASSERT(sizeof(IFFSampleHeader) == 20);
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(IFFSampleHeader, 20)
 
 
 bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file)
-//--------------------------------------------------------------------
 {
 	file.Rewind();
 
 	IFFHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader)
+	if(!file.ReadStruct(fileHeader)
 		|| memcmp(fileHeader.form, "FORM", 4 )
 		|| (memcmp(fileHeader.magic, "8SVX", 4) && memcmp(fileHeader.magic, "16SV", 4)))
 	{
@@ -2192,7 +2505,7 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file)
 	IFFSampleHeader sampleHeader;
 	if(!bodyChunk.IsValid()
 		|| !vhdrChunk.IsValid()
-		|| !vhdrChunk.ReadConvertEndianness(sampleHeader))
+		|| !vhdrChunk.ReadStruct(sampleHeader))
 	{
 		return false;
 	}
@@ -2236,2053 +2549,4 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file)
 }
 
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// FLAC Samples
-
-#ifdef MPT_WITH_FLAC
-
-struct FLACDecoder
-{
-	FileReader &file;
-	CSoundFile &sndFile;
-	SAMPLEINDEX sample;
-	bool ready;
-
-	FLACDecoder(FileReader &f, CSoundFile &sf, SAMPLEINDEX smp) : file(f), sndFile(sf), sample(smp), ready(false) { }
-
-	static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *client_data)
-	{
-		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
-		if(*bytes > 0)
-		{
-			FileReader::off_t readBytes = *bytes;
-			LimitMax(readBytes, file.BytesLeft());
-			file.ReadRaw(buffer, readBytes);
-			*bytes = readBytes;
-			if(*bytes == 0)
-				return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
-			else
-				return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
-		} else
-		{
-			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
-		}
-	}
-
-	static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *, FLAC__uint64 absolute_byte_offset, void *client_data)
-	{
-		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
-		if(!file.Seek(static_cast<FileReader::off_t>(absolute_byte_offset)))
-			return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
-		else
-			return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
-	}
-
-	static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *, FLAC__uint64 *absolute_byte_offset, void *client_data)
-	{
-		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
-		*absolute_byte_offset = file.GetPosition();
-		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
-	}
-
-	static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data)
-	{
-		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
-		*stream_length = file.GetLength();
-		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
-	}
-
-	static FLAC__bool eof_cb(const FLAC__StreamDecoder *, void *client_data)
-	{
-		FileReader &file = static_cast<FLACDecoder *>(client_data)->file;
-		return file.NoBytesLeft();
-	}
-
-	static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
-	{
-		FLACDecoder &client = *static_cast<FLACDecoder *>(client_data);
-		ModSample &sample = client.sndFile.GetSample(client.sample);
-
-		if(frame->header.number.sample_number >= sample.nLength || !client.ready)
-		{
-			// We're reading beyond the sample size already, or we aren't even ready to decode yet!
-			return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
-		}
-
-		// Number of samples to be copied in this call
-		const SmpLength copySamples = std::min(static_cast<SmpLength>(frame->header.blocksize), static_cast<SmpLength>(sample.nLength - frame->header.number.sample_number));
-		// Number of target channels
-		const uint8 modChannels = sample.GetNumChannels();
-		// Offset (in samples) into target data
-		const size_t offset = static_cast<size_t>(frame->header.number.sample_number) * modChannels;
-		// Source size in bytes
-		const size_t srcSize = frame->header.blocksize * 4;
-		// Source bit depth
-		const unsigned int bps = frame->header.bits_per_sample;
-
-		int8 *sampleData8 = sample.pSample8 + offset;
-		int16 *sampleData16 = sample.pSample16 + offset;
-
-		MPT_ASSERT((bps <= 8 && sample.GetElementarySampleSize() == 1) || (bps > 8 && sample.GetElementarySampleSize() == 2));
-		MPT_ASSERT(modChannels <= FLAC__stream_decoder_get_channels(decoder));
-		MPT_ASSERT(bps == FLAC__stream_decoder_get_bits_per_sample(decoder));
-		MPT_UNREFERENCED_PARAMETER(decoder); // decoder is unused if ASSERTs are compiled out
-
-		// Do the sample conversion
-		for(uint8 chn = 0; chn < modChannels; chn++)
-		{
-			if(bps <= 8)
-			{
-				CopySample<SC::ConversionChain<SC::ConvertShift< int8, int32,  0>, SC::DecodeIdentity<int32> > >(sampleData8  + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
-			} else if(bps <= 16)
-			{
-				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32,  0>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
-			} else if(bps <= 24)
-			{
-				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32,  8>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
-			} else if(bps <= 32)
-			{
-				CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32, 16>, SC::DecodeIdentity<int32> > >(sampleData16 + chn, copySamples, modChannels, buffer[chn], srcSize, 1);
-			}
-		}
-
-		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-	}
-
-	static void metadata_cb(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data)
-	{
-		FLACDecoder &client = *static_cast<FLACDecoder *>(client_data);
-		if(client.sample > client.sndFile.GetNumSamples())
-		{
-			client.sndFile.m_nSamples = client.sample;
-		}
-		ModSample &sample = client.sndFile.GetSample(client.sample);
-
-		if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0)
-		{
-			// Init sample information
-			client.sndFile.DestroySampleThreadsafe(client.sample);
-			strcpy(client.sndFile.m_szNames[client.sample], "");
-			sample.Initialize();
-			sample.uFlags.set(CHN_16BIT, metadata->data.stream_info.bits_per_sample > 8);
-			sample.uFlags.set(CHN_STEREO, metadata->data.stream_info.channels > 1);
-			sample.nLength = static_cast<SmpLength>(metadata->data.stream_info.total_samples);
-			sample.nC5Speed = metadata->data.stream_info.sample_rate;
-			client.ready = (sample.AllocateSample() != 0);
-		} else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4) && client.ready)
-		{
-			// Try reading RIFF loop points and other sample information
-			ChunkReader data(mpt::as_span(metadata->data.application.data, metadata->length));
-			ChunkReader::ChunkList<RIFFChunk> chunks = data.ReadChunks<RIFFChunk>(2);
-
-			// We're not really going to read a WAV file here because there will be only one RIFF chunk per metadata event, but we can still re-use the code for parsing RIFF metadata...
-			WAVReader riffReader(data);
-			riffReader.FindMetadataChunks(chunks);
-			riffReader.ApplySampleSettings(sample, client.sndFile.m_szNames[client.sample]);
-		} else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && client.ready)
-		{
-			// Try reading Vorbis Comments for sample title, sample rate and loop points
-			SmpLength loopStart = 0, loopLength = 0;
-			for(FLAC__uint32 i = 0; i < metadata->data.vorbis_comment.num_comments; i++)
-			{
-				const char *tag = mpt::byte_cast<const char *>(metadata->data.vorbis_comment.comments[i].entry);
-				const FLAC__uint32 length = metadata->data.vorbis_comment.comments[i].length;
-				if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6))
-				{
-					mpt::String::Read<mpt::String::maybeNullTerminated>(client.sndFile.m_szNames[client.sample], tag + 6, length - 6);
-				} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11))
-				{
-					uint32 sampleRate = ConvertStrTo<uint32>(tag + 11);
-					if(sampleRate > 0) sample.nC5Speed = sampleRate;
-				} else if(length > 10 && !mpt::CompareNoCaseAscii(tag, "LOOPSTART=", 10))
-				{
-					loopStart = ConvertStrTo<SmpLength>(tag + 10);
-				} else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "LOOPLENGTH=", 11))
-				{
-					loopLength = ConvertStrTo<SmpLength>(tag + 11);
-				}
-			}
-			if(loopLength > 0)
-			{
-				sample.nLoopStart = loopStart;
-				sample.nLoopEnd = loopStart + loopLength;
-				sample.uFlags.set(CHN_LOOP);
-				sample.SanitizeLoops();
-			}
-		}
-	}
-
-	static void error_cb(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *)
-	{
-	}
-};
-
-#endif // MPT_WITH_FLAC
-
-
-bool CSoundFile::ReadFLACSample(SAMPLEINDEX sample, FileReader &file)
-//-------------------------------------------------------------------
-{
-#ifdef MPT_WITH_FLAC
-	file.Rewind();
-	bool isOgg = false;
-#ifdef MPT_WITH_OGG
-	uint32 oggFlacBitstreamSerial = 0;
-#endif
-	// Check whether we are dealing with native FLAC, OggFlac or no FLAC at all.
-	if(file.ReadMagic("fLaC"))
-	{ // ok
-		isOgg = false;
-#ifdef MPT_WITH_OGG
-	} else if(file.ReadMagic("OggS"))
-	{ // use libogg to find the first OggFlac stream header
-		file.Rewind();
-		bool oggOK = false;
-		bool needMoreData = true;
-		static const long bufsize = 65536;
-		std::size_t readSize = 0;
-		char *buf = nullptr;
-		ogg_sync_state oy;
-		MemsetZero(oy);
-		ogg_page og;
-		MemsetZero(og);
-		std::map<uint32, ogg_stream_state*> oggStreams;
-		ogg_packet op;
-		MemsetZero(op);
-		if(ogg_sync_init(&oy) != 0)
-		{
-			return false;
-		}
-		while(needMoreData)
-		{
-			if(file.NoBytesLeft())
-			{ // stop at EOF
-				oggOK = false;
-				needMoreData = false;
-				break;
-			}
-			buf = ogg_sync_buffer(&oy, bufsize);
-			if(!buf)
-			{
-				oggOK = false;
-				needMoreData = false;
-				break;
-			}
-			readSize = file.ReadRaw(buf, bufsize);
-			if(ogg_sync_wrote(&oy, static_cast<long>(readSize)) != 0)
-			{
-				oggOK = false;
-				needMoreData = false;
-				break;
-			}
-			while(ogg_sync_pageout(&oy, &og) == 1)
-			{
-				if(!ogg_page_bos(&og))
-				{ // we stop scanning when seeing the first noo-begin-of-stream page
-					oggOK = false;
-					needMoreData = false;
-					break;
-				}
-				uint32 serial = ogg_page_serialno(&og);
-				if(!oggStreams[serial])
-				{ // previously unseen stream serial
-					oggStreams[serial] = new ogg_stream_state();
-					MemsetZero(*(oggStreams[serial]));
-					if(ogg_stream_init(oggStreams[serial], serial) != 0)
-					{
-						delete oggStreams[serial];
-						oggStreams.erase(serial);
-						oggOK = false;
-						needMoreData = false;
-						break;
-					}
-				}
-				if(ogg_stream_pagein(oggStreams[serial], &og) != 0)
-				{ // invalid page
-					oggOK = false;
-					needMoreData = false;
-					break;
-				}
-				if(ogg_stream_packetout(oggStreams[serial], &op) != 1)
-				{ // partial or broken packet, continue with more data
-					continue;
-				}
-				if(op.packetno != 0)
-				{ // non-begin-of-stream packet.
-					// This should not appear on first page for any known ogg codec,
-					// but deal gracefully with badly mused streams in that regard.
-					continue;
-				}
-				FileReader packet(op.packet, op.bytes);
-				if(packet.ReadIntLE<uint8>() == 0x7f && packet.ReadMagic("FLAC"))
-				{ // looks like OggFlac
-					oggOK = true;
-					oggFlacBitstreamSerial = serial;
-					needMoreData = false;
-					break;
-				}
-			}
-		}
-		while(oggStreams.size() > 0)
-		{
-			uint32 serial = oggStreams.begin()->first;
-			ogg_stream_clear(oggStreams[serial]);
-			delete oggStreams[serial];
-			oggStreams.erase(serial);
-		}
-		ogg_sync_clear(&oy);
-		if(!oggOK)
-		{
-			return false;
-		}
-		isOgg = true;
-#else // !MPT_WITH_OGG
-	} else if(file.CanRead(78) && file.ReadMagic("OggS"))
-	{ // first OggFlac page is exactly 78 bytes long
-		// only support plain OggFlac here with the FLAC logical bitstream being the first one
-		uint8 oggPageVersion = file.ReadIntLE<uint8>();
-		uint8 oggPageHeaderType = file.ReadIntLE<uint8>();
-		uint64 oggPageGranulePosition = file.ReadIntLE<uint64>();
-		uint32 oggPageBitstreamSerialNumber = file.ReadIntLE<uint32>();
-		uint32 oggPageSequenceNumber = file.ReadIntLE<uint32>();
-		uint32 oggPageChecksum = file.ReadIntLE<uint32>();
-		uint8 oggPageSegments = file.ReadIntLE<uint8>();
-		uint8 oggPageSegmentLength = file.ReadIntLE<uint8>();
-		if(oggPageVersion != 0)
-		{ // unknown Ogg version
-			return false;
-		}
-		if(!(oggPageHeaderType & 0x02) || (oggPageHeaderType& 0x01))
-		{ // not BOS or continuation
-			return false;
-		}
-		if(oggPageGranulePosition != 0)
-		{ // not starting position
-			return false;
-		}
-		if(oggPageSequenceNumber != 0)
-		{ // not first page
-			return false;
-		}
-		// skip CRC check for now
-		if(oggPageSegments != 1)
-		{ // first OggFlac page must contain exactly 1 segment
-			return false;
-		}
-		if(oggPageSegmentLength != 51)
-		{ // segment length must be 51 bytes in OggFlac mapping
-			return false;
-		}
-		if(file.ReadIntLE<uint8>() != 0x7f)
-		{ // OggFlac mapping demands 0x7f packet type
-			return false;
-		}
-		if(!file.ReadMagic("FLAC"))
-		{ // OggFlac magic
-			return false;
-		}
-		if(file.ReadIntLE<uint8>() != 0x01)
-		{ // OggFlac major version
-			return false;
-		}
-		// by now, we are pretty confident that we are not parsing random junk
-		isOgg = true;
-#endif // MPT_WITH_OGG
-	} else
-	{
-		return false;
-	}
-	file.Rewind();
-
-	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
-	if(decoder == nullptr)
-	{
-		return false;
-	}
-
-#ifdef MPT_WITH_OGG
-	if(isOgg)
-	{
-		// force flac decoding of the logical bitstream that actually is OggFlac
-		if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, oggFlacBitstreamSerial))
-		{
-			FLAC__stream_decoder_delete(decoder);
-			return false;
-		}
-	}
-#endif
-
-	// Give me all the metadata!
-	FLAC__stream_decoder_set_metadata_respond_all(decoder);
-
-	FLACDecoder client(file, *this, sample);
-
-	// Init decoder
-	FLAC__StreamDecoderInitStatus initStatus = isOgg ?
-		FLAC__stream_decoder_init_ogg_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client)
-		:
-		FLAC__stream_decoder_init_stream(decoder, FLACDecoder::read_cb, FLACDecoder::seek_cb, FLACDecoder::tell_cb, FLACDecoder::length_cb, FLACDecoder::eof_cb, FLACDecoder::write_cb, FLACDecoder::metadata_cb, FLACDecoder::error_cb, &client)
-		;
-	if(initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK)
-	{
-		FLAC__stream_decoder_delete(decoder);
-		return false;
-	}
-
-	// Decode file
-	FLAC__stream_decoder_process_until_end_of_stream(decoder);
-	FLAC__stream_decoder_finish(decoder);
-	FLAC__stream_decoder_delete(decoder);
-
-	if(client.ready && Samples[sample].pSample != nullptr)
-	{
-		Samples[sample].Convert(MOD_TYPE_IT, GetType());
-		Samples[sample].PrecomputeLoops(*this, false);
-		return true;
-	}
-#else
-	MPT_UNREFERENCED_PARAMETER(sample);
-	MPT_UNREFERENCED_PARAMETER(file);
-#endif // MPT_WITH_FLAC
-	return false;
-}
-
-
-#ifdef MPT_WITH_FLAC
-// Helper function for copying OpenMPT's sample data to FLAC's int32 buffer.
-template<typename T>
-inline static void SampleToFLAC32(FLAC__int32 *dst, const T *src, SmpLength numSamples)
-{
-	for(SmpLength i = 0; i < numSamples; i++)
-	{
-		dst[i] = src[i];
-	}
-};
-
-// RAII-style helper struct for FLAC encoder
-struct FLAC__StreamEncoder_RAII
-{
-	FLAC__StreamEncoder *encoder;
-	FILE *f;
-
-	operator FLAC__StreamEncoder *() { return encoder; }
-
-	FLAC__StreamEncoder_RAII() : encoder(FLAC__stream_encoder_new()), f(nullptr) { }
-	~FLAC__StreamEncoder_RAII()
-	{
-		FLAC__stream_encoder_delete(encoder);
-		if(f != nullptr) fclose(f);
-	}
-};
-
-#endif
-
-
-#ifndef MODPLUG_NO_FILESAVE
-bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, const mpt::PathString &filename) const
-//-----------------------------------------------------------------------------------------
-{
-#ifdef MPT_WITH_FLAC
-	FLAC__StreamEncoder_RAII encoder;
-	if(encoder == nullptr)
-	{
-		return false;
-	}
-
-	const ModSample &sample = Samples[nSample];
-	uint32 sampleRate = sample.GetSampleRate(GetType());
-
-	// First off, set up all the metadata...
-	FLAC__StreamMetadata *metadata[] =
-	{
-		FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT),
-		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// MPT sample information
-		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// Loop points
-		FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION),	// Cue points
-	};
-
-	unsigned numBlocks = 2;
-	if(metadata[0])
-	{
-		// Store sample name
-		FLAC__StreamMetadata_VorbisComment_Entry entry;
-		FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "TITLE", m_szNames[nSample]);
-		FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
-		FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ENCODER", MptVersion::GetOpenMPTVersionStr().c_str());
-		FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
-		if(sampleRate > FLAC__MAX_SAMPLE_RATE)
-		{
-			// FLAC only supports a sample rate of up to 655350 Hz.
-			// Store the real sample rate in a custom Vorbis comment.
-			FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "SAMPLERATE", mpt::ToString(sampleRate).c_str());
-			FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false);
-		}
-	}
-	if(metadata[1])
-	{
-		// Write MPT sample information
-		memcpy(metadata[1]->data.application.id, "riff", 4);
-
-		struct
-		{
-			RIFFChunk header;
-			WAVExtraChunk mptInfo;
-		} chunk;
-
-		chunk.header.id = RIFFChunk::idxtra;
-		chunk.header.length = sizeof(WAVExtraChunk);
-
-		chunk.mptInfo.ConvertToWAV(sample, GetType());
-
-		const uint32 length = sizeof(RIFFChunk) + sizeof(WAVExtraChunk);
-		chunk.header.ConvertEndianness();
-		chunk.mptInfo.ConvertEndianness();
-
-		FLAC__metadata_object_application_set_data(metadata[1], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
-	}
-	if(metadata[numBlocks] && sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP])
-	{
-		// Store loop points
-		memcpy(metadata[numBlocks]->data.application.id, "riff", 4);
-
-		struct
-		{
-			RIFFChunk header;
-			WAVSampleInfoChunk info;
-			WAVSampleLoop loops[2];
-		} chunk;
-
-		chunk.header.id = RIFFChunk::idsmpl;
-		chunk.header.length = sizeof(WAVSampleInfoChunk);
-
-		chunk.info.ConvertToWAV(sample.GetSampleRate(GetType()));
-
-		if(sample.uFlags[CHN_SUSTAINLOOP])
-		{
-			chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nSustainStart, sample.nSustainEnd, sample.uFlags[CHN_PINGPONGSUSTAIN]);
-			chunk.header.length += sizeof(WAVSampleLoop);
-		}
-		if(sample.uFlags[CHN_LOOP])
-		{
-			chunk.loops[chunk.info.numLoops++].ConvertToWAV(sample.nLoopStart, sample.nLoopEnd, sample.uFlags[CHN_PINGPONGLOOP]);
-			chunk.header.length += sizeof(WAVSampleLoop);
-		}
-
-		const uint32 length = sizeof(RIFFChunk) + chunk.header.length;
-		chunk.header.ConvertEndianness();
-		chunk.info.ConvertEndianness();
-		chunk.loops[0].ConvertEndianness();
-		chunk.loops[1].ConvertEndianness();
-
-		FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
-		numBlocks++;
-	}
-	if(metadata[numBlocks] && sample.HasCustomCuePoints())
-	{
-		// Store cue points
-		memcpy(metadata[numBlocks]->data.application.id, "riff", 4);
-
-		struct
-		{
-			RIFFChunk header;
-			uint32 numPoints;
-			WAVCuePoint cues[CountOf(sample.cues)];
-		} chunk;
-
-		chunk.header.id = RIFFChunk::idcue_;
-		chunk.header.length = 4 + sizeof(chunk.cues);
-		chunk.numPoints = SwapBytesReturnLE(CountOf(sample.cues));
-
-		for(uint32 i = 0; i < CountOf(sample.cues); i++)
-		{
-			chunk.cues[i].ConvertToWAV(i, sample.cues[i]);
-			chunk.cues[i].ConvertEndianness();
-		}
-
-		const uint32 length = sizeof(RIFFChunk) + chunk.header.length;
-		chunk.header.ConvertEndianness();
-
-		FLAC__metadata_object_application_set_data(metadata[numBlocks], reinterpret_cast<FLAC__byte *>(&chunk), length, true);
-		numBlocks++;
-	}
-
-	// FLAC allows a maximum sample rate of 655350 Hz.
-	// If the real rate is higher, we store it in a Vorbis comment above.
-	LimitMax(sampleRate, FLAC__MAX_SAMPLE_RATE);
-	if(!FLAC__format_sample_rate_is_subset(sampleRate))
-	{
-		// FLAC only supports 10 Hz granularity for frequencies above 65535 Hz if the streamable subset is chosen.
-		FLAC__stream_encoder_set_streamable_subset(encoder, false);
-	}
-	FLAC__stream_encoder_set_channels(encoder, sample.GetNumChannels());
-	FLAC__stream_encoder_set_bits_per_sample(encoder, sample.GetElementarySampleSize() * 8);
-	FLAC__stream_encoder_set_sample_rate(encoder, sampleRate);
-	FLAC__stream_encoder_set_total_samples_estimate(encoder, sample.nLength);
-	FLAC__stream_encoder_set_metadata(encoder, metadata, numBlocks);
-#ifdef MODPLUG_TRACKER
-	FLAC__stream_encoder_set_compression_level(encoder, TrackerSettings::Instance().m_FLACCompressionLevel);
-#endif // MODPLUG_TRACKER
-
-	bool result = false;
-	FLAC__int32 *sampleData = nullptr;
-
-	encoder.f = mpt_fopen(filename, "wb");
-	if(encoder.f == nullptr || FLAC__stream_encoder_init_FILE(encoder, encoder.f, nullptr, nullptr) != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
-	{
-		goto fail;
-	}
-
-	// Convert sample data to signed 32-Bit integer array.
-	const SmpLength numSamples = sample.nLength * sample.GetNumChannels();
-	sampleData = new (std::nothrow) FLAC__int32[numSamples];
-	if(sampleData == nullptr)
-	{
-		goto fail;
-	}
-
-	if(sample.GetElementarySampleSize() == 1)
-	{
-		SampleToFLAC32(sampleData, sample.pSample8, numSamples);
-	} else if(sample.GetElementarySampleSize() == 2)
-	{
-		SampleToFLAC32(sampleData, sample.pSample16, numSamples);
-	} else
-	{
-		MPT_ASSERT_NOTREACHED();
-	}
-
-	// Do the actual conversion.
-	FLAC__stream_encoder_process_interleaved(encoder, sampleData, sample.nLength);
-	result = true;
-
-fail:
-	FLAC__stream_encoder_finish(encoder);
-
-	delete[] sampleData;
-	for(size_t i = 0; i < CountOf(metadata); i++)
-	{
-		FLAC__metadata_object_delete(metadata[i]);
-	}
-
-	return result;
-#else
-	MPT_UNREFERENCED_PARAMETER(nSample);
-	MPT_UNREFERENCED_PARAMETER(filename);
-	return false;
-#endif // MPT_WITH_FLAC
-}
-#endif // MODPLUG_NO_FILESAVE
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Opus
-
-#if defined(MPT_WITH_OPUSFILE)
-
-static mpt::ustring UStringFromOpus(const char *str)
-//--------------------------------------------------
-{
-	return str ? mpt::ToUnicode(mpt::CharsetUTF8, str) : mpt::ustring();
-}
-
-static FileTags GetOpusFileTags(OggOpusFile *of)
-//----------------------------------------------
-{
-	FileTags tags;
-	const OpusTags *ot = op_tags(of, -1);
-	if(!ot)
-	{
-		return tags;
-	}
-	tags.encoder = UStringFromOpus(opus_tags_query(ot, "ENCODER", 0));
-	tags.title = UStringFromOpus(opus_tags_query(ot, "TITLE", 0));
-	tags.comments = UStringFromOpus(opus_tags_query(ot, "DESCRIPTION", 0));
-	tags.bpm = UStringFromOpus(opus_tags_query(ot, "BPM", 0)); // non-standard
-	tags.artist = UStringFromOpus(opus_tags_query(ot, "ARTIST", 0));
-	tags.album = UStringFromOpus(opus_tags_query(ot, "ALBUM", 0));
-	tags.trackno = UStringFromOpus(opus_tags_query(ot, "TRACKNUMBER", 0));
-	tags.year = UStringFromOpus(opus_tags_query(ot, "DATE", 0));
-	tags.url = UStringFromOpus(opus_tags_query(ot, "CONTACT", 0));
-	tags.genre = UStringFromOpus(opus_tags_query(ot, "GENRE", 0));
-	return tags;
-}
-
-#endif // MPT_WITH_OPUSFILE
-
-bool CSoundFile::ReadOpusSample(SAMPLEINDEX sample, FileReader &file)
-{
-	file.Rewind();
-
-#if defined(MPT_WITH_OPUSFILE)
-
-	int rate = 0;
-	int channels = 0;
-	std::vector<int16> raw_sample_data;
-
-	FileReader initial = file.GetChunk(65536); // 512 is recommended by libopusfile
-	if(op_test(NULL, initial.GetRawData<unsigned char>(), initial.GetLength()) != 0)
-	{
-		return false;
-	}
-
-	OggOpusFile *of = op_open_memory(file.GetRawData<unsigned char>(), file.GetLength(), NULL);
-	if(!of)
-	{
-		return false;
-	}
-
-	rate = 48000;
-	channels = op_channel_count(of, -1);
-	if(rate <= 0 || channels <= 0)
-	{
-		op_free(of);
-		of = NULL;
-		return false;
-	}
-	if(channels > 2 || op_link_count(of) != 1)
-	{
-		// We downmix multichannel to stereo as recommended by Opus specification in
-		// case we are not able to handle > 2 channels.
-		// We also decode chained files as stereo even if they start with a mono
-		// stream, which simplifies handling of link boundaries for us.
-		channels = 2;
-	}
-
-	std::vector<int16> decodeBuf(120 * 48000 / 1000); // 120ms (max Opus packet), 48kHz
-	bool eof = false;
-	while(!eof)
-	{
-		int framesRead = 0;
-		if(channels == 2)
-		{
-			framesRead = op_read_stereo(of, &(decodeBuf[0]), static_cast<int>(decodeBuf.size()));
-		} else if(channels == 1)
-		{
-			framesRead = op_read(of, &(decodeBuf[0]), static_cast<int>(decodeBuf.size()), NULL);
-		}
-		if(framesRead > 0)
-		{
-			raw_sample_data.insert(raw_sample_data.end(), decodeBuf.begin(), decodeBuf.begin() + (framesRead * channels));
-		} else if(framesRead == 0)
-		{
-			eof = true;
-		} else if(framesRead == OP_HOLE)
-		{
-			// continue
-		} else
-		{
-			// other errors are fatal, stop decoding
-			eof = true;
-		}
-	}
-
-	op_free(of);
-	of = NULL;
-
-	if(raw_sample_data.empty())
-	{
-		return false;
-	}
-
-	DestroySampleThreadsafe(sample);
-	strcpy(m_szNames[sample], "");
-	Samples[sample].Initialize();
-	Samples[sample].nC5Speed = rate;
-	Samples[sample].nLength = raw_sample_data.size() / channels;
-
-	Samples[sample].uFlags.set(CHN_16BIT);
-	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
-	Samples[sample].AllocateSample();
-
-	std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);
-
-	Samples[sample].Convert(MOD_TYPE_IT, GetType());
-	Samples[sample].PrecomputeLoops(*this, false);
-
-	return Samples[sample].pSample != nullptr;
-
-#else // !MPT_WITH_OPUSFILE
-
-	MPT_UNREFERENCED_PARAMETER(sample);
-	MPT_UNREFERENCED_PARAMETER(file);
-
-	return false;
-
-#endif // MPT_WITH_OPUSFILE
-
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Vorbis
-
-#if defined(MPT_WITH_VORBISFILE)
-
-static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource)
-{
-	FileReader &file = *reinterpret_cast<FileReader*>(datasource);
-	return file.ReadRaw(mpt::void_cast<mpt::byte*>(ptr), size * nmemb) / size;
-}
-
-static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence)
-{
-	FileReader &file = *reinterpret_cast<FileReader*>(datasource);
-	switch(whence)
-	{
-	case SEEK_SET:
-		{
-			if(!Util::TypeCanHoldValue<FileReader::off_t>(offset))
-			{
-				return -1;
-			}
-			return file.Seek(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
-		}
-		break;
-	case SEEK_CUR:
-		{
-			if(offset < 0)
-			{
-				if(offset == std::numeric_limits<ogg_int64_t>::min())
-				{
-					return -1;
-				}
-				if(!Util::TypeCanHoldValue<FileReader::off_t>(0-offset))
-				{
-					return -1;
-				}
-				return file.SkipBack(mpt::saturate_cast<FileReader::off_t>(0 - offset)) ? 0 : -1;
-			} else
-			{
-				if(!Util::TypeCanHoldValue<FileReader::off_t>(offset))
-				{
-					return -1;
-				}
-				return file.Skip(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
-			}
-		}
-		break;
-	case SEEK_END:
-		{
-			if(!Util::TypeCanHoldValue<FileReader::off_t>(offset))
-			{
-				return -1;
-			}
-			if(!Util::TypeCanHoldValue<FileReader::off_t>(file.GetLength() + offset))
-			{
-				return -1;
-			}
-			return file.Seek(mpt::saturate_cast<FileReader::off_t>(file.GetLength() + offset)) ? 0 : -1;
-		}
-		break;
-	default:
-		return -1;
-	}
-}
-
-static long VorbisfileFilereaderTell(void *datasource)
-{
-	FileReader &file = *reinterpret_cast<FileReader*>(datasource);
-	return file.GetPosition();
-}
-
-#if defined(MPT_WITH_VORBIS)
-static mpt::ustring UStringFromVorbis(const char *str)
-//----------------------------------------------------
-{
-	return str ? mpt::ToUnicode(mpt::CharsetUTF8, str) : mpt::ustring();
-}
-#endif // MPT_WITH_VORBIS
-
-static FileTags GetVorbisFileTags(OggVorbis_File &vf)
-//---------------------------------------------------
-{
-	FileTags tags;
-	#if defined(MPT_WITH_VORBIS)
-		vorbis_comment *vc = ov_comment(&vf, -1);
-		if(!vc)
-		{
-			return tags;
-		}
-		tags.encoder = UStringFromVorbis(vorbis_comment_query(vc, "ENCODER", 0));
-		tags.title = UStringFromVorbis(vorbis_comment_query(vc, "TITLE", 0));
-		tags.comments = UStringFromVorbis(vorbis_comment_query(vc, "DESCRIPTION", 0));
-		tags.bpm = UStringFromVorbis(vorbis_comment_query(vc, "BPM", 0)); // non-standard
-		tags.artist = UStringFromVorbis(vorbis_comment_query(vc, "ARTIST", 0));
-		tags.album = UStringFromVorbis(vorbis_comment_query(vc, "ALBUM", 0));
-		tags.trackno = UStringFromVorbis(vorbis_comment_query(vc, "TRACKNUMBER", 0));
-		tags.year = UStringFromVorbis(vorbis_comment_query(vc, "DATE", 0));
-		tags.url = UStringFromVorbis(vorbis_comment_query(vc, "CONTACT", 0));
-		tags.genre = UStringFromVorbis(vorbis_comment_query(vc, "GENRE", 0));
-	#endif // MPT_WITH_VORBIS
-	return tags;
-}
-
-#endif // MPT_WITH_VORBISFILE
-
-bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file)
-//---------------------------------------------------------------------
-{
-
-#if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS)
-
-	file.Rewind();
-
-	int rate = 0;
-	int channels = 0;
-	std::vector<int16> raw_sample_data;
-
-	std::string sampleName;
-
-#endif // VORBIS
-
-#if defined(MPT_WITH_VORBISFILE)
-
-	bool unsupportedSample = false;
-
-	ov_callbacks callbacks = {
-		&VorbisfileFilereaderRead,
-		&VorbisfileFilereaderSeek,
-		NULL,
-		&VorbisfileFilereaderTell
-	};
-	OggVorbis_File vf;
-	MemsetZero(vf);
-	if(ov_open_callbacks(&file, &vf, NULL, 0, callbacks) == 0)
-	{
-		if(ov_streams(&vf) == 1)
-		{ // we do not support chained vorbis samples
-			vorbis_info *vi = ov_info(&vf, -1);
-			if(vi && vi->rate > 0 && vi->channels > 0)
-			{
-				sampleName = mpt::ToCharset(GetCharsetLocaleOrModule(), GetSampleNameFromTags(GetVorbisFileTags(vf)));
-				rate = vi->rate;
-				channels = vi->channels;
-				std::size_t offset = 0;
-				int current_section = 0;
-				long decodedSamples = 0;
-				bool eof = false;
-				while(!eof)
-				{
-					float **output = nullptr;
-					long ret = ov_read_float(&vf, &output, 1024, &current_section);
-					if(ret == 0)
-					{
-						eof = true;
-					} else if(ret < 0)
-					{
-						// stream error, just try to continue
-					} else
-					{
-						decodedSamples = ret;
-						if(decodedSamples > 0 && (channels == 1 || channels == 2))
-						{
-							raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples));
-							for(int chn = 0; chn < channels; chn++)
-							{
-								CopyChannelToInterleaved<SC::Convert<int16, float> >(&(raw_sample_data[0]) + offset * channels, output[chn], channels, decodedSamples, chn);
-							}
-							offset += decodedSamples;
-						}
-					}
-				}
-			} else
-			{
-				unsupportedSample = true;
-			}
-		} else
-		{
-			unsupportedSample = true;
-		}
-		ov_clear(&vf);
-	} else
-	{
-		unsupportedSample = true;
-	}
-
-	if(unsupportedSample)
-	{
-		return false;
-	}
-
-#elif defined(MPT_WITH_STBVORBIS)
-
-	// NOTE/TODO: stb_vorbis does not handle inferred negative PCM sample position
-	// at stream start. (See
-	// <https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-132000A.2>). This
-	// means that, for remuxed and re-aligned/cutted (at stream start) Vorbis
-	// files, stb_vorbis will include superfluous samples at the beginning.
-
-	FileReader::PinnedRawDataView fileView = file.GetPinnedRawDataView();
-	const mpt::byte* data = fileView.data();
-	std::size_t dataLeft = fileView.size();
-
-	std::size_t offset = 0;
-	int consumed = 0;
-	int error = 0;
-	stb_vorbis *vorb = stb_vorbis_open_pushdata(data, mpt::saturate_cast<int>(dataLeft), &consumed, &error, nullptr);
-	file.Skip(consumed);
-	data += consumed;
-	dataLeft -= consumed;
-	if(!vorb)
-	{
-		return false;
-	}
-	rate = stb_vorbis_get_info(vorb).sample_rate;
-	channels = stb_vorbis_get_info(vorb).channels;
-	if(rate <= 0 || channels <= 0)
-	{
-		return false;
-	}
-	while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0)))
-	{
-		int frame_channels = 0;
-		int decodedSamples = 0;
-		float **output = nullptr;
-		consumed = stb_vorbis_decode_frame_pushdata(vorb, data, mpt::saturate_cast<int>(dataLeft), &frame_channels, &output, &decodedSamples);
-		file.Skip(consumed);
-		data += consumed;
-		dataLeft -= consumed;
-		LimitMax(frame_channels, channels);
-		if(decodedSamples > 0 && (frame_channels == 1 || frame_channels == 2))
-		{
-			raw_sample_data.resize(raw_sample_data.size() + (channels * decodedSamples));
-			for(int chn = 0; chn < frame_channels; chn++)
-			{
-				CopyChannelToInterleaved<SC::Convert<int16, float> >(&(raw_sample_data[0]) + offset * channels, output[chn], channels, decodedSamples, chn);
-			}
-			offset += decodedSamples;
-		}
-		error = stb_vorbis_get_error(vorb);
-	}
-	stb_vorbis_close(vorb);
-
-#endif // VORBIS
-
-#if defined(MPT_WITH_VORBISFILE) || defined(MPT_WITH_STBVORBIS)
-
-	if(rate <= 0 || channels <= 0 || raw_sample_data.empty())
-	{
-		return false;
-	}
-
-	DestroySampleThreadsafe(sample);
-	mpt::String::Copy(m_szNames[sample], sampleName);
-	Samples[sample].Initialize();
-	Samples[sample].nC5Speed = rate;
-	Samples[sample].nLength = raw_sample_data.size() / channels;
-
-	Samples[sample].uFlags.set(CHN_16BIT);
-	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
-	Samples[sample].AllocateSample();
-
-	std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);
-
-	Samples[sample].Convert(MOD_TYPE_IT, GetType());
-	Samples[sample].PrecomputeLoops(*this, false);
-
-	return Samples[sample].pSample != nullptr;
-
-#else // !VORBIS
-
-	MPT_UNREFERENCED_PARAMETER(sample);
-	MPT_UNREFERENCED_PARAMETER(file);
-
-	return false;
-
-#endif // VORBIS
-
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// MP3 Samples
-
-#if defined(MPT_WITH_MPG123) || defined(MPT_ENABLE_MPG123_DYNBIND)
-
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-
-	enum mpg123_parms
-	{
-		MPG123_VERBOSE = 0,
-		MPG123_FLAGS,
-		MPG123_ADD_FLAGS,
-		MPG123_FORCE_RATE,
-		MPG123_DOWN_SAMPLE,
-		MPG123_RVA,
-		MPG123_DOWNSPEED,
-		MPG123_UPSPEED,
-		MPG123_START_FRAME,
-		MPG123_DECODE_FRAMES,
-		MPG123_ICY_INTERVAL,
-		MPG123_OUTSCALE,
-		MPG123_TIMEOUT,
-		MPG123_REMOVE_FLAGS,
-		MPG123_RESYNC_LIMIT,
-		MPG123_INDEX_SIZE,
-		MPG123_PREFRAMES,
-		MPG123_FEEDPOOL,
-		MPG123_FEEDBUFFER
-	};
-
-	enum mpg123_parms_flags
-	{
-		MPG123_QUIET = 0x20
-	};
-
-	enum mpg123_enc_enum
-	{
-		MPG123_ENC_16 = 0x040, MPG123_ENC_SIGNED = 0x080
-	};
-
-	typedef struct {int foo;} mpg123_handle;
-
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-
-class ComponentMPG123
-#if defined(MPT_WITH_MPG123)
-	: public ComponentBuiltin
-#elif defined(MPT_ENABLE_MPG123_DYNBIND)
-	: public ComponentLibrary
-#endif
-{
-	MPT_DECLARE_COMPONENT_MEMBERS
-
-private:
-
-#if MPT_OS_WINDOWS
-#if defined(MPT_WITH_MPG123)
-#elif defined(MPT_ENABLE_MPG123_DYNBIND)
-	mpt::Library MSVCRT;
-	mpt::Library SHLWAPI;
-#endif // MPT_WITH_MPG123 || MPT_ENABLE_MPG123_DYNBIND
-#endif // MPT_OS_WINDOWS
-
-public:
-
-	int (*mpg123_init )(void);
-	void (*mpg123_exit )(void);
-	mpg123_handle* (*mpg123_new )(const char*,int*);
-	void (*mpg123_delete )(mpg123_handle*);
-	int (*mpg123_param )(mpg123_handle*, enum mpg123_parms, long, double);
-	int (*mpg123_open_handle )(mpg123_handle*, void*);
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-	int (*mpg123_open_handle_64 )(mpg123_handle*, void*);
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-#if MPT_COMPILER_MSVCCLANGC2
-	int (*mpg123_replace_reader_handle)(mpg123_handle*,
-		size_t(*r_read)(void *, void *, size_t),
-		_off_t(*r_lseek)(void *, _off_t, int),
-		void(*cleanup)(void *));
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-	int (*mpg123_replace_reader_handle_64)(mpg123_handle*,
-		size_t(*r_read)(void *, void *, size_t),
-		_off_t(*r_lseek)(void *, _off_t, int),
-		void(*cleanup)(void *));
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-#elif MPT_COMPILER_MSVC
-	int (*mpg123_replace_reader_handle)(mpg123_handle*,
-		size_t(*r_read)(void *, void *, size_t),
-		off_t(*r_lseek)(void *, off_t, int),
-		void(*cleanup)(void *));
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-	int (*mpg123_replace_reader_handle_64)(mpg123_handle*,
-		size_t(*r_read)(void *, void *, size_t),
-		off_t(*r_lseek)(void *, off_t, int),
-		void(*cleanup)(void *));
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-#else // !MPT_COMPILER_MSVC
-	int (*mpg123_replace_reader_handle)(mpg123_handle*,
-		ssize_t(*r_read)(void *, void *, size_t),
-		off_t(*r_lseek)(void *, off_t, int),
-		void(*cleanup)(void *));
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-	int (*mpg123_replace_reader_handle_64)(mpg123_handle*,
-		ssize_t(*r_read)(void *, void *, size_t),
-		off_t(*r_lseek)(void *, off_t, int),
-		void(*cleanup)(void *));
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-#endif // MPT_COMPILER_MSVC
-	int (*mpg123_read )(mpg123_handle*, unsigned char*, size_t, size_t*);
-	int (*mpg123_getformat )(mpg123_handle*, long*, int*, int*);
-	int (*mpg123_scan )(mpg123_handle*);
-#if MPT_COMPILER_MSVCCLANGC2
-	_off_t (*mpg123_length )(mpg123_handle*);
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-	_off_t (*mpg123_length_64 )(mpg123_handle*);
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-#else
-	off_t (*mpg123_length )(mpg123_handle*);
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND)
-	off_t (*mpg123_length_64 )(mpg123_handle*);
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-#endif
-
-#if MPT_COMPILER_MSVCCLANGC2
-	static size_t FileReaderRead(void *fp, void *buf, size_t count)
-#elif MPT_COMPILER_MSVC
-	static size_t FileReaderRead(void *fp, void *buf, size_t count)
-#else // !MPT_COMPILER_MSVC
-	static ssize_t FileReaderRead(void *fp, void *buf, size_t count)
-#endif // MPT_COMPILER_MSVC
-	{
-		FileReader &file = *static_cast<FileReader *>(fp);
-		size_t readBytes = std::min(count, static_cast<size_t>(file.BytesLeft()));
-		file.ReadRaw(static_cast<char *>(buf), readBytes);
-		return readBytes;
-	}
-#if MPT_COMPILER_MSVCCLANGC2
-	static _off_t FileReaderLSeek(void *fp, _off_t offset, int whence)
-#else
-	static off_t FileReaderLSeek(void *fp, off_t offset, int whence)
-#endif
-	{
-		FileReader &file = *static_cast<FileReader *>(fp);
-		if(whence == SEEK_CUR) file.Seek(file.GetPosition() + offset);
-		else if(whence == SEEK_END) file.Seek(file.GetLength() + offset);
-		else file.Seek(offset);
-		return file.GetPosition();
-	}
-
-public:
-	ComponentMPG123()
-#if defined(MPT_WITH_MPG123)
-		: ComponentBuiltin()
-#elif defined(MPT_ENABLE_MPG123_DYNBIND)
-		: ComponentLibrary(ComponentTypeForeign)
-#endif
-	{
-		return;
-	}
-	bool DoInitialize()
-	{
-#if defined(MPT_WITH_MPG123)
-		MPT_GLOBAL_BIND("mpg123", mpg123_init);
-		MPT_GLOBAL_BIND("mpg123", mpg123_exit);
-		MPT_GLOBAL_BIND("mpg123", mpg123_new);
-		MPT_GLOBAL_BIND("mpg123", mpg123_delete);
-		MPT_GLOBAL_BIND("mpg123", mpg123_param);
-		MPT_GLOBAL_BIND("mpg123", mpg123_open_handle);
-		MPT_GLOBAL_BIND("mpg123", mpg123_replace_reader_handle);
-		MPT_GLOBAL_BIND("mpg123", mpg123_read);
-		MPT_GLOBAL_BIND("mpg123", mpg123_getformat);
-		MPT_GLOBAL_BIND("mpg123", mpg123_scan);
-		MPT_GLOBAL_BIND("mpg123", mpg123_length);
-#elif defined(MPT_ENABLE_MPG123_DYNBIND)
-		#if MPT_OS_WINDOWS
-			// preload MSVCRT.DLL in order to prevent DLL preloading injection attacks from the current working directory,
-			// because the stock binary packages of libmpg123 link against it
-			MSVCRT = mpt::Library(mpt::LibraryPath::System(MPT_PATHSTRING("MSVCRT")));
-			#if defined(LIBOPENMPT_BUILD)
-				// require successful dependency loading for libopenmpt
-				if(!MSVCRT.IsValid())
-				{
-					return false;
-				}
-			#endif // LIBOPENMPT_BUILD
-			// preload shlwapi.dll for the same reasons
-			if(!SHLWAPI.IsValid()) SHLWAPI = mpt::Library(mpt::LibraryPath::System(MPT_PATHSTRING("shlwapi")));
-			#if defined(LIBOPENMPT_BUILD)
-				// require successful dependency loading for libopenmpt
-				if(!SHLWAPI.IsValid())
-				{
-					return false;
-				}
-			#endif // LIBOPENMPT_BUILD
-		#endif // MPT_OS_WINDOWS
-		#if defined(MODPLUG_TRACKER)
-			AddLibrary("mpg123", mpt::LibraryPath::AppFullName(MPT_PATHSTRING("libmpg123-0")));
-			AddLibrary("mpg123", mpt::LibraryPath::AppFullName(MPT_PATHSTRING("libmpg123")));
-			AddLibrary("mpg123", mpt::LibraryPath::AppFullName(MPT_PATHSTRING("mpg123-0")));
-			AddLibrary("mpg123", mpt::LibraryPath::AppFullName(MPT_PATHSTRING("mpg123")));
-		#elif defined(LIBOPENMPT_BUILD)
-			#if MPT_OS_WINDOWS
-				// libopenmpt on Windows only loads the official builds
-				AddLibrary("mpg123", mpt::LibraryPath::AppFullName(MPT_PATHSTRING("libmpg123-0")));
-			#else // !MPT_OS_WINDOWS
-				AddLibrary("mpg123", mpt::LibraryPath::System(MPT_PATHSTRING("mpg123")));
-			#endif // MPT_OS_WINDOWS
-		#endif
-		MPT_COMPONENT_BIND("mpg123", mpg123_init);
-		MPT_COMPONENT_BIND("mpg123", mpg123_exit);
-		MPT_COMPONENT_BIND("mpg123", mpg123_new);
-		MPT_COMPONENT_BIND("mpg123", mpg123_delete);
-		MPT_COMPONENT_BIND("mpg123", mpg123_param);
-		MPT_COMPONENT_BIND_OPTIONAL("mpg123", mpg123_open_handle);
-		MPT_COMPONENT_BIND_OPTIONAL("mpg123", mpg123_open_handle_64);
-		if(!mpg123_open_handle && !mpg123_open_handle_64)
-		{
-			return false;
-		}
-		MPT_COMPONENT_BIND_OPTIONAL("mpg123", mpg123_replace_reader_handle);
-		MPT_COMPONENT_BIND_OPTIONAL("mpg123", mpg123_replace_reader_handle_64);
-		if(!mpg123_replace_reader_handle && !mpg123_replace_reader_handle_64)
-		{
-			return false;
-		}
-		MPT_COMPONENT_BIND("mpg123", mpg123_read);
-		MPT_COMPONENT_BIND("mpg123", mpg123_getformat);
-		MPT_COMPONENT_BIND("mpg123", mpg123_scan);
-		MPT_COMPONENT_BIND_OPTIONAL("mpg123", mpg123_length);
-		MPT_COMPONENT_BIND_OPTIONAL("mpg123", mpg123_length_64);
-		if(!mpg123_length && !mpg123_length_64)
-		{
-			return false;
-		}
-		#if MPT_COMPILER_MSVC
-			if(!mpg123_open_handle || !mpg123_replace_reader_handle || !mpg123_length)
-			{
-				return false;
-			}
-		#endif
-		if(HasBindFailed())
-		{
-			return false;
-		}
-#endif
-		if(mpg123_init() != 0)
-		{
-			return false;
-		}
-		return true;
-	}
-	virtual ~ComponentMPG123()
-	{
-		if(IsAvailable())
-		{
-			mpg123_exit();
-		}
-	}
-};
-MPT_REGISTERED_COMPONENT(ComponentMPG123, "Mpg123")
-
-#endif // MPT_WITH_MPG123 || MPT_ENABLE_MPG123_DYNBIND
-
-
-bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode)
-//----------------------------------------------------------------------------------
-{
-#if defined(MPT_WITH_MPG123) || defined(MPT_ENABLE_MPG123_DYNBIND) || defined(MPT_WITH_MINIMP3)
-
-	// Check file for validity, or else mpg123 will happily munch many files that start looking vaguely resemble an MPEG stream mid-file.
-	file.Rewind();
-	while(file.CanRead(4))
-	{
-		uint8 magic[3];
-		file.ReadArray(magic);
-
-		if(!memcmp(magic, "ID3", 3))
-		{
-			// Skip ID3 tags
-			uint8 header[7];
-			file.ReadArray(header);
-
-			uint32 size = 0;
-			for(int i = 3; i < 7; i++)
-			{
-				if(header[i] & 0x80)
-					return false;
-				size = (size << 7) | header[i];
-			}
-			file.Skip(size);
-		} else if(!memcmp(magic, "APE", 3) && file.ReadMagic("TAGEX"))
-		{
-			// Skip APE tags
-			uint32 size = file.ReadUint32LE();
-			file.Skip(16 + size);
-		} else if(!memcmp(magic, "\x00\x00\x00", 3) || !memcmp(magic, "\xFF\x00\x00", 3))
-		{
-			// Some MP3 files are padded with zeroes...
-		} else if(magic[0] == 0)
-		{
-			// This might be some padding, followed by an MPEG header, so try again.
-			file.SkipBack(2);
-		} else if(MPEGFrame::IsMPEGHeader(magic))
-		{
-			// This is what we want!
-			break;
-		} else
-		{
-			// This, on the other hand, isn't.
-			return false;
-		}
-	}
-
-#endif // MPT_WITH_MPG123 || MPT_ENABLE_MPG123_DYNBIND || MPT_WITH_MINIMP3
-
-#if defined(MPT_WITH_MINIMP3)
-
-	file.Rewind();
-	FileReader::PinnedRawDataView rawDataView = file.GetPinnedRawDataView();
-	int64 bytes_left = rawDataView.size();
-	const uint8 *stream_pos = mpt::byte_cast<const uint8 *>(rawDataView.data());
-
-	std::vector<int16> raw_sample_data;
-
-	mp3_decoder_t *mp3 = reinterpret_cast<mp3_decoder_t *>(mp3_create()); // workaround minimp3 header typo
-
-	int rate = 0;
-	int channels = 0;
-
-	mp3_info_t info;
-	int frame_size = 0;
-	do
-	{
-		int16 sample_buf[MP3_MAX_SAMPLES_PER_FRAME];
-		frame_size = mp3_decode(mp3, const_cast<uint8 *>(stream_pos), bytes_left, sample_buf, &info); // workaround lack of const qualifier in mp3_decode (all internal functions have the required const correctness)
-		if(rate != 0 && rate != info.sample_rate) break; // inconsistent stream
-		if(channels != 0 && channels != info.channels) break; // inconsistent stream
-		rate = info.sample_rate;
-		channels = info.channels;
-		if(rate <= 0) break; // broken stream
-		if(channels != 1 && channels != 2) break; // broken stream
-		stream_pos += frame_size;
-		bytes_left -= frame_size;
-		if(info.audio_bytes >= 0)
-		{
-			try
-			{
-				raw_sample_data.insert(raw_sample_data.end(), sample_buf, sample_buf + (info.audio_bytes / sizeof(int16)));
-			} catch(MPTMemoryException)
-			{
-				break;
-			}
-		}
-	} while((bytes_left >= 0) && (frame_size > 0));
-
-	mp3_free(mp3);
-
-	if(rate == 0 || channels == 0 || raw_sample_data.empty())
-	{
-		return false;
-	}
-
-	DestroySampleThreadsafe(sample);
-	if(!mo3Decode)
-	{
-		strcpy(m_szNames[sample], "");
-		Samples[sample].Initialize();
-		Samples[sample].nC5Speed = rate;
-	}
-	Samples[sample].nLength = raw_sample_data.size() / channels;
-
-	Samples[sample].uFlags.set(CHN_16BIT);
-	Samples[sample].uFlags.set(CHN_STEREO, channels == 2);
-	Samples[sample].AllocateSample();
-
-	if(Samples[sample].pSample != nullptr)
-	{
-		std::copy(raw_sample_data.begin(), raw_sample_data.end(), Samples[sample].pSample16);
-	}
-
-	if(!mo3Decode)
-	{
-		Samples[sample].Convert(MOD_TYPE_IT, GetType());
-		Samples[sample].PrecomputeLoops(*this, false);
-	}
-	return Samples[sample].pSample != nullptr;
-
-#elif defined(MPT_WITH_MPG123) || defined(MPT_ENABLE_MPG123_DYNBIND)
-
-	ComponentHandle<ComponentMPG123> mpg123;
-	if(!IsComponentAvailable(mpg123))
-	{
-		return false;
-	}
-
-	mpg123_handle *mh;
-	int err;
-	if((mh = mpg123->mpg123_new(0, &err)) == nullptr) return false;
-	file.Rewind();
-
-	long rate; int nchannels, encoding;
-	SmpLength length;
-	// Set up decoder...
-	if(mpg123->mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND) && !MPT_COMPILER_MSVC
-	if(mpg123->mpg123_replace_reader_handle_64 && mpg123->mpg123_replace_reader_handle_64(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	} else
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-	if(mpg123->mpg123_replace_reader_handle(mh, ComponentMPG123::FileReaderRead, ComponentMPG123::FileReaderLSeek, 0))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND) && !MPT_COMPILER_MSVC
-	if(mpg123->mpg123_open_handle_64 && mpg123->mpg123_open_handle_64(mh, &file))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	} else
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-	if(mpg123->mpg123_open_handle(mh, &file))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-	if(mpg123->mpg123_scan(mh))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-	if(mpg123->mpg123_getformat(mh, &rate, &nchannels, &encoding))
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-	if(!nchannels || nchannels > 2
-		|| (encoding & (MPG123_ENC_16 | MPG123_ENC_SIGNED)) != (MPG123_ENC_16 | MPG123_ENC_SIGNED)
-		)
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-#if !defined(MPT_WITH_MPG123) && defined(MPT_ENABLE_MPG123_DYNBIND) && !MPT_COMPILER_MSVC
-	if(mpg123->mpg123_length_64)
-	{
-		length = mpg123->mpg123_length_64(mh);
-	} else
-#endif // !MPT_WITH_MPG123 && MPT_ENABLE_MPG123_DYNBIND
-	{
-		length = mpg123->mpg123_length(mh);
-	}
-	if(length == 0)
-	{
-		mpg123->mpg123_delete(mh);
-		return false;
-	}
-
-	DestroySampleThreadsafe(sample);
-	if(!mo3Decode)
-	{
-		strcpy(m_szNames[sample], "");
-		Samples[sample].Initialize();
-		Samples[sample].nC5Speed = rate;
-	}
-	Samples[sample].nLength = length;
-
-	Samples[sample].uFlags.set(CHN_16BIT);
-	Samples[sample].uFlags.set(CHN_STEREO, nchannels == 2);
-	Samples[sample].AllocateSample();
-
-	if(Samples[sample].pSample != nullptr)
-	{
-		size_t ndecoded;
-		mpg123->mpg123_read(mh, static_cast<unsigned char *>(Samples[sample].pSample), Samples[sample].GetSampleSizeInBytes(), &ndecoded);
-	}
-	mpg123->mpg123_delete(mh);
-
-	if(!mo3Decode)
-	{
-		Samples[sample].Convert(MOD_TYPE_IT, GetType());
-		Samples[sample].PrecomputeLoops(*this, false);
-	}
-	return Samples[sample].pSample != nullptr;
-
-#else
-
-	MPT_UNREFERENCED_PARAMETER(sample);
-	MPT_UNREFERENCED_PARAMETER(file);
-	MPT_UNREFERENCED_PARAMETER(mo3Decode);
-
-#endif // MPT_WITH_MPG123 || MPT_ENABLE_MPG123_DYNBIND || MPT_WITH_MINIMP3
-
-	return false;
-}
-
-
-#if defined(MPT_WITH_MEDIAFOUNDATION)
-
-template <typename T>
-static void mptMFSafeRelease(T **ppT)
-{
-	if(*ppT)
-	{
-		(*ppT)->Release();
-		*ppT = NULL;
-	}
-}
-
-#define MPT_MF_CHECKED(x) MPT_DO { \
-	HRESULT hr = (x); \
-	if(!SUCCEEDED(hr)) \
-	{ \
-		goto fail; \
-	} \
-} MPT_WHILE_0
-
-// Implementing IMFByteStream is apparently not enough to stream raw bytes
-// data to MediaFoundation.
-// Additionally, one has to also implement a custom IMFAsyncResult for the
-// BeginRead/EndRead interface which allows transferring the number of read
-// bytes around.
-// To make things even worse, MediaFoundation fails to detect some AAC and MPEG
-// files if a non-file-based or read-only stream is used for opening.
-// The only sane option which remains if we do not have an on-disk filename
-// available:
-//  1 - write a temporary file
-//  2 - close it
-//  3 - open it using MediaFoundation.
-// We use FILE_ATTRIBUTE_TEMPORARY which will try to keep the file data in
-// memory just like regular allocated memory and reduce the overhead basically
-// to memcpy.
-
-static FileTags ReadMFMetadata(IMFMediaSource *mediaSource)
-//---------------------------------------------------------
-{
-
-	FileTags tags;
-
-	IMFPresentationDescriptor *presentationDescriptor = NULL;
-	DWORD streams = 0;
-	IMFMetadataProvider *metadataProvider = NULL;
-	IMFMetadata *metadata = NULL;
-	PROPVARIANT varPropNames;
-	PropVariantInit(&varPropNames);
-
-	MPT_MF_CHECKED(mediaSource->CreatePresentationDescriptor(&presentationDescriptor));
-	MPT_MF_CHECKED(presentationDescriptor->GetStreamDescriptorCount(&streams));
-	MPT_MF_CHECKED(MFGetService(mediaSource, MF_METADATA_PROVIDER_SERVICE, IID_IMFMetadataProvider, (void**)&metadataProvider));
-	MPT_MF_CHECKED(metadataProvider->GetMFMetadata(presentationDescriptor, 0, 0, &metadata));
-
-	MPT_MF_CHECKED(metadata->GetAllPropertyNames(&varPropNames));
-	for(DWORD propIndex = 0; propIndex < varPropNames.calpwstr.cElems; ++propIndex)
-	{
-
-		PROPVARIANT propVal;
-		PropVariantInit(&propVal);
-
-		LPWSTR propName = varPropNames.calpwstr.pElems[propIndex];
-		if(S_OK != metadata->GetProperty(propName, &propVal))
-		{
-			PropVariantClear(&propVal);
-			break;
-		}
-
-		std::wstring stringVal;
-		std::vector<WCHAR> wcharVal(256);
-		for(;;)
-		{
-			HRESULT hrToString = PropVariantToString(propVal, &wcharVal[0], wcharVal.size());
-			if(hrToString == S_OK)
-			{
-				stringVal = &wcharVal[0];
-				break;
-			} else if(hrToString == ERROR_INSUFFICIENT_BUFFER)
-			{
-				wcharVal.resize(wcharVal.size() * 2);
-			} else
-			{
-				break;
-			}
-		}
-
-		PropVariantClear(&propVal);
-
-		if(stringVal.length() > 0)
-		{
-			if(propName == std::wstring(L"Author")) tags.artist = mpt::ToUnicode(stringVal);
-			if(propName == std::wstring(L"Title")) tags.title = mpt::ToUnicode(stringVal);
-			if(propName == std::wstring(L"WM/AlbumTitle")) tags.album = mpt::ToUnicode(stringVal);
-			if(propName == std::wstring(L"WM/Track")) tags.trackno = mpt::ToUnicode(stringVal);
-			if(propName == std::wstring(L"WM/Year")) tags.year = mpt::ToUnicode(stringVal);
-			if(propName == std::wstring(L"WM/Genre")) tags.genre = mpt::ToUnicode(stringVal);
-		}
-	}
-
-fail:
-
-	PropVariantClear(&varPropNames);
-	mptMFSafeRelease(&metadata);
-	mptMFSafeRelease(&metadataProvider);
-	mptMFSafeRelease(&presentationDescriptor);
-
-	return tags;
-
-}
-
-
-class ComponentMediaFoundation : public ComponentLibrary
-{
-	MPT_DECLARE_COMPONENT_MEMBERS
-public:
-	ComponentMediaFoundation()
-		: ComponentLibrary(ComponentTypeSystem)
-	{
-		return;
-	}
-	virtual bool DoInitialize()
-	{
-		if(!mpt::Windows::Version::Current().IsAtLeast(mpt::Windows::Version::Win7))
-		{
-			return false;
-		}
-		if(!(true
-			&& AddLibrary("mf", mpt::LibraryPath::System(MPT_PATHSTRING("mf")))
-			&& AddLibrary("mfplat", mpt::LibraryPath::System(MPT_PATHSTRING("mfplat")))
-			&& AddLibrary("mfreadwrite", mpt::LibraryPath::System(MPT_PATHSTRING("mfreadwrite")))
-			&& AddLibrary("propsys", mpt::LibraryPath::System(MPT_PATHSTRING("propsys")))
-			))
-		{
-			return false;
-		}
-		if(!SUCCEEDED(MFStartup(MF_VERSION)))
-		{
-			return false;
-		}
-		return true;
-	}
-	virtual ~ComponentMediaFoundation()
-	{
-		if(IsAvailable())
-		{
-			MFShutdown();
-		}
-	}
-};
-MPT_REGISTERED_COMPONENT(ComponentMediaFoundation, "MediaFoundation")
-
-#endif // MPT_WITH_MEDIAFOUNDATION
-
-
-#ifdef MODPLUG_TRACKER
-std::vector<FileType> CSoundFile::GetMediaFoundationFileTypes()
-//-------------------------------------------------------------
-{
-	std::vector<FileType> result;
-
-#if defined(MPT_WITH_MEDIAFOUNDATION)
-
-	ComponentHandle<ComponentMediaFoundation> mf;
-	if(!IsComponentAvailable(mf))
-	{
-		return result;
-	}
-
-	std::map<std::wstring, FileType> guidMap;
-
-	HKEY hkHandlers = NULL;
-	LSTATUS regResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers", 0, KEY_READ, &hkHandlers);
-	if(regResult != ERROR_SUCCESS)
-	{
-		return result;
-	}
-
-	for(DWORD handlerIndex = 0; ; ++handlerIndex)
-	{
-
-		WCHAR handlerTypeBuf[256];
-		MemsetZero(handlerTypeBuf);
-		regResult = RegEnumKeyW(hkHandlers, handlerIndex, handlerTypeBuf, 256);
-		if(regResult != ERROR_SUCCESS)
-		{
-			break;
-		}
-
-		std::wstring handlerType = handlerTypeBuf;
-
-		if(handlerType.length() < 1)
-		{
-			continue;
-		}
-
-		HKEY hkHandler = NULL;
-		regResult = RegOpenKeyExW(hkHandlers, handlerTypeBuf, 0, KEY_READ, &hkHandler);
-		if(regResult != ERROR_SUCCESS)
-		{
-			continue;
-		}
-
-		for(DWORD valueIndex = 0; ; ++valueIndex)
-		{
-			WCHAR valueNameBuf[16384];
-			MemsetZero(valueNameBuf);
-			DWORD valueNameBufLen = 16384;
-			DWORD valueType = 0;
-			BYTE valueData[16384];
-			MemsetZero(valueData);
-			DWORD valueDataLen = 16384;
-			regResult = RegEnumValueW(hkHandler, valueIndex, valueNameBuf, &valueNameBufLen, NULL, &valueType, valueData, &valueDataLen);
-			if(regResult != ERROR_SUCCESS)
-			{
-				break;
-			}
-			if(valueNameBufLen <= 0 || valueType != REG_SZ || valueDataLen <= 0)
-			{
-				continue;
-			}
-
-			std::wstring guid = std::wstring(valueNameBuf);
-
-			mpt::ustring description = mpt::ToUnicode(std::wstring(reinterpret_cast<WCHAR*>(valueData)));
-			description = mpt::String::Replace(description, MPT_USTRING("Byte Stream Handler"), MPT_USTRING("Files"));
-			description = mpt::String::Replace(description, MPT_USTRING("ByteStreamHandler"), MPT_USTRING("Files"));
-
-			guidMap[guid]
-				.ShortName(MPT_USTRING("mf"))
-				.Description(description)
-				;
-
-			if(handlerType[0] == L'.')
-			{
-				guidMap[guid].AddExtension(mpt::PathString::FromWide(handlerType.substr(1)));
-			} else
-			{
-				guidMap[guid].AddMimeType(mpt::ToCharset(mpt::CharsetASCII, handlerType));
-			}
-
-		}
-
-		RegCloseKey(hkHandler);
-		hkHandler = NULL;
-
-	}
-
-	RegCloseKey(hkHandlers);
-	hkHandlers = NULL;
-
-	for(std::map<std::wstring, FileType>::const_iterator it = guidMap.begin(); it != guidMap.end(); ++it)
-	{
-		result.push_back(it->second);
-	}
-
-#endif // MPT_WITH_MEDIAFOUNDATION
-
-	return result;
-}
-#endif // MODPLUG_TRACKER
-
-
-bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode)
-//----------------------------------------------------------------------------------------------
-{
-
-#if !defined(MPT_WITH_MEDIAFOUNDATION)
-
-	MPT_UNREFERENCED_PARAMETER(sample);
-	MPT_UNREFERENCED_PARAMETER(file);
-	MPT_UNREFERENCED_PARAMETER(mo3Decode);
-	return false;
-
-#else
-
-	ComponentHandle<ComponentMediaFoundation> mf;
-	if(!IsComponentAvailable(mf))
-	{
-		return false;
-	}
-
-	file.Rewind();
-	// When using MF to decode MP3 samples in MO3 files, we need the mp3 file extension
-	// for some of them or otherwise MF refuses to recognize them.
-	mpt::PathString tmpfileExtension = (mo3Decode ? MPT_PATHSTRING("mp3") : MPT_PATHSTRING("tmp"));
-	OnDiskFileWrapper diskfile(file, tmpfileExtension);
-	if(!diskfile.IsValid())
-	{
-		return false;
-	}
-
-	bool result = false;
-
-	std::vector<char> rawData;
-	FileTags tags;
-	std::string sampleName;
-
-	IMFSourceResolver *sourceResolver = NULL;
-	MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID;
-	IUnknown *unknownMediaSource = NULL;
-	IMFMediaSource *mediaSource = NULL;
-	IMFSourceReader *sourceReader = NULL;
-	IMFMediaType *uncompressedAudioType = NULL;
-	IMFMediaType *partialType = NULL;
-	UINT32 numChannels = 0;
-	UINT32 samplesPerSecond = 0;
-	UINT32 bitsPerSample = 0;
-
-	IMFSample *mfSample = NULL;
-	DWORD mfSampleFlags = 0;
-	IMFMediaBuffer *buffer = NULL;
-
-	SmpLength length = 0;
-
-	MPT_MF_CHECKED(MFCreateSourceResolver(&sourceResolver));
-	MPT_MF_CHECKED(sourceResolver->CreateObjectFromURL(diskfile.GetFilename().AsNative().c_str(), MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ, NULL, &objectType, &unknownMediaSource));
-	if(objectType != MF_OBJECT_MEDIASOURCE) goto fail;
-	MPT_MF_CHECKED(unknownMediaSource->QueryInterface(&mediaSource));
-
-	tags = ReadMFMetadata(mediaSource);
-
-	MPT_MF_CHECKED(MFCreateSourceReaderFromMediaSource(mediaSource, NULL, &sourceReader));
-	MPT_MF_CHECKED(MFCreateMediaType(&partialType));
-	MPT_MF_CHECKED(partialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
-	MPT_MF_CHECKED(partialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM));
-	MPT_MF_CHECKED(sourceReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, partialType));
-	MPT_MF_CHECKED(sourceReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, &uncompressedAudioType));
-	MPT_MF_CHECKED(sourceReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, TRUE));
-	MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &numChannels));
-	MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &samplesPerSecond));
-	MPT_MF_CHECKED(uncompressedAudioType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &bitsPerSample));
-	if(numChannels <= 0 || numChannels > 2) goto fail;
-	if(samplesPerSecond <= 0) goto fail;
-	if(bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) goto fail;
-
-	for(;;)
-	{
-		mfSampleFlags = 0;
-		MPT_MF_CHECKED(sourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &mfSampleFlags, NULL, &mfSample));
-		if(mfSampleFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
-		{
-			break;
-		}
-		if(mfSampleFlags & MF_SOURCE_READERF_ENDOFSTREAM)
-		{
-			break;
-		}
-		MPT_MF_CHECKED(mfSample->ConvertToContiguousBuffer(&buffer));
-		{
-			BYTE *data = NULL;
-			DWORD dataSize = 0;
-			MPT_MF_CHECKED(buffer->Lock(&data, NULL, &dataSize));
-			rawData.insert(rawData.end(), mpt::byte_cast<char*>(data), mpt::byte_cast<char*>(data + dataSize));
-			MPT_MF_CHECKED(buffer->Unlock());
-		}
-		mptMFSafeRelease(&buffer);
-		mptMFSafeRelease(&mfSample);
-	}
-
-	mptMFSafeRelease(&uncompressedAudioType);
-	mptMFSafeRelease(&partialType);
-	mptMFSafeRelease(&sourceReader);
-
-	sampleName = mpt::ToCharset(GetCharsetLocaleOrModule(), GetSampleNameFromTags(tags));
-
-	length = rawData.size() / numChannels / (bitsPerSample/8);
-
-	DestroySampleThreadsafe(sample);
-	if(!mo3Decode)
-	{
-		mpt::String::Copy(m_szNames[sample], sampleName);
-		Samples[sample].Initialize();
-		Samples[sample].nC5Speed = samplesPerSecond;
-	}
-	Samples[sample].nLength = length;
-	Samples[sample].uFlags.set(CHN_16BIT, bitsPerSample >= 16);
-	Samples[sample].uFlags.set(CHN_STEREO, numChannels == 2);
-	Samples[sample].AllocateSample();
-	if(Samples[sample].pSample == nullptr)
-	{
-		result = false;
-		goto fail;
-	}
-
-	if(bitsPerSample == 24)
-	{
-		if(numChannels == 2)
-		{
-			CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(Samples[sample], &rawData[0], rawData.size());
-		} else
-		{
-			CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(Samples[sample], &rawData[0], rawData.size());
-		}
-	} else if(bitsPerSample == 32)
-	{
-		if(numChannels == 2)
-		{
-			CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(Samples[sample], &rawData[0], rawData.size());
-		} else
-		{
-			CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(Samples[sample], &rawData[0], rawData.size());
-		}
-	} else
-	{
-		// just copy
-		std::copy(&rawData[0], &rawData[0] + rawData.size(), mpt::void_cast<char*>(Samples[sample].pSample));
-	}
-
-	result = true;
-
-fail:
-
-	mptMFSafeRelease(&buffer);
-	mptMFSafeRelease(&mfSample);
-	mptMFSafeRelease(&uncompressedAudioType);
-	mptMFSafeRelease(&partialType);
-	mptMFSafeRelease(&sourceReader);
-	mptMFSafeRelease(&mediaSource);
-	mptMFSafeRelease(&unknownMediaSource);
-	mptMFSafeRelease(&sourceResolver);
-
-	return result;
-
-#endif
-
-}
-
-
-bool CSoundFile::CanReadMP3()
-//---------------------------
-{
-	bool result = false;
-	#if defined(MPT_WITH_MPG123)
-		if(!result)
-		{
-			result = true;
-		}
-	#endif
-	#if defined(MPT_WITH_MINIMP3)
-		if(!result)
-		{
-			result = true;
-		}
-	#endif
-	#if defined(MPT_ENABLE_MPG123_DYNBIND)
-		if(!result)
-		{
-			ComponentHandle<ComponentMPG123> mpg123;
-			if(IsComponentAvailable(mpg123))
-			{
-				result = true;
-			}
-		}
-	#endif
-	#if defined(MPT_WITH_MEDIAFOUNDATION)
-		if(!result)
-		{
-			ComponentHandle<ComponentMediaFoundation> mf;
-			if(IsComponentAvailable(mf))
-			{
-				result = true;
-			}
-		}
-	#endif
-	return result;
-}
-
-
-bool CSoundFile::CanReadVorbis()
-//------------------------------
-{
-	bool result = false;
-	#if defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
-		if(!result)
-		{
-			result = true;
-		}
-	#endif
-	#if defined(MPT_WITH_STBVORBIS)
-		if(!result)
-		{
-			result = true;
-		}
-	#endif
-	return result;
-}
-
-
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/SampleIO.cpp b/soundlib/SampleIO.cpp
index b9932d9..9d6ccae 100644
--- a/soundlib/SampleIO.cpp
+++ b/soundlib/SampleIO.cpp
@@ -13,7 +13,9 @@
 #include "stdafx.h"
 #include "Loaders.h"
 #include "SampleIO.h"
-#include "SampleFormatConverters.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "ModSampleCopy.h"
 #include "ITCompression.h"
 #include "../common/mptIO.h"
 #ifndef MODPLUG_NO_FILESAVE
@@ -32,9 +34,8 @@ uintptr_t DMFUnpack(uint8 *psample, const uint8 *ibuf, const uint8 *ibufmax, uin
 
 // Read a sample from memory
 size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const
-//--------------------------------------------------------------------
 {
-	if(sample.nLength < 1 || !file.IsValid())
+	if(!file.IsValid())
 	{
 		return 0;
 	}
@@ -67,6 +68,38 @@ size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const
 		sourceBuf = restrictedSampleDataView.data();
 		fileSize = restrictedSampleDataView.size();
 	}
+	if(!IsVariableLengthEncoded() && sample.nLength > 0x40000)
+	{
+		// Limit sample length to available bytes in file to avoid excessive memory allocation.
+		// However, for ProTracker MODs we need to support samples exceeding the end of file
+		// (see the comment about MOD.shorttune2 in Load_mod.cpp), so as a semi-arbitrary threshold,
+		// we do not apply this limit to samples shorter than 256K.
+		size_t maxLength = fileSize - std::min(GetEncodedHeaderSize(), fileSize);
+		uint8 bps = GetEncodedBitsPerSample();
+		if(bps % 8u != 0)
+		{
+			MPT_ASSERT(GetEncoding() == ADPCM && bps == 4);
+			if(Util::MaxValueOfType(maxLength) / 2u >= maxLength)
+				maxLength *= 2;
+			else
+				maxLength = Util::MaxValueOfType(maxLength);
+		} else
+		{
+			size_t encodedBytesPerSample = GetNumChannels() * GetEncodedBitsPerSample() / 8u;
+			// Check if we can round up without overflowing
+			if(Util::MaxValueOfType(maxLength) - maxLength >= (encodedBytesPerSample - 1u))
+				maxLength += encodedBytesPerSample - 1u;
+			else
+				maxLength = Util::MaxValueOfType(maxLength);
+			maxLength /= encodedBytesPerSample;
+		}
+		LimitMax(sample.nLength, mpt::saturate_cast<SmpLength>(maxLength));
+	}
+
+	if(sample.nLength < 1)
+	{
+		return 0;
+	}
 
 	sample.uFlags.set(CHN_16BIT, GetBitDepth() >= 16);
 	sample.uFlags.set(CHN_STEREO, GetChannelFormat() != mono);
@@ -565,6 +598,32 @@ size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const
 	}
 
 	//////////////////////////////////////////////////////
+	// 64-Bit / Signed / Mono / PCM
+	else if(GetBitDepth() == 64 && GetChannelFormat() == mono && GetEncoding() == signedPCM)
+	{
+		if(GetEndianness() == littleEndian)
+		{
+			bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, littleEndian64> > >(sample, sourceBuf, fileSize);
+		} else
+		{
+			bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, bigEndian64> > >(sample, sourceBuf, fileSize);
+		}
+	}
+
+	//////////////////////////////////////////////////////
+	// 64-Bit / Signed / Stereo Interleaved / PCM
+	else if(GetBitDepth() == 64 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM)
+	{
+		if(GetEndianness() == littleEndian)
+		{
+			bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, littleEndian64> > >(sample, sourceBuf, fileSize);
+		} else
+		{
+			bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, bigEndian64> > >(sample, sourceBuf, fileSize);
+		}
+	}
+
+	//////////////////////////////////////////////////////
 	// 32-Bit / Float / Mono / PCM
 	else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM)
 	{
@@ -802,7 +861,6 @@ size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const
 
 // Write a sample to file
 size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength maxSamples) const
-//------------------------------------------------------------------------------------------------
 {
 	if(!sample.HasSampleData()) return 0;
 
@@ -841,14 +899,14 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 			}
 			if(GetEncoding() == deltaPCM)
 			{
-				buffer16[bufcount] = SwapBytesReturnLE((int16)(s_new - s_old));
+				buffer16[bufcount] = SwapBytesLE((int16)(s_new - s_old));
 				s_old = s_new;
 			} else
 			{
-				buffer16[bufcount] = SwapBytesReturnLE((int16)(s_new + s_ofs));
+				buffer16[bufcount] = SwapBytesLE((int16)(s_new + s_ofs));
 			}
 			bufcount++;
-			if(bufcount >= CountOf(buffer16))
+			if(bufcount >= mpt::size(buffer16))
 			{
 				mpt::IO::WriteRaw(*f, reinterpret_cast<mpt::byte*>(buffer16), bufcount * 2);
 				bufcount = 0;
@@ -882,7 +940,7 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 				{
 					buffer8[bufcount++] = (int8)(s_new + s_ofs);
 				}
-				if(bufcount >= CountOf(buffer8))
+				if(bufcount >= mpt::size(buffer8))
 				{
 					mpt::IO::WriteRaw(*f, reinterpret_cast<mpt::byte*>(buffer8), bufcount);
 					bufcount = 0;
@@ -911,14 +969,14 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 				p += 2;
 				if (GetEncoding() == deltaPCM)
 				{
-					buffer16[bufcount] = SwapBytesReturnLE((int16)(s_new - s_old));
+					buffer16[bufcount] = SwapBytesLE((int16)(s_new - s_old));
 					s_old = s_new;
 				} else
 				{
-					buffer16[bufcount] = SwapBytesReturnLE((int16)(s_new + s_ofs));
+					buffer16[bufcount] = SwapBytesLE((int16)(s_new + s_ofs));
 				}
 				bufcount++;
-				if(bufcount >= CountOf(buffer16))
+				if(bufcount >= mpt::size(buffer16))
 				{
 					mpt::IO::WriteRaw(*f, reinterpret_cast<mpt::byte*>(buffer16), bufcount * 2);
 					bufcount = 0;
@@ -928,7 +986,7 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 		}
 	}
 
-	else if((GetBitDepth() == 8 || (GetBitDepth() == 16 && GetEndianness() == nativeEndian)) && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM)
+	else if((GetBitDepth() == 8 || (GetBitDepth() == 16 && GetEndianness() == GetNativeEndianness())) && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM)
 	{
 		// Stereo signed interleaved
 		if(f) mpt::IO::WriteRaw(*f, mpt::void_cast<const mpt::byte*>(pSampleVoid), len);
@@ -943,7 +1001,7 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 		{
 			buffer8[bufcount] = (int8)((uint8)(pSample8[j]) + 0x80);
 			bufcount++;
-			if(bufcount >= CountOf(buffer8))
+			if(bufcount >= mpt::size(buffer8))
 			{
 				mpt::IO::WriteRaw(*f, reinterpret_cast<mpt::byte*>(buffer8), bufcount);
 				bufcount = 0;
@@ -969,9 +1027,10 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 		int sinc = sample.GetElementarySampleSize();
 		int s_old = 0;
 		const int s_ofs = (GetEncoding() == unsignedPCM) ? 0x80 : 0;
-#ifdef MPT_PLATFORM_LITTLE_ENDIAN
-		if (sample.uFlags[CHN_16BIT]) p++;
-#endif
+		MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
+		{
+			if (sample.uFlags[CHN_16BIT]) p++;
+		}
 
 		for (SmpLength j = 0; j < len; j++)
 		{
@@ -990,7 +1049,7 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 			{
 				buffer8[bufcount++] = (int8)(s_new + s_ofs);
 			}
-			if(bufcount >= CountOf(buffer8))
+			if(bufcount >= mpt::size(buffer8))
 			{
 				mpt::IO::WriteRaw(*f, reinterpret_cast<mpt::byte*>(buffer8), bufcount);
 				bufcount = 0;
@@ -1004,7 +1063,6 @@ size_t SampleIO::WriteSample(std::ostream *f, const ModSample &sample, SmpLength
 
 // Write a sample to file
 size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength maxSamples) const
-//------------------------------------------------------------------------------------------------
 {
 	return WriteSample(&f, sample, maxSamples);
 }
@@ -1012,7 +1070,6 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength
 
 // Write a sample to file
 size_t SampleIO::WriteSample(FILE *f, const ModSample &sample, SmpLength maxSamples) const
-//----------------------------------------------------------------------------------------
 {
 	mpt::FILE_ostream s(f);
 	return WriteSample(f ? &s : nullptr, sample, maxSamples);
diff --git a/soundlib/SampleIO.h b/soundlib/SampleIO.h
index 0a9c66c..23b2101 100644
--- a/soundlib/SampleIO.h
+++ b/soundlib/SampleIO.h
@@ -13,16 +13,16 @@
 #pragma once
 
 
+#include "../common/FileReaderFwd.h"
+
+
 OPENMPT_NAMESPACE_BEGIN
 
 
 struct ModSample;
-class FileReader;
 
 // Sample import / export formats
-//============
 class SampleIO
-//============
 {
 protected:
 	typedef uint32 format_type;
@@ -65,12 +65,7 @@ public:
 	enum Endianness
 	{
 		littleEndian = 0,
-		bigEndian,
-#ifdef MPT_PLATFORM_LITTLE_ENDIAN
-		nativeEndian = littleEndian,
-#else
-		nativeEndian = bigEndian,
-#endif
+		bigEndian = 1,
 	};
 
 	// Sample encoding
@@ -133,6 +128,22 @@ public:
 		format = (format & ~encodingMask) | (encoding << encodingOffset);
 	}
 
+	static inline Endianness GetNativeEndianness()
+	{
+		const mpt::endian_type endian = mpt::endian();
+		MPT_ASSERT((endian == mpt::endian_little) || (endian == mpt::endian_big));
+		Endianness result = littleEndian;
+		MPT_MAYBE_CONSTANT_IF(endian == mpt::endian_little)
+		{
+			result = littleEndian;
+		}
+		MPT_MAYBE_CONSTANT_IF(endian == mpt::endian_big)
+		{
+			result = bigEndian;
+		}
+		return result;
+	}
+
 	void MayNormalize()
 	{
 		if(GetBitDepth() == 24 || GetBitDepth() == 32)
@@ -148,9 +159,9 @@ public:
 	}
 
 	// Return 0 in case of variable-length encoded samples.
-	std::size_t GetEncodedBitsPerSample() const
+	uint8 GetEncodedBitsPerSample() const
 	{
-		std::size_t result = 0;
+		uint8 result = 0;
 		switch(GetEncoding())
 		{
 			case signedPCM:// Integer PCM, signed
diff --git a/soundlib/Snd_defs.h b/soundlib/Snd_defs.h
index 9fcda38..7d15847 100644
--- a/soundlib/Snd_defs.h
+++ b/soundlib/Snd_defs.h
@@ -36,15 +36,15 @@ typedef uint16 INSTRUMENTINDEX;
 typedef uint8 SEQUENCEINDEX;
 	const SEQUENCEINDEX SEQUENCEINDEX_INVALID = uint8_max;
 
-typedef uintptr_t SmpLength;
+typedef uint32 SmpLength;
 
 
-const SmpLength MAX_SAMPLE_LENGTH	= 0x10000000;	// Sample length in *samples*
+const SmpLength MAX_SAMPLE_LENGTH	= 0x10000000;	// Sample length in *frames*
 													// Note: Sample size in bytes can be more than this (= 256 MB).
 
 const ROWINDEX MAX_PATTERN_ROWS			= 1024;
-const ORDERINDEX MAX_ORDERS				= 256;
-const PATTERNINDEX MAX_PATTERNS			= 240;
+const ORDERINDEX MAX_ORDERS				= ORDERINDEX_MAX + 1;
+const PATTERNINDEX MAX_PATTERNS			= 4000;
 const SAMPLEINDEX MAX_SAMPLES			= 4000;
 const INSTRUMENTINDEX MAX_INSTRUMENTS	= 256;
 const PLUGINDEX MAX_MIXPLUGINS			= 250;
@@ -77,7 +77,7 @@ enum MODTYPE
 	MOD_TYPE_ULT	= 0x80,
 	MOD_TYPE_STM	= 0x100,
 	MOD_TYPE_FAR	= 0x200,
-	MOD_TYPE_WAV	= 0x400, // PCM as module
+	MOD_TYPE_DTM	= 0x400,
 	MOD_TYPE_AMF	= 0x800,
 	MOD_TYPE_AMS	= 0x1000,
 	MOD_TYPE_DSM	= 0x2000,
@@ -95,7 +95,7 @@ enum MODTYPE
 	MOD_TYPE_IMF	= 0x2000000,
 	MOD_TYPE_AMS2	= 0x4000000,
 	MOD_TYPE_DIGI	= 0x8000000,
-	MOD_TYPE_UAX	= 0x10000000, // sampleset as module
+	MOD_TYPE_STP	= 0x10000000,
 	MOD_TYPE_PLM	= 0x20000000,
 	MOD_TYPE_SFX	= 0x40000000,
 };
@@ -111,10 +111,12 @@ enum MODCONTAINERTYPE
 	MOD_CONTAINERTYPE_XPK  = 0x4,
 	MOD_CONTAINERTYPE_PP20 = 0x5,
 	MOD_CONTAINERTYPE_MMCMP= 0x6,
+	MOD_CONTAINERTYPE_WAV  = 0x7, // WAV as module
+	MOD_CONTAINERTYPE_UAX  = 0x8, // Unreal sample set as module
 };
 
 
-// Channel flags:
+// Module channel / sample flags
 enum ChannelFlags
 {
 	// Sample Flags
@@ -132,15 +134,15 @@ enum ChannelFlags
 	CHN_KEYOFF			= 0x200,		// exit sustain
 	CHN_NOTEFADE		= 0x400,		// fade note (instrument mode)
 	CHN_SURROUND		= 0x800,		// use surround channel
-	// UNUSED			= 0x1000,
-	// UNUSED			= 0x2000,
+	CHN_WRAPPED_LOOP	= 0x1000,		// loop just wrapped around to loop start (required for correct interpolation around loop points)
+	CHN_AMIGAFILTER		= 0x2000,		// Apply Amiga low-pass filter
 	CHN_FILTER			= 0x4000,		// Apply resonant filter on sample
 	CHN_VOLUMERAMP		= 0x8000,		// Apply volume ramping
 	CHN_VIBRATO			= 0x10000,		// Apply vibrato
 	CHN_TREMOLO			= 0x20000,		// Apply tremolo
 	//CHN_PANBRELLO		= 0x40000,		// Apply panbrello
 	CHN_PORTAMENTO		= 0x80000,		// Apply portamento
-	CHN_GLISSANDO		= 0x100000,		// Glissando mode
+	CHN_GLISSANDO		= 0x100000,		// Glissando (force portamento to semitones) mode
 	CHN_FASTVOLRAMP		= 0x200000,		// Force usage of global ramping settings instead of ramping over the complete render buffer length
 	CHN_EXTRALOUD		= 0x400000,		// Force sample to play at 0dB
 	CHN_REVERB			= 0x800000,		// Apply reverb on this channel
@@ -149,9 +151,10 @@ enum ChannelFlags
 	CHN_NOFX			= 0x4000000,	// dry channel -> CODE#0015 -> DESC="channels management dlg" -! NEW_FEATURE#0015
 	CHN_SYNCMUTE		= 0x8000000,	// keep sample sync on mute
 
-	// Sample storage flags (also saved in ModSample::uFlags, but are not relevant to mixing)
+	// Sample flags (only present in ModSample::uFlags, may overlap with CHN_CHANNELFLAGS)
 	SMP_MODIFIED		= 0x1000,	// Sample data has been edited in the tracker
 	SMP_KEEPONDISK		= 0x2000,	// Sample is not saved to file, data is restored from original sample file
+	SMP_NODEFAULTVOLUME	= 0x4000,	// Ignore default volume setting
 };
 DECLARE_FLAGSET(ChannelFlags)
 
@@ -196,6 +199,8 @@ enum EnvelopeType
 	ENV_VOLUME = 0,
 	ENV_PANNING,
 	ENV_PITCH,
+
+	ENV_MAXTYPES
 };
 
 // Filter Modes
@@ -226,7 +231,7 @@ enum EnvelopeType
 // Module flags - contains both song configuration and playback state... Use SONG_FILE_FLAGS and SONG_PLAY_FLAGS distinguish between the two.
 enum SongFlags
 {
-	SONG_EMBEDMIDICFG	= 0x0001,		// Embed macros in file
+	//SONG_EMBEDMIDICFG	= 0x0001,		// Embed macros in file
 	SONG_FASTVOLSLIDES	= 0x0002,		// Old Scream Tracker 3.0 volume slides
 	SONG_ITOLDEFFECTS	= 0x0004,		// Old Impulse Tracker effect implementations
 	SONG_ITCOMPATGXX	= 0x0008,		// IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects)
@@ -249,10 +254,11 @@ enum SongFlags
 	SONG_POSJUMP		= 0x100000,		// Position jump encountered (internal flag, do not touch)
 	SONG_PT_MODE		= 0x200000,		// ProTracker 1/2 playback mode
 	SONG_PLAYALLSONGS	= 0x400000,		// Play all subsongs consecutively (libopenmpt)
+	SONG_ISAMIGA		= 0x800000,		// Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler
 };
 DECLARE_FLAGSET(SongFlags)
 
-#define SONG_FILE_FLAGS	(SONG_EMBEDMIDICFG|SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_PT_MODE)
+#define SONG_FILE_FLAGS (SONG_FASTVOLSLIDES|SONG_ITOLDEFFECTS|SONG_ITCOMPATGXX|SONG_LINEARSLIDES|SONG_EXFILTERRANGE|SONG_AMIGALIMITS|SONG_S3MOLDVIBRATO|SONG_PT_MODE|SONG_ISAMIGA)
 #define SONG_PLAY_FLAGS (~SONG_FILE_FLAGS)
 
 // Global Options (Renderer)
@@ -290,6 +296,8 @@ enum ResamplingMode
 	SRCMODE_POLYPHASE = 3,
 	SRCMODE_FIRFILTER = 4,
 	SRCMODE_DEFAULT   = 5,
+
+	SRCMODE_AMIGA = 0xFF,	// Not explicitely user-selectable
 };
 
 static inline bool IsKnownResamplingMode(int mode)
@@ -444,11 +452,21 @@ enum PlayBehaviour
 	kST3PortaSampleChange,			// Portamento plus instrument number applies the volume settings of the new sample, but not the new sample itself.
 	kST3VibratoMemory,				// Do not remember vibrato type in effect memory
 	kST3LimitPeriod,				// Cut note instead of limiting  final period (ModPlug Tracker style)
+	KST3PortaAfterArpeggio,			// Portamento after arpeggio continues at the note where the arpeggio left off
 
 	kMODOneShotLoops,				// Allow ProTracker-like oneshot loops
 	kMODIgnorePanning,				// Do not process any panning commands
 	kMODSampleSwap,					// On-the-fly sample swapping
 
+	kFT2NoteOffFlags,				// Set and reset the correct fade/key-off flags with note-off and instrument number after note-off
+	kITMultiSampleInstrumentNumber,	// After portamento to different sample within multi-sampled instrument, lone instrument numbers in patterns always recall the new sample's default settings
+	kRowDelayWithNoteDelay,			// Retrigger note delays on every reptition of a row
+	kFT2TremoloRampWaveform,		// FT2-compatible tremolo ramp down / triangle waveform
+	kFT2PortaUpDownMemory,			// Portamento up and down have separate memory
+
+	kMODOutOfRangeNoteDelay,		// ProTracker behaviour for out-of-range note delays
+	kMODTempoOnSecondTick,			// ProTracker sets tempo after the first tick
+
 	// Add new play behaviours here.
 
 	kMaxPlayBehaviours,
@@ -462,57 +480,133 @@ public:
 	enum { Unity = 1u << 24 };
 	// Normalize the tempo swing coefficients so that they add up to exactly the specified tempo again
 	void Normalize();
-	void resize(size_type _Newsize, value_type val = Unity) { std::vector<uint32>::resize(_Newsize, val); Normalize(); }
+	void resize(size_type newSize, value_type val = Unity) { std::vector<uint32>::resize(newSize, val); Normalize(); }
 
 	static void Serialize(std::ostream &oStrm, const TempoSwing &swing);
 	static void Deserialize(std::istream &iStrm, TempoSwing &swing, const size_t);
 };
 
 
-// Fixed-point type, e.g. used for fractional tempos
+// Sample position and sample position increment value
+struct SamplePosition
+{
+	typedef int64 value_t;
+	typedef uint64 unsigned_value_t;
+
+protected:
+	value_t v;
+
+public:
+	static const uint32 fractMax = 0xFFFFFFFFu;
+	static MPT_FORCEINLINE uint32 GetFractMax() { return fractMax; }
+
+	SamplePosition() : v(0) { }
+	explicit SamplePosition(value_t pos) : v(pos) { }
+	SamplePosition(int32 intPart, uint32 fractPart) : v((static_cast<value_t>(intPart) * (1ll<<32)) | fractPart) { }
+	static SamplePosition Ratio(uint32 dividend, uint32 divisor) { return SamplePosition((static_cast<int64>(dividend) << 32) / divisor); }
+	static SamplePosition FromDouble(double pos) { return SamplePosition(static_cast<value_t>(pos * 4294967296.0)); }
+
+	// Set integer and fractional part
+	MPT_FORCEINLINE SamplePosition &Set(int32 intPart, uint32 fractPart = 0) { v = (static_cast<int64>(intPart) << 32) | fractPart; return *this; }
+	// Set integer part, keep fractional part
+	MPT_FORCEINLINE SamplePosition &SetInt(int32 intPart) { v = (static_cast<value_t>(intPart) << 32) | GetFract(); return *this; }
+	// Get integer part (as sample length / position)
+	MPT_FORCEINLINE SmpLength GetUInt() const { return static_cast<SmpLength>(static_cast<unsigned_value_t>(v) >> 32); }
+	// Get integer part
+	MPT_FORCEINLINE int32 GetInt() const { return static_cast<int32>(static_cast<unsigned_value_t>(v) >> 32); }
+	// Get fractional part
+	MPT_FORCEINLINE uint32 GetFract() const { return static_cast<uint32>(v); }
+	// Get the inverted fractional part
+	MPT_FORCEINLINE SamplePosition GetInvertedFract() const { return SamplePosition(0x100000000ll - GetFract()); }
+	// Get the raw fixed-point value
+	MPT_FORCEINLINE int64 GetRaw() const { return v; }
+	// Negate the current value
+	MPT_FORCEINLINE SamplePosition &Negate() { v = -v; return *this; }
+	// Multiply and divide by given integer scalars
+	MPT_FORCEINLINE SamplePosition &MulDiv(uint32 mul, uint32 div) { v = (v * mul) / div; return *this; }
+	// Removes the integer part, only keeping fractions
+	MPT_FORCEINLINE SamplePosition &RemoveInt() { v &= fractMax; return *this; }
+	// Check if value is 1.0
+	MPT_FORCEINLINE bool IsUnity() const { return v == 0x100000000ll; }
+	// Check if value is 0
+	MPT_FORCEINLINE bool IsZero() const { return v == 0; }
+	// Check if value is > 0
+	MPT_FORCEINLINE bool IsPositive() const { return v > 0; }
+	// Check if value is < 0
+	MPT_FORCEINLINE bool IsNegative() const { return v < 0; }
+
+	// Addition / subtraction of another fixed-point number
+	SamplePosition operator+ (const SamplePosition &other) const { return SamplePosition(v + other.v); }
+	SamplePosition operator- (const SamplePosition &other) const { return SamplePosition(v - other.v); }
+	void operator+= (const SamplePosition &other) { v += other.v; }
+	void operator-= (const SamplePosition &other) { v -= other.v; }
+
+	// Multiplication with integer scalar
+	template<typename T>
+	SamplePosition operator* (T other) const { return SamplePosition(static_cast<value_t>(v * other)); }
+	template<typename T>
+	void operator*= (T other) { v = static_cast<value_t>(v *other); }
+
+	// Division by other fractional point number; returns scalar
+	value_t operator/ (SamplePosition other) const { return v / other.v; }
+	// Division by scalar; returns fractional point number
+	SamplePosition operator/ (int div) const { return SamplePosition(v / div); }
+
+	bool operator== (const SamplePosition &other) const { return v == other.v; }
+	bool operator!= (const SamplePosition &other) const { return v != other.v; }
+	bool operator<= (const SamplePosition &other) const { return v <= other.v; }
+	bool operator>= (const SamplePosition &other) const { return v >= other.v; }
+	bool operator< (const SamplePosition &other) const { return v < other.v; }
+	bool operator> (const SamplePosition &other) const { return v > other.v; }
+};
+
+
+// Aaaand another fixed-point type, e.g. used for fractional tempos
 // Note that this doesn't use classical bit shifting for the fixed point part.
 // This is mostly for the clarity of stored values and to be able to represent any value .0000 to .9999 properly.
+// For easier debugging, use the Debugger Visualizers available in build/vs/debug/
+// to easily display the stored values.
 template<size_t FFact, typename T>
 struct FPInt
 {
 protected:
 	T v;
-	FPInt(T rawValue) : v(rawValue) { }
+	MPT_CONSTEXPR11_FUN FPInt(T rawValue) : v(rawValue) { }
 
 public:
 	static const size_t fractFact = FFact;
 	typedef T store_t;
 
-	FPInt() : v(0) { }
-	FPInt(const FPInt<fractFact, T> &other) : v(other.v) { }
-	FPInt(T intPart, T fractPart) : v((intPart * fractFact) + (fractPart % fractFact)) { }
-	explicit FPInt(float f) : v(static_cast<T>(f * float(fractFact))) { }
-	explicit FPInt(double f) : v(static_cast<T>(f * double(fractFact))) { }
+	MPT_CONSTEXPR11_FUN FPInt() : v(0) { }
+	MPT_CONSTEXPR11_FUN FPInt(const FPInt<fractFact, T> &other) : v(other.v) { }
+	MPT_CONSTEXPR11_FUN FPInt(T intPart, T fractPart) : v((intPart * fractFact) + (fractPart % fractFact)) { }
+	explicit MPT_CONSTEXPR11_FUN FPInt(float f) : v(static_cast<T>(f * float(fractFact))) { }
+	explicit MPT_CONSTEXPR11_FUN FPInt(double f) : v(static_cast<T>(f * double(fractFact))) { }
 
 	// Set integer and fractional part
-	FPInt<fractFact, T> &Set(T intPart, T fractPart = 0) { v = (intPart * fractFact) + (fractPart % fractFact); return *this; }
+	MPT_CONSTEXPR14_FUN FPInt<fractFact, T> &Set(T intPart, T fractPart = 0) { v = (intPart * fractFact) + (fractPart % fractFact); return *this; }
 	// Set raw internal representation directly
-	FPInt<fractFact, T> &SetRaw(T value) { v = value; return *this; }
+	MPT_CONSTEXPR14_FUN FPInt<fractFact, T> &SetRaw(T value) { v = value; return *this; }
 	// Retrieve the integer part of the stored value
-	T GetInt() const { return v / fractFact; }
+	MPT_CONSTEXPR11_FUN T GetInt() const { return v / fractFact; }
 	// Retrieve the fractional part of the stored value
-	T GetFract() const { return v % fractFact; }
+	MPT_CONSTEXPR11_FUN T GetFract() const { return v % fractFact; }
 	// Retrieve the raw internal representation of the stored value
-	T GetRaw() const { return v; }
+	MPT_CONSTEXPR11_FUN T GetRaw() const { return v; }
 	// Formats the stored value as a floating-point value
-	double ToDouble() const { return v / double(fractFact); }
-
-	FPInt<fractFact, T> operator+ (const FPInt<fractFact, T> &other) const { return FPInt<fractFact, T>(v + other.v); }
-	FPInt<fractFact, T> operator- (const FPInt<fractFact, T> &other) const { return FPInt<fractFact, T>(v - other.v); }
-	void operator+= (const FPInt<fractFact, T> &other) { v += other.v; }
-	void operator-= (const FPInt<fractFact, T> &other) { v -= other.v; }
-
-	bool operator== (const FPInt<fractFact, T> &other) const { return v == other.v; }
-	bool operator!= (const FPInt<fractFact, T> &other) const { return v != other.v; }
-	bool operator<= (const FPInt<fractFact, T> &other) const { return v <= other.v; }
-	bool operator>= (const FPInt<fractFact, T> &other) const { return v >= other.v; }
-	bool operator< (const FPInt<fractFact, T> &other) const { return v < other.v; }
-	bool operator> (const FPInt<fractFact, T> &other) const { return v > other.v; }
+	MPT_CONSTEXPR11_FUN double ToDouble() const { return v / double(fractFact); }
+
+	MPT_CONSTEXPR11_FUN FPInt<fractFact, T> operator+ (const FPInt<fractFact, T> &other) const { return FPInt<fractFact, T>(v + other.v); }
+	MPT_CONSTEXPR11_FUN FPInt<fractFact, T> operator- (const FPInt<fractFact, T> &other) const { return FPInt<fractFact, T>(v - other.v); }
+	MPT_CONSTEXPR14_FUN FPInt<fractFact, T> operator+= (const FPInt<fractFact, T> &other) { v += other.v; return *this; }
+	MPT_CONSTEXPR14_FUN FPInt<fractFact, T> operator-= (const FPInt<fractFact, T> &other) { v -= other.v; return *this; }
+
+	MPT_CONSTEXPR11_FUN bool operator== (const FPInt<fractFact, T> &other) const { return v == other.v; }
+	MPT_CONSTEXPR11_FUN bool operator!= (const FPInt<fractFact, T> &other) const { return v != other.v; }
+	MPT_CONSTEXPR11_FUN bool operator<= (const FPInt<fractFact, T> &other) const { return v <= other.v; }
+	MPT_CONSTEXPR11_FUN bool operator>= (const FPInt<fractFact, T> &other) const { return v >= other.v; }
+	MPT_CONSTEXPR11_FUN bool operator< (const FPInt<fractFact, T> &other) const { return v < other.v; }
+	MPT_CONSTEXPR11_FUN bool operator> (const FPInt<fractFact, T> &other) const { return v > other.v; }
 };
 
 typedef FPInt<10000, uint32> TEMPO;
diff --git a/soundlib/Snd_flt.cpp b/soundlib/Snd_flt.cpp
index ba592f2..d2c9225 100644
--- a/soundlib/Snd_flt.cpp
+++ b/soundlib/Snd_flt.cpp
@@ -2,7 +2,9 @@
  * snd_flt.cpp
  * -----------
  * Purpose: Calculation of resonant filter coefficients.
- * Notes  : (currently none)
+ * Notes  : Extended filter range was introduced in MPT 1.12 and went up to 8652 Hz.
+ *          MPT 1.16 upped this to the current 10670 Hz.
+ *          We have no way of telling whether a file was made with MPT 1.12 or 1.16 though.
  * Authors: Olivier Lapicque
  *          OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
@@ -22,12 +24,24 @@ OPENMPT_NAMESPACE_BEGIN
 // EMU10K1 docs: cutoff = reg[0-127]*62+100
 
 
+uint8 CSoundFile::FrequencyToCutOff(double frequency) const
+{
+	// IT Cutoff is computed as cutoff = 110 * 2 ^ (0.25 + x/y), where x is the cutoff and y defines the filter range.
+	// Reversed, this gives us x = (log2(cutoff / 110) - 0.25) * y.
+	// <==========> Rewrite as x = (log2(cutoff) - log2(110) - 0.25) * y.
+	// <==========> Rewrite as x = (ln(cutoff) - ln(110) - 0.25*ln(2)) * y/ln(2).
+	//                                           <4.8737671609324025>
+	double cutoff = (std::log(frequency) - 4.8737671609324025) * (m_SongFlags[SONG_EXFILTERRANGE] ? (20.0 / M_LN2) : (24.0 / M_LN2));
+	Limit(cutoff, 0.0, 127.0);
+	return Util::Round<uint8>(cutoff);
+}
+
+
 uint32 CSoundFile::CutOffToFrequency(uint32 nCutOff, int flt_modifier) const
-//--------------------------------------------------------------------------
 {
 	MPT_ASSERT(nCutOff < 128);
 	float Fc = 110.0f * std::pow(2.0f, 0.25f + ((float)(nCutOff * (flt_modifier + 256))) / (m_SongFlags[SONG_EXFILTERRANGE] ? 20.0f * 512.0f : 24.0f * 512.0f));
-	int freq = static_cast<int>(Fc);
+	int freq = Util::Round<int>(Fc);
 	Limit(freq, 120, 20000);
 	if (freq * 2 > (int)m_MixerSettings.gdwMixingFreq) freq = m_MixerSettings.gdwMixingFreq / 2;
 	return static_cast<uint32>(freq);
@@ -36,7 +50,6 @@ uint32 CSoundFile::CutOffToFrequency(uint32 nCutOff, int flt_modifier) const
 
 // Simple 2-poles resonant filter
 void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modifier) const
-//----------------------------------------------------------------------------------------
 {
 	int cutoff = (int)pChn->nCutOff + (int)pChn->nCutSwing;
 	int resonance = (int)(pChn->nResonance & 0x7F) + (int)pChn->nResSwing;
@@ -52,8 +65,6 @@ void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modif
 		pChn->nResSwing = 0;
 	}
 
-	float d, e;
-
 	// flt_modifier is in [-256, 256], so cutoff is in [0, 127 * 2] after this calculation.
 	const int computedCutoff = cutoff * (flt_modifier + 256) / 256;
 
@@ -71,28 +82,24 @@ void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modif
 
 	pChn->dwFlags.set(CHN_FILTER);
 
+	// 2 * damping factor
+	const float dmpfac = std::pow(10.0f, -resonance * ((24.0f / 128.0f) / 20.0f));
+	const float fc = CutOffToFrequency(cutoff, flt_modifier) * (2.0f * (float)M_PI);
+	float d, e;
 	if(m_playBehaviour[kITFilterBehaviour] && !m_SongFlags[SONG_EXFILTERRANGE])
 	{
-		const float freqParameterMultiplier = 128.0f / (24.0f * 256.0f);
+		const float r = m_MixerSettings.gdwMixingFreq / fc;
 
-		// 2 ^ (i / 24 * 256)
-		float frequency = 110.0f * pow(2.0f, 0.25f + (float)computedCutoff * freqParameterMultiplier);
-		LimitMax(frequency, (float)(m_MixerSettings.gdwMixingFreq / 2));
-		const float r = (float)m_MixerSettings.gdwMixingFreq / (2.0f * (float)M_PI * frequency);
-
-		d = ITResonanceTable[resonance] * r + ITResonanceTable[resonance] - 1.0f;
+		d = dmpfac * r + dmpfac - 1.0f;
 		e = r * r;
 	} else
 	{
-		float fc = (float)CutOffToFrequency(cutoff, flt_modifier);
-		const float dmpfac = pow(10.0f, -((24.0f / 128.0f) * (float)resonance) / 20.0f);
-
-		fc *= (float)(2.0f * (float)M_PI / (float)m_MixerSettings.gdwMixingFreq);
+		const float r = fc / m_MixerSettings.gdwMixingFreq;
 
-		d = (1.0f - 2.0f * dmpfac) * fc;
+		d = (1.0f - 2.0f * dmpfac) * r;
 		LimitMax(d, 2.0f);
-		d = (2.0f * dmpfac - d) / fc;
-		e = pow(1.0f / fc, 2.0f);
+		d = (2.0f * dmpfac - d) / r;
+		e = 1.0f / (r * r);
 	}
 
 	float fg = 1.0f / (1.0f + d + e);
@@ -100,7 +107,7 @@ void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modif
 	float fb1 = -e / (1.0f + d + e);
 
 #if defined(MPT_INTMIXER)
-#define FILTER_CONVERT(x) static_cast<mixsample_t>((x) * (1 << MIXING_FILTER_PRECISION))
+#define FILTER_CONVERT(x) Util::Round<mixsample_t>((x) * (1 << MIXING_FILTER_PRECISION))
 #else
 #define FILTER_CONVERT(x) (x)
 #endif
@@ -123,6 +130,8 @@ void CSoundFile::SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modif
 		pChn->nFilter_B0 = FILTER_CONVERT(fb0);
 		pChn->nFilter_B1 = FILTER_CONVERT(fb1);
 #ifdef MPT_INTMIXER
+		if(pChn->nFilter_A0 == 0)
+			pChn->nFilter_A0 = 1;	// Prevent silence at low filter cutoff and very high sampling rate
 		pChn->nFilter_HP = 0;
 #else
 		pChn->nFilter_HP = 0;
diff --git a/soundlib/Snd_fx.cpp b/soundlib/Snd_fx.cpp
index 529af47..e65eaff 100644
--- a/soundlib/Snd_fx.cpp
+++ b/soundlib/Snd_fx.cpp
@@ -33,7 +33,7 @@ OPENMPT_NAMESPACE_BEGIN
 #else
 #define GLOBALVOL_7BIT_FORMATS_EXT Enum<MODTYPE>::value_type()
 #endif // MODPLUG_TRACKER
-#define GLOBALVOL_7BIT_FORMATS (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_AMS2 | MOD_TYPE_DBM | MOD_TYPE_PTM | MOD_TYPE_MDL | GLOBALVOL_7BIT_FORMATS_EXT)
+#define GLOBALVOL_7BIT_FORMATS (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_AMS2 | MOD_TYPE_DBM | MOD_TYPE_PTM | MOD_TYPE_MDL | MOD_TYPE_DTM | GLOBALVOL_7BIT_FORMATS_EXT)
 
 
 // Compensate frequency slide LUTs depending on whether we are handling periods or frequency - "up" and "down" in function name are seen from frequency perspective.
@@ -54,7 +54,7 @@ protected:
 	const CSoundFile &sndFile;
 
 public:
-	CSoundFile::PlayState state;
+	std::unique_ptr<CSoundFile::PlayState> state;
 	struct ChnSettings
 	{
 		double patLoop;
@@ -64,13 +64,14 @@ public:
 		bool incChanged;		// When using sample sync, note frequency has changed
 		uint8 vol;
 
-		void Reset()
-		{
-			patLoop = 0.0;
-			patLoopSmp = 0;
-			patLoopStart = 0;
-			vol = 0xFF;
-		}
+		ChnSettings()
+			: patLoop(0.0)
+			, patLoopSmp(0)
+			, patLoopStart(0)
+			, ticksToRender(0)
+			, incChanged(false)
+			, vol(0xFF)
+		{ }
 	};
 
 #ifndef NO_PLUGINS
@@ -83,8 +84,7 @@ public:
 
 	GetLengthMemory(const CSoundFile &sf)
 		: sndFile(sf)
-		, state(sf.m_PlayState)
-		, chnSettings(sf.GetNumChannels())
+		, state(mpt::make_unique<CSoundFile::PlayState>(sf.m_PlayState))
 	{
 		Reset();
 	}
@@ -93,26 +93,26 @@ public:
 	{
 		plugParams.clear();
 		elapsedTime = 0.0;
-		state.m_lTotalSampleCount = 0;
-		state.m_nMusicSpeed = sndFile.m_nDefaultSpeed;
-		state.m_nMusicTempo = sndFile.m_nDefaultTempo;
-		state.m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume;
+		state->m_lTotalSampleCount = 0;
+		state->m_nMusicSpeed = sndFile.m_nDefaultSpeed;
+		state->m_nMusicTempo = sndFile.m_nDefaultTempo;
+		state->m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume;
+		chnSettings.assign(sndFile.GetNumChannels(), ChnSettings());
 		for(CHANNELINDEX chn = 0; chn < sndFile.GetNumChannels(); chn++)
 		{
-			chnSettings[chn].Reset();
-			state.Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn);
-			state.Chn[chn].nOldGlobalVolSlide = 0;
-			state.Chn[chn].nOldChnVolSlide = 0;
-			state.Chn[chn].nNote = state.Chn[chn].nNewNote = state.Chn[chn].nLastNote = NOTE_NONE;
+			state->Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn);
+			state->Chn[chn].nOldGlobalVolSlide = 0;
+			state->Chn[chn].nOldChnVolSlide = 0;
+			state->Chn[chn].nNote = state->Chn[chn].nNewNote = state->Chn[chn].nLastNote = NOTE_NONE;
 		}
 	}
 
 	// Increment playback position of sample and envelopes on a channel
 	void RenderChannel(CHANNELINDEX channel, uint32 tickDuration, uint32 portaStart = uint32_max)
 	{
-		ModChannel &chn = state.Chn[channel];
+		ModChannel &chn = state->Chn[channel];
 		uint32 numTicks = chnSettings[channel].ticksToRender;
-		if(numTicks == IGNORE_CHANNEL || numTicks == 0 || (chn.nInc == 0 && !chnSettings[channel].incChanged) || chn.pModSample == nullptr)
+		if(numTicks == IGNORE_CHANNEL || numTicks == 0 || (!chn.IsSamplePlaying() && !chnSettings[channel].incChanged) || chn.pModSample == nullptr)
 		{
 			return;
 		}
@@ -123,15 +123,15 @@ public:
 		const bool updatePitchEnv = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED;
 		bool stopNote = false;
 
-		int32 inc = chn.nInc * tickDuration;
-		if(chn.dwFlags[CHN_PINGPONGFLAG]) inc = -inc;
+		SamplePosition inc = chn.increment * tickDuration;
+		if(chn.dwFlags[CHN_PINGPONGFLAG]) inc.Negate();
 
 		for(uint32 i = 0; i < numTicks; i++)
 		{
 			bool updateInc = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED;
 			if(i >= portaStart)
 			{
-				const ModCommand *p = sndFile.Patterns[state.m_nPattern].GetpModCommand(state.m_nRow, channel);
+				const ModCommand *p = sndFile.Patterns[state->m_nPattern].GetpModCommand(state->m_nRow, channel);
 				if(p->command == CMD_TONEPORTAMENTO) sndFile.TonePortamento(&chn, p->param);
 				else if(p->command == CMD_TONEPORTAVOL) sndFile.TonePortamento(&chn, 0);
 				if(p->volcmd == VOLCMD_TONEPORTAMENTO)
@@ -163,37 +163,54 @@ public:
 
 			if(updateInc || chnSettings[channel].incChanged)
 			{
-				chn.nInc = sndFile.GetChannelIncrement(&chn, period, 0);
+				chn.increment = sndFile.GetChannelIncrement(&chn, period, 0);
 				chnSettings[channel].incChanged = false;
-				inc = chn.nInc * tickDuration;
-				if(chn.dwFlags[CHN_PINGPONGFLAG]) inc = -inc;
+				inc = chn.increment * tickDuration;
+				if(chn.dwFlags[CHN_PINGPONGFLAG]) inc.Negate();
 			}
 
-			chn.nPosLo += inc;
-			chn.nPos += ((int32)chn.nPosLo >> 16);
-			chn.nPosLo &= 0xFFFF;
+			chn.position += inc;
 
-			if(chn.nPos >= sampleEnd)
+			if(chn.position.GetUInt() >= sampleEnd)
 			{
 				if(chn.dwFlags[CHN_LOOP])
 				{
 					// We exceeded the sample loop, go back to loop start.
 					if(chn.dwFlags[CHN_PINGPONGLOOP])
 					{
-						// Ping-pong loops are not supported for now.
-						stopNote = true;
-						break;
+						if(chn.position < SamplePosition(chn.nLoopStart, 0))
+						{
+							chn.position = SamplePosition(chn.nLoopStart + chn.nLoopStart, 0) - chn.position;
+							chn.dwFlags.flip(CHN_PINGPONGFLAG);
+							inc.Negate();
+						}
+						SmpLength posInt = chn.position.GetUInt() - chn.nLoopStart;
+						SmpLength pingpongLength = loopLength * 2;
+						if(sndFile.m_playBehaviour[kITPingPongMode]) pingpongLength--;
+						posInt %= pingpongLength;
+						bool forward = (posInt < loopLength);
+						if(forward)
+							chn.position.SetInt(chn.nLoopStart + posInt);
+						else
+							chn.position.SetInt(chn.nLoopEnd - (posInt - loopLength));
+						if(forward == chn.dwFlags[CHN_PINGPONGFLAG])
+						{
+							chn.dwFlags.flip(CHN_PINGPONGFLAG);
+							inc.Negate();
+						}
 					} else
 					{
-						if(chn.nPos >= chn.nLoopEnd + loopLength)
+						SmpLength posInt = chn.position.GetUInt();
+						if(posInt >= chn.nLoopEnd + loopLength)
 						{
-							const SmpLength overshoot = chn.nPos - chn.nLoopEnd;
-							chn.nPos -= (overshoot / loopLength) * loopLength;
+							const SmpLength overshoot = posInt - chn.nLoopEnd;
+							posInt -= (overshoot / loopLength) * loopLength;
 						}
-						while(chn.nPos >= chn.nLoopEnd)
+						while(posInt >= chn.nLoopEnd)
 						{
-							chn.nPos -= loopLength;
+							posInt -= loopLength;
 						}
+						chn.position.SetInt(posInt);
 					}
 				} else
 				{
@@ -219,7 +236,6 @@ public:
 // [in]  target: Time or position target which should be reached, or no target to get length of the first sub song. Use GetLengthTarget::StartPos to also specify a position from where the seeking should begin.
 // [out] See definition of type GetLengthType for the returned values.
 std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target)
-//--------------------------------------------------------------------------------------------------------
 {
 	std::vector<GetLengthType> results;
 	GetLengthType retval;
@@ -231,15 +247,16 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 	const bool adjustSamplePos = (adjustMode & eAdjustSamplePositions) == eAdjustSamplePositions;
 
 	SEQUENCEINDEX sequence = target.sequence;
-	if(sequence > Order.GetNumSequences()) sequence = Order.GetCurrentSequenceIndex();
-	const ModSequence &orderList = Order.GetSequence(sequence);
+	if(sequence >= Order.GetNumSequences()) sequence = Order.GetCurrentSequenceIndex();
+	const ModSequence &orderList = Order(sequence);
 
 	GetLengthMemory memory(*this);
+	CSoundFile::PlayState &playState = *memory.state;
 	// Temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time)
 	RowVisitor visitedRows(*this, sequence);
 
-	memory.state.m_nNextRow = memory.state.m_nRow = target.startRow;
-	memory.state.m_nNextOrder = memory.state.m_nCurrentOrder = target.startOrder;
+	playState.m_nNextRow = playState.m_nRow = target.startRow;
+	playState.m_nNextOrder = playState.m_nCurrentOrder = target.startOrder;
 
 	// Fast LUTs for commands that are too weird / complicated / whatever to emulate in sample position adjust mode.
 	std::bitset<MAX_EFFECTS> forbiddenCommands;
@@ -260,7 +277,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 		{
 			if(ChnSettings[i].dwFlags[CHN_MUTE]) memory.chnSettings[i].ticksToRender = GetLengthMemory::IGNORE_CHANNEL;
 		}
-		if(target.mode == GetLengthTarget::SeekPosition && target.pos.order < orderList.GetLength())
+		if(target.mode == GetLengthTarget::SeekPosition && target.pos.order < orderList.size())
 		{
 			// If we know where to seek, we can directly rule out any channels on which a new note would be triggered right at the start.
 			const PATTERNINDEX seekPat = orderList[target.pos.order];
@@ -292,40 +309,40 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 		}
 
 		uint32 rowDelay = 0, tickDelay = 0;
-		memory.state.m_nRow = memory.state.m_nNextRow;
-		memory.state.m_nCurrentOrder = memory.state.m_nNextOrder;
+		playState.m_nRow = playState.m_nNextRow;
+		playState.m_nCurrentOrder = playState.m_nNextOrder;
 
 		// Check if pattern is valid
-		memory.state.m_nPattern = memory.state.m_nCurrentOrder < orderList.size() ? orderList[memory.state.m_nCurrentOrder] : orderList.GetInvalidPatIndex();
+		playState.m_nPattern = playState.m_nCurrentOrder < orderList.size() ? orderList[playState.m_nCurrentOrder] : orderList.GetInvalidPatIndex();
 		bool positionJumpOnThisRow = false;
 		bool patternBreakOnThisRow = false;
 		bool patternLoopEndedOnThisRow = false, patternLoopStartedOnThisRow = false;
 
-		if(memory.state.m_nPattern == orderList.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && memory.state.m_nCurrentOrder == target.pos.order)
+		if(playState.m_nPattern == orderList.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order)
 		{
 			// Early test: Target is inside +++ pattern
 			retval.targetReached = true;
 			break;
 		}
 
-		while(memory.state.m_nPattern >= Patterns.Size())
+		while(playState.m_nPattern >= Patterns.Size())
 		{
 			// End of song?
-			if((memory.state.m_nPattern == orderList.GetInvalidPatIndex()) || (memory.state.m_nCurrentOrder >= orderList.size()))
+			if((playState.m_nPattern == orderList.GetInvalidPatIndex()) || (playState.m_nCurrentOrder >= orderList.size()))
 			{
-				if(memory.state.m_nCurrentOrder == orderList.GetRestartPos())
+				if(playState.m_nCurrentOrder == orderList.GetRestartPos())
 					break;
 				else
-					memory.state.m_nCurrentOrder = orderList.GetRestartPos();
+					playState.m_nCurrentOrder = orderList.GetRestartPos();
 			} else
 			{
-				memory.state.m_nCurrentOrder++;
+				playState.m_nCurrentOrder++;
 			}
-			memory.state.m_nPattern = (memory.state.m_nCurrentOrder < orderList.size()) ? orderList[memory.state.m_nCurrentOrder] : orderList.GetInvalidPatIndex();
-			memory.state.m_nNextOrder = memory.state.m_nCurrentOrder;
-			if((!Patterns.IsValidPat(memory.state.m_nPattern)) && visitedRows.IsVisited(memory.state.m_nCurrentOrder, 0, true))
+			playState.m_nPattern = (playState.m_nCurrentOrder < orderList.size()) ? orderList[playState.m_nCurrentOrder] : orderList.GetInvalidPatIndex();
+			playState.m_nNextOrder = playState.m_nCurrentOrder;
+			if((!Patterns.IsValidPat(playState.m_nPattern)) && visitedRows.IsVisited(playState.m_nCurrentOrder, 0, true))
 			{
-				if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(memory.state.m_nNextOrder, memory.state.m_nNextRow, true))
+				if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nNextRow, true))
 				{
 					// We aren't searching for a specific row, or we couldn't find any more unvisited rows.
 					break;
@@ -334,30 +351,30 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					// We haven't found the target row yet, but we found some other unplayed row... continue searching from here.
 					retval.duration = memory.elapsedTime;
 					results.push_back(retval);
-					retval.startRow = memory.state.m_nNextRow;
-					retval.startOrder = memory.state.m_nNextOrder;
+					retval.startRow = playState.m_nNextRow;
+					retval.startOrder = playState.m_nNextOrder;
 					memory.Reset();
 
-					memory.state.m_nRow = memory.state.m_nNextRow;
-					memory.state.m_nCurrentOrder = memory.state.m_nNextOrder;
-					memory.state.m_nPattern = orderList[memory.state.m_nCurrentOrder];
+					playState.m_nRow = playState.m_nNextRow;
+					playState.m_nCurrentOrder = playState.m_nNextOrder;
+					playState.m_nPattern = orderList[playState.m_nCurrentOrder];
 					break;
 				}
 			}
 		}
-		if(memory.state.m_nNextOrder == ORDERINDEX_INVALID)
+		if(playState.m_nNextOrder == ORDERINDEX_INVALID)
 		{
 			// GetFirstUnvisitedRow failed, so there is nothing more to play
 			break;
 		}
 
 		// Skip non-existing patterns
-		if((memory.state.m_nPattern >= Patterns.Size()) || (!Patterns[memory.state.m_nPattern]))
+		if(!Patterns.IsValidPat(playState.m_nPattern))
 		{
 			// If there isn't even a tune, we should probably stop here.
-			if(memory.state.m_nCurrentOrder == orderList.GetRestartPos())
+			if(playState.m_nCurrentOrder == orderList.GetRestartPos())
 			{
-				if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(memory.state.m_nNextOrder, memory.state.m_nNextRow, true))
+				if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nNextRow, true))
 				{
 					// We aren't searching for a specific row, or we couldn't find any more unvisited rows.
 					break;
@@ -366,29 +383,29 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					// We haven't found the target row yet, but we found some other unplayed row... continue searching from here.
 					retval.duration = memory.elapsedTime;
 					results.push_back(retval);
-					retval.startRow = memory.state.m_nNextRow;
-					retval.startOrder = memory.state.m_nNextOrder;
+					retval.startRow = playState.m_nNextRow;
+					retval.startOrder = playState.m_nNextOrder;
 					memory.Reset();
 					continue;
 				}
 			}
-			memory.state.m_nNextOrder = memory.state.m_nCurrentOrder + 1;
+			playState.m_nNextOrder = playState.m_nCurrentOrder + 1;
 			continue;
 		}
 		// Should never happen
-		if(memory.state.m_nRow >= Patterns[memory.state.m_nPattern].GetNumRows())
-			memory.state.m_nRow = 0;
+		if(playState.m_nRow >= Patterns[playState.m_nPattern].GetNumRows())
+			playState.m_nRow = 0;
 
 		// Check whether target was reached.
-		if(target.mode == GetLengthTarget::SeekPosition && memory.state.m_nCurrentOrder == target.pos.order && memory.state.m_nRow == target.pos.row)
+		if(target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order && playState.m_nRow == target.pos.row)
 		{
 			retval.targetReached = true;
 			break;
 		}
 
-		if(visitedRows.IsVisited(memory.state.m_nCurrentOrder, memory.state.m_nRow, true))
+		if(visitedRows.IsVisited(playState.m_nCurrentOrder, playState.m_nRow, true))
 		{
-			if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(memory.state.m_nNextOrder, memory.state.m_nNextRow, true))
+			if(!hasSearchTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nNextRow, true))
 			{
 				// We aren't searching for a specific row, or we couldn't find any more unvisited rows.
 				break;
@@ -397,43 +414,43 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 				// We haven't found the target row yet, but we found some other unplayed row... continue searching from here.
 				retval.duration = memory.elapsedTime;
 				results.push_back(retval);
-				retval.startRow = memory.state.m_nNextRow;
-				retval.startOrder = memory.state.m_nNextOrder;
+				retval.startRow = playState.m_nNextRow;
+				retval.startOrder = playState.m_nNextOrder;
 				memory.Reset();
 				continue;
 			}
 		}
 
-		retval.endOrder = memory.state.m_nCurrentOrder;
-		retval.endRow = memory.state.m_nRow;
+		retval.endOrder = playState.m_nCurrentOrder;
+		retval.endRow = playState.m_nRow;
 
 		// Update next position
-		memory.state.m_nNextRow = memory.state.m_nRow + 1;
-		if(memory.state.m_nNextRow >= Patterns[memory.state.m_nPattern].GetNumRows())
+		playState.m_nNextRow = playState.m_nRow + 1;
+		if(playState.m_nNextRow >= Patterns[playState.m_nPattern].GetNumRows())
 		{
-			memory.state.m_nNextRow = 0;
-			memory.state.m_nNextOrder++;
+			playState.m_nNextRow = 0;
+			playState.m_nNextOrder++;
 		}
 
 		// Jumped to invalid pattern row?
-		if(memory.state.m_nRow >= Patterns[memory.state.m_nPattern].GetNumRows())
+		if(playState.m_nRow >= Patterns[playState.m_nPattern].GetNumRows())
 		{
-			memory.state.m_nRow = 0;
+			playState.m_nRow = 0;
 		}
 		// New pattern?
-		if(!memory.state.m_nRow)
+		if(!playState.m_nRow)
 		{
 			for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
 			{
 				memory.chnSettings[chn].patLoop = memory.elapsedTime;
-				memory.chnSettings[chn].patLoopSmp = memory.state.m_lTotalSampleCount;
+				memory.chnSettings[chn].patLoopSmp = playState.m_lTotalSampleCount;
 			}
 		}
 
-		ModChannel *pChn = memory.state.Chn;
+		ModChannel *pChn = playState.Chn;
 		
 		// For various effects, we need to know first how many ticks there are in this row.
-		const ModCommand *p = Patterns[memory.state.m_nPattern].GetRow(memory.state.m_nRow);
+		const ModCommand *p = Patterns[playState.m_nPattern].GetpModCommand(playState.m_nRow, 0);
 		for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++, p++)
 		{
 			if(m_playBehaviour[kST3NoMutedChannels] && ChnSettings[nChn].dwFlags[CHN_MUTE])	// not even effects are processed on muted S3M channels
@@ -458,17 +475,17 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 				// so it effectively counts down 65536 ticks with speed = 0 (song speed is a 16-bit variable in FT2)
 				if(GetType() == MOD_TYPE_XM && !p->param)
 				{
-					memory.state.m_nMusicSpeed = uint16_max;
+					playState.m_nMusicSpeed = uint16_max;
 				}
 #endif	// MODPLUG_TRACKER
-				if(p->param > 0) memory.state.m_nMusicSpeed = p->param;
+				if(p->param > 0) playState.m_nMusicSpeed = p->param;
 				break;
 
 			case CMD_TEMPO:
 				if(m_playBehaviour[kMODVBlankTiming])
 				{
 					// ProTracker MODs with VBlank timing: All Fxx parameters set the tick count.
-					if(p->param != 0) memory.state.m_nMusicSpeed = p->param;
+					if(p->param != 0) playState.m_nMusicSpeed = p->param;
 				}
 				break;
 
@@ -499,7 +516,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			}
 		}
 		if(rowDelay == 0) rowDelay = 1;
-		const uint32 numTicks = (memory.state.m_nMusicSpeed + tickDelay) * rowDelay;
+		const uint32 numTicks = (playState.m_nMusicSpeed + tickDelay) * rowDelay;
 		const uint32 nonRowTicks = numTicks - rowDelay;
 
 		for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); pChn++, nChn++) if(!pChn->rowCommand.IsEmpty())
@@ -549,12 +566,12 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			// Position Jump
 			case CMD_POSITIONJUMP:
 				positionJumpOnThisRow = true;
-				memory.state.m_nNextOrder = static_cast<ORDERINDEX>(CalculateXParam(memory.state.m_nPattern, memory.state.m_nRow, nChn));
-				memory.state.m_nNextPatStartRow = 0;  // FT2 E60 bug
+				playState.m_nNextOrder = static_cast<ORDERINDEX>(CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn));
+				playState.m_nNextPatStartRow = 0;  // FT2 E60 bug
 				// see https://forum.openmpt.org/index.php?topic=2769.0 - FastTracker resets Dxx if Bxx is called _after_ Dxx
 				// Test case: PatternJump.mod
 				if(!patternBreakOnThisRow || (GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM)))
-					memory.state.m_nNextRow = 0;
+					playState.m_nNextRow = 0;
 
 				if (adjustMode & eAdjust)
 				{
@@ -565,15 +582,15 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			// Pattern Break
 			case CMD_PATTERNBREAK:
 				{
-					ROWINDEX row = PatternBreak(memory.state, nChn, param);
+					ROWINDEX row = PatternBreak(playState, nChn, param);
 					if(row != ROWINDEX_INVALID)
 					{
 						patternBreakOnThisRow = true;
-						memory.state.m_nNextRow = row;
+						playState.m_nNextRow = row;
 
 						if(!positionJumpOnThisRow)
 						{
-							memory.state.m_nNextOrder = memory.state.m_nCurrentOrder + 1;
+							playState.m_nNextOrder = playState.m_nCurrentOrder + 1;
 						}
 						if(adjustMode & eAdjust)
 						{
@@ -587,26 +604,26 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			case CMD_TEMPO:
 				if(!m_playBehaviour[kMODVBlankTiming])
 				{
-					TEMPO tempo(CalculateXParam(memory.state.m_nPattern, memory.state.m_nRow, nChn), 0);
+					TEMPO tempo(CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn), 0);
 					if ((adjustMode & eAdjust) && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
 					{
 						if (tempo.GetInt()) pChn->nOldTempo = static_cast<uint8>(tempo.GetInt()); else tempo.Set(pChn->nOldTempo);
 					}
 
-					if (tempo.GetInt() >= 0x20) memory.state.m_nMusicTempo = tempo;
+					if (tempo.GetInt() >= 0x20) playState.m_nMusicTempo = tempo;
 					else
 					{
 						// Tempo Slide
 						TEMPO tempoDiff((tempo.GetInt() & 0x0F) * nonRowTicks, 0);
 						if ((tempo.GetInt() & 0xF0) == 0x10)
 						{
-							memory.state.m_nMusicTempo += tempoDiff;
+							playState.m_nMusicTempo += tempoDiff;
 						} else
 						{
-							if(tempoDiff < memory.state.m_nMusicTempo)
-								memory.state.m_nMusicTempo -= tempoDiff;
+							if(tempoDiff < playState.m_nMusicTempo)
+								playState.m_nMusicTempo -= tempoDiff;
 							else
-								memory.state.m_nMusicTempo.Set(0);
+								playState.m_nMusicTempo.Set(0);
 						}
 					}
 
@@ -615,7 +632,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					{
 						tempoMax.Set(255);
 					}
-					Limit(memory.state.m_nMusicTempo, tempoMin, tempoMax);
+					Limit(playState.m_nMusicTempo, tempoMin, tempoMax);
 				}
 				break;
 
@@ -651,8 +668,8 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 						for(CHANNELINDEX c = firstChn; c <= lastChn; c++)
 						{
 							memory.chnSettings[c].patLoop = memory.elapsedTime;
-							memory.chnSettings[c].patLoopSmp = memory.state.m_lTotalSampleCount;
-							memory.chnSettings[c].patLoopStart = memory.state.m_nRow;
+							memory.chnSettings[c].patLoopSmp = playState.m_lTotalSampleCount;
+							memory.chnSettings[c].patLoopStart = playState.m_nRow;
 						}
 						patternLoopStartedOnThisRow = true;
 					}
@@ -666,14 +683,14 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					// Pattern Loop
 					if (param & 0x0F)
 					{
-						memory.state.m_nNextPatStartRow = memory.chnSettings[nChn].patLoopStart; // FT2 E60 bug
+						playState.m_nNextPatStartRow = memory.chnSettings[nChn].patLoopStart; // FT2 E60 bug
 						patternLoopEndedOnThisRow = true;
 					} else
 					{
 						patternLoopStartedOnThisRow = true;
 						memory.chnSettings[nChn].patLoop = memory.elapsedTime;
-						memory.chnSettings[nChn].patLoopSmp = memory.state.m_lTotalSampleCount;
-						memory.chnSettings[nChn].patLoopStart = memory.state.m_nRow;
+						memory.chnSettings[nChn].patLoopSmp = playState.m_lTotalSampleCount;
+						memory.chnSettings[nChn].patLoopStart = playState.m_nRow;
 					}
 				}
 				break;
@@ -690,8 +707,24 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			{
 			// Portamento Up/Down
 			case CMD_PORTAMENTOUP:
+				if(param)
+				{
+					// FT2 compatibility: Separate effect memory for all portamento commands
+					// Test case: Porta-LinkMem.xm
+					if(!m_playBehaviour[kFT2PortaUpDownMemory])
+						pChn->nOldPortaDown = param;
+					pChn->nOldPortaUp = param;
+				}
+				break;
 			case CMD_PORTAMENTODOWN:
-				if (param) pChn->nOldPortaUpDown = param;
+				if(param)
+				{
+					// FT2 compatibility: Separate effect memory for all portamento commands
+					// Test case: Porta-LinkMem.xm
+					if(!m_playBehaviour[kFT2PortaUpDownMemory])
+						pChn->nOldPortaUp = param;
+					pChn->nOldPortaDown = param;
+				}
 				break;
 			// Tone-Portamento
 			case CMD_TONEPORTAMENTO:
@@ -716,10 +749,10 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 				// IT compatibility 16. ST3 and IT ignore out-of-range values
 				if(param <= 128)
 				{
-					memory.state.m_nGlobalVolume = param * 2;
+					playState.m_nGlobalVolume = param * 2;
 				} else if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M)))
 				{
-					memory.state.m_nGlobalVolume = 256;
+					playState.m_nGlobalVolume = 256;
 				}
 				break;
 			// Global Volume Slide
@@ -730,31 +763,31 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					if (param) pChn->nOldGlobalVolSlide = param; else param = pChn->nOldGlobalVolSlide;
 				} else
 				{
-					if (param) memory.state.Chn[0].nOldGlobalVolSlide = param; else param = memory.state.Chn[0].nOldGlobalVolSlide;
+					if (param) playState.Chn[0].nOldGlobalVolSlide = param; else param = playState.Chn[0].nOldGlobalVolSlide;
 				}
 				if (((param & 0x0F) == 0x0F) && (param & 0xF0))
 				{
 					param >>= 4;
 					if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
-					memory.state.m_nGlobalVolume += param << 1;
+					playState.m_nGlobalVolume += param << 1;
 				} else if (((param & 0xF0) == 0xF0) && (param & 0x0F))
 				{
 					param = (param & 0x0F) << 1;
 					if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
-					memory.state.m_nGlobalVolume -= param;
+					playState.m_nGlobalVolume -= param;
 				} else if (param & 0xF0)
 				{
 					param >>= 4;
 					param <<= 1;
 					if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
-					memory.state.m_nGlobalVolume += param * nonRowTicks;
+					playState.m_nGlobalVolume += param * nonRowTicks;
 				} else
 				{
 					param = (param & 0x0F) << 1;
 					if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
-					memory.state.m_nGlobalVolume -= param * nonRowTicks;
+					playState.m_nGlobalVolume -= param * nonRowTicks;
 				}
-				Limit(memory.state.m_nGlobalVolume, 0, 256);
+				Limit(playState.m_nGlobalVolume, 0, 256);
 				break;
 			case CMD_CHANNELVOLUME:
 				if (param <= 64) pChn->nGlobalVol = param;
@@ -779,6 +812,15 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 				Panning(pChn, param, Pan8bit);
 				break;
 			case CMD_MODCMDEX:
+				if(param < 0x10)
+				{
+					// LED filter
+					for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
+					{
+						playState.Chn[chn].dwFlags.set(CHN_AMIGAFILTER, !(param & 1));
+					}
+				}
+				MPT_FALLTHROUGH;
 			case CMD_S3MCMDEX:
 				if((param & 0xF0) == 0x80)
 				{
@@ -796,6 +838,12 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			case CMD_FINEVIBRATO:
 				FineVibrato(pChn, param);
 				break;
+			case CMD_TREMOLO:
+				Tremolo(pChn, param);
+				break;
+			case CMD_PANBRELLO:
+				Panbrello(pChn, param);
+				break;
 			}
 
 			switch(pChn->rowCommand.volcmd)
@@ -815,29 +863,66 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 				Vibrato(pChn, pChn->rowCommand.vol);
 				break;
 			}
+
+			// Process vibrato / tremolo / panbrello
+			switch(pChn->rowCommand.command)
+			{
+			case CMD_VIBRATO:
+			case CMD_FINEVIBRATO:
+			case CMD_VIBRATOVOL:
+				if(adjustMode & eAdjust)
+				{
+					uint32 vibTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks;
+					uint32 inc = pChn->nVibratoSpeed * vibTicks;
+					if(m_playBehaviour[kITVibratoTremoloPanbrello])
+						inc *= 4;
+					pChn->nVibratoPos += static_cast<uint8>(inc);
+				}
+				break;
+
+			case CMD_TREMOLO:
+				if(adjustMode & eAdjust)
+				{
+					uint32 tremTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks;
+					uint32 inc = pChn->nTremoloSpeed * tremTicks;
+					if(m_playBehaviour[kITVibratoTremoloPanbrello])
+						inc *= 4;
+					pChn->nTremoloPos += static_cast<uint8>(inc);
+				}
+				break;
+
+			case CMD_PANBRELLO:
+				if(adjustMode & eAdjust)
+				{
+					// Panbrello effect is permanent in compatible mode, so actually apply panbrello for the last tick of this row
+					pChn->nPanbrelloPos += static_cast<uint8>(pChn->nPanbrelloSpeed * (numTicks - 1));
+					ProcessPanbrello(pChn);
+				}
+				break;
+			}
 		}
 
 		// Interpret F00 effect in XM files as "stop song"
-		if(GetType() == MOD_TYPE_XM && memory.state.m_nMusicSpeed == uint16_max)
+		if(GetType() == MOD_TYPE_XM && playState.m_nMusicSpeed == uint16_max)
 		{
 			break;
 		}
 
-		memory.state.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
-		if(Patterns[memory.state.m_nPattern].GetOverrideSignature())
+		playState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
+		if(Patterns[playState.m_nPattern].GetOverrideSignature())
 		{
-			memory.state.m_nCurrentRowsPerBeat = Patterns[memory.state.m_nPattern].GetRowsPerBeat();
+			playState.m_nCurrentRowsPerBeat = Patterns[playState.m_nPattern].GetRowsPerBeat();
 		}
 
-		const uint32 tickDuration = GetTickDuration(memory.state);
+		const uint32 tickDuration = GetTickDuration(playState);
 		const uint32 rowDuration = tickDuration * numTicks;
 		memory.elapsedTime += static_cast<double>(rowDuration) / static_cast<double>(m_MixerSettings.gdwMixingFreq);
-		memory.state.m_lTotalSampleCount += rowDuration;
+		playState.m_lTotalSampleCount += rowDuration;
 
 		if(adjustSamplePos)
 		{
 			// Super experimental and dirty sample seeking
-			pChn = memory.state.Chn;
+			pChn = playState.Chn;
 			for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); pChn++, nChn++)
 			{
 				if(memory.chnSettings[nChn].ticksToRender == GetLengthMemory::IGNORE_CHANNEL)
@@ -855,7 +940,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					if(porta && memory.chnSettings[nChn].incChanged)
 					{
 						// If there's a portamento, the current channel increment mustn't be 0 in NoteChange()
-						pChn->nInc = GetChannelIncrement(pChn, pChn->nPeriod, 0);
+						pChn->increment = GetChannelIncrement(pChn, pChn->nPeriod, 0);
 					}
 					int32 setPan = pChn->nPan;
 					pChn->nNewNote = pChn->nLastNote;
@@ -872,7 +957,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					}
 					if(rowDelay > 1 && startTick != 0 && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
 					{
-						startTick += (memory.state.m_nMusicSpeed + tickDelay) * (rowDelay - 1);
+						startTick += (playState.m_nMusicSpeed + tickDelay) * (rowDelay - 1);
 					}
 					if(!porta) memory.chnSettings[nChn].ticksToRender = 0;
 
@@ -887,7 +972,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					if(m.command == CMD_OFFSET)
 					{
 						bool isExtended = false;
-						SmpLength offset = CalculateXParam(memory.state.m_nPattern, memory.state.m_nRow, nChn, &isExtended);
+						SmpLength offset = CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn, &isExtended);
 						if(!isExtended)
 						{
 							offset <<= 8;
@@ -902,7 +987,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					{
 						memory.RenderChannel(nChn, oldTickDuration);	// Re-sync what we've got so far
 						ReverseSampleOffset(*pChn, m.param);
-						startTick = memory.state.m_nMusicSpeed - 1;
+						startTick = playState.m_nMusicSpeed - 1;
 					} else if(m.volcmd == VOLCMD_OFFSET)
 					{
 						if(m.vol <= CountOf(pChn->pModSample->cues) && pChn->pModSample != nullptr)
@@ -954,7 +1039,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 						}
 					}
 
-					if(m.volcmd < MAX_VOLCMDS && forbiddenVolCommands[m.volcmd])
+					if(m.volcmd < forbiddenVolCommands.size() && forbiddenVolCommands[m.volcmd])
 					{
 						stopNote = true;
 					}
@@ -997,10 +1082,9 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 							// Reverse
 							memory.RenderChannel(nChn, oldTickDuration);	// Re-sync what we've got so far
 							pChn->dwFlags.set(CHN_PINGPONGFLAG);
-							if(!pChn->nPos && pChn->nLength && (m.IsNote() || !pChn->dwFlags[CHN_LOOP]))
+							if(!pChn->position.GetInt() && pChn->nLength && (m.IsNote() || !pChn->dwFlags[CHN_LOOP]))
 							{
-								pChn->nPos = pChn->nLength - 1;
-								pChn->nPosLo = 0xFFFF;
+								pChn->position.Set(pChn->nLength - 1, SamplePosition::fractMax);
 							}
 						} else if((m.param & 0xF0) == 0x70)
 						{
@@ -1037,7 +1121,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 			// This is really just a simple estimation for nested pattern loops. It should handle cases correctly where all parallel loops start and end on the same row.
 			// If one of them starts or ends "in between", it will most likely calculate a wrong duration.
 			// For S3M files, it's also way off.
-			pChn = memory.state.Chn;
+			pChn = playState.Chn;
 			for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++, pChn++)
 			{
 				ModCommand::COMMAND command = pChn->rowCommand.command;
@@ -1047,17 +1131,17 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 				{
 					const double start = memory.chnSettings[nChn].patLoop;
 					if(!startTimes[start]) startTimes[start] = 1;
-					startTimes[start] = Util::lcm<int>(startTimes[start], 1 + (param & 0x0F));
+					startTimes[start] = mpt::lcm(startTimes[start], 1 + (param & 0x0F));
 				}
 			}
-			for(std::map<double, int>::iterator i = startTimes.begin(); i != startTimes.end(); i++)
+			for(const auto &i : startTimes)
 			{
-				memory.elapsedTime += (memory.elapsedTime - i->first) * (double)(i->second - 1);
+				memory.elapsedTime += (memory.elapsedTime - i.first) * (double)(i.second - 1);
 				for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++, pChn++)
 				{
-					if(memory.chnSettings[nChn].patLoop == i->first)
+					if(memory.chnSettings[nChn].patLoop == i.first)
 					{
-						memory.state.m_lTotalSampleCount += (memory.state.m_lTotalSampleCount - memory.chnSettings[nChn].patLoopSmp) * (i->second - 1);
+						playState.m_lTotalSampleCount += (playState.m_lTotalSampleCount - memory.chnSettings[nChn].patLoopSmp) * (i.second - 1);
 						break;
 					}
 				}
@@ -1070,7 +1154,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 					if((pChn->rowCommand.command == CMD_S3MCMDEX && pChn->rowCommand.param >= 0xB1 && pChn->rowCommand.param <= 0xBF))
 					{
 						memory.chnSettings[nChn].patLoop = memory.elapsedTime;
-						memory.chnSettings[nChn].patLoopSmp = memory.state.m_lTotalSampleCount;
+						memory.chnSettings[nChn].patLoopSmp = playState.m_lTotalSampleCount;
 					}
 				}
 			}
@@ -1091,8 +1175,8 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 
 	if(retval.targetReached || target.mode == GetLengthTarget::NoTarget)
 	{
-		retval.lastOrder = memory.state.m_nCurrentOrder;
-		retval.lastRow = memory.state.m_nRow;
+		retval.lastOrder = playState.m_nCurrentOrder;
+		retval.lastRow = playState.m_nRow;
 	}
 	retval.duration = memory.elapsedTime;
 	results.push_back(retval);
@@ -1103,29 +1187,28 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 		if(retval.targetReached || target.mode == GetLengthTarget::NoTarget)
 		{
 			// Target found, or there is no target (i.e. play whole song)...
-			m_PlayState = memory.state;
+			m_PlayState = std::move(playState);
 			m_PlayState.m_nFrameDelay = m_PlayState.m_nPatternDelay = 0;
 			m_PlayState.m_nTickCount = Util::MaxValueOfType(m_PlayState.m_nTickCount) - 1;
 			m_PlayState.m_bPositionChanged = true;
 			for(CHANNELINDEX n = 0; n < GetNumChannels(); n++)
 			{
-				if(memory.state.Chn[n].nLastNote != NOTE_NONE)
+				if(m_PlayState.Chn[n].nLastNote != NOTE_NONE)
 				{
-					m_PlayState.Chn[n].nNewNote = memory.state.Chn[n].nLastNote;
+					m_PlayState.Chn[n].nNewNote = m_PlayState.Chn[n].nLastNote;
 				}
 				if(memory.chnSettings[n].vol != 0xFF && !adjustSamplePos)
 				{
-					if(memory.chnSettings[n].vol > 64) memory.chnSettings[n].vol = 64;
-					m_PlayState.Chn[n].nVolume = memory.chnSettings[n].vol * 4;
+					m_PlayState.Chn[n].nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4;
 				}
 			}
 
 #ifndef NO_PLUGINS
 			// If there were any PC events, update plugin parameters to their latest value.
 			std::bitset<MAX_MIXPLUGINS> plugSetProgram;
-			for(GetLengthMemory::PlugParamMap::const_iterator param = memory.plugParams.begin(); param != memory.plugParams.end(); param++)
+			for(const auto &param : memory.plugParams)
 			{
-				PLUGINDEX plug = param->first.first - 1;
+				PLUGINDEX plug = param.first.first - 1;
 				IMixPlugin *plugin = m_MixPlugins[plug].pMixPlugin;
 				if(plugin != nullptr)
 				{
@@ -1135,7 +1218,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 						plugSetProgram.set(plug);
 						plugin->BeginSetProgram();
 					}
-					plugin->SetParameter(param->first.second, param->second / PlugParamValue(ModCommand::maxColumnValue));
+					plugin->SetParameter(param.first.second, param.second / PlugParamValue(ModCommand::maxColumnValue));
 				}
 			}
 			if(plugSetProgram.any())
@@ -1174,10 +1257,8 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
 
 // Change sample or instrument number.
 void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, bool bUpdVol, bool bResetEnv) const
-//----------------------------------------------------------------------------------------------------------------
 {
-	if(instr >= MAX_INSTRUMENTS) return;
-	const ModInstrument *pIns = (instr < MAX_INSTRUMENTS) ? Instruments[instr] : nullptr;
+	const ModInstrument *pIns = instr <= GetNumInstruments() ? Instruments[instr] : nullptr;
 	const ModSample *pSmp = &Samples[instr];
 	ModCommand::NOTE note = pChn->nNewNote;
 
@@ -1237,7 +1318,8 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b
 		// Special XM hack (also applies to MOD / S3M, except when playing IT-style S3Ms, such as k_vision.s3m)
 		// Test case: PortaSmpChange.mod, PortaSmpChange.s3m
 		if((!instrumentChanged && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) && pIns)
-			|| (GetType() & (MOD_TYPE_MOD | MOD_TYPE_PLM))
+			|| (GetType() == MOD_TYPE_PLM)
+			|| (GetType() == MOD_TYPE_MOD && pChn->IsSamplePlaying())
 			|| m_playBehaviour[kST3PortaSampleChange])
 		{
 			// FT2 doesn't change the sample in this case,
@@ -1245,10 +1327,21 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b
 			returnAfterVolumeAdjust = true;
 		}
 	}
+	// IT compatibility: A lone instrument number should only reset sample properties to those of the corresponding sample in instrument mode.
+	// C#5 01 ... <-- sample 1
+	// C-5 .. g02 <-- sample 2
+	// ... 01 ... <-- still sample 1, but with properties of sample 2
+	// In the above example, no sample change happens on the second row. In the third row, sample 1 keeps playing but with the
+	// volume and panning properties of sample 2.
+	// Test case: InstrAfterMultisamplePorta.it
+	if(m_nInstruments && !instrumentChanged && sampleChanged && pChn->pCurrentSample != nullptr && m_playBehaviour[kITMultiSampleInstrumentNumber] && !pChn->rowCommand.IsNote())
+	{
+		returnAfterVolumeAdjust = true;
+	}
 
 	// IT Compatibility: Envelope pickup after SCx cut (but don't do this when working with plugins, or else envelope carry stops working)
 	// Test case: cut-carry.it
-	if(pChn->nInc == 0 && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (!pIns || !pIns->HasValidMIDIChannel()))
+	if(!pChn->IsSamplePlaying() && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (!pIns || !pIns->HasValidMIDIChannel()))
 	{
 		instrumentChanged = true;
 	}
@@ -1269,13 +1362,16 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b
 	// Update Volume
 	if (bUpdVol && (!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M)) || ((pSmp != nullptr && pSmp->pSample != nullptr) || pChn->HasMIDIOutput())))
 	{
-		pChn->nVolume = 0;
 		if(pSmp)
 		{
-			pChn->nVolume = pSmp->nVolume;
+			if(!pSmp->uFlags[SMP_NODEFAULTVOLUME])
+				pChn->nVolume = pSmp->nVolume;
 		} else if(pIns && pIns->nMixPlug)
 		{
 			pChn->nVolume = pChn->GetVSTVolume();
+		} else
+		{
+			pChn->nVolume = 0;
 		}
 	}
 
@@ -1297,17 +1393,7 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b
 		pChn->nNNA = pIns->nNNA;
 
 	// Update volume
-	if (pIns)
-	{
-		pChn->nInsVol = pIns->nGlobalVol;
-		if(pSmp != nullptr)
-		{
-			pChn->nInsVol = (pSmp->nGlobalVol * pChn->nInsVol) >> 6;
-		}
-	} else if (pSmp != nullptr)
-	{
-		pChn->nInsVol = pSmp->nGlobalVol;
-	}
+	pChn->UpdateInstrumentVolume(pSmp, pIns);
 
 	// Update panning
 	// FT2 compatibility: Only reset panning on instrument numbers, not notes (bUpdVol condition)
@@ -1441,7 +1527,7 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b
 	{
 		// IT/FT2 compatibility: If the note just stopped on the previous tick, prevent it from restarting.
 		// Test cases: PortaJustStoppedNote.xm, PortaJustStoppedNote.it
-		pChn->nInc = 0;
+		pChn->increment.Set(0);
 	}
 
 	pChn->pModSample = pSmp;
@@ -1499,18 +1585,17 @@ void CSoundFile::InstrumentChange(ModChannel *pChn, uint32 instr, bool bPorta, b
 
 	// Fix sample position on instrument change. This is needed for IT "on the fly" sample change.
 	// XXX is this actually called? In ProcessEffects(), a note-on effect is emulated if there's an on the fly sample change!
-	if(pChn->nPos >= pChn->nLength)
+	if(pChn->position.GetUInt() >= pChn->nLength)
 	{
 		if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))
 		{
-			pChn->nPos = pChn->nPosLo = 0;
+			pChn->position.Set(0);
 		}
 	}
 }
 
 
 void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bResetEnv, bool bManual) const
-//------------------------------------------------------------------------------------------------------
 {
 	if (note < NOTE_MIN) return;
 	const ModSample *pSmp = pChn->pModSample;
@@ -1555,7 +1640,7 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 			// IT compatibility: Stopping sample playback by setting sample increment to 0 rather than volume
 			// Test case: NoteOffInstr.it
 			if ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || (m_nInstruments != 0 && !m_playBehaviour[kITInstrWithNoteOff])) pChn->nVolume = 0;
-			if(m_playBehaviour[kITInstrWithNoteOff]) pChn->nInc = 0;
+			if(m_playBehaviour[kITInstrWithNoteOff]) pChn->increment.Set(0);
 			pChn->nFadeOutVol = 0;
 		}
 
@@ -1573,7 +1658,7 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 			pChn->nPortamentoDest = 0;
 		else
 		{
-			pChn->nPortamentoDest = pIns->pTuning->GetStepDistance(pChn->nNote, pChn->m_PortamentoFineSteps, static_cast<CTuningBase::NOTEINDEXTYPE>(note), 0);
+			pChn->nPortamentoDest = pIns->pTuning->GetStepDistance(pChn->nNote, pChn->m_PortamentoFineSteps, static_cast<Tuning::NOTEINDEXTYPE>(note), 0);
 			//Here pChn->nPortamentoDest means 'steps to slide'.
 			pChn->m_PortamentoFineSteps = -pChn->nPortamentoDest;
 		}
@@ -1592,7 +1677,7 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 	if(!bPorta && pSmp && m_playBehaviour[kITMultiSampleBehaviour])
 		pChn->nC5Speed = pSmp->nC5Speed;
 
-	if(bPorta && pChn->nInc == 0)
+	if(bPorta && !pChn->IsSamplePlaying())
 	{
 		if(m_playBehaviour[kFT2PortaNoNote])
 		{
@@ -1653,29 +1738,29 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 			// Volume Swing
 			if(pIns->nVolSwing)
 			{
-				pChn->nVolSwing = ((mpt::random<int8>(AccessPRNG()) * pIns->nVolSwing) / 64 + 1) * (m_playBehaviour[kITSwingBehaviour] ? pChn->nInsVol : ((pChn->nVolume + 1) / 2)) / 199;
+				pChn->nVolSwing = static_cast<int16>(((mpt::random<int8>(AccessPRNG()) * pIns->nVolSwing) / 64 + 1) * (m_playBehaviour[kITSwingBehaviour] ? pChn->nInsVol : ((pChn->nVolume + 1) / 2)) / 199);
 			}
 			// Pan Swing
 			if(pIns->nPanSwing)
 			{
-				pChn->nPanSwing = ((mpt::random<int8>(AccessPRNG()) * pIns->nPanSwing * 4) / 128);
+				pChn->nPanSwing = static_cast<int16>(((mpt::random<int8>(AccessPRNG()) * pIns->nPanSwing * 4) / 128));
 				if(!m_playBehaviour[kITSwingBehaviour])
 				{
-					pChn->nRestorePanOnNewNote = pChn->nPan + 1;
+					pChn->nRestorePanOnNewNote = static_cast<int16>(pChn->nPan + 1);
 				}
 			}
 			// Cutoff Swing
 			if(pIns->nCutSwing)
 			{
 				int32 d = ((int32)pIns->nCutSwing * (int32)(static_cast<int32>(mpt::random<int8>(AccessPRNG())) + 1)) / 128;
-				pChn->nCutSwing = (int16)((d * pChn->nCutOff + 1) / 128);
+				pChn->nCutSwing = static_cast<int16>((d * pChn->nCutOff + 1) / 128);
 				pChn->nRestoreCutoffOnNewNote = pChn->nCutOff + 1;
 			}
 			// Resonance Swing
 			if(pIns->nResSwing)
 			{
 				int32 d = ((int32)pIns->nResSwing * (int32)(static_cast<int32>(mpt::random<int8>(AccessPRNG())) + 1)) / 128;
-				pChn->nResSwing = (int16)((d * pChn->nResonance + 1) / 128);
+				pChn->nResSwing = static_cast<int16>((d * pChn->nResonance + 1) / 128);
 				pChn->nRestoreResonanceOnNewNote = pChn->nResonance + 1;
 			}
 		}
@@ -1705,12 +1790,10 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 			pChn->nLength = pSmp->nLength;
 			pChn->nLoopEnd = pSmp->nLength;
 			pChn->nLoopStart = 0;
-			pChn->nPos = 0;
-			pChn->nPosLo = 0;
+			pChn->position.Set(0);
 			if(m_SongFlags[SONG_PT_MODE] && !pChn->rowCommand.instr)
 			{
-				pChn->nPos = pChn->proTrackerOffset;
-				LimitMax(pChn->nPos, pChn->nLength - 1);
+				pChn->position.SetInt(std::min<SmpLength>(pChn->proTrackerOffset, pChn->nLength - 1));
 			} else
 			{
 				pChn->proTrackerOffset = 0;
@@ -1736,7 +1819,7 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 			if(pChn->dwFlags[CHN_REVERSE])
 			{
 				pChn->dwFlags.set(CHN_PINGPONGFLAG);
-				pChn->nPos = pChn->nLength - 1;
+				pChn->position.SetInt(pChn->nLength - 1);
 			}
 
 			// Handle "retrigger" waveform type
@@ -1747,7 +1830,7 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 					pChn->nVibratoPos = 0x10;
 				else if(GetType() == MOD_TYPE_MTM)
 					pChn->nVibratoPos = 0x20;
-				else
+				else if(!(GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM)))
 					pChn->nVibratoPos = 0;
 			}
 			// IT Compatibility: No "retrigger" waveform here
@@ -1756,7 +1839,7 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 				pChn->nTremoloPos = 0;
 			}
 		}
-		if(pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart;
+		if(pChn->position.GetUInt() >= pChn->nLength) pChn->position.SetInt(pChn->nLoopStart);
 	} else
 	{
 		bPorta = false;
@@ -1856,12 +1939,17 @@ void CSoundFile::NoteChange(ModChannel *pChn, int note, bool bPorta, bool bReset
 	{
 		if (!bManual) pChn->nPeriod = 0;
 	}
+
+	// Reset the Amiga resampler for this channel
+	if(!bPorta)
+	{
+		pChn->paulaState.Reset();
+	}
 }
 
 
 // Apply sample or instrumernt panning
 void CSoundFile::ApplyInstrumentPanning(ModChannel *pChn, const ModInstrument *instr, const ModSample *smp) const
-//---------------------------------------------------------------------------------------------------------------
 {
 	int32 newPan = int32_min;
 	// Default instrument panning
@@ -1885,7 +1973,6 @@ void CSoundFile::ApplyInstrumentPanning(ModChannel *pChn, const ModInstrument *i
 
 
 CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const
-//-------------------------------------------------------------
 {
 	const ModChannel *pChn = &m_PlayState.Chn[nChn];
 
@@ -1919,19 +2006,18 @@ CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const
 
 
 CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, bool forceCut)
-//-----------------------------------------------------------------------------------------
 {
 	CHANNELINDEX nnaChn = CHANNELINDEX_INVALID;
-	ModChannel *pChn = &m_PlayState.Chn[nChn];
+	ModChannel &srcChn = m_PlayState.Chn[nChn];
 	const ModInstrument *pIns = nullptr;
 	if(!ModCommand::IsNote(static_cast<ModCommand::NOTE>(note)))
 	{
 		return nnaChn;
 	}
 	// Always NNA cut - using
-	if((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_MT2)) || !m_nInstruments || forceCut) && !pChn->HasMIDIOutput())
+	if((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_MT2)) || !m_nInstruments || forceCut) && !srcChn.HasMIDIOutput())
 	{
-		if(!pChn->nLength || pChn->dwFlags[CHN_MUTE] || !(pChn->rightVol | pChn->leftVol))
+		if(!srcChn.nLength || srcChn.dwFlags[CHN_MUTE] || !(srcChn.rightVol | srcChn.leftVol))
 		{
 			return CHANNELINDEX_INVALID;
 		}
@@ -1940,7 +2026,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 		if(!nnaChn) return CHANNELINDEX_INVALID;
 		ModChannel &chn = m_PlayState.Chn[nnaChn];
 		// Copy Channel
-		chn = *pChn;
+		chn = srcChn;
 		chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_MUTE | CHN_PORTAMENTO);
 		chn.nPanbrelloOffset = 0;
 		chn.nMasterChn = nChn + 1;
@@ -1950,16 +2036,17 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 		chn.nFadeOutVol = 0;
 		chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
 		// Stop this channel
-		pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
-		pChn->nROfs = pChn->nLOfs = 0;
-		pChn->rightVol = pChn->leftVol = 0;
+		srcChn.nLength = 0;
+		srcChn.position.Set(0);
+		srcChn.nROfs = srcChn.nLOfs = 0;
+		srcChn.rightVol = srcChn.leftVol = 0;
 		return nnaChn;
 	}
-	if(instr >= MAX_INSTRUMENTS) instr = 0;
-	const ModSample *pSample = pChn->pModSample;
+	if(instr > GetNumInstruments()) instr = 0;
+	const ModSample *pSample = srcChn.pModSample;
 	// If no instrument is given, assume previous instrument to still be valid.
 	// Test case: DNA-NoInstr.it
-	pIns = instr > 0 ? Instruments[instr] : pChn->pModInstrument;
+	pIns = instr > 0 ? Instruments[instr] : srcChn.pModInstrument;
 	if(pIns != nullptr)
 	{
 		uint32 n = pIns->Keyboard[note - NOTE_MIN];
@@ -1975,40 +2062,40 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 			return CHANNELINDEX_INVALID;
 		}
 	}
-	ModChannel *p = pChn;
-	//if (!pIns) return;
-	if (pChn->dwFlags[CHN_MUTE]) return CHANNELINDEX_INVALID;
+	if (srcChn.dwFlags[CHN_MUTE])
+		return CHANNELINDEX_INVALID;
 
 	bool applyDNAtoPlug;	//rewbs.VSTiNNA
 
-	for(CHANNELINDEX i = nChn; i < MAX_CHANNELS; p++, i++)
-	if(i >= m_nChannels || p == pChn)
+	for(CHANNELINDEX i = nChn; i < MAX_CHANNELS; i++)
+	if(i >= m_nChannels || i == nChn)
 	{
+		ModChannel &chn = m_PlayState.Chn[i];
 		applyDNAtoPlug = false; //rewbs.VSTiNNA
-		if((p->nMasterChn == nChn + 1 || p == pChn) && p->pModInstrument != nullptr)
+		if((chn.nMasterChn == nChn + 1 || i == nChn) && chn.pModInstrument != nullptr)
 		{
 			bool bOk = false;
 			// Duplicate Check Type
-			switch(p->pModInstrument->nDCT)
+			switch(chn.pModInstrument->nDCT)
 			{
 			// Note
 			case DCT_NOTE:
-				if(note && p->nNote == note && pIns == p->pModInstrument) bOk = true;
+				if(note && chn.nNote == note && pIns == chn.pModInstrument) bOk = true;
 				if(pIns && pIns->nMixPlug) applyDNAtoPlug = true; //rewbs.VSTiNNA
 				break;
 			// Sample
 			case DCT_SAMPLE:
-				if(pSample != nullptr && pSample == p->pModSample) bOk = true;
+				if(pSample != nullptr && pSample == chn.pModSample) bOk = true;
 				break;
 			// Instrument
 			case DCT_INSTRUMENT:
-				if(pIns == p->pModInstrument) bOk = true;
+				if(pIns == chn.pModInstrument) bOk = true;
 				//rewbs.VSTiNNA
 				if(pIns && pIns->nMixPlug) applyDNAtoPlug = true;
 				break;
 			// Plugin
 			case DCT_PLUGIN:
-				if(pIns && (pIns->nMixPlug) && (pIns->nMixPlug == p->pModInstrument->nMixPlug))
+				if(pIns && (pIns->nMixPlug) && (pIns->nMixPlug == chn.pModInstrument->nMixPlug))
 				{
 					applyDNAtoPlug = true;
 					bOk = true;
@@ -2021,55 +2108,41 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 			if (bOk)
 			{
 #ifndef NO_PLUGINS
-				if (applyDNAtoPlug && p->nNote != NOTE_NONE)
+				if (applyDNAtoPlug && chn.nNote != NOTE_NONE)
 				{
-					ModCommand::NOTE plugNote;
-					if(p->nArpeggioLastNote != NOTE_NONE)
-					{
-						plugNote = p->nArpeggioLastNote;
-					} else
-					{
-						plugNote = p->nNote;
-						// Caution: When in compatible mode, ModChannel::nNote stores the "real" note, not the mapped note!
-						if(m_playBehaviour[kITRealNoteMapping] && plugNote < CountOf(p->pModInstrument->NoteMap))
-						{
-							plugNote = p->pModInstrument->NoteMap[plugNote - NOTE_MIN];
-						}
-					}
-
-					switch(p->pModInstrument->nDNA)
+					switch(chn.pModInstrument->nDNA)
 					{
 					case DNA_NOTECUT:
 					case DNA_NOTEOFF:
 					case DNA_NOTEFADE:
 						// Switch off duplicated note played on this plugin
-						SendMIDINote(i, plugNote + NOTE_MAX_SPECIAL, 0);
-						p->nArpeggioLastNote = NOTE_NONE;
+						SendMIDINote(i, chn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]) + NOTE_MAX_SPECIAL, 0);
+						chn.nArpeggioLastNote = NOTE_NONE;
 						break;
 					}
 				}
 #endif // NO_PLUGINS
 
-				switch(p->pModInstrument->nDNA)
+				switch(chn.pModInstrument->nDNA)
 				{
 				// Cut
 				case DNA_NOTECUT:
-					KeyOff(p);
-					p->nVolume = 0;
+					KeyOff(&chn);
+					chn.nVolume = 0;
 					break;
 				// Note Off
 				case DNA_NOTEOFF:
-					KeyOff(p);
+					KeyOff(&chn);
 					break;
 				// Note Fade
 				case DNA_NOTEFADE:
-					p->dwFlags.set(CHN_NOTEFADE);
+					chn.dwFlags.set(CHN_NOTEFADE);
 					break;
 				}
-				if(!p->nVolume)
+				if(!chn.nVolume)
 				{
-					p->nFadeOutVol = 0;
-					p->dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
+					chn.nFadeOutVol = 0;
+					chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
 				}
 			}
 		}
@@ -2079,7 +2152,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 	bool applyNNAtoPlug = false;
 #ifndef NO_PLUGINS
 	IMixPlugin *pPlugin = nullptr;
-	if(pChn->HasMIDIOutput() && ModCommand::IsNote(pChn->nNote)) // instro sends to a midi chan
+	if(srcChn.HasMIDIOutput() && ModCommand::IsNote(srcChn.nNote)) // instro sends to a midi chan
 	{
 		PLUGINDEX nPlugin = GetBestPlugin(nChn, PrioritiseInstrument, RespectMutes);
 
@@ -2088,83 +2161,70 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 			pPlugin =  m_MixPlugins[nPlugin-1].pMixPlugin;
 			if(pPlugin)
 			{
-				// apply NNA to this Plug iff this plug is currently playing a note on this tracking chan
+				// apply NNA to this plugin iff it is currently playing a note on this tracking channel
 				// (and if it is playing a note, we know that would be the last note played on this chan).
-				ModCommand::NOTE plugNote;
-				if(pChn->nArpeggioLastNote != NOTE_NONE)
-				{
-					plugNote = pChn->nArpeggioLastNote;
-				} else
-				{
-					plugNote = pChn->nNote;
-					// Caution: When in compatible mode, ModChannel::nNote stores the "real" note, not the mapped note!
-					if(m_playBehaviour[kITRealNoteMapping] && plugNote < CountOf(pChn->pModInstrument->NoteMap))
-					{
-						plugNote = pChn->pModInstrument->NoteMap[plugNote - NOTE_MIN];
-					}
-				}
-
-				applyNNAtoPlug = pPlugin->IsNotePlaying(plugNote, GetBestMidiChannel(nChn), nChn);
+				applyNNAtoPlug = pPlugin->IsNotePlaying(srcChn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]), GetBestMidiChannel(nChn), nChn);
 			}
 		}
 	}
 #endif // NO_PLUGINS
 
 	// New Note Action
-	//if ((pChn->nVolume) && (pChn->nLength))
-	if((pChn->nVolume != 0 && pChn->nLength != 0) || applyNNAtoPlug) //rewbs.VSTiNNA
+	//if ((pChn.nVolume) && (pChn.nLength))
+	if((srcChn.nVolume != 0 && srcChn.nLength != 0) || applyNNAtoPlug) //rewbs.VSTiNNA
 	{
 		nnaChn = GetNNAChannel(nChn);
 		if(nnaChn != 0)
 		{
-			ModChannel *p = &m_PlayState.Chn[nnaChn];
+			ModChannel &chn = m_PlayState.Chn[nnaChn];
 			// Copy Channel
-			*p = *pChn;
-			p->dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_PORTAMENTO);
-			p->nPanbrelloOffset = 0;
+			chn = srcChn;
+			chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_PORTAMENTO);
+			chn.nPanbrelloOffset = 0;
 
-			p->nMasterChn = nChn < GetNumChannels() ? nChn + 1 : 0;
-			p->nCommand = CMD_NONE;
+			chn.nMasterChn = nChn < GetNumChannels() ? nChn + 1 : 0;
+			chn.nCommand = CMD_NONE;
 #ifndef NO_PLUGINS
 			if(applyNNAtoPlug && pPlugin)
 			{
 				//Move note to the NNA channel (odd, but makes sense with DNA stuff).
 				//Actually a bad idea since it then become very hard to kill some notes.
-				//pPlugin->MoveNote(pChn->nNote, pChn->pModInstrument->nMidiChannel, nChn, n);
-				switch(pChn->nNNA)
+				//pPlugin->MoveNote(pChn.nNote, pChn.pModInstrument->nMidiChannel, nChn, n);
+				switch(srcChn.nNNA)
 				{
 				case NNA_NOTEOFF:
 				case NNA_NOTECUT:
 				case NNA_NOTEFADE:
 					//switch off note played on this plugin, on this tracker channel and midi channel
-					//pPlugin->MidiCommand(pChn->pModInstrument->nMidiChannel, pChn->pModInstrument->nMidiProgram, pChn->nNote + NOTE_MAX_SPECIAL, 0, n);
+					//pPlugin->MidiCommand(pChn.pModInstrument->nMidiChannel, pChn.pModInstrument->nMidiProgram, pChn.nNote + NOTE_MAX_SPECIAL, 0, n);
 					SendMIDINote(nChn, NOTE_KEYOFF, 0);
-					pChn->nArpeggioLastNote = NOTE_NONE;
+					srcChn.nArpeggioLastNote = NOTE_NONE;
 					break;
 				}
 			}
 #endif // NO_PLUGINS
 
 			// Key Off the note
-			switch(pChn->nNNA)
+			switch(srcChn.nNNA)
 			{
 			case NNA_NOTEOFF:
-				KeyOff(p);
+				KeyOff(&chn);
 				break;
 			case NNA_NOTECUT:
-				p->nFadeOutVol = 0;
+				chn.nFadeOutVol = 0;
 			case NNA_NOTEFADE:
-				p->dwFlags.set(CHN_NOTEFADE);
+				chn.dwFlags.set(CHN_NOTEFADE);
 				break;
 			}
-			if(!p->nVolume)
+			if(!chn.nVolume)
 			{
-				p->nFadeOutVol = 0;
-				p->dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
+				chn.nFadeOutVol = 0;
+				chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
 			}
 			// Stop this channel
-			pChn->nLength = pChn->nPos = pChn->nPosLo = 0;
-			pChn->nROfs = pChn->nLOfs = 0;
+			srcChn.nLength = 0;
+			srcChn.position.Set(0);
+			srcChn.nROfs = srcChn.nLOfs = 0;
 		}
 	}
 	return nnaChn;
@@ -2172,7 +2232,6 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo
 
 
 bool CSoundFile::ProcessEffects()
-//-------------------------------
 {
 	ModChannel *pChn = m_PlayState.Chn;
 	ROWINDEX nBreakRow = ROWINDEX_INVALID;		// Is changed if a break to row command is encountered
@@ -2189,9 +2248,9 @@ bool CSoundFile::ProcessEffects()
 	{
 		const uint32 tickCount = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay);
 		uint32 instr = pChn->rowCommand.instr;
-		uint32 volcmd = pChn->rowCommand.volcmd;
+		ModCommand::VOLCMD volcmd = pChn->rowCommand.volcmd;
 		uint32 vol = pChn->rowCommand.vol;
-		uint32 cmd = pChn->rowCommand.command;
+		ModCommand::COMMAND cmd = pChn->rowCommand.command;
 		uint32 param = pChn->rowCommand.param;
 		bool bPorta = pChn->rowCommand.IsPortamento();
 
@@ -2256,7 +2315,7 @@ bool CSoundFile::ProcessEffects()
 			instr = 0;
 			volcmd = VOLCMD_NONE;
 			vol = 0;
-			cmd = 0;
+			cmd = CMD_NONE;
 			param = 0;
 			bPorta = false;
 		}
@@ -2371,17 +2430,17 @@ bool CSoundFile::ProcessEffects()
 		}
 
 		bool triggerNote = (m_PlayState.m_nTickCount == nStartTick);	// Can be delayed by a note delay effect
-		if((GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) && nStartTick > 0 && tickCount == nStartTick)
-		{
-			// IT compatibility: Delayed notes (using SDx) that are on the same row as a Row Delay effect are retriggered. Scream Tracker 3 does the same.
-			// Test case: PatternDelay-NoteDelay.it
-			triggerNote = true;
-		} else if(m_playBehaviour[kFT2OutOfRangeDelay] && nStartTick >= m_PlayState.m_nMusicSpeed)
+		if(m_playBehaviour[kFT2OutOfRangeDelay] && nStartTick >= m_PlayState.m_nMusicSpeed)
 		{
 			// FT2 compatibility: Note delays greater than the song speed should be ignored.
 			// However, EEx pattern delay is *not* considered at all.
 			// Test case: DelayCombination.xm, PortaDelay.xm
 			triggerNote = false;
+		} else if(m_playBehaviour[kRowDelayWithNoteDelay] && nStartTick > 0 && tickCount == nStartTick)
+		{
+			// IT compatibility: Delayed notes (using SDx) that are on the same row as a Row Delay effect are retriggered. Scream Tracker 3 / FastTracker 2 do the same.
+			// Test case: PatternDelay-NoteDelay.it, PatternDelay-NoteDelay.xm
+			triggerNote = true;
 		}
 
 		// IT compatibility: Tick-0 vs non-tick-0 effect distinction is always based on tick delay.
@@ -2403,11 +2462,16 @@ bool CSoundFile::ProcessEffects()
 			// Instrument number resets the stacked ProTracker offset.
 			// Test case: ptoffset.mod
 			pChn->proTrackerOffset = 0;
-			// ProTracker compatibility: Instrument change always happens on the first tick, even when there is a note delay.
+			// ProTracker compatibility: Sample properties are always loaded on the first tick, even when there is a note delay.
 			// Test case: InstrDelay.mod
-			if(!triggerNote)
+			if(!triggerNote && pChn->IsSamplePlaying())
 			{
-				InstrumentChange(pChn, instr, true, true, false);
+				pChn->nNewIns = static_cast<ModCommand::INSTR>(instr);
+				if(instr <= GetNumSamples())
+				{
+					pChn->nVolume = Samples[instr].nVolume;
+					pChn->nFineTune = Samples[instr].nFineTune;
+				}
 			}
 		}
 
@@ -2476,7 +2540,7 @@ bool CSoundFile::ProcessEffects()
 			bool reloadSampleSettings = (m_playBehaviour[kFT2ReloadSampleSettings] && instr != 0);
 			// ProTracker Compatibility: If a sample was stopped before, lone instrument numbers can retrigger it
 			// Test case: PTSwapEmpty.mod
-			bool keepInstr = (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (m_playBehaviour[kMODSampleSwap] && pChn->nInc == 0 && pChn->pModSample != nullptr && pChn->pModSample->pSample == nullptr);
+			bool keepInstr = (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (m_playBehaviour[kMODSampleSwap] && !pChn->IsSamplePlaying() && pChn->pModSample != nullptr && pChn->pModSample->pSample == nullptr);
 
 			// Now it's time for some FT2 crap...
 			if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
@@ -2493,6 +2557,10 @@ bool CSoundFile::ProcessEffects()
 					note = NOTE_NONE;
 					instr = 0;
 					retrigEnv = false;
+					// FT2 Compatbility: Start fading the note for notes with no delay. Only relevant when a volume command is encountered after the note-off.
+					// Test case: NoteOffFadeNoEnv.xm
+					if(m_SongFlags[SONG_FIRSTTICK] && m_playBehaviour[kFT2NoteOffFlags])
+						pChn->dwFlags.set(CHN_NOTEFADE);
 				} else if(m_playBehaviour[kFT2RetrigWithNoteDelay] && !m_SongFlags[SONG_FIRSTTICK])
 				{
 					// FT2 Compatibility: Some special hacks for rogue note delays... (EDx with x > 0)
@@ -2542,7 +2610,8 @@ bool CSoundFile::ProcessEffects()
 
 				if(oldSample != nullptr)
 				{
-					pChn->nVolume = oldSample->nVolume;
+					if(!oldSample->uFlags[SMP_NODEFAULTVOLUME])
+						pChn->nVolume = oldSample->nVolume;
 					if(reloadSampleSettings)
 					{
 						// Also reload panning
@@ -2563,15 +2632,18 @@ bool CSoundFile::ProcessEffects()
 				//IT compatibility: Instrument with no note.
 				if(m_playBehaviour[kITInstrWithoutNote] || GetType() == MOD_TYPE_PLM)
 				{
+					// IT compatibility: Completely retrigger note after sample end to also reset portamento.
+					// Test case: PortaResetAfterRetrigger.it
+					bool triggerAfterSmpEnd = m_playBehaviour[kITMultiSampleInstrumentNumber] && !pChn->IsSamplePlaying();
 					if(GetNumInstruments())
 					{
 						// Instrument mode
-						if(instr < MAX_INSTRUMENTS && pChn->pModInstrument != Instruments[instr])
+						if(instr <= GetNumInstruments() && (pChn->pModInstrument != Instruments[instr] || triggerAfterSmpEnd))
 							note = pChn->nNote;
 					} else
 					{
 						// Sample mode
-						if(instr < MAX_SAMPLES && pChn->pModSample != &Samples[instr])
+						if(instr < MAX_SAMPLES && (pChn->pModSample != &Samples[instr] || triggerAfterSmpEnd))
 							note = pChn->nNote;
 					}
 				}
@@ -2584,11 +2656,13 @@ bool CSoundFile::ProcessEffects()
 					pChn->nAutoVibDepth = 0;
 					pChn->nAutoVibPos = 0;
 					pChn->nFadeOutVol = 65536;
+					// FT2 Compatbility: Reset key-off status with instrument number
+					// Test case: NoteOffInstrChange.xm
+					if(m_playBehaviour[kFT2NoteOffFlags])
+						pChn->dwFlags.reset(CHN_KEYOFF);
 				}
 				if (!keepInstr) instr = 0;
 			}
-			// Invalid Instrument ?
-			if (instr >= MAX_INSTRUMENTS) instr = 0;
 
 			// Note Cut/Off/Fade => ignore instrument
 			if (note >= NOTE_MIN_SPECIAL)
@@ -2606,7 +2680,7 @@ bool CSoundFile::ProcessEffects()
 							smp = Instruments[instr]->Keyboard[pChn->nLastNote - NOTE_MIN];
 						}
 					}
-					if(smp > 0 && smp <= GetNumSamples())
+					if(smp > 0 && smp <= GetNumSamples() && !Samples[smp].uFlags[SMP_NODEFAULTVOLUME])
 						pChn->nVolume = Samples[smp].nVolume;
 				}
 				instr = 0;
@@ -2666,17 +2740,17 @@ bool CSoundFile::ProcessEffects()
 					if(ModCommand::IsNote(note) && oldSample != pChn->pModSample)
 					{
 						//const bool newInstrument = oldInstrument != pChn->pModInstrument && pChn->pModInstrument->Keyboard[pChn->nNewNote - NOTE_MIN] != 0;
-						pChn->nPos = pChn->nPosLo = 0;
+						pChn->position.Set(0);
 					}
 				} else if ((GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT) && oldSample != pChn->pModSample && ModCommand::IsNote(note)))
 				{
 					// Special IT case: portamento+note causes sample change -> ignore portamento
 					bPorta = false;
-				} else if(m_playBehaviour[kMODSampleSwap] && pChn->nInc == 0)
+				} else if(m_playBehaviour[kMODSampleSwap] && pChn->increment.IsZero())
 				{
 					// If channel was paused and is resurrected by a lone instrument number, reset the sample position.
 					// Test case: PTSwapEmpty.mod
-					pChn->nPos = pChn->nPosLo = 0;
+					pChn->position.Set(0);
 				}
 			}
 			// New Note ?
@@ -2739,10 +2813,10 @@ bool CSoundFile::ProcessEffects()
 		{
 			if (volcmd == VOLCMD_TONEPORTAMENTO)
 			{
-				uint32 param = 0;
+				uint32 porta = 0;
 				if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_AMS | MOD_TYPE_AMS2 | MOD_TYPE_DMF | MOD_TYPE_DBM | MOD_TYPE_IMF | MOD_TYPE_PSM | MOD_TYPE_J2B | MOD_TYPE_ULT | MOD_TYPE_OKT | MOD_TYPE_MT2 | MOD_TYPE_MDL))
 				{
-					param = ImpulseTrackerPortaVolCmd[vol & 0x0F];
+					porta = ImpulseTrackerPortaVolCmd[vol & 0x0F];
 				} else
 				{
 					if(cmd == CMD_TONEPORTAMENTO && GetType() == MOD_TYPE_XM)
@@ -2754,16 +2828,16 @@ bool CSoundFile::ProcessEffects()
 						cmd = CMD_NONE;
 						vol *= 2;
 					}
-					param = vol << 4;
+					porta = vol << 4;
 
 					// FT2 compatibility: If there's a portamento and a note delay, execute the portamento, but don't update the parameter
 					// Test case: PortaDelay.xm
 					if(m_playBehaviour[kFT2PortaDelay] && nStartTick != 0)
 					{
-						param = 0;
+						porta = 0;
 					}
 				}
-				TonePortamento(pChn, param);
+				TonePortamento(pChn, porta);
 			} else
 			{
 				// FT2 Compatibility: FT2 ignores some volume commands with parameter = 0.
@@ -3240,7 +3314,7 @@ bool CSoundFile::ProcessEffects()
 						//If song is set to loop and a pattern break occurs we should stay on the same pattern.
 						//Use nPosJump to force playback to "jump to this pattern" rather than move to next, as by default.
 						//rewbs.to
-						nPosJump = (int)m_PlayState.m_nCurrentOrder;
+						nPosJump = m_PlayState.m_nCurrentOrder;
 					}
 				}
 			}
@@ -3317,6 +3391,15 @@ bool CSoundFile::ProcessEffects()
 				m_PlayState.m_nNextRow++;
 			}
 
+			// IT Compatibility: If the restart row is past the end of the current pattern
+			// (e.g. when continued from a previous pattern without explicit SB0 effect), continue the next pattern.
+			// Test case: LoopStartAfterPatternEnd.it
+			if(nPatLoopRow >= Patterns[m_PlayState.m_nPattern].GetNumRows())
+			{
+				m_PlayState.m_nNextOrder++;
+				m_PlayState.m_nNextRow = 0;
+			}
+
 			// As long as the pattern loop is running, mark the looped rows as not visited yet
 			visitedSongRows.ResetPatternLoop(m_PlayState.m_nCurrentOrder, nPatLoopRow);
 		}
@@ -3332,9 +3415,9 @@ bool CSoundFile::ProcessEffects()
 			if(!doBreakRow) nBreakRow = 0;
 			m_SongFlags.set(SONG_BREAKTOROW);
 
-			if(nPosJump >= Order.size())
+			if(nPosJump >= Order().size())
 			{
-				nPosJump = 0;
+				nPosJump = Order().GetRestartPos();
 			}
 
 			// IT / FT2 compatibility: don't reset loop count on pattern break.
@@ -3365,10 +3448,10 @@ bool CSoundFile::ProcessEffects()
 // Update the effect memory of all S3M effects that use the last non-zero effect parameter as memory (Dxy, Exx, Fxx, Ixy, Jxy, Kxy, Lxy, Qxy, Rxy, Sxy)
 // Test case: ParamMemory.s3m
 void CSoundFile::UpdateS3MEffectMemory(ModChannel *pChn, ModCommand::PARAM param) const
-//-------------------------------------------------------------------------------------
 {
 	pChn->nOldVolumeSlide = param;	// Dxy / Kxy / Lxy
-	pChn->nOldPortaUpDown = param;	// Exx / Fxx
+	pChn->nOldPortaUp = param;		// Exx / Fxx
+	pChn->nOldPortaDown = param;	// Exx / Fxx
 	pChn->nTremorParam = param;		// Ixy
 	pChn->nArpeggio = param;		// Jxy
 	pChn->nRetrigParam = param;		// Qxy
@@ -3382,7 +3465,6 @@ void CSoundFile::UpdateS3MEffectMemory(ModChannel *pChn, ModCommand::PARAM param
 // maxCommands sets the maximum number of XParam commands to look at for this effect
 // isExtended returns if the command is actually using any XParam extensions.
 uint32 CSoundFile::CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX chn, bool *isExtended) const
-//------------------------------------------------------------------------------------------------------------
 {
 	if(isExtended != nullptr) *isExtended = false;
 	ROWINDEX maxCommands = 4;
@@ -3428,7 +3510,6 @@ uint32 CSoundFile::CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX
 
 
 ROWINDEX CSoundFile::PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 param) const
-//--------------------------------------------------------------------------------------
 {
 	if(param >= 64 && (GetType() & MOD_TYPE_S3M))
 	{
@@ -3443,16 +3524,22 @@ ROWINDEX CSoundFile::PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 para
 
 
 void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular)
-//-------------------------------------------------------------------------------------------------------------
 {
 	ModChannel *pChn = &m_PlayState.Chn[nChn];
 
 	if(param)
-		pChn->nOldPortaUpDown = param;
-	else
-		param = pChn->nOldPortaUpDown;
+	{
+		// FT2 compatibility: Separate effect memory for all portamento commands
+		// Test case: Porta-LinkMem.xm
+		if(!m_playBehaviour[kFT2PortaUpDownMemory])
+			pChn->nOldPortaDown = param;
+		pChn->nOldPortaUp = param;
+	} else
+	{
+		param = pChn->nOldPortaUp;
+	}
 
-	const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI));
+	const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM));
 
 	// Process MIDI pitch bend for instrument plugins
 	MidiPortamento(nChn, param, doFineSlides);
@@ -3502,16 +3589,22 @@ void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const
 
 
 void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular)
-//---------------------------------------------------------------------------------------------------------------
 {
 	ModChannel *pChn = &m_PlayState.Chn[nChn];
 
 	if(param)
-		pChn->nOldPortaUpDown = param;
-	else
-		param = pChn->nOldPortaUpDown;
+	{
+		// FT2 compatibility: Separate effect memory for all portamento commands
+		// Test case: Porta-LinkMem.xm
+		if(!m_playBehaviour[kFT2PortaUpDownMemory])
+			pChn->nOldPortaUp = param;
+		pChn->nOldPortaDown = param;
+	} else
+	{
+		param = pChn->nOldPortaDown;
+	}
 
-	const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI));
+	const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM));
 
 	// Process MIDI pitch bend for instrument plugins
 	MidiPortamento(nChn, -static_cast<int>(param), doFineSlides);
@@ -3562,7 +3655,6 @@ void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, cons
 
 // Send portamento commands to plugins
 void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param, bool doFineSlides)
-//------------------------------------------------------------------------------
 {
 	int actualParam = mpt::abs(param);
 	int pitchBend = 0;
@@ -3610,7 +3702,6 @@ void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param, bool doFineSlides)
 
 
 void CSoundFile::FinePortamentoUp(ModChannel *pChn, ModCommand::PARAM param) const
-//--------------------------------------------------------------------------------
 {
 	if(GetType() == MOD_TYPE_XM)
 	{
@@ -3628,7 +3719,7 @@ void CSoundFile::FinePortamentoUp(ModChannel *pChn, ModCommand::PARAM param) con
 		{
 			if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
 			{
-				const int32 oldPeriod = pChn->nPeriod;
+				const auto oldPeriod = pChn->nPeriod;
 				pChn->nPeriod = Util::muldivr(pChn->nPeriod, GetLinearSlideUpTable(this, param & 0x0F), 65536);
 				if(oldPeriod == pChn->nPeriod)
 				{
@@ -3656,7 +3747,6 @@ void CSoundFile::FinePortamentoUp(ModChannel *pChn, ModCommand::PARAM param) con
 
 
 void CSoundFile::FinePortamentoDown(ModChannel *pChn, ModCommand::PARAM param) const
-//----------------------------------------------------------------------------------
 {
 	if(GetType() == MOD_TYPE_XM)
 	{
@@ -3674,7 +3764,7 @@ void CSoundFile::FinePortamentoDown(ModChannel *pChn, ModCommand::PARAM param) c
 		{
 			if (m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
 			{
-				const int32 oldPeriod = pChn->nPeriod;
+				const auto oldPeriod = pChn->nPeriod;
 				pChn->nPeriod = Util::muldivr(pChn->nPeriod, GetLinearSlideDownTable(this, param & 0x0F), 65536);
 				if(oldPeriod == pChn->nPeriod)
 				{
@@ -3694,7 +3784,6 @@ void CSoundFile::FinePortamentoDown(ModChannel *pChn, ModCommand::PARAM param) c
 
 
 void CSoundFile::ExtraFinePortamentoUp(ModChannel *pChn, ModCommand::PARAM param) const
-//-------------------------------------------------------------------------------------
 {
 	if(GetType() == MOD_TYPE_XM)
 	{
@@ -3734,7 +3823,6 @@ void CSoundFile::ExtraFinePortamentoUp(ModChannel *pChn, ModCommand::PARAM param
 
 
 void CSoundFile::ExtraFinePortamentoDown(ModChannel *pChn, ModCommand::PARAM param) const
-//---------------------------------------------------------------------------------------
 {
 	if(GetType() == MOD_TYPE_XM)
 	{
@@ -3767,7 +3855,6 @@ void CSoundFile::ExtraFinePortamentoDown(ModChannel *pChn, ModCommand::PARAM par
 // Implemented for IMF compatibility, can't actually save this in any formats
 // Slide up / down every x ticks by y semitones
 void CSoundFile::NoteSlide(ModChannel *pChn, uint32 param, bool slideUp, bool retrig) const
-//-----------------------------------------------------------------------------------------
 {
 	uint8 x, y;
 	if(m_SongFlags[SONG_FIRSTTICK])
@@ -3790,7 +3877,7 @@ void CSoundFile::NoteSlide(ModChannel *pChn, uint32 param, bool slideUp, bool re
 
 			if(retrig)
 			{
-				pChn->nPos = pChn->nPosLo = 0;
+				pChn->position.Set(0);
 			}
 		}
 	}
@@ -3798,15 +3885,14 @@ void CSoundFile::NoteSlide(ModChannel *pChn, uint32 param, bool slideUp, bool re
 
 // Portamento Slide
 void CSoundFile::TonePortamento(ModChannel *pChn, uint32 param) const
-//-------------------------------------------------------------------
 {
 	pChn->dwFlags.set(CHN_PORTAMENTO);
 
 	//IT compatibility 03: Share effect memory with portamento up/down
 	if((!m_SongFlags[SONG_ITCOMPATGXX] && m_playBehaviour[kITPortaMemoryShare]) || GetType() == MOD_TYPE_PLM)
 	{
-		if(param == 0) param = pChn->nOldPortaUpDown;
-		pChn->nOldPortaUpDown = static_cast<uint8>(param);
+		if(param == 0) param = pChn->nOldPortaUp;
+		pChn->nOldPortaUp = pChn->nOldPortaDown = static_cast<uint8>(param);
 	}
 
 	if(GetType() == MOD_TYPE_MPT && pChn->pModInstrument && pChn->pModInstrument->pTuning)
@@ -3912,11 +3998,7 @@ void CSoundFile::TonePortamento(ModChannel *pChn, uint32 param) const
 
 
 void CSoundFile::Vibrato(ModChannel *p, uint32 param) const
-//---------------------------------------------------------
 {
-	p->m_VibratoDepth = (param & 0x0F) / 15.0F;
-	//'New tuning'-thing: 0 - 1 <-> No depth - Full depth.
-
 	if (param & 0x0F) p->nVibratoDepth = (param & 0x0F) * 4;
 	if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
 	p->dwFlags.set(CHN_VIBRATO);
@@ -3924,7 +4006,6 @@ void CSoundFile::Vibrato(ModChannel *p, uint32 param) const
 
 
 void CSoundFile::FineVibrato(ModChannel *p, uint32 param) const
-//-------------------------------------------------------------
 {
 	if (param & 0x0F) p->nVibratoDepth = param & 0x0F;
 	if (param & 0xF0) p->nVibratoSpeed = (param >> 4) & 0x0F;
@@ -3939,7 +4020,6 @@ void CSoundFile::FineVibrato(ModChannel *p, uint32 param) const
 
 
 void CSoundFile::Panbrello(ModChannel *p, uint32 param) const
-//-----------------------------------------------------------
 {
 	if (param & 0x0F) p->nPanbrelloDepth = param & 0x0F;
 	if (param & 0xF0) p->nPanbrelloSpeed = (param >> 4) & 0x0F;
@@ -3947,7 +4027,6 @@ void CSoundFile::Panbrello(ModChannel *p, uint32 param) const
 
 
 void CSoundFile::Panning(ModChannel *pChn, uint32 param, PanningType panBits) const
-//---------------------------------------------------------------------------------
 {
 	// No panning in ProTracker mode
 	if(m_playBehaviour[kMODIgnorePanning])
@@ -4000,14 +4079,13 @@ void CSoundFile::Panning(ModChannel *pChn, uint32 param, PanningType panBits) co
 
 
 void CSoundFile::VolumeSlide(ModChannel *pChn, ModCommand::PARAM param)
-//---------------------------------------------------------------------
 {
 	if (param)
 		pChn->nOldVolumeSlide = param;
 	else
 		param = pChn->nOldVolumeSlide;
 
-	if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI)))
+	if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)))
 	{
 		// MOD / XM nibble priority
 		if((param & 0xF0) != 0)
@@ -4072,7 +4150,6 @@ void CSoundFile::VolumeSlide(ModChannel *pChn, ModCommand::PARAM param)
 
 
 void CSoundFile::PanningSlide(ModChannel *pChn, ModCommand::PARAM param, bool memory)
-//-----------------------------------------------------------------------------------
 {
 	if(memory)
 	{
@@ -4152,7 +4229,6 @@ void CSoundFile::PanningSlide(ModChannel *pChn, ModCommand::PARAM param, bool me
 
 
 void CSoundFile::FineVolumeUp(ModChannel *pChn, ModCommand::PARAM param, bool volCol) const
-//-----------------------------------------------------------------------------------------
 {
 	if(GetType() == MOD_TYPE_XM)
 	{
@@ -4177,7 +4253,6 @@ void CSoundFile::FineVolumeUp(ModChannel *pChn, ModCommand::PARAM param, bool vo
 
 
 void CSoundFile::FineVolumeDown(ModChannel *pChn, ModCommand::PARAM param, bool volCol) const
-//-------------------------------------------------------------------------------------------
 {
 	if(GetType() == MOD_TYPE_XM)
 	{
@@ -4202,7 +4277,6 @@ void CSoundFile::FineVolumeDown(ModChannel *pChn, ModCommand::PARAM param, bool
 
 
 void CSoundFile::Tremolo(ModChannel *pChn, uint32 param) const
-//------------------------------------------------------------
 {
 	if (param & 0x0F) pChn->nTremoloDepth = (param & 0x0F) << 2;
 	if (param & 0xF0) pChn->nTremoloSpeed = (param >> 4) & 0x0F;
@@ -4211,7 +4285,6 @@ void CSoundFile::Tremolo(ModChannel *pChn, uint32 param) const
 
 
 void CSoundFile::ChannelVolSlide(ModChannel *pChn, ModCommand::PARAM param) const
-//-------------------------------------------------------------------------------
 {
 	int32 nChnSlide = 0;
 	if (param) pChn->nOldChnVolSlide = param; else param = pChn->nOldChnVolSlide;
@@ -4246,7 +4319,6 @@ void CSoundFile::ChannelVolSlide(ModChannel *pChn, ModCommand::PARAM param) cons
 
 
 void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
-//------------------------------------------------------------------------------
 {
 	ModChannel *pChn = &m_PlayState.Chn[nChn];
 	uint8 command = param & 0xF0;
@@ -4254,6 +4326,12 @@ void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
 	switch(command)
 	{
 	// E0x: Set Filter
+	case 0x00:
+		for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
+		{
+			m_PlayState.Chn[chn].dwFlags.set(CHN_AMIGAFILTER, !(param & 1));
+		}
+		break;
 	// E1x: Fine Portamento Up
 	case 0x10:	if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(pChn, param); break;
 	// E2x: Fine Portamento Down
@@ -4313,7 +4391,6 @@ void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
 
 
 void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
-//------------------------------------------------------------------------------
 {
 	ModChannel *pChn = &m_PlayState.Chn[nChn];
 	uint8 command = param & 0xF0;
@@ -4459,7 +4536,7 @@ void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
 					if (!m_playBehaviour[kITHighOffsetNoRetrig] && pChn->rowCommand.IsNote())
 					{
 						SmpLength pos = param << 16;
-						if (pos < pChn->nLength) pChn->nPos = pos;
+						if (pos < pChn->nLength) pChn->position.SetInt(pos);
 					}
 				}
 				break;
@@ -4493,7 +4570,6 @@ void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
 
 
 void CSoundFile::ExtendedChannelEffect(ModChannel *pChn, uint32 param)
-//--------------------------------------------------------------------
 {
 	// S9x and X9x commands (S3M/XM/IT only)
 	if(!m_SongFlags[SONG_FIRSTTICK]) return;
@@ -4538,10 +4614,9 @@ void CSoundFile::ExtendedChannelEffect(ModChannel *pChn, uint32 param)
 		break;
 	// S9F: Go backward (and set playback position to the end if sample just started)
 	case 0x0F:
-		if(!pChn->nPos && pChn->nLength && (pChn->rowCommand.IsNote() || !pChn->dwFlags[CHN_LOOP]))
+		if(pChn->position.IsZero() && pChn->nLength && (pChn->rowCommand.IsNote() || !pChn->dwFlags[CHN_LOOP]))
 		{
-			pChn->nPos = pChn->nLength - 1;
-			pChn->nPosLo = 0xFFFF;
+			pChn->position.Set(pChn->nLength - 1, SamplePosition::fractMax);
 		}
 		pChn->dwFlags.set(CHN_PINGPONGFLAG);
 		break;
@@ -4550,7 +4625,6 @@ void CSoundFile::ExtendedChannelEffect(ModChannel *pChn, uint32 param)
 
 
 void CSoundFile::InvertLoop(ModChannel *pChn)
-//-------------------------------------------
 {
 	// EFx implementation for MOD files (PT 1.1A and up: Invert Loop)
 	// This effect trashes samples. Thanks to 8bitbubsy for making this work. :)
@@ -4582,7 +4656,6 @@ void CSoundFile::InvertLoop(ModChannel *pChn)
 // [in] param: Parameter for parametric macros (Z00 - Z7F)
 // [in] plugin: Plugin to send MIDI message to (if not specified but needed, it is autodetected)
 void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char *macro, uint8 param, PLUGINDEX plugin)
-//-------------------------------------------------------------------------------------------------------------------
 {
 	ModChannel &chn = m_PlayState.Chn[nChn];
 	const ModInstrument *pIns = GetNumInstruments() ? chn.pModInstrument : nullptr;
@@ -4768,7 +4841,6 @@ void CSoundFile::ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char *
 
 // Calculate smooth MIDI macro slide parameter for current tick.
 float CSoundFile::CalculateSmoothParamChange(float currentValue, float param) const
-//---------------------------------------------------------------------------------
 {
 	MPT_ASSERT(GetNumTicksOnCurrentRow() > m_PlayState.m_nTickCount);
 	const uint32 ticksLeft = GetNumTicksOnCurrentRow() - m_PlayState.m_nTickCount;
@@ -4787,7 +4859,6 @@ float CSoundFile::CalculateSmoothParamChange(float currentValue, float param) co
 
 // Process MIDI macro data parsed by ProcessMIDIMacro... return bytes sent on success, 0 on (parse) failure.
 uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned char *macro, uint32 macroLen, PLUGINDEX plugin)
-//------------------------------------------------------------------------------------------------------------------------------
 {
 	if(macroLen < 1)
 	{
@@ -4957,10 +5028,10 @@ uint32 CSoundFile::SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned
 
 
 void CSoundFile::SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume)
-//-------------------------------------------------------------------------
 {
 #ifndef NO_PLUGINS
-	const ModInstrument *pIns = m_PlayState.Chn[chn].pModInstrument;
+	auto &channel = m_PlayState.Chn[chn];
+	const ModInstrument *pIns = channel.pModInstrument;
 	// instro sends to a midi chan
 	if (pIns && pIns->HasValidMIDIChannel())
 	{
@@ -4971,6 +5042,8 @@ void CSoundFile::SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume)
 			if (pPlug != nullptr)
 			{
 				pPlug->MidiCommand(GetBestMidiChannel(chn), pIns->nMidiProgram, pIns->wMidiBank, note, volume, chn);
+				if(note < NOTE_MIN_SPECIAL)
+					channel.nLeftVU = channel.nRightVU = 0xFF;
 			}
 		}
 	}
@@ -4979,7 +5052,6 @@ void CSoundFile::SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume)
 
 
 void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const
-//-------------------------------------------------------------------
 {
 	chn.proTrackerOffset += param;
 
@@ -5010,15 +5082,14 @@ void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const
 		{
 			// ProTracker compatbility: PT1/2-style funky 9xx offset command
 			// Test case: ptoffset.mod
-			chn.nPos = chn.proTrackerOffset;
+			chn.position.Set(chn.proTrackerOffset);
 			chn.proTrackerOffset += param;
 		} else
 		{
-			chn.nPos = param;
+			chn.position.Set(param);
 		}
-		chn.nPosLo = 0;
 
-		if (chn.nPos >= chn.nLength || (chn.dwFlags[CHN_LOOP] && chn.nPos >= chn.nLoopEnd))
+		if (chn.position.GetUInt() >= chn.nLength || (chn.dwFlags[CHN_LOOP] && chn.position.GetUInt() >= chn.nLoopEnd))
 		{
 			// Offset beyond sample size
 			if (!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MOD | MOD_TYPE_MTM)))
@@ -5027,15 +5098,15 @@ void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const
 				if(m_playBehaviour[kITOffset])
 				{
 					if(m_SongFlags[SONG_ITOLDEFFECTS])
-						chn.nPos = chn.nLength; // Old FX: Clip to end of sample
+						chn.position.Set(chn.nLength); // Old FX: Clip to end of sample
 					else
-						chn.nPos = 0; // Reset to beginning of sample
+						chn.position.Set(0); // Reset to beginning of sample
 				} else
 				{
-					chn.nPos = chn.nLoopStart;
+					chn.position.Set(chn.nLoopStart);
 					if(m_SongFlags[SONG_ITOLDEFFECTS] && chn.nLength > 4)
 					{
-						chn.nPos = chn.nLength - 2;
+						chn.position.Set(chn.nLength - 2);
 					}
 				}
 			} else if(m_playBehaviour[kFT2OffsetOutOfRange] || GetType() == MOD_TYPE_MTM)
@@ -5046,40 +5117,36 @@ void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const
 				chn.nPeriod = 0;
 			} else if(GetType() == MOD_TYPE_MOD && chn.dwFlags[CHN_LOOP])
 			{
-				chn.nPos = chn.nLoopStart;
+				chn.position.Set(chn.nLoopStart);
 			}
 		}
 	} else if ((param < chn.nLength) && (GetType() & (MOD_TYPE_MTM | MOD_TYPE_DMF | MOD_TYPE_MDL | MOD_TYPE_PLM)))
 	{
 		// Some trackers can also call offset effects without notes next to them...
-		chn.nPos = param;
-		chn.nPosLo = 0;
+		chn.position.Set(param);
 	}
 }
 
 
 // 
 void CSoundFile::ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) const
-//----------------------------------------------------------------------------------
 {
 	if(chn.pModSample != nullptr)
 	{
 		chn.dwFlags.set(CHN_PINGPONGFLAG);
 		chn.dwFlags.reset(CHN_LOOP);
 		chn.nLength = chn.pModSample->nLength;	// If there was a loop, extend sample to whole length.
-		chn.nPos = (chn.nLength - 1) - std::min<SmpLength>(SmpLength(param) << 8, chn.nLength - 1);
-		chn.nPosLo = 0;
+		chn.position.Set((chn.nLength - 1) - std::min<SmpLength>(SmpLength(param) << 8, chn.nLength - 1), 0);
 	}
 }
 
 
 void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
-//-------------------------------------------------------------------
 {
 	// Retrig: bit 8 is set if it's the new XM retrig
 	ModChannel &chn = m_PlayState.Chn[nChn];
 	int retrigSpeed = param & 0x0F;
-	int retrigCount = chn.nRetrigCount;
+	int16 retrigCount = chn.nRetrigCount;
 	bool doRetrig = false;
 
 	// IT compatibility 15. Retrigger
@@ -5132,7 +5199,7 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
 		} else
 		{
 			int realspeed = retrigSpeed;
-			// FT2 bug: if a retrig (Rxy) occours together with a volume command, the first retrig interval is increased by one tick
+			// FT2 bug: if a retrig (Rxy) occurs together with a volume command, the first retrig interval is increased by one tick
 			if ((param & 0x100) && (chn.rowCommand.volcmd == VOLCMD_VOLUME) && (chn.rowCommand.param & 0xF0)) realspeed++;
 			if(!m_SongFlags[SONG_FIRSTTICK] || (param & 0x100))
 			{
@@ -5180,9 +5247,10 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
 		}
 		uint32 note = chn.nNewNote;
 		int32 oldPeriod = chn.nPeriod;
-		if ((note) && (note <= NOTE_MAX) && (chn.nLength)) CheckNNA(nChn, 0, note, true);
+		if (note >= NOTE_MIN && note <= NOTE_MAX && chn.nLength)
+			CheckNNA(nChn, 0, note, true);
 		bool resetEnv = false;
-		if(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))
+		if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
 		{
 			if((chn.rowCommand.instr) && (param < 0x100))
 			{
@@ -5191,9 +5259,14 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
 			}
 			if (param < 0x100) resetEnv = true;
 		}
+		bool fading = chn.dwFlags[CHN_NOTEFADE];
 		// IT compatibility: Really weird combination of envelopes and retrigger (see Storlek's q.it testcase)
 		// Test case: retrig.it
 		NoteChange(&chn, note, m_playBehaviour[kITRetrigger], resetEnv);
+		// XM compatibility: Prevent NoteChange from resetting the fade flag in case an instrument number + note-off is present.
+		// Test case: RetrigFade.xm
+		if(fading && GetType() == MOD_TYPE_XM)
+			chn.dwFlags.set(CHN_NOTEFADE);
 		chn.nVolume = vol;
 		if(m_nInstruments)
 		{
@@ -5205,7 +5278,7 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
 		if ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && (!chn.rowCommand.note) && (oldPeriod)) chn.nPeriod = oldPeriod;
 		if (!(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) retrigCount = 0;
 		// IT compatibility: see previous IT compatibility comment =)
-		if(m_playBehaviour[kITRetrigger]) chn.nPos = chn.nPosLo = 0;
+		if(m_playBehaviour[kITRetrigger]) chn.position.Set(0);
 
 		offset--;
 		if(offset >= 0 && offset <= static_cast<int>(CountOf(chn.pModSample->cues)) && chn.pModSample != nullptr)
@@ -5226,7 +5299,6 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
 
 
 void CSoundFile::DoFreqSlide(ModChannel *pChn, int32 nFreqSlide) const
-//--------------------------------------------------------------------
 {
 	if(!pChn->nPeriod) return;
 	if(GetType() == MOD_TYPE_669)
@@ -5239,7 +5311,7 @@ void CSoundFile::DoFreqSlide(ModChannel *pChn, int32 nFreqSlide) const
 	if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
 	{
 		// IT Linear slides
-		const int32 nOldPeriod = pChn->nPeriod;
+		const auto nOldPeriod = pChn->nPeriod;
 		uint32 n = mpt::abs(nFreqSlide) / 4u;
 		LimitMax(n, 255u);
 		if(n != 0)
@@ -5271,14 +5343,13 @@ void CSoundFile::DoFreqSlide(ModChannel *pChn, int32 nFreqSlide) const
 
 
 void CSoundFile::NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample)
-//-----------------------------------------------------------------------
 {
 	if (m_PlayState.m_nTickCount == nTick)
 	{
 		ModChannel *pChn = &m_PlayState.Chn[nChn];
 		if(cutSample)
 		{
-			pChn->nInc = 0;
+			pChn->increment.Set(0);
 			pChn->nFadeOutVol = 0;
 			pChn->dwFlags.set(CHN_NOTEFADE);
 		} else
@@ -5294,7 +5365,6 @@ void CSoundFile::NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample)
 
 
 void CSoundFile::KeyOff(ModChannel *pChn) const
-//---------------------------------------------
 {
 	const bool bKeyOn = !pChn->dwFlags[CHN_KEYOFF];
 	pChn->dwFlags.set(CHN_KEYOFF);
@@ -5317,11 +5387,10 @@ void CSoundFile::KeyOff(ModChannel *pChn) const
 			pChn->nLoopStart = pSmp->nLoopStart;
 			pChn->nLoopEnd = pSmp->nLoopEnd;
 			if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
-			if(pChn->nPos > pChn->nLength)
+			if(pChn->position.GetUInt() > pChn->nLength)
 			{
 				// Test case: SusAfterLoop.it
-				pChn->nPos = pChn->nPos - pChn->nLength + pChn->nLoopStart;
-				pChn->nPosLo = 0;
+				pChn->position.Set(pChn->position.GetInt() - pChn->nLength + pChn->nLoopStart);
 			}
 		} else
 		{
@@ -5353,7 +5422,6 @@ void CSoundFile::KeyOff(ModChannel *pChn) const
 
 
 void CSoundFile::SetSpeed(uint32 param)
-//-------------------------------------
 {
 #ifdef MODPLUG_TRACKER
 	// FT2 appears to be decrementing the tick count before checking for zero,
@@ -5367,31 +5435,33 @@ void CSoundFile::SetSpeed(uint32 param)
 }
 
 
-void CSoundFile::SetTempo(TEMPO param, bool setAsNonModcommand)
-//-------------------------------------------------------------
+void CSoundFile::SetTempo(TEMPO param, bool setFromUI)
 {
-	const CModSpecifications& specs = GetModSpecifications();
+	const CModSpecifications &specs = GetModSpecifications();
 
+	// Anything lower than the minimum tempo is considered to be a tempo slide
 	const TEMPO minTempo = (GetType() == MOD_TYPE_MDL) ? TEMPO(1, 0) : TEMPO(32, 0);
 
-	if(setAsNonModcommand)
+	if(setFromUI)
 	{
 		// Set tempo from UI - ignore slide commands and such.
 		m_PlayState.m_nMusicTempo = Clamp(param, specs.GetTempoMin(), specs.GetTempoMax());
-	} else if (param >= minTempo && m_SongFlags[SONG_FIRSTTICK])
+	} else if(param >= minTempo && m_SongFlags[SONG_FIRSTTICK] == !m_playBehaviour[kMODTempoOnSecondTick])
 	{
-		m_PlayState.m_nMusicTempo = param;
-		if (param > GetModSpecifications().GetTempoMax()) param = GetModSpecifications().GetTempoMax();
-	} else if (param < minTempo && !m_SongFlags[SONG_FIRSTTICK])
+		// ProTracker sets the tempo after the first tick.
+		// Note: The case of one tick per row is handled in ProcessRow() instead.
+		// Test case: TempoChange.mod
+		m_PlayState.m_nMusicTempo = std::min(param, specs.GetTempoMax());
+	} else if(param < minTempo && !m_SongFlags[SONG_FIRSTTICK])
 	{
 		// Tempo Slide
 		TEMPO tempDiff(param.GetInt() & 0x0F, 0);
-		if ((param.GetInt() & 0xF0) == 0x10)
+		if((param.GetInt() & 0xF0) == 0x10)
 			m_PlayState.m_nMusicTempo += tempDiff;
 		else
 			m_PlayState.m_nMusicTempo -= tempDiff;
 
-		TEMPO tempoMin = GetModSpecifications().GetTempoMin(), tempoMax = GetModSpecifications().GetTempoMax();
+		TEMPO tempoMin = specs.GetTempoMin(), tempoMax = specs.GetTempoMax();
 		if(m_playBehaviour[kTempoClamp])	// clamp tempo correctly in compatible mode
 		{
 			tempoMax.Set(255);
@@ -5402,7 +5472,6 @@ void CSoundFile::SetTempo(TEMPO param, bool setAsNonModcommand)
 
 
 ROWINDEX CSoundFile::PatternLoop(ModChannel *pChn, uint32 param)
-//--------------------------------------------------------------
 {
 	if (param)
 	{
@@ -5450,7 +5519,6 @@ ROWINDEX CSoundFile::PatternLoop(ModChannel *pChn, uint32 param)
 
 
 void CSoundFile::GlobalVolSlide(ModCommand::PARAM param, uint8 &nOldGlobalVolSlide)
-//-----------------------------------------------------------------------------------
 {
 	int32 nGlbSlide = 0;
 	if (param) nOldGlobalVolSlide = param; else param = nOldGlobalVolSlide;
@@ -5504,7 +5572,6 @@ void CSoundFile::GlobalVolSlide(ModCommand::PARAM param, uint8 &nOldGlobalVolSli
 
 // Find lowest note which has same or lower period as a given period (i.e. the note has the same or higher frequency)
 uint32 CSoundFile::GetNoteFromPeriod(uint32 period, int32 nFineTune, uint32 nC5Speed) const
-//-----------------------------------------------------------------------------------------
 {
 	if(!period) return 0;
 	if(m_playBehaviour[kFT2Periods])
@@ -5514,7 +5581,7 @@ uint32 CSoundFile::GetNoteFromPeriod(uint32 period, int32 nFineTune, uint32 nC5S
 	}
 	// This essentially implements std::lower_bound, with the difference that we don't need an iterable container.
 	uint32 minNote = NOTE_MIN, maxNote = NOTE_MAX, count = maxNote - minNote + 1;
-	const bool periodIsFreq = m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kHertzInLinearMode] && GetType() != MOD_TYPE_XM;
+	const bool periodIsFreq = PeriodsAreFrequencies();
 	while(count > 0)
 	{
 		const uint32 step = count / 2, midNote = minNote + step;
@@ -5533,13 +5600,16 @@ uint32 CSoundFile::GetNoteFromPeriod(uint32 period, int32 nFineTune, uint32 nC5S
 
 
 uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Speed) const
-//---------------------------------------------------------------------------------------
 {
 	if (note == NOTE_NONE || (note >= NOTE_MIN_SPECIAL)) return 0;
 	note -= NOTE_MIN;
-	if (GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT|MOD_TYPE_MT2|MOD_TYPE_S3M|MOD_TYPE_STM|MOD_TYPE_ULT|MOD_TYPE_WAV|MOD_TYPE_669|MOD_TYPE_PLM|MOD_TYPE_DSM
-				|MOD_TYPE_FAR|MOD_TYPE_DMF|MOD_TYPE_PTM|MOD_TYPE_AMS|MOD_TYPE_AMS2|MOD_TYPE_DBM|MOD_TYPE_AMF|MOD_TYPE_PSM|MOD_TYPE_J2B|MOD_TYPE_IMF|MOD_TYPE_UAX))
+	if (!UseFinetuneAndTranspose())
 	{
+		if(GetType() & (MOD_TYPE_MDL | MOD_TYPE_DTM))
+		{
+			// MDL uses non-linear slides, but their effectiveness does not depend on the middle-C frequency.
+			return (FreqS3MTable[note % 12u] << 4) >> (note / 12);
+		}
 		if(m_SongFlags[SONG_LINEARSLIDES] || GetType() == MOD_TYPE_669)
 		{
 			// In IT linear slide mode, directly use frequency in Hertz rather than periods.
@@ -5556,10 +5626,6 @@ uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Spe
 			return Util::muldiv_unsigned(8363, (FreqS3MTable[note % 12u] << 5), nC5Speed << (note / 12u));
 			//8363 * freq[note%12] / nC5Speed * 2^(5-note/12)
 		}
-	} else if (GetType() == MOD_TYPE_MDL)
-	{
-		// MDL uses non-linear slides, but their effectiveness does not depend on the middle-C frequency.
-		return (FreqS3MTable[note % 12u] << 4) >> (note / 12);
 	} else if (GetType() == MOD_TYPE_XM)
 	{
 		if (note < 12) note = 12;
@@ -5613,13 +5679,9 @@ uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Spe
 
 // Converts period value to sample frequency. Return value is fixed point, with FREQ_FRACBITS fractional bits.
 uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac) const
-//------------------------------------------------------------------------------------------
 {
 	if (!period) return 0;
-	if (GetType() & (MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_DIGI | MOD_TYPE_MTM | MOD_TYPE_AMF0 | MOD_TYPE_OKT | MOD_TYPE_SFX))
-	{
-		return ((3546895L * 4) << FREQ_FRACBITS) / period;
-	} else if (GetType() == MOD_TYPE_XM)
+	if (GetType() == MOD_TYPE_XM)
 	{
 		if(m_playBehaviour[kFT2Periods])
 		{
@@ -5650,11 +5712,14 @@ uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPerio
 			if(!period) period = 1;
 			return ((8363 * 1712L) << FREQ_FRACBITS) / period;
 		}
+	} else if (UseFinetuneAndTranspose())
+	{
+		return ((3546895L * 4) << FREQ_FRACBITS) / period;
 	} else if(GetType() == MOD_TYPE_669)
 	{
 		// We only really use c5speed for the finetune pattern command. All samples in 669 files have the same middle-C speed (imported as 8363 Hz).
-		return (period + c5speed - 8363) <<  FREQ_FRACBITS;
-	} else if(GetType() == MOD_TYPE_MDL)
+		return (period + c5speed - 8363) << FREQ_FRACBITS;
+	} else if(GetType() & (MOD_TYPE_MDL | MOD_TYPE_DTM))
 	{
 		LimitMax(period, Util::MaxValueOfType(period) >> 8);
 		if (!c5speed) c5speed = 8363;
@@ -5683,7 +5748,6 @@ uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPerio
 
 
 PLUGINDEX CSoundFile::GetBestPlugin(CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const
-//--------------------------------------------------------------------------------------------------------------------
 {
 	if (nChn >= MAX_CHANNELS)		//Check valid channel number
 	{
@@ -5721,7 +5785,6 @@ PLUGINDEX CSoundFile::GetBestPlugin(CHANNELINDEX nChn, PluginPriority priority,
 
 
 PLUGINDEX CSoundFile::GetChannelPlugin(CHANNELINDEX nChn, PluginMutePriority respectMutes) const
-//----------------------------------------------------------------------------------------------
 {
 	const ModChannel &channel = m_PlayState.Chn[nChn];
 
@@ -5752,7 +5815,6 @@ PLUGINDEX CSoundFile::GetChannelPlugin(CHANNELINDEX nChn, PluginMutePriority res
 
 
 PLUGINDEX CSoundFile::GetActiveInstrumentPlugin(CHANNELINDEX nChn, PluginMutePriority respectMutes) const
-//-------------------------------------------------------------------------------------------------------
 {
 	// Unlike channel settings, pModInstrument is copied from the original chan to the NNA chan,
 	// so we don't need to worry about finding the master chan.
@@ -5776,7 +5838,6 @@ PLUGINDEX CSoundFile::GetActiveInstrumentPlugin(CHANNELINDEX nChn, PluginMutePri
 // No plugin is returned if the channel is muted or if the instrument doesn't have a MIDI channel set up,
 // As this is meant to be used with instrument plugins.
 IMixPlugin *CSoundFile::GetChannelInstrumentPlugin(CHANNELINDEX chn) const
-//------------------------------------------------------------------------
 {
 #ifndef NO_PLUGINS
 	if(m_PlayState.Chn[chn].dwFlags[CHN_MUTE | CHN_SYNCMUTE])
@@ -5805,7 +5866,6 @@ IMixPlugin *CSoundFile::GetChannelInstrumentPlugin(CHANNELINDEX chn) const
 
 // Get the MIDI channel currently associated with a given tracker channel
 uint8 CSoundFile::GetBestMidiChannel(CHANNELINDEX nChn) const
-//-----------------------------------------------------------
 {
 	if(nChn >= MAX_CHANNELS)
 	{
@@ -5828,25 +5888,21 @@ uint8 CSoundFile::GetBestMidiChannel(CHANNELINDEX nChn) const
 }
 
 
+#ifdef MODPLUG_TRACKER
 void CSoundFile::HandlePatternTransitionEvents()
-//----------------------------------------------
 {
-	if (!m_PlayState.m_bPatternTransitionOccurred)
-		return;
-
 	// MPT sequence override
-	if(m_PlayState.m_nSeqOverride != ORDERINDEX_INVALID && m_PlayState.m_nSeqOverride < Order.size())
+	if(m_PlayState.m_nSeqOverride != ORDERINDEX_INVALID && m_PlayState.m_nSeqOverride < Order().size())
 	{
 		if(m_SongFlags[SONG_PATTERNLOOP])
 		{
-			m_PlayState.m_nPattern = Order[m_PlayState.m_nSeqOverride];
+			m_PlayState.m_nPattern = Order()[m_PlayState.m_nSeqOverride];
 		}
-		m_PlayState.m_nNextOrder = m_PlayState.m_nSeqOverride;
+		m_PlayState.m_nCurrentOrder = m_PlayState.m_nSeqOverride;
 		m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID;
 	}
 
 	// Channel mutes
-#ifdef MODPLUG_TRACKER
 	for (CHANNELINDEX chan = 0; chan < GetNumChannels(); chan++)
 	{
 		if (m_bChannelMuteTogglePending[chan])
@@ -5858,15 +5914,12 @@ void CSoundFile::HandlePatternTransitionEvents()
 			m_bChannelMuteTogglePending[chan] = false;
 		}
 	}
-#endif // MODPLUG_TRACKER
-
-	m_PlayState.m_bPatternTransitionOccurred = false;
 }
+#endif // MODPLUG_TRACKER
 
 
 // Update time signatures (global or pattern-specific). Don't forget to call this when changing the RPB/RPM settings anywhere!
 void CSoundFile::UpdateTimeSignature()
-//------------------------------------
 {
 	if(!Patterns.IsValidIndex(m_PlayState.m_nPattern) || !Patterns[m_PlayState.m_nPattern].GetOverrideSignature())
 	{
@@ -5881,7 +5934,6 @@ void CSoundFile::UpdateTimeSignature()
 
 
 void CSoundFile::PortamentoMPT(ModChannel* pChn, int param)
-//---------------------------------------------------------
 {
 	//Behavior: Modifies portamento by param-steps on every tick.
 	//Note that step meaning depends on tuning.
@@ -5892,7 +5944,6 @@ void CSoundFile::PortamentoMPT(ModChannel* pChn, int param)
 
 
 void CSoundFile::PortamentoFineMPT(ModChannel* pChn, int param)
-//-------------------------------------------------------------
 {
 	//Behavior: Divides portamento change between ticks/row. For example
 	//if Ticks/row == 6, and param == +-6, portamento goes up/down by one tuning-dependent
@@ -5913,7 +5964,6 @@ void CSoundFile::PortamentoFineMPT(ModChannel* pChn, int param)
 
 
 void CSoundFile::PortamentoExtraFineMPT(ModChannel* pChn, int param)
-//------------------------------------------------------------------
 {
 	// This kinda behaves like regular fine portamento.
 	// It changes the pitch by n finetune steps on the first tick.
diff --git a/soundlib/Sndfile.cpp b/soundlib/Sndfile.cpp
index 3bba6a9..37ebe31 100644
--- a/soundlib/Sndfile.cpp
+++ b/soundlib/Sndfile.cpp
@@ -28,9 +28,11 @@
 #include "Tables.h"
 #include "mod_specifications.h"
 #include "tuningcollection.h"
+#include "plugins/PluginManager.h"
 #include "plugins/PlugInterface.h"
 #include "../common/StringFixer.h"
 #include "../common/FileReader.h"
+#include "Container.h"
 #include <sstream>
 #include <time.h>
 
@@ -42,14 +44,7 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-// Module decompression
-bool UnpackXPK(std::vector<char> &unpackedData, FileReader &file);
-bool UnpackPP20(std::vector<char> &unpackedData, FileReader &file);
-bool UnpackMMCMP(std::vector<char> &unpackedData, FileReader &file);
-
-
 mpt::ustring FileHistory::AsISO8601() const
-//-----------------------------------------
 {
 	tm date = loadDate;
 	if(openTime > 0)
@@ -69,11 +64,13 @@ mpt::ustring FileHistory::AsISO8601() const
 // CSoundFile
 
 #ifdef MODPLUG_TRACKER
-CTuningCollection* CSoundFile::s_pTuningsSharedLocal(nullptr);
-const char (*CSoundFile::m_NoteNames)[4] = NoteNamesFlat;
+const NoteName *CSoundFile::m_NoteNames = NoteNamesFlat;
 #endif
 
 CSoundFile::CSoundFile() :
+#ifndef MODPLUG_TRACKER
+	m_NoteNames(NoteNamesSharp),
+#endif
 	m_pTuningsTuneSpecific(nullptr),
 	m_pModSpecs(&ModSpecs::itEx),
 	m_nType(MOD_TYPE_NONE),
@@ -86,7 +83,6 @@ CSoundFile::CSoundFile() :
 	m_PRNG(mpt::make_prng<mpt::fast_prng>(mpt::global_prng())),
 	visitedSongRows(*this),
 	m_pCustomLog(nullptr)
-//----------------------
 {
 	MemsetZero(MixSoundBuffer);
 	MemsetZero(MixRearBuffer);
@@ -102,12 +98,11 @@ CSoundFile::CSoundFile() :
 	m_nFreqFactor = m_nTempoFactor = 65536;
 #endif
 	m_nRepeatCount = 0;
-	m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID;
-	m_PlayState.m_bPatternTransitionOccurred = false;
 	m_nTempoMode = tempoModeClassic;
 	m_bIsRendering = false;
 
 #ifdef MODPLUG_TRACKER
+	m_lockRowStart = m_lockRowEnd = ROWINDEX_INVALID;
 	m_lockOrderStart = m_lockOrderEnd = ORDERINDEX_INVALID;
 	m_bChannelMuteTogglePending.reset();
 
@@ -118,32 +113,22 @@ CSoundFile::CSoundFile() :
 	m_nDefaultRowsPerMeasure = m_PlayState.m_nCurrentRowsPerMeasure = 16;
 #endif // MODPLUG_TRACKER
 
-	MemsetZero(m_PlayState.ChnMix);
 	MemsetZero(Instruments);
 	MemsetZero(m_szNames);
-#ifndef NO_PLUGINS
-	MemsetZero(m_MixPlugins);
-#endif // NO_PLUGINS
-	m_PlayState.m_lTotalSampleCount = 0;
-	m_PlayState.m_bPositionChanged = true;
 
-	LoadBuiltInTunings();
-	m_pTuningsTuneSpecific = new CTuningCollection("Tune specific tunings");
+	m_pTuningsTuneSpecific = new CTuningCollection();
 }
 
 
 CSoundFile::~CSoundFile()
-//-----------------------
 {
 	Destroy();
 	delete m_pTuningsTuneSpecific;
 	m_pTuningsTuneSpecific = nullptr;
-	UnloadBuiltInTunings();
 }
 
 
 void CSoundFile::AddToLog(LogLevel level, const mpt::ustring &text) const
-//-----------------------------------------------------------------------
 {
 	if(m_pCustomLog)
 	{
@@ -161,7 +146,6 @@ void CSoundFile::AddToLog(LogLevel level, const mpt::ustring &text) const
 
 // Global variable initializer for loader functions
 void CSoundFile::InitializeGlobals(MODTYPE type)
-//----------------------------------------------
 {
 	// Do not add or change any of these values! And if you do, review each and every loader to check if they require these defaults!
 	m_nType = type;
@@ -186,7 +170,6 @@ void CSoundFile::InitializeGlobals(MODTYPE type)
 	m_nDefaultSpeed = 6;
 	m_nDefaultTempo.Set(125);
 	m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
-	Order.SetRestartPos(0);
 	m_SongFlags.reset();
 	m_nMinPeriod = 16;
 	m_nMaxPeriod = 32767;
@@ -196,6 +179,7 @@ void CSoundFile::InitializeGlobals(MODTYPE type)
 	SetMixLevels(mixLevelsCompatible);
 
 	Patterns.ClearPatterns();
+	Order.Initialize();
 
 	m_songName.clear();
 	m_songArtist.clear();
@@ -203,11 +187,16 @@ void CSoundFile::InitializeGlobals(MODTYPE type)
 	m_madeWithTracker.clear();
 	m_FileHistory.clear();
 	m_tempoSwing.clear();
+
+	// Note: we do not use the Amiga resampler for DBM as it's a multichannel format and can make use of higher-quality Amiga soundcards instead of Paula.
+	if(GetType() & (/*MOD_TYPE_DBM | */MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP))
+	{
+		m_SongFlags.set(SONG_ISAMIGA);
+	}
 }
 
 
 void CSoundFile::InitializeChannels()
-//-----------------------------------
 {
 	for(CHANNELINDEX nChn = 0; nChn < MAX_BASECHANNELS; nChn++)
 	{
@@ -216,14 +205,135 @@ void CSoundFile::InitializeChannels()
 }
 
 
+CSoundFile::ProbeResult CSoundFile::ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize)
+{
+	const uint64 availableFileSize = file.GetLength();
+	const uint64 fileSize = (pfilesize ? *pfilesize : file.GetLength());
+	//const uint64 validFileSize = std::min<uint64>(fileSize, ProbeRecommendedSize);
+	const uint64 goalSize = file.GetPosition() + minimumAdditionalSize;
+	//const uint64 goalMinimumSize = std::min<uint64>(goalSize, ProbeRecommendedSize);
+	if(pfilesize)
+	{
+		if(availableFileSize < std::min<uint64>(fileSize, ProbeRecommendedSize))
+		{
+			if(availableFileSize < goalSize)
+			{
+				return ProbeWantMoreData;
+			}
+		} else
+		{
+			if(fileSize < goalSize)
+			{
+				return ProbeFailure;
+			}
+		}
+		return ProbeSuccess;
+	}
+	return ProbeSuccess;
+}
+
+
+const std::size_t CSoundFile::ProbeRecommendedSize = PROBE_RECOMMENDED_SIZE;
+
+
+#define MPT_DO_PROBE( storedResult , call ) \
+	MPT_DO { \
+		ProbeResult lastResult = call ; \
+		if(lastResult == ProbeSuccess) { \
+			return ProbeSuccess; \
+		} else if(lastResult == ProbeWantMoreData) { \
+			storedResult = ProbeWantMoreData; \
+		} \
+	} MPT_WHILE_0 \
+/**/
+
+
+CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize)
+{
+	ProbeResult result = ProbeFailure;
+	if(pfilesize && (*pfilesize < data.size()))
+	{
+		throw std::out_of_range("");
+	}
+	if(!data.data())
+	{
+		throw std::invalid_argument("");
+	}
+	MemoryFileReader file(data);
+	if(flags & ProbeContainers)
+	{
+		MPT_DO_PROBE(result, ProbeFileHeaderMMCMP(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderPP20(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderUMX(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderXPK(file, pfilesize));
+	}
+	if(flags & ProbeModules)
+	{
+		MPT_DO_PROBE(result, ProbeFileHeader669(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderAM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderAMF_Asylum(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderAMF_DSMI(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderAMS(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderAMS2(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderDBM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderDTM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderDIGI(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderDMF(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderDSM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderFAR(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderGDM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderICE(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderIMF(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderIT(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderITP(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderJ2B(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderM15(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderMDL(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderMED(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderMO3(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderMOD(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderMT2(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderMTM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderOKT(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderPLM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderPSM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderPSM16(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderPT36(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderPTM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderS3M(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderSFX(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderSTM(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderSTP(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderULT(file, pfilesize));
+		MPT_DO_PROBE(result, ProbeFileHeaderXM(file, pfilesize));
+	}
+	if(pfilesize)
+	{
+		if((result == ProbeWantMoreData) && (mpt::saturate_cast<std::size_t>(*pfilesize) <= data.size()))
+		{
+			// If the prober wants more data but we already reached EOF,
+			// probing must fail.
+			result = ProbeFailure;
+		}
+	} else
+	{
+		if((result == ProbeWantMoreData) && (data.size() >= ProbeRecommendedSize))
+		{
+			// If the prober wants more daat but we already provided the recommended required maximum,
+			// just return success as this is th ebest we can do for the suggestesd probing size.
+			result = ProbeSuccess;
+		}
+	}
+	return result;
+}
+
+
 #ifdef MODPLUG_TRACKER
 bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags, CModDoc *pModDoc)
-//-----------------------------------------------------------------------------------
 {
 	m_pModDoc = pModDoc;
 #else
 bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
-//-----------------------------------------------------------------
 {
 #endif // MODPLUG_TRACKER
 
@@ -231,50 +341,54 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 #ifndef MODPLUG_TRACKER
 	m_nFreqFactor = m_nTempoFactor = 65536;
 #endif
-	m_PlayState.m_nGlobalVolume = MAX_GLOBAL_VOLUME;
-
-	InitializeGlobals();
-	Order.resize(1);
-
-	// Playback
-	m_PlayState.m_nPatternDelay = 0;
-	m_PlayState.m_nFrameDelay = 0;
-	m_PlayState.m_nNextRow = 0;
-	m_PlayState.m_nRow = 0;
-	m_PlayState.m_nPattern = 0;
-	m_PlayState.m_nCurrentOrder = 0;
-	m_PlayState.m_nNextOrder = 0;
-	m_PlayState.m_nNextPatStartRow = 0;
-	m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID;
 
-	m_nMaxOrderPosition = 0;
-	MemsetZero(m_PlayState.ChnMix);
 	MemsetZero(Instruments);
 	MemsetZero(m_szNames);
 #ifndef NO_PLUGINS
-	MemsetZero(m_MixPlugins);
+	std::fill(std::begin(m_MixPlugins), std::end(m_MixPlugins), SNDMIXPLUGIN());
 #endif // NO_PLUGINS
 
 	if(file.IsValid())
 	{
 		try
 		{
+
 #ifndef NO_ARCHIVE_SUPPORT
 			CUnarchiver unarchiver(file);
-			if(unarchiver.ExtractBestFile(GetSupportedExtensions(true)))
+			if(!(loadFlags & skipContainer))
 			{
-				file = unarchiver.GetOutputFile();
+				if (unarchiver.ExtractBestFile(GetSupportedExtensions(true)))
+				{
+					file = unarchiver.GetOutputFile();
+				}
 			}
 #endif
 
+			std::vector<ContainerItem> containerItems;
 			MODCONTAINERTYPE packedContainerType = MOD_CONTAINERTYPE_NONE;
-			std::vector<char> unpackedData;
-			if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackXPK(unpackedData, file)) packedContainerType = MOD_CONTAINERTYPE_XPK;
-			if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackPP20(unpackedData, file)) packedContainerType = MOD_CONTAINERTYPE_PP20;
-			if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackMMCMP(unpackedData, file)) packedContainerType = MOD_CONTAINERTYPE_MMCMP;
-			if(packedContainerType != MOD_CONTAINERTYPE_NONE)
+			if(!(loadFlags & skipContainer))
 			{
-				file = FileReader(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(unpackedData)));
+				ContainerLoadingFlags containerLoadFlags = (loadFlags == onlyVerifyHeader) ? ContainerOnlyVerifyHeader : ContainerUnwrapData;
+				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackXPK(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_XPK;
+				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackPP20(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_PP20;
+				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackMMCMP(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_MMCMP;
+				if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackUMX(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_UMX;
+				if(packedContainerType != MOD_CONTAINERTYPE_NONE)
+				{
+					if(loadFlags == onlyVerifyHeader)
+					{
+						return true;
+					}
+					if(!containerItems.empty())
+					{
+						file = containerItems[0].file;
+					}
+				}
+			}
+
+			if(loadFlags & skipModules)
+			{
+				return false;
 			}
 
 			if(!ReadXM(file, loadFlags)
@@ -293,26 +407,30 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 			 && !ReadUlt(file, loadFlags)
 			 && !ReadDMF(file, loadFlags)
 			 && !ReadDSM(file, loadFlags)
-			 && !ReadUMX(file, loadFlags)
+#if defined(MODPLUG_TRACKER) || defined(MPT_FUZZ_TRACKER)
+			 && !ReadUAX(file, loadFlags)
+#endif // MODPLUG_TRACKER || MPT_FUZZ_TRACKER
 			 && !ReadAMF_Asylum(file, loadFlags)
 			 && !ReadAMF_DSMI(file, loadFlags)
 			 && !ReadPSM(file, loadFlags)
 			 && !ReadPSM16(file, loadFlags)
 			 && !ReadMT2(file, loadFlags)
 			 && !ReadITProject(file, loadFlags)
-#ifdef MODPLUG_TRACKER
+#if defined(MODPLUG_TRACKER) || defined(MPT_FUZZ_TRACKER)
 			 // this makes little sense for a module player library
 			 && !ReadWav(file, loadFlags)
 			 && !ReadMID(file, loadFlags)
-#endif // MODPLUG_TRACKER
+#endif // MODPLUG_TRACKER || MPT_FUZZ_TRACKER
 			 && !ReadGDM(file, loadFlags)
 			 && !ReadIMF(file, loadFlags)
 			 && !ReadDIGI(file, loadFlags)
+			 && !ReadDTM(file, loadFlags)
 			 && !ReadPLM(file, loadFlags)
 			 && !ReadAM(file, loadFlags)
 			 && !ReadJ2B(file, loadFlags)
 			 && !ReadPT36(file, loadFlags)
 			 && !ReadSFX(file, loadFlags)
+			 && !ReadSTP(file, loadFlags)
 			 && !ReadMod(file, loadFlags)
 			 && !ReadICE(file, loadFlags)
 			 && !Read669(file, loadFlags)
@@ -350,8 +468,9 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 				m_songMessage.assign(mpt::ToCharset(mpt::CharsetLocale, unarchiver.GetComment()));
 			}
 #endif
-		} catch(MPTMemoryException)
+		} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 		{
+			MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 #ifdef MODPLUG_TRACKER
 			return false;
 #else
@@ -362,6 +481,7 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 	} else
 	{
 		// New song
+		InitializeGlobals();
 		m_dwCreatedWithVersion = MptVersion::num;
 	}
 
@@ -395,7 +515,7 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 			{
 #ifndef MODPLUG_TRACKER
 				// OpenMPT has its own way of reporting this error in CModDoc.
-				AddToLog(LogError, mpt::String::Print(MPT_USTRING("Unable to load sample %1: %2"), i, filename.ToUnicode()));
+				AddToLog(LogError, mpt::format(MPT_USTRING("Unable to load sample %1: %2"))(i, filename.ToUnicode()));
 #endif // MODPLUG_TRACKER
 			}
 		} else
@@ -430,11 +550,13 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 	}
 	m_nInstruments = maxInstr;
 
-	// Set default values
+	// Set default play state values
 	if (!m_nDefaultTempo.GetInt()) m_nDefaultTempo.Set(125);
 	if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
 	m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
 	m_PlayState.m_nMusicTempo = m_nDefaultTempo;
+	m_PlayState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
+	m_PlayState.m_nCurrentRowsPerMeasure = m_nDefaultRowsPerMeasure;
 	m_PlayState.m_nGlobalVolume = static_cast<int32>(m_nDefaultGlobalVolume);
 	m_PlayState.m_lHighResRampingGlobalVolume = m_PlayState.m_nGlobalVolume<<VOLUMERAMPPRECISION;
 	m_PlayState.m_nGlobalVolumeDestination = m_PlayState.m_nGlobalVolume;
@@ -448,13 +570,19 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 	m_PlayState.m_nTickCount = m_PlayState.m_nMusicSpeed;
 	m_PlayState.m_nNextRow = 0;
 	m_PlayState.m_nRow = 0;
+	m_PlayState.m_nPatternDelay = 0;
+	m_PlayState.m_nFrameDelay = 0;
+	m_PlayState.m_nNextPatStartRow = 0;
+	m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID;
+
+	m_nMaxOrderPosition = 0;
 
 	RecalculateSamplesPerTick();
 	visitedSongRows.Initialize(true);
 
-	for(SEQUENCEINDEX i = 0; i < Order.GetNumSequences(); i++)
+	for(auto &order : Order)
 	{
-		ModSequence &order = Order.GetSequence(i);
+		order.Shrink();
 		if(order.GetRestartPos() >= order.size())
 		{
 			order.SetRestartPos(0);
@@ -466,51 +594,44 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 #ifdef MODPLUG_TRACKER
 	std::string notFoundText;
 #endif // MODPLUG_TRACKER
-	std::vector<SNDMIXPLUGININFO *> notFoundIDs;
+	std::vector<const SNDMIXPLUGININFO *> notFoundIDs;
 
-	if (loadFlags & loadPluginData)
+	if((loadFlags & (loadPluginData | loadPluginInstance)) == (loadPluginData | loadPluginInstance))
 	{
 		for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++)
 		{
-			if(m_MixPlugins[plug].IsValidPlugin())
+			auto &plugin = m_MixPlugins[plug];
+			if(plugin.IsValidPlugin())
 			{
 #ifdef MODPLUG_TRACKER
 				// Provide some visual feedback
 				{
 					mpt::ustring s = mpt::format(MPT_USTRING("Loading Plugin FX%1: %2 (%3)"))(
 						mpt::ufmt::dec0<2>(plug + 1),
-						mpt::ToUnicode(mpt::CharsetUTF8, m_MixPlugins[plug].Info.szLibraryName),
-						mpt::ToUnicode(mpt::CharsetLocale, m_MixPlugins[plug].Info.szName));
+						mpt::ToUnicode(mpt::CharsetUTF8, plugin.Info.szLibraryName),
+						mpt::ToUnicode(mpt::CharsetLocale, plugin.Info.szName));
 					CMainFrame::GetMainFrame()->SetHelpText(mpt::ToCString(s));
 				}
 #endif // MODPLUG_TRACKER
-				CreateMixPluginProc(m_MixPlugins[plug], *this);
-				if (m_MixPlugins[plug].pMixPlugin)
+				CreateMixPluginProc(plugin, *this);
+				if(plugin.pMixPlugin)
 				{
 					// Plugin was found
-					m_MixPlugins[plug].pMixPlugin->RestoreAllParameters(m_MixPlugins[plug].defaultProgram);
+					plugin.pMixPlugin->RestoreAllParameters(plugin.defaultProgram);
 				} else
 				{
 					// Plugin not found - add to list
-					bool found = false;
-					for(std::vector<SNDMIXPLUGININFO *>::const_iterator i = notFoundIDs.begin(); i != notFoundIDs.end(); ++i)
-					{
-						if((**i).dwPluginId2 == m_MixPlugins[plug].Info.dwPluginId2
-							&& (**i).dwPluginId1 == m_MixPlugins[plug].Info.dwPluginId1)
-						{
-							found = true;
-							break;
-						}
-					}
+					bool found = std::find_if(notFoundIDs.cbegin(), notFoundIDs.cend(),
+						[&plugin](const SNDMIXPLUGININFO *info) { return info->dwPluginId2 == plugin.Info.dwPluginId2 && info->dwPluginId1 == plugin.Info.dwPluginId1; }) != notFoundIDs.cend();
 
 					if(!found)
 					{
+						notFoundIDs.push_back(&plugin.Info);
 #ifdef MODPLUG_TRACKER
-						notFoundText.append(m_MixPlugins[plug].GetLibraryName());
+						notFoundText.append(plugin.GetLibraryName());
 						notFoundText.append("\n");
-						notFoundIDs.push_back(&m_MixPlugins[plug].Info); // add this to the list of missing IDs so we will find the needed plugins later when calling KVRAudio
 #else
-						AddToLog(LogWarning, MPT_USTRING("Plugin not found: ") + mpt::ToUnicode(mpt::CharsetUTF8, m_MixPlugins[plug].GetLibraryName()));
+						AddToLog(LogWarning, MPT_USTRING("Plugin not found: ") + mpt::ToUnicode(mpt::CharsetUTF8, plugin.GetLibraryName()));
 #endif // MODPLUG_TRACKER
 					}
 				}
@@ -533,10 +654,10 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 		if (Reporting::Confirm(mpt::ToWide(mpt::CharsetUTF8, notFoundText.c_str()), L"OpenMPT - Plugins missing", false, true) == cnfYes)
 		{
 			std::string url = "https://resources.openmpt.org/plugins/search.php?p=";
-			for(std::vector<SNDMIXPLUGININFO *>::const_iterator i = notFoundIDs.begin(); i != notFoundIDs.end(); ++i)
+			for(auto &id : notFoundIDs)
 			{
-				url += mpt::fmt::HEX0<8>(LittleEndian((**i).dwPluginId2));
-				url += (**i).szLibraryName;
+				url += mpt::fmt::HEX0<8>(id->dwPluginId2.get());
+				url += id->szLibraryName;
 				url += "%0a";
 			}
 			CTrackApp::OpenURL(mpt::PathString::FromUTF8(url));
@@ -554,10 +675,6 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 	}
 
 	SetModSpecsPointer(m_pModSpecs, GetBestSaveFormat());
-	const ORDERINDEX CacheSize = ModSequenceSet::s_nCacheSize; // workaround reference to static const member problem
-	const ORDERINDEX nMinLength = std::min(CacheSize, GetModSpecifications().ordersMax);
-	if (Order.GetLength() < nMinLength)
-		Order.resize(nMinLength);
 
 	// When reading a file made with an older version of MPT, it might be necessary to upgrade some settings automatically.
 	if(m_dwLastSavedWithVersion)
@@ -569,14 +686,13 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
 
 
 bool CSoundFile::Destroy()
-//------------------------
 {
-	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+	for(auto &chn : m_PlayState.Chn)
 	{
-		m_PlayState.Chn[i].pModInstrument = nullptr;
-		m_PlayState.Chn[i].pModSample = nullptr;
-		m_PlayState.Chn[i].pCurrentSample = nullptr;
-		m_PlayState.Chn[i].nLength = 0;
+		chn.pModInstrument = nullptr;
+		chn.pModSample = nullptr;
+		chn.pCurrentSample = nullptr;
+		chn.nLength = 0;
 	}
 
 	Patterns.DestroyPatterns();
@@ -587,19 +703,19 @@ bool CSoundFile::Destroy()
 	m_madeWithTracker.clear();
 	m_FileHistory.clear();
 
-	for(SAMPLEINDEX i = 1; i < MAX_SAMPLES; i++)
+	for(auto &smp : Samples)
 	{
-		Samples[i].FreeSample();
+		smp.FreeSample();
 	}
-	for(INSTRUMENTINDEX i = 0; i < MAX_INSTRUMENTS; i++)
+	for(auto &ins : Instruments)
 	{
-		delete Instruments[i];
-		Instruments[i] = nullptr;
+		delete ins;
+		ins = nullptr;
 	}
 #ifndef NO_PLUGINS
-	for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
+	for(auto &plug : m_MixPlugins)
 	{
-		m_MixPlugins[i].Destroy();
+		plug.Destroy();
 	}
 #endif // NO_PLUGINS
 
@@ -615,7 +731,6 @@ bool CSoundFile::Destroy()
 
 
 void CSoundFile::SetDspEffects(uint32 DSPMask)
-//--------------------------------------------
 {
 #ifdef ENABLE_ASM
 #ifndef NO_REVERB
@@ -628,7 +743,6 @@ void CSoundFile::SetDspEffects(uint32 DSPMask)
 
 
 void CSoundFile::SetPreAmp(uint32 nVol)
-//-------------------------------------
 {
 	if (nVol < 1) nVol = 1;
 	if (nVol > 0x200) nVol = 0x200;	// x4 maximum
@@ -643,7 +757,6 @@ void CSoundFile::SetPreAmp(uint32 nVol)
 
 
 double CSoundFile::GetCurrentBPM() const
-//--------------------------------------
 {
 	double bpm;
 
@@ -665,12 +778,11 @@ double CSoundFile::GetCurrentBPM() const
 
 
 void CSoundFile::ResetPlayPos()
-//-----------------------------
 {
 	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
 		m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i);
 
-	InitializeVisitedRows();
+	visitedSongRows.Initialize(true);
 	m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
 
 	m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume;
@@ -697,26 +809,25 @@ void CSoundFile::ResetPlayPos()
 
 
 void CSoundFile::SetCurrentOrder(ORDERINDEX nOrder)
-//-------------------------------------------------
-{
-	while ((nOrder < Order.size()) && (Order[nOrder] == Order.GetIgnoreIndex())) nOrder++;
-	if ((nOrder >= Order.size()) || (Order[nOrder] >= Patterns.Size())) return;
-	for (CHANNELINDEX j = 0; j < MAX_CHANNELS; j++)
-	{
-		m_PlayState.Chn[j].nPeriod = 0;
-		m_PlayState.Chn[j].nNote = NOTE_NONE;
-		m_PlayState.Chn[j].nPortamentoDest = 0;
-		m_PlayState.Chn[j].nCommand = 0;
-		m_PlayState.Chn[j].nPatternLoopCount = 0;
-		m_PlayState.Chn[j].nPatternLoop = 0;
-		m_PlayState.Chn[j].nVibratoPos = m_PlayState.Chn[j].nTremoloPos = m_PlayState.Chn[j].nPanbrelloPos = 0;
+{
+	while ((nOrder < Order().size()) && (Order()[nOrder] == Order.GetIgnoreIndex())) nOrder++;
+	if ((nOrder >= Order().size()) || (Order()[nOrder] >= Patterns.Size())) return;
+	for(auto &chn : m_PlayState.Chn)
+	{
+		chn.nPeriod = 0;
+		chn.nNote = NOTE_NONE;
+		chn.nPortamentoDest = 0;
+		chn.nCommand = 0;
+		chn.nPatternLoopCount = 0;
+		chn.nPatternLoop = 0;
+		chn.nVibratoPos = chn.nTremoloPos = chn.nPanbrelloPos = 0;
 		//IT compatibility 15. Retrigger
 		if(m_playBehaviour[kITRetrigger])
 		{
-			m_PlayState.Chn[j].nRetrigCount = 0;
-			m_PlayState.Chn[j].nRetrigParam = 1;
+			chn.nRetrigCount = 0;
+			chn.nRetrigParam = 1;
 		}
-		m_PlayState.Chn[j].nTremorCount = 0;
+		chn.nTremorCount = 0;
 	}
 
 #ifndef NO_PLUGINS
@@ -743,13 +854,12 @@ void CSoundFile::SetCurrentOrder(ORDERINDEX nOrder)
 }
 
 void CSoundFile::SuspendPlugins()
-//-------------------------------
 {
 #ifndef NO_PLUGINS
-	for (PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
+	for(auto &plug : m_MixPlugins)
 	{
-		IMixPlugin *pPlugin = m_MixPlugins[i].pMixPlugin;
-		if (pPlugin != nullptr && pPlugin->IsResumed())
+		IMixPlugin *pPlugin = plug.pMixPlugin;
+		if(pPlugin != nullptr && pPlugin->IsResumed())
 		{
 			pPlugin->NotifySongPlaying(false);
 			pPlugin->HardAllNotesOff();
@@ -760,13 +870,12 @@ void CSoundFile::SuspendPlugins()
 }
 
 void CSoundFile::ResumePlugins()
-//------------------------------
 {
 #ifndef NO_PLUGINS
-	for (PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
+	for(auto &plugin : m_MixPlugins)
 	{
-		IMixPlugin *pPlugin = m_MixPlugins[i].pMixPlugin;
-		if (pPlugin != nullptr && !pPlugin->IsResumed())
+		IMixPlugin *pPlugin = plugin.pMixPlugin;
+		if(pPlugin != nullptr && !pPlugin->IsResumed())
 		{
 			pPlugin->NotifySongPlaying(true);
 			pPlugin->Resume();
@@ -777,13 +886,12 @@ void CSoundFile::ResumePlugins()
 
 
 void CSoundFile::StopAllVsti()
-//----------------------------
 {
 #ifndef NO_PLUGINS
-	for (PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
+	for(auto &plugin : m_MixPlugins)
 	{
-		IMixPlugin *pPlugin = m_MixPlugins[i].pMixPlugin;
-		if (pPlugin != nullptr && pPlugin->IsResumed())
+		IMixPlugin *pPlugin = plugin.pMixPlugin;
+		if(pPlugin != nullptr && pPlugin->IsResumed())
 		{
 			pPlugin->HardAllNotesOff();
 		}
@@ -793,7 +901,6 @@ void CSoundFile::StopAllVsti()
 
 
 void CSoundFile::SetMixLevels(MixLevels levels)
-//---------------------------------------------
 {
 	m_nMixLevels = levels;
 	m_PlayConfig.SetMixLevels(m_nMixLevels);
@@ -802,31 +909,25 @@ void CSoundFile::SetMixLevels(MixLevels levels)
 
 
 void CSoundFile::RecalculateGainForAllPlugs()
-//-------------------------------------------
 {
 #ifndef NO_PLUGINS
-	for (PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
+	for(auto &plugin : m_MixPlugins)
 	{
-		if (!m_MixPlugins[i].pMixPlugin)
-			continue;  //most common branch
-
-		m_MixPlugins[i].pMixPlugin->RecalculateGain();
+		if(plugin.pMixPlugin != nullptr)
+			plugin.pMixPlugin->RecalculateGain();
 	}
 #endif // NO_PLUGINS
 }
 
 
-//end rewbs.VSTCompliance
-
 void CSoundFile::ResetChannels()
-//------------------------------
 {
 	m_SongFlags.reset(SONG_FADINGSONG | SONG_ENDREACHED);
 	m_PlayState.m_nBufferCount = 0;
-	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+	for(auto &chn : m_PlayState.Chn)
 	{
-		m_PlayState.Chn[i].nROfs = m_PlayState.Chn[i].nLOfs = 0;
-		m_PlayState.Chn[i].nLength = 0;
+		chn.nROfs = chn.nLOfs = 0;
+		chn.nLength = 0;
 	}
 }
 
@@ -834,12 +935,11 @@ void CSoundFile::ResetChannels()
 #ifdef MODPLUG_TRACKER
 
 void CSoundFile::PatternTranstionChnSolo(const CHANNELINDEX chnIndex)
-//-------------------------------------------------------------------
 {
 	if(chnIndex >= m_nChannels)
 		return;
 
-	for(CHANNELINDEX i = 0; i<m_nChannels; i++)
+	for(CHANNELINDEX i = 0; i < m_nChannels; i++)
 	{
 		m_bChannelMuteTogglePending[i] = !ChnSettings[i].dwFlags[CHN_MUTE];
 	}
@@ -848,9 +948,8 @@ void CSoundFile::PatternTranstionChnSolo(const CHANNELINDEX chnIndex)
 
 
 void CSoundFile::PatternTransitionChnUnmuteAll()
-//----------------------------------------------
 {
-	for(CHANNELINDEX i = 0; i<m_nChannels; i++)
+	for(CHANNELINDEX i = 0; i < m_nChannels; i++)
 	{
 		m_bChannelMuteTogglePending[i] = ChnSettings[i].dwFlags[CHN_MUTE];
 	}
@@ -860,7 +959,6 @@ void CSoundFile::PatternTransitionChnUnmuteAll()
 
 
 void CSoundFile::LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
-//------------------------------------------------------------
 {
 	if(!Patterns.IsValidPat(nPat))
 	{
@@ -880,9 +978,7 @@ void CSoundFile::LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
 }
 
 
-//rewbs.playSongFromCursor
 void CSoundFile::DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
-//----------------------------------------------------------------
 {
 	if(!Patterns.IsValidPat(nPat)) nPat = 0;
 	if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0;
@@ -895,18 +991,15 @@ void CSoundFile::DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
 	m_PlayState.m_nNextPatStartRow = 0;
 	m_SongFlags.reset(SONG_PATTERNLOOP);
 }
-//end rewbs.playSongFromCursor
 
 
 void CSoundFile::SetDefaultPlaybackBehaviour(MODTYPE type)
-//--------------------------------------------------------
 {
 	m_playBehaviour = GetDefaultPlaybackBehaviour(type);
 }
 
 
 PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
-//----------------------------------------------------------------------
 {
 	PlayBehaviourSet playBehaviour;
 	switch(type)
@@ -958,6 +1051,8 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
 		playBehaviour.set(kITPanningReset);
 		playBehaviour.set(kITPatternLoopWithJumps);
 		playBehaviour.set(kITInstrWithNoteOff);
+		playBehaviour.set(kITMultiSampleInstrumentNumber);
+		playBehaviour.set(kRowDelayWithNoteDelay);
 		break;
 
 	case MOD_TYPE_XM:
@@ -993,6 +1088,10 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
 		playBehaviour.set(kFT2PanWithDelayedNoteOff);
 		playBehaviour.set(kFT2VolColDelay);
 		playBehaviour.set(kFT2FinetunePrecision);
+		playBehaviour.set(kFT2NoteOffFlags);
+		playBehaviour.set(kRowDelayWithNoteDelay);
+		playBehaviour.set(kFT2TremoloRampWaveform);
+		playBehaviour.set(kFT2PortaUpDownMemory);
 		break;
 
 	case MOD_TYPE_S3M:
@@ -1004,6 +1103,8 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
 		playBehaviour.set(kST3PortaSampleChange);
 		playBehaviour.set(kST3EffectMemory);
 		playBehaviour.set(kST3VibratoMemory);
+		playBehaviour.set(KST3PortaAfterArpeggio);
+		playBehaviour.set(kRowDelayWithNoteDelay);
 		break;
 
 	case MOD_TYPE_MOD:
@@ -1011,6 +1112,8 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
 		playBehaviour.set(kMODOneShotLoops);
 		playBehaviour.set(kMODIgnorePanning);
 		playBehaviour.set(kMODSampleSwap);
+		playBehaviour.set(kMODOutOfRangeNoteDelay);
+		playBehaviour.set(kMODTempoOnSecondTick);
 		break;
 
 	default:
@@ -1025,7 +1128,6 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type)
 
 
 PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
-//--------------------------------------------------------------------
 {
 	PlayBehaviourSet playBehaviour;
 	switch(type)
@@ -1035,6 +1137,8 @@ PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
 		playBehaviour.set(kPerChannelGlobalVolSlide);
 		playBehaviour.set(kPanOverride);
 		playBehaviour.set(kITMultiSampleBehaviour);
+		playBehaviour.set(kITSampleAndHoldPanbrello);
+		playBehaviour.set(kITPanbrelloHold);
 		break;
 
 	case MOD_TYPE_XM:
@@ -1056,7 +1160,6 @@ PlayBehaviourSet CSoundFile::GetDefaultPlaybackBehaviour(MODTYPE type)
 
 
 MODTYPE CSoundFile::GetBestSaveFormat() const
-//-------------------------------------------
 {
 	switch(GetType())
 	{
@@ -1069,13 +1172,14 @@ MODTYPE CSoundFile::GetBestSaveFormat() const
 	case MOD_TYPE_AMF0:
 	case MOD_TYPE_DIGI:
 	case MOD_TYPE_SFX:
+	case MOD_TYPE_STP:
 		return MOD_TYPE_MOD;
 	case MOD_TYPE_MED:
 		if(m_nDefaultTempo == TEMPO(125, 0) && m_nDefaultSpeed == 6 && !m_nInstruments)
 		{
-			for(PATTERNINDEX i = 0; i < Patterns.Size(); i++)
+			for(const auto &pat : Patterns)
 			{
-				if(Patterns.IsValidPat(i) && Patterns[i].GetNumRows() != 64)
+				if(pat.IsValid() && pat.GetNumRows() != 64)
 					return MOD_TYPE_XM;
 			}
 			return MOD_TYPE_MOD;
@@ -1111,14 +1215,16 @@ MODTYPE CSoundFile::GetBestSaveFormat() const
 	case MOD_TYPE_MT2:
 	case MOD_TYPE_MDL:
 	case MOD_TYPE_PTM:
+	case MOD_TYPE_DTM:
 	default:
 		return MOD_TYPE_IT;
+	case MOD_TYPE_MID:
+		return MOD_TYPE_MPT;
 	}
 }
 
 
 const char *CSoundFile::GetSampleName(SAMPLEINDEX nSample) const
-//--------------------------------------------------------------
 {
 	MPT_ASSERT(nSample <= GetNumSamples());
 	if (nSample < MAX_SAMPLES)
@@ -1132,7 +1238,6 @@ const char *CSoundFile::GetSampleName(SAMPLEINDEX nSample) const
 
 
 const char *CSoundFile::GetInstrumentName(INSTRUMENTINDEX nInstr) const
-//---------------------------------------------------------------------
 {
 	if((nInstr >= MAX_INSTRUMENTS) || (!Instruments[nInstr]))
 		return "";
@@ -1143,7 +1248,6 @@ const char *CSoundFile::GetInstrumentName(INSTRUMENTINDEX nInstr) const
 
 
 bool CSoundFile::InitChannel(CHANNELINDEX nChn)
-//---------------------------------------------
 {
 	if(nChn >= MAX_BASECHANNELS) return true;
 
@@ -1166,10 +1270,22 @@ bool CSoundFile::InitChannel(CHANNELINDEX nChn)
 }
 
 
+void CSoundFile::InitAmigaResampler()
+{
+	if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
+	{
+		const Paula::State defaultState(GetSampleRate());
+		for(auto &chn : m_PlayState.Chn)
+		{
+			chn.paulaState = defaultState;
+		}
+	}
+}
+
+
 // Detect samples that are referenced by an instrument, but actually not used in a song.
 // Only works in instrument mode. Unused samples are marked as false in the vector.
 SAMPLEINDEX CSoundFile::DetectUnusedSamples(std::vector<bool> &sampleUsed) const
-//------------------------------------------------------------------------------
 {
 	sampleUsed.assign(GetNumSamples() + 1, false);
 
@@ -1177,14 +1293,14 @@ SAMPLEINDEX CSoundFile::DetectUnusedSamples(std::vector<bool> &sampleUsed) const
 	{
 		return 0;
 	}
-	SAMPLEINDEX nExt = 0;
+	SAMPLEINDEX unused = 0;
 	std::vector<ModCommand::INSTR> lastIns;
 
-	for (PATTERNINDEX pat = 0; pat < Patterns.Size(); pat++) if(Patterns.IsValidPat(pat))
+	for(const auto &pat : Patterns) if(pat.IsValid())
 	{
 		lastIns.assign(GetNumChannels(), 0);
-		const ModCommand *p = Patterns[pat];
-		for(ROWINDEX row = 0; row < Patterns[pat].GetNumRows(); row++)
+		auto p = pat.cbegin();
+		for(ROWINDEX row = 0; row < pat.GetNumRows(); row++)
 		{
 			for(CHANNELINDEX c = 0; c < GetNumChannels(); c++, p++)
 			{
@@ -1223,16 +1339,15 @@ SAMPLEINDEX CSoundFile::DetectUnusedSamples(std::vector<bool> &sampleUsed) const
 	}
 	for (SAMPLEINDEX ichk = GetNumSamples(); ichk >= 1; ichk--)
 	{
-		if ((!sampleUsed[ichk]) && (Samples[ichk].pSample)) nExt++;
+		if ((!sampleUsed[ichk]) && (Samples[ichk].pSample)) unused++;
 	}
 
-	return nExt;
+	return unused;
 }
 
 
 // Destroy samples where keepSamples index is false. First sample is keepSamples[1]!
 SAMPLEINDEX CSoundFile::RemoveSelectedSamples(const std::vector<bool> &keepSamples)
-//---------------------------------------------------------------------------------
 {
 	if(keepSamples.empty())
 	{
@@ -1266,7 +1381,6 @@ SAMPLEINDEX CSoundFile::RemoveSelectedSamples(const std::vector<bool> &keepSampl
 
 
 bool CSoundFile::DestroySample(SAMPLEINDEX nSample)
-//-------------------------------------------------
 {
 	if(!nSample || nSample >= MAX_SAMPLES)
 	{
@@ -1279,13 +1393,13 @@ bool CSoundFile::DestroySample(SAMPLEINDEX nSample)
 
 	ModSample &sample = Samples[nSample];
 
-	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+	for(auto &chn : m_PlayState.Chn)
 	{
-		if(m_PlayState.Chn[i].pModSample == &sample)
+		if(chn.pModSample == &sample)
 		{
-			m_PlayState.Chn[i].nPos = 0;
-			m_PlayState.Chn[i].nLength = 0;
-			m_PlayState.Chn[i].pCurrentSample = nullptr;
+			chn.position.Set(0);
+			chn.nLength = 0;
+			chn.pCurrentSample = nullptr;
 		}
 	}
 
@@ -1301,87 +1415,24 @@ bool CSoundFile::DestroySample(SAMPLEINDEX nSample)
 
 
 bool CSoundFile::DestroySampleThreadsafe(SAMPLEINDEX nSample)
-//-----------------------------------------------------------
 {
 	CriticalSection cs;
 	return DestroySample(nSample);
 }
 
 
-#ifdef MODPLUG_TRACKER
-void CSoundFile::DeleteStaticdata()
-//---------------------------------
-{
-	delete s_pTuningsSharedLocal; s_pTuningsSharedLocal = nullptr;
-}
-#endif
-
-
-#ifdef MODPLUG_TRACKER
-bool CSoundFile::SaveStaticTunings()
-//----------------------------------
-{
-	if(s_pTuningsSharedLocal->Serialize() != CTuningCollection::SERIALIZATION_SUCCESS)
-	{
-		AddToLog(LogError, MPT_USTRING("Static tuning serialisation failed"));
-		return false;
-	}
-	return true;
-}
-#endif
-
-
-#ifdef MODPLUG_TRACKER
-bool CSoundFile::LoadStaticTunings()
-//----------------------------------
-{
-	if(s_pTuningsSharedLocal) return true;
-	//For now not allowing to reload tunings(one should be careful when reloading them
-	//since various parts may use addresses of the tuningobjects).
-
-	s_pTuningsSharedLocal = new CTuningCollection("Local tunings");
-
-	// Load local tunings.
-	s_pTuningsSharedLocal->SetSavefilePath(
-		TrackerSettings::Instance().PathTunings.GetDefaultDir()
-		+ MPT_PATHSTRING("local_tunings")
-		+ mpt::PathString::FromUTF8(CTuningCollection::s_FileExtension)
-		);
-	s_pTuningsSharedLocal->Deserialize();
-
-	return false;
-}
-#endif
-
-
-void CSoundFile::LoadBuiltInTunings()
-//-----------------------------------
+CTuning* CSoundFile::CreateTuning12TET(const std::string &name)
 {
-	m_pTuningsBuiltIn = new CTuningCollection("Built-in tunings");
-	CTuningRTI* pT = new CTuningRTI;
-	pT->SetName("12TET [[fs15 1.17.02.49]]");
-	pT->CreateGeometric(12, 2);
-	pT->SetFineStepCount(15);
+	CTuning* pT = CTuning::CreateGeometric(name, 12, 2, 15);
 	for(ModCommand::NOTE note = 0; note < 12; ++note)
 	{
 		pT->SetNoteName(note, NoteNamesSharp[note]);
 	}
-	pT->SetEditMask(CTuningBase::EM_CONST_STRICT);
-	// Note: Tuning collection class handles deleting.
-	m_pTuningsBuiltIn->AddTuning(pT);
-}
-
-
-void CSoundFile::UnloadBuiltInTunings()
-//-------------------------------------
-{
-	delete m_pTuningsBuiltIn;
-	m_pTuningsBuiltIn = nullptr;
+	return pT;
 }
 
 
 std::string CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst) const
-//------------------------------------------------------------------------------------------------
 {
 	// For MPTM instruments with custom tuning, find the appropriate note name. Else, use default note names.
 	if(ModCommand::IsNote(note) && GetType() == MOD_TYPE_MPT && inst >= 1 && inst <= GetNumInstruments() && Instruments[inst] && Instruments[inst]->pTuning)
@@ -1394,27 +1445,25 @@ std::string CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUMEN
 }
 
 
-std::string CSoundFile::GetNoteName(const ModCommand::NOTE note)
-//--------------------------------------------------------------
+std::string CSoundFile::GetNoteName(const ModCommand::NOTE note) const
+{
+	return GetNoteName(note, m_NoteNames);
+}
+
+
+std::string CSoundFile::GetNoteName(const ModCommand::NOTE note, const char (*noteNames)[4])
 {
 	if(ModCommand::IsSpecialNote(note))
 	{
 		const char specialNoteNames[][4] = { "PCs",  "PC ", "~~~", "^^^", "===" };
 		STATIC_ASSERT(CountOf(specialNoteNames) == NOTE_MAX_SPECIAL - NOTE_MIN_SPECIAL + 1);
-
 		return specialNoteNames[note - NOTE_MIN_SPECIAL];
 	} else if(ModCommand::IsNote(note))
 	{
-		char name[4];
-#ifdef MODPLUG_TRACKER
-#define NOTENAMES m_NoteNames
-#else
-#define NOTENAMES NoteNamesSharp
-#endif // MODPLUG_TRACKER
-		MemCopy<char[4]>(name, NOTENAMES[(note - NOTE_MIN) % 12]);	// e.g. "C#"
-		name[2] = '0' + (note - NOTE_MIN) / 12;	// e.g. 5
-		return name; //NoteNamesSharp[(note - NOTE_MIN) % 12] + std::string(1, '0' + (note - NOTE_MIN) / 12);
-#undef NOTENAMES
+		return std::string()
+			.append(noteNames[(note - NOTE_MIN) % 12])
+			.append(1, '0' + (note - NOTE_MIN) / 12)
+			;	// e.g. "C#" + "5"
 	} else if(note == NOTE_NONE)
 	{
 		return "...";
@@ -1424,16 +1473,21 @@ std::string CSoundFile::GetNoteName(const ModCommand::NOTE note)
 
 
 #ifdef MODPLUG_TRACKER
+
 void CSoundFile::SetDefaultNoteNames()
-//------------------------------------
 {
 	m_NoteNames = TrackerSettings::Instance().accidentalFlats ? NoteNamesFlat : NoteNamesSharp;
 }
+
+const NoteName *CSoundFile::GetDefaultNoteNames()
+{
+	return m_NoteNames;
+}
+
 #endif // MODPLUG_TRACKER
 
 
 void CSoundFile::SetModSpecsPointer(const CModSpecifications*& pModSpecs, const MODTYPE type)
-//-------------------------------------------------------------------------------------------
 {
 	switch(type)
 	{
@@ -1462,7 +1516,6 @@ void CSoundFile::SetModSpecsPointer(const CModSpecifications*& pModSpecs, const
 
 
 void CSoundFile::SetType(MODTYPE type)
-//------------------------------------
 {
 	m_nType = type;
 	m_playBehaviour = GetDefaultPlaybackBehaviour(GetBestSaveFormat());
@@ -1473,7 +1526,6 @@ void CSoundFile::SetType(MODTYPE type)
 #ifdef MODPLUG_TRACKER
 
 void CSoundFile::ChangeModTypeTo(const MODTYPE& newType)
-//------------------------------------------------------
 {
 	const MODTYPE oldtype = GetType();
 	m_nType = newType;
@@ -1504,7 +1556,6 @@ void CSoundFile::ChangeModTypeTo(const MODTYPE& newType)
 
 
 bool CSoundFile::SetTitle(const std::string &newTitle)
-//----------------------------------------------------
 {
 	if(m_songName != newTitle)
 	{
@@ -1516,7 +1567,6 @@ bool CSoundFile::SetTitle(const std::string &newTitle)
 
 
 double CSoundFile::GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars, bool updateSamplePos)
-//-------------------------------------------------------------------------------------------------------
 {
 	const GetLengthType t = GetLength(updateVars ? (updateSamplePos ? eAdjustSamplePositions : eAdjust) : eNoAdjust, GetLengthTarget(ord, row)).back();
 	if(t.targetReached) return t.duration;
@@ -1529,7 +1579,6 @@ double CSoundFile::GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVa
 // because this is not called once per tick but in unrelated
 // circumstances. So this should not update error accumulation.
 void CSoundFile::RecalculateSamplesPerTick()
-//------------------------------------------
 {
 	switch(m_nTempoMode)
 	{
@@ -1558,7 +1607,6 @@ void CSoundFile::RecalculateSamplesPerTick()
 // This has to be called exactly once per tick because otherwise the error accumulation
 // goes wrong.
 uint32 CSoundFile::GetTickDuration(PlayState &playState) const
-//------------------------------------------------------------
 {
 	uint32 retval = 0;
 	switch(m_nTempoMode)
@@ -1574,7 +1622,7 @@ uint32 CSoundFile::GetTickDuration(PlayState &playState) const
 
 	case tempoModeModern:
 		{
-			double accurateBufferCount = static_cast<double>(m_MixerSettings.gdwMixingFreq) * (60.0 / playState.m_nMusicTempo.ToDouble() / Util::mul32to64_unsigned(playState.m_nMusicSpeed, playState.m_nCurrentRowsPerBeat));
+			double accurateBufferCount = static_cast<double>(m_MixerSettings.gdwMixingFreq) * (60.0 / (playState.m_nMusicTempo.ToDouble() * Util::mul32to64_unsigned(playState.m_nMusicSpeed, playState.m_nCurrentRowsPerBeat)));
 			const TempoSwing &swing = (Patterns.IsValidPat(playState.m_nPattern) && Patterns[playState.m_nPattern].HasTempoSwing())
 				? Patterns[playState.m_nPattern].GetTempoSwing()
 				: m_tempoSwing;
@@ -1604,7 +1652,7 @@ uint32 CSoundFile::GetTickDuration(PlayState &playState) const
 	}
 #ifndef MODPLUG_TRACKER
 	// when the user modifies the tempo, we do not really care about accurate tempo error accumulation
-	retval = Util::muldivr(retval, m_nTempoFactor, 65536);
+	retval = Util::muldivr_unsigned(retval, m_nTempoFactor, 65536);
 #endif // !MODPLUG_TRACKER
 	if(!retval)
 		retval  = 1;
@@ -1614,7 +1662,6 @@ uint32 CSoundFile::GetTickDuration(PlayState &playState) const
 
 // Get the duration of a row in milliseconds, based on the current rows per beat and given speed and tempo settings.
 double CSoundFile::GetRowDuration(TEMPO tempo, uint32 speed) const
-//----------------------------------------------------------------
 {
 	switch(m_nTempoMode)
 	{
@@ -1635,7 +1682,6 @@ double CSoundFile::GetRowDuration(TEMPO tempo, uint32 speed) const
 
 
 const CModSpecifications& CSoundFile::GetModSpecifications(const MODTYPE type)
-//----------------------------------------------------------------------------
 {
 	const CModSpecifications* p = nullptr;
 	SetModSpecsPointer(p, type);
@@ -1646,7 +1692,6 @@ const CModSpecifications& CSoundFile::GetModSpecifications(const MODTYPE type)
 // Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified.
 // SAMPLEINDEX_INVLAID is returned if no free sample slot could be found.
 SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMPLEINDEX start) const
-//--------------------------------------------------------------------------------------------------
 {
 	// Find empty slot in two passes - in the first pass, we only search for samples with empty sample names,
 	// in the second pass we check all samples with non-empty sample names.
@@ -1691,7 +1736,6 @@ SAMPLEINDEX CSoundFile::GetNextFreeSample(INSTRUMENTINDEX targetInstrument, SAMP
 // Find an unused instrument slot.
 // INSTRUMENTINDEX_INVALID is returned if no free instrument slot could be found.
 INSTRUMENTINDEX CSoundFile::GetNextFreeInstrument(INSTRUMENTINDEX start) const
-//----------------------------------------------------------------------------
 {
 	for(INSTRUMENTINDEX i = start; i <= GetModSpecifications().instrumentsMax; i++)
 	{
@@ -1707,7 +1751,6 @@ INSTRUMENTINDEX CSoundFile::GetNextFreeInstrument(INSTRUMENTINDEX start) const
 
 // Check whether a given sample is used by a given instrument.
 bool CSoundFile::IsSampleReferencedByInstrument(SAMPLEINDEX sample, INSTRUMENTINDEX instr) const
-//----------------------------------------------------------------------------------------------
 {
 	ModInstrument *targetIns = nullptr;
 	if(instr > 0 && instr <= GetNumInstruments())
@@ -1729,7 +1772,6 @@ bool CSoundFile::IsSampleReferencedByInstrument(SAMPLEINDEX sample, INSTRUMENTIN
 
 
 ModInstrument *CSoundFile::AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample)
-//----------------------------------------------------------------------------------------------
 {
 	if(instr == 0 || instr >= MAX_INSTRUMENTS)
 	{
@@ -1746,12 +1788,15 @@ ModInstrument *CSoundFile::AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX
 		// Create new instrument
 		Instruments[instr] = ins = new (std::nothrow) ModInstrument(assignedSample);
 	}
+	if(ins != nullptr)
+	{
+		m_nInstruments = std::max(m_nInstruments, instr);
+	}
 	return ins;
 }
 
 
 void CSoundFile::PrecomputeSampleLoops(bool updateChannels)
-//---------------------------------------------------------
 {
 	for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
 	{
@@ -1764,7 +1809,6 @@ void CSoundFile::PrecomputeSampleLoops(bool updateChannels)
 // Load external waveform, but keep sample properties like frequency, panning, etc...
 // Returns true if the file could be loaded.
 bool CSoundFile::LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &filename)
-//-----------------------------------------------------------------------------------
 {
 	bool ok = false;
 	InputFile f(filename);
@@ -1803,7 +1847,6 @@ bool CSoundFile::LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &file
 
 // Set up channel panning and volume suitable for MOD + similar files. If the current mod type is not MOD, bForceSetup has to be set to true.
 void CSoundFile::SetupMODPanning(bool bForceSetup)
-//------------------------------------------------
 {
 	// Setup LRRL panning, max channel volume
 	if(!(GetType() & MOD_TYPE_MOD) && bForceSetup == false) return;
@@ -1821,21 +1864,20 @@ void CSoundFile::SetupMODPanning(bool bForceSetup)
 
 
 void CSoundFile::PropagateXMAutoVibrato(INSTRUMENTINDEX ins, uint8 type, uint8 sweep, uint8 depth, uint8 rate)
-//------------------------------------------------------------------------------------------------------------
 {
 	if(ins > m_nInstruments || Instruments[ins] == nullptr)
 		return;
 	const std::set<SAMPLEINDEX> referencedSamples = Instruments[ins]->GetSamples();
 
 	// Propagate changes to all samples that belong to this instrument.
-	for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++)
+	for(auto sample : referencedSamples)
 	{
-		if(*sample <= m_nSamples)
+		if(sample <= m_nSamples)
 		{
-			Samples[*sample].nVibDepth = depth;
-			Samples[*sample].nVibType = type;
-			Samples[*sample].nVibRate = rate;
-			Samples[*sample].nVibSweep = sweep;
+			Samples[sample].nVibDepth = depth;
+			Samples[sample].nVibType = type;
+			Samples[sample].nVibRate = rate;
+			Samples[sample].nVibSweep = sweep;
 		}
 	}
 }
@@ -1843,21 +1885,20 @@ void CSoundFile::PropagateXMAutoVibrato(INSTRUMENTINDEX ins, uint8 type, uint8 s
 
 // Normalize the tempo swing coefficients so that they add up to exactly the specified tempo again
 void TempoSwing::Normalize()
-//--------------------------
 {
 	if(empty()) return;
 	uint64 sum = 0;
-	for(iterator i = begin(); i != end(); i++)
+	for(auto &i : *this)
 	{
-		Limit(*i, Unity / 4u, Unity * 4u);
-		sum += *i;
+		Limit(i, Unity / 4u, Unity * 4u);
+		sum += i;
 	}
 	sum /= size();
 	int64 remain = Unity * size();
-	for(iterator i = begin(); i != end(); i++)
+	for(auto &i : *this)
 	{
-		*i = Util::muldivr_unsigned(*i, Unity, static_cast<int32>(sum));
-		remain -= *i;
+		i = Util::muldivr_unsigned(i, Unity, static_cast<int32>(sum));
+		remain -= i;
 	}
 	//MPT_ASSERT(static_cast<uint32>(mpt::abs(static_cast<int32>(remain))) <= size());
 	at(0) += static_cast<int32>(remain);
@@ -1865,7 +1906,6 @@ void TempoSwing::Normalize()
 
 
 void TempoSwing::Serialize(std::ostream &oStrm, const TempoSwing &swing)
-//----------------------------------------------------------------------
 {
 	mpt::IO::WriteIntLE<uint16>(oStrm, static_cast<uint16>(swing.size()));
 	for(std::size_t i = 0; i < swing.size(); i++)
@@ -1876,7 +1916,6 @@ void TempoSwing::Serialize(std::ostream &oStrm, const TempoSwing &swing)
 
 
 void TempoSwing::Deserialize(std::istream &iStrm, TempoSwing &swing, const size_t)
-//--------------------------------------------------------------------------------
 {
 	uint16 numEntries;
 	mpt::IO::ReadIntLE<uint16>(iStrm, numEntries);
diff --git a/soundlib/Sndfile.h b/soundlib/Sndfile.h
index 3e3565f..3d1f4fa 100644
--- a/soundlib/Sndfile.h
+++ b/soundlib/Sndfile.h
@@ -19,7 +19,7 @@
 #include <bitset>
 #include <set>
 #include "Snd_defs.h"
-#include "tuning.h"
+#include "tuningbase.h"
 #include "MIDIMacros.h"
 #ifdef MODPLUG_TRACKER
 #include "../mptrack/MIDIMapping.h"
@@ -51,11 +51,12 @@
 #include "patternContainer.h"
 #include "ModSequence.h"
 
+#include "../common/FileReaderFwd.h"
+
 
 OPENMPT_NAMESPACE_BEGIN
 
 
-class FileReader;
 // -----------------------------------------------------------------------------
 // MODULAR ModInstrument FIELD ACCESS : body content in InstrumentExtensions.cpp
 // -----------------------------------------------------------------------------
@@ -207,7 +208,10 @@ enum deleteInstrumentSamples
 };
 
 
+namespace Tuning {
 class CTuningCollection;
+} // namespace Tuning
+typedef Tuning::CTuningCollection CTuningCollection;
 struct CModSpecifications;
 #ifdef MODPLUG_TRACKER
 class CModDoc;
@@ -219,9 +223,7 @@ class CModDoc;
 
 #define HISTORY_TIMER_PRECISION	18.2f
 
-//================
 struct FileHistory
-//================
 {
 	// Date when the file was loaded in the the tracker or created.
 	tm loadDate;
@@ -260,9 +262,10 @@ public:
 };
 
 
-//==============
+typedef char NoteName[4];
+
+
 class CSoundFile
-//==============
 {
 	friend class GetLengthMemory;
 
@@ -278,31 +281,23 @@ public: //Misc
 
 	//Tuning-->
 public:
-#ifdef MODPLUG_TRACKER
-	static bool LoadStaticTunings();
-	bool SaveStaticTunings();
-	static void DeleteStaticdata();
-	static CTuningCollection& GetLocalTunings() {return *s_pTuningsSharedLocal;}
-#endif
-	void LoadBuiltInTunings();
-	void UnloadBuiltInTunings();
-	CTuningCollection& GetBuiltInTunings() {return *m_pTuningsBuiltIn;}
+	static CTuning* CreateTuning12TET(const std::string &name);
 	static CTuning *GetDefaultTuning() {return nullptr;}
 	CTuningCollection& GetTuneSpecificTunings() {return *m_pTuningsTuneSpecific;}
 
 	std::string GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst) const;
-	static std::string GetNoteName(const ModCommand::NOTE note);
+	std::string GetNoteName(const ModCommand::NOTE note) const;
+	static std::string GetNoteName(const ModCommand::NOTE note, const NoteName *noteNames);
 #ifdef MODPLUG_TRACKER
-	static const char (*m_NoteNames)[4];
+	static const NoteName *m_NoteNames;
 	static void SetDefaultNoteNames();
+	static const NoteName *GetDefaultNoteNames();
+#else
+	const NoteName *m_NoteNames;
 #endif
 
 private:
 	CTuningCollection* m_pTuningsTuneSpecific;
-#ifdef MODPLUG_TRACKER
-	static CTuningCollection* s_pTuningsSharedLocal;
-#endif
-	CTuningCollection* m_pTuningsBuiltIn;
 	//<--Tuning
 
 #ifdef MODPLUG_TRACKER
@@ -370,6 +365,8 @@ public:
 	TempoMode m_nTempoMode;
 
 #ifdef MODPLUG_TRACKER
+	// Lock playback between two rows. Lock is active if lock start != ROWINDEX_INVALID).
+	ROWINDEX m_lockRowStart, m_lockRowEnd;
 	// Lock playback between two orders. Lock is active if lock start != ORDERINDEX_INVALID).
 	ORDERINDEX m_lockOrderStart, m_lockOrderEnd;
 #endif // MODPLUG_TRACKER
@@ -435,8 +432,8 @@ public:
 		uint32 m_nTickCount;
 	protected:
 		uint32 m_nPatternDelay, m_nFrameDelay;	// m_nPatternDelay = pattern delay (rows), m_nFrameDelay = fine pattern delay (ticks)
-		uint32 m_nSamplesPerTick;
 	public:
+		uint32 m_nSamplesPerTick;
 		ROWINDEX m_nCurrentRowsPerBeat, m_nCurrentRowsPerMeasure;	// current rows per beat and measure for this module
 		uint32 m_nMusicSpeed;	// Current speed
 		TEMPO m_nMusicTempo;	// Current tempo
@@ -462,17 +459,21 @@ public:
 		bool m_bPositionChanged;		// Report to plugins that we jumped around in the module
 
 	public:
-		CHANNELINDEX ChnMix[MAX_CHANNELS];					// Channels to be mixed
-		ModChannel Chn[MAX_CHANNELS];						// Mixing channels... First m_nChannel channels are master channels (i.e. they are never NNA channels)!
-
-	protected:
-		bool m_bPatternTransitionOccurred;
+		CHANNELINDEX ChnMix[MAX_CHANNELS];	// Channels to be mixed
+		ModChannel Chn[MAX_CHANNELS];		// Mixing channels... First m_nChannels channels are master channels (i.e. they are never NNA channels)!
 
 	public:
-		PlayState &operator= (const PlayState &other) { memcpy(this, &other, sizeof(PlayState)); return *this; }
+		PlayState()
+			: m_lTotalSampleCount(0)
+			, m_nSeqOverride(ORDERINDEX_INVALID)
+			, m_bPositionChanged(true)
+		{
+			std::fill(std::begin(Chn), std::end(Chn), ModChannel());
+		}
 	};
 
 	PlayState m_PlayState;
+
 protected:
 	// For handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav.
 	RowVisitor visitedSongRows;
@@ -487,7 +488,7 @@ public:
 public:
 #ifdef LIBOPENMPT_BUILD
 #ifndef NO_PLUGINS
-	MPT_SHARED_PTR<CVstPluginManager> m_PluginManager;
+	std::unique_ptr<CVstPluginManager> m_PluginManager;
 #endif
 #endif
 
@@ -498,7 +499,7 @@ public:
 
 	// Song message
 	SongMessage m_songMessage;
-	std::string m_madeWithTracker;
+	mpt::ustring m_madeWithTracker;
 
 protected:
 	std::vector<FileHistory> m_FileHistory;	// File edit history
@@ -512,7 +513,7 @@ protected:
 	std::vector<mpt::PathString> m_samplePaths;
 
 public:
-	void SetSamplePath(SAMPLEINDEX smp, const mpt::PathString &filename) { if(m_samplePaths.size() < smp) m_samplePaths.resize(smp); m_samplePaths[smp - 1] = filename; }
+	void SetSamplePath(SAMPLEINDEX smp, const mpt::PathString &filename) { if(m_samplePaths.size() < smp) m_samplePaths.resize(smp); m_samplePaths[smp - 1] = filename.Simplify(); }
 	void ResetSamplePath(SAMPLEINDEX smp) { if(m_samplePaths.size() >= smp) m_samplePaths[smp - 1] = mpt::PathString(); Samples[smp].uFlags.reset(SMP_KEEPONDISK | SMP_MODIFIED);}
 	mpt::PathString GetSamplePath(SAMPLEINDEX smp) const { if(m_samplePaths.size() >= smp) return m_samplePaths[smp - 1]; else return mpt::PathString(); }
 	bool SampleHasPath(SAMPLEINDEX smp) const { if(m_samplePaths.size() >= smp) return !m_samplePaths[smp - 1].empty(); else return false; }
@@ -542,15 +543,46 @@ public:
 
 	enum ModLoadingFlags
 	{
-		onlyVerifyHeader	= 0x00,
-		loadPatternData		= 0x01,	// If unset, advise loaders to not process any pattern data (if possible)
-		loadSampleData		= 0x02,	// If unset, advise loaders to not process any sample data (if possible)
-		loadPluginData		= 0x04,	// If unset, plugins are not instanciated.
+		onlyVerifyHeader   = 0x00,
+		loadPatternData    = 0x01,	// If unset, advise loaders to not process any pattern data (if possible)
+		loadSampleData     = 0x02,	// If unset, advise loaders to not process any sample data (if possible)
+		loadPluginData     = 0x04,	// If unset, plugin data is not loaded (and as a consequence, plugins are not instanciated).
+		loadPluginInstance = 0x08,	// If unset, plugins are not instanciated.
+		skipContainer      = 0x10,
+		skipModules        = 0x20,
+
 		// Shortcuts
-		loadCompleteModule	= loadSampleData | loadPatternData | loadPluginData,
+		loadCompleteModule = loadSampleData | loadPatternData | loadPluginData | loadPluginInstance,
 		loadNoPatternOrPluginData	= loadSampleData,
+		loadNoPluginInstance = loadSampleData | loadPatternData | loadPluginData,
 	};
 
+	#define PROBE_RECOMMENDED_SIZE 2048u
+
+	static const std::size_t ProbeRecommendedSize;
+
+	enum ProbeFlags
+	{
+		ProbeModules    = 0x1,
+		ProbeContainers = 0x2,
+
+		ProbeFlagsDefault = ProbeModules | ProbeContainers,
+		ProbeFlagsNone = 0
+	};
+
+	enum ProbeResult
+	{
+		ProbeSuccess      =  1,
+		ProbeFailure      =  0,
+		ProbeWantMoreData = -1
+	};
+
+	static ProbeResult ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize);
+
+	static ProbeResult Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize);
+
+public:
+
 #ifdef MODPLUG_TRACKER
 	// Get parent CModDoc. Can be nullptr if previewing from tree view, and is always nullptr if we're not actually compiling OpenMPT.
 	CModDoc *GetpModDoc() const { return m_pModDoc; }
@@ -566,13 +598,16 @@ public:
 	MODCONTAINERTYPE GetContainerType() const { return m_ContainerType; }
 
 	// rough heuristic, could be improved
-	mpt::Charset GetCharset() const { return GetCharsetFromModType(GetType()); }
-	mpt::Charset GetCharsetLocaleOrModule() const
+	mpt::Charset GetCharsetFile() const // 8bit string encoding of strings in the on-disk file
+	{
+		return GetCharsetFromModType(GetType());
+	}
+	mpt::Charset GetCharsetInternal() const // 8bit string encoding of strings internal in CSoundFile
 	{
 		#if defined(MODPLUG_TRACKER)
 			return mpt::CharsetLocale;
 		#else // MODPLUG_TRACKER
-			return GetCharset();
+			return GetCharsetFile();
 		#endif // MODPLUG_TRACKER
 	}
 
@@ -601,7 +636,7 @@ public:
 #endif // MODPLUG_TRACKER
 
 	double GetCurrentBPM() const;
-	void DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0);		//rewbs.playSongFromCursor
+	void DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0);
 	CHANNELINDEX GetMixStat() const { return m_nMixStat; }
 	void ResetMixStat() { m_nMixStat = 0; }
 	void ResetPlayPos();
@@ -618,8 +653,6 @@ public:
 	//specific order&row etc. Return value is in seconds.
 	std::vector<GetLengthType> GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target = GetLengthTarget());
 
-	void InitializeVisitedRows() { visitedSongRows.Initialize(true); }
-
 public:
 	//Returns song length in seconds.
 	double GetSongTime() { return GetLength(eNoAdjust).back().duration; }
@@ -635,53 +668,101 @@ public:
 	void LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0);
 
 	bool InitChannel(CHANNELINDEX nChn);
+	void InitAmigaResampler();
+
+	static ProbeResult ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize);
+
+	static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize);
+	static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize);
 
 	// Module Loaders
-	bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadS3M(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMod(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadICE(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadPT36(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMed(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadIT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadITProject(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadUlt(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadWav(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadDSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadFAR(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadAMS(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadAMS2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadOKT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadDMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadPTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadDBM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadPSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadPSM16(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadUMX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadDTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadDMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadDSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadFAR(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadGDM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadICE(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadIMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadIT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadITProject(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadJ2B(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadMed(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadMod(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadMTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadOKT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadPLM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
-	bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadPSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadPSM16(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadPT36(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadPTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadS3M(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 	bool ReadSFX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadUlt(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+
+	bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+	bool ReadWav(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
 
 	static std::vector<const char *> GetSupportedExtensions(bool otherFormats);
+	static bool IsExtensionSupported(const char *ext); // UTF8, casing of ext is ignored
 	static mpt::Charset GetCharsetFromModType(MODTYPE modtype);
-	static const char * ModTypeToString(MODTYPE modtype);
-	static std::string ModContainerTypeToString(MODCONTAINERTYPE containertype);
-	static std::string ModTypeToTracker(MODTYPE modtype);
-	static std::string ModContainerTypeToTracker(MODCONTAINERTYPE containertype);
+	static mpt::ustring ModTypeToString(MODTYPE modtype);
+	static mpt::ustring ModContainerTypeToString(MODCONTAINERTYPE containertype);
+	static mpt::ustring ModTypeToTracker(MODTYPE modtype);
+	static mpt::ustring ModContainerTypeToTracker(MODCONTAINERTYPE containertype);
 
 	void UpgradeModule();
 
@@ -699,7 +780,7 @@ public:
 	void LoadExtendedSongProperties(FileReader &file, bool* pInterpretMptMade = nullptr);
 	void LoadMPTMProperties(FileReader &file, uint16 cwtv);
 
-	std::string GetSchismTrackerVersion(uint16 cwtv);
+	mpt::ustring GetSchismTrackerVersion(uint16 cwtv);
 
 	// Reads extended instrument properties(XM/IT/MPTM).
 	// If no errors occur and song extension tag is found, returns pointer to the beginning
@@ -797,13 +878,13 @@ protected:
 	void ProcessPitchPanSeparation(ModChannel *pChn) const;
 	void ProcessPanbrello(ModChannel *pChn) const;
 
-	void ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps);
-	void ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTYPE &vibratoFactor);
-	void ProcessSampleAutoVibrato(ModChannel *pChn, int &period, CTuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const;
+	void ProcessArpeggio(CHANNELINDEX nChn, int &period, Tuning::NOTEINDEXTYPE &arpeggioSteps);
+	void ProcessVibrato(CHANNELINDEX nChn, int &period, Tuning::RATIOTYPE &vibratoFactor);
+	void ProcessSampleAutoVibrato(ModChannel *pChn, int &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const;
 
 	void ProcessRamping(ModChannel *pChn) const;
 
-	uint32 GetChannelIncrement(ModChannel *pChn, uint32 period, int periodFrac) const;
+	SamplePosition GetChannelIncrement(ModChannel *pChn, uint32 period, int periodFrac) const;
 
 protected:
 	// Type of panning command
@@ -856,11 +937,34 @@ protected:
 	void SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume);
 
 	void SetupChannelFilter(ModChannel *pChn, bool bReset, int flt_modifier = 256) const;
+
 	// Low-Level effect processing
 	void DoFreqSlide(ModChannel *pChn, int32 nFreqSlide) const;
 	void UpdateTimeSignature();
 
 public:
+	// Convert frequency to IT cutoff (0...127)
+	uint8 FrequencyToCutOff(double frequency) const;
+	// Convert IT cutoff (0...127 + modifier) to frequency
+	uint32 CutOffToFrequency(uint32 nCutOff, int flt_modifier = 256) const; // [0-127] => [1-10KHz]
+
+	// Returns true if periods are actually plain frequency values in Hz.
+	bool PeriodsAreFrequencies() const
+	{
+		return m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kHertzInLinearMode] && GetType() != MOD_TYPE_XM;
+	}
+	
+	// Returns true if the current format uses transpose+finetune rather than frequency in Hz to specify middle-C.
+	static constexpr bool UseFinetuneAndTranspose(MODTYPE type)
+	{
+		return (type & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_MTM | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP | MOD_TYPE_XM));
+	}
+	bool UseFinetuneAndTranspose() const
+	{
+		return UseFinetuneAndTranspose(GetType());
+	}
+
+public:
 	uint32 GetNumTicksOnCurrentRow() const
 	{
 		return (m_PlayState.m_nMusicSpeed  + m_PlayState.m_nFrameDelay) * std::max(m_PlayState.m_nPatternDelay, static_cast<uint32>(1));
@@ -913,12 +1017,14 @@ public:
 #endif
 	static bool CanReadMP3();
 	static bool CanReadVorbis();
+	static bool CanReadMediaFoundation();
 
 	// Instrument file I/O
 	bool ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize=false);
 	bool ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
 	bool ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
 	bool ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
+	bool ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
 	bool ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize=false);
 #ifndef MODPLUG_NO_FILESAVE
 	bool SaveXIInstrument(INSTRUMENTINDEX nInstr, const mpt::PathString &filename) const;
@@ -937,7 +1043,7 @@ public:
 	ModSample &GetSample(SAMPLEINDEX sample) { MPT_ASSERT(sample <= m_nSamples && sample < CountOf(Samples)); return Samples[sample]; }
 	const ModSample &GetSample(SAMPLEINDEX sample) const { MPT_ASSERT(sample <= m_nSamples && sample < CountOf(Samples)); return Samples[sample]; }
 
-	uint32 MapMidiInstrument(uint32 dwProgram, uint32 nChannel, uint32 nNote);
+	uint32 MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<16> drumChns);
 	size_t ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers);
 	void LoadMixPlugins(FileReader &file);
 #ifndef NO_PLUGINS
@@ -945,7 +1051,6 @@ public:
 	void ProcessMidiOut(CHANNELINDEX nChn);
 #endif // NO_PLUGINS
 
-	uint32 CutOffToFrequency(uint32 nCutOff, int flt_modifier = 256) const; // [0-127] => [1-10KHz]
 	void ProcessGlobalVolume(long countChunk);
 	void ProcessStereoSeparation(long countChunk);
 
@@ -965,9 +1070,8 @@ public:
 
 #ifndef NO_PLUGINS
 inline IMixPlugin* CSoundFile::GetInstrumentPlugin(INSTRUMENTINDEX instr)
-//-----------------------------------------------------------------------
 {
-	if(instr > 0 && instr < MAX_INSTRUMENTS && Instruments[instr] && Instruments[instr]->nMixPlug && Instruments[instr]->nMixPlug <= MAX_MIXPLUGINS)
+	if(instr > 0 && instr <= GetNumInstruments() && Instruments[instr] && Instruments[instr]->nMixPlug && Instruments[instr]->nMixPlug <= MAX_MIXPLUGINS)
 		return m_MixPlugins[Instruments[instr]->nMixPlug - 1].pMixPlugin;
 	else
 		return nullptr;
diff --git a/soundlib/Sndmix.cpp b/soundlib/Sndmix.cpp
index 5c3b642..e88fe82 100644
--- a/soundlib/Sndmix.cpp
+++ b/soundlib/Sndmix.cpp
@@ -31,7 +31,7 @@ OPENMPT_NAMESPACE_BEGIN
 // Log tables for pre-amp
 // Pre-amp (or more precisely: Pre-attenuation) depends on the number of channels,
 // Which this table takes care of.
-static const uint32 PreAmpTable[16] =
+static const uint8 PreAmpTable[16] =
 {
 	0x60, 0x60, 0x60, 0x70,	// 0-7
 	0x80, 0x88, 0x90, 0x98,	// 8-15
@@ -40,7 +40,7 @@ static const uint32 PreAmpTable[16] =
 };
 
 #ifndef NO_AGC
-static const uint32 PreAmpAGCTable[16] =
+static const uint8 PreAmpAGCTable[16] =
 {
 	0x60, 0x60, 0x60, 0x64,
 	0x68, 0x70, 0x78, 0x80,
@@ -58,7 +58,6 @@ static uint32 GetFineLinearSlideUpTable  (const CSoundFile *sndFile, uint32 i) {
 
 
 void CSoundFile::SetMixerSettings(const MixerSettings &mixersettings)
-//-------------------------------------------------------------------
 {
 	SetPreAmp(mixersettings.m_nPreAmp); // adjust agc
 	bool reset = false;
@@ -75,21 +74,21 @@ void CSoundFile::SetMixerSettings(const MixerSettings &mixersettings)
 
 
 void CSoundFile::SetResamplerSettings(const CResamplerSettings &resamplersettings)
-//--------------------------------------------------------------------------------
 {
 	m_Resampler.m_Settings = resamplersettings;
 	m_Resampler.UpdateTables();
+	InitAmigaResampler();
 }
 
 
 void CSoundFile::InitPlayer(bool bReset)
-//--------------------------------------
 {
 	if(bReset)
 	{
 		ResetMixStat();
 		gnDryLOfsVol = 0;
 		gnDryROfsVol = 0;
+		InitAmigaResampler();
 	}
 	m_Resampler.UpdateTables();
 #ifndef NO_REVERB
@@ -111,7 +110,6 @@ void CSoundFile::InitPlayer(bool bReset)
 
 
 bool CSoundFile::FadeSong(uint32 msec)
-//------------------------------------
 {
 	samplecount_t nsamples = Util::muldiv(msec, m_MixerSettings.gdwMixingFreq, 1000);
 	if (nsamples <= 0) return false;
@@ -121,15 +119,14 @@ bool CSoundFile::FadeSong(uint32 msec)
 	// Ramp everything down
 	for (uint32 noff=0; noff < m_nMixChannels; noff++)
 	{
-		ModChannel *pramp = &m_PlayState.Chn[m_PlayState.ChnMix[noff]];
-		if (!pramp) continue;
-		pramp->newRightVol = pramp->newLeftVol = 0;
-		pramp->leftRamp = (-pramp->leftVol << VOLUMERAMPPRECISION) / nRampLength;
-		pramp->rightRamp = (-pramp->rightVol << VOLUMERAMPPRECISION) / nRampLength;
-		pramp->rampLeftVol = pramp->leftVol << VOLUMERAMPPRECISION;
-		pramp->rampRightVol = pramp->rightVol << VOLUMERAMPPRECISION;
-		pramp->nRampLength = nRampLength;
-		pramp->dwFlags.set(CHN_VOLUMERAMP);
+		ModChannel &pramp = m_PlayState.Chn[m_PlayState.ChnMix[noff]];
+		pramp.newRightVol = pramp.newLeftVol = 0;
+		pramp.leftRamp = (-pramp.leftVol << VOLUMERAMPPRECISION) / nRampLength;
+		pramp.rightRamp = (-pramp.rightVol << VOLUMERAMPPRECISION) / nRampLength;
+		pramp.rampLeftVol = pramp.leftVol << VOLUMERAMPPRECISION;
+		pramp.rampRightVol = pramp.rightVol << VOLUMERAMPPRECISION;
+		pramp.nRampLength = nRampLength;
+		pramp.dwFlags.set(CHN_VOLUMERAMP);
 	}
 	return true;
 }
@@ -138,8 +135,7 @@ bool CSoundFile::FadeSong(uint32 msec)
 // Apply stereo separation factor on an interleaved stereo/quad stream.
 // count = Number of stereo sample pairs to process
 // separation = -256...256 (negative values = swap L/R, 0 = mono, 128 = normal)
-static void ApplyStereoSeparation(mixsample_t *mixBuf, CSoundFile::samplecount_t count, int32 separation)
-//-------------------------------------------------------------------------------------------------------
+static void ApplyStereoSeparation(mixsample_t *mixBuf, std::size_t count, int32 separation)
 {
 #ifdef MPT_INTMIXER
 	const mixsample_t factor_num = separation; // 128 =^= 1.0f
@@ -154,7 +150,7 @@ static void ApplyStereoSeparation(mixsample_t *mixBuf, CSoundFile::samplecount_t
 	const float mid_factor = normalize_factor;
 	const float side_factor = factor * normalize_factor;
 #endif
-	for(CSoundFile::samplecount_t i = 0; i < count; i++)
+	for(std::size_t i = 0; i < count; i++)
 	{
 		mixsample_t l = mixBuf[0];
 		mixsample_t r = mixBuf[1];
@@ -177,7 +173,6 @@ static void ApplyStereoSeparation(mixsample_t *mixBuf, CSoundFile::samplecount_t
 
 
 static void ApplyStereoSeparation(mixsample_t *SoundFrontBuffer, mixsample_t *SoundRearBuffer, std::size_t channels, std::size_t countChunk, int32 separation)
-//------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	if(separation == MixerSettings::StereoSeparationScale)
 	{ // identity
@@ -189,15 +184,14 @@ static void ApplyStereoSeparation(mixsample_t *SoundFrontBuffer, mixsample_t *So
 
 
 CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget &target)
-//---------------------------------------------------------------------------------------
 {
 	MPT_ASSERT_ALWAYS(m_MixerSettings.IsValid());
 
 	bool mixPlugins = false;
 #ifndef NO_PLUGINS
-	for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; ++i)
+	for(const auto &plug : m_MixPlugins)
 	{
-		if(m_MixPlugins[i].pMixPlugin)
+		if(plug.pMixPlugin)
 		{
 			mixPlugins = true;
 			break;
@@ -205,9 +199,8 @@ CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget
 	}
 #endif // NO_PLUGINS
 
-	const samplecount_t countGoal = count;
 	samplecount_t countRendered = 0;
-	samplecount_t countToRender = countGoal;
+	samplecount_t countToRender = count;
 
 	while(!m_SongFlags[SONG_ENDREACHED] && countToRender > 0)
 	{
@@ -337,7 +330,6 @@ CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget
 
 
 void CSoundFile::ProcessDSP(std::size_t countChunk)
-//-------------------------------------------------
 {
 	#ifndef NO_DSP
 		if(m_MixerSettings.DSPMask & SNDDSP_SURROUND)
@@ -376,7 +368,6 @@ void CSoundFile::ProcessDSP(std::size_t countChunk)
 // Handles navigation/effects
 
 bool CSoundFile::ProcessRow()
-//---------------------------
 {
 	while(++m_PlayState.m_nTickCount >= GetNumTicksOnCurrentRow())
 	{
@@ -385,9 +376,9 @@ bool CSoundFile::ProcessRow()
 		const bool ignoreRow = m_PlayState.m_nPatternDelay != 0 && m_SongFlags[SONG_BREAKTOROW] && GetType() == MOD_TYPE_MOD;
 
 		// Done with the last row of the pattern or jumping somewhere else
-		if(m_PlayState.m_nNextRow == 0 || m_SongFlags[SONG_BREAKTOROW])
+		const bool patternTransition = m_PlayState.m_nNextRow == 0 || m_SongFlags[SONG_BREAKTOROW];
+		if(patternTransition)
 		{
-			m_PlayState.m_bPatternTransitionOccurred = true;
 			if(GetType() == MOD_TYPE_S3M)
 			{
 				// Reset pattern loop start
@@ -399,7 +390,6 @@ bool CSoundFile::ProcessRow()
 			}
 		}
 
-		HandlePatternTransitionEvents();
 		m_PlayState.m_nPatternDelay = 0;
 		m_PlayState.m_nFrameDelay = 0;
 		m_PlayState.m_nTickCount = 0;
@@ -408,8 +398,17 @@ bool CSoundFile::ProcessRow()
 		m_PlayState.m_nCurrentOrder = m_PlayState.m_nNextOrder;
 
 #ifdef MODPLUG_TRACKER
+		if(patternTransition)
+		{
+			HandlePatternTransitionEvents();
+		}
+		// "Lock row" editing feature
+		if(m_lockRowStart != ROWINDEX_INVALID && (m_PlayState.m_nRow < m_lockRowStart || m_PlayState.m_nRow > m_lockRowEnd) && !IsRenderingToDisc())
+		{
+			m_PlayState.m_nRow = m_lockRowStart;
+		}
 		// "Lock order" editing feature
-		if(Order.IsPositionLocked(m_PlayState.m_nCurrentOrder) && !IsRenderingToDisc())
+		if(Order().IsPositionLocked(m_PlayState.m_nCurrentOrder) && !IsRenderingToDisc())
 		{
 			m_PlayState.m_nCurrentOrder = m_lockOrderStart;
 		}
@@ -418,25 +417,25 @@ bool CSoundFile::ProcessRow()
 		// Check if pattern is valid
 		if(!m_SongFlags[SONG_PATTERNLOOP])
 		{
-			m_PlayState.m_nPattern = (m_PlayState.m_nCurrentOrder < Order.size()) ? Order[m_PlayState.m_nCurrentOrder] : Order.GetInvalidPatIndex();
-			if ((m_PlayState.m_nPattern < Patterns.Size()) && (!Patterns[m_PlayState.m_nPattern])) m_PlayState.m_nPattern = Order.GetIgnoreIndex();
+			m_PlayState.m_nPattern = (m_PlayState.m_nCurrentOrder < Order().size()) ? Order()[m_PlayState.m_nCurrentOrder] : Order.GetInvalidPatIndex();
+			if (m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid()) m_PlayState.m_nPattern = Order.GetIgnoreIndex();
 			while (m_PlayState.m_nPattern >= Patterns.Size())
 			{
 				// End of song?
-				if ((m_PlayState.m_nPattern == Order.GetInvalidPatIndex()) || (m_PlayState.m_nCurrentOrder >= Order.size()))
+				if ((m_PlayState.m_nPattern == Order.GetInvalidPatIndex()) || (m_PlayState.m_nCurrentOrder >= Order().size()))
 				{
 
 					//if (!m_nRepeatCount) return false;
 
-					ORDERINDEX restartPosOverride = Order.GetRestartPos();
-					if(restartPosOverride == 0 && m_PlayState.m_nCurrentOrder <= Order.size() && m_PlayState.m_nCurrentOrder > 0)
+					ORDERINDEX restartPosOverride = Order().GetRestartPos();
+					if(restartPosOverride == 0 && m_PlayState.m_nCurrentOrder <= Order().size() && m_PlayState.m_nCurrentOrder > 0)
 					{
-						/* Subtune detection. Subtunes are separated by "---" order items, so if we're in a
-						   subtune and there's no restart position, we go to the first order of the subtune
-						   (i.e. the first order after the previous "---" item) */
+						// Subtune detection. Subtunes are separated by "---" order items, so if we're in a
+						// subtune and there's no restart position, we go to the first order of the subtune
+						// (i.e. the first order after the previous "---" item)
 						for(ORDERINDEX ord = m_PlayState.m_nCurrentOrder - 1; ord > 0; ord--)
 						{
-							if(Order[ord] == Order.GetInvalidPatIndex())
+							if(Order()[ord] == Order.GetInvalidPatIndex())
 							{
 								// Jump back to first order of this subtune
 								restartPosOverride = ord + 1;
@@ -494,13 +493,13 @@ bool CSoundFile::ProcessRow()
 					m_PlayState.m_nCurrentOrder = restartPosOverride;
 					m_SongFlags.reset(SONG_BREAKTOROW);
 					//If restart pos points to +++, move along
-					while(m_PlayState.m_nCurrentOrder < Order.size() && Order[m_PlayState.m_nCurrentOrder] == Order.GetIgnoreIndex())
+					while(m_PlayState.m_nCurrentOrder < Order().size() && Order()[m_PlayState.m_nCurrentOrder] == Order.GetIgnoreIndex())
 					{
 						m_PlayState.m_nCurrentOrder++;
 					}
 					//Check for end of song or bad pattern
-					if (m_PlayState.m_nCurrentOrder >= Order.size()
-						|| !Order.IsValidPat(m_PlayState.m_nCurrentOrder))
+					if (m_PlayState.m_nCurrentOrder >= Order().size()
+						|| !Order().IsValidPat(m_PlayState.m_nCurrentOrder))
 					{
 						visitedSongRows.Initialize(true);
 						return false;
@@ -510,12 +509,12 @@ bool CSoundFile::ProcessRow()
 					m_PlayState.m_nCurrentOrder++;
 				}
 
-				if (m_PlayState.m_nCurrentOrder < Order.size())
-					m_PlayState.m_nPattern = Order[m_PlayState.m_nCurrentOrder];
+				if (m_PlayState.m_nCurrentOrder < Order().size())
+					m_PlayState.m_nPattern = Order()[m_PlayState.m_nCurrentOrder];
 				else
 					m_PlayState.m_nPattern = Order.GetInvalidPatIndex();
 
-				if ((m_PlayState.m_nPattern < Patterns.Size()) && (!Patterns[m_PlayState.m_nPattern]))
+				if (m_PlayState.m_nPattern < Patterns.Size() && !Patterns[m_PlayState.m_nPattern].IsValid())
 					m_PlayState.m_nPattern = Order.GetIgnoreIndex();
 			}
 			m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder;
@@ -594,8 +593,8 @@ bool CSoundFile::ProcessRow()
 
 					m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder;
 					m_PlayState.m_nNextRow = m_PlayState.m_nRow;
-					if(Order.size() > m_PlayState.m_nCurrentOrder)
-						m_PlayState.m_nPattern = Order[m_PlayState.m_nCurrentOrder];
+					if(Order().size() > m_PlayState.m_nCurrentOrder)
+						m_PlayState.m_nPattern = Order()[m_PlayState.m_nCurrentOrder];
 					visitedSongRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow);
 					if (!Patterns.IsValidPat(m_PlayState.m_nPattern))
 						return false;
@@ -627,6 +626,34 @@ bool CSoundFile::ProcessRow()
 		ModCommand *m = Patterns[m_PlayState.m_nPattern].GetRow(m_PlayState.m_nRow);
 		for (ModChannel *pChn = m_PlayState.Chn, *pEnd = pChn + m_nChannels; pChn != pEnd; pChn++, m++)
 		{
+			// First, handle some quirks that happen after the last tick of the previous row...
+			if(m_playBehaviour[KST3PortaAfterArpeggio]
+				&& pChn->nCommand == CMD_ARPEGGIO	// Previous row state!
+				&& (m->command == CMD_PORTAMENTOUP || m->command == CMD_PORTAMENTODOWN))
+			{
+				// In ST3, a portamento immediately following an arpeggio continues where the arpeggio left off.
+				// Test case: PortaAfterArp.s3m
+				pChn->nPeriod = GetPeriodFromNote(pChn->nArpeggioLastNote, pChn->nFineTune, pChn->nC5Speed);
+			}
+
+			if(m_playBehaviour[kMODOutOfRangeNoteDelay]
+				&& !m->IsNote()
+				&& pChn->rowCommand.IsNote()
+				&& pChn->rowCommand.command == CMD_MODCMDEX && (pChn->rowCommand.param & 0xF0) == 0xD0
+				&& (pChn->rowCommand.param & 0x0Fu) >= m_PlayState.m_nMusicSpeed)
+			{
+				// In ProTracker, a note triggered by an out-of-range note delay can be heard on the next row
+				// if there is no new note on that row.
+				// Test case: NoteDelay-NextRow.mod
+				pChn->nPeriod = GetPeriodFromNote(pChn->rowCommand.note, pChn->nFineTune, 0);
+			}
+			if(m_playBehaviour[kMODTempoOnSecondTick] && !m_playBehaviour[kMODVBlankTiming] && m_PlayState.m_nMusicSpeed == 1 && pChn->rowCommand.command == CMD_TEMPO)
+			{
+				// ProTracker sets the tempo after the first tick. This block handles the case of one tick per row.
+				// Test case: TempoChange.mod
+				m_PlayState.m_nMusicTempo = TEMPO(pChn->rowCommand.param, 0);
+			}
+
 			pChn->rowCommand = *m;
 
 			pChn->rightVol = pChn->newRightVol;
@@ -691,7 +718,6 @@ bool CSoundFile::ProcessRow()
 
 // Calculate delta for Vibrato / Tremolo / Panbrello effect
 int CSoundFile::GetVibratoDelta(int type, int position) const
-//-----------------------------------------------------------
 {
 	// IT compatibility: IT has its own, more precise tables
 	if(m_playBehaviour[kITVibratoTremoloPanbrello])
@@ -709,6 +735,15 @@ int CSoundFile::GetVibratoDelta(int type, int position) const
 		case 3:	// Random
 			return mpt::random<int, 7>(AccessPRNG()) - 0x40;
 		}
+	} else if(GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM))
+	{
+		// Other waveforms are not supported.
+		static const int8 DBMSinus[] =
+		{
+			33, 52, 69, 84, 96, 107, 116, 122,  125, 127,  125, 122, 116, 107, 96, 84,
+			69, 52, 33, 13, -8, -31, -54, -79, -104,-128, -104, -79, -54, -31, -8, 13,
+		};
+		return DBMSinus[(position / 2u) & 0x1F];
 	} else
 	{
 		position &= 0x3F;
@@ -729,7 +764,6 @@ int CSoundFile::GetVibratoDelta(int type, int position) const
 
 
 void CSoundFile::ProcessVolumeSwing(ModChannel *pChn, int &vol) const
-//-------------------------------------------------------------------
 {
 	if(m_playBehaviour[kITSwingBehaviour])
 	{
@@ -750,7 +784,6 @@ void CSoundFile::ProcessVolumeSwing(ModChannel *pChn, int &vol) const
 
 
 void CSoundFile::ProcessPanningSwing(ModChannel *pChn) const
-//----------------------------------------------------------
 {
 	if(m_playBehaviour[kITSwingBehaviour] || m_playBehaviour[kMPTOldSwingBehaviour])
 	{
@@ -767,7 +800,6 @@ void CSoundFile::ProcessPanningSwing(ModChannel *pChn) const
 
 
 void CSoundFile::ProcessTremolo(ModChannel *pChn, int &vol) const
-//---------------------------------------------------------------
 {
 	if (pChn->dwFlags[CHN_TREMOLO])
 	{
@@ -778,32 +810,51 @@ void CSoundFile::ProcessTremolo(ModChannel *pChn, int &vol) const
 			return;
 		}
 
-		uint32 trempos = pChn->nTremoloPos;
 		// IT compatibility: Why would you not want to execute tremolo at volume 0?
 		if(vol > 0 || m_playBehaviour[kITVibratoTremoloPanbrello])
 		{
 			// IT compatibility: We don't need a different attenuation here because of the different tables we're going to use
 			const uint8 attenuation = ((GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD)) || m_playBehaviour[kITVibratoTremoloPanbrello]) ? 5 : 6;
 
-			int delta = GetVibratoDelta(pChn->nTremoloType, trempos);
-			if(GetType() == MOD_TYPE_DMF)
-				delta -= 127;
-			vol += (delta * pChn->nTremoloDepth) / (1 << attenuation);
+			int delta = GetVibratoDelta(pChn->nTremoloType, pChn->nTremoloPos);
+			if((pChn->nTremoloType & 0x03) == 1 && m_playBehaviour[kFT2TremoloRampWaveform])
+			{
+				// FT2 compatibility: Tremolo ramp down / triangle implementation is weird and affected by vibrato position (copypaste bug)
+				// Test case: TremoloWaveforms.xm, TremoloVibrato.xm
+				uint8 ramp = (pChn->nTremoloPos * 4u) & 0x7F;
+				// Volume-colum vibrato gets executed first in FT2, so we may need to advance the vibrato position first
+				uint32 vibPos = pChn->nVibratoPos;
+				if(!m_SongFlags[SONG_FIRSTTICK] && pChn->dwFlags[CHN_VIBRATO])
+					vibPos += pChn->nVibratoSpeed;
+				if((vibPos & 0x3F) >= 32)
+					ramp ^= 0x7F;
+				if((pChn->nTremoloPos & 0x3F) >= 32)
+					delta = -ramp;
+				else
+					delta = ramp;
+			}
+			if(GetType() != MOD_TYPE_DMF)
+			{
+				vol += (delta * pChn->nTremoloDepth) / (1 << attenuation);
+			} else
+			{
+				// Tremolo in DMF always attenuates by a percentage of the current note volume
+				vol -= (vol * pChn->nTremoloDepth * (64 - delta)) / (128 * 64);
+			}
 		}
-		if(!m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_STM|MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]))
+		if(!m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]))
 		{
 			// IT compatibility: IT has its own, more precise tables
 			if(m_playBehaviour[kITVibratoTremoloPanbrello])
-				pChn->nTremoloPos = (pChn->nTremoloPos + 4 * pChn->nTremoloSpeed) & 0xFF;
+				pChn->nTremoloPos += 4 * pChn->nTremoloSpeed;
 			else
-				pChn->nTremoloPos = (pChn->nTremoloPos + pChn->nTremoloSpeed) & 0x3F;
+				pChn->nTremoloPos += pChn->nTremoloSpeed;
 		}
 	}
 }
 
 
 void CSoundFile::ProcessTremor(CHANNELINDEX nChn, int &vol)
-//---------------------------------------------------------
 {
 	ModChannel &chn = m_PlayState.Chn[nChn];
 
@@ -917,7 +968,6 @@ void CSoundFile::ProcessTremor(CHANNELINDEX nChn, int &vol)
 
 
 bool CSoundFile::IsEnvelopeProcessed(const ModChannel *pChn, EnvelopeType env) const
-//----------------------------------------------------------------------------------
 {
 	if(pChn->pModInstrument == nullptr)
 	{
@@ -933,7 +983,6 @@ bool CSoundFile::IsEnvelopeProcessed(const ModChannel *pChn, EnvelopeType env) c
 
 
 void CSoundFile::ProcessVolumeEnvelope(ModChannel *pChn, int &vol) const
-//----------------------------------------------------------------------
 {
 	if(IsEnvelopeProcessed(pChn, ENV_VOLUME))
 	{
@@ -974,7 +1023,6 @@ void CSoundFile::ProcessVolumeEnvelope(ModChannel *pChn, int &vol) const
 
 
 void CSoundFile::ProcessPanningEnvelope(ModChannel *pChn) const
-//-------------------------------------------------------------
 {
 	if(IsEnvelopeProcessed(pChn, ENV_PANNING))
 	{
@@ -1005,7 +1053,6 @@ void CSoundFile::ProcessPanningEnvelope(ModChannel *pChn) const
 
 
 void CSoundFile::ProcessPitchFilterEnvelope(ModChannel *pChn, int &period) const
-//------------------------------------------------------------------------------
 {
 	if(IsEnvelopeProcessed(pChn, ENV_PITCH))
 	{
@@ -1055,7 +1102,7 @@ void CSoundFile::ProcessPitchFilterEnvelope(ModChannel *pChn, int &period) const
 				}
 			} else //Original behavior
 			{
-				const bool useFreq = m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kHertzInLinearMode];
+				const bool useFreq = PeriodsAreFrequencies();
 				const uint32 (&upTable)[256] = useFreq ? LinearSlideUpTable : LinearSlideDownTable;
 				const uint32 (&downTable)[256] = useFreq ? LinearSlideDownTable : LinearSlideUpTable;
 
@@ -1077,7 +1124,6 @@ void CSoundFile::ProcessPitchFilterEnvelope(ModChannel *pChn, int &period) const
 
 
 void CSoundFile::IncrementEnvelopePosition(ModChannel *pChn, EnvelopeType envType) const
-//--------------------------------------------------------------------------------------
 {
 	ModChannel::EnvInfo &chnEnv = pChn->GetEnvelope(envType);
 
@@ -1192,7 +1238,6 @@ void CSoundFile::IncrementEnvelopePosition(ModChannel *pChn, EnvelopeType envTyp
 
 
 void CSoundFile::IncrementEnvelopePositions(ModChannel *pChn) const
-//-----------------------------------------------------------------
 {
 	IncrementEnvelopePosition(pChn, ENV_VOLUME);
 	IncrementEnvelopePosition(pChn, ENV_PANNING);
@@ -1201,7 +1246,6 @@ void CSoundFile::IncrementEnvelopePositions(ModChannel *pChn) const
 
 
 void CSoundFile::ProcessInstrumentFade(ModChannel *pChn, int &vol) const
-//----------------------------------------------------------------------
 {
 	// FadeOut volume
 	if(pChn->dwFlags[CHN_NOTEFADE] && pChn->pModInstrument != nullptr)
@@ -1223,7 +1267,6 @@ void CSoundFile::ProcessInstrumentFade(ModChannel *pChn, int &vol) const
 
 
 void CSoundFile::ProcessPitchPanSeparation(ModChannel *pChn) const
-//----------------------------------------------------------------
 {
 	const ModInstrument *pIns = pChn->pModInstrument;
 
@@ -1237,7 +1280,6 @@ void CSoundFile::ProcessPitchPanSeparation(ModChannel *pChn) const
 
 
 void CSoundFile::ProcessPanbrello(ModChannel *pChn) const
-//-------------------------------------------------------
 {
 	int pdelta = pChn->nPanbrelloOffset;
 	if(pChn->rowCommand.command == CMD_PANBRELLO)
@@ -1245,9 +1287,9 @@ void CSoundFile::ProcessPanbrello(ModChannel *pChn) const
 		uint32 panpos;
 		// IT compatibility: IT has its own, more precise tables
 		if(m_playBehaviour[kITVibratoTremoloPanbrello])
-			panpos = pChn->nPanbrelloPos & 0xFF;
+			panpos = pChn->nPanbrelloPos;
 		else
-			panpos = ((pChn->nPanbrelloPos + 0x10) >> 2) & 0x3F;
+			panpos = ((pChn->nPanbrelloPos + 0x10) >> 2);
 
 		pdelta = GetVibratoDelta(pChn->nPanbrelloType, panpos);
 
@@ -1282,8 +1324,7 @@ void CSoundFile::ProcessPanbrello(ModChannel *pChn) const
 }
 
 
-void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEINDEXTYPE &arpeggioSteps)
-//-----------------------------------------------------------------------------------------------------
+void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, Tuning::NOTEINDEXTYPE &arpeggioSteps)
 {
 	ModChannel *pChn = &m_PlayState.Chn[nChn];
 
@@ -1350,6 +1391,12 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 			pChn->m_ReCalculateFreqOnFirstTick = true;
 		} else
 		{
+			if(GetType() == MOD_TYPE_MT2 && m_SongFlags[SONG_FIRSTTICK])
+			{
+				// MT2 resets any previous portamento when an arpeggio occurs.
+				pChn->nPeriod = period = GetPeriodFromNote(pChn->nNote, pChn->nFineTune, pChn->nC5Speed);
+			}
+
 			if(m_playBehaviour[kITArpeggio])
 			{
 				//IT playback compatibility 01 & 02
@@ -1364,7 +1411,7 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 					case 1: arpRatio = LinearSlideUpTable[(pChn->nArpeggio >> 4) * 16]; break;
 					case 2: arpRatio = LinearSlideUpTable[(pChn->nArpeggio & 0x0F) * 16]; break;
 					}
-					if(m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kHertzInLinearMode])
+					if(PeriodsAreFrequencies())
 						period = Util::muldivr(period, arpRatio, 65536);
 					else
 						period = Util::muldivr(period, 65536, arpRatio);
@@ -1377,7 +1424,7 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 					// Arpeggio is added on top of current note, but cannot do it the IT way because of
 					// the behaviour in ArpeggioClamp.xm.
 					// Test case: ArpSlide.xm
-					uint8 note = (uint8)GetNoteFromPeriod(period, pChn->nFineTune, pChn->nC5Speed);//pChn->nNote;
+					auto note = GetNoteFromPeriod(period, pChn->nFineTune, pChn->nC5Speed);
 
 					// The fact that arpeggio behaves in a totally fucked up way at 16 ticks/row or more is that the arpeggio offset LUT only has 16 entries in FT2.
 					// At more than 16 ticks/row, FT2 reads into the vibrato table, which is placed right after the arpeggio table.
@@ -1392,11 +1439,15 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 					case 2: note += (pChn->nArpeggio & 0x0F); break;
 					}
 
+					period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC5Speed);
+
+					// FT2 compatibility: FT2 has a different note limit for Arpeggio.
 					// Test case: ArpeggioClamp.xm
-					if(note > 108 + NOTE_MIN && arpPos != 0)
-						note = 108 + NOTE_MIN; // FT2's note limit
+					if(note >= 108 + NOTE_MIN && arpPos != 0)
+					{
+						period = std::max<uint32>(period, GetPeriodFromNote(108 + NOTE_MIN, 0, pChn->nC5Speed));
+					}
 
-					period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC5Speed);
 				}
 			}
 			// Other trackers
@@ -1406,13 +1457,14 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 				if(GetType() == MOD_TYPE_STM)
 					tick >>= 4;
 
-				int note = pChn->nNote;
+				// TODO other likely formats for MOD case: MED, OKT, etc
+				uint8 note = (GetType() != MOD_TYPE_MOD) ? pChn->nNote : static_cast<uint8>(GetNoteFromPeriod(period, pChn->nFineTune, pChn->nC5Speed));
 				switch(tick % 3)
 				{
 				case 1: note += (pChn->nArpeggio >> 4); break;
 				case 2: note += (pChn->nArpeggio & 0x0F); break;
 				}
-				if(note != pChn->nNote || GetType() == MOD_TYPE_STM)
+				if(note != pChn->nNote || GetType() == MOD_TYPE_STM || m_playBehaviour[KST3PortaAfterArpeggio])
 				{
 					if(m_SongFlags[SONG_PT_MODE])
 					{
@@ -1429,11 +1481,14 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 					}
 					period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC5Speed);
 
-					// The arpeggio note offset remains effective after the end of the current row in ScreamTracker 2.
-					// This fixes the flute lead in MORPH.STM by Skaven, pattern 27.
 					if(GetType() & (MOD_TYPE_STM | MOD_TYPE_PSM))
 					{
+						// The arpeggio note offset remains effective after the end of the current row in ScreamTracker 2.
+						// This fixes the flute lead in MORPH.STM by Skaven, pattern 27.
 						pChn->nPeriod = period;
+					} else if(m_playBehaviour[KST3PortaAfterArpeggio])
+					{
+						pChn->nArpeggioLastNote = note;
 					}
 				}
 			}
@@ -1442,8 +1497,7 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int &period, CTuning::NOTEIN
 }
 
 
-void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTYPE &vibratoFactor)
-//------------------------------------------------------------------------------------------------
+void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, Tuning::RATIOTYPE &vibratoFactor)
 {
 	ModChannel &chn = m_PlayState.Chn[nChn];
 
@@ -1453,20 +1507,23 @@ void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTY
 		{
 			if(chn.nVibratoPos % 2u)
 			{
-				period += chn.nVibratoDepth * 166;	// Already multiplied by 4, and it seems like the real factor here is 669... how original =)
+				period += chn.nVibratoDepth * 167;	// Already multiplied by 4, and it seems like the real factor here is 669... how original =)
 			}
 			chn.nVibratoPos++;
 			return;
 		}
 
-		uint32 vibpos = chn.nVibratoPos;
-		int vdelta = GetVibratoDelta(chn.nVibratoType, vibpos);
+		// IT compatibility: IT has its own, more precise tables and pre-increments the vibrato position
+		if(m_playBehaviour[kITVibratoTremoloPanbrello])
+			chn.nVibratoPos += 4 * chn.nVibratoSpeed;
+
+		int vdelta = GetVibratoDelta(chn.nVibratoType, chn.nVibratoPos);
 
 		if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning)
 		{
 			//Hack implementation: Scaling vibratofactor to [0.95; 1.05]
 			//using figure from above tables and vibratodepth parameter
-			vibratoFactor += 0.05F * vdelta * chn.m_VibratoDepth / 128.0F;
+			vibratoFactor += 0.05f * (vdelta * chn.nVibratoDepth) / (128.0f * 60.0f);
 			chn.m_CalculateFreq = true;
 			chn.m_ReCalculateFreqOnFirstTick = false;
 
@@ -1504,9 +1561,17 @@ void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTY
 				}
 			} else
 			{
-				vdepth = ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || m_SongFlags[SONG_ITOLDEFFECTS]) ? 6 : 7;
-				if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_MTM)) vdepth = 7;	// Closer than 6, but not quite.
-				if(m_SongFlags[SONG_S3MOLDVIBRATO]) vdepth = 5;
+				if(m_SongFlags[SONG_S3MOLDVIBRATO])
+					vdepth = 5;
+				else if(GetType() == MOD_TYPE_DTM)
+					vdepth = 8;
+				else if(GetType() & (MOD_TYPE_DBM | MOD_TYPE_MTM))
+					vdepth = 7;
+				else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])
+					vdepth = 7;
+				else
+					vdepth = 6;
+
 				// ST3 compatibility: Do not distinguish between vibrato types in effect memory
 				// Test case: VibratoTypeChange.s3m
 				if(m_playBehaviour[kST3VibratoMemory] && chn.rowCommand.command == CMD_FINEVIBRATO)
@@ -1560,11 +1625,9 @@ void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTY
 				return;
 			}
 
-			// IT compatibility: IT has its own, more precise tables
-			if(m_playBehaviour[kITVibratoTremoloPanbrello])
-				chn.nVibratoPos = (vibpos + 4 * chn.nVibratoSpeed) & 0xFF;
-			else
-				chn.nVibratoPos = (vibpos + chn.nVibratoSpeed) & 0x3F;
+			// IT compatibility: IT has its own, more precise tables and pre-increments the vibrato position
+			if(!m_playBehaviour[kITVibratoTremoloPanbrello])
+				chn.nVibratoPos += chn.nVibratoSpeed;
 		}
 	} else if(chn.dwOldFlags[CHN_VIBRATO])
 	{
@@ -1580,8 +1643,7 @@ void CSoundFile::ProcessVibrato(CHANNELINDEX nChn, int &period, CTuning::RATIOTY
 }
 
 
-void CSoundFile::ProcessSampleAutoVibrato(ModChannel *pChn, int &period, CTuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const
-//---------------------------------------------------------------------------------------------------------------------------------
+void CSoundFile::ProcessSampleAutoVibrato(ModChannel *pChn, int &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const
 {
 	// Sample Auto-Vibrato
 	if ((pChn->pModSample) && (pChn->pModSample->nVibDepth))
@@ -1591,15 +1653,18 @@ void CSoundFile::ProcessSampleAutoVibrato(ModChannel *pChn, int &period, CTuning
 
 		// In IT linear slide mode, we use frequencies, otherwise we use periods, which are upside down.
 		// In this context, the "up" tables refer to the tables that increase frequency, and the down tables are the ones that decrease frequency.
-		const bool useFreq = m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kHertzInLinearMode];
+		const bool useFreq = PeriodsAreFrequencies();
 		const uint32 (&upTable)[256] = useFreq ? LinearSlideUpTable : LinearSlideDownTable;
 		const uint32 (&downTable)[256] = useFreq ? LinearSlideDownTable : LinearSlideUpTable;
 		const uint32 (&fineUpTable)[16] = useFreq ? FineLinearSlideUpTable : FineLinearSlideDownTable;
 		const uint32 (&fineDownTable)[16] = useFreq ? FineLinearSlideDownTable : FineLinearSlideUpTable;
 
 		// IT compatibility: Autovibrato is so much different in IT that I just put this in a separate code block, to get rid of a dozen IsCompatibilityMode() calls.
-		if(m_playBehaviour[kITVibratoTremoloPanbrello] && !alternativeTuning)
+		if(m_playBehaviour[kITVibratoTremoloPanbrello] && !alternativeTuning && GetType() != MOD_TYPE_MT2)
 		{
+			if(!pSmp->nVibRate)
+				return;
+
 			// Schism's autovibrato code
 
 			/*
@@ -1759,7 +1824,6 @@ void CSoundFile::ProcessSampleAutoVibrato(ModChannel *pChn, int &period, CTuning
 
 
 void CSoundFile::ProcessRamping(ModChannel *pChn) const
-//-----------------------------------------------------
 {
 	pChn->leftRamp = pChn->rightRamp = 0;
 	if(pChn->dwFlags[CHN_VOLUMERAMP] && (pChn->leftVol != pChn->newLeftVol || pChn->rightVol != pChn->newRightVol))
@@ -1824,8 +1888,7 @@ void CSoundFile::ProcessRamping(ModChannel *pChn) const
 }
 
 
-uint32 CSoundFile::GetChannelIncrement(ModChannel *pChn, uint32 period, int periodFrac) const
-//-------------------------------------------------------------------------------------------
+SamplePosition CSoundFile::GetChannelIncrement(ModChannel *pChn, uint32 period, int periodFrac) const
 {
 	uint32 freq;
 
@@ -1846,7 +1909,7 @@ uint32 CSoundFile::GetChannelIncrement(ModChannel *pChn, uint32 period, int peri
 
 	// Avoid increment to overflow and become negative with unrealisticly high frequencies.
 	LimitMax(freq, uint32(int32_max));
-	return Util::muldivr(freq, 0x10000, m_MixerSettings.gdwMixingFreq << FREQ_FRACBITS);
+	return SamplePosition::Ratio(freq, m_MixerSettings.gdwMixingFreq << FREQ_FRACBITS);
 }
 
 
@@ -1854,7 +1917,6 @@ uint32 CSoundFile::GetChannelIncrement(ModChannel *pChn, uint32 period, int peri
 // Handles envelopes & mixer setup
 
 bool CSoundFile::ReadNote()
-//-------------------------
 {
 #ifdef MODPLUG_TRACKER
 	// Checking end of row ?
@@ -1938,15 +2000,15 @@ bool CSoundFile::ReadNote()
 			continue;
 		}
 		// Reset channel data
-		pChn->nInc = 0;
+		pChn->increment = SamplePosition(0);
 		pChn->nRealVolume = 0;
 		pChn->nCalcVolume = 0;
 
 		pChn->nRampLength = 0;
 
 		//Aux variables
-		CTuning::RATIOTYPE vibratoFactor = 1;
-		CTuning::NOTEINDEXTYPE arpeggioSteps = 0;
+		Tuning::RATIOTYPE vibratoFactor = 1;
+		Tuning::NOTEINDEXTYPE arpeggioSteps = 0;
 
 		const ModInstrument *pIns = pChn->pModInstrument;
 
@@ -2022,7 +2084,7 @@ bool CSoundFile::ReadNote()
 			// Test case: PeriodLimit.s3m
 			if (pChn->nPeriod < m_nMinPeriod
 				&& GetType() != MOD_TYPE_S3M
-				&& !(m_playBehaviour[kHertzInLinearMode] && m_SongFlags[SONG_LINEARSLIDES]))
+				&& !PeriodsAreFrequencies())
 			{
 				pChn->nPeriod = m_nMinPeriod;
 			}
@@ -2084,6 +2146,25 @@ bool CSoundFile::ReadNote()
 			ProcessPitchFilterEnvelope(pChn, period);
 		}
 
+		if(pChn->rowCommand.volcmd == VOLCMD_VIBRATODEPTH &&
+			(pChn->rowCommand.command == CMD_VIBRATO || pChn->rowCommand.command == CMD_VIBRATOVOL || pChn->rowCommand.command == CMD_FINEVIBRATO))
+		{
+			if(GetType() == MOD_TYPE_XM)
+			{
+				// XM Compatibility: Vibrato should be advanced twice (but not added up) if both volume-column and effect column vibrato is present.
+				// Effect column vibrato parameter has precedence if non-zero.
+				// Test case: VibratoDouble.xm
+				if(!m_SongFlags[SONG_FIRSTTICK])
+					pChn->nVibratoPos += pChn->nVibratoSpeed;
+			} else if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
+			{
+				// IT Compatibility: Vibrato should be applied twice if both volume-colum and effect column vibrato is present.
+				// Volume column vibrato parameter has precedence if non-zero.
+				// Test case: VibratoDouble.it
+				Vibrato(pChn, pChn->rowCommand.vol);
+				ProcessVibrato(nChn, period, vibratoFactor);
+			}
+		}
 		// Plugins may also receive vibrato
 		ProcessVibrato(nChn, period, vibratoFactor);
 
@@ -2108,6 +2189,8 @@ bool CSoundFile::ReadNote()
 				{
 					ModCommand::NOTE note = pChn->nNote;
 					if(!ModCommand::IsNote(note)) note = pChn->nLastNote;
+					if(m_playBehaviour[kITRealNoteMapping] && note >= NOTE_MIN && note <= NOTE_MAX)
+						note = pIns->NoteMap[note - NOTE_MIN];
 					pChn->m_Freq = Util::Round<uint32>((pChn->nC5Speed << FREQ_FRACBITS) * vibratoFactor * pIns->pTuning->GetRatio(note - NOTE_MIDDLEC + arpeggioSteps, pChn->nFineTune+pChn->m_PortamentoFineSteps));
 					if(!pChn->m_CalculateFreq)
 						pChn->m_ReCalculateFreqOnFirstTick = false;
@@ -2117,20 +2200,15 @@ bool CSoundFile::ReadNote()
 			}
 
 
-			uint32 ninc = GetChannelIncrement(pChn, period, nPeriodFrac);
+			SamplePosition ninc = GetChannelIncrement(pChn, period, nPeriodFrac);
 #ifndef MODPLUG_TRACKER
-			ninc = Util::muldivr(ninc, m_nFreqFactor, 65536);
+			ninc.MulDiv(m_nFreqFactor, 65536);
 #endif // !MODPLUG_TRACKER
-			if(ninc == 0)
+			if(ninc.IsZero())
 			{
-				ninc = 1;
+				ninc.Set(0, 1);
 			}
-			pChn->nInc = ninc;
-		} else
-		{
-			// Avoid nasty noises...
-			// This could have been != 0 if a plugin was assigned to the channel, for macro purposes.
-			pChn->nRealVolume = 0;
+			pChn->increment = ninc;
 		}
 
 		// Increment envelope positions
@@ -2147,11 +2225,9 @@ bool CSoundFile::ReadNote()
 		if (pChn->nLeftVU > VUMETER_DECAY) pChn->nLeftVU -= VUMETER_DECAY; else pChn->nLeftVU = 0;
 		if (pChn->nRightVU > VUMETER_DECAY) pChn->nRightVU -= VUMETER_DECAY; else pChn->nRightVU = 0;
 
-		// Check for too big nInc
-		//if (((pChn->nInc >> 16) + 1) >= (int32)(pChn->nLoopEnd - pChn->nLoopStart)) pChn->dwFlags.reset(CHN_LOOP);
 		pChn->newLeftVol = pChn->newRightVol = 0;
-		pChn->pCurrentSample = (pChn->pModSample && pChn->pModSample->pSample && pChn->nLength && pChn->nInc) ? pChn->pModSample->pSample : nullptr;
-		if (pChn->pCurrentSample)
+		pChn->pCurrentSample = (pChn->pModSample && pChn->pModSample->pSample && pChn->nLength && pChn->IsSamplePlaying()) ? pChn->pModSample->pSample : nullptr;
+		if (pChn->pCurrentSample || (pChn->HasMIDIOutput() && !pChn->dwFlags[CHN_KEYOFF | CHN_NOTEFADE]))
 		{
 			// Update VU-Meter (nRealVolume is 14-bit)
 			uint32 vul = (pChn->nRealVolume * pChn->nRealPan) / (1 << 14);
@@ -2164,7 +2240,15 @@ bool CSoundFile::ReadNote()
 			if (pChn->nRightVU > 127) pChn->nRightVU = (uint8)vur;
 			vur /= 2;
 			if (pChn->nRightVU < vur) pChn->nRightVU = (uint8)vur;
+		} else
+		{
+			// Note change but no sample
+			if (pChn->nLeftVU > 128) pChn->nLeftVU = 0;
+			if (pChn->nRightVU > 128) pChn->nRightVU = 0;
+		}
 
+		if (pChn->pCurrentSample)
+		{
 #ifdef MODPLUG_TRACKER
 			const uint32 kChnMasterVol = pChn->dwFlags[CHN_EXTRALOUD] ? (uint32)m_PlayConfig.getNormalSamplePreAmp() : nMasterVol;
 #else
@@ -2225,31 +2309,32 @@ bool CSoundFile::ReadNote()
 			//if (pChn->nNewRightVol > 0xFFFF) pChn->nNewRightVol = 0xFFFF;
 			//if (pChn->nNewLeftVol > 0xFFFF) pChn->nNewLeftVol = 0xFFFF;
 
-			if(pChn->nInc == 0x10000 && !(pChn->dwFlags[CHN_VIBRATO] || pChn->nAutoVibDepth))
+			if(pChn->pModInstrument && IsKnownResamplingMode(pChn->pModInstrument->nResampling))
 			{
-				// Exact sample rate match, do not resample at all, regardless of selected resampler
-				// - unless vibrato is applied, because in this case the constant enabling and disabling
-				// of resampling can introduce clicks (this is easily observable with a sine sample
-				// played at the mix rate).
-				pChn->resamplingMode = SRCMODE_NEAREST;
-			} else if(pChn->pModInstrument && IsKnownResamplingMode(pChn->pModInstrument->nResampling))
-			{
-				// for defined resampling modes, use per-instrument resampling mode if set
+				// For defined resampling modes, use per-instrument resampling mode if set
 				pChn->resamplingMode = static_cast<uint8>(pChn->pModInstrument->nResampling);
 			} else if(IsKnownResamplingMode(m_nResampling))
 			{
 				pChn->resamplingMode = static_cast<uint8>(m_nResampling);
+			} else if(m_SongFlags[SONG_ISAMIGA] && m_Resampler.m_Settings.emulateAmiga)
+			{
+				// Enforce Amiga resampler for Amiga modules
+				pChn->resamplingMode = SRCMODE_AMIGA;
 			} else
 			{
-				// default to global mixer settings
+				// Default to global mixer settings
 				pChn->resamplingMode = static_cast<uint8>(m_Resampler.m_Settings.SrcMode);
 			}
 
-			/*if (m_pConfig->getUseGlobalPreAmp())
+			if(pChn->increment.IsUnity() && !(pChn->dwFlags[CHN_VIBRATO] || pChn->nAutoVibDepth || pChn->resamplingMode == SRCMODE_AMIGA))
 			{
-				pChn->nNewRightVol >>= MIXING_ATTENUATION;
-				pChn->nNewLeftVol >>= MIXING_ATTENUATION;
-			}*/
+				// Exact sample rate match, do not interpolate at all
+				// - unless vibrato is applied, because in this case the constant enabling and disabling
+				// of resampling can introduce clicks (this is easily observable with a sine sample
+				// played at the mix rate).
+				pChn->resamplingMode = SRCMODE_NEAREST;
+			}
+
 			const int extraAttenuation = m_PlayConfig.getExtraSampleAttenuation();
 			pChn->newLeftVol /= (1 << extraAttenuation);
 			pChn->newRightVol /= (1 << extraAttenuation);
@@ -2258,7 +2343,7 @@ bool CSoundFile::ReadNote()
 			if(pChn->dwFlags[CHN_SURROUND] && m_MixerSettings.gnChannels == 2) pChn->newRightVol = - pChn->newRightVol;
 
 			// Checking Ping-Pong Loops
-			if(pChn->dwFlags[CHN_PINGPONGFLAG]) pChn->nInc = -pChn->nInc;
+			if(pChn->dwFlags[CHN_PINGPONGFLAG]) pChn->increment.Negate();
 
 			// Setting up volume ramp
 			ProcessRamping(pChn);
@@ -2267,10 +2352,6 @@ bool CSoundFile::ReadNote()
 			m_PlayState.ChnMix[m_nMixChannels++] = nChn;
 		} else
 		{
-			// Note change but no sample
-			if (pChn->nLeftVU > 128) pChn->nLeftVU = 0;
-			if (pChn->nRightVU > 128) pChn->nRightVU = 0;
-
 			pChn->rightVol = pChn->leftVol = 0;
 			pChn->nLength = 0;
 		}
@@ -2278,27 +2359,17 @@ bool CSoundFile::ReadNote()
 		pChn->dwOldFlags = pChn->dwFlags;
 	}
 
-	// Checking Max Mix Channels reached: ordering by volume
+	// If there are more channels being mixed than allowed, order them by volume and discard the most quiet ones
 	if(m_nMixChannels >= m_MixerSettings.m_nMaxMixChannels)
 	{
-		for(CHANNELINDEX i=0; i<m_nMixChannels; i++)
-		{
-			CHANNELINDEX j=i;
-			while ((j+1<m_nMixChannels) && (m_PlayState.Chn[m_PlayState.ChnMix[j]].nRealVolume < m_PlayState.Chn[m_PlayState.ChnMix[j+1]].nRealVolume))
-			{
-				CHANNELINDEX n = m_PlayState.ChnMix[j];
-				m_PlayState.ChnMix[j] = m_PlayState.ChnMix[j+1];
-				m_PlayState.ChnMix[j+1] = n;
-				j++;
-			}
-		}
+		std::partial_sort(std::begin(m_PlayState.ChnMix), std::begin(m_PlayState.ChnMix) + m_MixerSettings.m_nMaxMixChannels, std::begin(m_PlayState.ChnMix) + m_nMixChannels,
+			[this](CHANNELINDEX i, CHANNELINDEX j) { return (m_PlayState.Chn[i].nRealVolume > m_PlayState.Chn[j].nRealVolume); });
 	}
 	return true;
 }
 
 
 void CSoundFile::ProcessMacroOnChannel(CHANNELINDEX nChn)
-//-------------------------------------------------------
 {
 	ModChannel *pChn = &m_PlayState.Chn[nChn];
 	if(nChn < GetNumChannels())
@@ -2321,7 +2392,6 @@ void CSoundFile::ProcessMacroOnChannel(CHANNELINDEX nChn)
 #ifndef NO_PLUGINS
 
 void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn)
-//------------------------------------------------
 {
 	ModChannel &chn = m_PlayState.Chn[nChn];
 
@@ -2427,7 +2497,7 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn)
 
 
 template<int channels>
-forceinline void ApplyGlobalVolumeWithRamping(int *SoundBuffer, int *RearBuffer, int32 lCount, int32 m_nGlobalVolume, int32 step, int32 &m_nSamplesToGlobalVolRampDest, int32 &m_lHighResRampingGlobalVolume)
+MPT_FORCEINLINE void ApplyGlobalVolumeWithRamping(int *SoundBuffer, int *RearBuffer, int32 lCount, int32 m_nGlobalVolume, int32 step, int32 &m_nSamplesToGlobalVolRampDest, int32 &m_lHighResRampingGlobalVolume)
 {
 	const bool isStereo = (channels >= 2);
 	const bool hasRear = (channels >= 4);
@@ -2457,7 +2527,6 @@ forceinline void ApplyGlobalVolumeWithRamping(int *SoundBuffer, int *RearBuffer,
 
 
 void CSoundFile::ProcessGlobalVolume(long lCount)
-//-----------------------------------------------
 {
 
 	// should we ramp?
@@ -2521,7 +2590,6 @@ void CSoundFile::ProcessGlobalVolume(long lCount)
 
 
 void CSoundFile::ProcessStereoSeparation(long countChunk)
-//-------------------------------------------------------
 {
 	ApplyStereoSeparation(MixSoundBuffer, MixRearBuffer, m_MixerSettings.gnChannels, countChunk, m_MixerSettings.m_nStereoSeparation);
 }
diff --git a/soundlib/SoundFilePlayConfig.cpp b/soundlib/SoundFilePlayConfig.cpp
index d725981..2bc37bb 100644
--- a/soundlib/SoundFilePlayConfig.cpp
+++ b/soundlib/SoundFilePlayConfig.cpp
@@ -16,18 +16,15 @@
 OPENMPT_NAMESPACE_BEGIN
 
 CSoundFilePlayConfig::CSoundFilePlayConfig()
-//------------------------------------------
 {
 	setVSTiVolume(1.0f);
 }
 
 CSoundFilePlayConfig::~CSoundFilePlayConfig()
-//-------------------------------------------
 {
 }
 
 void CSoundFilePlayConfig::SetMixLevels(MixLevels mixLevelType)
-//-------------------------------------------------------------
 {
 	switch (mixLevelType)
 	{
diff --git a/soundlib/Tables.cpp b/soundlib/Tables.cpp
index fe8ca53..9fa3511 100644
--- a/soundlib/Tables.cpp
+++ b/soundlib/Tables.cpp
@@ -42,98 +42,100 @@ const char NoteNamesFlat[12][4] =
 
 struct ModFormatInfo
 {
-	MODTYPE format;			// MOD_TYPE_XXXX
-	const char *name;		// "ProTracker"
-	const char *extension;	// "mod"
+	MODTYPE format;              // MOD_TYPE_XXXX
+	const MPT_UCHAR_TYPE *name;  // "ProTracker"
+	const char *extension;       // "mod"
 };
 
 // remember to also update libopenmpt/foo_openmpt.cpp (all other plugins read these dynamically)
-static const ModFormatInfo modFormatInfo[] =
+static constexpr ModFormatInfo modFormatInfo[] =
 {
-	{ MOD_TYPE_MOD,		"ProTracker",				"mod" },
-	{ MOD_TYPE_S3M,		"ScreamTracker 3",			"s3m" },
-	{ MOD_TYPE_XM,		"FastTracker II",			"xm" },
-	{ MOD_TYPE_IT,		"Impulse Tracker",			"it" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("ProTracker"),              "mod" },
+	{ MOD_TYPE_S3M,  MPT_ULITERAL("ScreamTracker 3"),         "s3m" },
+	{ MOD_TYPE_XM,   MPT_ULITERAL("FastTracker II"),          "xm" },
+	{ MOD_TYPE_IT,   MPT_ULITERAL("Impulse Tracker"),         "it" },
 #ifdef MPT_EXTERNAL_SAMPLES
-	{ MOD_TYPE_IT,		"Impulse Tracker Project",	"itp" },
+	{ MOD_TYPE_IT,   MPT_ULITERAL("Impulse Tracker Project"), "itp" },
 #endif
-	{ MOD_TYPE_MPT,		"OpenMPT",					"mptm" },
-	{ MOD_TYPE_STM,		"ScreamTracker 2",			"stm" },
-	{ MOD_TYPE_MOD,		"ProTracker",				"pt36" },
-	{ MOD_TYPE_MOD,		"NoiseTracker",				"nst" },
-	{ MOD_TYPE_MOD,		"Soundtracker",				"m15" },
-	{ MOD_TYPE_MOD,		"Soundtracker",				"stk" },
-	{ MOD_TYPE_MOD,		"SoundTracker 2.6",			"st26" },
-	{ MOD_TYPE_MOD,		"Ice Tracker",				"ice" },
-	{ MOD_TYPE_MOD,		"Mod's Grave",				"wow" },
-	{ MOD_TYPE_ULT,		"UltraTracker",				"ult" },
-	{ MOD_TYPE_669,		"Composer 669 / UNIS 669",	"669" },
-	{ MOD_TYPE_MTM,		"MultiTracker",				"mtm" },
-	{ MOD_TYPE_MED,		"OctaMed",					"med" },
-	{ MOD_TYPE_FAR,		"Farandole Composer",		"far" },
-	{ MOD_TYPE_MDL,		"Digitrakker",				"mdl" },
-	{ MOD_TYPE_AMS,		"Extreme's Tracker",		"ams" },
-	{ MOD_TYPE_AMS2,	"Velvet Studio",			"ams" },
-	{ MOD_TYPE_DSM,		"DSIK Format",				"dsm" },
-	{ MOD_TYPE_AMF,		"DSMI",						"amf" },
-	{ MOD_TYPE_AMF0,	"ASYLUM",					"amf" },
-	{ MOD_TYPE_OKT,		"Oktalyzer",				"okt" },
-	{ MOD_TYPE_DMF,		"X-Tracker",				"dmf" },
-	{ MOD_TYPE_PTM,		"PolyTracker",				"ptm" },
-	{ MOD_TYPE_PSM,		"Epic Megagames MASI",		"psm" },
-	{ MOD_TYPE_MT2,		"MadTracker 2",				"mt2" },
-	{ MOD_TYPE_DBM,		"DigiBooster Pro",			"dbm" },
-	{ MOD_TYPE_DIGI,	"DigiBooster",				"digi" },
-	{ MOD_TYPE_IMF,		"Imago Orpheus",			"imf" },
-	{ MOD_TYPE_J2B,		"Galaxy Sound System",		"j2b" },
-	{ MOD_TYPE_PLM,		"Disorder Tracker 2",		"plm" },
-	{ MOD_TYPE_SFX,		"SoundFX",					"sfx" },
-	{ MOD_TYPE_SFX,		"SoundFX",					"sfx2" },
-	{ MOD_TYPE_SFX,		"MultiMedia Sound",			"mms" },
+	{ MOD_TYPE_MPT,  MPT_ULITERAL("OpenMPT"),                 "mptm" },
+	{ MOD_TYPE_STM,  MPT_ULITERAL("ScreamTracker 2"),         "stm" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("ProTracker"),              "pt36" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("NoiseTracker"),            "nst" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("Soundtracker"),            "m15" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("Soundtracker"),            "stk" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("SoundTracker 2.6"),        "st26" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("Ice Tracker"),             "ice" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("Mod's Grave"),             "wow" },
+	{ MOD_TYPE_ULT,  MPT_ULITERAL("UltraTracker"),            "ult" },
+	{ MOD_TYPE_669,  MPT_ULITERAL("Composer 669 / UNIS 669"), "669" },
+	{ MOD_TYPE_MTM,  MPT_ULITERAL("MultiTracker"),            "mtm" },
+	{ MOD_TYPE_MED,  MPT_ULITERAL("OctaMed"),                 "med" },
+	{ MOD_TYPE_FAR,  MPT_ULITERAL("Farandole Composer"),      "far" },
+	{ MOD_TYPE_MDL,  MPT_ULITERAL("Digitrakker"),             "mdl" },
+	{ MOD_TYPE_AMS,  MPT_ULITERAL("Extreme's Tracker"),       "ams" },
+	{ MOD_TYPE_AMS2, MPT_ULITERAL("Velvet Studio"),           "ams" },
+	{ MOD_TYPE_DSM,  MPT_ULITERAL("DSIK Format"),             "dsm" },
+	{ MOD_TYPE_AMF,  MPT_ULITERAL("DSMI"),                    "amf" },
+	{ MOD_TYPE_AMF0, MPT_ULITERAL("ASYLUM"),                  "amf" },
+	{ MOD_TYPE_OKT,  MPT_ULITERAL("Oktalyzer"),               "okt" },
+	{ MOD_TYPE_DMF,  MPT_ULITERAL("X-Tracker"),               "dmf" },
+	{ MOD_TYPE_PTM,  MPT_ULITERAL("PolyTracker"),             "ptm" },
+	{ MOD_TYPE_PSM,  MPT_ULITERAL("Epic Megagames MASI"),     "psm" },
+	{ MOD_TYPE_MT2,  MPT_ULITERAL("MadTracker 2"),            "mt2" },
+	{ MOD_TYPE_DBM,  MPT_ULITERAL("DigiBooster Pro"),         "dbm" },
+	{ MOD_TYPE_DIGI, MPT_ULITERAL("DigiBooster"),             "digi" },
+	{ MOD_TYPE_IMF,  MPT_ULITERAL("Imago Orpheus"),           "imf" },
+	{ MOD_TYPE_J2B,  MPT_ULITERAL("Galaxy Sound System"),     "j2b" },
+	{ MOD_TYPE_PLM,  MPT_ULITERAL("Disorder Tracker 2"),      "plm" },
+	{ MOD_TYPE_SFX,  MPT_ULITERAL("SoundFX"),                 "sfx" },
+	{ MOD_TYPE_SFX,  MPT_ULITERAL("SoundFX"),                 "sfx2" },
+	{ MOD_TYPE_SFX,  MPT_ULITERAL("MultiMedia Sound"),        "mms" },
+	{ MOD_TYPE_STP,  MPT_ULITERAL("Soundtracker Pro II"),     "stp" },
+	{ MOD_TYPE_DTM,  MPT_ULITERAL("Digital Tracker"),         "dtm" },
 
 #ifndef NO_ARCHIVE_SUPPORT
 	// Compressed modules
-	{ MOD_TYPE_MOD,		"ProTracker",				"mdz" },
-	{ MOD_TYPE_MOD,		"ProTracker",				"mdr" },
-	{ MOD_TYPE_S3M,		"ScreamTracker 3",			"s3z" },
-	{ MOD_TYPE_XM,		"FastTracker II",			"xmz" },
-	{ MOD_TYPE_IT,		"Impulse Tracker",			"itz" },
-	{ MOD_TYPE_MPT,		"OpenMPT",					"mptmz" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("ProTracker"),              "mdz" },
+	{ MOD_TYPE_MOD,  MPT_ULITERAL("ProTracker"),              "mdr" },
+	{ MOD_TYPE_S3M,  MPT_ULITERAL("ScreamTracker 3"),         "s3z" },
+	{ MOD_TYPE_XM,   MPT_ULITERAL("FastTracker II"),          "xmz" },
+	{ MOD_TYPE_IT,   MPT_ULITERAL("Impulse Tracker"),         "itz" },
+	{ MOD_TYPE_MPT,  MPT_ULITERAL("OpenMPT"),                 "mptmz" },
 #endif
 };
 
 
 struct ModContainerInfo
 {
-	MODCONTAINERTYPE format; // MOD_CONTAINERTYPE_XXXX
-	const char *name;        // "Unreal Music"
-	const char *extension;   // "umx"
+	MODCONTAINERTYPE format;     // MOD_CONTAINERTYPE_XXXX
+	const MPT_UCHAR_TYPE *name;  // "Unreal Music"
+	const char *extension;       // "umx"
 };
 
 // remember to also update libopenmpt/libopenmpt_foobar2000.cpp (all other plugins read these dynamically)
-static const ModContainerInfo modContainerInfo[] =
+static constexpr ModContainerInfo modContainerInfo[] =
 {
 	// Container formats
-	{ MOD_CONTAINERTYPE_GDM,   "General Digital Music",    "gdm"   },
-	{ MOD_CONTAINERTYPE_UMX,   "Unreal Music",             "umx"   },
-#if defined(MPT_ENABLE_MO3)
-	{ MOD_CONTAINERTYPE_MO3,   "Un4seen MO3",              "mo3"   },
-#endif // MPT_ENABLE_MO3
-	{ MOD_CONTAINERTYPE_XPK,   "XPK packed",               "xpk"   },
-	{ MOD_CONTAINERTYPE_PP20,  "PowerPack PP20",           "ppm"   },
-	{ MOD_CONTAINERTYPE_MMCMP, "Music Module Compressor",  "mmcmp" }
+	{ MOD_CONTAINERTYPE_GDM,   MPT_ULITERAL("General Digital Music"),    "gdm"   },
+	{ MOD_CONTAINERTYPE_UMX,   MPT_ULITERAL("Unreal Music"),             "umx"   },
+	{ MOD_CONTAINERTYPE_MO3,   MPT_ULITERAL("Un4seen MO3"),              "mo3"   },
+	{ MOD_CONTAINERTYPE_XPK,   MPT_ULITERAL("XPK packed"),               "xpk"   },
+	{ MOD_CONTAINERTYPE_PP20,  MPT_ULITERAL("PowerPack PP20"),           "ppm"   },
+	{ MOD_CONTAINERTYPE_MMCMP, MPT_ULITERAL("Music Module Compressor"),  "mmcmp" }
+#ifdef MODPLUG_TRACKER
+	,
+	{ MOD_CONTAINERTYPE_WAV,   MPT_ULITERAL("Wave"),                     "wav"   },
+	{ MOD_CONTAINERTYPE_UAX,   MPT_ULITERAL("Unreal Sounds"),            "uax"   }
+#endif
 };
 
 
 #ifdef MODPLUG_TRACKER
-static const ModFormatInfo otherFormatInfo[] =
-{
-	// Other stuff
-	{ MOD_TYPE_WAV,		"Wave",						"wav" }, // PCM as module
-	{ MOD_TYPE_UAX,		"Unreal Sounds",			"uax" }, // sampleset as module
-	{ MOD_TYPE_MID,		"MIDI",						"mid" },
-	{ MOD_TYPE_MID,		"MIDI",						"rmi" },
-	{ MOD_TYPE_MID,		"MIDI",						"smf" },
+static constexpr ModFormatInfo otherFormatInfo[] =
+{
+	{ MOD_TYPE_MID,  MPT_ULITERAL("MIDI"), "mid" },
+	{ MOD_TYPE_MID,  MPT_ULITERAL("MIDI"), "rmi" },
+	{ MOD_TYPE_MID,  MPT_ULITERAL("MIDI"), "smf" }
 };
 #endif
 
@@ -144,16 +146,19 @@ struct ModCharsetInfo
 	mpt::Charset charset;
 };
 
-static const ModCharsetInfo ModCharsetInfos[] =
+static constexpr ModCharsetInfo ModCharsetInfos[] =
 {
 	// Amiga
 	{ MOD_TYPE_OKT , mpt::CharsetISO8859_1  },
 	{ MOD_TYPE_DBM , mpt::CharsetISO8859_1  },
 	{ MOD_TYPE_DIGI, mpt::CharsetISO8859_1  },
 	{ MOD_TYPE_SFX , mpt::CharsetISO8859_1  },
+	{ MOD_TYPE_STP,  mpt::CharsetISO8859_1  },
 	// Amiga // DOS
 	{ MOD_TYPE_MOD , mpt::CharsetISO8859_1  },
 	{ MOD_TYPE_MED , mpt::CharsetISO8859_1  },
+	// Atari
+	{ MOD_TYPE_DTM , mpt::CharsetISO8859_1  },
 	// DOS
 	{ MOD_TYPE_S3M , mpt::CharsetCP437      },
 	{ MOD_TYPE_XM  , mpt::CharsetCP437      },
@@ -179,22 +184,18 @@ static const ModCharsetInfo ModCharsetInfos[] =
 	{ MOD_TYPE_MPT , mpt::CharsetWindows1252},
 	// random stuff
 	{ MOD_TYPE_MID , mpt::CharsetASCII      },
-	{ MOD_TYPE_WAV , mpt::CharsetASCII      },
-	// end
-	{ MOD_TYPE_NONE, mpt::CharsetASCII      }
 };
 
 
-mpt::Charset CSoundFile::GetCharsetFromModType(MODTYPE modtype)
-//-------------------------------------------------------------
+mpt::Charset CSoundFile::GetCharsetFromModType(MODTYPE modType)
 {
 	// This is just a rough heuristic.
 	// It could be improved by adjusting the charset according to the tracker that had been used to save the file.
-	for(const ModCharsetInfo *charsetInfoIt = ModCharsetInfos; charsetInfoIt->type != MOD_TYPE_NONE; ++charsetInfoIt)
+	for(const auto &charsetInfo : ModCharsetInfos)
 	{
-		if(charsetInfoIt->type == modtype)
+		if(charsetInfo.type == modType)
 		{
-			return charsetInfoIt->charset;
+			return charsetInfo.charset;
 		}
 	}
 	// fallback
@@ -203,31 +204,30 @@ mpt::Charset CSoundFile::GetCharsetFromModType(MODTYPE modtype)
 
 
 std::vector<const char *> CSoundFile::GetSupportedExtensions(bool otherFormats)
-//-----------------------------------------------------------------------------
 {
 	std::vector<const char *> exts;
-	for(size_t i = 0; i < CountOf(modFormatInfo); i++)
+	for(const auto &formatInfo : modFormatInfo)
 	{
 		// Avoid dupes in list
-		if(i == 0 || strcmp(modFormatInfo[i].extension, modFormatInfo[i - 1].extension))
+		if(exts.empty() || strcmp(formatInfo.extension, exts.back()))
 		{
-			exts.push_back(modFormatInfo[i].extension);
+			exts.push_back(formatInfo.extension);
 		}
 	}
-	for(size_t i = 0; i < CountOf(modContainerInfo); i++)
+	for(const auto &containerInfo : modContainerInfo)
 	{
 		// Avoid dupes in list
-		if(i == 0 || strcmp(modContainerInfo[i].extension, modContainerInfo[i - 1].extension))
+		if(exts.empty() || strcmp(containerInfo.extension, exts.back()))
 		{
-			exts.push_back(modContainerInfo[i].extension);
+			exts.push_back(containerInfo.extension);
 		}
 	}
 #ifdef MODPLUG_TRACKER
 	if(otherFormats)
 	{
-		for(size_t i = 0; i < CountOf(otherFormatInfo); i++)
+		for(const auto &formatInfo : otherFormatInfo)
 		{
-			exts.push_back(otherFormatInfo[i].extension);
+			exts.push_back(formatInfo.extension);
 		}
 	}
 #else
@@ -237,50 +237,87 @@ std::vector<const char *> CSoundFile::GetSupportedExtensions(bool otherFormats)
 }
 
 
-const char * CSoundFile::ModTypeToString(MODTYPE modtype)
-//-------------------------------------------------------
+static bool IsEqualExtension(const char *a, const char *b)
+{
+	std::size_t lena = std::strlen(a);
+	std::size_t lenb = std::strlen(b);
+	if(lena != lenb)
+	{
+		return false;
+	}
+	return mpt::CompareNoCaseAscii(a, b, lena) == 0;
+}
+
+
+bool CSoundFile::IsExtensionSupported(const char *ext)
 {
-	for(size_t i = 0; i < CountOf(modFormatInfo); i++)
+	if(ext == nullptr || ext[0] == 0)
+	{
+		return false;
+	}
+	for(const auto &formatInfo : modFormatInfo)
+	{
+		if(IsEqualExtension(ext, formatInfo.extension))
+		{
+			return true;
+		}
+	}
+	for(const auto &containerInfo : modContainerInfo)
 	{
-		if(modFormatInfo[i].format & modtype)
+		if(IsEqualExtension(ext, containerInfo.extension))
 		{
-			return modFormatInfo[i].extension;
+			return true;
 		}
 	}
-	return "";
+	return false;
 }
 
 
-std::string CSoundFile::ModContainerTypeToString(MODCONTAINERTYPE containertype)
-//------------------------------------------------------------------------------
+mpt::ustring CSoundFile::ModTypeToString(MODTYPE modtype)
 {
-	for(size_t i = 0; i < CountOf(modContainerInfo); i++)
+	for(const auto &formatInfo : modFormatInfo)
 	{
-		if(modContainerInfo[i].format == containertype)
+		if(formatInfo.format & modtype)
 		{
-			return modContainerInfo[i].extension;
+			return mpt::ToUnicode(mpt::CharsetUTF8, formatInfo.extension);
 		}
 	}
-	return "";
+	return mpt::ustring();
 }
 
 
-std::string CSoundFile::ModTypeToTracker(MODTYPE modtype)
-//-------------------------------------------------------
+mpt::ustring CSoundFile::ModContainerTypeToString(MODCONTAINERTYPE containertype)
 {
-	std::set<std::string> retvals;
-	std::string retval;
-	for(size_t i = 0; i < CountOf(modFormatInfo); i++)
+	for(const auto &containerInfo : modContainerInfo)
 	{
-		if(modFormatInfo[i].format & modtype)
+		if(containerInfo.format == containertype)
 		{
-			std::string name = modFormatInfo[i].name;
+			return mpt::ToUnicode(mpt::CharsetUTF8, containerInfo.extension);
+		}
+	}
+	return mpt::ustring();
+}
+
+
+mpt::ustring CSoundFile::ModTypeToTracker(MODTYPE modtype)
+{
+	std::set<mpt::ustring> retvals;
+	mpt::ustring retval;
+	if(modtype == MOD_TYPE_MOD)
+	{ // special case MOD
+		return MPT_USTRING("Generic Amiga / PC MOD file");
+	}
+	for(const auto &formatInfo : modFormatInfo)
+	{
+		if(formatInfo.format & modtype)
+		{
+			mpt::ustring name = formatInfo.name;
 			if(retvals.find(name) == retvals.end())
 			{
 				retvals.insert(name);
 				if(!retval.empty())
 				{
-					retval += " / ";
+					retval += MPT_USTRING(" / ");
 				}
 				retval += name;
 			}
@@ -290,22 +327,21 @@ std::string CSoundFile::ModTypeToTracker(MODTYPE modtype)
 }
 
 
-std::string CSoundFile::ModContainerTypeToTracker(MODCONTAINERTYPE containertype)
-//-------------------------------------------------------------------------------
+mpt::ustring CSoundFile::ModContainerTypeToTracker(MODCONTAINERTYPE containertype)
 {
-	std::set<std::string> retvals;
-	std::string retval;
-	for(size_t i = 0; i < CountOf(modContainerInfo); i++)
+	std::set<mpt::ustring> retvals;
+	mpt::ustring retval;
+	for(const auto &containerInfo : modContainerInfo)
 	{
-		if(modContainerInfo[i].format == containertype)
+		if(containerInfo.format == containertype)
 		{
-			std::string name = modContainerInfo[i].name;
+			mpt::ustring name = containerInfo.name;
 			if(retvals.find(name) == retvals.end())
 			{
 				retvals.insert(name);
 				if(!retval.empty())
 				{
-					retval += " / ";
+					retval += MPT_USTRING(" / ");
 				}
 				retval += name;
 			}
@@ -580,7 +616,7 @@ const uint32 FineLinearSlideUpTable[16] =
 // round(65536 * 2**(-n/768))
 // 768 = 64 extra-fine finetune steps for 12 notes
 // Table content is in 16.16 format
-// Note that there are a few errors in this table (typos?), but well, this table comes straight from ITTECH.TXT...
+// Note that there are a few errors in this table (typos?), but well, this table comes straight from Impulse Tracker's source...
 // Entry 0 (65535) should be 65536 (this value is unused and most likely stored this way so that it fits in a 16-bit integer)
 // Entry 11 (64888) should be 64889 - rounding error?
 // Entry 15 (64645) should be 64655 - typo?
@@ -591,122 +627,83 @@ const uint32 FineLinearSlideDownTable[16] =
 };
 
 
-// floor(65536 * 2**(n/192))
+// round(65536 * 2**(n/192))
 // 192 = 16 finetune steps for 12 notes
 // Table content is in 16.16 format
 const uint32 LinearSlideUpTable[256] =
 {
-	65536, 65773, 66010, 66249, 66489, 66729, 66971, 67213,
-	67456, 67700, 67945, 68190, 68437, 68685, 68933, 69182,
-	69432, 69684, 69936, 70189, 70442, 70697, 70953, 71209,
-	71467, 71725, 71985, 72245, 72507, 72769, 73032, 73296,
-	73561, 73827, 74094, 74362, 74631, 74901, 75172, 75444,
-	75717, 75991, 76265, 76541, 76818, 77096, 77375, 77655,
-	77935, 78217, 78500, 78784, 79069, 79355, 79642, 79930,
-	80219, 80509, 80800, 81093, 81386, 81680, 81976, 82272,
-	82570, 82868, 83168, 83469, 83771, 84074, 84378, 84683,
-	84989, 85297, 85605, 85915, 86225, 86537, 86850, 87164,
-	87480, 87796, 88113, 88432, 88752, 89073, 89395, 89718,
-	90043, 90369, 90695, 91023, 91353, 91683, 92015, 92347,
-	92681, 93017, 93353, 93691, 94029, 94370, 94711, 95053,
-	95397, 95742, 96088, 96436, 96785, 97135, 97486, 97839,
-	98193, 98548, 98904, 99262, 99621, 99981, 100343, 100706,
-	101070, 101435, 101802, 102170, 102540, 102911, 103283, 103657,
-	104031, 104408, 104785, 105164, 105545, 105926, 106309, 106694,
-	107080, 107467, 107856, 108246, 108637, 109030, 109425, 109820,
-	110217, 110616, 111016, 111418, 111821, 112225, 112631, 113038,
-	113447, 113857, 114269, 114682, 115097, 115514, 115931, 116351,
-	116771, 117194, 117618, 118043, 118470, 118898, 119328, 119760,
-	120193, 120628, 121064, 121502, 121941, 122382, 122825, 123269,
-	123715, 124162, 124611, 125062, 125514, 125968, 126424, 126881,
-	127340, 127801, 128263, 128727, 129192, 129660, 130129, 130599,
-	131072, 131546, 132021, 132499, 132978, 133459, 133942, 134426,
-	134912, 135400, 135890, 136381, 136875, 137370, 137866, 138365,
-	138865, 139368, 139872, 140378, 140885, 141395, 141906, 142419,
-	142935, 143451, 143970, 144491, 145014, 145538, 146064, 146593,
-	147123, 147655, 148189, 148725, 149263, 149803, 150344, 150888,
-	151434, 151982, 152531, 153083, 153637, 154192, 154750, 155310,
-	155871, 156435, 157001, 157569, 158138, 158710, 159284, 159860,
-	160439, 161019, 161601, 162186, 162772, 163361, 163952, 164545,
+	65536, 65773, 66011, 66250, 66489, 66730, 66971, 67213,
+	67456, 67700, 67945, 68191, 68438, 68685, 68933, 69183,
+	69433, 69684, 69936, 70189, 70443, 70698, 70953, 71210,
+	71468, 71726, 71985, 72246, 72507, 72769, 73032, 73297,
+	73562, 73828, 74095, 74363, 74632, 74902, 75172, 75444,
+	75717, 75991, 76266, 76542, 76819, 77096, 77375, 77655,
+	77936, 78218, 78501, 78785, 79069, 79355, 79642, 79930,
+	80220, 80510, 80801, 81093, 81386, 81681, 81976, 82273,
+	82570, 82869, 83169, 83469, 83771, 84074, 84378, 84683,
+	84990, 85297, 85606, 85915, 86226, 86538, 86851, 87165,
+	87480, 87796, 88114, 88433, 88752, 89073, 89396, 89719,
+	90043, 90369, 90696, 91024, 91353, 91684, 92015, 92348,
+	92682, 93017, 93354, 93691, 94030, 94370, 94711, 95054,
+	95398, 95743, 96089, 96436, 96785, 97135, 97487, 97839,
+	98193, 98548, 98905, 99262, 99621, 99982, 100343, 100706,
+	101070, 101436, 101803, 102171, 102540, 102911, 103283, 103657,
+	104032, 104408, 104786, 105165, 105545, 105927, 106310, 106694,
+	107080, 107468, 107856, 108246, 108638, 109031, 109425, 109821,
+	110218, 110617, 111017, 111418, 111821, 112226, 112631, 113039,
+	113448, 113858, 114270, 114683, 115098, 115514, 115932, 116351,
+	116772, 117194, 117618, 118043, 118470, 118899, 119329, 119760,
+	120194, 120628, 121065, 121502, 121942, 122383, 122825, 123270,
+	123715, 124163, 124612, 125063, 125515, 125969, 126425, 126882,
+	127341, 127801, 128263, 128727, 129193, 129660, 130129, 130600,
+	131072, 131546, 132022, 132499, 132978, 133459, 133942, 134427,
+	134913, 135401, 135890, 136382, 136875, 137370, 137867, 138366,
+	138866, 139368, 139872, 140378, 140886, 141395, 141907, 142420,
+	142935, 143452, 143971, 144491, 145014, 145539, 146065, 146593,
+	147123, 147655, 148189, 148725, 149263, 149803, 150345, 150889,
+	151434, 151982, 152532, 153083, 153637, 154193, 154750, 155310,
+	155872, 156435, 157001, 157569, 158139, 158711, 159285, 159861,
+	160439, 161019, 161602, 162186, 162773, 163361, 163952, 164545
 };
 
 
-// floor(65536 * 2**(-n/192))
+// round(65536 * 2**(-n/192))
 // 192 = 16 finetune steps for 12 notes
 // Table content is in 16.16 format
 const uint32 LinearSlideDownTable[256] =
 {
-	65536, 65299, 65064, 64830, 64596, 64363, 64131, 63900,
-	63670, 63440, 63212, 62984, 62757, 62531, 62305, 62081,
-	61857, 61634, 61412, 61191, 60970, 60751, 60532, 60314,
-	60096, 59880, 59664, 59449, 59235, 59021, 58809, 58597,
-	58385, 58175, 57965, 57757, 57548, 57341, 57134, 56928,
-	56723, 56519, 56315, 56112, 55910, 55709, 55508, 55308,
-	55108, 54910, 54712, 54515, 54318, 54123, 53928, 53733,
-	53540, 53347, 53154, 52963, 52772, 52582, 52392, 52204,
-	52015, 51828, 51641, 51455, 51270, 51085, 50901, 50717,
-	50535, 50353, 50171, 49990, 49810, 49631, 49452, 49274,
-	49096, 48919, 48743, 48567, 48392, 48218, 48044, 47871,
-	47698, 47526, 47355, 47185, 47014, 46845, 46676, 46508,
-	46340, 46173, 46007, 45841, 45676, 45511, 45347, 45184,
-	45021, 44859, 44697, 44536, 44376, 44216, 44056, 43898,
-	43740, 43582, 43425, 43268, 43112, 42957, 42802, 42648,
-	42494, 42341, 42189, 42037, 41885, 41734, 41584, 41434,
-	41285, 41136, 40988, 40840, 40693, 40546, 40400, 40254,
-	40109, 39965, 39821, 39677, 39534, 39392, 39250, 39108,
-	38967, 38827, 38687, 38548, 38409, 38270, 38132, 37995,
-	37858, 37722, 37586, 37450, 37315, 37181, 37047, 36913,
-	36780, 36648, 36516, 36384, 36253, 36122, 35992, 35862,
-	35733, 35604, 35476, 35348, 35221, 35094, 34968, 34842,
-	34716, 34591, 34466, 34342, 34218, 34095, 33972, 33850,
-	33728, 33606, 33485, 33364, 33244, 33124, 33005, 32886,
-	32768, 32649, 32532, 32415, 32298, 32181, 32065, 31950,
-	31835, 31720, 31606, 31492, 31378, 31265, 31152, 31040,
-	30928, 30817, 30706, 30595, 30485, 30375, 30266, 30157,
-	30048, 29940, 29832, 29724, 29617, 29510, 29404, 29298,
-	29192, 29087, 28982, 28878, 28774, 28670, 28567, 28464,
-	28361, 28259, 28157, 28056, 27955, 27854, 27754, 27654,
-	27554, 27455, 27356, 27257, 27159, 27061, 26964, 26866,
-	26770, 26673, 26577, 26481, 26386, 26291, 26196, 26102,
-};
-
-
-// LUT for 2 * damping factor
-// pow(10, -n * (24 / 128) / 20) for n=0...127
-const float ITResonanceTable[128] =
-{
-	1.0000000000000000f, 0.9786446094512940f, 0.9577452540397644f, 0.9372922182083130f,
-	0.9172759056091309f, 0.8976871371269226f, 0.8785166740417481f, 0.8597555756568909f,
-	0.8413951396942139f, 0.8234267830848694f, 0.8058421611785889f, 0.7886331081390381f,
-	0.7717915177345276f, 0.7553095817565918f, 0.7391796708106995f, 0.7233941555023193f,
-	0.7079457640647888f, 0.6928272843360901f, 0.6780316829681397f, 0.6635520458221436f,
-	0.6493816375732422f, 0.6355138421058655f, 0.6219421625137329f, 0.6086603403091431f,
-	0.5956621170043945f, 0.5829415321350098f, 0.5704925656318665f, 0.5583094954490662f,
-	0.5463865399360657f, 0.5347182154655457f, 0.5232990980148315f, 0.5121238231658936f,
-	0.5011872053146362f, 0.4904841780662537f, 0.4800096750259399f, 0.4697588682174683f,
-	0.4597269892692566f, 0.4499093294143677f, 0.4403013288974762f, 0.4308985173702240f,
-	0.4216965138912201f, 0.4126909971237183f, 0.4038778245449066f, 0.3952528536319733f,
-	0.3868120610713959f, 0.3785515129566193f, 0.3704673945903778f, 0.3625559210777283f,
-	0.3548133969306946f, 0.3472362160682678f, 0.3398208320140839f, 0.3325638175010681f,
-	0.3254617750644684f, 0.3185114264488220f, 0.3117094635963440f, 0.3050527870655060f,
-	0.2985382676124573f, 0.2921628654003143f, 0.2859236001968384f, 0.2798175811767578f,
-	0.2738419771194458f, 0.2679939568042755f, 0.2622708380222321f, 0.2566699385643005f,
-	0.2511886358261108f, 0.2458244115114212f, 0.2405747324228287f, 0.2354371547698975f,
-	0.2304092943668366f, 0.2254888117313385f, 0.2206734120845795f, 0.2159608304500580f,
-	0.2113489061594009f, 0.2068354636430740f, 0.2024184018373489f, 0.1980956792831421f,
-	0.1938652694225311f, 0.1897251904010773f, 0.1856735348701477f, 0.1817083954811096f,
-	0.1778279393911362f, 0.1740303486585617f, 0.1703138649463654f, 0.1666767448186874f,
-	0.1631172895431519f, 0.1596338599920273f, 0.1562248021364212f, 0.1528885662555695f,
-	0.1496235728263855f, 0.1464282870292664f, 0.1433012634515762f, 0.1402409970760346f,
-	0.1372461020946503f, 0.1343151479959488f, 0.1314467936754227f, 0.1286396980285645f,
-	0.1258925348520279f, 0.1232040524482727f, 0.1205729842185974f, 0.1179980933666229f,
-	0.1154781952500343f, 0.1130121126770973f, 0.1105986908078194f, 0.1082368120551109f,
-	0.1059253737330437f, 0.1036632955074310f, 0.1014495193958283f, 0.0992830246686935f,
-	0.0971627980470657f, 0.0950878411531448f, 0.0930572077631950f, 0.0910699293017387f,
-	0.0891250967979431f, 0.0872217938303947f, 0.0853591337800026f, 0.0835362523794174f,
-	0.0817523002624512f, 0.0800064504146576f, 0.0782978758215904f, 0.0766257941722870f,
-	0.0749894231557846f, 0.0733879879117012f, 0.0718207582831383f, 0.0702869966626167f,
-	0.0687859877943993f, 0.0673170387744904f, 0.0658794566988945f, 0.0644725710153580f,
+	65536, 65300, 65065, 64830, 64596, 64364, 64132, 63901,
+	63670, 63441, 63212, 62984, 62757, 62531, 62306, 62081,
+	61858, 61635, 61413, 61191, 60971, 60751, 60532, 60314,
+	60097, 59880, 59664, 59449, 59235, 59022, 58809, 58597,
+	58386, 58176, 57966, 57757, 57549, 57341, 57135, 56929,
+	56724, 56519, 56316, 56113, 55911, 55709, 55508, 55308,
+	55109, 54910, 54713, 54515, 54319, 54123, 53928, 53734,
+	53540, 53347, 53155, 52963, 52773, 52582, 52393, 52204,
+	52016, 51829, 51642, 51456, 51270, 51085, 50901, 50718,
+	50535, 50353, 50172, 49991, 49811, 49631, 49452, 49274,
+	49097, 48920, 48743, 48568, 48393, 48218, 48044, 47871,
+	47699, 47527, 47356, 47185, 47015, 46846, 46677, 46509,
+	46341, 46174, 46008, 45842, 45677, 45512, 45348, 45185,
+	45022, 44859, 44698, 44537, 44376, 44216, 44057, 43898,
+	43740, 43582, 43425, 43269, 43113, 42958, 42803, 42649,
+	42495, 42342, 42189, 42037, 41886, 41735, 41584, 41434,
+	41285, 41136, 40988, 40840, 40693, 40547, 40400, 40255,
+	40110, 39965, 39821, 39678, 39535, 39392, 39250, 39109,
+	38968, 38828, 38688, 38548, 38409, 38271, 38133, 37996,
+	37859, 37722, 37586, 37451, 37316, 37181, 37047, 36914,
+	36781, 36648, 36516, 36385, 36254, 36123, 35993, 35863,
+	35734, 35605, 35477, 35349, 35221, 35095, 34968, 34842,
+	34716, 34591, 34467, 34343, 34219, 34095, 33973, 33850,
+	33728, 33607, 33486, 33365, 33245, 33125, 33005, 32887,
+	32768, 32650, 32532, 32415, 32298, 32182, 32066, 31950,
+	31835, 31720, 31606, 31492, 31379, 31266, 31153, 31041,
+	30929, 30817, 30706, 30596, 30485, 30376, 30266, 30157,
+	30048, 29940, 29832, 29725, 29618, 29511, 29405, 29299,
+	29193, 29088, 28983, 28879, 28774, 28671, 28567, 28464,
+	28362, 28260, 28158, 28056, 27955, 27855, 27754, 27654,
+	27554, 27455, 27356, 27258, 27159, 27062, 26964, 26867,
+	26770, 26674, 26577, 26482, 26386, 26291, 26196, 26102
 };
 
 
@@ -901,7 +898,6 @@ SINC_TYPE CResampler::gDownsample13x[SINC_PHASES*8];	// Downsample 1.333x
 SINC_TYPE CResampler::gDownsample2x[SINC_PHASES*8];		// Downsample 2x
 #ifndef MPT_INTMIXER
 mixsample_t CResampler::FastSincTablef[256 * 4];		// Cubic spline LUT
-mixsample_t CResampler::LinearTablef[256];				// Linear interpolation LUT
 #endif // !defined(MPT_INTMIXER)
 #endif // MODPLUG_TRACKER
 
@@ -913,19 +909,13 @@ void CResampler::InitFloatmixerTables()
 	// when fuzzing OpenMPT for crashes and hangs. This content of the tables is not really
 	// relevant for any kind of possible crashes or hangs.
 	return;
-#endif
+#endif // MPT_BUILD_FUZZER
 #ifndef MPT_INTMIXER
 	// Prepare fast sinc coefficients for floating point mixer
 	for(size_t i = 0; i < CountOf(FastSincTable); i++)
 	{
 		FastSincTablef[i] = static_cast<mixsample_t>(FastSincTable[i] * mixsample_t(1.0f / 16384.0f));
 	}
-
-	// Prepare linear interpolation coefficients for floating point mixer
-	for(size_t i = 0; i < CountOf(LinearTablef); i++)
-	{
-		LinearTablef[i] = static_cast<mixsample_t>(i * mixsample_t(1.0f / CountOf(LinearTablef)));
-	}
 #endif // !defined(MPT_INTMIXER)
 }
 
diff --git a/soundlib/Tables.h b/soundlib/Tables.h
index 3ba7717..a9803c7 100644
--- a/soundlib/Tables.h
+++ b/soundlib/Tables.h
@@ -34,7 +34,6 @@ extern const uint32 FineLinearSlideUpTable[16];
 extern const uint32 FineLinearSlideDownTable[16];
 extern const uint32 LinearSlideUpTable[256];
 extern const uint32 LinearSlideDownTable[256];
-extern const float ITResonanceTable[128];
 extern const uint16 XMPanningTable[256];
 
 extern const uint8 AutoVibratoIT2XM[8];
diff --git a/soundlib/Tagging.cpp b/soundlib/Tagging.cpp
index 0d6b674..e8db921 100644
--- a/soundlib/Tagging.cpp
+++ b/soundlib/Tagging.cpp
@@ -16,10 +16,23 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 FileTags::FileTags()
-//------------------
 {
 	encoder = mpt::ToUnicode(mpt::CharsetASCII, MptVersion::GetOpenMPTVersionStr());
 }
 
 
+mpt::ustring GetSampleNameFromTags(const FileTags &tags)
+{
+	mpt::ustring result;
+	if(tags.artist.empty())
+	{
+		result = tags.title;
+	} else
+	{
+		result = mpt::format(MPT_USTRING("%1 (by %2)"))(tags.title, tags.artist);
+	}
+	return result;
+}
+
+
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/Tagging.h b/soundlib/Tagging.h
index 7a91882..b31f716 100644
--- a/soundlib/Tagging.h
+++ b/soundlib/Tagging.h
@@ -15,9 +15,7 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-//=============
 struct FileTags
-//=============
 {
 
 	mpt::ustring encoder;
@@ -40,4 +38,7 @@ struct FileTags
 };
 
 
+mpt::ustring GetSampleNameFromTags(const FileTags &tags);
+
+
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/UMXTools.cpp b/soundlib/UMXTools.cpp
new file mode 100644
index 0000000..5bf021d
--- /dev/null
+++ b/soundlib/UMXTools.cpp
@@ -0,0 +1,213 @@
+/*
+* UMXTools.h
+* ------------
+* Purpose: UMX/UAX (Unreal) helper functions
+* Notes  : None.
+* Authors: Johannes Schultz (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format)
+* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+*/
+
+
+#include "stdafx.h"
+#include "Loaders.h"
+#include "UMXTools.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+// Read compressed unreal integers - similar to MIDI integers, but signed values are possible.
+template <typename Tfile>
+static int32 ReadUMXIndexImpl(Tfile &chunk)
+{
+	enum
+	{
+		signMask		= 0x80,	// Highest bit of first byte indicates if value is signed
+		valueMask1		= 0x3F,	// Low 6 bits of first byte are actual value
+		continueMask1	= 0x40,	// Second-highest bit of first byte indicates if further bytes follow
+		valueMask		= 0x7F,	// Low 7 bits of following bytes are actual value
+		continueMask	= 0x80,	// Highest bit of following bytes indicates if further bytes follow
+	};
+
+	// Read first byte
+	uint8 b = chunk.ReadUint8();
+	bool isSigned = (b & signMask) != 0;
+	int32 result = (b & valueMask1);
+	int shift = 6;
+
+	if(b & continueMask1)
+	{
+		// Read remaining bytes
+		do
+		{
+			b = chunk.ReadUint8();
+			int32 data = static_cast<int32>(b) & valueMask;
+			data <<= shift;
+			result |= data;
+			shift += 7;
+		} while((b & continueMask) != 0 && (shift < 32));
+	}
+
+	if(isSigned)
+	{
+		result = -result;
+	}
+	return result;
+}
+
+int32 ReadUMXIndex(FileReader &chunk)
+{
+	return ReadUMXIndexImpl(chunk);
+}
+
+
+// Returns true if the given nme exists in the name table.
+template <typename TFile>
+static bool FindUMXNameTableEntryImpl(TFile &file, const UMXFileHeader &fileHeader, const char *name)
+{
+	if(!name)
+	{
+		return false;
+	}
+	std::size_t name_len = std::strlen(name);
+	if(name_len == 0)
+	{
+		return false;
+	}
+	bool result = false;
+	const FileReader::off_t oldpos = file.GetPosition();
+	if(file.Seek(fileHeader.nameOffset))
+	{
+		for(uint32 i = 0; i < fileHeader.nameCount && file.CanRead(4); i++)
+		{
+			if(fileHeader.packageVersion >= 64)
+			{
+				int32 length = ReadUMXIndexImpl(file);
+				if(length <= 0)
+				{
+					continue;
+				}
+			}
+			bool match = true;
+			std::size_t pos = 0;
+			char c = 0;
+			while((c = file.ReadUint8()) != 0)
+			{
+				c = mpt::ToLowerCaseAscii(c);
+				if(pos < name_len)
+				{
+					match = match && (c == name[pos]);
+				}
+				pos++;
+			}
+			if(pos != name_len)
+			{
+				match = false;
+			}
+			if(match)
+			{
+				result = true;
+			}
+			file.Skip(4);  // Object flags
+		}
+	}
+	file.Seek(oldpos);
+	return result;
+}
+
+bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
+{
+	return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name)
+{
+	return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+
+
+// Read an entry from the name table.
+std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion)
+{
+	std::string name;
+	if(packageVersion >= 64)
+	{
+		// String length
+		int32 length = ReadUMXIndex(chunk);
+		if(length <= 0)
+		{
+			return "";
+		}
+		name.reserve(length);
+	}
+
+	// Simple zero-terminated string
+	uint8 chr;
+	while((chr = chunk.ReadUint8()) != 0)
+	{
+		// Convert string to lower case
+		if(chr >= 'A' && chr <= 'Z')
+		{
+			chr = chr - 'A' + 'a';
+		}
+		name.append(1, static_cast<char>(chr));
+	}
+
+	chunk.Skip(4);	// Object flags
+	return name;
+}
+
+
+// Read complete name table.
+std::vector<std::string> ReadUMXNameTable(FileReader &file, const UMXFileHeader &fileHeader)
+{
+	std::vector<std::string> names;
+	if(!file.Seek(fileHeader.nameOffset))
+	{
+		return names;
+	}
+	names.reserve(fileHeader.nameCount);
+	for(uint32 i = 0; i < fileHeader.nameCount && file.CanRead(4); i++)
+	{
+		names.push_back(ReadUMXNameTableEntry(file, fileHeader.packageVersion));
+	}
+	return names;
+}
+
+
+// Read an entry from the import table.
+int32 ReadUMXImportTableEntry(FileReader &chunk, uint16 packageVersion)
+{
+	ReadUMXIndex(chunk);		// Class package
+	ReadUMXIndex(chunk);		// Class name
+	if(packageVersion >= 60)
+	{
+		chunk.Skip(4); // Package
+	} else
+	{
+		ReadUMXIndex(chunk); // ??
+	}
+	return ReadUMXIndex(chunk);	// Object name (offset into the name table)
+}
+
+
+// Read an entry from the export table.
+void ReadUMXExportTableEntry(FileReader &chunk, int32 &objClass, int32 &objOffset, int32 &objSize, int32 &objName, uint16 packageVersion)
+{
+	objClass = ReadUMXIndex(chunk);	// Object class
+	ReadUMXIndex(chunk);			// Object parent
+	if(packageVersion >= 60)
+	{
+		chunk.Skip(4);				// Internal package / group of the object
+	}
+	objName = ReadUMXIndex(chunk);	// Object name (offset into the name table)
+	chunk.Skip(4);					// Object flags
+	objSize = ReadUMXIndex(chunk);
+	if(objSize > 0)
+	{
+		objOffset = ReadUMXIndex(chunk);
+	}
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/UMXTools.h b/soundlib/UMXTools.h
new file mode 100644
index 0000000..856d266
--- /dev/null
+++ b/soundlib/UMXTools.h
@@ -0,0 +1,57 @@
+/*
+ * UMXTools.h
+ * ------------
+ * Purpose: UMX/UAX (Unreal) helper functions
+ * Notes  : None.
+ * Authors: Johannes Schultz (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format)
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+// UMX File Header
+struct UMXFileHeader
+{
+	char     magic[4];	// C1 83 2A 9E
+	uint16le packageVersion;
+	uint16le licenseMode;
+	uint32le flags;
+	uint32le nameCount;
+	uint32le nameOffset;
+	uint32le exportCount;
+	uint32le exportOffset;
+	uint32le importCount;
+	uint32le importOffset;
+};
+
+MPT_BINARY_STRUCT(UMXFileHeader, 36)
+
+
+// Read compressed unreal integers - similar to MIDI integers, but signed values are possible.
+int32 ReadUMXIndex(FileReader &chunk);
+
+// Returns true if the given nme exists in the name table.
+bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name);
+
+// Returns true if the given nme exists in the name table.
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name);
+
+// Read an entry from the name table.
+std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion);
+
+// Read complete name table.
+std::vector<std::string> ReadUMXNameTable(FileReader &file, const UMXFileHeader &fileHeader);
+
+// Read an entry from the import table.
+int32 ReadUMXImportTableEntry(FileReader &chunk, uint16 packageVersion);
+
+// Read an entry from the export table.
+void ReadUMXExportTableEntry(FileReader &chunk, int32 &objClass, int32 &objOffset, int32 &objSize, int32 &objName, uint16 packageVersion);
+
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/UpgradeModule.cpp b/soundlib/UpgradeModule.cpp
index b3bd4c4..ddeef2a 100644
--- a/soundlib/UpgradeModule.cpp
+++ b/soundlib/UpgradeModule.cpp
@@ -18,7 +18,6 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 struct UpgradePatternData
-//=======================
 {
 	UpgradePatternData(CSoundFile &sf)
 		: sndFile(sf)
@@ -38,21 +37,23 @@ struct UpgradePatternData
 		{
 			return;
 		}
+		const auto version = sndFile.m_dwLastSavedWithVersion;
+		const auto modType = sndFile.GetType();
 
-		if(sndFile.GetType() == MOD_TYPE_S3M)
+		if(modType == MOD_TYPE_S3M)
 		{
 			// Out-of-range global volume commands should be ignored in S3M. Fixed in OpenMPT 1.19 (r831).
 			// So for tracks made with older versions of OpenMPT, we limit invalid global volume commands.
-			if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 19, 00, 00) && m.command == CMD_GLOBALVOLUME)
+			if(version < MAKE_VERSION_NUMERIC(1, 19, 00, 00) && m.command == CMD_GLOBALVOLUME)
 			{
 				LimitMax(m.param, ModCommand::PARAM(64));
 			}
 		}
 
-		else if((sndFile.GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))
+		else if(modType & (MOD_TYPE_IT | MOD_TYPE_MPT))
 		{
-			if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 03, 02) ||
-				(!compatPlay && sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
+			if(version < MAKE_VERSION_NUMERIC(1, 17, 03, 02) ||
+				(!compatPlay && version < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
 			{
 				if(m.command == CMD_GLOBALVOLUME)
 				{
@@ -80,14 +81,14 @@ struct UpgradePatternData
 			// In the IT format, slide commands with both nibbles set should be ignored.
 			// For note volume slides, OpenMPT 1.18 fixes this in compatible mode, OpenMPT 1.20 fixes this in normal mode as well.
 			const bool noteVolSlide =
-				(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 18, 00, 00) ||
-				(!compatPlay && sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
+				(version < MAKE_VERSION_NUMERIC(1, 18, 00, 00) ||
+				(!compatPlay && version < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
 				&&
 				(m.command == CMD_VOLUMESLIDE || m.command == CMD_VIBRATOVOL || m.command == CMD_TONEPORTAVOL || m.command == CMD_PANNINGSLIDE);
 
 			// OpenMPT 1.20 also fixes this for global volume and channel volume slides.
 			const bool chanVolSlide =
-				(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
+				(version < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
 				&&
 				(m.command == CMD_GLOBALVOLSLIDE || m.command == CMD_CHANNELVOLSLIDE);
 
@@ -99,8 +100,8 @@ struct UpgradePatternData
 				}
 			}
 
-			if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 01, 04)
-				&& sndFile.m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 22, 00, 00))	// Ignore compatibility export
+			if(version < MAKE_VERSION_NUMERIC(1, 22, 01, 04)
+				&& version != MAKE_VERSION_NUMERIC(1, 22, 00, 00))	// Ignore compatibility export
 			{
 				// OpenMPT 1.22.01.04 fixes illegal (out of range) instrument numbers; they should do nothing. In previous versions, they stopped the playing sample.
 				if(sndFile.GetNumInstruments() && m.instr > sndFile.GetNumInstruments() && !compatPlay)
@@ -111,20 +112,20 @@ struct UpgradePatternData
 			}
 		}
 
-		else if(sndFile.GetType() == MOD_TYPE_XM)
+		else if(modType == MOD_TYPE_XM)
 		{
 			// Something made be believe that out-of-range global volume commands are ignored in XM
 			// just like they are ignored in IT, but apparently they are not. Aaaaaargh!
-			if(((sndFile.m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 17, 03, 02) && compatPlay) || (sndFile.m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
-				&& sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 24, 02, 02)
+			if(((version >= MAKE_VERSION_NUMERIC(1, 17, 03, 02) && compatPlay) || (version >= MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
+				&& version < MAKE_VERSION_NUMERIC(1, 24, 02, 02)
 				&& m.command == CMD_GLOBALVOLUME
 				&& m.param > 64)
 			{
 				m.command = CMD_NONE;
 			}
 
-			if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 19, 00, 00)
-				|| (!compatPlay && sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
+			if(version < MAKE_VERSION_NUMERIC(1, 19, 00, 00)
+				|| (!compatPlay && version < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
 			{
 				if(m.command == CMD_OFFSET && m.volcmd == VOLCMD_TONEPORTAMENTO)
 				{
@@ -134,7 +135,7 @@ struct UpgradePatternData
 				}
 			}
 
-			if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 01, 10)
+			if(version < MAKE_VERSION_NUMERIC(1, 20, 01, 10)
 				&& m.volcmd == VOLCMD_TONEPORTAMENTO && m.command == CMD_TONEPORTAMENTO
 				&& (m.vol != 0 || compatPlay) && m.param != 0)
 			{
@@ -145,7 +146,7 @@ struct UpgradePatternData
 				m.param = mpt::saturate_cast<ModCommand::PARAM>(param);
 			}
 
-			if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 07, 09)
+			if(version < MAKE_VERSION_NUMERIC(1, 22, 07, 09)
 				&& m.command == CMD_SPEED && m.param == 0)
 			{
 				// OpenMPT can emulate FT2's F00 behaviour now.
@@ -153,7 +154,7 @@ struct UpgradePatternData
 			}
 		}
 
-		if(sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
+		if(version < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
 		{
 			// Pattern Delay fixes
 
@@ -161,7 +162,7 @@ struct UpgradePatternData
 			// We also fix X6x commands in hacked XM files, since they are treated identically to the S6x command in IT/S3M files.
 			// We don't treat them in files made with OpenMPT 1.18+ that have compatible play enabled, though, since they are ignored there anyway.
 			const bool fixX6x = (m.command == CMD_XFINEPORTAUPDOWN && (m.param & 0xF0) == 0x60
-				&& (!(compatPlay && sndFile.GetType() == MOD_TYPE_XM) || sndFile.m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 18, 00, 00)));
+				&& (!(compatPlay && modType == MOD_TYPE_XM) || version < MAKE_VERSION_NUMERIC(1, 18, 00, 00)));
 
 			if(fixS6x || fixX6x)
 			{
@@ -191,8 +192,27 @@ struct UpgradePatternData
 			}
 		}
 
+		if(m.volcmd == VOLCMD_VIBRATODEPTH
+			&& version < MAKE_VERSION_NUMERIC(1, 27, 00, 37)
+			&& version != MAKE_VERSION_NUMERIC(1, 27, 00, 00))
+		{
+			// Fix handling of double vibrato commands - previously only one of them was applied at a time
+			if(m.command == CMD_VIBRATOVOL && m.vol > 0)
+			{
+				m.command = CMD_VOLUMESLIDE;
+			} else if((m.command == CMD_VIBRATO || m.command == CMD_FINEVIBRATO) && (m.param & 0x0F) == 0)
+			{
+				m.command = CMD_VIBRATO;
+				m.param |= (m.vol & 0x0F);
+				m.volcmd = VOLCMD_NONE;
+			} else if(m.command == CMD_VIBRATO || m.command == CMD_VIBRATOVOL || m.command == CMD_FINEVIBRATO)
+			{
+				m.volcmd = VOLCMD_NONE;
+			}
+		}
+
 		// Volume column offset in IT/XM is bad, mkay?
-		if(sndFile.GetType() != MOD_TYPE_MPT && m.volcmd == VOLCMD_OFFSET && m.command == CMD_NONE)
+		if(modType != MOD_TYPE_MPT && m.volcmd == VOLCMD_OFFSET && m.command == CMD_NONE)
 		{
 			m.command = CMD_OFFSET;
 			m.param = m.vol << 3;
@@ -208,7 +228,6 @@ struct UpgradePatternData
 
 
 void CSoundFile::UpgradeModule()
-//------------------------------
 {
 	if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 02, 46) && m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 17, 00, 00))
 	{
@@ -398,7 +417,7 @@ void CSoundFile::UpgradeModule()
 	if(compatModeIT && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
 	{
 		// Pre-1.26: Detailed compatibility flags did not exist.
-		static const PlayBehaviourVersion behaviours[] =
+		static constexpr PlayBehaviourVersion behaviours[] =
 		{
 			{ kTempoClamp,						MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
 			{ kPerChannelGlobalVolSlide,		MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
@@ -432,6 +451,7 @@ void CSoundFile::UpgradeModule()
 			{ kITNoSurroundPan,					MAKE_VERSION_NUMERIC(1, 20, 00, 53) },
 			{ kITShortSampleRetrig,				MAKE_VERSION_NUMERIC(1, 20, 00, 54) },
 			{ kITPortaNoNote,					MAKE_VERSION_NUMERIC(1, 20, 00, 56) },
+			{ kRowDelayWithNoteDelay,			MAKE_VERSION_NUMERIC(1, 20, 00, 76) },
 			{ kITDontResetNoteOffOnPorta,		MAKE_VERSION_NUMERIC(1, 20, 02, 06) },
 			{ kITVolColMemory,					MAKE_VERSION_NUMERIC(1, 21, 01, 16) },
 			{ kITPortamentoSwapResetsPos,		MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
@@ -444,17 +464,14 @@ void CSoundFile::UpgradeModule()
 			{ kITPatternLoopWithJumps,			MAKE_VERSION_NUMERIC(1, 25, 00, 19) },
 		};
 
-		for(size_t i = 0; i < CountOf(behaviours); i++)
+		for(const auto &b : behaviours)
 		{
-			m_playBehaviour.set(behaviours[i].behaviour, (m_dwLastSavedWithVersion >= behaviours[i].version || m_dwLastSavedWithVersion == (behaviours[i].version & 0xFFFF0000)));
+			m_playBehaviour.set(b.behaviour, (m_dwLastSavedWithVersion >= b.version || m_dwLastSavedWithVersion == (b.version & 0xFFFF0000)));
 		}
-
-		// The following behaviours were added in OpenMPT 1.26, so are not affected by the upgrade mechanism above.
-		m_playBehaviour.reset(kITInstrWithNoteOff);
 	} else if(compatModeXM && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
 	{
 		// Pre-1.26: Detailed compatibility flags did not exist.
-		static const PlayBehaviourVersion behaviours[] =
+		static constexpr PlayBehaviourVersion behaviours[] =
 		{
 			{ kTempoClamp,						MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
 			{ kPerChannelGlobalVolSlide,		MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
@@ -488,22 +505,77 @@ void CSoundFile::UpgradeModule()
 			{ kFT2FinetunePrecision,			MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
 		};
 
-		for(size_t i = 0; i < CountOf(behaviours); i++)
+		for(const auto &b : behaviours)
+		{
+			m_playBehaviour.set(b.behaviour, m_dwLastSavedWithVersion >= b.version);
+		}
+	}
+	
+	if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
+	{
+		// The following behaviours were added in/after OpenMPT 1.26, so are not affected by the upgrade mechanism above.
+		static constexpr PlayBehaviourVersion behaviours[] =
+		{
+			{ kITInstrWithNoteOff,				MAKE_VERSION_NUMERIC(1, 26, 00, 01) },
+			{ kITMultiSampleInstrumentNumber,	MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
+		};
+
+		for(const auto &b : behaviours)
 		{
-			m_playBehaviour.set(behaviours[i].behaviour, m_dwLastSavedWithVersion >= behaviours[i].version);
+			if(m_dwLastSavedWithVersion < (b.version & 0xFFFF0000))
+				m_playBehaviour.reset(b.behaviour);
+			// Full version information available, i.e. not compatibility-exported.
+			else if(m_dwLastSavedWithVersion > (b.version & 0xFFFF0000) && m_dwLastSavedWithVersion < b.version)
+				m_playBehaviour.reset(b.behaviour);
+		}
+	} else if(GetType() == MOD_TYPE_XM)
+	{
+		// The following behaviours were added after OpenMPT 1.26, so are not affected by the upgrade mechanism above.
+		static constexpr PlayBehaviourVersion behaviours[] =
+		{
+			{ kFT2NoteOffFlags,					MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
+			{ kRowDelayWithNoteDelay,			MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
+			{ kFT2TremoloRampWaveform,			MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
+			{ kFT2PortaUpDownMemory,			MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
+		};
+
+		for(const auto &b : behaviours)
+		{
+			if(m_dwLastSavedWithVersion < b.version)
+				m_playBehaviour.reset(b.behaviour);
 		}
 	} else if(GetType() == MOD_TYPE_S3M)
 	{
-		if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 18, 00, 00))
-			m_playBehaviour.reset(kST3NoMutedChannels);
-		if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
-			m_playBehaviour.reset(kST3EffectMemory);
-		if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 00, 00))
-			m_playBehaviour.reset(kST3PortaSampleChange);
-		if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
-			m_playBehaviour.reset(kST3VibratoMemory);
-		if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
-			m_playBehaviour.reset(kITPanbrelloHold);
+		// We do not store any of these flags in S3M files.
+		static constexpr PlayBehaviourVersion behaviours[] =
+		{
+			{ kST3NoMutedChannels,		MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
+			{ kST3EffectMemory,			MAKE_VERSION_NUMERIC(1, 20, 00, 00) },
+			{ kRowDelayWithNoteDelay,	MAKE_VERSION_NUMERIC(1, 20, 00, 00) },
+			{ kST3PortaSampleChange,	MAKE_VERSION_NUMERIC(1, 22, 00, 00) },
+			{ kST3VibratoMemory,		MAKE_VERSION_NUMERIC(1, 26, 00, 00) },
+			{ kITPanbrelloHold,			MAKE_VERSION_NUMERIC(1, 26, 00, 00) },
+			{ KST3PortaAfterArpeggio,	MAKE_VERSION_NUMERIC(1, 27, 00, 00) },
+		};
+
+		for(const auto &b : behaviours)
+		{
+			if(m_dwLastSavedWithVersion < b.version)
+				m_playBehaviour.reset(b.behaviour);
+		}
+	}
+
+	if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 27, 00, 27) && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 27, 00, 49))
+	{
+		// OpenMPT 1.27 inserted some IT/FT2 flags before the S3M flags that are never saved to files anyway, to keep the flag IDs a bit more compact.
+		// However, it was overlooked that these flags would still be read by OpenMPT 1.26 and thus S3M-specific behaviour would be enabled in IT/XM files.
+		// Hence, in OpenMPT 1.27.00.49 the flag IDs got remapped to no longer conflict with OpenMPT 1.26.
+		// Files made with the affected pre-release versions of OpenMPT 1.27 are upgraded here to use the new IDs.
+		for(int i = 0; i < 5; i++)
+		{
+			m_playBehaviour.set(kFT2NoteOffFlags + i, m_playBehaviour[kST3NoMutedChannels + i]);
+			m_playBehaviour.reset(kST3NoMutedChannels + i);
+		}
 	}
 
 	if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 00, 00))
diff --git a/soundlib/WAVTools.cpp b/soundlib/WAVTools.cpp
index 19bf70c..d83935b 100644
--- a/soundlib/WAVTools.cpp
+++ b/soundlib/WAVTools.cpp
@@ -11,6 +11,7 @@
 #include "stdafx.h"
 #include "Loaders.h"
 #include "WAVTools.h"
+#include "Tagging.h"
 #ifndef MODPLUG_NO_FILESAVE
 #include "../common/mptFileIO.h"
 #endif
@@ -24,15 +25,14 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 WAVReader::WAVReader(FileReader &inputFile) : file(inputFile)
-//-----------------------------------------------------------
 {
 	file.Rewind();
 
 	RIFFHeader fileHeader;
 	isDLS = false;
-	extFormat = 0;
+	subFormat = 0;
 	mayBeCoolEdit16_8 = false;
-	if(!file.ReadConvertEndianness(fileHeader)
+	if(!file.ReadStruct(fileHeader)
 		|| (fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST)
 		|| (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave))
 	{
@@ -41,7 +41,7 @@ WAVReader::WAVReader(FileReader &inputFile) : file(inputFile)
 
 	isDLS = (fileHeader.magic == RIFFHeader::idLIST);
 
-	ChunkReader::ChunkList<RIFFChunk> chunks = file.ReadChunks<RIFFChunk>(2);
+	auto chunks = file.ReadChunks<RIFFChunk>(2);
 
 	if(chunks.size() >= 4
 		&& chunks[1].GetHeader().GetID() == RIFFChunk::iddata
@@ -66,7 +66,7 @@ WAVReader::WAVReader(FileReader &inputFile) : file(inputFile)
 
 	// Read format chunk
 	FileReader formatChunk = chunks.GetChunk(RIFFChunk::idfmt_);
-	if(!formatChunk.ReadConvertEndianness(formatInfo))
+	if(!formatChunk.ReadStruct(formatInfo))
 	{
 		return;
 	}
@@ -83,11 +83,11 @@ WAVReader::WAVReader(FileReader &inputFile) : file(inputFile)
 	} else if(formatInfo.format == WAVFormatChunk::fmtExtensible)
 	{
 		WAVFormatChunkExtension extFormat;
-		if(!formatChunk.ReadConvertEndianness(extFormat))
+		if(!formatChunk.ReadStruct(extFormat))
 		{
 			return;
 		}
-		this->extFormat = extFormat.subFormat;
+		subFormat = static_cast<uint16>(mpt::UUID(extFormat.subFormat).GetData1());
 	}
 
 	// Read sample data
@@ -127,10 +127,10 @@ WAVReader::WAVReader(FileReader &inputFile) : file(inputFile)
 
 
 void WAVReader::FindMetadataChunks(ChunkReader::ChunkList<RIFFChunk> &chunks)
-//---------------------------------------------------------------------------
 {
-	// Read sample loop points
+	// Read sample loop points and other sampler information
 	smplChunk = chunks.GetChunk(RIFFChunk::idsmpl);
+	instChunk = chunks.GetChunk(RIFFChunk::idinst);
 
 	// Read sample cues
 	cueChunk = chunks.GetChunk(RIFFChunk::idcue_);
@@ -148,7 +148,6 @@ void WAVReader::FindMetadataChunks(ChunkReader::ChunkList<RIFFChunk> &chunks)
 
 
 void WAVReader::ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SAMPLENAME])
-//----------------------------------------------------------------------------------------
 {
 	// Read sample name
 	FileReader textChunk = infoChunk.GetChunk(RIFFChunk::idINAM);
@@ -168,31 +167,51 @@ void WAVReader::ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SA
 	// Convert loops
 	WAVSampleInfoChunk sampleInfo;
 	smplChunk.Rewind();
-	if(smplChunk.ReadConvertEndianness(sampleInfo))
+	if(smplChunk.ReadStruct(sampleInfo))
 	{
 		WAVSampleLoop loopData;
-		if(sampleInfo.numLoops > 1 && smplChunk.ReadConvertEndianness(loopData))
+		if(sampleInfo.numLoops > 1 && smplChunk.ReadStruct(loopData))
 		{
 			// First loop: Sustain loop
 			loopData.ApplyToSample(sample.nSustainStart, sample.nSustainEnd, sample.nLength, sample.uFlags, CHN_SUSTAINLOOP, CHN_PINGPONGSUSTAIN, isOldMPT);
 		}
 		// First loop (if only one loop is present) or second loop (if more than one loop is present): Normal sample loop
-		if(smplChunk.ReadConvertEndianness(loopData))
+		if(smplChunk.ReadStruct(loopData))
 		{
 			loopData.ApplyToSample(sample.nLoopStart, sample.nLoopEnd, sample.nLength, sample.uFlags, CHN_LOOP, CHN_PINGPONGLOOP, isOldMPT);
 		}
+		//sample.Transpose((60 - sampleInfo.baseNote) / 12.0);
+		sample.rootNote = static_cast<uint8>(sampleInfo.baseNote);
+		if(sample.rootNote < 128)
+			sample.rootNote += NOTE_MIN;
+		else
+			sample.rootNote = NOTE_NONE;
 		sample.SanitizeLoops();
 	}
 
+	if(sample.rootNote == NOTE_NONE && instChunk.LengthIsAtLeast(sizeof(WAVInstrumentChunk)))
+	{
+		WAVInstrumentChunk inst;
+		instChunk.Rewind();
+		if(instChunk.ReadStruct(inst))
+		{
+			sample.rootNote = inst.unshiftedNote;
+			if(sample.rootNote < 128)
+				sample.rootNote += NOTE_MIN;
+			else
+				sample.rootNote = NOTE_NONE;
+		}
+	}
+
 	// Read cue points
 	if(cueChunk.IsValid())
 	{
 		uint32 numPoints = cueChunk.ReadUint32LE();
-		LimitMax(numPoints, CountOf(sample.cues));
+		LimitMax(numPoints, mpt::saturate_cast<uint32>(MPT_ARRAY_COUNT(sample.cues)));
 		for(uint32 i = 0; i < numPoints; i++)
 		{
 			WAVCuePoint cuePoint;
-			cueChunk.ReadConvertEndianness(cuePoint);
+			cueChunk.ReadStruct(cuePoint);
 			sample.cues[i] = cuePoint.position;
 		}
 	}
@@ -200,13 +219,13 @@ void WAVReader::ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SA
 	// Read MPT extra info
 	WAVExtraChunk mptInfo;
 	xtraChunk.Rewind();
-	if(xtraChunk.ReadConvertEndianness(mptInfo))
+	if(xtraChunk.ReadStruct(mptInfo))
 	{
 		if(mptInfo.flags & WAVExtraChunk::setPanning) sample.uFlags.set(CHN_PANNING);
 
-		sample.nPan = std::min(mptInfo.defaultPan, uint16(256));
-		sample.nVolume = std::min(mptInfo.defaultVolume, uint16(256));
-		sample.nGlobalVol = std::min(mptInfo.globalVolume, uint16(64));
+		sample.nPan = std::min<uint16>(mptInfo.defaultPan, 256);
+		sample.nVolume = std::min<uint16>(mptInfo.defaultVolume, 256);
+		sample.nGlobalVol = std::min<uint16>(mptInfo.globalVolume, 64);
 		sample.nVibType = mptInfo.vibratoType;
 		sample.nVibSweep = mptInfo.vibratoSweep;
 		sample.nVibDepth = mptInfo.vibratoDepth;
@@ -224,7 +243,6 @@ void WAVReader::ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SA
 
 // Apply WAV loop information to a mod sample.
 void WAVSampleLoop::ApplyToSample(SmpLength &start, SmpLength &end, SmpLength sampleLength, SampleFlags &flags, ChannelFlags enableFlag, ChannelFlags bidiFlag, bool mptLoopFix) const
-//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	if(loopEnd == 0)
 	{
@@ -249,7 +267,6 @@ void WAVSampleLoop::ApplyToSample(SmpLength &start, SmpLength &end, SmpLength sa
 
 // Convert internal loop information into a WAV loop.
 void WAVSampleLoop::ConvertToWAV(SmpLength start, SmpLength end, bool bidi)
-//-------------------------------------------------------------------------
 {
 	identifier = 0;
 	loopType = bidi ? loopBidi : loopForward;
@@ -275,7 +292,6 @@ void WAVSampleLoop::ConvertToWAV(SmpLength start, SmpLength end, bool bidi)
 
 // Output to stream: Initialize with std::ostream*.
 WAVWriter::WAVWriter(std::ostream *stream) : s(nullptr), memory(nullptr), memSize(0)
-//----------------------------------------------------------------------------------
 {
 	s = stream;
 	Init();
@@ -284,14 +300,12 @@ WAVWriter::WAVWriter(std::ostream *stream) : s(nullptr), memory(nullptr), memSiz
 
 // Output to clipboard: Initialize with pointer to memory and size of reserved memory.
 WAVWriter::WAVWriter(void *mem, size_t size) : s(nullptr), memory(static_cast<uint8 *>(mem)), memSize(size)
-//----------------------------------------------------------------------------------------------------------
 {
 	Init();
 }
 
 
 WAVWriter::~WAVWriter()
-//---------------------
 {
 	Finalize();
 }
@@ -299,7 +313,6 @@ WAVWriter::~WAVWriter()
 
 // Reset all file variables.
 void WAVWriter::Init()
-//--------------------
 {
 	chunkStartPos = 0;
 	position = 0;
@@ -312,7 +325,6 @@ void WAVWriter::Init()
 
 // Finalize the file by closing the last open chunk and updating the file header. Returns total size of file.
 size_t WAVWriter::Finalize()
-//--------------------------
 {
 	FinalizeChunk();
 
@@ -320,7 +332,6 @@ size_t WAVWriter::Finalize()
 	fileHeader.magic = RIFFHeader::idRIFF;
 	fileHeader.length = static_cast<uint32>(totalSize - 8);
 	fileHeader.type = RIFFHeader::idWAVE;
-	fileHeader.ConvertEndianness();
 
 	Seek(0);
 	Write(fileHeader);
@@ -333,8 +344,7 @@ size_t WAVWriter::Finalize()
 
 
 // Write a new chunk header to the file.
-void WAVWriter::StartChunk(RIFFChunk::id_type id)
-//-----------------------------------------------
+void WAVWriter::StartChunk(RIFFChunk::ChunkIdentifiers id)
 {
 	FinalizeChunk();
 
@@ -346,13 +356,11 @@ void WAVWriter::StartChunk(RIFFChunk::id_type id)
 
 // End current chunk by updating the chunk header and writing a padding byte if necessary.
 void WAVWriter::FinalizeChunk()
-//-----------------------------
 {
 	if(chunkStartPos != 0)
 	{
 		const size_t chunkSize = position - (chunkStartPos + sizeof(RIFFChunk));
 		chunkHeader.length = chunkSize;
-		chunkHeader.ConvertEndianness();
 
 		size_t curPos = position;
 		Seek(chunkStartPos);
@@ -373,7 +381,6 @@ void WAVWriter::FinalizeChunk()
 
 // Seek to a position in file.
 void WAVWriter::Seek(size_t pos)
-//------------------------------
 {
 	position = pos;
 	totalSize = std::max(totalSize, position);
@@ -387,7 +394,6 @@ void WAVWriter::Seek(size_t pos)
 
 // Write some data to the file.
 void WAVWriter::Write(const void *data, size_t numBytes)
-//------------------------------------------------------
 {
 	if(s != nullptr)
 	{
@@ -410,7 +416,6 @@ void WAVWriter::Write(const void *data, size_t numBytes)
 
 // Write the WAV format to the file.
 void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding)
-//-------------------------------------------------------------------------------------------------------------------------
 {
 	StartChunk(RIFFChunk::idfmt_);
 	WAVFormatChunk wavFormat;
@@ -424,7 +429,6 @@ void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChanne
 	wavFormat.byteRate = wavFormat.sampleRate * wavFormat.blockAlign;
 	wavFormat.bitsPerSample = bitDepth;
 
-	wavFormat.ConvertEndianness();
 	Write(wavFormat);
 
 	if(extensible)
@@ -450,11 +454,7 @@ void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChanne
 			extFormat.channelMask = 0;
 			break;
 		}
-		extFormat.subFormat = static_cast<uint16>(encoding);
-		const uint8 guid[] = { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 };
-		MemCopy<uint8[14]>(extFormat.guid, guid);
-
-		extFormat.ConvertEndianness();
+		extFormat.subFormat = mpt::UUID(static_cast<uint16>(encoding), 0x0000, 0x0010, 0x800000AA00389B71ull);
 		Write(extFormat);
 	}
 }
@@ -462,7 +462,6 @@ void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChanne
 
 // Write text tags to the file.
 void WAVWriter::WriteMetatags(const FileTags &tags)
-//-------------------------------------------------
 {
 	StartChunk(RIFFChunk::idLIST);
 	const char info[] = { 'I', 'N', 'F', 'O' };
@@ -482,8 +481,7 @@ void WAVWriter::WriteMetatags(const FileTags &tags)
 
 
 // Write a single tag into a open idLIST chunk
-void WAVWriter::WriteTag(RIFFChunk::id_type id, const mpt::ustring &utext)
-//------------------------------------------------------------------------
+void WAVWriter::WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &utext)
 {
 	std::string text = mpt::ToCharset(mpt::CharsetWindows1252, utext);
 	if(!text.empty())
@@ -493,7 +491,6 @@ void WAVWriter::WriteTag(RIFFChunk::id_type id, const mpt::ustring &utext)
 		RIFFChunk chunk;
 		chunk.id = static_cast<uint32>(id);
 		chunk.length = length;
-		chunk.ConvertEndianness();
 		Write(chunk);
 		Write(text.c_str(), length);
 
@@ -508,9 +505,8 @@ void WAVWriter::WriteTag(RIFFChunk::id_type id, const mpt::ustring &utext)
 
 // Write a sample loop information chunk to the file.
 void WAVWriter::WriteLoopInformation(const ModSample &sample)
-//-----------------------------------------------------------
 {
-	if(!sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP])
+	if(!sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP] && !ModCommand::IsNote(sample.rootNote))
 	{
 		return;
 	}
@@ -524,7 +520,7 @@ void WAVWriter::WriteLoopInformation(const ModSample &sample)
 		sampleRate = ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune);
 	}
 
-	info.ConvertToWAV(sampleRate);
+	info.ConvertToWAV(sampleRate, sample.rootNote);
 
 	// Set up loops
 	WAVSampleLoop loops[2];
@@ -543,11 +539,9 @@ void WAVWriter::WriteLoopInformation(const ModSample &sample)
 		loops[info.numLoops++].ConvertToWAV(0, 0, false);
 	}
 
-	info.ConvertEndianness();
 	Write(info);
 	for(uint32 i = 0; i < info.numLoops; i++)
 	{
-		loops[i].ConvertEndianness();
 		Write(loops[i]);
 	}
 }
@@ -555,18 +549,16 @@ void WAVWriter::WriteLoopInformation(const ModSample &sample)
 
 // Write a sample's cue points to the file.
 void WAVWriter::WriteCueInformation(const ModSample &sample)
-//----------------------------------------------------------
 {
 	StartChunk(RIFFChunk::idcue_);
 	{
-		const uint32 numPoints = SwapBytesLE_(static_cast<uint32>(CountOf(sample.cues)));
+		const uint32 numPoints = SwapBytesLE(static_cast<uint32>(CountOf(sample.cues)));
 		Write(numPoints);
 	}
 	for(uint32 i = 0; i < CountOf(sample.cues); i++)
 	{
 		WAVCuePoint cuePoint;
 		cuePoint.ConvertToWAV(i, sample.cues[i]);
-		cuePoint.ConvertEndianness();
 		Write(cuePoint);
 	}
 }
@@ -574,13 +566,11 @@ void WAVWriter::WriteCueInformation(const ModSample &sample)
 
 // Write MPT's sample information chunk to the file.
 void WAVWriter::WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName)
-//-----------------------------------------------------------------------------------------------------
 {
 	StartChunk(RIFFChunk::idxtra);
 	WAVExtraChunk mptInfo;
 
 	mptInfo.ConvertToWAV(sample, modType);
-	mptInfo.ConvertEndianness();
 	Write(mptInfo);
 
 	if(sampleName != nullptr)
diff --git a/soundlib/WAVTools.h b/soundlib/WAVTools.h
index ef05a59..3747c4d 100644
--- a/soundlib/WAVTools.h
+++ b/soundlib/WAVTools.h
@@ -11,104 +11,87 @@
 #pragma once
 
 #include "ChunkReader.h"
-#include "Tagging.h"
+#include "Loaders.h"
+#include "../common/mptUUID.h"
 
 OPENMPT_NAMESPACE_BEGIN
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
+struct FileTags;
 
 // RIFF header
-struct PACKED RIFFHeader
+struct RIFFHeader
 {
 	// 32-Bit chunk identifiers
 	enum RIFFMagic
 	{
-		idRIFF	= 0x46464952,	// magic for WAV files
-		idLIST	= 0x5453494C,	// magic for samples in DLS banks
-		idWAVE	= 0x45564157,	// type for WAV files
-		idwave	= 0x65766177,	// type for samples in DLS banks
+		idRIFF	= MAGIC4LE('R','I','F','F'),	// magic for WAV files
+		idLIST	= MAGIC4LE('L','I','S','T'),	// magic for samples in DLS banks
+		idWAVE	= MAGIC4LE('W','A','V','E'),	// type for WAV files
+		idwave	= MAGIC4LE('w','a','v','e'),	// type for samples in DLS banks
 	};
 
-	uint32 magic;	// RIFF (in WAV files) or LIST (in DLS banks)
-	uint32 length;	// Size of the file, not including magic and length
-	uint32 type;	// WAVE (in WAV files) or wave (in DLS banks)
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(magic);
-		SwapBytesLE(length);
-		SwapBytesLE(type);
-	}
+	uint32le magic;		// RIFF (in WAV files) or LIST (in DLS banks)
+	uint32le length;	// Size of the file, not including magic and length
+	uint32le type;		// WAVE (in WAV files) or wave (in DLS banks)
 };
 
-STATIC_ASSERT(sizeof(RIFFHeader) == 12);
+MPT_BINARY_STRUCT(RIFFHeader, 12)
 
 
 // General RIFF Chunk header
-struct PACKED RIFFChunk
+struct RIFFChunk
 {
 	// 32-Bit chunk identifiers
 	enum ChunkIdentifiers
 	{
-		idfmt_	= 0x20746D66,	// "fmt "
-		iddata	= 0x61746164,	// "data"
-		idpcm_	= 0x206d6370,	// "pcm " (IMA ADPCM samples)
-		idfact	= 0x74636166,	// "fact" (compressed samples)
-		idsmpl	= 0x6C706D73,	// "smpl"
-		idLIST	= 0x5453494C,	// "LIST"
-		idxtra	= 0x61727478,	// "xtra"
-		idcue_	= 0x20657563,	// "cue "
-		idwsmp	= 0x706D7377,	// "wsmp" (DLS bank samples)
+		idfmt_	= MAGIC4LE('f','m','t',' '),	// Sample format information
+		iddata	= MAGIC4LE('d','a','t','a'),	// Sample data
+		idpcm_	= MAGIC4LE('p','c','m',' '),	// IMA ADPCM samples
+		idfact	= MAGIC4LE('f','a','c','t'),	// Compressed samples
+		idsmpl	= MAGIC4LE('s','m','p','l'),	// Sampler and loop information
+		idinst	= MAGIC4LE('i','n','s','t'),	// Instrument information
+		idLIST	= MAGIC4LE('L','I','S','T'),	// List of chunks
+		idxtra	= MAGIC4LE('x','t','r','a'),	// OpenMPT extra infomration
+		idcue_	= MAGIC4LE('c','u','e',' '),	// Cue points
+		idwsmp	= MAGIC4LE('w','s','m','p'),	// DLS bank samples
 		id____	= 0x00000000,	// Found when loading buggy MPT samples
 
 		// Identifiers in "LIST" chunk
-		idINAM	= 0x4D414E49, // title
-		idISFT	= 0x54465349, // software
-		idICOP	= 0x504F4349, // copyright
-		idIART	= 0x54524149, // artist
-		idIPRD	= 0x44525049, // product (album)
-		idICMT	= 0x544D4349, // comment
-		idIENG	= 0x474E4549, // engineer
-		idISBJ	= 0x4A425349, // subject
-		idIGNR	= 0x524E4749, // genre
-		idICRD	= 0x44524349, // date created
-
-		idYEAR  = 0x52414559, // year
-		idTRCK  = 0x4B435254, // track number
-		idTURL  = 0x4C535554, // url
+		idINAM	= MAGIC4LE('I','N','A','M'), // title
+		idISFT	= MAGIC4LE('I','S','F','T'), // software
+		idICOP	= MAGIC4LE('I','C','O','P'), // copyright
+		idIART	= MAGIC4LE('I','A','R','T'), // artist
+		idIPRD	= MAGIC4LE('I','P','R','D'), // product (album)
+		idICMT	= MAGIC4LE('I','C','M','T'), // comment
+		idIENG	= MAGIC4LE('I','E','N','G'), // engineer
+		idISBJ	= MAGIC4LE('I','S','B','J'), // subject
+		idIGNR	= MAGIC4LE('I','G','N','R'), // genre
+		idICRD	= MAGIC4LE('I','C','R','D'), // date created
+
+		idYEAR  = MAGIC4LE('Y','E','A','R'), // year
+		idTRCK  = MAGIC4LE('T','R','C','K'), // track number
+		idTURL  = MAGIC4LE('T','U','R','L'), // url
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint32 id;		// See ChunkIdentifiers
-	uint32 length;	// Chunk size without header
+	uint32le id;		// See ChunkIdentifiers
+	uint32le length;	// Chunk size without header
 
 	size_t GetLength() const
 	{
-		return SwapBytesReturnLE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
-	}
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(id);
-		SwapBytesLE(length);
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(RIFFChunk) == 8);
+MPT_BINARY_STRUCT(RIFFChunk, 8)
 
 
 // Format Chunk
-struct PACKED WAVFormatChunk
+struct WAVFormatChunk
 {
 	// Sample formats
 	enum SampleFormats
@@ -122,84 +105,52 @@ struct PACKED WAVFormatChunk
 		fmtExtensible	= 0xFFFE,
 	};
 
-	uint16 format;			// Sample format, see SampleFormats
-	uint16 numChannels;		// Number of audio channels
-	uint32 sampleRate;		// Sample rate in Hz
-	uint32 byteRate;		// Bytes per second (should be freqHz * blockAlign)
-	uint16 blockAlign;		// Size of a sample, in bytes (do not trust this value, it's incorrect in some files)
-	uint16 bitsPerSample;	// Bits per sample
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(format);
-		SwapBytesLE(numChannels);
-		SwapBytesLE(sampleRate);
-		SwapBytesLE(byteRate);
-		SwapBytesLE(blockAlign);
-		SwapBytesLE(bitsPerSample);
-	}
+	uint16le format;			// Sample format, see SampleFormats
+	uint16le numChannels;		// Number of audio channels
+	uint32le sampleRate;		// Sample rate in Hz
+	uint32le byteRate;			// Bytes per second (should be freqHz * blockAlign)
+	uint16le blockAlign;		// Size of a sample, in bytes (do not trust this value, it's incorrect in some files)
+	uint16le bitsPerSample;		// Bits per sample
 };
 
-STATIC_ASSERT(sizeof(WAVFormatChunk) == 16);
+MPT_BINARY_STRUCT(WAVFormatChunk, 16)
 
 
 // Extension of the WAVFormatChunk structure, used if format == formatExtensible
-struct PACKED WAVFormatChunkExtension
+struct WAVFormatChunkExtension
 {
-	uint16 size;
-	uint16 validBitsPerSample;
-	uint32 channelMask;
-	uint16 subFormat;
-	uint8  guid[14];
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(size);
-		SwapBytesLE(validBitsPerSample);
-		SwapBytesLE(channelMask);
-		SwapBytesLE(subFormat);
-	}
+	uint16le size;
+	uint16le validBitsPerSample;
+	uint32le channelMask;
+	GUIDms   subFormat;
 };
 
-STATIC_ASSERT(sizeof(WAVFormatChunkExtension) == 24);
+MPT_BINARY_STRUCT(WAVFormatChunkExtension, 24)
 
 
 // Sample information chunk
-struct PACKED WAVSampleInfoChunk
+struct WAVSampleInfoChunk
 {
-	uint32 manufacturer;
-	uint32 product;
-	uint32 samplePeriod;	// 1000000000 / sampleRate
-	uint32 baseNote;		// MIDI base note of sample
-	uint32 pitchFraction;
-	uint32 SMPTEFormat;
-	uint32 SMPTEOffset;
-	uint32 numLoops;		// number of loops
-	uint32 samplerData;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(manufacturer);
-		SwapBytesLE(product);
-		SwapBytesLE(samplePeriod);
-		SwapBytesLE(baseNote);
-		SwapBytesLE(pitchFraction);
-		SwapBytesLE(SMPTEFormat);
-		SwapBytesLE(SMPTEOffset);
-		SwapBytesLE(numLoops);
-		SwapBytesLE(samplerData);
-	}
+	uint32le manufacturer;
+	uint32le product;
+	uint32le samplePeriod;	// 1000000000 / sampleRate
+	uint32le baseNote;		// MIDI base note of sample
+	uint32le pitchFraction;
+	uint32le SMPTEFormat;
+	uint32le SMPTEOffset;
+	uint32le numLoops;		// number of loops
+	uint32le samplerData;
 
 	// Set up information
-	void ConvertToWAV(uint32 freq)
+	void ConvertToWAV(uint32 freq, uint8 rootNote)
 	{
 		manufacturer = 0;
 		product = 0;
 		samplePeriod = 1000000000 / freq;
-		baseNote = NOTE_MIDDLEC - NOTE_MIN;
+		if(rootNote != 0)
+			baseNote = rootNote - NOTE_MIN;
+		else
+			baseNote = NOTE_MIDDLEC - NOTE_MIN;
 		pitchFraction = 0;
 		SMPTEFormat = 0;
 		SMPTEOffset = 0;
@@ -208,11 +159,11 @@ struct PACKED WAVSampleInfoChunk
 	}
 };
 
-STATIC_ASSERT(sizeof(WAVSampleInfoChunk) == 36);
+MPT_BINARY_STRUCT(WAVSampleInfoChunk, 36)
 
 
 // Sample loop information chunk (found after WAVSampleInfoChunk in "smpl" chunk)
-struct PACKED WAVSampleLoop
+struct WAVSampleLoop
 {
 	// Sample Loop Types
 	enum LoopType
@@ -222,23 +173,12 @@ struct PACKED WAVSampleLoop
 		loopBackward	= 2,
 	};
 
-	uint32 identifier;
-	uint32 loopType;		// See LoopType
-	uint32 loopStart;		// Loop start in samples
-	uint32 loopEnd;			// Loop end in samples
-	uint32 fraction;
-	uint32 playCount;		// Loop Count, 0 = infinite
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(identifier);
-		SwapBytesLE(loopType);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(fraction);
-		SwapBytesLE(playCount);
-	}
+	uint32le identifier;
+	uint32le loopType;		// See LoopType
+	uint32le loopStart;		// Loop start in samples
+	uint32le loopEnd;		// Loop end in samples
+	uint32le fraction;
+	uint32le playCount;		// Loop Count, 0 = infinite
 
 	// Apply WAV loop information to a mod sample.
 	void ApplyToSample(SmpLength &start, SmpLength &end, SmpLength sampleLength, SampleFlags &flags, ChannelFlags enableFlag, ChannelFlags bidiFlag, bool mptLoopFix) const;
@@ -247,35 +187,41 @@ struct PACKED WAVSampleLoop
 	void ConvertToWAV(SmpLength start, SmpLength end, bool bidi);
 };
 
-STATIC_ASSERT(sizeof(WAVSampleLoop) == 24);
+MPT_BINARY_STRUCT(WAVSampleLoop, 24)
+
+
+// Instrument information chunk
+struct WAVInstrumentChunk
+{
+	uint8 unshiftedNote;	// Root key of sample, 0...127
+	int8  finetune;			// Finetune of root key in cents
+	int8  gain;				// in dB
+	uint8 lowNote;			// Note range, 0...127
+	uint8 highNote;
+	uint8 lowVelocity;		// Velocity range, 0...127
+	uint8 highVelocity;
+};
+
+MPT_BINARY_STRUCT(WAVInstrumentChunk, 7)
 
 
 // MPT-specific "xtra" chunk
-struct PACKED WAVExtraChunk
+struct WAVExtraChunk
 {
 	enum Flags
 	{
 		setPanning	= 0x20,
 	};
 
-	uint32 flags;
-	uint16 defaultPan;
-	uint16 defaultVolume;
-	uint16 globalVolume;
-	uint16 reserved;
-	uint8  vibratoType;
-	uint8  vibratoSweep;
-	uint8  vibratoDepth;
-	uint8  vibratoRate;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(flags);
-		SwapBytesLE(defaultPan);
-		SwapBytesLE(defaultVolume);
-		SwapBytesLE(globalVolume);
-	}
+	uint32le flags;
+	uint16le defaultPan;
+	uint16le defaultVolume;
+	uint16le globalVolume;
+	uint16le reserved;
+	uint8le  vibratoType;
+	uint8le  vibratoSweep;
+	uint8le  vibratoDepth;
+	uint8le  vibratoRate;
 
 	// Set up sample information
 	void ConvertToWAV(const ModSample &sample, MODTYPE modType)
@@ -304,29 +250,18 @@ struct PACKED WAVExtraChunk
 	}
 };
 
-STATIC_ASSERT(sizeof(WAVExtraChunk) == 16);
+MPT_BINARY_STRUCT(WAVExtraChunk, 16)
 
 
 // Sample cue point structure for the "cue " chunk
-struct PACKED WAVCuePoint
+struct WAVCuePoint
 {
-	uint32 id;			// Unique identification value
-	uint32 position;	// Play order position
-	uint32 riffChunkID;	// RIFF ID of corresponding data chunk
-	uint32 chunkStart;	// Byte Offset of Data Chunk
-	uint32 blockStart;	// Byte Offset to sample of First Channel
-	uint32 offset;		// Byte Offset to sample byte of First Channel
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(id);
-		SwapBytesLE(position);
-		SwapBytesLE(riffChunkID);
-		SwapBytesLE(chunkStart);
-		SwapBytesLE(blockStart);
-		SwapBytesLE(offset);
-	}
+	uint32le id;			// Unique identification value
+	uint32le position;		// Play order position
+	uint32le riffChunkID;	// RIFF ID of corresponding data chunk
+	uint32le chunkStart;	// Byte Offset of Data Chunk
+	uint32le blockStart;	// Byte Offset to sample of First Channel
+	uint32le offset;		// Byte Offset to sample byte of First Channel
 
 	// Set up sample information
 	void ConvertToWAV(uint32 id_, SmpLength offset_)
@@ -340,27 +275,20 @@ struct PACKED WAVCuePoint
 	}
 };
 
-STATIC_ASSERT(sizeof(WAVCuePoint) == 24);
-
+MPT_BINARY_STRUCT(WAVCuePoint, 24)
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
 
-
-//=============
 class WAVReader
-//=============
 {
 protected:
 	ChunkReader file;
-	FileReader sampleData, smplChunk, xtraChunk, wsmpChunk, cueChunk;
+	FileReader sampleData, smplChunk, instChunk, xtraChunk, wsmpChunk, cueChunk;
 	ChunkReader::ChunkList<RIFFChunk> infoChunk;
 
 	FileReader::off_t sampleLength;
-	bool isDLS;
 	WAVFormatChunk formatInfo;
-	uint16 extFormat;
+	uint16 subFormat;
+	bool isDLS;
 	bool mayBeCoolEdit16_8;
 
 public:
@@ -371,7 +299,7 @@ public:
 	void FindMetadataChunks(ChunkReader::ChunkList<RIFFChunk> &chunks);
 
 	// Self-explanatory getters.
-	WAVFormatChunk::SampleFormats GetSampleFormat() const { return IsExtensibleFormat() ? static_cast<WAVFormatChunk::SampleFormats>(extFormat) : static_cast<WAVFormatChunk::SampleFormats>(formatInfo.format); }
+	WAVFormatChunk::SampleFormats GetSampleFormat() const { return IsExtensibleFormat() ? static_cast<WAVFormatChunk::SampleFormats>(subFormat) : static_cast<WAVFormatChunk::SampleFormats>(formatInfo.format.get()); }
 	uint16 GetNumChannels() const { return formatInfo.numChannels; }
 	uint16 GetBitsPerSample() const { return formatInfo.bitsPerSample; }
 	uint32 GetSampleRate() const { return formatInfo.sampleRate; }
@@ -385,7 +313,7 @@ public:
 	uint16 GetSampleSize() const { return ((GetNumChannels() * GetBitsPerSample()) + 7) / 8; }
 
 	// Get sample length (in samples)
-	SmpLength GetSampleLength() const { return sampleLength; }
+	SmpLength GetSampleLength() const { return mpt::saturate_cast<SmpLength>(sampleLength); }
 
 	// Apply sample settings from file (loop points, MPT extra settings, ...) to a sample.
 	void ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]);
@@ -394,9 +322,7 @@ public:
 
 #ifndef MODPLUG_NO_FILESAVE
 
-//=============
 class WAVWriter
-//=============
 {
 protected:
 	// When writing to a stream: Stream pointer
@@ -428,7 +354,7 @@ public:
 	// Finalize the file by closing the last open chunk and updating the file header. Returns total size of file.
 	size_t Finalize();
 	// Begin writing a new chunk to the file.
-	void StartChunk(RIFFChunk::id_type id);
+	void StartChunk(RIFFChunk::ChunkIdentifiers id);
 
 	// Skip some bytes... For example after writing sample data.
 	void Skip(size_t numBytes) { Seek(position + numBytes); }
@@ -480,7 +406,7 @@ protected:
 	void Write(const void *data, size_t numBytes);
 
 	// Write a single tag into a open idLIST chunk
-	void WriteTag(RIFFChunk::id_type id, const mpt::ustring &utext);
+	void WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &utext);
 };
 
 #endif // MODPLUG_NO_FILESAVE
diff --git a/soundlib/XMTools.cpp b/soundlib/XMTools.cpp
index 81b2708..2b79849 100644
--- a/soundlib/XMTools.cpp
+++ b/soundlib/XMTools.cpp
@@ -19,42 +19,8 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void XMFileHeader::ConvertEndianness()
-//------------------------------------
-{
-	SwapBytesLE(version);
-	SwapBytesLE(size);
-	SwapBytesLE(orders);
-	SwapBytesLE(restartPos);
-	SwapBytesLE(channels);
-	SwapBytesLE(patterns);
-	SwapBytesLE(instruments);
-	SwapBytesLE(flags);
-	SwapBytesLE(speed);
-	SwapBytesLE(tempo);
-}
-
-
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void XMInstrument::ConvertEndianness()
-//------------------------------------
-{
-	for(size_t i = 0; i < CountOf(volEnv); i++)
-	{
-		SwapBytesLE(volEnv[i]);
-		SwapBytesLE(panEnv[i]);
-	}
-	SwapBytesLE(volFade);
-	SwapBytesLE(midiProgram);
-	SwapBytesLE(pitchWheelRange);
-}
-
-
-
 // Convert OpenMPT's internal envelope representation to XM envelope data.
-void XMInstrument::ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8 &numPoints, uint8 &flags, uint8 &sustain, uint8 &loopStart, uint8 &loopEnd, EnvType env)
-//---------------------------------------------------------------------------------------------------------------------------------------------------------------------
+void XMInstrument::ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8le &numPoints, uint8le &flags, uint8le &sustain, uint8le &loopStart, uint8le &loopEnd, EnvType env)
 {
 	numPoints = static_cast<uint8>(std::min(12u, mptEnv.size()));
 
@@ -89,7 +55,6 @@ void XMInstrument::ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8 &
 
 // Convert OpenMPT's internal sample representation to an XMInstrument.
 uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
-//-------------------------------------------------------------------------------------
 {
 	MemsetZero(*this);
 
@@ -101,12 +66,12 @@ uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibility
 	ConvertEnvelopeToXM(mptIns.PanEnv, panPoints, panFlags, panSustain, panLoopStart, panLoopEnd, EnvTypePan);
 
 	// Create sample assignment table
-	std::vector<SAMPLEINDEX> sampleList = GetSampleList(mptIns, compatibilityExport);
+	auto sampleList = GetSampleList(mptIns, compatibilityExport);
 	for(size_t i = 0; i < CountOf(sampleMap); i++)
 	{
 		if(mptIns.Keyboard[i + 12] > 0)
 		{
-			std::vector<SAMPLEINDEX>::iterator sample = std::find(sampleList.begin(), sampleList.end(), mptIns.Keyboard[i + 12]);
+			auto sample = std::find(sampleList.begin(), sampleList.end(), mptIns.Keyboard[i + 12]);
 			if(sample != sampleList.end())
 			{
 				// Yep, we want to export this sample.
@@ -129,7 +94,6 @@ uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibility
 
 // Get a list of samples that should be written to the file.
 std::vector<SAMPLEINDEX> XMInstrument::GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const
-//---------------------------------------------------------------------------------------------------------------
 {
 	std::vector<SAMPLEINDEX> sampleList;		// List of samples associated with this instrument
 	std::vector<bool> addedToList;			// Which samples did we already add to the sample list?
@@ -160,9 +124,8 @@ std::vector<SAMPLEINDEX> XMInstrument::GetSampleList(const ModInstrument &mptIns
 
 // Convert XM envelope data to an OpenMPT's internal envelope representation.
 void XMInstrument::ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoints, uint8 flags, uint8 sustain, uint8 loopStart, uint8 loopEnd, EnvType env) const
-//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
-	mptEnv.resize(std::min(numPoints, uint8(12)));
+	mptEnv.resize(std::min<uint8>(numPoints, 12));
 
 	// Envelope Data
 	for(uint32 i = 0; i < mptEnv.size(); i++)
@@ -171,11 +134,11 @@ void XMInstrument::ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoi
 		{
 		case EnvTypeVol:
 			mptEnv[i].tick = volEnv[i * 2];
-			mptEnv[i].value = static_cast<uint8>(volEnv[i * 2 + 1]);
+			mptEnv[i].value = static_cast<EnvelopeNode::value_t>(volEnv[i * 2 + 1]);
 			break;
 		case EnvTypePan:
 			mptEnv[i].tick = panEnv[i * 2];
-			mptEnv[i].value = static_cast<uint8>(panEnv[i * 2 + 1]);
+			mptEnv[i].value = static_cast<EnvelopeNode::value_t>(panEnv[i * 2 + 1]);
 			break;
 		}
 
@@ -214,7 +177,6 @@ void XMInstrument::ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoi
 
 // Convert an XMInstrument to OpenMPT's internal instrument representation.
 void XMInstrument::ConvertToMPT(ModInstrument &mptIns) const
-//----------------------------------------------------------
 {
 	mptIns.nFadeOut = volFade;
 
@@ -232,7 +194,7 @@ void XMInstrument::ConvertToMPT(ModInstrument &mptIns) const
 	{
 		mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
 		Limit(mptIns.nMidiChannel, uint8(MidiFirstChannel), uint8(MidiLastChannel));
-		mptIns.nMidiProgram = static_cast<uint8>(std::min(read_unaligned_field(midiProgram), uint16(127)) + 1);
+		mptIns.nMidiProgram = static_cast<uint8>(std::min<uint16>(midiProgram, 127) + 1);
 	}
 	mptIns.midiPWD = static_cast<int8>(pitchWheelRange);
 }
@@ -240,7 +202,6 @@ void XMInstrument::ConvertToMPT(ModInstrument &mptIns) const
 
 // Apply auto-vibrato settings from sample to file.
 void XMInstrument::ApplyAutoVibratoToXM(const ModSample &mptSmp, MODTYPE fromType)
-//--------------------------------------------------------------------------------
 {
 	vibType = mptSmp.nVibType;
 	vibSweep = mptSmp.nVibSweep;
@@ -250,7 +211,7 @@ void XMInstrument::ApplyAutoVibratoToXM(const ModSample &mptSmp, MODTYPE fromTyp
 	if((vibDepth | vibRate) != 0 && !(fromType & MOD_TYPE_XM))
 	{
 		if(mptSmp.nVibSweep != 0)
-			vibSweep = mpt::saturate_cast<uint8>(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep));
+			vibSweep = mpt::saturate_cast<decltype(vibSweep)::base_type>(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep));
 		else
 			vibSweep = 255;
 	}
@@ -259,7 +220,6 @@ void XMInstrument::ApplyAutoVibratoToXM(const ModSample &mptSmp, MODTYPE fromTyp
 
 // Apply auto-vibrato settings from file to a sample.
 void XMInstrument::ApplyAutoVibratoToMPT(ModSample &mptSmp) const
-//---------------------------------------------------------------
 {
 	mptSmp.nVibType = vibType;
 	mptSmp.nVibSweep = vibSweep;
@@ -268,20 +228,8 @@ void XMInstrument::ApplyAutoVibratoToMPT(ModSample &mptSmp) const
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void XMInstrumentHeader::ConvertEndianness()
-//------------------------------------------
-{
-	SwapBytesLE(size);
-	SwapBytesLE(sampleHeaderSize);
-	SwapBytesLE(numSamples);
-	instrument.ConvertEndianness();
-}
-
-
 // Write stuff to the header that's always necessary (also for empty instruments)
 void XMInstrumentHeader::Finalise()
-//---------------------------------
 {
 	size = sizeof(XMInstrumentHeader);
 	if(numSamples > 0)
@@ -298,7 +246,6 @@ void XMInstrumentHeader::Finalise()
 
 // Convert OpenMPT's internal sample representation to an XMInstrumentHeader.
 void XMInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
-//-----------------------------------------------------------------------------------------
 {
 	numSamples = instrument.ConvertToXM(mptIns, compatibilityExport);
 	mpt::String::Write<mpt::String::spacePadded>(name, mptIns.name);
@@ -309,7 +256,6 @@ void XMInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibi
 
 // Convert an XMInstrumentHeader to OpenMPT's internal instrument representation.
 void XMInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const
-//----------------------------------------------------------------
 {
 	instrument.ConvertToMPT(mptIns);
 
@@ -335,19 +281,8 @@ void XMInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void XIInstrumentHeader::ConvertEndianness()
-//------------------------------------------
-{
-	SwapBytesLE(version);
-	SwapBytesLE(numSamples);
-	instrument.ConvertEndianness();
-}
-
-
 // Convert OpenMPT's internal sample representation to an XIInstrumentHeader.
 void XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
-//-----------------------------------------------------------------------------------------
 {
 	numSamples = instrument.ConvertToXM(mptIns, compatibilityExport);
 
@@ -364,7 +299,6 @@ void XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibi
 
 // Convert an XIInstrumentHeader to OpenMPT's internal instrument representation.
 void XIInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const
-//----------------------------------------------------------------
 {
 	instrument.ConvertToMPT(mptIns);
 
@@ -381,19 +315,8 @@ void XIInstrumentHeader::ConvertToMPT(ModInstrument &mptIns) const
 }
 
 
-// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-void XMSample::ConvertEndianness()
-//--------------------------------
-{
-	SwapBytesLE(length);
-	SwapBytesLE(loopStart);
-	SwapBytesLE(loopLength);
-}
-
-
 // Convert OpenMPT's internal sample representation to an XMSample.
 void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport)
-//---------------------------------------------------------------------------------------------
 {
 	MemsetZero(*this);
 
@@ -414,10 +337,10 @@ void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compa
 	}
 
 	flags = 0;
-	if(mptSmp.uFlags[CHN_LOOP])
-	{
-		flags |= mptSmp.uFlags[CHN_PINGPONGLOOP] ? XMSample::sampleBidiLoop : XMSample::sampleLoop;
-	}
+	if(mptSmp.uFlags[CHN_PINGPONGLOOP])
+		flags |= XMSample::sampleBidiLoop;
+	else if(mptSmp.uFlags[CHN_LOOP])
+		flags |= XMSample::sampleLoop;
 
 	// Sample Length and Loops
 	length = mpt::saturate_cast<uint32>(mptSmp.nLength);
@@ -444,7 +367,6 @@ void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compa
 
 // Convert an XMSample to OpenMPT's internal sample representation.
 void XMSample::ConvertToMPT(ModSample &mptSmp) const
-//--------------------------------------------------
 {
 	mptSmp.Initialize(MOD_TYPE_XM);
 
@@ -496,7 +418,6 @@ void XMSample::ConvertToMPT(ModSample &mptSmp) const
 
 // Retrieve the internal sample format flags for this instrument.
 SampleIO XMSample::GetSampleFormat() const
-//----------------------------------------
 {
 	if(reserved == sampleADPCM && !(flags & (XMSample::sample16Bit | XMSample::sampleStereo)))
 	{
diff --git a/soundlib/XMTools.h b/soundlib/XMTools.h
index a93441d..a519135 100644
--- a/soundlib/XMTools.h
+++ b/soundlib/XMTools.h
@@ -14,12 +14,8 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
 // XM File Header
-struct PACKED XMFileHeader
+struct XMFileHeader
 {
 	enum XMHeaderFlags
 	{
@@ -27,30 +23,27 @@ struct PACKED XMFileHeader
 		extendedFilterRange		= 0x1000,
 	};
 
-	char   signature[17];	// "Extended Module: "
-	char   songName[20];	// Song Name, not null-terminated (any nulls are treated as spaces)
-	uint8  eof;				// DOS EOF Character (0x1A)
-	char   trackerName[20];	// Software that was used to create the XM file
-	uint16 version;			// File version (1.02 - 1.04 are supported)
-	uint32 size;			// Header Size
-	uint16 orders;			// Number of Orders
-	uint16 restartPos;		// Restart Position
-	uint16 channels;		// Number of Channels
-	uint16 patterns;		// Number of Patterns
-	uint16 instruments;		// Number of Unstruments
-	uint16 flags;			// Song Flags
-	uint16 speed;			// Default Speed
-	uint16 tempo;			// Default Tempo
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	char     signature[17];		// "Extended Module: "
+	char     songName[20];		// Song Name, not null-terminated (any nulls are treated as spaces)
+	uint8le  eof;				// DOS EOF Character (0x1A)
+	char     trackerName[20];	// Software that was used to create the XM file
+	uint16le version;			// File version (1.02 - 1.04 are supported)
+	uint32le size;				// Header Size
+	uint16le orders;			// Number of Orders
+	uint16le restartPos;		// Restart Position
+	uint16le channels;			// Number of Channels
+	uint16le patterns;			// Number of Patterns
+	uint16le instruments;		// Number of Unstruments
+	uint16le flags;				// Song Flags
+	uint16le speed;				// Default Speed
+	uint16le tempo;				// Default Tempo
 };
 
-STATIC_ASSERT(sizeof(XMFileHeader) == 80);
+MPT_BINARY_STRUCT(XMFileHeader, 80)
 
 
 // XM Instrument Data
-struct PACKED XMInstrument
+struct XMInstrument
 {
 	// Envelope Flags
 	enum XMEnvelopeFlags
@@ -60,33 +53,30 @@ struct PACKED XMInstrument
 		envLoop		= 0x04,
 	};
 
-	uint8  sampleMap[96];	// Note -> Sample assignment
-	uint16 volEnv[24];		// Volume envelope nodes / values (0...64)
-	uint16 panEnv[24];		// Panning envelope nodes / values (0...63)
-	uint8  volPoints;		// Volume envelope length
-	uint8  panPoints;		// Panning envelope length
-	uint8  volSustain;		// Volume envelope sustain point
-	uint8  volLoopStart;	// Volume envelope loop start point
-	uint8  volLoopEnd;		// Volume envelope loop end point
-	uint8  panSustain;		// Panning envelope sustain point
-	uint8  panLoopStart;	// Panning envelope loop start point
-	uint8  panLoopEnd;		// Panning envelope loop end point
-	uint8  volFlags;		// Volume envelope flags
-	uint8  panFlags;		// Panning envelope flags
-	uint8  vibType;			// Sample Auto-Vibrato Type
-	uint8  vibSweep;		// Sample Auto-Vibrato Sweep
-	uint8  vibDepth;		// Sample Auto-Vibrato Depth
-	uint8  vibRate;			// Sample Auto-Vibrato Rate
-	uint16 volFade;			// Volume Fade-Out
-	uint8  midiEnabled;		// MIDI Out Enabled (0 / 1)
-	uint8  midiChannel;		// MIDI Channel (0...15)
-	uint16 midiProgram;		// MIDI Program (0...127)
-	uint16 pitchWheelRange;	// MIDI Pitch Wheel Range (0...36 halftones)
-	uint8  muteComputer;	// Mute instrument if MIDI is enabled (0 / 1)
-	uint8  reserved[15];	// Reserved
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	uint8le  sampleMap[96];		// Note -> Sample assignment
+	uint16le volEnv[24];		// Volume envelope nodes / values (0...64)
+	uint16le panEnv[24];		// Panning envelope nodes / values (0...63)
+	uint8le  volPoints;			// Volume envelope length
+	uint8le  panPoints;			// Panning envelope length
+	uint8le  volSustain;		// Volume envelope sustain point
+	uint8le  volLoopStart;		// Volume envelope loop start point
+	uint8le  volLoopEnd;		// Volume envelope loop end point
+	uint8le  panSustain;		// Panning envelope sustain point
+	uint8le  panLoopStart;		// Panning envelope loop start point
+	uint8le  panLoopEnd;		// Panning envelope loop end point
+	uint8le  volFlags;			// Volume envelope flags
+	uint8le  panFlags;			// Panning envelope flags
+	uint8le  vibType;			// Sample Auto-Vibrato Type
+	uint8le  vibSweep;			// Sample Auto-Vibrato Sweep
+	uint8le  vibDepth;			// Sample Auto-Vibrato Depth
+	uint8le  vibRate;			// Sample Auto-Vibrato Rate
+	uint16le volFade;			// Volume Fade-Out
+	uint8le  midiEnabled;		// MIDI Out Enabled (0 / 1)
+	uint8le  midiChannel;		// MIDI Channel (0...15)
+	uint16le midiProgram;		// MIDI Program (0...127)
+	uint16le pitchWheelRange;	// MIDI Pitch Wheel Range (0...36 halftones)
+	uint8le  muteComputer;		// Mute instrument if MIDI is enabled (0 / 1)
+	uint8le  reserved[15];		// Reserved
 
 	enum EnvType
 	{
@@ -94,7 +84,7 @@ struct PACKED XMInstrument
 		EnvTypePan,
 	};
 	// Convert OpenMPT's internal envelope representation to XM envelope data.
-	void ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8 &numPoints, uint8 &flags, uint8 &sustain, uint8 &loopStart, uint8 &loopEnd, EnvType env);
+	void ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8le &numPoints, uint8le &flags, uint8le &sustain, uint8le &loopStart, uint8le &loopEnd, EnvType env);
 	// Convert XM envelope data to an OpenMPT's internal envelope representation.
 	void ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoints, uint8 flags, uint8 sustain, uint8 loopStart, uint8 loopEnd, EnvType env) const;
 
@@ -111,22 +101,19 @@ struct PACKED XMInstrument
 	std::vector<SAMPLEINDEX> GetSampleList(const ModInstrument &mptIns, bool compatibilityExport) const;
 };
 
-STATIC_ASSERT(sizeof(XMInstrument) == 230);
+MPT_BINARY_STRUCT(XMInstrument, 230)
 
 
 // XM Instrument Header
-struct PACKED XMInstrumentHeader
+struct XMInstrumentHeader
 {
-	uint32 size;				// Size of XMInstrumentHeader + XMInstrument
-	char   name[22];			// Instrument Name, not null-terminated (any nulls are treated as spaces)
-	uint8  type;				// Instrument Type (Apparently FT2 writes some crap here, but it's the same crap for all instruments of the same module!)
-	uint16 numSamples;			// Number of Samples associated with instrument
-	uint32 sampleHeaderSize;	// Size of XMSample
+	uint32le size;				// Size of XMInstrumentHeader + XMInstrument
+	char     name[22];			// Instrument Name, not null-terminated (any nulls are treated as spaces)
+	uint8le  type;				// Instrument Type (Apparently FT2 writes some crap here, but it's the same crap for all instruments of the same module!)
+	uint16le numSamples;		// Number of Samples associated with instrument
+	uint32le sampleHeaderSize;	// Size of XMSample
 	XMInstrument instrument;
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
-
 	// Write stuff to the header that's always necessary (also for empty instruments)
 	void Finalise();
 
@@ -136,27 +123,24 @@ struct PACKED XMInstrumentHeader
 	void ConvertToMPT(ModInstrument &mptIns) const;
 };
 
-STATIC_ASSERT(sizeof(XMInstrumentHeader) == 263);
+MPT_BINARY_STRUCT(XMInstrumentHeader, 263)
 
 
 // XI Instrument Header
-struct PACKED XIInstrumentHeader
+struct XIInstrumentHeader
 {
 	enum
 	{
 		fileVersion	= 0x102,
 	};
 
-	char   signature[21];		// "Extended Instrument: "
-	char   name[22];			// Instrument Name, not null-terminated (any nulls are treated as spaces)
-	uint8  eof;					// DOS EOF Character (0x1A)
-	char   trackerName[20];		// Software that was used to create the XI file
-	uint16 version;				// File Version (1.02)
+	char     signature[21];		// "Extended Instrument: "
+	char     name[22];			// Instrument Name, not null-terminated (any nulls are treated as spaces)
+	uint8le  eof;				// DOS EOF Character (0x1A)
+	char     trackerName[20];	// Software that was used to create the XI file
+	uint16le version;			// File Version (1.02)
 	XMInstrument instrument;
-	uint16 numSamples;			// Number of embedded sample headers + samples
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	uint16le numSamples;		// Number of embedded sample headers + samples
 
 	// Convert OpenMPT's internal sample representation to an XIInstrumentHeader.
 	void ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport);
@@ -164,11 +148,11 @@ struct PACKED XIInstrumentHeader
 	void ConvertToMPT(ModInstrument &mptIns) const;
 };
 
-STATIC_ASSERT(sizeof(XIInstrumentHeader) == 298);
+MPT_BINARY_STRUCT(XIInstrumentHeader, 298)
 
 
 // XM Sample Header
-struct PACKED XMSample
+struct XMSample
 {
 	enum XMSampleFlags
 	{
@@ -180,19 +164,16 @@ struct PACKED XMSample
 		sampleADPCM			= 0xAD,		// MODPlugin :(
 	};
 
-	uint32 length;			// Sample Length (in bytes)
-	uint32 loopStart;		// Loop Start (in bytes)
-	uint32 loopLength;		// Loop Length (in bytes)
-	uint8  vol;				// Default Volume
-	int8   finetune;		// Sample Finetune
-	uint8  flags;			// Sample Flags
-	uint8  pan;				// Sample Panning
-	int8   relnote;			// Sample Transpose
-	uint8  reserved;		// Reserved (abused for ModPlug's ADPCM compression)
-	char   name[22];		// Sample Name, not null-terminated (any nulls are treated as spaces)
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness();
+	uint32le length;		// Sample Length (in bytes)
+	uint32le loopStart;		// Loop Start (in bytes)
+	uint32le loopLength;	// Loop Length (in bytes)
+	uint8le  vol;			// Default Volume
+	int8le   finetune;		// Sample Finetune
+	uint8le  flags;			// Sample Flags
+	uint8le  pan;			// Sample Panning
+	int8le   relnote;		// Sample Transpose
+	uint8le  reserved;		// Reserved (abused for ModPlug's ADPCM compression)
+	char     name[22];		// Sample Name, not null-terminated (any nulls are treated as spaces)
 
 	// Convert OpenMPT's internal sample representation to an XMSample.
 	void ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport);
@@ -202,12 +183,7 @@ struct PACKED XMSample
 	SampleIO GetSampleFormat() const;
 };
 
-STATIC_ASSERT(sizeof(XMSample) == 40);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(XMSample, 40)
 
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/load_j2b.cpp b/soundlib/load_j2b.cpp
index 82a75de..897e7a6 100644
--- a/soundlib/load_j2b.cpp
+++ b/soundlib/load_j2b.cpp
@@ -18,7 +18,7 @@
 #if defined(MPT_WITH_ZLIB)
 #include <zlib.h>
 #elif defined(MPT_WITH_MINIZ)
-#include <miniz/miniz.c>
+#include <miniz/miniz.h>
 #endif
 
 
@@ -31,42 +31,29 @@ static const uint8 j2bAutoVibratoTrans[] =
 	VIB_SINE, VIB_SQUARE, VIB_RAMP_UP, VIB_RAMP_DOWN, VIB_RANDOM,
 };
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
 
 // header for compressed j2b files
-struct PACKED J2BFileHeader
+struct J2BFileHeader
 {
 	// Magic Bytes
 	// 32-Bit J2B header identifiers
 	static const uint32 magicDEADBEAF = 0xAFBEADDEu;
 	static const uint32 magicDEADBABE = 0xBEBAADDEu;
 
-	char   signature[4];	// MUSE
-	uint32 deadbeaf;		// 0xDEADBEAF (AM) or 0xDEADBABE (AMFF)
-	uint32 fileLength;		// complete filesize
-	uint32 crc32;			// checksum of the compressed data block
-	uint32 packedLength;	// length of the compressed data block
-	uint32 unpackedLength;	// length of the decompressed module
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(deadbeaf);
-		SwapBytesLE(fileLength);
-		SwapBytesLE(crc32);
-		SwapBytesLE(packedLength);
-		SwapBytesLE(unpackedLength);
-	}
+	char     signature[4];		// MUSE
+	uint32le deadbeaf;			// 0xDEADBEAF (AM) or 0xDEADBABE (AMFF)
+	uint32le fileLength;		// complete filesize
+	uint32le crc32;				// checksum of the compressed data block
+	uint32le packedLength;		// length of the compressed data block
+	uint32le unpackedLength;	// length of the decompressed module
 };
 
-STATIC_ASSERT(sizeof(J2BFileHeader) == 24);
+MPT_BINARY_STRUCT(J2BFileHeader, 24)
 
 
 // AM(FF) stuff
 
-struct PACKED AMFFRiffChunk
+struct AMFFRiffChunk
 {
 	// 32-Bit chunk identifiers
 	enum ChunkIdentifiers
@@ -84,34 +71,25 @@ struct PACKED AMFFRiffChunk
 		idAS__	= MAGIC4LE('A','S',' ',' '),
 	};
 
-	typedef ChunkIdentifiers id_type;
-
-	uint32 id;		// See ChunkIdentifiers
-	uint32 length;	// Chunk size without header
+	uint32le id;		// See ChunkIdentifiers
+	uint32le length;	// Chunk size without header
 
 	size_t GetLength() const
 	{
-		return SwapBytesReturnLE(length);
+		return length;
 	}
 
-	id_type GetID() const
+	ChunkIdentifiers GetID() const
 	{
-		return static_cast<id_type>(SwapBytesReturnLE(id));
-	}
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(id);
-		SwapBytesLE(length);
+		return static_cast<ChunkIdentifiers>(id.get());
 	}
 };
 
-STATIC_ASSERT(sizeof(AMFFRiffChunk) == 8);
+MPT_BINARY_STRUCT(AMFFRiffChunk, 8)
 
 
 // This header is used for both AM's "INIT" as well as AMFF's "MAIN" chunk
-struct PACKED AMFFMainChunk
+struct AMFFMainChunk
 {
 	// Main Chunk flags
 	enum MainFlags
@@ -119,44 +97,31 @@ struct PACKED AMFFMainChunk
 		amigaSlides = 0x01,
 	};
 
-	char   songname[64];
-	uint8  flags;
-	uint8  channels;
-	uint8  speed;
-	uint8  tempo;
-	uint16 minPeriod;
-	uint16 maxPeriod;
-	uint8  globalvolume;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(minPeriod);
-		SwapBytesLE(maxPeriod);
-	}
+	char     songname[64];
+	uint8le  flags;
+	uint8le  channels;
+	uint8le  speed;
+	uint8le  tempo;
+	uint16le minPeriod;
+	uint16le maxPeriod;
+	uint8le  globalvolume;
 };
 
-STATIC_ASSERT(sizeof(AMFFMainChunk) == 73);
+MPT_BINARY_STRUCT(AMFFMainChunk, 73)
 
 
 // AMFF instrument envelope point (old format)
-struct PACKED AMFFEnvelopePoint
+struct AMFFEnvelopePoint
 {
-	uint16 tick;
-	uint8  value;	// 0...64
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(tick);
-	}
+	uint16le tick;
+	uint8le  value;	// 0...64
 };
 
-STATIC_ASSERT(sizeof(AMFFEnvelopePoint) == 3);
+MPT_BINARY_STRUCT(AMFFEnvelopePoint, 3)
 
 
 // AMFF instrument envelope (old format)
-struct PACKED AMFFEnvelope
+struct AMFFEnvelope
 {
 	// Envelope flags (also used for RIFF AM)
 	enum EnvelopeFlags
@@ -166,24 +131,14 @@ struct PACKED AMFFEnvelope
 		envLoop		= 0x04,
 	};
 
-	uint8  envFlags;			// high nibble = pan env flags, low nibble = vol env flags (both nibbles work the same way)
-	uint8  envNumPoints;		// high nibble = pan env length, low nibble = vol env length
-	uint8  envSustainPoints;	// you guessed it... high nibble = pan env sustain point, low nibble = vol env sustain point
-	uint8  envLoopStarts;		// i guess you know the pattern now.
-	uint8  envLoopEnds;			// same here.
+	uint8le envFlags;			// high nibble = pan env flags, low nibble = vol env flags (both nibbles work the same way)
+	uint8le envNumPoints;		// high nibble = pan env length, low nibble = vol env length
+	uint8le envSustainPoints;	// you guessed it... high nibble = pan env sustain point, low nibble = vol env sustain point
+	uint8le envLoopStarts;		// I guess you know the pattern now.
+	uint8le envLoopEnds;		// same here.
 	AMFFEnvelopePoint volEnv[10];
 	AMFFEnvelopePoint panEnv[10];
 
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		for(size_t i = 0; i < CountOf(volEnv); i++)
-		{
-			volEnv[i].ConvertEndianness();
-			panEnv[i].ConvertEndianness();
-		}
-	}
-
 	// Convert weird envelope data to OpenMPT's internal format.
 	void ConvertEnvelope(uint8 flags, uint8 numPoints, uint8 sustainPoint, uint8 loopStart, uint8 loopEnd, const AMFFEnvelopePoint *points, InstrumentEnvelope &mptEnv) const
 	{
@@ -203,7 +158,7 @@ struct PACKED AMFFEnvelope
 			else if(mptEnv[i].tick < mptEnv[i - 1].tick)
 				mptEnv[i].tick = mptEnv[i - 1].tick + 1;
 
-			mptEnv[i].value = Clamp(points[i].value, uint8(0), uint8(0x40));
+			mptEnv[i].value = Clamp<uint8, uint8>(points[i].value, 0, 64);
 		}
 
 		mptEnv.dwFlags.set(ENV_ENABLED, (flags & AMFFEnvelope::envEnabled) != 0);
@@ -218,38 +173,30 @@ struct PACKED AMFFEnvelope
 		// but just has room for 10 envelope points. That means that long (>= 16 points)
 		// envelopes are cut off, and envelopes have to be trimmed to 10 points, even if
 		// the header claims that they are longer.
+		// For XM files the number of points also appears to be off by one,
+		// but luckily there are no official J2Bs using envelopes anyway.
 		ConvertEnvelope(envFlags & 0x0F, envNumPoints & 0x0F, envSustainPoints & 0x0F, envLoopStarts & 0x0F, envLoopEnds & 0x0F, volEnv, mptIns.VolEnv);
 		ConvertEnvelope(envFlags >> 4, envNumPoints >> 4, envSustainPoints >> 4, envLoopStarts >> 4, envLoopEnds >> 4, panEnv, mptIns.PanEnv);
 	}
 };
 
-STATIC_ASSERT(sizeof(AMFFEnvelope) == 65);
+MPT_BINARY_STRUCT(AMFFEnvelope, 65)
 
 
 // AMFF instrument header (old format)
-struct PACKED AMFFInstrumentHeader
+struct AMFFInstrumentHeader
 {
-	uint8  unknown;				// 0x00
-	uint8  index;				// actual instrument number
-	char   name[28];
-	uint8  numSamples;
-	uint8  sampleMap[120];
-	uint8  vibratoType;
-	uint16 vibratoSweep;
-	uint16 vibratoDepth;
-	uint16 vibratoRate;
+	uint8le  unknown;		// 0x00
+	uint8le  index;			// actual instrument number
+	char     name[28];
+	uint8le  numSamples;
+	uint8le  sampleMap[120];
+	uint8le  vibratoType;
+	uint16le vibratoSweep;
+	uint16le vibratoDepth;
+	uint16le vibratoRate;
 	AMFFEnvelope envelopes;
-	uint16 fadeout;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(vibratoSweep);
-		SwapBytesLE(vibratoDepth);
-		SwapBytesLE(vibratoRate);
-		envelopes.ConvertEndianness();
-		SwapBytesLE(fadeout);
-	}
+	uint16le fadeout;
 
 	// Convert instrument data to OpenMPT's internal format.
 	void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample)
@@ -268,11 +215,11 @@ struct PACKED AMFFInstrumentHeader
 
 };
 
-STATIC_ASSERT(sizeof(AMFFInstrumentHeader) == 225);
+MPT_BINARY_STRUCT(AMFFInstrumentHeader, 225)
 
 
 // AMFF sample header (old format)
-struct PACKED AMFFSampleHeader
+struct AMFFSampleHeader
 {
 	// Sample flags (also used for RIFF AM)
 	enum SampleFlags
@@ -285,30 +232,18 @@ struct PACKED AMFFSampleHeader
 		// some flags are still missing... what is e.g. 0x8000?
 	};
 
-	uint32 id;	// "SAMP"
-	uint32 chunkSize;	// header + sample size
-	char   name[28];
-	uint8  pan;
-	uint8  volume;
-	uint16 flags;
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint32 sampleRate;
-	uint32 reserved1;
-	uint32 reserved2;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(id);
-		SwapBytesLE(chunkSize);
-		SwapBytesLE(flags);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sampleRate);
-	}
+	uint32le id;		// "SAMP"
+	uint32le chunkSize;	// header + sample size
+	char     name[28];
+	uint8le  pan;
+	uint8le  volume;
+	uint16le flags;
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint32le sampleRate;
+	uint32le reserved1;
+	uint32le reserved2;
 
 	// Convert sample header to OpenMPT's internal format.
 	void ConvertToMPT(AMFFInstrumentHeader &instrHeader, ModSample &mptSmp) const
@@ -354,47 +289,29 @@ struct PACKED AMFFSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(AMFFSampleHeader) == 64);
+MPT_BINARY_STRUCT(AMFFSampleHeader, 64)
 
 
 // AM instrument envelope point (new format)
-struct PACKED AMEnvelopePoint
+struct AMEnvelopePoint
 {
-	uint16 tick;
-	uint16 value;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(tick);
-		SwapBytesLE(value);
-	}
+	uint16le tick;
+	uint16le value;
 };
 
-STATIC_ASSERT(sizeof(AMEnvelopePoint) == 4);
+MPT_BINARY_STRUCT(AMEnvelopePoint, 4)
 
 
 // AM instrument envelope (new format)
-struct PACKED AMEnvelope
+struct AMEnvelope
 {
-	uint16 flags;
-	uint8  numPoints;	// actually, it's num. points - 1, and 0xFF if there is no envelope
-	uint8  sustainPoint;
-	uint8  loopStart;
-	uint8  loopEnd;
+	uint16le flags;
+	uint8le  numPoints;		// actually, it's num. points - 1, and 0xFF if there is no envelope
+	uint8le  sustainPoint;
+	uint8le  loopStart;
+	uint8le  loopEnd;
 	AMEnvelopePoint values[10];
-	uint16 fadeout;		// why is this here? it's only needed for the volume envelope...
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(flags);
-		for(size_t i = 0; i < CountOf(values); i++)
-		{
-			values[i].ConvertEndianness();
-		}
-		SwapBytesLE(fadeout);
-	}
+	uint16le fadeout;		// why is this here? it's only needed for the volume envelope...
 
 	// Convert envelope data to OpenMPT's internal format.
 	void ConvertToMPT(InstrumentEnvelope &mptEnv, EnvelopeType envType) const
@@ -421,6 +338,7 @@ struct PACKED AMEnvelope
 			switch(envType)
 			{
 			case ENV_VOLUME:	// 0....32767
+			default:
 				mptEnv[i].value = (uint8)((val + 1) >> 9);
 				break;
 			case ENV_PITCH:		// -4096....4096
@@ -439,39 +357,26 @@ struct PACKED AMEnvelope
 	}
 };
 
-STATIC_ASSERT(sizeof(AMEnvelope) == 48);
+MPT_BINARY_STRUCT(AMEnvelope, 48)
 
 
 // AM instrument header (new format)
-struct PACKED AMInstrumentHeader
+struct AMInstrumentHeader
 {
-	uint32 headSize;	// Header size (i.e. the size of this struct)
-	uint8  unknown1;	// 0x00
-	uint8  index;		// Actual instrument number
-	char   name[32];
-	uint8  sampleMap[128];
-	uint8  vibratoType;
-	uint16 vibratoSweep;
-	uint16 vibratoDepth;
-	uint16 vibratoRate;
-	uint8  unknown2[7];
+	uint32le headSize;	// Header size (i.e. the size of this struct)
+	uint8le  unknown1;	// 0x00
+	uint8le  index;		// Actual instrument number
+	char     name[32];
+	uint8le  sampleMap[128];
+	uint8le  vibratoType;
+	uint16le vibratoSweep;
+	uint16le vibratoDepth;
+	uint16le vibratoRate;
+	uint8le  unknown2[7];
 	AMEnvelope volEnv;
 	AMEnvelope pitchEnv;
 	AMEnvelope panEnv;
-	uint16 numSamples;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(headSize);
-		SwapBytesLE(vibratoSweep);
-		SwapBytesLE(vibratoDepth);
-		SwapBytesLE(vibratoRate);
-		volEnv.ConvertEndianness();
-		pitchEnv.ConvertEndianness();
-		panEnv.ConvertEndianness();
-		SwapBytesLE(numSamples);
-	}
+	uint16le numSamples;
 
 	// Convert instrument data to OpenMPT's internal format.
 	void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample)
@@ -497,42 +402,29 @@ struct PACKED AMInstrumentHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(AMInstrumentHeader) == 326);
+MPT_BINARY_STRUCT(AMInstrumentHeader, 326)
 
 
 // AM sample header (new format)
-struct PACKED AMSampleHeader
+struct AMSampleHeader
 {
-	uint32 headSize;	// Header size (i.e. the size of this struct), apparently not including headSize.
-	char   name[32];
-	uint16 pan;
-	uint16 volume;
-	uint16 flags;
-	uint16 unkown;		// 0x0000 / 0x0080?
-	uint32 length;
-	uint32 loopStart;
-	uint32 loopEnd;
-	uint32 sampleRate;
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(headSize);
-		SwapBytesLE(pan);
-		SwapBytesLE(volume);
-		SwapBytesLE(flags);
-		SwapBytesLE(length);
-		SwapBytesLE(loopStart);
-		SwapBytesLE(loopEnd);
-		SwapBytesLE(sampleRate);
-	}
+	uint32le headSize;		// Header size (i.e. the size of this struct), apparently not including headSize.
+	char     name[32];
+	uint16le pan;
+	uint16le volume;
+	uint16le flags;
+	uint16le unkown;		// 0x0000 / 0x0080?
+	uint32le length;
+	uint32le loopStart;
+	uint32le loopEnd;
+	uint32le sampleRate;
 
 	// Convert sample header to OpenMPT's internal format.
 	void ConvertToMPT(AMInstrumentHeader &instrHeader, ModSample &mptSmp) const
 	{
 		mptSmp.Initialize();
-		mptSmp.nPan = std::min(pan, static_cast<uint16>(32767)) * 256 / 32767;
-		mptSmp.nVolume = std::min(volume, static_cast<uint16>(32767)) * 256 / 32767;
+		mptSmp.nPan = std::min<uint16>(pan, 32767) * 256 / 32767;
+		mptSmp.nVolume = std::min<uint16>(volume, 32767) * 256 / 32767;
 		mptSmp.nGlobalVol = 64;
 		mptSmp.nLength = length;
 		mptSmp.nLoopStart = loopStart;
@@ -551,13 +443,13 @@ struct PACKED AMSampleHeader
 		}
 
 		if(flags & AMFFSampleHeader::smp16Bit)
-			mptSmp.uFlags |= CHN_16BIT;
+			mptSmp.uFlags.set(CHN_16BIT);
 		if(flags & AMFFSampleHeader::smpLoop)
-			mptSmp.uFlags |= CHN_LOOP;
+			mptSmp.uFlags.set(CHN_LOOP);
 		if(flags & AMFFSampleHeader::smpPingPong)
-			mptSmp.uFlags |= CHN_PINGPONGLOOP;
+			mptSmp.uFlags.set(CHN_PINGPONGLOOP);
 		if(flags & AMFFSampleHeader::smpPanning)
-			mptSmp.uFlags |= CHN_PANNING;
+			mptSmp.uFlags.set(CHN_PANNING);
 	}
 
 	// Retrieve the internal sample format flags for this sample.
@@ -571,20 +463,14 @@ struct PACKED AMSampleHeader
 	}
 };
 
-STATIC_ASSERT(sizeof(AMSampleHeader) == 60);
-
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(AMSampleHeader, 60)
 
 
 // Convert RIFF AM(FF) pattern data to MPT pattern data.
 static bool ConvertAMPattern(FileReader chunk, PATTERNINDEX pat, bool isAM, CSoundFile &sndFile)
-//----------------------------------------------------------------------------------------------
 {
 	// Effect translation LUT
-	static const ModCommand::COMMAND amEffTrans[] =
+	static const EffectCommand amEffTrans[] =
 	{
 		CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO,
 		CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO,
@@ -640,16 +526,16 @@ static bool ConvertAMPattern(FileReader chunk, PATTERNINDEX pat, bool isAM, CSou
 			if(flags & effectFlag) // effect
 			{
 				m.param = chunk.ReadUint8();
-				m.command = chunk.ReadUint8();
+				uint8 command = chunk.ReadUint8();
 
-				if(m.command < CountOf(amEffTrans))
+				if(command < CountOf(amEffTrans))
 				{
 					// command translation
-					m.command = amEffTrans[m.command];
+					m.command = amEffTrans[command];
 				} else
 				{
 #ifdef DEBUG
-					Log(mpt::String::Print("J2B: Unknown command: 0x%1, param 0x%2", mpt::fmt::HEX0<2>(m.command), mpt::fmt::HEX0<2>(m.param)));
+					Log(mpt::format("J2B: Unknown command: 0x%1, param 0x%2")(mpt::fmt::HEX0<2>(command), mpt::fmt::HEX0<2>(m.param)));
 #endif // DEBUG
 					m.command = CMD_NONE;
 				}
@@ -728,24 +614,88 @@ static bool ConvertAMPattern(FileReader chunk, PATTERNINDEX pat, bool isAM, CSou
 }
 
 
+struct AMFFRiffChunkFormat
+{
+	uint32le format;
+};
+
+MPT_BINARY_STRUCT(AMFFRiffChunkFormat, 4)
+
+
+static bool ValidateHeader(const AMFFRiffChunk &fileHeader)
+{
+	if(fileHeader.id != AMFFRiffChunk::idRIFF)
+	{
+		return false;
+	}
+	if(fileHeader.GetLength() < 8 + sizeof(AMFFMainChunk))
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static bool ValidateHeader(const AMFFRiffChunkFormat &formatHeader)
+{
+	if(formatHeader.format != AMFFRiffChunk::idAMFF && formatHeader.format != AMFFRiffChunk::idAM__)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize)
+{
+	AMFFRiffChunk fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	AMFFRiffChunkFormat formatHeader;
+	if(!file.ReadStruct(formatHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(formatHeader))
+	{
+		return ProbeFailure;
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
-//------------------------------------------------------------------
 {
 	file.Rewind();
 	AMFFRiffChunk fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
 	}
-
-	if(fileHeader.id != AMFFRiffChunk::idRIFF)
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	AMFFRiffChunkFormat formatHeader;
+	if(!file.ReadStruct(formatHeader))
+	{
+		return false;
+	}
+	if(!ValidateHeader(formatHeader))
 	{
 		return false;
 	}
 
 	bool isAM; // false: AMFF, true: AM
 
-	uint32 format = file.ReadUint32LE();
+	uint32 format = formatHeader.format;
 	if(format == AMFFRiffChunk::idAMFF)
 		isAM = false; // "AMFF"
 	else if(format == AMFFRiffChunk::idAM__)
@@ -767,12 +717,12 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 	else
 		chunks = chunkFile.ReadChunks<AMFFRiffChunk>(isAM ? 2 : 1);
 
-	FileReader chunk(chunks.GetChunk(mainChunkID));
+	FileReader chunkMain(chunks.GetChunk(mainChunkID));
 	AMFFMainChunk mainChunk;
-	if(!chunk.IsValid() 
-		|| !chunk.ReadConvertEndianness(mainChunk)
+	if(!chunkMain.IsValid() 
+		|| !chunkMain.ReadStruct(mainChunk)
 		|| mainChunk.channels < 1
-		|| !chunk.CanRead(mainChunk.channels))
+		|| !chunkMain.CanRead(mainChunk.channels))
 	{
 		return false;
 	} else if(loadFlags == onlyVerifyHeader)
@@ -789,11 +739,11 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 	m_nDefaultTempo.Set(mainChunk.tempo);
 	m_nDefaultGlobalVolume = mainChunk.globalvolume * 2;
 
-	m_madeWithTracker = "Galaxy Sound System (";
+	m_madeWithTracker = MPT_USTRING("Galaxy Sound System (");
 	if(isAM)
-		m_madeWithTracker += "new version)";
+		m_madeWithTracker += MPT_USTRING("new version)");
 	else
-		m_madeWithTracker += "old version)";
+		m_madeWithTracker += MPT_USTRING("old version)");
 
 	if(mainChunk.minPeriod < mainChunk.maxPeriod)
 	{
@@ -810,7 +760,7 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 	{
 		ChnSettings[nChn].Reset();
 
-		uint8 pan = chunk.ReadUint8();
+		uint8 pan = chunkMain.ReadUint8();
 		if(isAM)
 		{
 			if(pan > 128)
@@ -831,17 +781,17 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 		// "ORDR" - Order list
 		FileReader chunk(chunks.GetChunk(AMFFRiffChunk::idORDR));
 		uint8 numOrders = chunk.ReadUint8() + 1;
-		Order.ReadAsByte(chunk, numOrders, numOrders, 0xFF, 0xFE);
+		ReadOrderFromFile<uint8>(Order(), chunk, numOrders, 0xFF, 0xFE);
 	}
 
 	// "PATT" - Pattern data for one pattern
 	if(loadFlags & loadPatternData)
 	{
 		PATTERNINDEX maxPattern = 0;
-		std::vector<FileReader> pattChunks = chunks.GetAllChunks(AMFFRiffChunk::idPATT);
-		for(std::vector<FileReader>::iterator patternIter = pattChunks.begin(); patternIter != pattChunks.end(); patternIter++)
+		auto pattChunks = chunks.GetAllChunks(AMFFRiffChunk::idPATT);
+		Patterns.ResizeArray(static_cast<PATTERNINDEX>(pattChunks.size()));
+		for(auto chunk : pattChunks)
 		{
-			FileReader chunk(*patternIter);
 			PATTERNINDEX pat = chunk.ReadUint8();
 			size_t patternSize = chunk.ReadUint32LE();
 			ConvertAMPattern(chunk.ReadChunk(patternSize), pat, isAM, *this);
@@ -857,12 +807,11 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 	if(!isAM)
 	{
 		// "INST" - Instrument (only in RIFF AMFF)
-		std::vector<FileReader> instChunks = chunks.GetAllChunks(AMFFRiffChunk::idINST);
-		for(std::vector<FileReader>::iterator instIter = instChunks.begin(); instIter != instChunks.end(); instIter++)
+		auto instChunks = chunks.GetAllChunks(AMFFRiffChunk::idINST);
+		for(auto chunk : instChunks)
 		{
-			FileReader chunk(*instIter);
 			AMFFInstrumentHeader instrHeader;
-			if(!chunk.ReadConvertEndianness(instrHeader))
+			if(!chunk.ReadStruct(instrHeader))
 			{
 				continue;
 			}
@@ -877,8 +826,6 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 				continue;
 			}
 
-			m_nInstruments = std::max(m_nInstruments, instr);
-
 			instrHeader.ConvertToMPT(*pIns, m_nSamples);
 
 			// read sample sub-chunks - this is a rather "flat" format compared to RIFF AM and has no nested RIFF chunks.
@@ -886,7 +833,7 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 			{
 				AMFFSampleHeader sampleHeader;
 
-				if(m_nSamples + 1 >= MAX_SAMPLES || !chunk.ReadConvertEndianness(sampleHeader))
+				if(m_nSamples + 1 >= MAX_SAMPLES || !chunk.ReadStruct(sampleHeader))
 				{
 					continue;
 				}
@@ -909,23 +856,22 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 	} else
 	{
 		// "RIFF" - Instrument (only in RIFF AM)
-		std::vector<FileReader> instChunks = chunks.GetAllChunks(AMFFRiffChunk::idRIFF);
-		for(std::vector<FileReader>::iterator instIter = instChunks.begin(); instIter != instChunks.end(); instIter++)
+		auto instChunks = chunks.GetAllChunks(AMFFRiffChunk::idRIFF);
+		for(ChunkReader chunk : instChunks)
 		{
-			ChunkReader chunk(*instIter);
 			if(chunk.ReadUint32LE() != AMFFRiffChunk::idAI__)
 			{
 				continue;
 			}
 
 			AMFFRiffChunk instChunk;
-			if(!chunk.ReadConvertEndianness(instChunk) || instChunk.id != AMFFRiffChunk::idINST)
+			if(!chunk.ReadStruct(instChunk) || instChunk.id != AMFFRiffChunk::idINST)
 			{
 				continue;
 			}
 
 			AMInstrumentHeader instrHeader;
-			if(!chunk.ReadConvertEndianness(instrHeader))
+			if(!chunk.ReadStruct(instrHeader))
 			{
 				continue;
 			}
@@ -940,19 +886,15 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 			{
 				continue;
 			}
-			m_nInstruments = std::max(m_nInstruments, instr);
 
 			instrHeader.ConvertToMPT(*pIns, m_nSamples);
 
 			// Read sample sub-chunks (RIFF nesting ftw)
-			ChunkReader::ChunkList<AMFFRiffChunk> sampleChunkFile = chunk.ReadChunks<AMFFRiffChunk>(2);
-			std::vector<FileReader> sampleChunks = sampleChunkFile.GetAllChunks(AMFFRiffChunk::idRIFF);
+			auto sampleChunks = chunk.ReadChunks<AMFFRiffChunk>(2).GetAllChunks(AMFFRiffChunk::idRIFF);
 			MPT_ASSERT(sampleChunks.size() == instrHeader.numSamples);
 
-			for(std::vector<FileReader>::iterator smpIter = sampleChunks.begin(); smpIter != sampleChunks.end(); smpIter++)
+			for(auto sampleChunk : sampleChunks)
 			{
-				ChunkReader sampleChunk(*smpIter);
-
 				if(sampleChunk.ReadUint32LE() != AMFFRiffChunk::idAS__ || m_nSamples + 1 >= MAX_SAMPLES)
 				{
 					continue;
@@ -968,7 +910,7 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 
 				// Aaand even more nested chunks! Great, innit?
 				AMFFRiffChunk sampleHeaderChunk;
-				if(!sampleChunk.ReadConvertEndianness(sampleHeaderChunk) || sampleHeaderChunk.id != AMFFRiffChunk::idSAMP)
+				if(!sampleChunk.ReadStruct(sampleHeaderChunk) || sampleHeaderChunk.id != AMFFRiffChunk::idSAMP)
 				{
 					break;
 				}
@@ -976,7 +918,7 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 				FileReader sampleFileChunk = sampleChunk.ReadChunk(sampleHeaderChunk.length);
 
 				AMSampleHeader sampleHeader;
-				if(!sampleFileChunk.ReadConvertEndianness(sampleHeader))
+				if(!sampleFileChunk.ReadStruct(sampleHeader))
 				{
 					break;
 				}
@@ -998,8 +940,62 @@ bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
 	return true;
 }
 
+
+static bool ValidateHeader(const J2BFileHeader &fileHeader)
+{
+	if(std::memcmp(fileHeader.signature, "MUSE", 4)
+		|| (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
+			&& fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
+		)
+	{
+		return false;
+	}
+	if(fileHeader.packedLength == 0)
+	{
+		return false;
+	}
+	if(fileHeader.fileLength != fileHeader.packedLength + sizeof(J2BFileHeader))
+	{
+		return false;
+	}
+	return true;
+}
+
+
+static bool ValidateHeaderFileSize(const J2BFileHeader &fileHeader, uint64 filesize)
+{
+	if(filesize != fileHeader.fileLength)
+	{
+		return false;
+	}
+	return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize)
+{
+	J2BFileHeader fileHeader;
+	if(!file.ReadStruct(fileHeader))
+	{
+		return ProbeWantMoreData;
+	}
+	if(!ValidateHeader(fileHeader))
+	{
+		return ProbeFailure;
+	}
+	if(pfilesize)
+	{
+		if(!ValidateHeaderFileSize(fileHeader, *pfilesize))
+		{
+			return ProbeFailure;
+		}
+	}
+	MPT_UNREFERENCED_PARAMETER(pfilesize);
+	return ProbeSuccess;
+}
+
+
 bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
 {
 
 #if !defined(MPT_WITH_ZLIB) && !defined(MPT_WITH_MINIZ)
@@ -1012,21 +1008,21 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
 
 	file.Rewind();
 	J2BFileHeader fileHeader;
-	if(!file.ReadConvertEndianness(fileHeader))
+	if(!file.ReadStruct(fileHeader))
 	{
 		return false;
 	}
-
-	if(memcmp(fileHeader.signature, "MUSE", 4)
-		|| (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
-			&& fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
-		|| fileHeader.fileLength != file.GetLength()
+	if(!ValidateHeader(fileHeader))
+	{
+		return false;
+	}
+	if(fileHeader.fileLength != file.GetLength()
 		|| fileHeader.packedLength != file.BytesLeft()
-		|| fileHeader.packedLength == 0
 		)
 	{
 		return false;
-	} else if(loadFlags == onlyVerifyHeader)
+	}
+	if(loadFlags == onlyVerifyHeader)
 	{
 		return true;
 	}
@@ -1034,7 +1030,7 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
 	FileReader::PinnedRawDataView filePackedView = file.GetPinnedRawDataView(fileHeader.packedLength);
 
 #ifndef MPT_BUILD_FUZZER
-	if(fileHeader.crc32 != crc32(0, mpt::byte_cast<const Bytef*>(filePackedView.data()), filePackedView.size()))
+	if(fileHeader.crc32 != crc32(0, mpt::byte_cast<const Bytef*>(filePackedView.data()), static_cast<uint32>(filePackedView.size())))
 	{
 		return false;
 	}
@@ -1043,10 +1039,9 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
 	// Header is valid, now unpack the RIFF AM file using inflate
 	uLongf destSize = fileHeader.unpackedLength;
 	std::vector<Bytef> amFileData(destSize);
-	int retVal = uncompress(&amFileData[0], &destSize, mpt::byte_cast<const Bytef*>(filePackedView.data()), filePackedView.size());
+	int retVal = uncompress(amFileData.data(), &destSize, mpt::byte_cast<const Bytef*>(filePackedView.data()), static_cast<uint32>(filePackedView.size()));
 
 	bool result = false;
-
 #ifndef MPT_BUILD_FUZZER
 	if(destSize == fileHeader.unpackedLength && retVal == Z_OK)
 #endif
@@ -1055,7 +1050,6 @@ bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
 		FileReader amFile(mpt::as_span(amFileData));
 		result = ReadAM(amFile, loadFlags);
 	}
-
 	return result;
 
 #endif
diff --git a/soundlib/mod_specifications.cpp b/soundlib/mod_specifications.cpp
index db11a10..ea32108 100644
--- a/soundlib/mod_specifications.cpp
+++ b/soundlib/mod_specifications.cpp
@@ -8,7 +8,7 @@
  */
 
 
-#include <stdafx.h>
+#include "stdafx.h"
 #include "mod_specifications.h"
 #include "../common/misc_util.h"
 #include <algorithm>
@@ -24,7 +24,7 @@ namespace ModSpecs
 #define SongFlag FlagSet<SongFlags>::store_type
 
 
-const CModSpecifications mptm =
+MPT_CONSTEXPR11_VAR CModSpecifications mptm_ =
 {
 	/*
 	TODO: Proper, less arbitrarily chosen values here.
@@ -51,10 +51,11 @@ const CModSpecifications mptm =
 	12,											// Max sample filename length
 	25,											// Max instrument name length
 	12,											// Max instrument filename length
+	0,											// Max comment line length
 	3999,										// SamplesMax
 	255,										// instrumentMax
 	mixLevels1_17RC3,							// defaultMixLevels
-	SongFlag(0) | SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX | SONG_EMBEDMIDICFG,	// Supported song flags
+	SongFlag(0) | SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX,	// Supported song flags
 	200,										// Max MIDI mapping directives
 	MAX_ENVPOINTS,								// Envelope point count
 	true,										// Has notecut.
@@ -78,7 +79,7 @@ const CModSpecifications mptm =
 
 
 
-const CModSpecifications mod =
+MPT_CONSTEXPR11_VAR CModSpecifications mod_ =
 {
 	MOD_TYPE_MOD,								// Internal MODTYPE value
 	"mod",										// File extension
@@ -100,10 +101,11 @@ const CModSpecifications mod =
 	0,											// Max sample filename length
 	0,											// Max instrument name length
 	0,											// Max instrument filename length
+	0,											// Max comment line length
 	31,											// SamplesMax
 	0,											// instrumentMax
 	mixLevelsCompatible,						// defaultMixLevels
-	SongFlag(0) | SONG_PT_MODE | SONG_AMIGALIMITS,	// Supported song flags
+	SongFlag(0) | SONG_PT_MODE | SONG_AMIGALIMITS | SONG_ISAMIGA,	// Supported song flags
 	0,											// Max MIDI mapping directives
 	0,											// No instrument envelopes
 	false,										// No notecut.
@@ -125,7 +127,7 @@ const CModSpecifications mod =
 };
 
 
-const CModSpecifications xm =
+MPT_CONSTEXPR11_VAR CModSpecifications xm_ =
 {
 	MOD_TYPE_XM,								// Internal MODTYPE value
 	"xm",										// File extension
@@ -147,6 +149,7 @@ const CModSpecifications xm =
 	0,											// Max sample filename length
 	22,											// Max instrument name length
 	0,											// Max instrument filename length
+	0,											// Max comment line length
 	128 * 16,									// SamplesMax (actually 16 per instrument)
 	128,										// instrumentMax
 	mixLevelsCompatibleFT2,						// defaultMixLevels
@@ -172,7 +175,7 @@ const CModSpecifications xm =
 };
 
 // XM with MPT extensions
-const CModSpecifications xmEx =
+MPT_CONSTEXPR11_VAR CModSpecifications xmEx_ =
 {
 	MOD_TYPE_XM,								// Internal MODTYPE value
 	"xm",										// File extension
@@ -194,10 +197,11 @@ const CModSpecifications xmEx =
 	0,											// Max sample filename length
 	22,											// Max instrument name length
 	0,											// Max instrument filename length
+	0,											// Max comment line length
 	MAX_SAMPLES - 1,							// SamplesMax (actually 32 per instrument(256 * 32 = 8192), but limited to MAX_SAMPLES = 4000)
 	255,										// instrumentMax
 	mixLevelsCompatibleFT2,						// defaultMixLevels
-	SongFlag(0) | SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_EMBEDMIDICFG,	// Supported song flags
+	SongFlag(0) | SONG_LINEARSLIDES | SONG_EXFILTERRANGE,	// Supported song flags
 	200,										// Max MIDI mapping directives
 	12,											// Envelope point count
 	false,										// No notecut.
@@ -218,7 +222,7 @@ const CModSpecifications xmEx =
 	" vpcdabuhlrg????",							// Supported Volume Column commands
 };
 
-const CModSpecifications s3m =
+MPT_CONSTEXPR11_VAR CModSpecifications s3m_ =
 {
 	MOD_TYPE_S3M,								// Internal MODTYPE value
 	"s3m",										// File extension
@@ -240,6 +244,7 @@ const CModSpecifications s3m =
 	12,											// Max sample filename length
 	0,											// Max instrument name length
 	0,											// Max instrument filename length
+	0,											// Max comment line length
 	99,											// SamplesMax
 	0,											// instrumentMax
 	mixLevelsCompatible,						// defaultMixLevels
@@ -265,7 +270,7 @@ const CModSpecifications s3m =
 };
 
 // S3M with MPT extensions
-const CModSpecifications s3mEx =
+MPT_CONSTEXPR11_VAR CModSpecifications s3mEx_ =
 {
 	MOD_TYPE_S3M,								// Internal MODTYPE value
 	"s3m",										// File extension
@@ -287,6 +292,7 @@ const CModSpecifications s3mEx =
 	12,											// Max sample filename length
 	0,											// Max instrument name length
 	0,											// Max instrument filename length
+	0,											// Max comment line length
 	99,											// SamplesMax
 	0,											// instrumentMax
 	mixLevelsCompatible,						// defaultMixLevels
@@ -311,7 +317,7 @@ const CModSpecifications s3mEx =
 	" vp?????????????",							// Supported Volume Column commands
 };
 
-const CModSpecifications it =
+MPT_CONSTEXPR11_VAR CModSpecifications it_ =
 {
 	MOD_TYPE_IT,								// Internal MODTYPE value
 	"it",										// File extension
@@ -333,10 +339,11 @@ const CModSpecifications it =
 	12,											// Max sample filename length
 	25,											// Max instrument name length
 	12,											// Max instrument filename length
+	75,											// Max comment line length
 	99,											// SamplesMax
 	99,											// instrumentMax
 	mixLevelsCompatible,						// defaultMixLevels
-	SongFlag(0) | SONG_LINEARSLIDES | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX | SONG_EMBEDMIDICFG,	// Supported song flags
+	SongFlag(0) | SONG_LINEARSLIDES | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX,	// Supported song flags
 	0,											// Max MIDI mapping directives
 	25,											// Envelope point count
 	true,										// Has notecut.
@@ -357,7 +364,7 @@ const CModSpecifications it =
 	" vpcdab?h??gfe??",							// Supported Volume Column commands
 };
 
-const CModSpecifications itEx =
+MPT_CONSTEXPR11_VAR CModSpecifications itEx_ =
 {
 	MOD_TYPE_IT,								// Internal MODTYPE value
 	"it",										// File extension
@@ -379,10 +386,11 @@ const CModSpecifications itEx =
 	12,											// Max sample filename length
 	25,											// Max instrument name length
 	12,											// Max instrument filename length
+	75,											// Max comment line length
 	3999,										// SamplesMax
 	255,										// instrumentMax
 	mixLevelsCompatible,						// defaultMixLevels
-	SongFlag(0) | SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX | SONG_EMBEDMIDICFG,	// Supported song flags
+	SongFlag(0) | SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX,	// Supported song flags
 	200,										// Max MIDI mapping directives
 	25,											// Envelope point count
 	true,										// Has notecut.
@@ -403,13 +411,21 @@ const CModSpecifications itEx =
 	" vpcdab?h??gfe??",							// Supported Volume Column commands
 };
 
-const CModSpecifications *Collection[] = { &mptm, &mod, &s3m, &s3mEx, &xm, &xmEx, &it, &itEx };
+const CModSpecifications *Collection[8] = { &mptm_, &mod_, &s3m_, &s3mEx_, &xm_, &xmEx_, &it_, &itEx_ };
+
+const CModSpecifications & mptm = mptm_;
+const CModSpecifications & mod = mod_;
+const CModSpecifications & s3m = s3m_;
+const CModSpecifications & s3mEx = s3mEx_;
+const CModSpecifications & xm = xm_;
+const CModSpecifications & xmEx = xmEx_;
+const CModSpecifications & it = it_;
+const CModSpecifications & itEx = itEx_;
 
 } // namespace ModSpecs
 
 
 MODTYPE CModSpecifications::ExtensionToType(std::string ext)
-//----------------------------------------------------------
 {
 	if(ext == "")
 	{
@@ -432,7 +448,6 @@ MODTYPE CModSpecifications::ExtensionToType(std::string ext)
 
 
 bool CModSpecifications::HasNote(ModCommand::NOTE note) const
-//-----------------------------------------------------------
 {
 	if(note >= noteMin && note <= noteMax)
 		return true;
@@ -453,7 +468,6 @@ bool CModSpecifications::HasNote(ModCommand::NOTE note) const
 
 
 bool CModSpecifications::HasVolCommand(ModCommand::VOLCMD volcmd) const
-//---------------------------------------------------------------------
 {
 	if(volcmd >= MAX_VOLCMDS) return false;
 	if(volcommands[volcmd] == '?') return false;
@@ -462,7 +476,6 @@ bool CModSpecifications::HasVolCommand(ModCommand::VOLCMD volcmd) const
 
 
 bool CModSpecifications::HasCommand(ModCommand::COMMAND cmd) const
-//----------------------------------------------------------------
 {
 	if(cmd >= MAX_EFFECTS) return false;
 	if(commands[cmd] == '?') return false;
@@ -471,7 +484,6 @@ bool CModSpecifications::HasCommand(ModCommand::COMMAND cmd) const
 
 
 char CModSpecifications::GetVolEffectLetter(ModCommand::VOLCMD volcmd) const
-//--------------------------------------------------------------------------
 {
 	if(volcmd >= MAX_VOLCMDS) return '?';
 	return volcommands[volcmd];
@@ -479,7 +491,6 @@ char CModSpecifications::GetVolEffectLetter(ModCommand::VOLCMD volcmd) const
 
 
 char CModSpecifications::GetEffectLetter(ModCommand::COMMAND cmd) const
-//---------------------------------------------------------------------
 {
 	if(cmd >= MAX_EFFECTS) return '?';
 	return commands[cmd];
diff --git a/soundlib/mod_specifications.h b/soundlib/mod_specifications.h
index bb8f517..c7c01d7 100644
--- a/soundlib/mod_specifications.h
+++ b/soundlib/mod_specifications.h
@@ -18,9 +18,7 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-//=======================
 struct CModSpecifications
-//=======================
 {
 	/// Returns modtype corresponding to given file extension. The extension string
 	/// may begin with or without dot, e.g. both ".it" and "it" will be handled correctly.
@@ -36,7 +34,7 @@ struct CModSpecifications
 
 	// NOTE: If changing order, update all initializations in .cpp file.
 	MODTYPE internalType;				// Internal MODTYPE value
-	char fileExtension[6];				// File extension without dot.
+	const char *fileExtension;			// File extension without dot.
 	ModCommand::NOTE noteMin;			// Minimum note index (index starts from 1)
 	ModCommand::NOTE noteMax;			// Maximum note index (index starts from 1)
 	PATTERNINDEX patternsMax;
@@ -55,6 +53,7 @@ struct CModSpecifications
 	uint16 sampleFilenameLengthMax;		// Ditto
 	uint16 instrNameLengthMax;			// Ditto
 	uint16 instrFilenameLengthMax;		// Ditto
+	uint16 commentLineLengthMax;		// not including line break, 0 for unlimited
 	SAMPLEINDEX samplesMax;				// Max number of samples == Highest possible sample index
 	INSTRUMENTINDEX instrumentsMax;		// Max number of instruments == Highest possible instrument index
 	MixLevels defaultMixLevels;			// Default mix levels that are used when creating a new file in this format
@@ -62,38 +61,38 @@ struct CModSpecifications
 	uint8 MIDIMappingDirectivesMax;		// Number of MIDI Mapping directives that the format can store (0 = none)
 	uint8 envelopePointsMax;			// Maximum number of points of each envelope
 	//	Work around a possible code generation bug in MSVC10 with boolean bitfields by using uint8
-	uint8 hasNoteCut : 1;				// True if format has note cut (^^).
-	uint8 hasNoteOff : 1;				// True if format has note off (==).
-	uint8 hasNoteFade : 1;				// True if format has note fade (~~).
-	uint8 hasReleaseNode : 1;			// Envelope release node
-	uint8 hasComments : 1;				// True if format has a comments field
-	uint8 hasIgnoreIndex : 1;			// Does "+++" pattern exist?
-	uint8 hasStopIndex : 1;				// Does "---" pattern exist?
-	uint8 hasRestartPos : 1;			// Format has an automatic restart order position
-	uint8 supportsPlugins : 1;			// Format can store plugins
-	uint8 hasPatternSignatures : 1;		// Can patterns have a custom time signature?
-	uint8 hasPatternNames : 1;			// Can patterns have a name?
-	uint8 hasArtistName : 1;			// Can artist name be stored in file?
-	uint8 hasDefaultResampling : 1;		// Can default resampling be saved? (if not, it can still be modified in the GUI but won't set the module as modified)
-	uint8 hasFractionalTempo : 1;		// Are fractional tempos allowed?
-	char commands[MAX_EFFECTS + 1];		// An array holding all commands this format supports; commands that are not supported are marked with "?"
-	char volcommands[MAX_VOLCMDS + 1];	// Ditto, but for volume column
-	TEMPO GetTempoMin() const { return TEMPO(tempoMinInt, 0); }
-	TEMPO GetTempoMax() const { return TEMPO(tempoMaxInt, 0); }
-	FlagSet<SongFlags> GetSongFlags() const { return FlagSet<SongFlags>(songFlags); }
+	bool hasNoteCut;					// True if format has note cut (^^).
+	bool hasNoteOff;					// True if format has note off (==).
+	bool hasNoteFade;					// True if format has note fade (~~).
+	bool hasReleaseNode;				// Envelope release node
+	bool hasComments;					// True if format has a comments field
+	bool hasIgnoreIndex;				// Does "+++" pattern exist?
+	bool hasStopIndex;					// Does "---" pattern exist?
+	bool hasRestartPos;					// Format has an automatic restart order position
+	bool supportsPlugins;				// Format can store plugins
+	bool hasPatternSignatures;			// Can patterns have a custom time signature?
+	bool hasPatternNames;				// Can patterns have a name?
+	bool hasArtistName;					// Can artist name be stored in file?
+	bool hasDefaultResampling;			// Can default resampling be saved? (if not, it can still be modified in the GUI but won't set the module as modified)
+	bool hasFractionalTempo;			// Are fractional tempos allowed?
+	const char *commands;				// An array holding all commands this format supports; commands that are not supported are marked with "?"
+	const char *volcommands;			// Ditto, but for volume column
+	MPT_CONSTEXPR11_FUN TEMPO GetTempoMin() const { return TEMPO(tempoMinInt, 0); }
+	MPT_CONSTEXPR11_FUN TEMPO GetTempoMax() const { return TEMPO(tempoMaxInt, 0); }
+	MPT_CONSTEXPR11_FUN FlagSet<SongFlags> GetSongFlags() const { return FlagSet<SongFlags>(songFlags); }
 };
 
 
 namespace ModSpecs
 {
-	extern const CModSpecifications mptm;
-	extern const CModSpecifications mod;
-	extern const CModSpecifications s3m;
-	extern const CModSpecifications s3mEx;
-	extern const CModSpecifications xm;
-	extern const CModSpecifications xmEx;
-	extern const CModSpecifications it;
-	extern const CModSpecifications itEx;
+	extern const CModSpecifications & mptm;
+	extern const CModSpecifications & mod;
+	extern const CModSpecifications & s3m;
+	extern const CModSpecifications & s3mEx;
+	extern const CModSpecifications & xm;
+	extern const CModSpecifications & xmEx;
+	extern const CModSpecifications & it;
+	extern const CModSpecifications & itEx;
 	extern const CModSpecifications *Collection[8];
 }
 
diff --git a/soundlib/modcommand.cpp b/soundlib/modcommand.cpp
index 01ae229..b616736 100644
--- a/soundlib/modcommand.cpp
+++ b/soundlib/modcommand.cpp
@@ -47,7 +47,6 @@ STATIC_ASSERT(CountOf(volumeEffectTypes) == MAX_VOLCMDS);
 
 
 EffectType ModCommand::GetEffectType(COMMAND cmd)
-//-----------------------------------------------
 {
 	if(cmd < CountOf(effectTypes))
 	{
@@ -60,7 +59,6 @@ EffectType ModCommand::GetEffectType(COMMAND cmd)
 
 
 EffectType ModCommand::GetVolumeEffectType(VOLCMD volcmd)
-//-------------------------------------------------------
 {
 	if(volcmd < CountOf(volumeEffectTypes))
 	{
@@ -74,7 +72,6 @@ EffectType ModCommand::GetVolumeEffectType(VOLCMD volcmd)
 
 // Convert an Exx command (MOD) to Sxx command (S3M)
 void ModCommand::ExtendedMODtoS3MEffect()
-//---------------------------------------
 {
 	if(command != CMD_MODCMDEX)
 		return;
@@ -90,8 +87,8 @@ void ModCommand::ExtendedMODtoS3MEffect()
 	case 0x60: param = (param & 0x0F) | 0xB0; break;
 	case 0x70: param = (param & 0x03) | 0x40; break;
 	case 0x90: command = CMD_RETRIG; param = (param & 0x0F); break;
-	case 0xA0: if(param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command = 0; break;
-	case 0xB0: if(param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command = 0; break;
+	case 0xA0: if(param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command = CMD_NONE; break;
+	case 0xB0: if(param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command = CMD_NONE; break;
 	case 0xC0: if(param == 0xC0) { command = CMD_NONE; note = NOTE_NOTECUT; }	// this does different things in IT and ST3
 	case 0xD0: if(param == 0xD0) { command = CMD_NONE; }	// ditto
 	// rest are the same
@@ -101,7 +98,6 @@ void ModCommand::ExtendedMODtoS3MEffect()
 
 // Convert an Sxx command (S3M) to Exx command (MOD)
 void ModCommand::ExtendedS3MtoMODEffect()
-//---------------------------------------
 {
 	if(command != CMD_S3MCMDEX)
 		return;
@@ -126,7 +122,6 @@ void ModCommand::ExtendedS3MtoMODEffect()
 
 // Convert a mod command from one format to another.
 void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &sndFile)
-//-----------------------------------------------------------------------------------
 {
 	if(fromType == toType)
 	{
@@ -250,10 +245,11 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd
 				volcmd = VOLCMD_VOLUME;
 				vol = param;
 				if(vol > 64) vol = 64;
-				command = param = 0;
+				command = CMD_NONE;
+				param = 0;
 			} else if(volcmd == VOLCMD_PANNING)
 			{
-				SwapEffects();
+				std::swap(vol, param);
 				volcmd = VOLCMD_VOLUME;
 				if(vol > 64) vol = 64;
 				command = CMD_S3MCMDEX;
@@ -648,7 +644,7 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd
 				param = vol << 4;
 				break;
 		}
-		volcmd = CMD_NONE;
+		volcmd = VOLCMD_NONE;
 	} // End if(newTypeIsMOD)
 
 	///////////////////////////////////////////////////
@@ -660,67 +656,67 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd
 			case VOLCMD_VOLSLIDEDOWN:
 				command = CMD_VOLUMESLIDE;
 				param = vol;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_VOLSLIDEUP:
 				command = CMD_VOLUMESLIDE;
 				param = vol << 4;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_FINEVOLDOWN:
 				command = CMD_VOLUMESLIDE;
 				param = 0xF0 | vol;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_FINEVOLUP:
 				command = CMD_VOLUMESLIDE;
 				param = (vol << 4) | 0x0F;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_PORTADOWN:
 				command = CMD_PORTAMENTODOWN;
 				param = vol << 2;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_PORTAUP:
 				command = CMD_PORTAMENTOUP;
 				param = vol << 2;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_TONEPORTAMENTO:
 				command = CMD_TONEPORTAMENTO;
 				param = vol << 2;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_VIBRATODEPTH:
 				command = CMD_VIBRATO;
 				param = vol;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_VIBRATOSPEED:
 				command = CMD_VIBRATO;
 				param = vol << 4;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_PANSLIDELEFT:
 				command = CMD_PANNINGSLIDE;
 				param = vol << 4;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 
 			case VOLCMD_PANSLIDERIGHT:
 				command = CMD_PANNINGSLIDE;
 				param = vol;
-				volcmd = CMD_NONE;
+				volcmd = VOLCMD_NONE;
 				break;
 		}
 	} // End if(newTypeIsS3M)
@@ -732,7 +728,8 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd
 		// remove EDx if no note is next to it, or it will retrigger the note in FT2 mode
 		if(command == CMD_MODCMDEX && (param & 0xF0) == 0xD0 && note == NOTE_NONE)
 		{
-			command = param = 0;
+			command = CMD_NONE;
+			param = 0;
 		}
 
 		if(IsSpecialNote())
@@ -853,10 +850,51 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd
 }
 
 
+bool ModCommand::IsGlobalCommand() const
+{
+	switch(command)
+	{
+	case CMD_POSITIONJUMP:
+	case CMD_PATTERNBREAK:
+	case CMD_SPEED:
+	case CMD_TEMPO:
+	case CMD_GLOBALVOLUME:
+	case CMD_GLOBALVOLSLIDE:
+	case CMD_MIDI:
+	case CMD_SMOOTHMIDI:
+	case CMD_DBMECHO:
+		return true;
+	case CMD_MODCMDEX:
+		switch(param & 0xF0)
+		{
+		case 0x00:	// LED Filter
+		case 0x60:	// Pattern Loop
+		case 0xE0:	// Row Delay
+			return true;
+		default:
+			return false;
+		}
+	case CMD_XFINEPORTAUPDOWN:
+	case CMD_S3MCMDEX:
+		switch(param & 0xF0)
+		{
+		case 0x60:	// Tick Delay
+		case 0x90:	// Sound Control
+		case 0xB0:	// Pattern Loop
+		case 0xE0:	// Row Delay
+			return true;
+		default:
+			return false;
+		}
+
+	default:
+		return false;
+	}
+}
+
 // "Importance" of every FX command. Table is used for importing from formats with multiple effect colums
 // and is approximately the same as in SchismTracker.
 size_t ModCommand::GetEffectWeight(COMMAND cmd)
-//---------------------------------------------
 {
 	// Effect weights, sorted from lowest to highest weight.
 	static const COMMAND weights[] =
@@ -924,7 +962,6 @@ size_t ModCommand::GetEffectWeight(COMMAND cmd)
 // If moving the command into the volume column is more important than accuracy, use force = true.
 // (Code translated from SchismTracker and mainly supposed to be used with loaders ported from this tracker)
 bool ModCommand::ConvertVolEffect(uint8 &effect, uint8 &param, bool force)
-//------------------------------------------------------------------------
 {
 	switch(effect)
 	{
@@ -1039,7 +1076,6 @@ bool ModCommand::ConvertVolEffect(uint8 &effect, uint8 &param, bool force)
 
 // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1.
 bool ModCommand::CombineEffects(uint8 &eff1, uint8 &param1, uint8 &eff2, uint8 &param2)
-//-------------------------------------------------------------------------------------
 {
 	if(eff1 == CMD_VOLUMESLIDE && (eff2 == CMD_VIBRATO || eff2 == CMD_TONEPORTAVOL) && param2 == 0)
 	{
@@ -1087,7 +1123,6 @@ bool ModCommand::CombineEffects(uint8 &eff1, uint8 &param1, uint8 &eff2, uint8 &
 
 
 bool ModCommand::TwoRegularCommandsToMPT(uint8 &effect1, uint8 &param1, uint8 &effect2, uint8 &param2)
-//----------------------------------------------------------------------------------------------------
 {
 	for(uint8 n = 0; n < 4; n++)
 	{
diff --git a/soundlib/modcommand.h b/soundlib/modcommand.h
index f1e1f63..f9d717f 100644
--- a/soundlib/modcommand.h
+++ b/soundlib/modcommand.h
@@ -1,7 +1,7 @@
 /*
  * ModCommand.h
  * ------------
- * Purpose: Moduel Command (pattern content) header class and helpers. One Module Command corresponds to one pattern cell.
+ * Purpose: ModCommand declarations and helpers. One ModCommand corresponds to one pattern cell.
  * Notes  : (currently none)
  * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
@@ -11,11 +11,8 @@
 #pragma once
 
 #include "Snd_defs.h"
-
 #include "../common/misc_util.h"
 
-#include <cstring>
-
 OPENMPT_NAMESPACE_BEGIN
 
 class CSoundFile;
@@ -35,7 +32,7 @@ class CSoundFile;
 
 
 // Volume Column commands
-enum VolumeCommands
+enum VolumeCommand : uint8
 {
 	VOLCMD_NONE				= 0,
 	VOLCMD_VOLUME			= 1,
@@ -58,7 +55,7 @@ enum VolumeCommands
 
 
 // Effect column commands
-enum EffectCommands
+enum EffectCommand : uint8
 {
 	CMD_NONE				= 0,
 	CMD_ARPEGGIO			= 1,
@@ -106,7 +103,7 @@ enum EffectCommands
 };
 
 
-enum EffectType
+enum EffectType : uint8
 {
 	EFFECT_TYPE_NORMAL  = 0,
 	EFFECT_TYPE_GLOBAL  = 1,
@@ -117,9 +114,7 @@ enum EffectType
 };
 
 
-//==============
 class ModCommand
-//==============
 {
 public:
 	typedef uint8 NOTE;
@@ -134,7 +129,7 @@ public:
 	static const int maxColumnValue = 999;
 
 	// Returns empty modcommand.
-	static ModCommand Empty() { ModCommand m = { 0, 0, 0, 0, 0, 0 }; return m; }
+	static ModCommand Empty() { ModCommand m = { 0, 0, VOLCMD_NONE, CMD_NONE, 0, 0 }; return m; }
 
 	bool operator==(const ModCommand& mc) const
 	{
@@ -151,11 +146,11 @@ public:
 
 	uint16 GetValueVolCol() const { return GetValueVolCol(volcmd, vol); }
 	static uint16 GetValueVolCol(uint8 volcmd, uint8 vol) { return (volcmd << 8) + vol; }
-	void SetValueVolCol(const uint16 val) { volcmd = static_cast<uint8>(val >> 8); vol = static_cast<uint8>(val & 0xFF); }
+	void SetValueVolCol(const uint16 val) { volcmd = static_cast<VOLCMD>(val >> 8); vol = static_cast<uint8>(val & 0xFF); }
 
 	uint16 GetValueEffectCol() const { return GetValueEffectCol(command, param); }
 	static uint16 GetValueEffectCol(uint8 command, uint8 param) { return (command << 8) + param; }
-	void SetValueEffectCol(const uint16 val) { command = static_cast<uint8>(val >> 8); param = static_cast<uint8>(val & 0xFF); }
+	void SetValueEffectCol(const uint16 val) { command = static_cast<COMMAND>(val >> 8); param = static_cast<uint8>(val & 0xFF); }
 
 	// Clears modcommand.
 	void Clear() { memset(this, 0, sizeof(ModCommand)); }
@@ -174,8 +169,8 @@ public:
 	static bool IsPcNote(const NOTE note_id) { return note_id == NOTE_PC || note_id == NOTE_PCS; }
 
 	// Returns true if and only if note is a valid musical note.
-	bool IsNote() const { return note >= NOTE_MIN && note <= NOTE_MAX; }
-	static bool IsNote(NOTE note) { return note >= NOTE_MIN && note <= NOTE_MAX; }
+	bool IsNote() const { return IsInRange(note, NOTE_MIN, NOTE_MAX); }
+	static bool IsNote(NOTE note) { return IsInRange(note, NOTE_MIN, NOTE_MAX); }
 	// Returns true if and only if note is a valid special note.
 	bool IsSpecialNote() const { return IsInRange(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); }
 	static bool IsSpecialNote(NOTE note) { return IsInRange(note, NOTE_MIN_SPECIAL, NOTE_MAX_SPECIAL); }
@@ -184,6 +179,12 @@ public:
 	static bool IsNoteOrEmpty(NOTE note) { return note == NOTE_NONE || IsNote(note); }
 	// Returns true if any of the commands in this cell trigger a tone portamento.
 	bool IsPortamento() const { return command == CMD_TONEPORTAMENTO || command == CMD_TONEPORTAVOL || volcmd == VOLCMD_TONEPORTAMENTO; }
+	// Returns true if the cell contains an effect command that may affect the global state of the module.
+	bool IsGlobalCommand() const;
+
+	// Returns true if the note is inside the Amiga frequency range
+	bool IsAmigaNote() const { return IsAmigaNote(note); }
+	static bool IsAmigaNote(NOTE note) { return !IsNote(note) || (note >= NOTE_MIDDLEC - 12 && note < NOTE_MIDDLEC + 24); }
 
 	static EffectType GetEffectType(COMMAND cmd);
 	EffectType GetEffectType() const { return GetEffectType(command); }
@@ -207,13 +208,6 @@ public:
 	// Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1.
 	static bool CombineEffects(uint8 &eff1, uint8 &param1, uint8 &eff2, uint8 &param2);
 
-	// Swap volume and effect column (doesn't do any conversion as it's mainly for importing formats with multiple effect columns, so beware!)
-	void SwapEffects()
-	{
-		std::swap(volcmd, command);
-		std::swap(vol, param);
-	}
-
 public:
 	uint8 note;
 	uint8 instr;
@@ -223,6 +217,4 @@ public:
 	uint8 param;
 };
 
-typedef ModCommand MODCOMMAND_ORIGINAL;
-
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/modsmp_ctrl.cpp b/soundlib/modsmp_ctrl.cpp
index 5df4ac8..5edf2f7 100644
--- a/soundlib/modsmp_ctrl.cpp
+++ b/soundlib/modsmp_ctrl.cpp
@@ -12,7 +12,8 @@
 #include "modsmp_ctrl.h"
 #include "AudioCriticalSection.h"
 #include "Sndfile.h"
-#include "SampleFormatConverters.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
 
 #define new DEBUG_NEW
 
@@ -22,7 +23,6 @@ namespace ctrlSmp
 {
 
 void ReplaceSample(ModSample &smp, void *pNewSample, const SmpLength nNewLength, CSoundFile &sndFile)
-//---------------------------------------------------------------------------------------------------
 {
 	void * const pOldSmp = smp.pSample;
 	FlagSet<ChannelFlags> setFlags, resetFlags;
@@ -35,7 +35,7 @@ void ReplaceSample(ModSample &smp, void *pNewSample, const SmpLength nNewLength,
 
 	CriticalSection cs;
 
-	ctrlChn::ReplaceSample(sndFile.m_PlayState.Chn, smp, pNewSample, nNewLength, setFlags, resetFlags);
+	ctrlChn::ReplaceSample(sndFile, smp, pNewSample, nNewLength, setFlags, resetFlags);
 	smp.pSample = pNewSample;
 	smp.nLength = nNewLength;
 	ModSample::FreeSample(pOldSmp);
@@ -43,7 +43,6 @@ void ReplaceSample(ModSample &smp, void *pNewSample, const SmpLength nNewLength,
 
 
 SmpLength InsertSilence(ModSample &smp, const SmpLength nSilenceLength, const SmpLength nStartFrom, CSoundFile &sndFile)
-//----------------------------------------------------------------------------------------------------------------------
 {
 	if(nSilenceLength == 0 || nSilenceLength > MAX_SAMPLE_LENGTH || smp.nLength > MAX_SAMPLE_LENGTH - nSilenceLength || nStartFrom > smp.nLength)
 		return smp.nLength;
@@ -111,7 +110,6 @@ namespace
 }
 
 SmpLength RemoveRange(ModSample &smp, SmpLength selStart, SmpLength selEnd, CSoundFile &sndFile)
-//----------------------------------------------------------------------------------------------
 {
 	LimitMax(selEnd, smp.nLength);
 	if(selEnd <= selStart)
@@ -140,7 +138,6 @@ SmpLength RemoveRange(ModSample &smp, SmpLength selStart, SmpLength selEnd, CSou
 
 
 SmpLength ResizeSample(ModSample &smp, const SmpLength nNewLength, CSoundFile &sndFile)
-//-------------------------------------------------------------------------------------
 {
 	// Invalid sample size
 	if(nNewLength > MAX_SAMPLE_LENGTH || nNewLength == smp.nLength)
@@ -208,7 +205,6 @@ public:
 	}
 
 	void CopyLoop(bool direction) const
-	//---------------------------------
 	{
 		// Direction: true = start reading and writing forward, false = start reading and writing backward (write direction never changes)
 		const int numSamples = 2 * InterpolationMaxLookahead + (direction ? 1 : 0);	// Loop point is included in forward loop expansion
@@ -261,7 +257,6 @@ public:
 
 template<typename T>
 void PrecomputeLoopsImpl(ModSample &smp, const CSoundFile &sndFile)
-//-----------------------------------------------------------------
 {
 	const int numChannels = smp.GetNumChannels();
 	const int copySamples = numChannels * InterpolationMaxLookahead;
@@ -306,7 +301,6 @@ void PrecomputeLoopsImpl(ModSample &smp, const CSoundFile &sndFile)
 
 
 bool PrecomputeLoops(ModSample &smp, CSoundFile &sndFile, bool updateChannels)
-//----------------------------------------------------------------------------
 {
 	if(smp.nLength == 0 || smp.pSample == nullptr)
 		return false;
@@ -330,7 +324,6 @@ bool PrecomputeLoops(ModSample &smp, CSoundFile &sndFile, bool updateChannels)
 
 // Propagate loop point changes to player
 bool UpdateLoopPoints(const ModSample &smp, CSoundFile &sndFile)
-//--------------------------------------------------------------
 {
 	if(!smp.HasSampleData())
 		return false;
@@ -338,10 +331,9 @@ bool UpdateLoopPoints(const ModSample &smp, CSoundFile &sndFile)
 	CriticalSection cs;
 
 	// Update channels with new loop values
-	for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) if((sndFile.m_PlayState.Chn[i].pModSample == &smp) && sndFile.m_PlayState.Chn[i].nLength != 0)
+	for(auto &chn : sndFile.m_PlayState.Chn) if((chn.pModSample == &smp) && chn.nLength != 0)
 	{
 		bool looped = false, bidi = false;
-		ModChannel &chn = sndFile.m_PlayState.Chn[i];
 
 		if(smp.nSustainStart < smp.nSustainEnd && smp.nSustainEnd <= smp.nLength && smp.uFlags[CHN_SUSTAINLOOP] && !chn.dwFlags[CHN_KEYOFF])
 		{
@@ -363,12 +355,15 @@ bool UpdateLoopPoints(const ModSample &smp, CSoundFile &sndFile)
 		chn.dwFlags.set(CHN_LOOP, looped);
 		chn.dwFlags.set(CHN_PINGPONGLOOP, looped && bidi);
 
-		if(chn.nPos > chn.nLength)
+		if(chn.position.GetUInt() > chn.nLength)
+		{
+			chn.position.Set(chn.nLoopStart);
+			chn.dwFlags.reset(CHN_PINGPONGFLAG);
+		}
+		if(!bidi)
 		{
-			chn.nPos = chn.nLoopStart;
 			chn.dwFlags.reset(CHN_PINGPONGFLAG);
 		}
-		
 		if(!looped)
 		{
 			chn.nLength = smp.nLength;
@@ -380,7 +375,6 @@ bool UpdateLoopPoints(const ModSample &smp, CSoundFile &sndFile)
 
 
 void ResetSamples(CSoundFile &sndFile, ResetFlag resetflag, SAMPLEINDEX minSample, SAMPLEINDEX maxSample)
-//-------------------------------------------------------------------------------------------------------
 {
 	if(minSample == SAMPLEINDEX_INVALID)
 	{
@@ -417,7 +411,7 @@ void ResetSamples(CSoundFile &sndFile, ResetFlag resetflag, SAMPLEINDEX minSampl
 			sample.nVibRate = 0;
 			sample.nVibSweep = 0;
 			sample.nVibType = 0;
-			sample.uFlags.reset(CHN_PANNING);
+			sample.uFlags.reset(CHN_PANNING | SMP_NODEFAULTVOLUME);
 			break;
 		case SmpResetVibrato:
 			sample.nVibDepth = 0;
@@ -447,7 +441,6 @@ namespace
 	// DC offset value is average of [-1.0, 1.0[-normalized offset values.
 	template<class T>
 	OffsetData CalculateOffset(const T *pStart, const SmpLength nLength)
-	//------------------------------------------------------------------
 	{
 		OffsetData offsetVals = {0,0,0};
 
@@ -475,7 +468,6 @@ namespace
 
 	template <class T>
 	void RemoveOffsetAndNormalize(T *pStart, const SmpLength nLength, const double dOffset, const double dAmplify)
-	//------------------------------------------------------------------------------------------------------------
 	{
 		T *p = pStart;
 		for(SmpLength i = 0; i < nLength; i++, p++)
@@ -493,7 +485,6 @@ float RemoveDCOffset(ModSample &smp,
 					 SmpLength iEnd,
 					 const MODTYPE modtype,
 					 CSoundFile &sndFile)
-//---------------------------------------
 {
 	if(!smp.HasSampleData())
 		return 0;
@@ -545,15 +536,11 @@ float RemoveDCOffset(ModSample &smp,
 		CriticalSection cs;
 
 		smp.nGlobalVol = std::min(Util::Round<uint16>(smp.nGlobalVol / dAmplify), uint16(64));
-		for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+		for(auto &chn : sndFile.m_PlayState.Chn)
 		{
-			if(sndFile.m_PlayState.Chn[i].pModSample == &smp)
+			if(chn.pModSample == &smp)
 			{
-				sndFile.m_PlayState.Chn[i].nInsVol = smp.nGlobalVol;
-				if(sndFile.m_PlayState.Chn[i].pModInstrument)
-				{
-					sndFile.m_PlayState.Chn[i].nInsVol = (smp.nGlobalVol * sndFile.m_PlayState.Chn[i].pModInstrument->nGlobalVol) >> 6;
-				}
+				chn.UpdateInstrumentVolume(&smp, chn.pModInstrument);
 			}
 		}
 	}
@@ -566,7 +553,6 @@ float RemoveDCOffset(ModSample &smp,
 
 template <class T>
 static void ReverseSampleImpl(T *pStart, const SmpLength nLength)
-//---------------------------------------------------------------
 {
 	for(SmpLength i = 0; i < nLength / 2; i++)
 	{
@@ -576,7 +562,6 @@ static void ReverseSampleImpl(T *pStart, const SmpLength nLength)
 
 // Reverse sample data
 bool ReverseSample(ModSample &smp, SmpLength iStart, SmpLength iEnd, CSoundFile &sndFile)
-//---------------------------------------------------------------------------------------
 {
 	if(!smp.HasSampleData()) return false;
 	if(iEnd == 0 || iStart > smp.nLength || iEnd > smp.nLength)
@@ -604,7 +589,6 @@ bool ReverseSample(ModSample &smp, SmpLength iStart, SmpLength iEnd, CSoundFile
 
 template <class T>
 static void UnsignSampleImpl(T *pStart, const SmpLength nLength)
-//--------------------------------------------------------------
 {
 	const T offset = (std::numeric_limits<T>::min)();
 	for(SmpLength i = 0; i < nLength; i++)
@@ -615,7 +599,6 @@ static void UnsignSampleImpl(T *pStart, const SmpLength nLength)
 
 // Virtually unsign sample data
 bool UnsignSample(ModSample &smp, SmpLength iStart, SmpLength iEnd, CSoundFile &sndFile)
-//--------------------------------------------------------------------------------------
 {
 	if(!smp.HasSampleData()) return false;
 	if(iEnd == 0 || iStart > smp.nLength || iEnd > smp.nLength)
@@ -639,7 +622,6 @@ bool UnsignSample(ModSample &smp, SmpLength iStart, SmpLength iEnd, CSoundFile &
 
 template <class T>
 static void InvertSampleImpl(T *pStart, const SmpLength nLength)
-//--------------------------------------------------------------
 {
 	for(SmpLength i = 0; i < nLength; i++)
 	{
@@ -649,7 +631,6 @@ static void InvertSampleImpl(T *pStart, const SmpLength nLength)
 
 // Invert sample data (flip by 180 degrees)
 bool InvertSample(ModSample &smp, SmpLength iStart, SmpLength iEnd, CSoundFile &sndFile)
-//--------------------------------------------------------------------------------------
 {
 	if(!smp.HasSampleData()) return false;
 	if(iEnd == 0 || iStart > smp.nLength || iEnd > smp.nLength)
@@ -673,7 +654,6 @@ bool InvertSample(ModSample &smp, SmpLength iStart, SmpLength iEnd, CSoundFile &
 
 template <class T>
 static void XFadeSampleImpl(const T *srcIn, const T *srcOut, T *output, const SmpLength fadeLength, double e)
-//-----------------------------------------------------------------------------------------------------------
 {
 	const double length = 1.0 / static_cast<double>(fadeLength);
 	for(SmpLength i = 0; i < fadeLength; i++, srcIn++, srcOut++, output++)
@@ -689,7 +669,6 @@ static void XFadeSampleImpl(const T *srcIn, const T *srcOut, T *output, const Sm
 
 // X-Fade sample data to create smooth loop transitions
 bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterloopFade, bool useSustainLoop, CSoundFile &sndFile)
-//-------------------------------------------------------------------------------------------------------------------------------
 {
 	if(!smp.HasSampleData()) return false;
 	const SmpLength loopStart = useSustainLoop ? smp.nSustainStart : smp.nLoopStart;
@@ -726,7 +705,6 @@ bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterlo
 
 template <class T>
 static void SilenceSampleImpl(T *p, SmpLength length, SmpLength inc, bool fromStart, bool toEnd)
-//----------------------------------------------------------------------------------------------
 {
 	const int dest = toEnd ? 0 : p[(length - 1) * inc];
 	const int base = fromStart ? 0 :p[0];
@@ -742,7 +720,6 @@ static void SilenceSampleImpl(T *p, SmpLength length, SmpLength inc, bool fromSt
 
 // X-Fade sample data to create smooth loop transitions
 bool SilenceSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &sndFile)
-//-------------------------------------------------------------------------------------
 {
 	LimitMax(end, smp.nLength);
 	if(!smp.HasSampleData() || start >= end) return false;
@@ -768,8 +745,42 @@ bool SilenceSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &s
 
 
 template <class T>
+static void StereoSepSampleImpl(T *p, SmpLength length, int32 separation)
+{
+	const int32 fac1 = static_cast<int32>(32768 + separation / 2), fac2 = static_cast<int32>(32768 - separation / 2);
+	while(length--)
+	{
+		const int32 l = p[0], r = p[1];
+		p[0] = mpt::saturate_cast<T>((Util::mul32to64(l, fac1) + Util::mul32to64(r, fac2)) >> 16);
+		p[1] = mpt::saturate_cast<T>((Util::mul32to64(l, fac2) + Util::mul32to64(r, fac1)) >> 16);
+		p += 2;
+	}
+}
+
+// X-Fade sample data to create smooth loop transitions
+bool StereoSepSample(ModSample &smp, SmpLength start, SmpLength end, double separation, CSoundFile &sndFile)
+{
+	LimitMax(end, smp.nLength);
+	if(!smp.HasSampleData() || start >= end || smp.GetNumChannels() != 2) return false;
+
+	const SmpLength length = end - start;
+	const uint8 numChn = smp.GetNumChannels();
+	const int32 sep32 = Util::Round<int32>(separation * (65536.0 / 100.0));
+
+	if(smp.GetElementarySampleSize() == 2)
+		StereoSepSampleImpl(smp.pSample16 + start * numChn, length, sep32);
+	else if(smp.GetElementarySampleSize() == 1)
+		StereoSepSampleImpl(smp.pSample8 + start * numChn, length, sep32);
+	else
+		return false;
+
+	PrecomputeLoops(smp, sndFile, false);
+	return true;
+}
+
+
+template <class T>
 static void ConvertStereoToMonoMixImpl(T *pDest, const SmpLength length)
-//----------------------------------------------------------------------
 {
 	const T *pEnd = pDest + length;
 	for(T *pSource = pDest; pDest != pEnd; pDest++, pSource += 2)
@@ -781,7 +792,6 @@ static void ConvertStereoToMonoMixImpl(T *pDest, const SmpLength length)
 
 template <class T>
 static void ConvertStereoToMonoOneChannelImpl(T *pDest, const SmpLength length)
-//-----------------------------------------------------------------------------
 {
 	const T *pEnd = pDest + length;
 	for(T *pSource = pDest; pDest != pEnd; pDest++, pSource += 2)
@@ -793,7 +803,6 @@ static void ConvertStereoToMonoOneChannelImpl(T *pDest, const SmpLength length)
 
 // Convert a multichannel sample to mono (currently only implemented for stereo)
 bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode conversionMode)
-//--------------------------------------------------------------------------------------
 {
 	if(!smp.HasSampleData() || smp.GetNumChannels() != 2) return false;
 
@@ -822,11 +831,11 @@ bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode convers
 
 	CriticalSection cs;
 	smp.uFlags.reset(CHN_STEREO);
-	for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+	for(auto &chn : sndFile.m_PlayState.Chn)
 	{
-		if(sndFile.m_PlayState.Chn[i].pModSample == &smp)
+		if(chn.pModSample == &smp)
 		{
-			sndFile.m_PlayState.Chn[i].dwFlags.reset(CHN_STEREO);
+			chn.dwFlags.reset(CHN_STEREO);
 		}
 	}
 
@@ -837,7 +846,6 @@ bool ConvertToMono(ModSample &smp, CSoundFile &sndFile, StereoToMonoMode convers
 
 template <class T>
 static void ConvertMonoToStereoImpl(const T * MPT_RESTRICT src, T * MPT_RESTRICT dst, SmpLength length)
-//-----------------------------------------------------------------------------------------------------
 {
 	while(length--)
 	{
@@ -851,7 +859,6 @@ static void ConvertMonoToStereoImpl(const T * MPT_RESTRICT src, T * MPT_RESTRICT
 
 // Convert a multichannel sample to mono (currently only implemented for stereo)
 bool ConvertToStereo(ModSample &smp, CSoundFile &sndFile)
-//-------------------------------------------------------
 {
 	if(!smp.HasSampleData() || smp.GetNumChannels() != 1) return false;
 
@@ -879,16 +886,15 @@ bool ConvertToStereo(ModSample &smp, CSoundFile &sndFile)
 
 // Convert 16-bit sample to 8-bit
 bool ConvertTo8Bit(ModSample &smp, CSoundFile &sndFile)
-//-----------------------------------------------------
 {
 	if(!smp.HasSampleData() || smp.GetElementarySampleSize() != 2)
 		return false;
 
 	CopySample<SC::ConversionChain<SC::Convert<int8, int16>, SC::DecodeIdentity<int16> > >(smp.pSample8, smp.nLength * smp.GetNumChannels(), 1, smp.pSample16, smp.GetSampleSizeInBytes(), 1);
 	smp.uFlags.reset(CHN_16BIT);
-	for(CHANNELINDEX j = 0; j < MAX_CHANNELS; j++) if(sndFile.m_PlayState.Chn[j].pModSample == &smp)
+	for(auto &chn : sndFile.m_PlayState.Chn) if(chn.pModSample == &smp)
 	{
-		sndFile.m_PlayState.Chn[j].dwFlags.reset(CHN_16BIT);
+		chn.dwFlags.reset(CHN_16BIT);
 	}
 
 	smp.PrecomputeLoops(sndFile, false);
@@ -898,7 +904,6 @@ bool ConvertTo8Bit(ModSample &smp, CSoundFile &sndFile)
 
 // Convert 8-bit sample to 16-bit
 bool ConvertTo16Bit(ModSample &smp, CSoundFile &sndFile)
-//------------------------------------------------------
 {
 	if(!smp.HasSampleData() || smp.GetElementarySampleSize() != 1)
 		return false;
@@ -922,34 +927,44 @@ bool ConvertTo16Bit(ModSample &smp, CSoundFile &sndFile)
 namespace ctrlChn
 {
 
-void ReplaceSample( ModChannel (&Chn)[MAX_CHANNELS],
+void ReplaceSample( CSoundFile &sndFile,
 					const ModSample &sample,
 					const void * const pNewSample,
 					const SmpLength nNewLength,
 					FlagSet<ChannelFlags> setFlags,
 					FlagSet<ChannelFlags> resetFlags)
 {
-	for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
+	const bool periodIsFreq = sndFile.PeriodsAreFrequencies();
+	auto begin = sndFile.m_PlayState.Chn, end = sndFile.m_PlayState.Chn + CountOf(sndFile.m_PlayState.Chn);
+	for (auto chn = begin; chn != end; chn++)
 	{
-		if (Chn[i].pModSample == &sample)
+		if (chn->pModSample == &sample)
 		{
-			if (Chn[i].pCurrentSample != nullptr)
-				Chn[i].pCurrentSample = pNewSample;
-			if (Chn[i].nPos > nNewLength)
-				Chn[i].nPos = 0;
-			if (Chn[i].nLength > 0)
-				LimitMax(Chn[i].nLength, nNewLength);
-			if(Chn[i].InSustainLoop())
+			if (chn->pCurrentSample != nullptr)
+				chn->pCurrentSample = pNewSample;
+			if (chn->position.GetUInt() > nNewLength)
+				chn->position.Set(0);
+			if (chn->nLength > 0)
+				LimitMax(chn->nLength, nNewLength);
+			if(chn->InSustainLoop())
 			{
-				Chn[i].nLoopStart = sample.nSustainStart;
-				Chn[i].nLoopEnd = sample.nSustainEnd;
+				chn->nLoopStart = sample.nSustainStart;
+				chn->nLoopEnd = sample.nSustainEnd;
 			} else
 			{
-				Chn[i].nLoopStart = sample.nLoopStart;
-				Chn[i].nLoopEnd = sample.nLoopEnd;
+				chn->nLoopStart = sample.nLoopStart;
+				chn->nLoopEnd = sample.nLoopEnd;
+			}
+			chn->dwFlags.set(setFlags);
+			chn->dwFlags.reset(resetFlags);
+			if(chn->nC5Speed && sample.nC5Speed && !sndFile.UseFinetuneAndTranspose())
+			{
+				if(periodIsFreq)
+					chn->nPeriod = Util::muldivr_unsigned(chn->nPeriod, sample.nC5Speed, chn->nC5Speed);
+				else
+					chn->nPeriod = Util::muldivr_unsigned(chn->nPeriod, chn->nC5Speed, sample.nC5Speed);
 			}
-			Chn[i].dwFlags.set(setFlags);
-			Chn[i].dwFlags.reset(resetFlags);
+			chn->nC5Speed = sample.nC5Speed;
 		}
 	}
 }
diff --git a/soundlib/modsmp_ctrl.h b/soundlib/modsmp_ctrl.h
index 45113df..d99fbe2 100644
--- a/soundlib/modsmp_ctrl.h
+++ b/soundlib/modsmp_ctrl.h
@@ -85,6 +85,9 @@ bool XFadeSample(ModSample &smp, SmpLength fadeLength, int fadeLaw, bool afterlo
 // Silence parts of the sample data
 bool SilenceSample(ModSample &smp, SmpLength start, SmpLength end, CSoundFile &sndFile);
 
+// Modify stereo separation of the sample data. separation is in range [-200, 200]
+bool StereoSepSample(ModSample &smp, SmpLength start, SmpLength end, double separation, CSoundFile &sndFile);
+
 enum StereoToMonoMode
 {
 	mixChannels,
@@ -111,7 +114,7 @@ namespace ctrlChn
 {
 
 // Replaces sample from sound channels by given sample.
-void ReplaceSample( ModChannel (&Chn)[MAX_CHANNELS],
+void ReplaceSample( CSoundFile &sndFile,
 					const ModSample &sample,
 					const void * const pNewSample,
 					const SmpLength nNewLength,
diff --git a/soundlib/pattern.cpp b/soundlib/pattern.cpp
index 16975e9..99e3a7f 100644
--- a/soundlib/pattern.cpp
+++ b/soundlib/pattern.cpp
@@ -26,7 +26,6 @@ const CSoundFile& CPattern::GetSoundFile() const { return m_rPatternContainer.Ge
 
 
 CHANNELINDEX CPattern::GetNumChannels() const
-//-------------------------------------------
 {
 	return GetSoundFile().GetNumChannels();
 }
@@ -34,9 +33,8 @@ CHANNELINDEX CPattern::GetNumChannels() const
 
 // Check if there is any note data on a given row.
 bool CPattern::IsEmptyRow(ROWINDEX row) const
-//-------------------------------------------
 {
-	if(m_ModCommands == nullptr || !IsValidRow(row))
+	if(m_ModCommands.empty() || !IsValidRow(row))
 	{
 		return true;
 	}
@@ -54,7 +52,6 @@ bool CPattern::IsEmptyRow(ROWINDEX row) const
 
 
 bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure)
-//------------------------------------------------------------------------------------
 {
 	if(rowsPerBeat < 1
 		|| rowsPerBeat > GetSoundFile().GetModSpecifications().patternRowsMax
@@ -70,11 +67,9 @@ bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMe
 
 
 // Add or remove rows from the pattern.
-bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits)
-//-------------------------------------------------------------------------
+bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits, bool resizeAtEnd)
 {
 	CSoundFile &sndFile = GetSoundFile();
-	ModCommand *newPattern;
 
 	if(newRowCount == m_Rows || newRowCount < 1 || newRowCount > MAX_PATTERN_ROWS)
 	{
@@ -82,120 +77,108 @@ bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits)
 	}
 	if(enforceFormatLimits)
 	{
-		const CModSpecifications& specs = sndFile.GetModSpecifications();
+		auto &specs = sndFile.GetModSpecifications();
 		if(newRowCount > specs.patternRowsMax || newRowCount < specs.patternRowsMin) return false;
 	}
 
-	if(m_ModCommands == nullptr
-		|| (newPattern = AllocatePattern(newRowCount, GetNumChannels())) == nullptr)
+	try
 	{
+		size_t count = ((newRowCount > m_Rows) ? (newRowCount - m_Rows) : (m_Rows - newRowCount)) * GetNumChannels();
+
+		if(newRowCount > m_Rows)
+			m_ModCommands.insert(resizeAtEnd ? m_ModCommands.end() : m_ModCommands.begin(), count, ModCommand::Empty());
+		else if(resizeAtEnd)
+			m_ModCommands.erase(m_ModCommands.end() - count, m_ModCommands.end());
+		else
+			m_ModCommands.erase(m_ModCommands.begin(), m_ModCommands.begin() + count);
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		return false;
 	}
 
-	// Copy over pattern data
-	memcpy(newPattern, m_ModCommands, GetNumChannels() * std::min(m_Rows, newRowCount) * sizeof(ModCommand));
-
-	FreePattern(m_ModCommands);
-	m_ModCommands = newPattern;
 	m_Rows = newRowCount;
-
 	return true;
 }
 
 
 void CPattern::ClearCommands()
-//----------------------------
 {
-	if(m_ModCommands != nullptr)
-		memset(m_ModCommands, 0, GetNumRows() * GetNumChannels() * sizeof(ModCommand));
+	std::fill(m_ModCommands.begin(), m_ModCommands.end(), ModCommand::Empty());
 }
 
 
 bool CPattern::AllocatePattern(ROWINDEX rows)
-//-------------------------------------------
 {
-	ModCommand *m = m_ModCommands;
-	if(m != nullptr && rows == GetNumRows())
+	size_t newSize = GetNumChannels() * rows;
+	if(rows == 0)
+	{
+		return false;
+	} else if(rows == GetNumRows() && m_ModCommands.size() == newSize)
 	{
 		// Re-use allocated memory
 		ClearCommands();
-		m_ModCommands = nullptr;
+		return true;
 	} else
 	{
-		m = AllocatePattern(rows, GetNumChannels());
-		if(m == nullptr)
-		{
-			return false;
-		}
+		// Do this in two steps in order to keep the old pattern data in case of OOM
+		decltype(m_ModCommands) newPattern(newSize, ModCommand::Empty());
+		m_ModCommands = std::move(newPattern);
 	}
-	Deallocate();
-	m_ModCommands = m;
 	m_Rows = rows;
 	return true;
 }
 
 
 void CPattern::Deallocate()
-//-------------------------
 {
 	m_Rows = m_RowsPerBeat = m_RowsPerMeasure = 0;
-	FreePattern(m_ModCommands);
-	m_ModCommands = nullptr;
+	m_ModCommands.clear();
 	m_PatternName.clear();
 }
 
 
-#ifdef MODPLUG_TRACKER
-
 bool CPattern::operator== (const CPattern &other) const
-//-----------------------------------------------------
 {
-	if(GetNumRows() != other.GetNumRows()
-		|| GetNumChannels() != other.GetNumChannels()
-		|| GetOverrideSignature() != other.GetOverrideSignature()
-		|| GetRowsPerBeat() != other.GetRowsPerBeat()
-		|| GetRowsPerMeasure() != other.GetRowsPerMeasure()
-		|| GetTempoSwing() != other.GetTempoSwing())
-		return false;
-	if(m_ModCommands == nullptr || other.m_ModCommands == nullptr)
-		return m_ModCommands == other.m_ModCommands;
-
-	uint32 i = GetNumRows() * GetNumChannels();
-	const ModCommand *m1 = m_ModCommands, *m2 = other.m_ModCommands;
-	while(i--)
-	{
-		if(*m1 != *m2)
-		{
-			return false;
-		}
-		m1++;
-		m2++;
-	}
-	return true;
+	return GetNumRows() == other.GetNumRows()
+		&& GetNumChannels() == other.GetNumChannels()
+		&& GetOverrideSignature() == other.GetOverrideSignature()
+		&& GetRowsPerBeat() == other.GetRowsPerBeat()
+		&& GetRowsPerMeasure() == other.GetRowsPerMeasure()
+		&& GetTempoSwing() == other.GetTempoSwing()
+		&& m_ModCommands == other.m_ModCommands;
 }
 
 
+#ifdef MODPLUG_TRACKER
+
 bool CPattern::Expand()
-//---------------------
 {
 	const ROWINDEX newRows = m_Rows * 2;
 	const CHANNELINDEX nChns = GetNumChannels();
-	ModCommand *newPattern;
 
-	if(!m_ModCommands
-		|| newRows > GetSoundFile().GetModSpecifications().patternRowsMax
-		|| (newPattern = AllocatePattern(newRows, nChns)) == nullptr)
+	if(m_ModCommands.empty()
+		|| newRows > GetSoundFile().GetModSpecifications().patternRowsMax)
 	{
 		return false;
 	}
 
-	for(ROWINDEX y = 0; y < m_Rows; y++)
+	decltype(m_ModCommands) newPattern;
+	try
+	{
+		newPattern.assign(m_ModCommands.size() * 2, ModCommand::Empty());
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		return false;
+	}
+
+	for(auto mSrc = m_ModCommands.begin(), mDst = newPattern.begin(); mSrc != m_ModCommands.end(); mSrc += nChns, mDst += 2 * nChns)
 	{
-		memcpy(newPattern + y * 2 * nChns, m_ModCommands + y * nChns, nChns * sizeof(ModCommand));
+		std::copy(mSrc, mSrc + nChns, mDst);
 	}
 
-	FreePattern(m_ModCommands);
-	m_ModCommands = newPattern;
+	m_ModCommands = std::move(newPattern);
 	m_Rows = newRows;
 
 	return true;
@@ -203,9 +186,8 @@ bool CPattern::Expand()
 
 
 bool CPattern::Shrink()
-//---------------------
 {
-	if (!m_ModCommands
+	if (m_ModCommands.empty()
 		|| m_Rows < GetSoundFile().GetModSpecifications().patternRowsMin * 2)
 	{
 		return false;
@@ -245,6 +227,7 @@ bool CPattern::Shrink()
 			}
 		}
 	}
+	m_ModCommands.resize(m_ModCommands.size() / 2);
 
 	return true;
 }
@@ -254,7 +237,6 @@ bool CPattern::Shrink()
 
 
 bool CPattern::SetName(const std::string &newName)
-//------------------------------------------------
 {
 	m_PatternName = newName;
 	return true;
@@ -262,7 +244,6 @@ bool CPattern::SetName(const std::string &newName)
 
 
 bool CPattern::SetName(const char *newName, size_t maxChars)
-//----------------------------------------------------------
 {
 	if(newName == nullptr || maxChars == 0)
 	{
@@ -273,25 +254,11 @@ bool CPattern::SetName(const char *newName, size_t maxChars)
 }
 
 
-bool CPattern::GetName(char *buffer, size_t maxChars) const
-//---------------------------------------------------------
-{
-	if(buffer == nullptr || maxChars == 0)
-	{
-		return false;
-	}
-	strncpy(buffer, m_PatternName.c_str(), maxChars - 1);
-	buffer[maxChars - 1] = '\0';
-	return true;
-}
-
-
 // Write some kind of effect data to the pattern. Exact data to be written and write behaviour can be found in the EffectWriter object.
 bool CPattern::WriteEffect(EffectWriter &settings)
-//------------------------------------------------
 {
 	// First, reject invalid parameters.
-	if(!m_ModCommands
+	if(m_ModCommands.empty()
 		|| settings.m_row >= GetNumRows()
 		|| (settings.m_channel >= GetNumChannels() && settings.m_channel != CHANNELINDEX_INVALID))
 	{
@@ -318,7 +285,7 @@ bool CPattern::WriteEffect(EffectWriter &settings)
 		{
 			if(!settings.m_isVolEffect && m->command == settings.m_command)
 				return true;
-			if(settings.m_isVolEffect && m->volcmd == settings.m_command)
+			if(settings.m_isVolEffect && m->volcmd == settings.m_volcmd)
 				return true;
 		}
 	}
@@ -335,8 +302,8 @@ bool CPattern::WriteEffect(EffectWriter &settings)
 		}
 		if(settings.m_isVolEffect && m->volcmd == VOLCMD_NONE)
 		{
-			m->volcmd = settings.m_command;
-			m->vol = settings.m_param;
+			m->volcmd = settings.m_volcmd;
+			m->vol = settings.m_vol;
 			return true;
 		}
 	}
@@ -355,6 +322,10 @@ bool CPattern::WriteEffect(EffectWriter &settings)
 				switch(m->command)
 				{
 				case CMD_VOLUME:
+					if(!GetSoundFile().GetModSpecifications().HasVolCommand(VOLCMD_VOLUME))
+					{
+						break;
+					}
 					m->volcmd = VOLCMD_VOLUME;
 					m->vol = m->param;
 					m->command = settings.m_command;
@@ -362,7 +333,7 @@ bool CPattern::WriteEffect(EffectWriter &settings)
 					return true;
 
 				case CMD_PANNING8:
-					if(isS3M && settings.m_param > 0x80)
+					if(isS3M && m->param > 0x80)
 					{
 						break;
 					}
@@ -371,68 +342,78 @@ bool CPattern::WriteEffect(EffectWriter &settings)
 					m->command = settings.m_command;
 
 					if(isS3M)
-					{
-						m->vol = m->param >> 1;
-					} else
-					{
-						m->vol = (m->param >> 2) + 1;
-					}
+						m->vol = (m->param + 1u) / 2u;
+					else
+						m->vol = (m->param + 2u) / 4u;
 
 					m->param = settings.m_param;
 					return true;
+
+				default:
+					break;
 				}
 			}
 		}
 
 		// Let's try it again by writing into the "other" effect column.
-		uint8 newCommand = CMD_NONE, newParam = settings.m_param;
 		if(settings.m_isVolEffect)
 		{
 			// Convert volume effect to normal effect
-			switch(settings.m_command)
+			ModCommand::COMMAND newCommand = CMD_NONE;
+			ModCommand::PARAM newParam = settings.m_vol;
+			switch(settings.m_volcmd)
 			{
 			case VOLCMD_PANNING:
 				newCommand = CMD_PANNING8;
-				if(isS3M)
-				{
-					newParam <<= 1;
-				} else
-				{
-					newParam = MIN(settings.m_param << 2, 0xFF);
-				}
+				newParam = mpt::saturate_cast<ModCommand::PARAM>(settings.m_vol * (isS3M ? 2u : 4u));
 				break;
 			case VOLCMD_VOLUME:
 				newCommand = CMD_VOLUME;
 				break;
+			default:
+				break;
+			}
+
+			if(newCommand != CMD_NONE)
+			{
+				settings.m_command = static_cast<EffectCommand>(newCommand);
+				settings.m_param = newParam;
+				settings.m_retry = false;
 			}
 		} else
 		{
 			// Convert normal effect to volume effect
+			ModCommand::VOLCMD newVolCmd = VOLCMD_NONE;
+			ModCommand::VOL newVol = settings.m_param;
 			if(settings.m_command == CMD_PANNING8 && isS3M)
 			{
 				// This needs some manual fixing.
 				if(settings.m_param <= 0x80)
 				{
 					// Can't have surround in volume column, only normal panning
-					newCommand = VOLCMD_PANNING;
-					newParam >>= 1;
+					newVolCmd = VOLCMD_PANNING;
+					newVol /= 2u;
 				}
 			} else
 			{
-				newCommand = settings.m_command;
-				if(!ModCommand::ConvertVolEffect(newCommand, newParam, true))
+				newVolCmd = settings.m_command;
+				if(!ModCommand::ConvertVolEffect(newVolCmd, newVol, true))
 				{
 					// No Success :(
-					newCommand = CMD_NONE;
+					newVolCmd = VOLCMD_NONE;
 				}
 			}
+
+			if(newVolCmd != CMD_NONE)
+			{
+				settings.m_volcmd = static_cast<VolumeCommand>(newVolCmd);
+				settings.m_vol = newVol;
+				settings.m_retry = false;
+			}
 		}
 
-		if(newCommand != CMD_NONE)
+		if(!settings.m_retry)
 		{
-			settings.m_command = newCommand;
-			settings.m_param = newParam;
-			settings.m_retry = false;
 			settings.m_isVolEffect = !settings.m_isVolEffect;
 			if(WriteEffect(settings))
 			{
@@ -460,48 +441,6 @@ bool CPattern::WriteEffect(EffectWriter &settings)
 
 ////////////////////////////////////////////////////////////////////////
 //
-//	Static allocation / deallocation methods
-//
-////////////////////////////////////////////////////////////////////////
-
-
-ModCommand *CPattern::AllocatePattern(ROWINDEX rows, CHANNELINDEX nchns)
-//----------------------------------------------------------------------
-{
-	size_t patSize = rows * nchns;
-	ModCommand *p = new (std::nothrow) ModCommand[patSize];
-	if(p != nullptr)
-	{
-		memset(p, 0, patSize * sizeof(ModCommand));
-	}
-	return p;
-}
-
-
-void CPattern::FreePattern(ModCommand *pat)
-//-----------------------------------------
-{
-	delete[] pat;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-//
-//	ITP functions
-//
-////////////////////////////////////////////////////////////////////////
-
-
-bool CPattern::WriteITPdata(FILE* f) const
-//----------------------------------------
-{
-	fwrite(m_ModCommands, sizeof(ModCommand), GetNumRows() * GetNumChannels(), f);
-	return false;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-//
 //	Pattern serialization functions
 //
 ////////////////////////////////////////////////////////////////////////
@@ -522,7 +461,6 @@ void WriteData(std::ostream& oStrm, const CPattern& pat);
 void ReadData(std::istream& iStrm, CPattern& pat, const size_t nSize = 0);
 
 void WriteModPattern(std::ostream& oStrm, const CPattern& pat)
-//------------------------------------------------------------
 {
 	srlztn::SsbWrite ssb(oStrm);
 	ssb.BeginWrite(FileIdPattern, MptVersion::num);
@@ -542,7 +480,6 @@ void WriteModPattern(std::ostream& oStrm, const CPattern& pat)
 
 
 void ReadModPattern(std::istream& iStrm, CPattern& pat, const size_t)
-//-------------------------------------------------------------------
 {
 	srlztn::SsbRead ssb(iStrm);
 	ssb.BeginRead(FileIdPattern, MptVersion::num);
@@ -562,7 +499,6 @@ void ReadModPattern(std::istream& iStrm, CPattern& pat, const size_t)
 
 
 static uint8 CreateDiffMask(const ModCommand &chnMC, const ModCommand &newMC)
-//---------------------------------------------------------------------------
 {
 	uint8 mask = 0;
 	if(chnMC.note != newMC.note)
@@ -583,9 +519,8 @@ static uint8 CreateDiffMask(const ModCommand &chnMC, const ModCommand &newMC)
 
 // Writes pattern data. Adapted from SaveIT.
 void WriteData(std::ostream& oStrm, const CPattern& pat)
-//------------------------------------------------------
 {
-	if(!pat)
+	if(!pat.IsValid())
 		return;
 
 	const ROWINDEX rows = pat.GetNumRows();
@@ -637,9 +572,8 @@ if(ch < chns)						\
 
 
 void ReadData(std::istream& iStrm, CPattern& pat, const size_t)
-//-------------------------------------------------------------
 {
-	if (!pat) // Expecting patterns to be allocated and resized properly.
+	if (!pat.IsValid()) // Expecting patterns to be allocated and resized properly.
 		return;
 
 	const CHANNELINDEX chns = pat.GetNumChannels();
diff --git a/soundlib/pattern.h b/soundlib/pattern.h
index 791495d..80282dc 100644
--- a/soundlib/pattern.h
+++ b/soundlib/pattern.h
@@ -25,29 +25,25 @@ class EffectWriter;
 typedef ModCommand* PatternRow;
 
 
-//============
 class CPattern
-//============
 {
 	friend class CPatternContainer;
 	
 public:
 //BEGIN: OPERATORS
-	//To mimic ModCommand*
-	operator ModCommand*() { return m_ModCommands; }
-	operator const ModCommand*() const { return m_ModCommands; }
-	CPattern& operator=(ModCommand* const p) { m_ModCommands = p; return *this; }
-	CPattern& operator=(const CPattern& pat)
+	CPattern& operator= (const CPattern &pat)
 	{
 		m_ModCommands = pat.m_ModCommands;
 		m_Rows = pat.m_Rows;
 		m_RowsPerBeat = pat.m_RowsPerBeat;
 		m_RowsPerMeasure = pat.m_RowsPerMeasure;
+		m_tempoSwing = pat.m_tempoSwing;
 		m_PatternName = pat.m_PatternName;
 		return *this;
 	}
 
 	bool operator== (const CPattern &other) const;
+	bool operator!= (const CPattern &other) const { return !(*this == other); }
 //END: OPERATORS
 
 //BEGIN: INTERFACE METHODS
@@ -60,8 +56,10 @@ public:
 	ROWINDEX GetRowsPerMeasure() const { return m_RowsPerMeasure; }		// pattern-specific rows per measure
 	bool GetOverrideSignature() const { return (m_RowsPerBeat + m_RowsPerMeasure > 0); }	// override song time signature?
 
-	// Return true if modcommand can be accessed from given row, false otherwise.
+	// Returns true if pattern data can be accessed at given row, false otherwise.
 	bool IsValidRow(const ROWINDEX row) const { return (row < GetNumRows()); }
+	// Returns true if any pattern data is present.
+	bool IsValid() const { return !m_ModCommands.empty(); }
 
 	// Return PatternRow object which has operator[] defined so that ModCommand
 	// at (iRow, iChn) can be accessed with GetRow(iRow)[iChn].
@@ -71,7 +69,7 @@ public:
 	CHANNELINDEX GetNumChannels() const;
 
 	// Add or remove rows from the pattern.
-	bool Resize(const ROWINDEX newRowCount, bool enforceFormatLimits = true);
+	bool Resize(const ROWINDEX newRowCount, bool enforceFormatLimits = true, bool resizeAtEnd = true);
 
 	// Check if there is any note data on a given row.
 	bool IsEmptyRow(ROWINDEX row) const;
@@ -88,7 +86,8 @@ public:
 	CSoundFile& GetSoundFile();
 	const CSoundFile& GetSoundFile() const;
 
-	bool SetData(ModCommand* p, const ROWINDEX rows) { m_ModCommands = p; m_Rows = rows; return false; }
+	const std::vector<ModCommand> &GetData() const { return m_ModCommands; }
+	void SetData(std::vector<ModCommand> &&data) { MPT_ASSERT(data.size() == GetNumRows() * GetNumChannels()); m_ModCommands = std::move(data); }
 
 	// Set pattern signature (rows per beat, rows per measure). Returns true on success.
 	bool SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure);
@@ -101,19 +100,13 @@ public:
 
 	// Pattern name functions - bool functions return true on success.
 	bool SetName(const std::string &newName);
-	bool SetName(const char *newName, size_t maxChars = MAX_PATTERNNAME);
+	bool SetName(const char *newName, size_t maxChars);
 	template<size_t bufferSize>
 	bool SetName(const char (&buffer)[bufferSize])
 	{
 		return SetName(buffer, bufferSize);
 	}
 
-	template<size_t bufferSize>
-	bool GetName(char (&buffer)[bufferSize]) const
-	{
-		return GetName(buffer, bufferSize);
-	}
-	bool GetName(char *buffer, size_t maxChars) const;
 	std::string GetName() const { return m_PatternName; };
 
 #ifdef MODPLUG_TRACKER
@@ -127,24 +120,22 @@ public:
 	// Write some kind of effect data to the pattern
 	bool WriteEffect(EffectWriter &settings);
 
-	bool WriteITPdata(FILE* f) const;
-
-	// Static allocation / deallocation helpers
-	static ModCommand *AllocatePattern(ROWINDEX rows, CHANNELINDEX nchns);
-	static void FreePattern(ModCommand *pat);
-
 //END: INTERFACE METHODS
 
-	typedef ModCommand* iterator;
-	typedef const ModCommand *const_iterator;
+	typedef std::vector<ModCommand>::iterator iterator;
+	typedef std::vector<ModCommand>::const_iterator const_iterator;
 
-	iterator Begin() { return m_ModCommands; }
-	const_iterator Begin() const { return m_ModCommands; }
+	iterator begin() { return m_ModCommands.begin(); }
+	const_iterator begin() const { return m_ModCommands.begin(); }
+	const_iterator cbegin() const { return m_ModCommands.cbegin(); }
 
-	iterator End() { return (m_ModCommands != nullptr) ? m_ModCommands + m_Rows * GetNumChannels() : nullptr; }
-	const_iterator End() const { return (m_ModCommands != nullptr) ? m_ModCommands + m_Rows * GetNumChannels() : nullptr; }
+	iterator end() { return m_ModCommands.end(); }
+	const_iterator end() const { return m_ModCommands.end(); }
+	const_iterator cend() const { return m_ModCommands.cend(); }
 
 	CPattern(CPatternContainer& patCont) : m_ModCommands(0), m_Rows(64), m_RowsPerBeat(0), m_RowsPerMeasure(0), m_rPatternContainer(patCont) {};
+	CPattern(const CPattern &) = default;
+	CPattern(CPattern &&) noexcept = default;
 
 protected:
 	ModCommand& GetModCommand(size_t i) { return m_ModCommands[i]; }
@@ -156,7 +147,7 @@ protected:
 
 //BEGIN: DATA
 protected:
-	ModCommand* m_ModCommands;
+	std::vector<ModCommand> m_ModCommands;
 	ROWINDEX m_Rows;
 	ROWINDEX m_RowsPerBeat;		// patterns-specific time signature. if != 0, this is implicitely set.
 	ROWINDEX m_RowsPerMeasure;	// ditto
@@ -175,13 +166,10 @@ void WriteModPattern(std::ostream& oStrm, const CPattern& patc);
 
 // Class for conveniently writing an effect to the pattern.
 
-//================
 class EffectWriter
-//================
 {
 	friend class CPattern;
 	
-public:
 	// Row advance mode
 	enum RetryMode
 	{
@@ -190,9 +178,10 @@ public:
 		rmTryPreviousRow,	// If effect can't be written, try previous row.
 	};
 
+public:
 	// Constructors with effect commands
-	EffectWriter(EffectCommands cmd, ModCommand::PARAM param) : m_command(static_cast<uint8>(cmd)), m_param(param), m_isVolEffect(false) { Init(); }
-	EffectWriter(VolumeCommands cmd, ModCommand::VOL param) : m_command(static_cast<uint8>(cmd)), m_param(param), m_isVolEffect(true) { Init(); }
+	EffectWriter(EffectCommand cmd, ModCommand::PARAM param) : m_command(cmd), m_param(param), m_isVolEffect(false) { Init(); }
+	EffectWriter(VolumeCommand cmd, ModCommand::VOL param) : m_volcmd(cmd), m_vol(param), m_isVolEffect(true) { Init(); }
 
 	// Additional constructors:
 	// Set row in which writing should start
@@ -202,14 +191,25 @@ public:
 	// Allow multiple effects of the same kind to be written in the same row.
 	EffectWriter &AllowMultiple() { m_allowMultiple = true; return *this; }
 	// Set retry mode.
-	EffectWriter &Retry(RetryMode retryMode) { m_retryMode = retryMode; return *this; }
+	EffectWriter &RetryNextRow() { m_retryMode = rmTryNextRow; return *this; }
+	EffectWriter &RetryPreviousRow() { m_retryMode = rmTryPreviousRow; return *this; }
 
 protected:
-	uint8 m_command, m_param;
-	
+	RetryMode m_retryMode;
 	ROWINDEX m_row;
 	CHANNELINDEX m_channel;
-	RetryMode m_retryMode;
+
+	union
+	{
+		EffectCommand m_command;
+		VolumeCommand m_volcmd;
+	};
+	union
+	{
+		ModCommand::PARAM m_param;
+		ModCommand::VOL m_vol;
+	};
+
 	bool m_retry : 1;
 	bool m_allowMultiple : 1;
 	bool m_isVolEffect : 1;
diff --git a/soundlib/patternContainer.cpp b/soundlib/patternContainer.cpp
index 45be8a9..4d084a5 100644
--- a/soundlib/patternContainer.cpp
+++ b/soundlib/patternContainer.cpp
@@ -20,15 +20,13 @@ OPENMPT_NAMESPACE_BEGIN
 
 
 void CPatternContainer::ClearPatterns()
-//-------------------------------------
 {
 	DestroyPatterns();
-	m_Patterns.assign(m_Patterns.size(), MODPATTERN(*this));
+	m_Patterns.assign(m_Patterns.size(), CPattern(*this));
 }
 
 
 void CPatternContainer::DestroyPatterns()
-//---------------------------------------
 {
 	for(PATTERNINDEX i = 0; i < m_Patterns.size(); i++)
 	{
@@ -38,83 +36,74 @@ void CPatternContainer::DestroyPatterns()
 
 
 PATTERNINDEX CPatternContainer::Duplicate(PATTERNINDEX from, bool respectQtyLimits)
-//---------------------------------------------------------------------------------
 {
 	if(!IsValidPat(from))
 	{
 		return PATTERNINDEX_INVALID;
 	}
 
-	const CPattern oldPat = m_Patterns[from];
-	PATTERNINDEX newPatIndex = InsertAny(oldPat.GetNumRows(), respectQtyLimits);
+	PATTERNINDEX newPatIndex = InsertAny(m_Patterns[from].GetNumRows(), respectQtyLimits);
 
 	if(newPatIndex != PATTERNINDEX_INVALID)
 	{
-		CPattern &newPat = m_Patterns[newPatIndex];
-		memcpy(newPat.m_ModCommands, oldPat.m_ModCommands, newPat.GetNumChannels() * newPat.GetNumRows() * sizeof(ModCommand));
-		newPat.m_Rows = oldPat.m_Rows;
-		newPat.m_RowsPerBeat = oldPat.m_RowsPerBeat;
-		newPat.m_RowsPerMeasure = oldPat.m_RowsPerMeasure;
-		newPat.m_PatternName = oldPat.m_PatternName;
-		newPat.m_tempoSwing = oldPat.m_tempoSwing;
+		m_Patterns[newPatIndex] = m_Patterns[from];
 	}
 	return newPatIndex;
 }
 
 
 PATTERNINDEX CPatternContainer::InsertAny(const ROWINDEX rows, bool respectQtyLimits)
-//-----------------------------------------------------------------------------------
 {
 	PATTERNINDEX i = 0;
 	for(i = 0; i < m_Patterns.size(); i++)
-		if(!m_Patterns[i]) break;
+		if(!m_Patterns[i].IsValid()) break;
 	if(respectQtyLimits && i >= m_rSndFile.GetModSpecifications().patternsMax)
 		return PATTERNINDEX_INVALID;
 	if(!Insert(i, rows))
 		return PATTERNINDEX_INVALID;
 	else return i;
-
 }
 
 
 bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows)
-//---------------------------------------------------------------------------
 {
 	if(rows > MAX_PATTERN_ROWS || rows == 0)
 		return false;
-	if(index < m_Patterns.size() && m_Patterns[index])
+	if(IsValidPat(index))
 		return false;
 
-	if(index >= m_Patterns.size())
+	try
+	{
+		if(index >= m_Patterns.size())
+		{
+			m_Patterns.resize(index + 1, CPattern(*this));
+		}
+		m_Patterns[index].AllocatePattern(rows);
+		m_Patterns[index].RemoveSignature();
+		m_Patterns[index].SetName("");
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 	{
-		m_Patterns.resize(index + 1, MODPATTERN(*this));
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		return false;
 	}
-
-	m_Patterns[index].AllocatePattern(rows);
-	m_Patterns[index].RemoveSignature();
-	m_Patterns[index].SetName("");
-
-	return m_Patterns[index] != nullptr;
+	return m_Patterns[index].IsValid();
 }
 
 
 void CPatternContainer::Remove(const PATTERNINDEX ipat)
-//-----------------------------------------------------
 {
 	if(ipat < m_Patterns.size()) m_Patterns[ipat].Deallocate();
 }
 
 
 bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const
-//-------------------------------------------------------------------
 {
 	if(!IsValidPat(nPat))
 		return false;
 	
-	const ModCommand *m = m_Patterns[nPat].m_ModCommands;
-	for(const ModCommand *mEnd = m + m_Patterns[nPat].GetNumChannels() * m_Patterns[nPat].GetNumRows(); m != mEnd; m++)
+	for(const auto &m : m_Patterns[nPat].m_ModCommands)
 	{
-		if(!m->IsEmpty())
+		if(!m.IsEmpty())
 			return false;
 	}
 	return true;
@@ -122,26 +111,24 @@ bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const
 
 
 void CPatternContainer::ResizeArray(const PATTERNINDEX newSize)
-//-------------------------------------------------------------
 {
 	if(Size() <= newSize)
-		m_Patterns.resize(newSize, MODPATTERN(*this));
-	else
 	{
-		for(PATTERNINDEX i = Size(); i > newSize; i--) Remove(i-1);
-		m_Patterns.resize(newSize, MODPATTERN(*this));
+		m_Patterns.resize(newSize, CPattern(*this));
+	} else
+	{
+		for(PATTERNINDEX i = Size(); i > newSize; i--)
+			Remove(i - 1);
+		m_Patterns.resize(newSize, CPattern(*this));
 	}
 }
 
 
 void CPatternContainer::OnModTypeChanged(const MODTYPE /*oldtype*/)
-//-----------------------------------------------------------------
 {
 	const CModSpecifications specs = m_rSndFile.GetModSpecifications();
-	if(specs.patternsMax < Size())
-		ResizeArray(MAX(MAX_PATTERNS, specs.patternsMax));
-	else if(Size() < MAX_PATTERNS)
-		ResizeArray(MAX_PATTERNS);
+	//if(specs.patternsMax < Size())
+	//	ResizeArray(specs.patternsMax);
 
 	// remove pattern time signatures
 	if(!specs.hasPatternSignatures)
@@ -155,20 +142,7 @@ void CPatternContainer::OnModTypeChanged(const MODTYPE /*oldtype*/)
 }
 
 
-void CPatternContainer::Init()
-//----------------------------
-{
-	for(PATTERNINDEX i = 0; i < Size(); i++)
-	{
-		Remove(i);
-	}
-
-	ResizeArray(MAX_PATTERNS);
-}
-
-
 PATTERNINDEX CPatternContainer::GetNumPatterns() const
-//----------------------------------------------------
 {
 	if(Size() == 0)
 	{
@@ -186,7 +160,6 @@ PATTERNINDEX CPatternContainer::GetNumPatterns() const
 
 
 PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const
-//---------------------------------------------------------
 {
 	if(Size() == 0)
 	{
@@ -205,13 +178,12 @@ PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const
 
 
 void WriteModPatterns(std::ostream& oStrm, const CPatternContainer& patc)
-//----------------------------------------------------------------------
 {
 	srlztn::SsbWrite ssb(oStrm);
 	ssb.BeginWrite(FileIdPatterns, MptVersion::num);
 	const PATTERNINDEX nPatterns = patc.Size();
 	uint16 nCount = 0;
-	for(uint16 i = 0; i < nPatterns; i++) if (patc[i])
+	for(uint16 i = 0; i < nPatterns; i++) if (patc[i].IsValid())
 	{
 		ssb.WriteItem(patc[i], srlztn::ID::FromInt<uint16>(i), &WriteModPattern);
 		nCount = i + 1;
@@ -222,7 +194,6 @@ void WriteModPatterns(std::ostream& oStrm, const CPatternContainer& patc)
 
 
 void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t)
-//--------------------------------------------------------------------------------
 {
 	srlztn::SsbRead ssb(iStrm);
 	ssb.BeginRead(FileIdPatterns, MptVersion::num);
diff --git a/soundlib/patternContainer.h b/soundlib/patternContainer.h
index 386ee58..c903014 100644
--- a/soundlib/patternContainer.h
+++ b/soundlib/patternContainer.h
@@ -17,31 +17,15 @@
 OPENMPT_NAMESPACE_BEGIN
 
 class CSoundFile;
-typedef CPattern MODPATTERN;
 
-//=====================
 class CPatternContainer
-//=====================
 {
-//BEGIN: TYPEDEFS
 public:
-	typedef std::vector<MODPATTERN> PATTERNVECTOR;
-//END: TYPEDEFS
+	CPattern& operator[](const int pat) { return m_Patterns[pat]; }
+	const CPattern& operator[](const int pat) const { return m_Patterns[pat]; }
 
-
-//BEGIN: OPERATORS
-public:
-	//To mimic old pattern == ModCommand* behavior.
-	MODPATTERN& operator[](const int pat) {return m_Patterns[pat];}
-	const MODPATTERN& operator[](const int pat) const {return m_Patterns[pat];}
-//END: OPERATORS
-
-//BEGIN: INTERFACE METHODS
 public:
-	CPatternContainer(CSoundFile& sndFile) : m_rSndFile(sndFile) {m_Patterns.assign(MAX_PATTERNS, MODPATTERN(*this));}
-
-	// Clears existing patterns and resizes array to default size.
-	void Init();
+	CPatternContainer(CSoundFile& sndFile) : m_rSndFile(sndFile) { }
 
 	// Empty and initialize all patterns.
 	void ClearPatterns();
@@ -69,18 +53,25 @@ public:
 	template <class Func>
 	Func ForEachModCommand(PATTERNINDEX nStartPat, PATTERNINDEX nLastPat, Func func);
 	template <class Func>
-	Func ForEachModCommand(Func func) {return ForEachModCommand(0, Size() - 1, func);}
+	Func ForEachModCommand(Func func) { return ForEachModCommand(0, Size() - 1, func); }
 
-	PATTERNINDEX Size() const {return static_cast<PATTERNINDEX>(m_Patterns.size());}
+	std::vector<CPattern>::iterator begin() { return m_Patterns.begin(); }
+	std::vector<CPattern>::const_iterator begin() const { return m_Patterns.begin(); }
+	std::vector<CPattern>::const_iterator cbegin() const { return m_Patterns.cbegin(); }
+	std::vector<CPattern>::iterator end() { return m_Patterns.end(); }
+	std::vector<CPattern>::const_iterator end() const { return m_Patterns.end(); }
+	std::vector<CPattern>::const_iterator cend() const { return m_Patterns.cend(); }
 
-	CSoundFile& GetSoundFile() {return m_rSndFile;}
-	const CSoundFile& GetSoundFile() const {return m_rSndFile;}
+	PATTERNINDEX Size() const { return static_cast<PATTERNINDEX>(m_Patterns.size()); }
+
+	CSoundFile& GetSoundFile() { return m_rSndFile; }
+	const CSoundFile& GetSoundFile() const { return m_rSndFile; }
 
 	// Return true if pattern can be accessed with operator[](iPat), false otherwise.
-	bool IsValidIndex(const PATTERNINDEX iPat) const {return (iPat < Size());}
+	bool IsValidIndex(const PATTERNINDEX iPat) const { return (iPat < Size()); }
 
 	// Return true if IsValidIndex() is true and the corresponding pattern has allocated modcommand array, false otherwise.
-	bool IsValidPat(const PATTERNINDEX iPat) const {return IsValidIndex(iPat) && (*this)[iPat];}
+	bool IsValidPat(const PATTERNINDEX iPat) const { return IsValidIndex(iPat) && m_Patterns[iPat].IsValid(); }
 
 	// Returns true if the pattern is empty, i.e. there are no notes/effects in this pattern
 	bool IsPatternEmpty(const PATTERNINDEX nPat) const;
@@ -95,26 +86,20 @@ public:
 	// Returns index of highest pattern with pattern named + 1.
 	PATTERNINDEX GetNumNamedPatterns() const;
 
-//END: INTERFACE METHODS
-
 
-//BEGIN: DATA MEMBERS
 private:
-	PATTERNVECTOR m_Patterns;
+	std::vector<CPattern> m_Patterns;
 	CSoundFile &m_rSndFile;
-//END: DATA MEMBERS
-
 };
 
 
 template <class Func>
 Func CPatternContainer::ForEachModCommand(PATTERNINDEX nStartPat, PATTERNINDEX nLastPat, Func func)
-//-------------------------------------------------------------------------------------------------
 {
 	if (nStartPat > nLastPat || nLastPat >= Size())
 		return func;
-	for (PATTERNINDEX nPat = nStartPat; nPat <= nLastPat; nPat++) if (m_Patterns[nPat])
-		std::for_each(m_Patterns[nPat].Begin(), m_Patterns[nPat].End(), func);
+	for (PATTERNINDEX nPat = nStartPat; nPat <= nLastPat; nPat++) if (m_Patterns[nPat].IsValid())
+		std::for_each(m_Patterns[nPat].begin(), m_Patterns[nPat].end(), func);
 	return func;
 }
 
diff --git a/soundlib/plugins/DigiBoosterEcho.cpp b/soundlib/plugins/DigiBoosterEcho.cpp
index cd5b741..1cd2c94 100644
--- a/soundlib/plugins/DigiBoosterEcho.cpp
+++ b/soundlib/plugins/DigiBoosterEcho.cpp
@@ -17,7 +17,6 @@
 OPENMPT_NAMESPACE_BEGIN
 
 IMixPlugin* DigiBoosterEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//------------------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) DigiBoosterEcho(factory, sndFile, mixStruct);
 }
@@ -28,7 +27,6 @@ DigiBoosterEcho::DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SND
 	, m_bufferSize(0)
 	, m_writePos(0)
 	, m_sampleRate(sndFile.GetSampleRate())
-//---------------------------------------------------------------------------------------------------
 {
 	m_mixBuffer.Initialize(2, 2);
 	InsertIntoFactoryList();
@@ -36,7 +34,6 @@ DigiBoosterEcho::DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SND
 
 
 void DigiBoosterEcho::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//-------------------------------------------------------------------------
 {
 	if(!m_bufferSize)
 		return;
@@ -85,28 +82,25 @@ void DigiBoosterEcho::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 void DigiBoosterEcho::SaveAllParameters()
-//---------------------------------------
 {
 	m_pMixStruct->defaultProgram = -1;
-	if(m_pMixStruct->nPluginDataSize != sizeof(chunk) || m_pMixStruct->pPluginData == nullptr)
+	try
 	{
-		delete[] m_pMixStruct->pPluginData;
-		m_pMixStruct->nPluginDataSize = sizeof(chunk);
-		m_pMixStruct->pPluginData = new (std::nothrow) char[sizeof(chunk)];
-	}
-	if(m_pMixStruct->pPluginData != nullptr)
+		m_pMixStruct->pluginData.resize(sizeof(m_chunk));
+		memcpy(m_pMixStruct->pluginData.data(), &m_chunk, sizeof(m_chunk));
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 	{
-		memcpy(m_pMixStruct->pPluginData, &chunk, sizeof(chunk));
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		m_pMixStruct->pluginData.clear();
 	}
 }
 
 
 void DigiBoosterEcho::RestoreAllParameters(int32 program)
-//-------------------------------------------------------
 {
-	if(m_pMixStruct->nPluginDataSize == sizeof(chunk) && !memcmp(m_pMixStruct->pPluginData, "Echo", 4))
+	if(m_pMixStruct->pluginData.size() == sizeof(m_chunk) && !memcmp(m_pMixStruct->pluginData.data(), "Echo", 4))
 	{
-		memcpy(&chunk, m_pMixStruct->pPluginData, sizeof(chunk));
+		memcpy(&m_chunk, m_pMixStruct->pluginData.data(), sizeof(m_chunk));
 	} else
 	{
 		IMixPlugin::RestoreAllParameters(program);
@@ -116,39 +110,43 @@ void DigiBoosterEcho::RestoreAllParameters(int32 program)
 
 
 PlugParamValue DigiBoosterEcho::GetParameter(PlugParamIndex index)
-//----------------------------------------------------------------
 {
 	if(index < kEchoNumParameters)
 	{
-		return chunk.param[index] / 255.0f;
+		return m_chunk.param[index] / 255.0f;
 	}
 	return 0;
 }
 
 
 void DigiBoosterEcho::SetParameter(PlugParamIndex index, PlugParamValue value)
-//----------------------------------------------------------------------------
 {
 	if(index < kEchoNumParameters)
 	{
-		chunk.param[index] = Util::Round<uint8>(value * 255.0f);
+		m_chunk.param[index] = Util::Round<uint8>(value * 255.0f);
 		RecalculateEchoParams();
 	}
 }
 
 
 void DigiBoosterEcho::Resume()
-//----------------------------
 {
 	m_isResumed = true;
 	m_sampleRate = m_SndFile.GetSampleRate();
-	m_bufferSize = (m_sampleRate >> 1) + (m_sampleRate >> 6);
 	RecalculateEchoParams();
+	PositionChanged();
+}
+
+
+void DigiBoosterEcho::PositionChanged()
+{
+	m_bufferSize = (m_sampleRate >> 1) + (m_sampleRate >> 6);
 	try
 	{
 		m_delayLine.assign(m_bufferSize * 2, 0);
-	} catch(MPTMemoryException)
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		m_bufferSize = 0;
 	}
 	m_writePos = 0;
@@ -158,7 +156,6 @@ void DigiBoosterEcho::Resume()
 #ifdef MODPLUG_TRACKER
 
 CString DigiBoosterEcho::GetParamName(PlugParamIndex param)
-//---------------------------------------------------------
 {
 	switch(param)
 	{
@@ -172,7 +169,6 @@ CString DigiBoosterEcho::GetParamName(PlugParamIndex param)
 
 
 CString DigiBoosterEcho::GetParamLabel(PlugParamIndex param)
-//----------------------------------------------------------
 {
 	if(param == kEchoDelay)
 		return _T("ms");
@@ -181,16 +177,15 @@ CString DigiBoosterEcho::GetParamLabel(PlugParamIndex param)
 
 
 CString DigiBoosterEcho::GetParamDisplay(PlugParamIndex param)
-//------------------------------------------------------------
 {
 	CString s;
 	if(param == kEchoMix)
 	{
-		int wet = (chunk.param[kEchoMix] * 100) / 255;
+		int wet = (m_chunk.param[kEchoMix] * 100) / 255;
 		s.Format(_T("%d%% / %d%%"), wet, 100 - wet);
 	} else if(param < kEchoNumParameters)
 	{
-		int val = chunk.param[param];
+		int val = m_chunk.param[param];
 		if(param == kEchoDelay)
 			val *= 2;
 		s.Format(_T("%d"), val);
@@ -201,35 +196,33 @@ CString DigiBoosterEcho::GetParamDisplay(PlugParamIndex param)
 #endif // MODPLUG_TRACKER
 
 
-size_t DigiBoosterEcho::GetChunk(char *(&data), bool)
-//---------------------------------------------------
+IMixPlugin::ChunkData DigiBoosterEcho::GetChunk(bool)
 {
-	data = reinterpret_cast<char *>(&chunk);
-	return sizeof(chunk);
+	auto data = reinterpret_cast<const mpt::byte *>(&m_chunk);
+	return ChunkData(data, sizeof(m_chunk));
 }
 
 
-void DigiBoosterEcho::SetChunk(size_t size, char *data, bool)
-//-----------------------------------------------------------
+void DigiBoosterEcho::SetChunk(const ChunkData &chunk, bool)
 {
-	if(size == sizeof(chunk) && !memcmp(data, "Echo", 4))
+	auto data = chunk.data();
+	if(chunk.size() == sizeof(chunk) && !memcmp(data, "Echo", 4))
 	{
-		memcpy(&chunk, data, size);
+		memcpy(&m_chunk, data, chunk.size());
 		RecalculateEchoParams();
 	}
 }
 
 
 void DigiBoosterEcho::RecalculateEchoParams()
-//-------------------------------------------
 {
-	m_delayTime = (chunk.param[kEchoDelay] * m_sampleRate + 250) / 500;
-	m_PMix = (chunk.param[kEchoMix]) * (1.0f / 256.0f);
-	m_NMix = (256 - chunk.param[kEchoMix]) * (1.0f / 256.0f);
-	m_PCrossPBack = (chunk.param[kEchoCross] * chunk.param[kEchoFeedback]) * (1.0f / 65536.0f);
-	m_PCrossNBack = (chunk.param[kEchoCross] * (256 - chunk.param[kEchoFeedback])) * (1.0f / 65536.0f);
-	m_NCrossPBack = ((chunk.param[kEchoCross] - 256) * chunk.param[kEchoFeedback]) * (1.0f / 65536.0f);
-	m_NCrossNBack = ((chunk.param[kEchoCross] - 256) * (chunk.param[kEchoFeedback] - 256)) * (1.0f / 65536.0f);
+	m_delayTime = (m_chunk.param[kEchoDelay] * m_sampleRate + 250) / 500;
+	m_PMix = (m_chunk.param[kEchoMix]) * (1.0f / 256.0f);
+	m_NMix = (256 - m_chunk.param[kEchoMix]) * (1.0f / 256.0f);
+	m_PCrossPBack = (m_chunk.param[kEchoCross] * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f);
+	m_PCrossNBack = (m_chunk.param[kEchoCross] * (256 - m_chunk.param[kEchoFeedback])) * (1.0f / 65536.0f);
+	m_NCrossPBack = ((m_chunk.param[kEchoCross] - 256) * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f);
+	m_NCrossNBack = ((m_chunk.param[kEchoCross] - 256) * (m_chunk.param[kEchoFeedback] - 256)) * (1.0f / 65536.0f);
 }
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/DigiBoosterEcho.h b/soundlib/plugins/DigiBoosterEcho.h
index 9c9723b..0a8e529 100644
--- a/soundlib/plugins/DigiBoosterEcho.h
+++ b/soundlib/plugins/DigiBoosterEcho.h
@@ -14,9 +14,7 @@
 
 OPENMPT_NAMESPACE_BEGIN
 
-//=======================================
 class DigiBoosterEcho : public IMixPlugin
-//=======================================
 {
 public:
 	enum Parameters
@@ -59,75 +57,60 @@ protected:
 	float m_NCrossPBack, m_NCrossNBack;
 
 	// Settings chunk for file I/O
-	PluginChunk chunk;
+	PluginChunk m_chunk;
 
 public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual void SaveAllParameters();
-	virtual void RestoreAllParameters(int32 program);
-	virtual int32 GetUID() const { int32 id; memcpy(&id, "Echo", 4); return id; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
-
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
-
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
-
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
-
-	virtual PlugParamIndex GetNumParameters() const { return kEchoNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
-
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
-
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	void Release() override { delete this; }
+	void SaveAllParameters() override;
+	void RestoreAllParameters(int32 program) override;
+	int32 GetUID() const override { int32le id; memcpy(&id, "Echo", 4); return id; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-#ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("Echo"); }
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	PlugParamIndex GetNumParameters() const override { return kEchoNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual bool HasEditor() const { return false; }
-#endif
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("Echo"); }
 
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
+
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
+
+	bool HasEditor() const override { return false; }
+#endif
 
-	virtual bool ProgramsAreChunks() const { return true; }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
-	virtual size_t GetChunk(char *(&data), bool);
-	virtual void SetChunk(size_t size, char *data, bool);
+	bool ProgramsAreChunks() const override { return true; }
+	ChunkData GetChunk(bool) override;
+	void SetChunk(const ChunkData &chunk, bool) override;
 
 protected:
 	void RecalculateEchoParams();
diff --git a/soundlib/plugins/LFOPlugin.cpp b/soundlib/plugins/LFOPlugin.cpp
new file mode 100644
index 0000000..4338993
--- /dev/null
+++ b/soundlib/plugins/LFOPlugin.cpp
@@ -0,0 +1,522 @@
+/*
+* LFOPlugin.cpp
+* -------------
+* Purpose: Plugin for automating other plugins' parameters
+* Notes  : (currently none)
+* Authors: OpenMPT Devs
+* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+*/
+
+
+#include "stdafx.h"
+
+#ifndef NO_PLUGINS
+#include "LFOPlugin.h"
+#include "../Sndfile.h"
+#include "../../common/FileReader.h"
+#ifdef MODPLUG_TRACKER
+#include "../../mptrack/plugins/LFOPluginEditor.h"
+#endif // MODPLUG_TRACKER
+
+OPENMPT_NAMESPACE_BEGIN
+
+IMixPlugin* LFOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+{
+	return new (std::nothrow) LFOPlugin(factory, sndFile, mixStruct);
+}
+
+
+LFOPlugin::LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+	: IMixPlugin(factory, sndFile, mixStruct)
+	, m_nextRandom(0)
+	, m_tempo(0)
+	, m_PRNG(mpt::make_prng<mpt::fast_prng>(mpt::global_prng()))
+{
+	m_amplitude = 0.5f;
+	m_offset = 0.5f;
+	m_frequency = 0.290241f;
+	m_tempoSync = false;
+	m_waveForm = kSine;
+	m_polarity = false;
+	m_bypassed = false;
+	m_outputToCC = false;
+	m_outputParam = int32_max;
+	m_oneshot = false;
+	RecalculateFrequency();
+	RecalculateIncrement();
+
+	m_mixBuffer.Initialize(2, 2);
+	InsertIntoFactoryList();
+}
+
+
+// Processing (we do not process audio, just send out parameters)
+void LFOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames)
+{
+	if(!m_bypassed)
+	{
+		ResetSilence();
+		if(m_tempoSync)
+		{
+			double tempo = m_SndFile.GetCurrentBPM();
+			if(tempo != m_tempo)
+			{
+				m_tempo = tempo;
+				RecalculateIncrement();
+			}
+		}
+
+		if(m_oneshot)
+		{
+			LimitMax(m_phase, 1.0);
+		} else
+		{
+			int intPhase = static_cast<int>(m_phase);
+			if(intPhase > 0 && (m_waveForm == kSHNoise || m_waveForm == kSmoothNoise))
+			{
+				// Phase wrap-around happened
+				NextRandom();
+			}
+			m_phase -= intPhase;
+		}
+
+		double value = 0;
+		switch(m_waveForm)
+		{
+		case kSine:
+			value = std::sin(m_phase * 2.0 * M_PI);
+			break;
+		case kTriangle:
+			value = 1.0 - 4.0 * mpt::abs(m_phase - 0.5);
+			break;
+		case kSaw:
+			value = 2.0 * m_phase - 1.0;
+			break;
+		case kSquare:
+			value = m_phase < 0.5 ? -1.0 : 1.0;
+			break;
+		case kSHNoise:
+			value = m_random;
+			break;
+		case kSmoothNoise:
+			value = m_phase * m_phase * m_phase * (m_phase * (m_phase * 6 - 15) + 10);	// Smootherstep
+			value = m_nextRandom * value + m_random * (1.0 - value);
+			break;
+		default:
+			break;
+		}
+		if(m_polarity)
+			value = -value;
+		// Transform value from -1...+1 to 0...1 range and apply offset/amplitude
+		value = value * m_amplitude + m_offset;
+		Limit(value, 0.0, 1.0);
+
+		IMixPlugin *plugin = GetOutputPlugin();
+		if(plugin != nullptr)
+		{
+			if(m_outputToCC)
+			{
+				plugin->MidiSend(MIDIEvents::CC(static_cast<MIDIEvents::MidiCC>(m_outputParam & 0x7F), static_cast<uint8>((m_outputParam >> 8) & 0x0F), Util::Round<uint8>(value * 127.0f)));
+			} else
+			{
+				plugin->SetParameter(m_outputParam, static_cast<PlugParamValue>(value));
+			}
+		}
+
+		m_phase += m_increment * numFrames;
+	}
+
+	ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1), numFrames);
+}
+
+
+PlugParamValue LFOPlugin::GetParameter(PlugParamIndex index)
+{
+	switch(index)
+	{
+	case kAmplitude: return m_amplitude;
+	case kOffset: return m_offset;
+	case kFrequency: return m_frequency;
+	case kTempoSync: return m_tempoSync ? 1.0f : 0.0f;
+	case kWaveform: return WaveformToParam(m_waveForm);
+	case kPolarity: return m_polarity ? 1.0f : 0.0f;
+	case kBypassed: return m_bypassed ? 1.0f : 0.0f;
+	case kLoopMode: return m_oneshot ? 1.0f : 0.0f;
+	default: return 0;
+	}
+}
+
+
+void LFOPlugin::SetParameter(PlugParamIndex index, PlugParamValue value)
+{
+	ResetSilence();
+	Limit(value, 0.0f, 1.0f);
+	switch(index)
+	{
+	case kAmplitude: m_amplitude = value; break;
+	case kOffset: m_offset = value; break;
+	case kFrequency:
+		m_frequency = value;
+		RecalculateFrequency();
+		break;
+	case kTempoSync:
+		m_tempoSync = (value >= 0.5f);
+		RecalculateFrequency();
+		break;
+	case kWaveform:
+		m_waveForm = ParamToWaveform(value);
+		if(m_waveForm >= kNumWaveforms)
+			m_waveForm = static_cast<LFOWaveform>(kNumWaveforms - 1);
+		break;
+	case kPolarity: m_polarity = (value >= 0.5f); break;
+	case kBypassed: m_bypassed = (value >= 0.5f); break;
+	case kLoopMode: m_oneshot = (value >= 0.5f); break;
+	case kCurrentPhase:
+		if(value == 0)
+		{
+			// Enforce next random value for random LFOs
+			NextRandom();
+		}
+		m_phase = value;
+		return;
+
+	default: return;
+	}
+
+#ifdef MODPLUG_TRACKER
+	if(GetEditor() != nullptr)
+	{
+		GetEditor()->PostMessage(WM_PARAM_UDPATE, GetSlot(), index);
+	}
+#endif
+}
+
+
+void LFOPlugin::Resume()
+{
+	m_isResumed = true;
+	RecalculateIncrement();
+	NextRandom();
+	PositionChanged();
+}
+
+
+void LFOPlugin::PositionChanged()
+{
+	// TODO Changing tempo (with tempo sync enabled), parameter automation over time and setting the LFO phase manually is not considered here.
+	m_phase = m_increment * m_SndFile.GetTotalSampleCount();
+	m_phase -= static_cast<int64>(m_phase);
+}
+
+
+bool LFOPlugin::MidiSend(uint32 midiCode)
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+		return plugin->MidiSend(midiCode);
+	else
+		return true;
+}
+
+
+bool LFOPlugin::MidiSysexSend(const void *message, uint32 length)
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+		return plugin->MidiSysexSend(message, length);
+	else
+		return true;
+}
+
+
+void LFOPlugin::MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel)
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+	{
+		plugin->MidiCC(nMidiCh, nController, nParam, trackChannel);
+	}
+}
+
+
+void LFOPlugin::MidiPitchBend(uint8 nMidiCh, int32 increment, int8 pwd)
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+	{
+		plugin->MidiPitchBend(nMidiCh, increment, pwd);
+	}
+}
+
+
+void LFOPlugin::MidiVibrato(uint8 nMidiCh, int32 depth, int8 pwd)
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+	{
+		plugin->MidiVibrato(nMidiCh, depth, pwd);
+	}
+}
+
+
+void LFOPlugin::MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel)
+{
+	if(ModCommand::IsNote(static_cast<ModCommand::NOTE>(note)) && vol > 0)
+	{
+		SetParameter(kCurrentPhase, 0);
+	}
+	if(IMixPlugin *plugin = GetOutputPlugin())
+	{
+		plugin->MidiCommand(nMidiCh, nMidiProg, wMidiBank, note, vol, trackChannel);
+	}
+}
+
+
+void LFOPlugin::HardAllNotesOff()
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+	{
+		plugin->HardAllNotesOff();
+	}
+}
+
+
+bool LFOPlugin::IsNotePlaying(uint32 note, uint32 midiChn, uint32 trackerChn)
+{
+	if(IMixPlugin *plugin = GetOutputPlugin())
+		return plugin->IsNotePlaying(note, midiChn, trackerChn);
+	else
+		return false;
+}
+
+
+void LFOPlugin::SaveAllParameters()
+{
+	auto chunk = GetChunk(false);
+	if(chunk.empty())
+		return;
+
+	m_pMixStruct->defaultProgram = -1;
+	m_pMixStruct->pluginData.assign(chunk.cbegin(), chunk.cend());
+}
+
+
+void LFOPlugin::RestoreAllParameters(int32 /*program*/)
+{
+	SetChunk(mpt::as_span(m_pMixStruct->pluginData), false);
+}
+
+
+struct PluginData
+{
+	char     magic[4];
+	uint32le version;
+	uint32le amplitude;	// float
+	uint32le offset;	// float
+	uint32le frequency;	// float
+	uint32le waveForm;
+	uint32le outputParam;
+	uint8le  tempoSync;
+	uint8le  polarity;
+	uint8le  bypassed;
+	uint8le  outputToCC;
+	uint8le  loopMode;
+};
+
+MPT_BINARY_STRUCT(PluginData, 33)
+
+
+IMixPlugin::ChunkData LFOPlugin::GetChunk(bool)
+{
+	PluginData chunk;
+	memcpy(chunk.magic, "LFO ", 4);
+	chunk.version = 0;
+	chunk.amplitude = IEEE754binary32LE(m_amplitude).GetInt32();
+	chunk.offset = IEEE754binary32LE(m_offset).GetInt32();
+	chunk.frequency = IEEE754binary32LE(m_frequency).GetInt32();
+	chunk.waveForm = m_waveForm;
+	chunk.outputParam = m_outputParam;
+	chunk.tempoSync = m_tempoSync ? 1 : 0;
+	chunk.polarity = m_polarity ? 1 : 0;
+	chunk.bypassed = m_bypassed ? 1 : 0;
+	chunk.outputToCC = m_outputToCC ? 1 : 0;
+	chunk.loopMode = m_oneshot ? 1 : 0;
+
+	m_chunkData.resize(sizeof(chunk));
+	memcpy(m_chunkData.data(), &chunk, sizeof(chunk));
+	return mpt::as_span(m_chunkData);
+}
+
+
+void LFOPlugin::SetChunk(const ChunkData &chunk, bool)
+{
+	FileReader file(chunk);
+	PluginData data;
+	if(file.ReadStructPartial(data, file.BytesLeft())
+		&& !memcmp(data.magic, "LFO ", 4)
+		&& data.version == 0)
+	{
+		m_amplitude = Clamp<float>(IEEE754binary32LE().SetInt32(data.amplitude), 0.0f, 1.0f);
+		m_offset = Clamp<float>(IEEE754binary32LE().SetInt32(data.offset), 0.0f, 1.0f);
+		m_frequency = Clamp<float>(IEEE754binary32LE().SetInt32(data.frequency), 0.0f, 1.0f);
+		if(data.waveForm < kNumWaveforms)
+			m_waveForm = static_cast<LFOWaveform>(data.waveForm.get());
+		m_outputParam = data.outputParam;
+		m_tempoSync = data.tempoSync != 0;
+		m_polarity = data.polarity != 0;
+		m_bypassed = data.bypassed != 0;
+		m_outputToCC = data.outputToCC != 0;
+		m_oneshot = data.loopMode != 0;
+	}
+}
+
+
+#ifdef MODPLUG_TRACKER
+
+CString LFOPlugin::GetParamName(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kAmplitude: return _T("Amplitude");
+	case kOffset: return _T("Offset");
+	case kFrequency: return _T("Frequency");
+	case kTempoSync: return _T("Tempo Sync");
+	case kWaveform: return _T("Waveform");
+	case kPolarity: return _T("Polarity");
+	case kBypassed: return _T("Bypassed");
+	case kLoopMode: return _T("Loop Mode");
+	case kCurrentPhase: return _T("Set LFO Phase");
+	}
+	return CString();
+}
+
+
+CString LFOPlugin::GetParamLabel(PlugParamIndex param)
+{
+	if(param == kFrequency)
+	{
+		if(m_tempoSync && m_computedFrequency > 0.0 && m_computedFrequency < 1.0)
+			return _T("Beats Per Cycle");
+		else if(m_tempoSync)
+			return _T("Cycles Per Beat");
+		else
+			return _T("Hz");
+	}
+	return CString();
+}
+
+
+CString LFOPlugin::GetParamDisplay(PlugParamIndex param)
+{
+	CString s;
+	if(param == kPolarity)
+	{
+		return m_polarity ? _T("Inverted") : _T("Normal");
+	} else if(param == kTempoSync)
+	{
+		return m_tempoSync ? _T("Yes") : _T("No");
+	} else if(param == kBypassed)
+	{
+		return m_bypassed ? _T("Yes") : _T("No");
+	} else if(param == kWaveform)
+	{
+		static const TCHAR *waveforms[] = { _T("Sine"), _T("Triangle"), _T("Saw"), _T("Square"), _T("Noise"), _T("Smoothed Noise") };
+		if(m_waveForm < MPT_ARRAY_COUNT(waveforms))
+			return waveforms[m_waveForm];
+	} else if(param == kLoopMode)
+	{
+		return m_oneshot ? _T("One-Shot") : _T("Looped");
+	} else if(param == kCurrentPhase)
+	{
+		return _T("Write-Only");
+	} else if(param < kLFONumParameters)
+	{
+		auto val = GetParameter(param);
+		if(param == kOffset)
+			val = 2.0f * val - 1.0f;
+		if(param == kFrequency)
+		{
+			val = static_cast<PlugParamValue>(m_computedFrequency);
+			if(m_tempoSync && val > 0.0f && val < 1.0f)
+				val = static_cast<PlugParamValue>(1.0 / m_computedFrequency);
+		}
+		s.Format(_T("%.3f"), val);
+	}
+	return s;
+}
+
+
+CAbstractVstEditor *LFOPlugin::OpenEditor()
+{
+	try
+	{
+		return new LFOPluginEditor(*this);
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		return nullptr;
+	}
+}
+
+#endif // MODPLUG_TRACKER
+
+
+void LFOPlugin::NextRandom()
+{
+	m_random = m_nextRandom;
+	m_nextRandom = mpt::random<int32>(m_PRNG) / static_cast<float>(int32_min);
+}
+
+
+void LFOPlugin::RecalculateFrequency()
+{
+	m_computedFrequency = 0.25 * std::pow(2.0, m_frequency * 8.0) - 0.25;
+	if(m_tempoSync)
+	{
+		if(m_computedFrequency > 0.00045)
+		{
+			double freqLog = std::log(m_computedFrequency) / M_LN2;
+			double freqFrac = freqLog - std::floor(freqLog);
+			freqLog -= freqFrac;
+
+			// Lock to powers of two and 1.5 times or 1.333333... times the powers of two
+			if(freqFrac < 0.20751874963942190927313052802609)
+				freqFrac = 0.0;
+			else if(freqFrac < 0.5)
+				freqFrac = 0.41503749927884381854626105605218;
+			else if(freqFrac < 0.79248125036057809072686947197391)
+				freqFrac = 0.58496250072115618145373894394782;
+			else
+				freqFrac = 1.0;
+
+			m_computedFrequency = std::pow(2.0, freqLog + freqFrac) * 0.5;
+		} else
+		{
+			m_computedFrequency = 0;
+		}
+	}
+	RecalculateIncrement();
+}
+
+
+void LFOPlugin::RecalculateIncrement()
+{
+	m_increment = m_computedFrequency / m_SndFile.GetSampleRate();
+	if(m_tempoSync)
+	{
+		m_increment *= m_tempo / 60.0;
+	}
+}
+
+
+IMixPlugin *LFOPlugin::GetOutputPlugin() const
+{
+	PLUGINDEX outPlug = m_pMixStruct->GetOutputPlugin();
+	if(outPlug > m_nSlot && outPlug < MAX_MIXPLUGINS)
+		return m_SndFile.m_MixPlugins[outPlug].pMixPlugin;
+	else
+		return nullptr;
+}
+
+
+OPENMPT_NAMESPACE_END
+
+#else
+MPT_MSVC_WORKAROUND_LNK4221(LFOPlugin)
+
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/LFOPlugin.h b/soundlib/plugins/LFOPlugin.h
new file mode 100644
index 0000000..3e5c24a
--- /dev/null
+++ b/soundlib/plugins/LFOPlugin.h
@@ -0,0 +1,151 @@
+/*
+* LFOPlugin.h
+* -----------
+* Purpose: Plugin for automating other plugins' parameters
+* Notes  : (currently none)
+* Authors: OpenMPT Devs
+* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+*/
+
+
+#pragma once
+
+#ifndef NO_PLUGINS
+
+#include "PlugInterface.h"
+#include "../../common/mptRandom.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+class LFOPlugin : public IMixPlugin
+{
+	friend class LFOPluginEditor;
+
+protected:
+	enum Parameters
+	{
+		kAmplitude = 0,
+		kOffset,
+		kFrequency,
+		kTempoSync,
+		kWaveform,
+		kPolarity,
+		kBypassed,
+		kLoopMode,
+		kCurrentPhase,
+		kLFONumParameters
+	};
+
+	enum LFOWaveform
+	{
+		kSine = 0,
+		kTriangle,
+		kSaw,
+		kSquare,
+		kSHNoise,
+		kSmoothNoise,
+		kNumWaveforms
+	};
+
+	std::vector<mpt::byte> m_chunkData;
+
+	// LFO parameters
+	float m_amplitude, m_offset, m_frequency;
+	LFOWaveform m_waveForm;
+	PlugParamIndex m_outputParam;
+	bool m_tempoSync, m_polarity, m_bypassed, m_outputToCC, m_oneshot;
+
+	// LFO state
+	double m_computedFrequency;
+	double m_phase, m_increment;
+	double m_random, m_nextRandom;
+	double m_tempo;
+
+	mpt::fast_prng m_PRNG;
+
+#ifdef MODPLUG_TRACKER
+	static const int WM_PARAM_UDPATE = WM_USER + 500;
+#endif
+
+public:
+	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+	LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+
+	void Release() override { delete this; }
+	int32 GetUID() const override { int32 id; memcpy(&id, "LFO ", 4); return id; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
+
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
+
+	float RenderSilence(uint32) override { return 0.0f; }
+
+	// MIDI event handling (mostly passing it through to the follow-up plugin)
+	bool MidiSend(uint32 midiCode) override;
+	bool MidiSysexSend(const void *message, uint32 length) override;
+	void MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override;
+	void MidiPitchBend(uint8 nMidiCh, int32 increment, int8 pwd) override;
+	void MidiVibrato(uint8 nMidiCh, int32 depth, int8 pwd) override;
+	void MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override;
+	void HardAllNotesOff() override;
+	bool IsNotePlaying(uint32 note, uint32 midiChn, uint32 trackerChn) override;
+
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
+
+	PlugParamIndex GetNumParameters() const override { return kLFONumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
+
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
+
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("LFO"); }
+
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
+
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
+
+	bool HasEditor() const override { return true; }
+protected:
+	CAbstractVstEditor *OpenEditor() override;
+#endif
+
+public:
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
+
+	bool ProgramsAreChunks() const override { return true; }
+	// Save parameters for storing them in a module file
+	void SaveAllParameters() override;
+	// Restore parameters from module file
+	void RestoreAllParameters(int32 program) override;
+	ChunkData GetChunk(bool) override;
+	void SetChunk(const ChunkData &chunk, bool) override;
+
+protected:
+	void NextRandom();
+	void RecalculateFrequency();
+	void RecalculateIncrement();
+	IMixPlugin *GetOutputPlugin() const;
+
+public:
+	static LFOWaveform ParamToWaveform(float param) { return static_cast<LFOWaveform>(Util::Round<int>(param * 32.0f)); }
+	static float WaveformToParam(LFOWaveform waveform) { return waveform / 32.0f; }
+};
+
+OPENMPT_NAMESPACE_END
+
+#endif // NO_PLUGINS
diff --git a/soundlib/plugins/PlugInterface.cpp b/soundlib/plugins/PlugInterface.cpp
index 7776fca..2bae4ec 100644
--- a/soundlib/plugins/PlugInterface.cpp
+++ b/soundlib/plugins/PlugInterface.cpp
@@ -40,7 +40,6 @@ const CModDoc *IMixPlugin::GetModDoc() const { return m_SndFile.GetpModDoc(); }
 
 
 IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//-----------------------------------------------------------------------------------------
 	: m_pNext(nullptr)
 	, m_pPrev(nullptr)
 	, m_Factory(factory)
@@ -71,7 +70,6 @@ IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN
 
 
 IMixPlugin::~IMixPlugin()
-//-----------------------
 {
 #ifdef MODPLUG_TRACKER
 	CloseEditor();
@@ -94,7 +92,6 @@ IMixPlugin::~IMixPlugin()
 
 
 void IMixPlugin::InsertIntoFactoryList()
-//--------------------------------------
 {
 	m_pMixStruct->pMixPlugin = this;
 
@@ -110,7 +107,6 @@ void IMixPlugin::InsertIntoFactoryList()
 #ifdef MODPLUG_TRACKER
 
 void IMixPlugin::SetSlot(PLUGINDEX slot)
-//--------------------------------------
 {
 	m_nSlot = slot;
 	m_pMixStruct = &m_SndFile.m_MixPlugins[slot];
@@ -118,7 +114,6 @@ void IMixPlugin::SetSlot(PLUGINDEX slot)
 
 
 CString IMixPlugin::GetFormattedParamName(PlugParamIndex param)
-//-------------------------------------------------------------
 {
 	CString paramName = GetParamName(param);
 	CString name;
@@ -127,7 +122,7 @@ CString IMixPlugin::GetFormattedParamName(PlugParamIndex param)
 		name.Format(_T("%02u: Parameter %02u"), param, param);
 	} else
 	{
-		name.Format(_T("%02u: %s"), param, paramName);
+		name.Format(_T("%02u: %s"), param, paramName.GetString());
 	}
 	return name;
 }
@@ -135,7 +130,6 @@ CString IMixPlugin::GetFormattedParamName(PlugParamIndex param)
 
 // Get a parameter's current value, represented by the plugin.
 CString IMixPlugin::GetFormattedParamValue(PlugParamIndex param)
-//--------------------------------------------------------------
 {
 
 	CString paramDisplay = GetParamDisplay(param);
@@ -149,7 +143,6 @@ CString IMixPlugin::GetFormattedParamValue(PlugParamIndex param)
 
 
 CString IMixPlugin::GetFormattedProgramName(int32 index)
-//------------------------------------------------------
 {
 	CString rawname = GetProgramName(index);
 	
@@ -157,17 +150,16 @@ CString IMixPlugin::GetFormattedProgramName(int32 index)
 	index++;
 
 	CString formattedName;
-	if((unsigned char)rawname[0] < ' ')
-		formattedName.Format("%02u - Program %u", index, index);
+	if(rawname[0] >= 0 && rawname[0] < _T(' '))
+		formattedName.Format(_T("%02u - Program %u"), index, index);
 	else
-		formattedName.Format("%02u - %s", index, rawname);
+		formattedName.Format(_T("%02u - %s"), index, rawname.GetString());
 
 	return formattedName;
 }
 
 
 void IMixPlugin::SetEditorPos(int32 x, int32 y)
-//---------------------------------------------
 {
 	m_pMixStruct->editorX = x;
 	m_pMixStruct->editorY = y;
@@ -175,7 +167,6 @@ void IMixPlugin::SetEditorPos(int32 x, int32 y)
 
 
 void IMixPlugin::GetEditorPos(int32 &x, int32 &y) const
-//-----------------------------------------------------
 {
 	x = m_pMixStruct->editorX;
 	y = m_pMixStruct->editorY;
@@ -186,14 +177,12 @@ void IMixPlugin::GetEditorPos(int32 &x, int32 &y) const
 
 
 bool IMixPlugin::IsBypassed() const
-//---------------------------------
 {
 	return m_pMixStruct != nullptr && m_pMixStruct->IsBypassed();
 }
 
 
 void IMixPlugin::RecalculateGain()
-//--------------------------------
 {
 	float gain = 0.1f * static_cast<float>(m_pMixStruct ? m_pMixStruct->GetGain() : 10);
 	if(gain < 0.1f) gain = 1.0f;
@@ -208,7 +197,6 @@ void IMixPlugin::RecalculateGain()
 
 
 void IMixPlugin::SetDryRatio(uint32 param)
-//----------------------------------------
 {
 	param = std::min(param, uint32(127));
 	m_pMixStruct->fDryRatio = 1.0f - (param / 127.0f);
@@ -216,7 +204,6 @@ void IMixPlugin::SetDryRatio(uint32 param)
 
 
 void IMixPlugin::Bypass(bool bypass)
-//----------------------------------
 {
 	m_pMixStruct->Info.SetBypass(bypass);
 
@@ -228,7 +215,6 @@ void IMixPlugin::Bypass(bool bypass)
 
 
 double IMixPlugin::GetOutputLatency() const
-//-----------------------------------------
 {
 	if(GetSoundFile().IsRenderingToDisc())
 		return 0;
@@ -238,7 +224,6 @@ double IMixPlugin::GetOutputLatency() const
 
 
 void IMixPlugin::ProcessMixOps(float * MPT_RESTRICT pOutL, float * MPT_RESTRICT pOutR, float * MPT_RESTRICT leftPlugOutput, float * MPT_RESTRICT rightPlugOutput, uint32 numFrames) const
-//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 /*	float *leftPlugOutput;
 	float *rightPlugOutput;
@@ -375,7 +360,6 @@ void IMixPlugin::ProcessMixOps(float * MPT_RESTRICT pOutL, float * MPT_RESTRICT
 
 // Render some silence and return maximum level returned by the plugin.
 float IMixPlugin::RenderSilence(uint32 numFrames)
-//-----------------------------------------------
 {
 	// The JUCE framework doesn't like processing while being suspended.
 	const bool wasSuspended = !IsResumed();
@@ -391,7 +375,7 @@ float IMixPlugin::RenderSilence(uint32 numFrames)
 	while(numFrames > 0)
 	{
 		uint32 renderSamples = numFrames;
-		LimitMax(renderSamples, CountOf(out[0]));
+		LimitMax(renderSamples, mpt::saturate_cast<uint32>(MPT_ARRAY_COUNT(out[0])));
 		MemsetZero(out);
 
 		Process(out[0], out[1], renderSamples);
@@ -415,7 +399,6 @@ float IMixPlugin::RenderSilence(uint32 numFrames)
 
 // Get list of plugins to which output is sent. A nullptr indicates master output.
 size_t IMixPlugin::GetOutputPlugList(std::vector<IMixPlugin *> &list)
-//-------------------------------------------------------------------
 {
 	// At the moment we know there will only be 1 output.
 	// Returning nullptr means plugin outputs directly to master.
@@ -438,7 +421,6 @@ size_t IMixPlugin::GetOutputPlugList(std::vector<IMixPlugin *> &list)
 
 // Get a list of plugins that send data to this plugin.
 size_t IMixPlugin::GetInputPlugList(std::vector<IMixPlugin *> &list)
-//------------------------------------------------------------------
 {
 	std::vector<IMixPlugin *> candidatePlugOutputs;
 	list.clear();
@@ -450,9 +432,9 @@ size_t IMixPlugin::GetInputPlugList(std::vector<IMixPlugin *> &list)
 		{
 			candidatePlug->GetOutputPlugList(candidatePlugOutputs);
 
-			for(std::vector<IMixPlugin *>::iterator iter = candidatePlugOutputs.begin(); iter != candidatePlugOutputs.end(); iter++)
+			for(auto &outPlug : candidatePlugOutputs)
 			{
-				if(*iter == this)
+				if(outPlug == this)
 				{
 					list.push_back(candidatePlug);
 					break;
@@ -467,7 +449,6 @@ size_t IMixPlugin::GetInputPlugList(std::vector<IMixPlugin *> &list)
 
 // Get a list of instruments that send data to this plugin.
 size_t IMixPlugin::GetInputInstrumentList(std::vector<INSTRUMENTINDEX> &list)
-//---------------------------------------------------------------------------
 {
 	list.clear();
 	const PLUGINDEX nThisMixPlug = m_nSlot + 1;		//m_nSlot is position in mixplug array.
@@ -485,7 +466,6 @@ size_t IMixPlugin::GetInputInstrumentList(std::vector<INSTRUMENTINDEX> &list)
 
 
 size_t IMixPlugin::GetInputChannelList(std::vector<CHANNELINDEX> &list)
-//---------------------------------------------------------------------
 {
 	list.clear();
 
@@ -505,7 +485,6 @@ size_t IMixPlugin::GetInputChannelList(std::vector<CHANNELINDEX> &list)
 
 
 void IMixPlugin::SaveAllParameters()
-//----------------------------------
 {
 	if (m_pMixStruct == nullptr)
 	{
@@ -518,42 +497,34 @@ void IMixPlugin::SaveAllParameters()
 	uint32 nLen = numParams * sizeof(IEEE754binary32LE);
 	if (!nLen) return;
 	nLen += sizeof(uint32);
-	if ((m_pMixStruct->pPluginData) && (m_pMixStruct->nPluginDataSize >= nLen))
-	{
-		m_pMixStruct->nPluginDataSize = nLen;
-	} else
-	{
-		if (m_pMixStruct->pPluginData) delete[] m_pMixStruct->pPluginData;
-		m_pMixStruct->nPluginDataSize = 0;
-		m_pMixStruct->pPluginData = new (std::nothrow) char[nLen];
-		if (m_pMixStruct->pPluginData)
-		{
-			m_pMixStruct->nPluginDataSize = nLen;
-		}
-	}
-	if (m_pMixStruct->pPluginData != nullptr)
+
+	try
 	{
-		std::pair<mpt::span<char>, mpt::IO::Offset> memFile = std::make_pair(mpt::as_span(m_pMixStruct->pPluginData, nLen), 0);
+		m_pMixStruct->pluginData.resize(nLen);
+		auto memFile = std::make_pair(mpt::as_span(m_pMixStruct->pluginData), mpt::IO::Offset(0));
 		mpt::IO::WriteIntLE<uint32>(memFile, 0);	// Plugin data type
 		for(PlugParamIndex i = 0; i < numParams; i++)
 		{
 			mpt::IO::Write(memFile, IEEE754binary32LE(GetParameter(i)));
 		}
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		m_pMixStruct->pluginData.clear();
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 	}
 }
 
 
 void IMixPlugin::RestoreAllParameters(int32 /*program*/)
-//------------------------------------------------------
 {
-	if(m_pMixStruct != nullptr && m_pMixStruct->pPluginData != nullptr && m_pMixStruct->nPluginDataSize >= sizeof(uint32))
+	if(m_pMixStruct != nullptr && m_pMixStruct->pluginData.size() >= sizeof(uint32))
 	{
-		FileReader memFile(mpt::as_span(mpt::byte_cast<const mpt::byte *>(m_pMixStruct->pPluginData), m_pMixStruct->nPluginDataSize));
+		FileReader memFile(mpt::as_span(m_pMixStruct->pluginData));
 		uint32 type = memFile.ReadUint32LE();
 		if(type == 0)
 		{
 			const uint32 numParams = GetNumParameters();
-			if((m_pMixStruct->nPluginDataSize - sizeof(uint32)) >= (numParams * sizeof(IEEE754binary32LE)))
+			if((m_pMixStruct->pluginData.size() - sizeof(uint32)) >= (numParams * sizeof(IEEE754binary32LE)))
 			{
 				BeginSetProgram(-1);
 				for(uint32 i = 0; i < numParams; i++)
@@ -569,7 +540,6 @@ void IMixPlugin::RestoreAllParameters(int32 /*program*/)
 
 #ifdef MODPLUG_TRACKER
 void IMixPlugin::ToggleEditor()
-//-----------------------------
 {
 	// We only really need this mutex for bridged plugins, as we may be processing window messages (in the same thread) while the editor opens.
 	// The user could press the toggle button while the editor is loading and thus close the editor while still being initialized.
@@ -595,20 +565,19 @@ void IMixPlugin::ToggleEditor()
 
 // Provide default plugin editor
 CAbstractVstEditor *IMixPlugin::OpenEditor()
-//------------------------------------------
 {
 	try
 	{
 		return new CDefaultVstEditor(*this);
-	} catch(MPTMemoryException)
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		return nullptr;
 	}
 }
 
 
 void IMixPlugin::CloseEditor()
-//----------------------------
 {
 	if(m_pEditor)
 	{
@@ -621,7 +590,6 @@ void IMixPlugin::CloseEditor()
 
 // Automate a parameter from the plugin GUI (both custom and default plugin GUI)
 void IMixPlugin::AutomateParameter(PlugParamIndex param)
-//------------------------------------------------------
 {
 	CModDoc *modDoc = GetModDoc();
 	if(modDoc == nullptr)
@@ -644,16 +612,12 @@ void IMixPlugin::AutomateParameter(PlugParamIndex param)
 	if(pVstEditor && pVstEditor->m_hWnd)
 	{
 		// Mark track modified if GUI is open and format supports plugins
-		if(m_SndFile.GetModSpecifications().supportsPlugins)
-		{
-			CMainFrame::GetMainFrame()->ThreadSafeSetModified(modDoc);
-		}
-
+		SetModified();
 
-		if (CMainFrame::GetInputHandler()->ShiftPressed())
+		if (CMainFrame::GetInputHandler()->ShiftPressed() && TrackerSettings::Instance().midiMappingInPluginEditor)
 		{
 			// Shift pressed -> Open MIDI mapping dialog
-			CMainFrame::GetInputHandler()->SetModifierMask(0); // Make sure that the dialog will open only once.
+			CMainFrame::GetInputHandler()->SetModifierMask(ModNone); // Make sure that the dialog will open only once.
 			CMainFrame::GetMainFrame()->PostMessage(WM_MOD_MIDIMAPPING, m_nSlot, param);
 		}
 
@@ -668,8 +632,17 @@ void IMixPlugin::AutomateParameter(PlugParamIndex param)
 }
 
 
+void IMixPlugin::SetModified()
+{
+	CModDoc *modDoc = GetModDoc();
+	if(modDoc != nullptr && m_SndFile.GetModSpecifications().supportsPlugins)
+	{
+		CMainFrame::GetMainFrame()->ThreadSafeSetModified(modDoc);
+	}
+}
+
+
 bool IMixPlugin::SaveProgram()
-//----------------------------
 {
 	mpt::PathString defaultDir = TrackerSettings::Instance().PathPluginPresets.GetWorkingDir();
 	bool useDefaultDir = !defaultDir.empty();
@@ -710,7 +683,6 @@ bool IMixPlugin::SaveProgram()
 
 
 bool IMixPlugin::LoadProgram(mpt::PathString fileName)
-//----------------------------------------------------
 {
 	mpt::PathString defaultDir = TrackerSettings::Instance().PathPluginPresets.GetWorkingDir();
 	bool useDefaultDir = !defaultDir.empty();
@@ -772,7 +744,6 @@ bool IMixPlugin::LoadProgram(mpt::PathString fileName)
 
 IMidiPlugin::IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	: IMixPlugin(factory, sndFile, mixStruct)
-//-------------------------------------------------------------------------------------------
 {
 	MemsetZero(m_MidiCh);
 	for(int ch = 0; ch < 16; ch++)
@@ -784,7 +755,6 @@ IMidiPlugin::IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGI
 
 
 void IMidiPlugin::ApplyPitchWheelDepth(int32 &value, int8 pwd)
-//------------------------------------------------------------
 {
 	if(pwd != 0)
 	{
@@ -797,7 +767,6 @@ void IMidiPlugin::ApplyPitchWheelDepth(int32 &value, int8 pwd)
 
 
 void IMidiPlugin::MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX /*trackChannel*/)
-//------------------------------------------------------------------------------------------------------------------
 {
 	//Error checking
 	LimitMax(nController, MIDIEvents::MIDICC_end);
@@ -812,7 +781,6 @@ void IMidiPlugin::MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nP
 
 // Bend MIDI pitch for given MIDI channel using fine tracker param (one unit = 1/64th of a note step)
 void IMidiPlugin::MidiPitchBend(uint8 nMidiCh, int32 increment, int8 pwd)
-//-----------------------------------------------------------------------
 {
 	if(m_SndFile.m_playBehaviour[kOldMIDIPitchBends])
 	{
@@ -834,7 +802,6 @@ void IMidiPlugin::MidiPitchBend(uint8 nMidiCh, int32 increment, int8 pwd)
 
 // Set MIDI pitch for given MIDI channel using fixed point pitch bend value (converted back to 0-16383 MIDI range)
 void IMidiPlugin::MidiPitchBend(uint8 nMidiCh, int32 newPitchBendPos)
-//-------------------------------------------------------------------
 {
 	MPT_ASSERT(EncodePitchBendParam(MIDIEvents::pitchBendMin) <= newPitchBendPos && newPitchBendPos <= EncodePitchBendParam(MIDIEvents::pitchBendMax));
 	m_MidiCh[nMidiCh].midiPitchBendPos = newPitchBendPos;
@@ -844,7 +811,6 @@ void IMidiPlugin::MidiPitchBend(uint8 nMidiCh, int32 newPitchBendPos)
 
 // Apply vibrato effect through pitch wheel commands on a given MIDI channel.
 void IMidiPlugin::MidiVibrato(uint8 nMidiCh, int32 depth, int8 pwd)
-//-----------------------------------------------------------------
 {
 	depth = EncodePitchBendParam(depth);
 	if(depth != 0 || (m_MidiCh[nMidiCh].midiPitchBendPos & vstVibratoFlag))
@@ -870,7 +836,6 @@ void IMidiPlugin::MidiVibrato(uint8 nMidiCh, int32 depth, int8 pwd)
 
 
 void IMidiPlugin::MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel)
-//---------------------------------------------------------------------------------------------------------------------------------
 {
 	PlugInstrChannel &channel = m_MidiCh[nMidiCh];
 
@@ -972,7 +937,6 @@ void IMidiPlugin::MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank,
 
 
 bool IMidiPlugin::IsNotePlaying(uint32 note, uint32 midiChn, uint32 trackerChn)
-//-------------------------------------------------------------------------
 {
 	note -= NOTE_MIN;
 	return (m_MidiCh[midiChn].noteOnMap[note][trackerChn] != 0);
@@ -980,7 +944,6 @@ bool IMidiPlugin::IsNotePlaying(uint32 note, uint32 midiChn, uint32 trackerChn)
 
 
 void IMidiPlugin::ReceiveMidi(uint32 midiCode)
-//--------------------------------------------
 {
 	ResetSilence();
 
@@ -1005,7 +968,6 @@ void IMidiPlugin::ReceiveMidi(uint32 midiCode)
 
 
 void IMidiPlugin::ReceiveSysex(const void *message, uint32 length)
-//----------------------------------------------------------------
 {
 	ResetSilence();
 
@@ -1024,7 +986,6 @@ void IMidiPlugin::ReceiveSysex(const void *message, uint32 length)
 // SNDMIXPLUGIN functions
 
 void SNDMIXPLUGIN::SetGain(uint8 gain)
-//------------------------------------
 {
 	Info.gain = gain;
 	if(pMixPlugin != nullptr) pMixPlugin->RecalculateGain();
@@ -1032,7 +993,6 @@ void SNDMIXPLUGIN::SetGain(uint8 gain)
 
 
 void SNDMIXPLUGIN::SetBypass(bool bypass)
-//---------------------------------------
 {
 	if(pMixPlugin != nullptr)
 		pMixPlugin->Bypass(bypass);
@@ -1042,17 +1002,14 @@ void SNDMIXPLUGIN::SetBypass(bool bypass)
 
 
 void SNDMIXPLUGIN::Destroy()
-//--------------------------
 {
-	delete[] pPluginData;
-	pPluginData = nullptr;
-	nPluginDataSize = 0;
-
 	if(pMixPlugin)
 	{
 		pMixPlugin->Release();
 		pMixPlugin = nullptr;
 	}
+	pluginData.clear();
+	pluginData.shrink_to_fit();
 }
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/PlugInterface.h b/soundlib/plugins/PlugInterface.h
index 5dabc71..1ce5696 100644
--- a/soundlib/plugins/PlugInterface.h
+++ b/soundlib/plugins/PlugInterface.h
@@ -52,9 +52,7 @@ struct SNDMIXPLUGINSTATE
 };
 
 
-//==============
 class IMixPlugin
-//==============
 {
 	friend class CAbstractVstEditor;
 
@@ -120,6 +118,7 @@ public:
 	virtual int32 GetUID() const = 0;
 	virtual int32 GetVersion() const = 0;
 	virtual void Idle() = 0;
+	// Plugin latency in samples
 	virtual uint32 GetLatency() const = 0;
 
 	virtual int32 GetNumPrograms() const = 0;
@@ -138,14 +137,17 @@ public:
 	void ProcessMixOps(float *pOutL, float *pOutR, float *leftPlugOutput, float *rightPlugOutput, uint32 numFrames) const;
 	// Render silence and return the highest resulting output level
 	virtual float RenderSilence(uint32 numSamples);
-	virtual bool MidiSend(uint32 midiCode) = 0;
-	virtual bool MidiSysexSend(const void *message, uint32 length) = 0;
-	virtual void MidiCC(uint8 nMidiCh, MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) = 0;
-	virtual void MidiPitchBend(uint8 nMidiCh, int32 increment, int8 pwd) = 0;
-	virtual void MidiVibrato(uint8 nMidiCh, int32 depth, int8 pwd) = 0;
-	virtual void MidiCommand(uint8 nMidiCh, uint8 nMidiProg, uint16 wMidiBank, uint16 note, uint16 vol, CHANNELINDEX trackChannel) = 0;
-	virtual void HardAllNotesOff() = 0;
-	virtual bool IsNotePlaying(uint32 note, uint32 midiChn, uint32 trackerChn) = 0;
+
+	// MIDI event handling
+	virtual bool MidiSend(uint32 /*midiCode*/) { return true; }
+	virtual bool MidiSysexSend(const void * /*message*/, uint32 /*length*/) { return true; }
+	virtual void MidiCC(uint8 /*nMidiCh*/, MIDIEvents::MidiCC /*nController*/, uint8 /*nParam*/, CHANNELINDEX /*trackChannel*/) { }
+	virtual void MidiPitchBend(uint8 /*nMidiCh*/, int32 /*increment*/, int8 /*pwd*/) { }
+	virtual void MidiVibrato(uint8 /*nMidiCh*/, int32 /*depth*/, int8 /*pwd*/) { }
+	virtual void MidiCommand(uint8 /*nMidiCh*/, uint8 /*nMidiProg*/, uint16 /*wMidiBank*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { }
+	virtual void HardAllNotesOff() { }
+	virtual bool IsNotePlaying(uint32 /*note*/, uint32 /*midiChn*/, uint32 /*trackerChn*/) { return false; }
+
 	// Modify parameter by given amount. Only needs to be re-implemented if plugin architecture allows this to be performed atomically.
 	virtual void ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff);
 	virtual void NotifySongPlaying(bool playing) { m_isSongPlaying = playing; }
@@ -156,7 +158,7 @@ public:
 	// Tell the plugin that there is a discontinuity between the previous and next render call (e.g. aftert jumping around in the module)
 	virtual void PositionChanged() = 0;
 	virtual void Bypass(bool = true);
-	bool ToggleBypass() { Bypass(!IsBypassed()); return IsBypassed(); };
+	bool ToggleBypass() { Bypass(!IsBypassed()); return IsBypassed(); }
 	virtual bool IsInstrument() const = 0;
 	virtual bool CanRecieveMidiEvents() = 0;
 	// If false is returned, mixing this plugin can be skipped if its input are currently completely silent.
@@ -175,8 +177,8 @@ public:
 	virtual CString GetDefaultEffectName() = 0;
 
 	// Cache a range of names, in case one-by-one retrieval would be slow (e.g. when using plugin bridge)
-	virtual void CacheProgramNames(int32 firstProg, int32 lastProg) = 0;
-	virtual void CacheParameterNames(int32 firstParam, int32 lastParam) = 0;
+	virtual void CacheProgramNames(int32 /*firstProg*/, int32 /*lastProg*/) { }
+	virtual void CacheParameterNames(int32 /*firstParam*/, int32 /*lastParam*/) { }
 
 	virtual CString GetParamName(PlugParamIndex param) = 0;
 	virtual CString GetParamLabel(PlugParamIndex param) = 0;
@@ -200,23 +202,26 @@ public:
 	void SetEditorPos(int32 x, int32 y);
 	void GetEditorPos(int32 &x, int32 &y) const;
 
+	// Notify OpenMPT that a plugin parameter has changed and set document as modified
 	void AutomateParameter(PlugParamIndex param);
+	// Plugin state changed, set document as modified.
+	void SetModified();
 #endif
 
-	virtual void BeginSetProgram(int32 program = -1) = 0;
-	virtual void EndSetProgram() = 0;
+	virtual void BeginSetProgram(int32 /*program*/ = -1) { }
+	virtual void EndSetProgram() { }
 
 	virtual int GetNumInputChannels() const = 0;
 	virtual int GetNumOutputChannels() const = 0;
 
-	virtual bool ProgramsAreChunks() const = 0;
-	virtual size_t GetChunk(char *(&chunk), bool isBank) = 0;
-	virtual void SetChunk(size_t size, char *chunk, bool isBank) = 0;
+	typedef mpt::const_byte_span ChunkData;
+	virtual bool ProgramsAreChunks() const { return false; }
+	virtual ChunkData GetChunk(bool /*isBank*/) { return ChunkData(); }
+	virtual void SetChunk(const ChunkData &/*chunk*/, bool /*isBank*/) { }
 };
 
 
 inline void IMixPlugin::ModifyParameter(PlugParamIndex nIndex, PlugParamValue diff)
-//---------------------------------------------------------------------------------
 {
 	float val = GetParameter(nIndex) + diff;
 	Limit(val, PlugParamValue(0), PlugParamValue(1));
@@ -226,9 +231,7 @@ inline void IMixPlugin::ModifyParameter(PlugParamIndex nIndex, PlugParamValue di
 
 // IMidiPlugin: Default implementation of plugins with MIDI input
 
-//===================================
 class IMidiPlugin : public IMixPlugin
-//===================================
 {
 protected:
 	enum
diff --git a/soundlib/plugins/PluginManager.cpp b/soundlib/plugins/PluginManager.cpp
index 9a4d683..c29d84b 100644
--- a/soundlib/plugins/PluginManager.cpp
+++ b/soundlib/plugins/PluginManager.cpp
@@ -16,17 +16,23 @@
 #include "PluginManager.h"
 #include "PlugInterface.h"
 
+#include "../../common/mptUUID.h"
+
 // Built-in plugins
 #include "DigiBoosterEcho.h"
+#include "LFOPlugin.h"
 #include "dmo/DMOPlugin.h"
+#include "dmo/Chorus.h"
 #include "dmo/Compressor.h"
 #include "dmo/Distortion.h"
 #include "dmo/Echo.h"
+#include "dmo/Flanger.h"
 #include "dmo/Gargle.h"
+#include "dmo/I3DL2Reverb.h"
 #include "dmo/ParamEq.h"
 #include "dmo/WavesReverb.h"
 #ifdef MODPLUG_TRACKER
-#include "../../plugins/MidiInOut/MidiInOut.h"
+#include "../../mptrack/plugins/MidiInOut.h"
 #endif // MODPLUG_TRACKER
 
 #include "../../common/StringFixer.h"
@@ -63,7 +69,6 @@ static const MPT_UCHAR_TYPE *const cacheSection = MPT_ULITERAL("PluginCache");
 
 
 uint8 VSTPluginLib::GetDllBits(bool fromCache) const
-//--------------------------------------------------
 {
 	// Built-in plugins are always native.
 	if(dllPath.empty())
@@ -81,20 +86,18 @@ uint8 VSTPluginLib::GetDllBits(bool fromCache) const
 
 
 // PluginCache format:
-// LibraryName = <ID1><ID2><CRC32> (hex-encoded)
-// <ID1><ID2><CRC32> = FullDllPath
+// FullDllPath = <ID1><ID2><CRC32> (hex-encoded)
 // <ID1><ID2><CRC32>.Flags = Plugin Flags (see VSTPluginLib::DecodeCacheFlags).
 // <ID1><ID2><CRC32>.Vendor = Plugin Vendor String.
 
 #ifdef MODPLUG_TRACKER
 void VSTPluginLib::WriteToCache() const
-//-------------------------------------
 {
 	SettingsContainer &cacheFile = theApp.GetPluginCache();
 
-	const std::string libName = libraryName.ToUTF8();
-	const uint32 crc = mpt::crc32(libName);
-	const mpt::ustring IDs = mpt::ufmt::HEX0<8>(SwapBytesReturnLE(pluginId1)) + mpt::ufmt::HEX0<8>(SwapBytesReturnLE(pluginId2)) + mpt::ufmt::HEX0<8>(SwapBytesReturnLE(crc));
+	const std::string crcName = dllPath.ToUTF8();
+	const uint32 crc = mpt::crc32(crcName);
+	const mpt::ustring IDs = mpt::ufmt::HEX0<8>(SwapBytesLE(pluginId1)) + mpt::ufmt::HEX0<8>(SwapBytesLE(pluginId2)) + mpt::ufmt::HEX0<8>(SwapBytesLE(crc));
 
 	mpt::PathString writePath = dllPath;
 	if(theApp.IsPortableMode())
@@ -102,8 +105,7 @@ void VSTPluginLib::WriteToCache() const
 		writePath = theApp.AbsolutePathToRelative(writePath);
 	}
 
-	cacheFile.Write<mpt::ustring>(cacheSection, libraryName.ToUnicode(), IDs);
-	cacheFile.Write<mpt::PathString>(cacheSection, IDs, writePath);
+	cacheFile.Write<mpt::ustring>(cacheSection, writePath.ToUnicode(), IDs);
 	cacheFile.Write<CString>(cacheSection, IDs + MPT_USTRING(".Vendor"), vendor);
 	cacheFile.Write<int32>(cacheSection, IDs + MPT_USTRING(".Flags"), EncodeCacheFlags());
 }
@@ -111,7 +113,6 @@ void VSTPluginLib::WriteToCache() const
 
 
 bool CreateMixPluginProc(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile)
-//--------------------------------------------------------------------
 {
 #ifdef MODPLUG_TRACKER
 	CVstPluginManager *that = theApp.GetPluginManager();
@@ -123,7 +124,7 @@ bool CreateMixPluginProc(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile)
 #else
 	if(!sndFile.m_PluginManager)
 	{
-		sndFile.m_PluginManager = mpt::make_shared<CVstPluginManager>();
+		sndFile.m_PluginManager = mpt::make_unique<CVstPluginManager>();
 	}
 	return sndFile.m_PluginManager->CreateMixPlugin(mixPlugin, sndFile);
 #endif // MODPLUG_TRACKER
@@ -131,13 +132,12 @@ bool CreateMixPluginProc(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile)
 
 
 CVstPluginManager::CVstPluginManager()
-//------------------------------------
-#if MPT_OS_WINDOWS && !defined(NO_DMO)
+#ifndef NO_DMO
 	: MustUnInitilizeCOM(false)
 #endif
 {
 
-	#if MPT_OS_WINDOWS && !defined(NO_DMO)
+	#ifndef NO_DMO
 		HRESULT COMinit = CoInitializeEx(NULL, COINIT_MULTITHREADED);
 		if(COMinit == S_OK || COMinit == S_FALSE)
 		{
@@ -145,110 +145,71 @@ CVstPluginManager::CVstPluginManager()
 		}
 	#endif
 
-	// DirectX Media Objects
-	#ifdef MODPLUG_TRACKER
-		EnumerateDirectXDMOs(true);
-	#else // !MODPLUG_TRACKER
-		// For security reasons, we only load known DMO plugins in libopenmpt.
-		EnumerateDirectXDMOs(false);
-	#endif // MODPLUG_TRACKER
-
 	// Hard-coded "plugins"
-	VSTPluginLib *plug;
-
-	// DigiBooster Pro Echo DSP
-	plug = new (std::nothrow) VSTPluginLib(DigiBoosterEcho::Create, true, mpt::PathString(), MPT_PATHSTRING("DigiBooster Pro Echo"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		memcpy(&plug->pluginId1, "DBM0", 4);
-		memcpy(&plug->pluginId2, "Echo", 4);
-		plug->category = VSTPluginLib::catRoomFx;
-	}
-
+	static constexpr struct
+	{
+		VSTPluginLib::CreateProc createProc;
+		const char *filename, *name;
+		uint32 pluginId1, pluginId2;
+		VSTPluginLib::PluginCategory category;
+		bool isInstrument, isOurs;
+	} BuiltInPlugins[] =
+	{
+		// DirectX Media Objects Emulation
+		{ DMO::Chorus::Create,		"{EFE6629C-81F7-4281-BD91-C9D604A95AF6}", "Chorus",			kDmoMagic, 0xEFE6629C, VSTPluginLib::catDMO, false, false },
+		{ DMO::Compressor::Create,	"{EF011F79-4000-406D-87AF-BFFB3FC39D57}", "Compressor",		kDmoMagic, 0xEF011F79, VSTPluginLib::catDMO, false, false },
+		{ DMO::Distortion::Create,	"{EF114C90-CD1D-484E-96E5-09CFAF912A21}", "Distortion",		kDmoMagic, 0xEF114C90, VSTPluginLib::catDMO, false, false },
+		{ DMO::Echo::Create,		"{EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D}", "Echo",			kDmoMagic, 0xEF3E932C, VSTPluginLib::catDMO, false, false },
+		{ DMO::Flanger::Create,		"{EFCA3D92-DFD8-4672-A603-7420894BAD98}", "Flanger",		kDmoMagic, 0xEFCA3D92, VSTPluginLib::catDMO, false, false },
+		{ DMO::Gargle::Create,		"{DAFD8210-5711-4B91-9FE3-F75B7AE279BF}", "Gargle",			kDmoMagic, 0xDAFD8210, VSTPluginLib::catDMO, false, false },
+		{ DMO::I3DL2Reverb::Create,	"{EF985E71-D5C7-42D4-BA4D-2D073E2E96F4}", "I3DL2Reverb",	kDmoMagic, 0xEF985E71, VSTPluginLib::catDMO, false, false },
+		{ DMO::ParamEq::Create,		"{120CED89-3BF4-4173-A132-3CB406CF3231}", "ParamEq",		kDmoMagic, 0x120CED89, VSTPluginLib::catDMO, false, false },
+		{ DMO::WavesReverb::Create,	"{87FC0268-9A55-4360-95AA-004A1D9DE26C}", "WavesReverb",	kDmoMagic, 0x87FC0268, VSTPluginLib::catDMO, false, false },
+		// DigiBooster Pro Echo DSP
+		{ DigiBoosterEcho::Create, "", "DigiBooster Pro Echo", MAGIC4LE('D','B','M','0'), MAGIC4LE('E','c','h','o'), VSTPluginLib::catRoomFx, false, true },
+		// LFO
+		{ LFOPlugin::Create, "", "LFO", MAGIC4LE('O','M','P','T'), MAGIC4LE('L','F','O',' '), VSTPluginLib::catGenerator, false, true },
 #ifdef MODPLUG_TRACKER
-	plug = new (std::nothrow) VSTPluginLib(MidiInOut::Create, true, mpt::PathString(), MPT_PATHSTRING("MIDI Input Output"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = PLUGMAGIC('V','s','t','P');
-		plug->pluginId2 = PLUGMAGIC('M','M','I','D');
-		plug->category = VSTPluginLib::catSynth;
-		plug->isInstrument = true;
-	}
+		{ MidiInOut::Create, "", "MIDI Input Output", PLUGMAGIC('V','s','t','P'), PLUGMAGIC('M','M','I','D'), VSTPluginLib::catSynth, true, true },
 #endif // MODPLUG_TRACKER
+	};
 
-#ifdef NO_DMO
-	// DirectX Media Objects Emulation
-	plug = new (std::nothrow) VSTPluginLib(DMO::Compressor::Create, true, MPT_PATHSTRING("{EF011F79-4000-406D-87AF-BFFB3FC39D57}"), MPT_PATHSTRING("Compressor"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = kDmoMagic;
-		plug->pluginId2 = 0xEF011F79;
-		plug->category = VSTPluginLib::catDMO;
-	}
-
-	plug = new (std::nothrow) VSTPluginLib(DMO::Distortion::Create, true, MPT_PATHSTRING("{EF114C90-CD1D-484E-96E5-09CFAF912A21}"), MPT_PATHSTRING("Distortion"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = kDmoMagic;
-		plug->pluginId2 = 0xEF114C90;
-		plug->category = VSTPluginLib::catDMO;
-	}
-
-	plug = new (std::nothrow) VSTPluginLib(DMO::Echo::Create, true, MPT_PATHSTRING("{EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D}"), MPT_PATHSTRING("Echo"));
-	if(plug != nullptr)
+	pluginList.reserve(mpt::size(BuiltInPlugins));
+	for(const auto &plugin : BuiltInPlugins)
 	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = kDmoMagic;
-		plug->pluginId2 = 0xEF3E932C;
-		plug->category = VSTPluginLib::catDMO;
-	}
-
-	plug = new (std::nothrow) VSTPluginLib(DMO::Gargle::Create, true, MPT_PATHSTRING("{DAFD8210-5711-4B91-9FE3-F75B7AE279BF}"), MPT_PATHSTRING("Gargle"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = kDmoMagic;
-		plug->pluginId2 = 0xDAFD8210;
-		plug->category = VSTPluginLib::catDMO;
-	}
-
-	plug = new (std::nothrow) VSTPluginLib(DMO::ParamEq::Create, true, MPT_PATHSTRING("{120CED89-3BF4-4173-A132-3CB406CF3231}"), MPT_PATHSTRING("ParamEq"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = kDmoMagic;
-		plug->pluginId2 = 0x120CED89;
-		plug->category = VSTPluginLib::catDMO;
+		VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(plugin.createProc, true, mpt::PathString::FromUTF8(plugin.filename), mpt::PathString::FromUTF8(plugin.name));
+		if(plug != nullptr)
+		{
+			pluginList.push_back(plug);
+			plug->pluginId1 = plugin.pluginId1;
+			plug->pluginId2 = plugin.pluginId2;
+			plug->category = plugin.category;
+			plug->isInstrument = plugin.isInstrument;
+#ifdef MODPLUG_TRACKER
+			if(plugin.isOurs)
+				plug->vendor = _T("OpenMPT Project");
+#endif // MODPLUG_TRACKER
+		}
 	}
 
-	plug = new (std::nothrow) VSTPluginLib(DMO::WavesReverb::Create, true, MPT_PATHSTRING("{87FC0268-9A55-4360-95AA-004A1D9DE26C}"), MPT_PATHSTRING("WavesReverb"));
-	if(plug != nullptr)
-	{
-		pluginList.push_back(plug);
-		plug->pluginId1 = kDmoMagic;
-		plug->pluginId2 = 0x87FC0268;
-		plug->category = VSTPluginLib::catDMO;
-	}
-#endif // NO_DMO
+#ifdef MODPLUG_TRACKER
+	// For security reasons, we do not load untrusted DMO plugins in libopenmpt.
+	EnumerateDirectXDMOs();
+#endif
 }
 
 
 CVstPluginManager::~CVstPluginManager()
-//-------------------------------------
 {
-	for(const_iterator p = begin(); p != end(); p++)
+	for(auto &plug : pluginList)
 	{
-		while((**p).pPluginsList != nullptr)
+		while(plug->pPluginsList != nullptr)
 		{
-			(**p).pPluginsList->Release();
+			plug->pPluginsList->Release();
 		}
-		delete *p;
+		delete plug;
 	}
-	#if MPT_OS_WINDOWS && !defined(NO_DMO)
+	#ifndef NO_DMO
 		if(MustUnInitilizeCOM)
 		{
 			CoUninitialize();
@@ -259,48 +220,29 @@ CVstPluginManager::~CVstPluginManager()
 
 
 bool CVstPluginManager::IsValidPlugin(const VSTPluginLib *pLib) const
-//-------------------------------------------------------------------
 {
-	for(const_iterator p = begin(); p != end(); p++)
-	{
-		if(*p == pLib) return true;
-	}
-	return false;
+	return std::find(pluginList.begin(), pluginList.end(), pLib) != pluginList.end();
 }
 
 
-#ifndef NO_DMO
-
-static GUID make_GUID(uint32 d1, uint16 d2, uint16 d3, uint8 d41, uint8 d42, uint8 d43, uint8 d44, uint8 d45, uint8 d46, uint8 d47, uint8 d48)
-{
-	GUID guid = { d1, d2, d3, d41, d42, d43, d44, d45, d46, d47, d48 };
-	return guid;
-}
-
-static bool IsKnownDMO(const CLSID &clsid)
-//----------------------------------------
+void CVstPluginManager::EnumerateDirectXDMOs()
 {
-	if(IsEqualGUID(clsid, make_GUID(0xEFE6629C, 0x81F7, 0x4281u, 0xBD, 0x91, 0xC9, 0xD6, 0x04, 0xA9, 0x5A, 0xF6))) return true; // Chorus
-	if(IsEqualGUID(clsid, make_GUID(0xEF011F79, 0x4000, 0x406Du, 0x87, 0xAF, 0xBF, 0xFB, 0x3F, 0xC3, 0x9D, 0x57))) return true; // Compressor
-	if(IsEqualGUID(clsid, make_GUID(0xEF114C90, 0xCD1D, 0x484Eu, 0x96, 0xE5, 0x09, 0xCF, 0xAF, 0x91, 0x2A, 0x21))) return true; // Distortion
-	if(IsEqualGUID(clsid, make_GUID(0xEF3E932C, 0xD40B, 0x4F51u, 0x8C, 0xCF, 0x3F, 0x98, 0xF1, 0xB2, 0x9D, 0x5D))) return true; // Echo
-	if(IsEqualGUID(clsid, make_GUID(0xEFCA3D92, 0xDFD8, 0x4672u, 0xA6, 0x03, 0x74, 0x20, 0x89, 0x4B, 0xAD, 0x98))) return true; // Flanger
-	if(IsEqualGUID(clsid, make_GUID(0xDAFD8210, 0x5711, 0x4B91u, 0x9F, 0xE3, 0xF7, 0x5B, 0x7A, 0xE2, 0x79, 0xBF))) return true; // Gargle
-	if(IsEqualGUID(clsid, make_GUID(0xEF985E71, 0xD5C7, 0x42D4u, 0xBA, 0x4D, 0x2D, 0x07, 0x3E, 0x2E, 0x96, 0xF4))) return true; // I3DL2Reverb
-	if(IsEqualGUID(clsid, make_GUID(0x120CED89, 0x3BF4, 0x4173u, 0xA1, 0x32, 0x3C, 0xB4, 0x06, 0xCF, 0x32, 0x31))) return true; // ParamEq
-	if(IsEqualGUID(clsid, make_GUID(0x87FC0268, 0x9A55, 0x4360u, 0x95, 0xAA, 0x00, 0x4A, 0x1D, 0x9D, 0xE2, 0x6C))) return true; // WavesReverb
-	return false;
-}
-
-#endif // !NO_DMO
-
+#ifndef NO_DMO
+	const mpt::UUID knownDMOs[] =
+	{
+		MPT_UUID(745057C7,F353,4F2D,A7EE,58434477730E), // AEC (Acoustic echo cancellation, not usable)
+		MPT_UUID(EFE6629C,81F7,4281,BD91,C9D604A95AF6), // Chorus
+		MPT_UUID(EF011F79,4000,406D,87AF,BFFB3FC39D57), // Compressor
+		MPT_UUID(EF114C90,CD1D,484E,96E5,09CFAF912A21), // Distortion
+		MPT_UUID(EF3E932C,D40B,4F51,8CCF,3F98F1B29D5D), // Echo
+		MPT_UUID(EFCA3D92,DFD8,4672,A603,7420894BAD98), // Flanger
+		MPT_UUID(DAFD8210,5711,4B91,9FE3,F75B7AE279BF), // Gargle
+		MPT_UUID(EF985E71,D5C7,42D4,BA4D,2D073E2E96F4), // I3DL2Reverb
+		MPT_UUID(120CED89,3BF4,4173,A132,3CB406CF3231), // ParamEq
+		MPT_UUID(87FC0268,9A55,4360,95AA,004A1D9DE26C), // WavesReverb
+		MPT_UUID(F447B69E,1884,4A7E,8055,346F74D6EDB3), // Resampler DMO (not usable)
+	};
 
-void CVstPluginManager::EnumerateDirectXDMOs(bool loadDMOSystemUnknown)
-//---------------------------------------------------------------------
-{
-#ifdef NO_DMO
-	MPT_UNREFERENCED_PARAMETER(loadDMOSystemUnknown);
-#else
 	HKEY hkEnum;
 	WCHAR keyname[128];
 
@@ -314,7 +256,7 @@ void CVstPluginManager::EnumerateDirectXDMOs(bool loadDMOSystemUnknown)
 			std::wstring formattedKey = std::wstring(L"{") + std::wstring(keyname) + std::wstring(L"}");
 			if(Util::VerifyStringToCLSID(formattedKey, clsid))
 			{
-				if(loadDMOSystemUnknown || IsKnownDMO(clsid))
+				if(std::find(std::begin(knownDMOs), std::end(knownDMOs), clsid) == std::end(knownDMOs))
 				{
 					HKEY hksub;
 					formattedKey = std::wstring(L"software\\classes\\DirectShow\\MediaObjects\\") + std::wstring(keyname);
@@ -331,12 +273,19 @@ void CVstPluginManager::EnumerateDirectXDMOs(bool loadDMOSystemUnknown)
 							VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(DMOPlugin::Create, true, mpt::PathString::FromNative(Util::GUIDToString(clsid)), mpt::PathString::FromNative(name));
 							if(plug != nullptr)
 							{
-								pluginList.push_back(plug);
-								plug->pluginId1 = kDmoMagic;
-								plug->pluginId2 = clsid.Data1;
-								plug->category = VSTPluginLib::catDMO;
+								try
+								{
+									pluginList.push_back(plug);
+									plug->pluginId1 = kDmoMagic;
+									plug->pluginId2 = clsid.Data1;
+									plug->category = VSTPluginLib::catDMO;
+								} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+								{
+									MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+									delete plug;
+								}
 #ifdef DMO_LOG
-								Log(mpt::String::Print(L"Found \"%1\" clsid=%2\n", plug->libraryName, plug->dllPath));
+								Log(mpt::format(L"Found \"%1\" clsid=%2\n")(plug->libraryName, plug->dllPath));
 #endif
 							}
 						}
@@ -355,7 +304,6 @@ void CVstPluginManager::EnumerateDirectXDMOs(bool loadDMOSystemUnknown)
 // Extract instrument and category information from plugin.
 #ifndef NO_VST
 static void GetPluginInformation(AEffect *effect, VSTPluginLib &library)
-//----------------------------------------------------------------------
 {
 	unsigned long exception = 0;
 	library.category = static_cast<VSTPluginLib::PluginCategory>(CVstPlugin::DispatchSEH(effect, effGetPlugCategory, 0, 0, nullptr, 0, exception));
@@ -370,10 +318,9 @@ static void GetPluginInformation(AEffect *effect, VSTPluginLib &library)
 	}
 
 #ifdef MODPLUG_TRACKER
-	CStringA s;
-	CVstPlugin::DispatchSEH(effect, effGetVendorString, 0, 0, s.GetBuffer(256), 0, exception);
-	s.ReleaseBuffer();
-	library.vendor = mpt::ToCString(mpt::CharsetLocale, s);
+	std::vector<char> s(256, 0);
+	CVstPlugin::DispatchSEH(effect, effGetVendorString, 0, 0, s.data(), 0, exception);
+	library.vendor = mpt::ToCString(mpt::CharsetLocale, s.data());
 #endif // MODPLUG_TRACKER
 }
 #endif // NO_VST
@@ -382,14 +329,13 @@ static void GetPluginInformation(AEffect *effect, VSTPluginLib &library)
 #ifdef MODPLUG_TRACKER
 // Add a plugin to the list of known plugins.
 VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, const mpt::ustring &tags, bool fromCache, const bool checkFileExistence, std::wstring *const errStr)
-//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	const mpt::PathString fileName = dllPath.GetFileName();
 
 	// Check if this is already a known plugin.
-	for(const_iterator dupePlug = begin(); dupePlug != end(); dupePlug++)
+	for(const auto &dupePlug : pluginList)
 	{
-		if(!dllPath.CompareNoCase(dllPath, (**dupePlug).dllPath)) return *dupePlug;
+		if(!dllPath.CompareNoCase(dllPath, dupePlug->dllPath)) return dupePlug;
 	}
 
 	if(checkFileExistence && errStr != nullptr && !dllPath.IsFile())
@@ -401,52 +347,52 @@ VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, const
 	if(fromCache)
 	{
 		SettingsContainer & cacheFile = theApp.GetPluginCache();
-		const mpt::ustring IDs = cacheFile.Read<mpt::ustring>(cacheSection, fileName.ToUnicode(), MPT_USTRING(""));
+		// First try finding the full path
+		mpt::ustring IDs = cacheFile.Read<mpt::ustring>(cacheSection, dllPath.ToUnicode(), MPT_USTRING(""));
+		if(IDs.length() < 16)
+		{
+			// If that didn't work out, find relative path
+			mpt::PathString relPath = theApp.AbsolutePathToRelative(dllPath);
+			IDs = cacheFile.Read<mpt::ustring>(cacheSection, relPath.ToUnicode(), MPT_USTRING(""));
+		}
 
 		if(IDs.length() >= 16)
 		{
-			// Get path from cache file
-			mpt::PathString realPath = cacheFile.Read<mpt::PathString>(cacheSection, IDs, MPT_PATHSTRING(""));
-			realPath = theApp.RelativePathToAbsolute(realPath);
+			VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(nullptr, false, dllPath, fileName, tags);
+			if(plug == nullptr)
+			{
+				return nullptr;
+			}
+			pluginList.push_back(plug);
 
-			if(!realPath.empty() && !dllPath.CompareNoCase(realPath, dllPath))
+			// Extract plugin IDs
+			for (int i = 0; i < 16; i++)
 			{
-				VSTPluginLib *plug = new (std::nothrow) VSTPluginLib(nullptr, false, dllPath, fileName, tags);
-				if(plug == nullptr)
+				int32 n = IDs[i] - '0';
+				if (n > 9) n = IDs[i] + 10 - 'A';
+				n &= 0x0f;
+				if (i < 8)
 				{
-					return nullptr;
-				}
-				pluginList.push_back(plug);
-
-				// Extract plugin IDs
-				for (int i = 0; i < 16; i++)
+					plug->pluginId1 = (plug->pluginId1 << 4) | n;
+				} else
 				{
-					int32 n = IDs[i] - '0';
-					if (n > 9) n = IDs[i] + 10 - 'A';
-					n &= 0x0f;
-					if (i < 8)
-					{
-						plug->pluginId1 = (plug->pluginId1 << 4) | n;
-					} else
-					{
-						plug->pluginId2 = (plug->pluginId2 << 4) | n;
-					}
+					plug->pluginId2 = (plug->pluginId2 << 4) | n;
 				}
+			}
 
-				const mpt::ustring flagKey = IDs + MPT_USTRING(".Flags");
-				plug->DecodeCacheFlags(cacheFile.Read<int32>(cacheSection, flagKey, 0));
-				plug->vendor = cacheFile.Read<CString>(cacheSection, IDs + MPT_USTRING(".Vendor"), CString());
+			const mpt::ustring flagKey = IDs + MPT_USTRING(".Flags");
+			plug->DecodeCacheFlags(cacheFile.Read<int32>(cacheSection, flagKey, 0));
+			plug->vendor = cacheFile.Read<CString>(cacheSection, IDs + MPT_USTRING(".Vendor"), CString());
 
 #ifdef VST_LOG
-				Log("Plugin \"%s\" found in PluginCache\n", plug->libraryName.ToLocale().c_str());
+			Log("Plugin \"%s\" found in PluginCache\n", plug->libraryName.ToLocale().c_str());
 #endif // VST_LOG
-				return plug;
-			} else
-			{
+			return plug;
+		} else
+		{
 #ifdef VST_LOG
-				Log("Plugin \"%s\" mismatch in PluginCache: \"%s\" [%s]=\"%s\"\n", s, dllPath, (LPCTSTR)IDs, (LPCTSTR)strFullPath);
+			Log("Plugin \"%s\" mismatch in PluginCache: \"%s\" [%s]=\"%s\"\n", s, dllPath, (LPCTSTR)IDs, (LPCTSTR)strFullPath);
 #endif // VST_LOG
-			}
 		}
 	}
 
@@ -494,7 +440,7 @@ VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, const
 	FreeLibrary(hLib);
 	if(exception != 0)
 	{
-		CVstPluginManager::ReportPlugException(mpt::String::Print(L"Exception %1 while trying to load plugin \"%2\"!\n", mpt::wfmt::HEX<8>(exception), plug->libraryName));
+		CVstPluginManager::ReportPlugException(mpt::format(L"Exception %1 while trying to load plugin \"%2\"!\n")(mpt::wfmt::HEX<8>(exception), plug->libraryName));
 	}
 #endif // NO_VST
 
@@ -517,7 +463,6 @@ VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, const
 
 // Remove a plugin from the list of known plugins and release any remaining instances of it.
 bool CVstPluginManager::RemovePlugin(VSTPluginLib *pFactory)
-//----------------------------------------------------------
 {
 	for(const_iterator p = begin(); p != end(); p++)
 	{
@@ -543,7 +488,6 @@ bool CVstPluginManager::RemovePlugin(VSTPluginLib *pFactory)
 
 // Create an instance of a plugin.
 bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile)
-//-----------------------------------------------------------------------------------
 {
 	VSTPluginLib *pFound = nullptr;
 #ifdef MODPLUG_TRACKER
@@ -552,15 +496,19 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd
 
 	// Find plugin in library
 	int8 match = 0;	// "Match quality" of found plugin. Higher value = better match.
-	for(const_iterator p = begin(); p != end(); p++)
+#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
+	const mpt::PathString libraryName = mpt::PathString::FromUTF8(mixPlugin.GetLibraryName());
+#else
+	const std::string libraryName = mpt::ToLowerCaseAscii(mixPlugin.GetLibraryName());
+#endif
+	for(const auto &plug : pluginList)
 	{
-		VSTPluginLib *plug = *p;
 		const bool matchID = (plug->pluginId1 == mixPlugin.Info.dwPluginId1)
 			&& (plug->pluginId2 == mixPlugin.Info.dwPluginId2);
-#if MPT_OS_WINDOWS
-		const bool matchName = !mpt::PathString::CompareNoCase(plug->libraryName, mpt::PathString::FromUTF8(mixPlugin.GetLibraryName()));
+#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
+		const bool matchName = !mpt::PathString::CompareNoCase(plug->libraryName, libraryName);
 #else
-		const bool matchName = (mpt::ToLowerCaseAscii(plug->libraryName.ToUTF8()) == mpt::ToLowerCaseAscii(mixPlugin.GetLibraryName()));
+		const bool matchName = (mpt::ToLowerCaseAscii(plug->libraryName.ToUTF8()) == libraryName);
 #endif
 
 		if(matchID && matchName)
@@ -649,7 +597,7 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd
 		if(!validPlugin)
 		{
 			FreeLibrary(hLibrary);
-			CVstPluginManager::ReportPlugException(mpt::String::Print(L"Unable to create plugin \"%1\"!\n", pFound->libraryName));
+			CVstPluginManager::ReportPlugException(mpt::format(L"Unable to create plugin \"%1\"!\n")(pFound->libraryName));
 		}
 		return validPlugin;
 	} else
@@ -668,12 +616,11 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd
 
 #ifdef MODPLUG_TRACKER
 void CVstPluginManager::OnIdle()
-//------------------------------
 {
-	for(const_iterator pFactory = begin(); pFactory != end(); pFactory++)
+	for(auto &factory : pluginList)
 	{
 		// Note: bridged plugins won't receive these messages and generate their own idle messages.
-		IMixPlugin *p = (**pFactory).pPluginsList;
+		IMixPlugin *p = factory->pPluginsList;
 		while (p)
 		{
 			//rewbs. VSTCompliance: A specific plug has requested indefinite periodic processing time.
@@ -693,7 +640,6 @@ void CVstPluginManager::OnIdle()
 
 
 void CVstPluginManager::ReportPlugException(const std::string &msg)
-//-----------------------------------------------------------------
 {
 	Reporting::Notification(msg.c_str());
 #ifdef VST_LOG
@@ -702,7 +648,6 @@ void CVstPluginManager::ReportPlugException(const std::string &msg)
 }
 
 void CVstPluginManager::ReportPlugException(const std::wstring &msg)
-//--------------------------------------------------------------
 {
 	Reporting::Notification(msg);
 #ifdef VST_LOG
diff --git a/soundlib/plugins/PluginManager.h b/soundlib/plugins/PluginManager.h
index 60ba348..9193273 100644
--- a/soundlib/plugins/PluginManager.h
+++ b/soundlib/plugins/PluginManager.h
@@ -127,13 +127,11 @@ public:
 };
 
 
-//=====================
 class CVstPluginManager
-//=====================
 {
 #ifndef NO_PLUGINS
 protected:
-#if MPT_OS_WINDOWS && !defined(NO_DMO)
+#ifndef NO_DMO
 	bool MustUnInitilizeCOM;
 #endif
 	std::vector<VSTPluginLib *> pluginList;
@@ -160,7 +158,7 @@ public:
 	static void ReportPlugException(const std::string &msg);
 
 protected:
-	void EnumerateDirectXDMOs(bool loadDMOSystemUnknown);
+	void EnumerateDirectXDMOs();
 
 #else // NO_PLUGINS
 public:
diff --git a/soundlib/plugins/PluginMixBuffer.h b/soundlib/plugins/PluginMixBuffer.h
index a8cc9f5..07a81f1 100644
--- a/soundlib/plugins/PluginMixBuffer.h
+++ b/soundlib/plugins/PluginMixBuffer.h
@@ -16,9 +16,7 @@ OPENMPT_NAMESPACE_BEGIN
 // buffer_t: Sample buffer type (float, double, ...)
 // bufferSize: Buffer size in samples
 template<typename buffer_t, uint32 bufferSize>
-//===================
 class PluginMixBuffer
-//===================
 {
 protected:
 
@@ -29,12 +27,11 @@ protected:
 
 	// Align buffer to 16 bytes
 	static_assert(sizeof(buffer_t) < 16, "Check buffer alignment code");
-	static const size_t bufferAlignmentInBytes = (16 - 1);
-	static const size_t additionalBuffer = bufferAlignmentInBytes / sizeof(buffer_t);
+	static const uintptr_t bufferAlignmentInBytes = (16 - 1);
+	static const uintptr_t additionalBuffer = bufferAlignmentInBytes / sizeof(buffer_t);
 
 	// Return pointer to an aligned buffer
-	buffer_t *GetBuffer(uint32 index) const
-	//-------------------------------------
+	buffer_t *GetBuffer(size_t index) const
 	{
 		MPT_ASSERT(index < inputs.size() + outputs.size());
 		return &alignedBuffer[bufferSize * index];
@@ -44,7 +41,6 @@ public:
 
 	// Allocate input and output buffers
 	bool Initialize(uint32 numInputs, uint32 numOutputs)
-	//--------------------------------------------------
 	{
 		// Short cut - we do not need to recreate the buffers.
 		if(inputs.size() == numInputs && outputs.size() == numOutputs)
@@ -62,9 +58,10 @@ public:
 			mixBuffer.assign(totalBufferSize, 0);
 
 			// Align buffer start.
-			alignedBuffer = reinterpret_cast<buffer_t *>((reinterpret_cast<intptr_t>(&mixBuffer[0]) + bufferAlignmentInBytes) & ~bufferAlignmentInBytes);
-		} catch(MPTMemoryException)
+			alignedBuffer = reinterpret_cast<buffer_t *>((reinterpret_cast<uintptr_t>(mixBuffer.data()) + bufferAlignmentInBytes) & ~bufferAlignmentInBytes);
+		} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 		{
+			MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 			inputs.clear();
 			outputs.clear();
 			mixBuffer.clear();
@@ -87,7 +84,6 @@ public:
 
 	// Silence all input buffers.
 	void ClearInputBuffers(uint32 numSamples)
-	//---------------------------------------
 	{
 		MPT_ASSERT(numSamples <= bufferSize);
 		for(size_t i = 0; i < inputs.size(); i++)
@@ -98,7 +94,6 @@ public:
 
 	// Silence all output buffers.
 	void ClearOutputBuffers(uint32 numSamples)
-	//----------------------------------------
 	{
 		MPT_ASSERT(numSamples <= bufferSize);
 		for(size_t i = 0; i < outputs.size(); i++)
@@ -108,7 +103,6 @@ public:
 	}
 
 	PluginMixBuffer()
-	//---------------
 	{
 		Initialize(2, 0);
 	}
@@ -118,8 +112,8 @@ public:
 	buffer_t *GetOutputBuffer(uint32 index) const { return GetBuffer(inputs.size() + index); }
 
 	// Return pointer array to all input or output buffers
-	buffer_t **GetInputBufferArray() { return inputs.empty() ? nullptr : &inputs[0]; }
-	buffer_t **GetOutputBufferArray() { return outputs.empty() ? nullptr : &outputs[0]; }
+	buffer_t **GetInputBufferArray() { return inputs.empty() ? nullptr : inputs.data(); }
+	buffer_t **GetOutputBufferArray() { return outputs.empty() ? nullptr : outputs.data(); }
 
 	bool Ok() const { return alignedBuffer != nullptr; }
 };
diff --git a/soundlib/plugins/PluginStructs.h b/soundlib/plugins/PluginStructs.h
index e852ee8..cbca759 100644
--- a/soundlib/plugins/PluginStructs.h
+++ b/soundlib/plugins/PluginStructs.h
@@ -30,66 +30,54 @@ class CSoundFile;
 
 #ifndef NO_PLUGINS
 
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(push, 1)
-#endif
-
-struct PACKED SNDMIXPLUGININFO
+struct SNDMIXPLUGININFO
 {
 	// dwInputRouting flags
 	enum RoutingFlags
 	{
-		irApplyToMaster	= 0x01,		// Apply to master mix
-		irBypass		= 0x02,		// Bypass effect
-		irWetMix		= 0x04,		// Wet Mix (dry added)
-		irExpandMix		= 0x08,		// [0%,100%] -> [-200%,200%]
-		irAutoSuspend	= 0x10,		// Plugin will automatically suspend on silence
+		irApplyToMaster	= 0x01,	// Apply to master mix
+		irBypass		= 0x02,	// Bypass effect
+		irWetMix		= 0x04,	// Wet Mix (dry added)
+		irExpandMix		= 0x08,	// [0%,100%] -> [-200%,200%]
+		irAutoSuspend	= 0x10,	// Plugin will automatically suspend on silence
 	};
 
-	int32 dwPluginId1;				// Plugin type (kEffectMagic, kDmoMagic, kBuzzMagic)
-	int32 dwPluginId2;				// Plugin unique ID
-	uint8 routingFlags;				// See RoutingFlags
-	uint8 mixMode;
-	uint8 gain;						// Divide by 10 to get real gain
-	uint8 reserved;
-	uint32 dwOutputRouting;			// 0 = send to master 0x80 + x = send to plugin x
-	uint32 dwReserved[4];			// Reserved for routing info
-	char szName[32];				// User-chosen plugin display name - this is locale ANSI!
-	char szLibraryName[64];			// original DLL name - this is UTF-8!
+	int32le dwPluginId1;			// Plugin type (kEffectMagic, kDmoMagic, kBuzzMagic)
+	int32le dwPluginId2;			// Plugin unique ID
+	uint8le routingFlags;			// See RoutingFlags
+	uint8le mixMode;
+	uint8le gain;					// Divide by 10 to get real gain
+	uint8le reserved;
+	uint32le dwOutputRouting;		// 0 = send to master 0x80 + x = send to plugin x
+	uint32le dwReserved[4];			// Reserved for routing info
+	char    szName[32];				// User-chosen plugin display name - this is locale ANSI!
+	char    szLibraryName[64];		// original DLL name - this is UTF-8!
 
 	// Should only be called from SNDMIXPLUGIN::SetBypass() and IMixPlugin::Bypass()
-	void SetBypass(bool bypass = true) { if(bypass) routingFlags |= irBypass; else routingFlags &= ~irBypass; }
-
-	// Convert all multi-byte numeric values to current platform's endianness or vice versa.
-	void ConvertEndianness()
-	{
-		SwapBytesLE(dwPluginId1);
-		SwapBytesLE(dwPluginId2);
-		SwapBytesLE(dwOutputRouting);
-		SwapBytesLE(dwReserved[0]);
-		SwapBytesLE(dwReserved[1]);
-		SwapBytesLE(dwReserved[2]);
-		SwapBytesLE(dwReserved[3]);
-	}
+	void SetBypass(bool bypass = true) { if(bypass) routingFlags |= irBypass; else routingFlags &= uint8(~irBypass); }
 };
 
-STATIC_ASSERT(sizeof(SNDMIXPLUGININFO) == 128);	// this is directly written to files, so the size must be correct!
-
-#ifdef NEEDS_PRAGMA_PACK
-#pragma pack(pop)
-#endif
+MPT_BINARY_STRUCT(SNDMIXPLUGININFO, 128)	// this is directly written to files, so the size must be correct!
 
 
 struct SNDMIXPLUGIN
 {
 	IMixPlugin *pMixPlugin;
-	char *pPluginData;
-	uint32 nPluginDataSize;
+	std::vector<mpt::byte> pluginData;
 	SNDMIXPLUGININFO Info;
 	float fDryRatio;
 	int32 defaultProgram;
 	int32 editorX, editorY;
 
+	SNDMIXPLUGIN()
+		: pMixPlugin(nullptr)
+		, fDryRatio(0.0f)
+		, defaultProgram(0)
+		, editorX(0), editorY(0)
+	{
+		MemsetZero(Info);
+	}
+
 	const char *GetName() const
 		{ return Info.szName; }
 	const char *GetLibraryName() const
@@ -119,14 +107,14 @@ struct SNDMIXPLUGIN
 	void SetMixMode(uint8 mixMode)
 		{ Info.mixMode = mixMode; }
 	void SetMasterEffect(bool master = true)
-		{ if(master) Info.routingFlags |= SNDMIXPLUGININFO::irApplyToMaster; else Info.routingFlags &= ~SNDMIXPLUGININFO::irApplyToMaster; }
+		{ if(master) Info.routingFlags |= SNDMIXPLUGININFO::irApplyToMaster; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irApplyToMaster); }
 	void SetWetMix(bool wetMix = true)
-		{ if(wetMix) Info.routingFlags |= SNDMIXPLUGININFO::irWetMix; else Info.routingFlags &= ~SNDMIXPLUGININFO::irWetMix; }
+		{ if(wetMix) Info.routingFlags |= SNDMIXPLUGININFO::irWetMix; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irWetMix); }
 	void SetExpandedMix(bool expanded = true)
-		{ if(expanded) Info.routingFlags |= SNDMIXPLUGININFO::irExpandMix; else Info.routingFlags &= ~SNDMIXPLUGININFO::irExpandMix; }
+		{ if(expanded) Info.routingFlags |= SNDMIXPLUGININFO::irExpandMix; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irExpandMix); }
 	void SetBypass(bool bypass = true);
 	void SetAutoSuspend(bool suspend = true)
-		{ if(suspend) Info.routingFlags |= SNDMIXPLUGININFO::irAutoSuspend; else Info.routingFlags &= ~SNDMIXPLUGININFO::irAutoSuspend; }
+		{ if(suspend) Info.routingFlags |= SNDMIXPLUGININFO::irAutoSuspend; else Info.routingFlags &= uint8(~SNDMIXPLUGININFO::irAutoSuspend); }
 
 	// Output routing getters
 	bool IsOutputToMaster() const
diff --git a/soundlib/plugins/dmo/Chorus.cpp b/soundlib/plugins/dmo/Chorus.cpp
new file mode 100644
index 0000000..56d11f2
--- /dev/null
+++ b/soundlib/plugins/dmo/Chorus.cpp
@@ -0,0 +1,277 @@
+/*
+ * Chorus.cpp
+ * ----------
+ * Purpose: Implementation of the DMO Chorus DSP (for non-Windows platforms)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#ifndef NO_PLUGINS
+#include "../../Sndfile.h"
+#include "Chorus.h"
+#endif // !NO_PLUGINS
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifndef NO_PLUGINS
+
+namespace DMO
+{
+
+IMixPlugin* Chorus::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+{
+	return new (std::nothrow) Chorus(factory, sndFile, mixStruct);
+}
+
+
+Chorus::Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+	: IMixPlugin(factory, sndFile, mixStruct)
+{
+	m_param[kChorusWetDryMix] = 0.5f;
+	m_param[kChorusDepth] = 0.1f;
+	m_param[kChorusFrequency] = 0.11f;
+	m_param[kChorusWaveShape] = 1.0f;
+	m_param[kChorusPhase] = 0.75f;
+	m_param[kChorusFeedback] = (25.0f + 99.0f) / 198.0f;
+	m_param[kChorusDelay] = 0.8f;
+
+	m_mixBuffer.Initialize(2, 2);
+	InsertIntoFactoryList();
+}
+
+
+// Integer part of buffer position
+int32 Chorus::GetBufferIntOffset(int32 fpOffset) const
+{
+	if(fpOffset < 0)
+		fpOffset += m_bufSize * 4096;
+	MPT_ASSERT(fpOffset >= 0);
+	return (fpOffset / 4096) % m_bufSize;
+}
+
+
+void Chorus::Process(float *pOutL, float *pOutR, uint32 numFrames)
+{
+	if(!m_bufSize || !m_mixBuffer.Ok())
+		return;
+
+	const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
+	float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
+
+	const bool isTriangle = IsTriangle();
+
+	const float feedback = Feedback() / 100.0f;
+	const float wetDryMix = WetDryMix();
+	const uint32 phase = Phase();
+	for(uint32 i = numFrames; i != 0; i--)
+	{
+		const float leftIn = *(in[0])++;
+		const float rightIn = *(in[1])++;
+
+		int32 readOffset = GetBufferIntOffset(m_bufPos + m_delayOffset);
+		int32 writeOffset = GetBufferIntOffset(m_bufPos);
+		m_buffer[writeOffset] = (m_buffer[readOffset] * feedback) + (rightIn + leftIn) * 0.5f;
+
+		float waveMin;
+		float waveMax;
+		if(isTriangle)
+		{
+			m_waveShapeMin += m_waveShapeVal;
+			m_waveShapeMax += m_waveShapeVal;
+			if(m_waveShapeMin > 1)
+				m_waveShapeMin -= 2;
+			if(m_waveShapeMax > 1)
+				m_waveShapeMax -= 2;
+			waveMin = mpt::abs(m_waveShapeMin) * 2 - 1;
+			waveMax = mpt::abs(m_waveShapeMax) * 2 - 1;
+		} else
+		{
+			m_waveShapeMin = m_waveShapeMax * m_waveShapeVal + m_waveShapeMin;
+			m_waveShapeMax = m_waveShapeMax - m_waveShapeMin * m_waveShapeVal;
+			waveMin = m_waveShapeMin;
+			waveMax = m_waveShapeMax;
+		}
+
+		float left1 = m_buffer[GetBufferIntOffset(m_bufPos + m_delayL1)];
+		float left2 = m_buffer[GetBufferIntOffset(m_bufPos + m_delayL2)];
+		float fracPos = (m_delayL1 & 0xFFF) * (1.0f / 4096.0f);
+		float leftOut = (left2 - left1) * fracPos + left1;
+		*(out[0])++ = leftIn + (leftOut - leftIn) * wetDryMix;
+
+		float right1 = m_buffer[GetBufferIntOffset(m_bufPos + m_delayR1)];
+		float right2 = m_buffer[GetBufferIntOffset(m_bufPos + m_delayR2)];
+		fracPos = (m_delayR1 & 0xFFF) * (1.0f / 4096.0f);
+		float rightOut = (right2 - right1) * fracPos + right1;
+		*(out[1])++ = rightIn + (rightOut - rightIn) * wetDryMix;
+
+		// Increment delay positions
+		m_delayL1 = m_delayOffset + (phase < 4 ? 1 : -1) * static_cast<int32>(waveMin * m_depthDelay);
+		m_delayL2 = m_delayL1 + 4096;
+
+		m_delayR1 = m_delayOffset + (phase < 2 ? -1 : 1) * static_cast<int32>(((phase % 2u) ? waveMax : waveMin) * m_depthDelay);
+		m_delayR2 = m_delayR1 + 4096;
+
+		if(m_bufPos <= 0)
+			m_bufPos += m_bufSize * 4096;
+		m_bufPos -= 4096;
+	}
+
+	ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
+}
+
+
+PlugParamValue Chorus::GetParameter(PlugParamIndex index)
+{
+	if(index < kChorusNumParameters)
+	{
+		return m_param[index];
+	}
+	return 0;
+}
+
+
+void Chorus::SetParameter(PlugParamIndex index, PlugParamValue value)
+{
+	if(index < kChorusNumParameters)
+	{
+		Limit(value, 0.0f, 1.0f);
+		if(index == kChorusWaveShape && value < 1.0f)
+			value = 0.0f;
+		else if(index == kChorusPhase)
+			value = Util::Round(value * 4.0f) / 4.0f;
+		m_param[index] = value;
+		RecalculateChorusParams();
+	}
+}
+
+
+void Chorus::Resume()
+{
+	PositionChanged();
+	RecalculateChorusParams();
+
+	m_isResumed = true;
+	m_waveShapeMin = 0.0f;
+	m_waveShapeMax = IsTriangle() ? 0.5f : 1.0f;
+	m_delayL1 = m_delayL2 = m_delayR1 = m_delayR2 = m_delayOffset;
+	m_bufPos = 0;
+}
+
+
+void Chorus::PositionChanged()
+{
+	m_bufSize = Util::muldiv(m_SndFile.GetSampleRate(), 3840, 1000);
+	try
+	{
+		m_buffer.assign(m_bufSize, 0.0f);
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+		m_bufSize = 0;
+	}
+}
+
+
+#ifdef MODPLUG_TRACKER
+
+CString Chorus::GetParamName(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kChorusWetDryMix: return _T("WetDryMix");
+	case kChorusDepth: return _T("Depth");
+	case kChorusFrequency: return _T("Frequency");
+	case kChorusWaveShape: return _T("WaveShape");
+	case kChorusPhase: return _T("Phase");
+	case kChorusFeedback: return _T("Feedback");
+	case kChorusDelay: return _T("Delay");
+	}
+	return CString();
+}
+
+
+CString Chorus::GetParamLabel(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kChorusWetDryMix:
+	case kChorusDepth:
+	case kChorusFeedback:
+		return _T("%");
+	case kChorusFrequency:
+		return _T("Hz");
+	case kChorusPhase:
+		return _T("°");
+	case kChorusDelay:
+		return _T("ms");
+	}
+	return CString();
+}
+
+
+CString Chorus::GetParamDisplay(PlugParamIndex param)
+{
+	CString s;
+	float value = m_param[param];
+	switch(param)
+	{
+	case kChorusWetDryMix:
+	case kChorusDepth:
+		value *= 100.0f;
+		break;
+	case kChorusFrequency:
+		value = FrequencyInHertz();
+		break;
+	case kChorusWaveShape:
+		return (value < 0.5f) ? _T("Triangle") : _T("Sine");
+		break;
+	case kChorusPhase:
+		switch(Phase())
+		{
+		case 0: return _T("-180");
+		case 1: return _T("-90");
+		case 2: return _T("0");
+		case 3: return _T("90");
+		case 4: return _T("180");
+		}
+		break;
+	case kChorusFeedback:
+		value = Feedback();
+		break;
+	case kChorusDelay:
+		value = Delay();
+	}
+	s.Format(_T("%.2f"), value);
+	return s;
+}
+
+#endif // MODPLUG_TRACKER
+
+
+void Chorus::RecalculateChorusParams()
+{
+	const float sampleRate = static_cast<float>(m_SndFile.GetSampleRate());
+
+	float delaySamples = Delay() * sampleRate / 1000.0f;
+	m_depthDelay = Depth() * delaySamples * 2048.0f;
+	m_delayOffset = Util::Round<int32>(4096.0f * (delaySamples + 2.0f));
+	m_frequency = FrequencyInHertz();
+	const float frequencySamples = m_frequency / sampleRate;
+	if(IsTriangle())
+		m_waveShapeVal = frequencySamples * 2.0f;
+	else
+		m_waveShapeVal = std::sin(frequencySamples * float(M_PI)) * 2.0f;
+}
+
+} // namespace DMO
+
+#else
+MPT_MSVC_WORKAROUND_LNK4221(Chorus)
+
+#endif // !NO_PLUGINS
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Chorus.h b/soundlib/plugins/dmo/Chorus.h
new file mode 100644
index 0000000..8a8c207
--- /dev/null
+++ b/soundlib/plugins/dmo/Chorus.h
@@ -0,0 +1,117 @@
+/*
+ * Chorus.h
+ * --------
+ * Purpose: Implementation of the DMO Chorus DSP (for non-Windows platforms)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#ifndef NO_PLUGINS
+
+#include "../PlugInterface.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+namespace DMO
+{
+
+class Chorus : public IMixPlugin
+{
+protected:
+	enum Parameters
+	{
+		kChorusWetDryMix = 0,
+		kChorusDepth,
+		kChorusFrequency,
+		kChorusWaveShape,
+		kChorusPhase,
+		kChorusFeedback,
+		kChorusDelay,
+		kChorusNumParameters
+	};
+
+	float m_param[kChorusNumParameters];
+
+	// Calculated parameters
+	float m_waveShapeMin, m_waveShapeMax, m_waveShapeVal;
+	float m_depthDelay;
+	float m_frequency;
+	int32 m_delayOffset;
+
+	// State
+	std::vector<float> m_buffer;
+	int32 m_bufPos, m_bufSize;
+
+	int32 m_delayL1, m_delayL2, m_delayR1, m_delayR2;
+
+public:
+	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+	Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xEFE6629C; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
+
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
+
+	float RenderSilence(uint32) override { return 0.0f; }
+
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
+
+	PlugParamIndex GetNumParameters() const override { return kChorusNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
+
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("Chorus"); }
+
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
+
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
+
+	bool HasEditor() const override { return false; }
+#endif
+
+	void BeginSetProgram(int32) override { }
+	void EndSetProgram() override { }
+
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
+
+protected:
+	int32 GetBufferIntOffset(int32 fpOffset) const;
+
+	virtual float WetDryMix() const { return m_param[kChorusWetDryMix]; }
+	virtual bool IsTriangle() const { return m_param[kChorusWaveShape] < 1; }
+	virtual float Depth() const { return m_param[kChorusDepth]; }
+	virtual float Feedback() const { return -99.0f + m_param[kChorusFeedback] * 198.0f; }
+	virtual float Delay() const { return m_param[kChorusDelay] * 20.0f; }
+	virtual float FrequencyInHertz() const { return m_param[kChorusFrequency] * 10.0f; }
+	virtual int Phase() const { return Util::Round<uint32>(m_param[kChorusPhase] * 4.0f); }
+	void RecalculateChorusParams();
+};
+
+} // namespace DMO
+
+OPENMPT_NAMESPACE_END
+
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/Compressor.cpp b/soundlib/plugins/dmo/Compressor.cpp
index 6707685..757e74f 100644
--- a/soundlib/plugins/dmo/Compressor.cpp
+++ b/soundlib/plugins/dmo/Compressor.cpp
@@ -12,14 +12,14 @@
 
 #include "stdafx.h"
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 #include "../../Sndfile.h"
 #include "Compressor.h"
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 namespace DMO
 {
@@ -28,7 +28,6 @@ namespace DMO
 float logGain(float x, int32 shiftL, int32 shiftR);
 
 IMixPlugin* Compressor::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//-------------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) Compressor(factory, sndFile, mixStruct);
 }
@@ -36,7 +35,6 @@ IMixPlugin* Compressor::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMI
 
 Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	: IMixPlugin(factory, sndFile, mixStruct)
-//-----------------------------------------------------------------------------------------
 {
 	m_param[kCompGain] = 0.5f;
 	m_param[kCompAttack] = 0.02f;
@@ -51,7 +49,6 @@ Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN
 
 
 void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//--------------------------------------------------------------------
 {
 	if(!m_bufSize || !m_mixBuffer.Ok())
 		return;
@@ -64,12 +61,8 @@ void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames)
 		float leftIn  = *(in[0])++;
 		float rightIn = *(in[1])++;
 			
-		while(m_bufPos < 0)
-			m_bufPos += m_bufSize * 4096;
-
-		int32 writeOffset = (m_bufPos / 4096) % m_bufSize;
-		m_buffer[writeOffset * 2] = leftIn;
-		m_buffer[writeOffset * 2 + 1] = rightIn;
+		m_buffer[m_bufPos * 2] = leftIn;
+		m_buffer[m_bufPos * 2 + 1] = rightIn;
 
 		leftIn = mpt::abs(leftIn);
 		rightIn = mpt::abs(rightIn);
@@ -96,7 +89,7 @@ void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames)
 		}
 		compGainPow >>= (31 - compGainInt);
 		
-		int32 readOffset = m_predelay + m_bufPos + m_bufSize - 1;
+		int32 readOffset = m_predelay + m_bufPos * 4096 + m_bufSize - 1;
 		readOffset /= 4096;
 		readOffset %= m_bufSize;
 		
@@ -104,7 +97,8 @@ void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames)
 		*(out[0])++ = m_buffer[readOffset * 2] * outGain;
 		*(out[1])++ = m_buffer[readOffset * 2 + 1] * outGain;
 		
-		m_bufPos -= 4096;
+		if(m_bufPos-- == 0)
+			m_bufPos += m_bufSize;
 	}
 
 	ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
@@ -112,7 +106,6 @@ void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 PlugParamValue Compressor::GetParameter(PlugParamIndex index)
-//-----------------------------------------------------------
 {
 	if(index < kCompNumParameters)
 	{
@@ -123,7 +116,6 @@ PlugParamValue Compressor::GetParameter(PlugParamIndex index)
 
 
 void Compressor::SetParameter(PlugParamIndex index, PlugParamValue value)
-//-----------------------------------------------------------------------
 {
 	if(index < kCompNumParameters)
 	{
@@ -135,34 +127,32 @@ void Compressor::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void Compressor::Resume()
-//-----------------------
 {
-	uint64 bufferSize = Util::mul32to64_unsigned(m_SndFile.GetSampleRate(), 200) / 1000;
-	if(bufferSize > uint64(int32_max))
-	{
-		m_bufSize = 0;
-		return;
-	}
-	m_bufSize = static_cast<int32>(bufferSize);
+	m_isResumed = true;
+	PositionChanged();
+	RecalculateCompressorParams();
+}
+
+
+void Compressor::PositionChanged()
+{
+	m_bufSize = Util::muldiv(m_SndFile.GetSampleRate(), 200, 1000);
 	try
 	{
 		m_buffer.assign(m_bufSize * 2, 0.0f);
-	} catch(MPTMemoryException)
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		m_bufSize = 0;
 	}
-
-	m_isResumed = true;
 	m_bufPos = 0;
 	m_peak = 0.0f;
-	RecalculateCompressorParams();
 }
 
 
 #ifdef MODPLUG_TRACKER
 
 CString Compressor::GetParamName(PlugParamIndex param)
-//----------------------------------------------------
 {
 	switch(param)
 	{
@@ -178,7 +168,6 @@ CString Compressor::GetParamName(PlugParamIndex param)
 
 
 CString Compressor::GetParamLabel(PlugParamIndex param)
-//-----------------------------------------------------
 {
 	switch(param)
 	{
@@ -195,7 +184,6 @@ CString Compressor::GetParamLabel(PlugParamIndex param)
 
 
 CString Compressor::GetParamDisplay(PlugParamIndex param)
-//-------------------------------------------------------
 {
 	float value = m_param[param];
 	switch(param)
@@ -220,7 +208,7 @@ CString Compressor::GetParamDisplay(PlugParamIndex param)
 		break;
 	}
 	CString s;
-	s.Format("%.2f", value);
+	s.Format(_T("%.2f"), value);
 	return s;
 }
 
@@ -228,15 +216,14 @@ CString Compressor::GetParamDisplay(PlugParamIndex param)
 
 
 void Compressor::RecalculateCompressorParams()
-//--------------------------------------------
 {
 	const float sampleRate = m_SndFile.GetSampleRate() / 1000.0f;
 	m_gain = std::pow(10.0f, GainInDecibel() / 20.0f);
 	m_attack = std::pow(10.0f, -1.0f / (AttackTime() * sampleRate));
 	m_release = std::pow(10.0f, -1.0f / (ReleaseTime() * sampleRate));
-	const double _2e31 = double(1u << 31);
-	const double _2e26 = double(1u << 26);
-	m_threshold = static_cast<float>(std::min((_2e31 - 1.0), (std::log(std::pow(10.0f, ThresholdInDecibel() / 20.0f) * _2e31) * _2e26) / M_LN2 + _2e26) * (1.0 / _2e31));
+	const float _2e31 = float(1u << 31);
+	const float _2e26 = float(1u << 26);
+	m_threshold = std::min((_2e31 - 1.0f), (std::log(std::pow(10.0f, ThresholdInDecibel() / 20.0f) * _2e31) * _2e26) / static_cast<float>(M_LN2) + _2e26) * (1.0f / _2e31);
 	m_ratio = 1.0f - (1.0f / CompressorRatio());
 	m_predelay = static_cast<int32>((PreDelay() * sampleRate) + 2.0f);
 }
@@ -246,6 +233,6 @@ void Compressor::RecalculateCompressorParams()
 #else
 MPT_MSVC_WORKAROUND_LNK4221(Compressor)
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Compressor.h b/soundlib/plugins/dmo/Compressor.h
index 76e20d1..56fb3ce 100644
--- a/soundlib/plugins/dmo/Compressor.h
+++ b/soundlib/plugins/dmo/Compressor.h
@@ -8,7 +8,7 @@
  */
 
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 #include "../PlugInterface.h"
 
@@ -17,11 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 namespace DMO
 {
 
-//==================================
 class Compressor : public IMixPlugin
-//==================================
 {
-public:
+protected:
 	enum Parameters
 	{
 		kCompGain = 0,
@@ -33,7 +31,6 @@ public:
 		kCompNumParameters
 	};
 
-protected:
 	float m_param[kCompNumParameters];
 
 	// Calculated parameters and coefficients
@@ -53,66 +50,47 @@ public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return 0xEF011F79; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
-
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
-
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
-
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
-
-	virtual PlugParamIndex GetNumParameters() const { return kCompNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
-
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xEF011F79; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-#ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("Compressor"); }
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	PlugParamIndex GetNumParameters() const override { return kCompNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual bool HasEditor() const { return false; }
-#endif
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("Compressor"); }
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual bool ProgramsAreChunks() const { return false; }
+	bool HasEditor() const override { return false; }
+#endif
 
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
 protected:
 	float GainInDecibel() const { return -60.0f + m_param[kCompGain] * 120.0f; }
diff --git a/soundlib/plugins/dmo/DMOPlugin.cpp b/soundlib/plugins/dmo/DMOPlugin.cpp
index 05d6659..2d0032b 100644
--- a/soundlib/plugins/dmo/DMOPlugin.cpp
+++ b/soundlib/plugins/dmo/DMOPlugin.cpp
@@ -2,7 +2,9 @@
  * DMOPlugin.h
  * -----------
  * Purpose: DirectX Media Object plugin handling / processing.
- * Notes  : (currently none)
+ * Notes  : Some default plugins only have the same output characteristics in the floating point code path (compared to integer PCM)
+ *          if we feed them input in the range [-32768, +32768] rather than the more usual [-1, +1].
+ *          Hence, OpenMPT uses this range for both the floating-point and integer path.
  * Authors: OpenMPT Devs
  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  */
@@ -29,7 +31,6 @@ OPENMPT_NAMESPACE_BEGIN
 #define DMO_LOG
 
 IMixPlugin* DMOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//------------------------------------------------------------------------------------------------
 {
 	CLSID clsid;
 	if (Util::VerifyStringToCLSID(factory.dllPath.ToWide(), clsid))
@@ -71,7 +72,6 @@ DMOPlugin::DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *m
 	, m_pMediaParams(nullptr)
 	, m_nSamplesPerSec(sndFile.GetSampleRate())
 	, m_uid(uid)
-//--------------------------------------------------------------------------------------------------------------------------------------------------
 {
 	if(FAILED(m_pMediaObject->QueryInterface(IID_IMediaParamInfo, (void **)&m_pParamInfo)))
 		m_pParamInfo = nullptr;
@@ -86,7 +86,6 @@ DMOPlugin::DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *m
 
 
 DMOPlugin::~DMOPlugin()
-//---------------------
 {
 	if(m_pMediaParams)
 	{
@@ -112,7 +111,6 @@ DMOPlugin::~DMOPlugin()
 
 
 uint32 DMOPlugin::GetLatency() const
-//----------------------------------
 {
 	REFERENCE_TIME time;	// Unit 100-nanoseconds
 	if(m_pMediaProcess->GetLatency(&time) == S_OK)
@@ -128,7 +126,6 @@ static const float _si2f = 1.0f / 32768.0f;
 
 
 static void InterleaveStereo(const float * MPT_RESTRICT inputL, const float * MPT_RESTRICT inputR, float * MPT_RESTRICT output, uint32 numFrames)
-//-----------------------------------------------------------------------------------------------------------------------------------------------
 {
 #if (defined(ENABLE_SSE) || defined(ENABLE_SSE2))
 	if(GetProcSupport() & PROCSUPPORT_SSE)
@@ -163,7 +160,6 @@ static void InterleaveStereo(const float * MPT_RESTRICT inputL, const float * MP
 
 
 static void DeinterleaveStereo(const float * MPT_RESTRICT input, float * MPT_RESTRICT outputL, float * MPT_RESTRICT outputR, uint32 numFrames)
-//--------------------------------------------------------------------------------------------------------------------------------------------
 {
 #if (defined(ENABLE_SSE) || defined(ENABLE_SSE2))
 	if(GetProcSupport() & PROCSUPPORT_SSE)
@@ -199,10 +195,9 @@ static void DeinterleaveStereo(const float * MPT_RESTRICT input, float * MPT_RES
 
 // Interleave two float streams into one int16 stereo stream.
 static void InterleaveFloatToInt16(const float * MPT_RESTRICT inputL, const float * MPT_RESTRICT inputR, int16 * MPT_RESTRICT output, uint32 numFrames)
-//-----------------------------------------------------------------------------------------------------------------------------------------------------
 {
 #ifdef ENABLE_SSE
-	// This uses __m64, so it's not avilable on the MSVC 64-bit compiler.
+	// This uses __m64, so it's not available on the MSVC 64-bit compiler.
 	// But if the user runs a 64-bit operating system, they will go the floating-point path anyway.
 	if(GetProcSupport() & PROCSUPPORT_SSE)
 	{
@@ -252,10 +247,9 @@ static void InterleaveFloatToInt16(const float * MPT_RESTRICT inputL, const floa
 
 // Deinterleave an int16 stereo stream into two float streams.
 static void DeinterleaveInt16ToFloat(const int16 * MPT_RESTRICT input, float * MPT_RESTRICT outputL, float * MPT_RESTRICT outputR, uint32 numFrames)
-//--------------------------------------------------------------------------------------------------------------------------------------------------
 {
 #ifdef ENABLE_SSE
-	// This uses __m64, so it's not avilable on the MSVC 64-bit compiler.
+	// This uses __m64, so it's not available on the MSVC 64-bit compiler.
 	// But if the user runs a 64-bit operating system, they will go the floating-point path anyway.
 	if(GetProcSupport() & PROCSUPPORT_SSE)
 	{
@@ -309,7 +303,6 @@ static void DeinterleaveInt16ToFloat(const int16 * MPT_RESTRICT input, float * M
 
 
 void DMOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//-------------------------------------------------------------------
 {
 	if(!numFrames || !m_mixBuffer.Ok())
 		return;
@@ -318,8 +311,6 @@ void DMOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames)
 	
 	if(m_useFloat)
 	{
-		// Some plugins only have the same output characteristics in the floating point code path (compared to integer PCM)
-		// if we feed them input in the range [-32768, +32768] rather than the more usual [-1, +1].
 		InterleaveStereo(m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1), m_alignedBuffer.f32, numFrames);
 		m_pMediaProcess->Process(numFrames * 2 * sizeof(float), reinterpret_cast<BYTE *>(m_alignedBuffer.f32), startTime, DMO_INPLACE_NORMAL);
 		DeinterleaveStereo(m_alignedBuffer.f32, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
@@ -335,7 +326,6 @@ void DMOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 PlugParamIndex DMOPlugin::GetNumParameters() const
-//------------------------------------------------
 {
 	DWORD dwParamCount = 0;
 	m_pParamInfo->GetParamCount(&dwParamCount);
@@ -344,7 +334,6 @@ PlugParamIndex DMOPlugin::GetNumParameters() const
 
 
 PlugParamValue DMOPlugin::GetParameter(PlugParamIndex index)
-//----------------------------------------------------------
 {
 	if(index < GetNumParameters() && m_pParamInfo != nullptr && m_pMediaParams != nullptr)
 	{
@@ -377,7 +366,6 @@ PlugParamValue DMOPlugin::GetParameter(PlugParamIndex index)
 
 
 void DMOPlugin::SetParameter(PlugParamIndex index, PlugParamValue value)
-//----------------------------------------------------------------------
 {
 	if(index < GetNumParameters() && m_pParamInfo != nullptr && m_pMediaParams != nullptr)
 	{
@@ -405,7 +393,6 @@ void DMOPlugin::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void DMOPlugin::Resume()
-//----------------------
 {
 	m_nSamplesPerSec = m_SndFile.GetSampleRate();
 	m_isResumed = true;
@@ -453,8 +440,14 @@ void DMOPlugin::Resume()
 }
 
 
+void DMOPlugin::PositionChanged()
+{
+	m_pMediaObject->Discontinuity(0);
+	m_pMediaObject->Flush();
+}
+
+
 void DMOPlugin::Suspend()
-//-----------------------
 {
 	m_isResumed = false;
 	m_pMediaObject->Flush();
@@ -466,7 +459,6 @@ void DMOPlugin::Suspend()
 #ifdef MODPLUG_TRACKER
 
 CString DMOPlugin::GetParamName(PlugParamIndex param)
-//---------------------------------------------------
 {
 	if(param < GetNumParameters() && m_pParamInfo != nullptr)
 	{
@@ -485,7 +477,6 @@ CString DMOPlugin::GetParamName(PlugParamIndex param)
 
 
 CString DMOPlugin::GetParamLabel(PlugParamIndex param)
-//----------------------------------------------------
 {
 	if(param < GetNumParameters() && m_pParamInfo != nullptr)
 	{
@@ -503,7 +494,6 @@ CString DMOPlugin::GetParamLabel(PlugParamIndex param)
 
 
 CString DMOPlugin::GetParamDisplay(PlugParamIndex param)
-//------------------------------------------------------
 {
 	if(param < GetNumParameters() && m_pParamInfo != nullptr && m_pMediaParams != nullptr)
 	{
@@ -521,7 +511,7 @@ CString DMOPlugin::GetParamDisplay(PlugParamIndex param)
 				case MPT_FLOAT:
 					{
 						CString s;
-						s.Format("%.2f", md);
+						s.Format(_T("%.2f"), md);
 						return s;
 					}
 					break;
diff --git a/soundlib/plugins/dmo/DMOPlugin.h b/soundlib/plugins/dmo/DMOPlugin.h
index 6525758..0fbb863 100644
--- a/soundlib/plugins/dmo/DMOPlugin.h
+++ b/soundlib/plugins/dmo/DMOPlugin.h
@@ -21,9 +21,7 @@ typedef interface IMediaParams IMediaParams;
 
 OPENMPT_NAMESPACE_BEGIN
 
-//=================================
 class DMOPlugin : public IMixPlugin
-//=================================
 {
 protected:
 	IMediaObject *m_pMediaObject;
@@ -53,66 +51,47 @@ protected:
 	~DMOPlugin();
 
 public:
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return m_uid; }
-	virtual int32 GetVersion() const { return 2; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const;
-
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
-
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
-
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32 /*nIndex*/) { }
-
-	virtual PlugParamIndex GetNumParameters() const;
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
-
-	virtual void Resume();
-	virtual void Suspend();
-	virtual void PositionChanged() { }
-
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return m_uid; }
+	int32 GetVersion() const override { return 2; }
+	void Idle() override { }
+	uint32 GetLatency() const override;
 
-#ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return CString(); }
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32 /*nIndex*/) override { }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex param);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	PlugParamIndex GetNumParameters() const override;
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	// TODO we could simply add our own preset mechanism. But is it really useful for these plugins?
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	void Resume() override;
+	void Suspend() override;
+	void PositionChanged() override;
 
-	virtual bool HasEditor() const { return false; }
-#endif
+	bool IsInstrument() const  override { return false; }
+	bool CanRecieveMidiEvents()  override { return false; }
+	bool ShouldProcessSilence()  override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return CString(); }
+
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex param) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
+	// TODO we could simply add our own preset mechanism. But is it really useful for these plugins?
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual int GetNumInputChannels() const {return 2; }
-	virtual int GetNumOutputChannels() const {return 2; }
+	bool HasEditor() const override { return false; }
+#endif
 
-	virtual bool ProgramsAreChunks() const { return false; }
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 };
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Distortion.cpp b/soundlib/plugins/dmo/Distortion.cpp
index a79e0b4..eb15b0f 100644
--- a/soundlib/plugins/dmo/Distortion.cpp
+++ b/soundlib/plugins/dmo/Distortion.cpp
@@ -12,21 +12,20 @@
 
 #include "stdafx.h"
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 #include "../../Sndfile.h"
 #include "Distortion.h"
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 namespace DMO
 {
 
 // Computes (log2(x) + 1) * 2 ^ (shiftL - shiftR) (x = -2^31...2^31)
 float logGain(float x, int32 shiftL, int32 shiftR)
-//------------------------------------------------
 {
 	uint32 intSample = static_cast<uint32>(static_cast<int32>(x));
 	const uint32 sign = intSample & 0x80000000;
@@ -53,7 +52,6 @@ float logGain(float x, int32 shiftL, int32 shiftR)
 
 
 IMixPlugin* Distortion::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//-------------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) Distortion(factory, sndFile, mixStruct);
 }
@@ -61,7 +59,6 @@ IMixPlugin* Distortion::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMI
 
 Distortion::Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	: IMixPlugin(factory, sndFile, mixStruct)
-//-----------------------------------------------------------------------------------------
 {
 	m_param[kDistGain] = 0.7f;
 	m_param[kDistEdge] = 0.15f;
@@ -75,7 +72,6 @@ Distortion::Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN
 
 
 void Distortion::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//--------------------------------------------------------------------
 {
 	if(!m_mixBuffer.Ok())
 		return;
@@ -113,7 +109,6 @@ void Distortion::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 PlugParamValue Distortion::GetParameter(PlugParamIndex index)
-//-----------------------------------------------------------
 {
 	if(index < kDistNumParameters)
 	{
@@ -124,7 +119,6 @@ PlugParamValue Distortion::GetParameter(PlugParamIndex index)
 
 
 void Distortion::SetParameter(PlugParamIndex index, PlugParamValue value)
-//-----------------------------------------------------------------------
 {
 	if(index < kDistNumParameters)
 	{
@@ -136,11 +130,15 @@ void Distortion::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void Distortion::Resume()
-//-----------------------
 {
 	m_isResumed = true;
 	RecalculateDistortionParams();
+	PositionChanged();
+}
+
 
+void Distortion::PositionChanged()
+{
 	// Reset filter state
 	m_preEQz1[0] = m_preEQz1[1] = 0;
 	m_postEQz1[0] = m_postEQz2[0] = 0;
@@ -151,7 +149,6 @@ void Distortion::Resume()
 #ifdef MODPLUG_TRACKER
 
 CString Distortion::GetParamName(PlugParamIndex param)
-//----------------------------------------------------
 {
 	switch(param)
 	{
@@ -166,7 +163,6 @@ CString Distortion::GetParamName(PlugParamIndex param)
 
 
 CString Distortion::GetParamLabel(PlugParamIndex param)
-//-----------------------------------------------------
 {
 	switch(param)
 	{
@@ -180,7 +176,6 @@ CString Distortion::GetParamLabel(PlugParamIndex param)
 
 
 CString Distortion::GetParamDisplay(PlugParamIndex param)
-//-------------------------------------------------------
 {
 	float value = m_param[param];
 	switch(param)
@@ -198,7 +193,7 @@ CString Distortion::GetParamDisplay(PlugParamIndex param)
 		break;
 	}
 	CString s;
-	s.Format("%.2f", value);
+	s.Format(_T("%.2f"), value);
 	return s;
 }
 
@@ -206,7 +201,6 @@ CString Distortion::GetParamDisplay(PlugParamIndex param)
 
 
 void Distortion::RecalculateDistortionParams()
-//--------------------------------------------
 {
 	// Pre-EQ
 	m_preEQb1 = std::sqrt((2.0f * std::cos(2.0f * float(M_PI) * std::min(FreqInHertz(m_param[kDistPreLowpassCutoff]) / m_SndFile.GetSampleRate(), 0.5f)) + 3.0f) / 5.0f);
@@ -216,7 +210,7 @@ void Distortion::RecalculateDistortionParams()
 	float edge = 2.0f + m_param[kDistEdge] * 29.0f;
 	m_edge = static_cast<uint8>(edge);	// 2...31 shifted bits
 
-	// Work out the magical shift factor (= floor(log2(edge)) + 1 / index of highest bit + 1)
+	// Work out the magical shift factor (= floor(log2(edge)) + 1 == index of highest bit + 1)
 	uint8 shift;
 	if(m_edge <= 3)
 		shift = 2;
@@ -228,16 +222,12 @@ void Distortion::RecalculateDistortionParams()
 		shift = 5;
 	m_shift = shift;
 
-	static const double LogNorm[32] =
+	static const float LogNorm[32] =
 	{
-		1.0000000000000000, 1.0000000000000000, 1.5000000000000000, 1.0000000000000000,
-		1.7500000000000000, 1.3999999999999999, 1.1699999999999999, 1.0000000000000000,
-		1.8799999999999999, 1.7600000000000000, 1.5000000000000000, 1.3600000000000001,
-		1.2500000000000000, 1.1499999999999999, 1.0700000000000001, 1.0000000000000000,
-		1.9399999999999999, 1.8200000000000001, 1.7200000000000000, 1.6299999999999999,
-		1.5500000000000000, 1.4800000000000000, 1.4099999999999999, 1.3500000000000001,
-		1.2900000000000000, 1.2400000000000000, 1.1899999999999999, 1.1499999999999999,
-		1.1100000000000001, 1.0700000000000001, 1.0300000000000000, 1.0000000000000000,
+		1.00f, 1.00f, 1.50f, 1.00f, 1.75f, 1.40f, 1.17f, 1.00f,
+		1.88f, 1.76f, 1.50f, 1.36f, 1.25f, 1.15f, 1.07f, 1.00f,
+		1.94f, 1.82f, 1.72f, 1.63f, 1.55f, 1.48f, 1.41f, 1.35f,
+		1.29f, 1.24f, 1.19f, 1.15f, 1.11f, 1.07f, 1.03f, 1.00f,
 	};
 
 	// Post-EQ
@@ -247,7 +237,7 @@ void Distortion::RecalculateDistortionParams()
 	const float t = std::tan(5.0e-1f * postBw);
 	m_postEQb1 = ((1.0f - t) / (1.0f + t));
 	m_postEQb0 = -std::cos(postFreq);
-	m_postEQa0 = static_cast<float>(gain * std::sqrt(1.0f - m_postEQb0 * m_postEQb0) * std::sqrt(1.0f - m_postEQb1 * m_postEQb1) * LogNorm[m_edge]);
+	m_postEQa0 = gain * std::sqrt(1.0f - m_postEQb0 * m_postEQb0) * std::sqrt(1.0f - m_postEQb1 * m_postEQb1) * LogNorm[m_edge];
 }
 
 } // namespace DMO
@@ -255,6 +245,6 @@ void Distortion::RecalculateDistortionParams()
 #else
 MPT_MSVC_WORKAROUND_LNK4221(Distortion)
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Distortion.h b/soundlib/plugins/dmo/Distortion.h
index e6727f8..9ce1ff1 100644
--- a/soundlib/plugins/dmo/Distortion.h
+++ b/soundlib/plugins/dmo/Distortion.h
@@ -8,7 +8,7 @@
  */
 
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 #include "../PlugInterface.h"
 
@@ -17,11 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 namespace DMO
 {
 
-//==================================
 class Distortion : public IMixPlugin
-//==================================
 {
-public:
+protected:
 	enum Parameters
 	{
 		kDistGain = 0,
@@ -32,7 +30,6 @@ public:
 		kDistNumParameters
 	};
 
-protected:
 	float m_param[kDistNumParameters];
 
 	// Pre-EQ coefficients
@@ -45,66 +42,47 @@ public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return 0xEF114C90; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
-
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
-
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
-
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
-
-	virtual PlugParamIndex GetNumParameters() const { return kDistNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
-
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xEF114C90; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-#ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("Distortion"); }
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	PlugParamIndex GetNumParameters() const override { return kDistNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual bool HasEditor() const { return false; }
-#endif
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("Distortion"); }
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual bool ProgramsAreChunks() const { return false; }
+	bool HasEditor() const override { return false; }
+#endif
 
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
 protected:
 	static float FreqInHertz(float param) { return 100.0f + param * 7900.0f; }
@@ -116,4 +94,4 @@ protected:
 
 OPENMPT_NAMESPACE_END
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/Echo.cpp b/soundlib/plugins/dmo/Echo.cpp
index 4223c4b..b367da5 100644
--- a/soundlib/plugins/dmo/Echo.cpp
+++ b/soundlib/plugins/dmo/Echo.cpp
@@ -10,20 +10,19 @@
 
 #include "stdafx.h"
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 #include "../../Sndfile.h"
 #include "Echo.h"
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 namespace DMO
 {
 
 IMixPlugin* Echo::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//-------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) Echo(factory, sndFile, mixStruct);
 }
@@ -35,7 +34,6 @@ Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	, m_writePos(0)
 	, m_sampleRate(sndFile.GetSampleRate())
 	, m_initialFeedback(0.0f)
-//-----------------------------------------------------------------------------
 {
 	m_param[kEchoWetDry] = 0.5f;
 	m_param[kEchoFeedback] = 0.5f;
@@ -49,7 +47,6 @@ Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 
 
 void Echo::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//--------------------------------------------------------------
 {
 	if(!m_bufferSize || !m_mixBuffer.Ok())
 		return;
@@ -91,7 +88,6 @@ void Echo::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 PlugParamValue Echo::GetParameter(PlugParamIndex index)
-//-----------------------------------------------------
 {
 	if(index < kEchoNumParameters)
 	{
@@ -102,7 +98,6 @@ PlugParamValue Echo::GetParameter(PlugParamIndex index)
 
 
 void Echo::SetParameter(PlugParamIndex index, PlugParamValue value)
-//-----------------------------------------------------------------
 {
 	if(index < kEchoNumParameters)
 	{
@@ -116,17 +111,23 @@ void Echo::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void Echo::Resume()
-//-----------------
 {
 	m_isResumed = true;
 	m_sampleRate = m_SndFile.GetSampleRate();
-	m_bufferSize = m_sampleRate * 2u;
 	RecalculateEchoParams();
+	PositionChanged();
+}
+
+
+void Echo::PositionChanged()
+{
+	m_bufferSize = m_sampleRate * 2u;
 	try
 	{
 		m_delayLine.assign(m_bufferSize * 2, 0);
-	} catch(MPTMemoryException)
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
 	{
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
 		m_bufferSize = 0;
 	}
 	m_writePos = 0;
@@ -136,7 +137,6 @@ void Echo::Resume()
 #ifdef MODPLUG_TRACKER
 
 CString Echo::GetParamName(PlugParamIndex param)
-//----------------------------------------------
 {
 	switch(param)
 	{
@@ -151,7 +151,6 @@ CString Echo::GetParamName(PlugParamIndex param)
 
 
 CString Echo::GetParamLabel(PlugParamIndex param)
-//-----------------------------------------------
 {
 	if(param == kEchoLeftDelay || param == kEchoRightDelay)
 		return _T("ms");
@@ -160,18 +159,17 @@ CString Echo::GetParamLabel(PlugParamIndex param)
 
 
 CString Echo::GetParamDisplay(PlugParamIndex param)
-//-------------------------------------------------
 {
 	CString s;
 	switch(param)
 	{
 	case kEchoWetDry:
 	case kEchoFeedback:
-		s.Format("%.2f", m_param[param] * 100.0f);
+		s.Format(_T("%.2f"), m_param[param] * 100.0f);
 		break;
 	case kEchoLeftDelay:
 	case kEchoRightDelay:
-		s.Format("%.2f", m_param[param] * 2000.0f);
+		s.Format(_T("%.2f"), m_param[param] * 2000.0f);
 		break;
 	case kEchoPanDelay:
 		s = (m_param[param] <= 0.5) ? _T("No") : _T("Yes");
@@ -183,7 +181,6 @@ CString Echo::GetParamDisplay(PlugParamIndex param)
 
 
 void Echo::RecalculateEchoParams()
-//--------------------------------
 {
 	m_initialFeedback = std::sqrt(1.0f - (m_param[kEchoFeedback] * m_param[kEchoFeedback]));
 	m_delayTime[0] = static_cast<uint32>(m_param[kEchoLeftDelay] * (2 * m_sampleRate));
@@ -196,6 +193,6 @@ void Echo::RecalculateEchoParams()
 #else
 MPT_MSVC_WORKAROUND_LNK4221(Echo)
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Echo.h b/soundlib/plugins/dmo/Echo.h
index c8f3865..5d4e632 100644
--- a/soundlib/plugins/dmo/Echo.h
+++ b/soundlib/plugins/dmo/Echo.h
@@ -8,7 +8,7 @@
  */
 
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 #include "../PlugInterface.h"
 
@@ -17,11 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 namespace DMO
 {
 
-//============================
 class Echo : public IMixPlugin
-//============================
 {
-public:
+protected:
 	enum Parameters
 	{
 		kEchoWetDry = 0,
@@ -32,7 +30,6 @@ public:
 		kEchoNumParameters
 	};
 
-protected:
 	std::vector<float> m_delayLine;	// Echo delay line
 	float m_param[kEchoNumParameters];
 	uint32 m_bufferSize;			// Delay line length in frames
@@ -48,67 +45,48 @@ public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return 0xEF3E932C; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xEF3E932C; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
+	void Process(float *pOutL, float *pOutR, uint32 numFrames)override;
 
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual PlugParamIndex GetNumParameters() const { return kEchoNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
+	PlugParamIndex GetNumParameters() const override { return kEchoNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
 
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
 
 #ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("Echo"); }
-
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	CString GetDefaultEffectName() override { return _T("Echo"); }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual bool HasEditor() const { return false; }
+	bool HasEditor() const override { return false; }
 #endif
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
-
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
-
-	virtual bool ProgramsAreChunks() const { return false; }
-
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
 protected:
 	void RecalculateEchoParams();
@@ -118,4 +96,4 @@ protected:
 
 OPENMPT_NAMESPACE_END
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/Flanger.cpp b/soundlib/plugins/dmo/Flanger.cpp
new file mode 100644
index 0000000..3eaf657
--- /dev/null
+++ b/soundlib/plugins/dmo/Flanger.cpp
@@ -0,0 +1,145 @@
+/*
+ * Flanger.cpp
+ * -----------
+ * Purpose: Implementation of the DMO Flanger DSP (for non-Windows platforms)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#ifndef NO_PLUGINS
+#include "../../Sndfile.h"
+#include "Flanger.h"
+#endif // !NO_PLUGINS
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifndef NO_PLUGINS
+
+namespace DMO
+{
+
+IMixPlugin* Flanger::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+{
+	return new (std::nothrow) Flanger(factory, sndFile, mixStruct);
+}
+
+
+Flanger::Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+	: Chorus(factory, sndFile, mixStruct)
+{
+	m_param[kFlangerWetDryMix] = 0.5f;
+	m_param[kFlangerWaveShape] = 1.0f;
+	m_param[kFlangerFrequency] = 0.025f;
+	m_param[kFlangerDepth] = 1.0f;
+	m_param[kFlangerPhase] = 0.5f;
+	m_param[kFlangerFeedback] = (-50.0f + 99.0f) / 198.0f;
+	m_param[kFlangerDelay] = 0.5f;
+
+	// Already done in Chorus constructor
+	//m_mixBuffer.Initialize(2, 2);
+	//InsertIntoFactoryList();
+}
+
+
+void Flanger::SetParameter(PlugParamIndex index, PlugParamValue value)
+{
+	if(index < kFlangerNumParameters)
+	{
+		Limit(value, 0.0f, 1.0f);
+		if(index == kFlangerWaveShape && value < 1.0f)
+			value = 0.0f;
+		else if(index == kFlangerPhase)
+			value = Util::Round(value * 4.0f) / 4.0f;
+		m_param[index] = value;
+		RecalculateChorusParams();
+	}
+}
+
+
+#ifdef MODPLUG_TRACKER
+
+CString Flanger::GetParamName(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kFlangerWetDryMix: return _T("WetDryMix");
+	case kFlangerWaveShape: return _T("WaveShape");
+	case kFlangerFrequency: return _T("Frequency");
+	case kFlangerDepth: return _T("Depth");
+	case kFlangerPhase: return _T("Phase");
+	case kFlangerFeedback: return _T("Feedback");
+	case kFlangerDelay: return _T("Delay");
+	}
+	return CString();
+}
+
+
+CString Flanger::GetParamLabel(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kFlangerWetDryMix:
+	case kFlangerDepth:
+	case kFlangerFeedback:
+		return _T("%");
+	case kFlangerFrequency:
+		return _T("Hz");
+	case kFlangerPhase:
+		return _T("°");
+	case kFlangerDelay:
+		return _T("ms");
+	}
+	return CString();
+}
+
+
+CString Flanger::GetParamDisplay(PlugParamIndex param)
+{
+	CString s;
+	float value = m_param[param];
+	switch(param)
+	{
+	case kFlangerWetDryMix:
+	case kFlangerDepth:
+		value *= 100.0f;
+		break;
+	case kFlangerFrequency:
+		value = FrequencyInHertz();
+		break;
+	case kFlangerWaveShape:
+		return (value < 1) ? _T("Triangle") : _T("Sine");
+		break;
+	case kFlangerPhase:
+		switch(Phase())
+		{
+		case 0: return _T("-180");
+		case 1: return _T("-90");
+		case 2: return _T("0");
+		case 3: return _T("90");
+		case 4: return _T("180");
+		}
+		break;
+	case kFlangerFeedback:
+		value = Feedback();
+		break;
+	case kFlangerDelay:
+		value = Delay();
+	}
+	s.Format(_T("%.2f"), value);
+	return s;
+}
+
+#endif // MODPLUG_TRACKER
+
+} // namespace DMO
+
+#else
+MPT_MSVC_WORKAROUND_LNK4221(Flanger)
+
+#endif // !NO_PLUGINS
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Flanger.h b/soundlib/plugins/dmo/Flanger.h
new file mode 100644
index 0000000..d38f7b7
--- /dev/null
+++ b/soundlib/plugins/dmo/Flanger.h
@@ -0,0 +1,69 @@
+/*
+ * Flanger.h
+ * ---------
+ * Purpose: Implementation of the DMO Flanger DSP (for non-Windows platforms)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#ifndef NO_PLUGINS
+
+#include "Chorus.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+namespace DMO
+{
+
+class Flanger : public Chorus
+{
+protected:
+	enum Parameters
+	{
+		kFlangerWetDryMix = 0,
+		kFlangerWaveShape,
+		kFlangerFrequency,
+		kFlangerDepth,
+		kFlangerPhase,
+		kFlangerFeedback,
+		kFlangerDelay,
+		kFlangerNumParameters
+	};
+
+public:
+	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+	Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xEFCA3D92; }
+
+	PlugParamIndex GetNumParameters() const override { return kFlangerNumParameters; }
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("Flanger"); }
+
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
+#endif
+
+protected:
+	float WetDryMix() const override { return m_param[kFlangerWetDryMix]; }
+	bool IsTriangle() const override { return m_param[kFlangerWaveShape] < 1; }
+	float Depth() const override { return m_param[kFlangerDepth]; }
+	float Feedback() const override { return -99.0f + m_param[kFlangerFeedback] * 198.0f; }
+	float Delay() const override { return m_param[kFlangerDelay] * 4.0f; }
+	float FrequencyInHertz() const override { return m_param[kFlangerFrequency] * 10.0f; }
+	int Phase() const override { return Util::Round<uint32>(m_param[kFlangerPhase] * 4.0f); }
+};
+
+} // namespace DMO
+
+OPENMPT_NAMESPACE_END
+
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/Gargle.cpp b/soundlib/plugins/dmo/Gargle.cpp
index 10884ab..b17dc02 100644
--- a/soundlib/plugins/dmo/Gargle.cpp
+++ b/soundlib/plugins/dmo/Gargle.cpp
@@ -10,20 +10,19 @@
 
 #include "stdafx.h"
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 #include "../../Sndfile.h"
 #include "Gargle.h"
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 namespace DMO
 {
 
 IMixPlugin* Gargle::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//---------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) Gargle(factory, sndFile, mixStruct);
 }
@@ -31,7 +30,6 @@ IMixPlugin* Gargle::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLU
 
 Gargle::Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	: IMixPlugin(factory, sndFile, mixStruct)
-//---------------------------------------------------------------------------------
 {
 	m_param[kGargleRate] = 0.02f;
 	m_param[kGargleWaveShape] = 0.0f;
@@ -42,7 +40,6 @@ Gargle::Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStru
 
 
 void Gargle::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//----------------------------------------------------------------
 {
 	if(!m_mixBuffer.Ok())
 		return;
@@ -111,7 +108,6 @@ void Gargle::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 PlugParamValue Gargle::GetParameter(PlugParamIndex index)
-//-------------------------------------------------------
 {
 	if(index < kEqNumParameters)
 	{
@@ -122,7 +118,6 @@ PlugParamValue Gargle::GetParameter(PlugParamIndex index)
 
 
 void Gargle::SetParameter(PlugParamIndex index, PlugParamValue value)
-//-------------------------------------------------------------------
 {
 	if(index < kEqNumParameters)
 	{
@@ -136,7 +131,6 @@ void Gargle::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void Gargle::Resume()
-//-------------------
 {
 	RecalculateGargleParams();
 	m_counter = 0;
@@ -147,7 +141,6 @@ void Gargle::Resume()
 #ifdef MODPLUG_TRACKER
 
 CString Gargle::GetParamName(PlugParamIndex param)
-//------------------------------------------------
 {
 	switch(param)
 	{
@@ -159,7 +152,6 @@ CString Gargle::GetParamName(PlugParamIndex param)
 
 
 CString Gargle::GetParamLabel(PlugParamIndex param)
-//-------------------------------------------------
 {
 	switch(param)
 	{
@@ -170,13 +162,12 @@ CString Gargle::GetParamLabel(PlugParamIndex param)
 
 
 CString Gargle::GetParamDisplay(PlugParamIndex param)
-//---------------------------------------------------
 {
 	CString s;
 	switch(param)
 	{
 	case kGargleRate:
-		s.Format("%d", RateInHertz());
+		s.Format(_T("%d"), RateInHertz());
 		break;
 	case kGargleWaveShape:
 		return (m_param[param] < 0.5) ? _T("Triangle") : _T("Square");
@@ -188,14 +179,12 @@ CString Gargle::GetParamDisplay(PlugParamIndex param)
 
 
 uint32 Gargle::RateInHertz() const
-//--------------------------------
 {
 	return Util::Round<uint32>(m_param[kGargleRate] * 999.0f) + 1;
 }
 
 
 void Gargle::RecalculateGargleParams()
-//------------------------------------
 {
 	m_period = m_SndFile.GetSampleRate() / RateInHertz();
 	if(m_period < 2) m_period = 2;
@@ -208,6 +197,6 @@ void Gargle::RecalculateGargleParams()
 #else
 MPT_MSVC_WORKAROUND_LNK4221(Gargle)
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/Gargle.h b/soundlib/plugins/dmo/Gargle.h
index 6acc3c1..a05960b 100644
--- a/soundlib/plugins/dmo/Gargle.h
+++ b/soundlib/plugins/dmo/Gargle.h
@@ -8,7 +8,7 @@
  */
 
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 #include "../PlugInterface.h"
 
@@ -17,11 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 namespace DMO
 {
 
-//===============================
 class Gargle : public IMixPlugin
-//===============================
 {
-public:
+protected:
 	enum Parameters
 	{
 		kGargleRate = 0,
@@ -29,7 +27,6 @@ public:
 		kEqNumParameters
 	};
 
-protected:
 	float m_param[kEqNumParameters];
 
 	uint32 m_period, m_periodHalf, m_counter;	// In frames
@@ -38,67 +35,48 @@ public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return 0xDAFD8210; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xDAFD8210; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual PlugParamIndex GetNumParameters() const { return kEqNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
+	PlugParamIndex GetNumParameters() const override { return kEqNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override { m_counter = 0; }
 
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
 
 #ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("Gargle"); }
-
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	CString GetDefaultEffectName() override { return _T("Gargle"); }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual bool HasEditor() const { return false; }
+	bool HasEditor() const override { return false; }
 #endif
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
-
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
-
-	virtual bool ProgramsAreChunks() const { return false; }
-
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
 protected:
 	uint32 RateInHertz() const;
@@ -109,4 +87,4 @@ protected:
 
 OPENMPT_NAMESPACE_END
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/I3DL2Reverb.cpp b/soundlib/plugins/dmo/I3DL2Reverb.cpp
new file mode 100644
index 0000000..d1e24ff
--- /dev/null
+++ b/soundlib/plugins/dmo/I3DL2Reverb.cpp
@@ -0,0 +1,590 @@
+/*
+ * I3DL2Reverb.cpp
+ * ---------------
+ * Purpose: Implementation of the DMO I3DL2Reverb DSP (for non-Windows platforms)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+
+#ifndef NO_PLUGINS
+#include "../../Sndfile.h"
+#include "I3DL2Reverb.h"
+#endif // !NO_PLUGINS
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifndef NO_PLUGINS
+
+namespace DMO
+{
+
+void I3DL2Reverb::DelayLine::Init(int32 ms, int32 padding, uint32 sampleRate, int32 delayTap)
+{
+	m_length = Util::muldiv(sampleRate, ms, 1000) + padding;
+	m_position = 0;
+	SetDelayTap(delayTap);
+	assign(m_length, 0.0f);
+}
+
+
+void I3DL2Reverb::DelayLine::SetDelayTap(int32 delayTap)
+{
+	if(m_length > 0)
+		m_delayPosition = (delayTap + m_position + m_length) % m_length;
+}
+
+
+void I3DL2Reverb::DelayLine::Advance()
+{
+	if(--m_position < 0)
+		m_position += m_length;
+	if(--m_delayPosition < 0)
+		m_delayPosition += m_length;
+}
+
+
+MPT_FORCEINLINE void I3DL2Reverb::DelayLine::Set(float value)
+{
+	at(m_position) = value;
+}
+
+
+float I3DL2Reverb::DelayLine::Get(int32 offset) const
+{
+	offset = (offset + m_position) % m_length;
+	if(offset < 0)
+		offset += m_length;
+	return at(offset);
+}
+
+
+MPT_FORCEINLINE float I3DL2Reverb::DelayLine::Get() const
+{
+	return at(m_delayPosition);
+}
+
+
+IMixPlugin* I3DL2Reverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+{
+	return new (std::nothrow) I3DL2Reverb(factory, sndFile, mixStruct);
+}
+
+
+I3DL2Reverb::I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
+	: IMixPlugin(factory, sndFile, mixStruct)
+	, m_recalcParams(true)
+{
+	m_param[kI3DL2ReverbRoom] = 0.9f;
+	m_param[kI3DL2ReverbRoomHF] = 0.99f;
+	m_param[kI3DL2ReverbRoomRolloffFactor] = 0.0f;
+	m_param[kI3DL2ReverbDecayTime] = 0.07f;
+	m_param[kI3DL2ReverbDecayHFRatio] = 0.3842105f;
+	m_param[kI3DL2ReverbReflections] = 0.672545433f;
+	m_param[kI3DL2ReverbReflectionsDelay] = 0.233333333f;
+	m_param[kI3DL2ReverbReverb] = 0.85f;
+	m_param[kI3DL2ReverbReverbDelay] = 0.11f;
+	m_param[kI3DL2ReverbDiffusion] = 1.0f;
+	m_param[kI3DL2ReverbDensity] = 1.0f;
+	m_param[kI3DL2ReverbHFReference] = (5000.0f - 20.0f) / 19980.0f;
+	m_param[kI3DL2ReverbQuality] = 2.0f / 3.0f;
+
+	m_mixBuffer.Initialize(2, 2);
+	InsertIntoFactoryList();
+}
+
+
+void I3DL2Reverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
+{
+	if(m_recalcParams)
+	{
+		auto sampleRate = m_effectiveSampleRate;
+		RecalculateI3DL2ReverbParams();
+		// Resize and clear delay lines if quality has changed
+		if(sampleRate != m_effectiveSampleRate)
+			PositionChanged();
+	}
+
+	if(!m_ok || !m_mixBuffer.Ok())
+		return;
+
+	const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
+	float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
+
+	uint32 frames = numFrames;
+	if(!(m_quality & kFullSampleRate) && m_remain && frames > 0)
+	{
+		// Remaining frame from previous render call
+		frames--;
+		*(out[0]++) = m_prevL;
+		*(out[1]++) = m_prevR;
+		in[0]++;
+		in[1]++;
+		m_remain = false;
+	}
+	
+	while(frames > 0)
+	{
+		// Apply room filter and insert into early reflection delay lines
+		const float inL = *(in[0]++);
+		const float inRoomL = (m_filterHist[12] - inL) * m_roomFilter + inL;
+		m_filterHist[12] = inRoomL;
+		m_delayLines[15].Set(inRoomL);
+
+		const float inR = *(in[1]++);
+		const float inRoomR = (m_filterHist[13] - inR) * m_roomFilter + inR;
+		m_filterHist[13] = inRoomR;
+		m_delayLines[16].Set(inRoomR);
+
+		// Early reflections (left)
+		float earlyL = m_delayLines[15].Get(m_earlyTaps[0][1]) * 0.68f
+			- m_delayLines[15].Get(m_earlyTaps[0][2]) * 0.5f
+			- m_delayLines[15].Get(m_earlyTaps[0][3]) * 0.62f
+			- m_delayLines[15].Get(m_earlyTaps[0][4]) * 0.5f
+			- m_delayLines[15].Get(m_earlyTaps[0][5]) * 0.62f;
+		if(m_quality & kMoreDelayLines)
+		{
+			float earlyL2 = earlyL;
+			earlyL = m_delayLines[13].Get() + earlyL * 0.618034f;
+			m_delayLines[13].Set(earlyL2 - earlyL * 0.618034f);
+		}
+		const float earlyRefOutL = earlyL * m_ERLevel;
+		m_filterHist[15] = m_delayLines[15].Get(m_earlyTaps[0][0]) + m_filterHist[15];
+		m_filterHist[16] = m_delayLines[16].Get(m_earlyTaps[1][0]) + m_filterHist[16];
+
+		// Lots of slightly different copy-pasta ahead
+		float reverbL1, reverbL2, reverbL3, reverbR1, reverbR2, reverbR3;
+
+		reverbL1 = -m_filterHist[15] * 0.707f;
+		reverbL2 = m_filterHist[16] * 0.707f + reverbL1;
+		reverbR2 = reverbL1 - m_filterHist[16] * 0.707f;
+
+		m_filterHist[5] = (m_filterHist[5] - m_delayLines[5].Get()) * m_delayCoeffs[5][1] + m_delayLines[5].Get();
+		reverbL1 = m_filterHist[5] * m_delayCoeffs[5][0] + reverbL2 * m_diffusion;
+		m_delayLines[5].Set(reverbL2 - reverbL1 * m_diffusion);
+		reverbL2 = reverbL1;
+		reverbL3 = -0.15f * reverbL1;
+
+		m_filterHist[4] = (m_filterHist[4] - m_delayLines[4].Get()) * m_delayCoeffs[4][1] + m_delayLines[4].Get();
+		reverbL1 = m_filterHist[4] * m_delayCoeffs[4][0] + reverbL2 * m_diffusion;
+		m_delayLines[4].Set(reverbL2 - reverbL1 * m_diffusion);
+		reverbL2 = reverbL1;
+		reverbL3 -= reverbL1 * 0.2f;
+
+		if(m_quality & kMoreDelayLines)
+		{
+			m_filterHist[3] = (m_filterHist[3] - m_delayLines[3].Get()) * m_delayCoeffs[3][1] + m_delayLines[3].Get();
+			reverbL1 = m_filterHist[3] * m_delayCoeffs[3][0] + reverbL2 * m_diffusion;
+			m_delayLines[3].Set(reverbL2 - reverbL1 * m_diffusion);
+			reverbL2 = reverbL1;
+			reverbL3 += 0.35f * reverbL1;
+
+			m_filterHist[2] = (m_filterHist[2] - m_delayLines[2].Get()) * m_delayCoeffs[2][1] + m_delayLines[2].Get();
+			reverbL1 = m_filterHist[2] * m_delayCoeffs[2][0] + reverbL2 * m_diffusion;
+			m_delayLines[2].Set(reverbL2 - reverbL1 * m_diffusion);
+			reverbL2 = reverbL1;
+			reverbL3 -= reverbL1 * 0.38f;
+		}
+		m_delayLines[17].Set(reverbL2);
+
+		reverbL1 = m_delayLines[17].Get() * m_delayCoeffs[12][0];
+		m_filterHist[17] = (m_filterHist[17] - reverbL1) * m_delayCoeffs[12][1] + reverbL1;
+
+		m_filterHist[1] = (m_filterHist[1] - m_delayLines[1].Get()) * m_delayCoeffs[1][1] + m_delayLines[1].Get();
+		reverbL1 = m_filterHist[17] * m_diffusion + m_filterHist[1] * m_delayCoeffs[1][0];
+		m_delayLines[1].Set(m_filterHist[17] - reverbL1 * m_diffusion);
+		reverbL2 = reverbL1;
+		float reverbL4 = reverbL1 * 0.38f;
+
+		m_filterHist[0] = (m_filterHist[0] - m_delayLines[0].Get()) * m_delayCoeffs[0][1] + m_delayLines[0].Get();
+		reverbL1 = m_filterHist[0] * m_delayCoeffs[0][0] + reverbL2 * m_diffusion;
+		m_delayLines[0].Set(reverbL2 - reverbL1 * m_diffusion);
+		reverbL3 -= reverbL1 * 0.38f;
+		m_filterHist[15] = reverbL1;
+		
+		// Early reflections (right)
+		float earlyR = m_delayLines[16].Get(m_earlyTaps[1][1]) * 0.707f
+			- m_delayLines[16].Get(m_earlyTaps[1][2]) * 0.6f
+			- m_delayLines[16].Get(m_earlyTaps[1][3]) * 0.5f
+			- m_delayLines[16].Get(m_earlyTaps[1][4]) * 0.6f
+			- m_delayLines[16].Get(m_earlyTaps[1][5]) * 0.5f;
+		if(m_quality & kMoreDelayLines)
+		{
+			float earlyR2 = earlyR;
+			earlyR = m_delayLines[14].Get() + earlyR * 0.618034f;
+			m_delayLines[14].Set(earlyR2 - earlyR * 0.618034f);
+		}
+		const float earlyRefOutR = earlyR * m_ERLevel;
+
+		m_filterHist[11] = (m_filterHist[11] - m_delayLines[11].Get()) * m_delayCoeffs[11][1] + m_delayLines[11].Get();
+		reverbR1 = m_filterHist[11] * m_delayCoeffs[11][0] + reverbR2 * m_diffusion;
+		m_delayLines[11].Set(reverbR2 - reverbR1 * m_diffusion);
+		reverbR2 = reverbR1;
+
+		m_filterHist[10] = (m_filterHist[10] - m_delayLines[10].Get()) * m_delayCoeffs[10][1] + m_delayLines[10].Get();
+		reverbR1 = m_filterHist[10] * m_delayCoeffs[10][0] + reverbR2 * m_diffusion;
+		m_delayLines[10].Set(reverbR2 - reverbR1 * m_diffusion);
+		reverbR3 = reverbL4 - reverbR2 * 0.15f - reverbR1 * 0.2f;
+		reverbR2 = reverbR1;
+
+		if(m_quality & kMoreDelayLines)
+		{
+			m_filterHist[9] = (m_filterHist[9] - m_delayLines[9].Get()) * m_delayCoeffs[9][1] + m_delayLines[9].Get();
+			reverbR1 = m_filterHist[9] * m_delayCoeffs[9][0] + reverbR2 * m_diffusion;
+			m_delayLines[9].Set(reverbR2 - reverbR1 * m_diffusion);
+			reverbR2 = reverbR1;
+			reverbR3 += reverbR1 * 0.35f;
+
+			m_filterHist[8] = (m_filterHist[8] - m_delayLines[8].Get()) * m_delayCoeffs[8][1] + m_delayLines[8].Get();
+			reverbR1 = m_filterHist[8] * m_delayCoeffs[8][0] + reverbR2 * m_diffusion;
+			m_delayLines[8].Set(reverbR2 - reverbR1 * m_diffusion);
+			reverbR2 = reverbR1;
+			reverbR3 -= reverbR1 * 0.38f;
+		}
+		m_delayLines[18].Set(reverbR2);
+
+		reverbR1 = m_delayLines[18].Get() * m_delayCoeffs[12][0];
+		m_filterHist[18] = (m_filterHist[18] - reverbR1) * m_delayCoeffs[12][1] + reverbR1;
+			
+		m_filterHist[7] = (m_filterHist[7] - m_delayLines[7].Get()) * m_delayCoeffs[7][1] + m_delayLines[7].Get();
+		reverbR1 = m_filterHist[18] * m_diffusion + m_filterHist[7] * m_delayCoeffs[7][0];
+		m_delayLines[7].Set(m_filterHist[18] - reverbR1 * m_diffusion);
+		reverbR2 = reverbR1;
+
+		float lateRevOutL = (reverbL3 + reverbR1 * 0.38f) * m_ReverbLevelL;
+
+		m_filterHist[6] = (m_filterHist[6] - m_delayLines[6].Get()) * m_delayCoeffs[6][1] + m_delayLines[6].Get();
+		reverbR1 = m_filterHist[6] * m_delayCoeffs[6][0] + reverbR2 * m_diffusion;
+		m_delayLines[6].Set(reverbR2 - reverbR1 * m_diffusion);
+		m_filterHist[16] = reverbR1;
+
+		float lateRevOutR = (reverbR3 - reverbR1 * 0.38f) * m_ReverbLevelR;
+
+		float outL = earlyRefOutL + lateRevOutL;
+		float outR = earlyRefOutR + lateRevOutR;
+
+		for(std::size_t d = 0; d < mpt::size(m_delayLines); d++)
+			m_delayLines[d].Advance();
+
+		if(!(m_quality & kFullSampleRate))
+		{
+			*(out[0]++) = (outL + m_prevL) * 0.5f;
+			*(out[1]++) = (outR + m_prevR) * 0.5f;
+			m_prevL = outL;
+			m_prevR = outR;
+			in[0]++;
+			in[1]++;
+			if(frames-- == 1)
+			{
+				m_remain = true;
+				break;
+			}
+		}
+		*(out[0]++) = outL;
+		*(out[1]++) = outR;
+		frames--;
+	}
+
+	ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
+}
+
+
+PlugParamValue I3DL2Reverb::GetParameter(PlugParamIndex index)
+{
+	if(index < kI3DL2ReverbNumParameters)
+	{
+		return m_param[index];
+	}
+	return 0;
+}
+
+
+void I3DL2Reverb::SetParameter(PlugParamIndex index, PlugParamValue value)
+{
+	if(index < kI3DL2ReverbNumParameters)
+	{
+		Limit(value, 0.0f, 1.0f);
+		if(index == kI3DL2ReverbQuality)
+			value = Util::Round(value * 3.0f) / 3.0f;
+		m_param[index] = value;
+		m_recalcParams = true;
+	}
+}
+
+
+void I3DL2Reverb::Resume()
+{
+	RecalculateI3DL2ReverbParams();
+	PositionChanged();
+	m_isResumed = true;
+}
+
+
+void I3DL2Reverb::PositionChanged()
+{
+	MemsetZero(m_filterHist);
+	m_prevL = 0;
+	m_prevR = 0;
+	m_remain = false;
+
+	try
+	{
+		uint32 sampleRate = static_cast<uint32>(m_effectiveSampleRate);
+		m_delayLines[0].Init(67, 5, sampleRate, m_delayTaps[0]);
+		m_delayLines[1].Init(62, 5, sampleRate, m_delayTaps[1]);
+		m_delayLines[2].Init(53, 5, sampleRate, m_delayTaps[2]);
+		m_delayLines[3].Init(43, 5, sampleRate, m_delayTaps[3]);
+		m_delayLines[4].Init(32, 5, sampleRate, m_delayTaps[4]);
+		m_delayLines[5].Init(22, 5, sampleRate, m_delayTaps[5]);
+		m_delayLines[6].Init(75, 5, sampleRate, m_delayTaps[6]);
+		m_delayLines[7].Init(69, 5, sampleRate, m_delayTaps[7]);
+		m_delayLines[8].Init(60, 5, sampleRate, m_delayTaps[8]);
+		m_delayLines[9].Init(48, 5, sampleRate, m_delayTaps[9]);
+		m_delayLines[10].Init(36, 5, sampleRate, m_delayTaps[10]);
+		m_delayLines[11].Init(25, 5, sampleRate, m_delayTaps[11]);
+		m_delayLines[12].Init(0, 0, 0);	// Dummy for array index consistency with both tap and coefficient arrays
+		m_delayLines[13].Init(3, 0, sampleRate, m_delayTaps[13]);
+		m_delayLines[14].Init(3, 0, sampleRate, m_delayTaps[14]);
+		m_delayLines[15].Init(407, 1, sampleRate);
+		m_delayLines[16].Init(400, 1, sampleRate);
+		m_delayLines[17].Init(10, 0, sampleRate, -1);
+		m_delayLines[18].Init(10, 0, sampleRate, -1);
+		m_ok = true;
+	} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
+	{
+		m_ok = false;
+		MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
+	}
+}
+
+
+#ifdef MODPLUG_TRACKER
+
+CString I3DL2Reverb::GetParamName(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kI3DL2ReverbRoom: return _T("Room");
+	case kI3DL2ReverbRoomHF: return _T("RoomHF");
+	case kI3DL2ReverbRoomRolloffFactor: return _T("RoomRolloffFactor");
+	case kI3DL2ReverbDecayTime: return _T("DecayTime");
+	case kI3DL2ReverbDecayHFRatio: return _T("DecayHFRatio");
+	case kI3DL2ReverbReflections: return _T("Reflections");
+	case kI3DL2ReverbReflectionsDelay: return _T("ReflectionsDelay");
+	case kI3DL2ReverbReverb: return _T("Reverb");
+	case kI3DL2ReverbReverbDelay: return _T("ReverbDelay");
+	case kI3DL2ReverbDiffusion: return _T("Diffusion");
+	case kI3DL2ReverbDensity: return _T("Density");
+	case kI3DL2ReverbHFReference: return _T("HFRefrence");
+	case kI3DL2ReverbQuality: return _T("Quality");
+	}
+	return CString();
+}
+
+
+CString I3DL2Reverb::GetParamLabel(PlugParamIndex param)
+{
+	switch(param)
+	{
+	case kI3DL2ReverbRoom:
+	case kI3DL2ReverbRoomHF:
+	case kI3DL2ReverbReflections:
+	case kI3DL2ReverbReverb:
+		return _T("dB");
+	case kI3DL2ReverbDecayTime:
+	case kI3DL2ReverbReflectionsDelay:
+	case kI3DL2ReverbReverbDelay:
+		return _T("s");
+	case kI3DL2ReverbDiffusion:
+	case kI3DL2ReverbDensity:
+		return _T("%");
+	case kI3DL2ReverbHFReference:
+		return _T("Hz");
+	}
+	return CString();
+}
+
+
+CString I3DL2Reverb::GetParamDisplay(PlugParamIndex param)
+{
+	static const TCHAR *modes[] = { _T("LQ"), _T("LQ+"), _T("HQ"), _T("HQ+") };
+	float value = m_param[param];
+	switch(param)
+	{
+	case kI3DL2ReverbRoom: value = Room() * 0.01f; break;
+	case kI3DL2ReverbRoomHF: value = RoomHF() * 0.01f; break;
+	case kI3DL2ReverbRoomRolloffFactor: value = RoomRolloffFactor(); break;
+	case kI3DL2ReverbDecayTime: value = DecayTime(); break;
+	case kI3DL2ReverbDecayHFRatio: value = DecayHFRatio(); break;
+	case kI3DL2ReverbReflections: value = Reflections() * 0.01f; break;
+	case kI3DL2ReverbReflectionsDelay: value = ReflectionsDelay(); break;
+	case kI3DL2ReverbReverb: value = Reverb() * 0.01f; break;
+	case kI3DL2ReverbReverbDelay: value = ReverbDelay(); break;
+	case kI3DL2ReverbDiffusion: value = Diffusion(); break;
+	case kI3DL2ReverbDensity: value = Density(); break;
+	case kI3DL2ReverbHFReference: value = HFReference(); break;
+	case kI3DL2ReverbQuality: return modes[Quality() % 4u];
+	}
+	CString s;
+	s.Format(_T("%.2f"), value);
+	return s;
+}
+
+#endif // MODPLUG_TRACKER
+
+
+void I3DL2Reverb::RecalculateI3DL2ReverbParams()
+{
+	m_quality = Quality();
+	m_effectiveSampleRate = static_cast<float>(m_SndFile.GetSampleRate() / ((m_quality & kFullSampleRate) ? 1u : 2u));
+
+	// Diffusion
+	m_diffusion = Diffusion() * (0.618034f / 100.0f);
+	// Early Reflection Level
+	m_ERLevel = std::min(std::pow(10.0f, (Room() + Reflections()) / (100.0f * 20.0f)), 1.0f) * 0.761f;
+
+	// Room Filter
+	float roomHF = std::pow(10.0f, RoomHF() / 100.0f / 10.0f);
+	if(roomHF == 1.0)
+	{
+		m_roomFilter = 0.0f;
+	} else
+	{
+		float freq = std::cos(HFReference() * static_cast<float>(2.0 * M_PI) / m_effectiveSampleRate);
+		float roomFilter = (freq * (roomHF + roomHF) - 2.0f + std::sqrt(freq * (roomHF * roomHF * freq * 4.0f) + roomHF * 8.0f - roomHF * roomHF * 4.0f - roomHF * freq * 8.0f)) / (roomHF + roomHF - 2.0f);
+		m_roomFilter = Clamp(roomFilter, 0.0f, 1.0f);
+	}
+
+	SetDelayTaps();
+	SetDecayCoeffs();
+
+	m_recalcParams = false;
+}
+
+
+void I3DL2Reverb::SetDelayTaps()
+{
+	// Early reflections
+	static const float delays[] =
+	{
+		1.0000f, 1.0000f, 0.0000f, 0.1078f, 0.1768f, 0.2727f,
+		0.3953f, 0.5386f, 0.6899f, 0.8306f, 0.9400f, 0.9800f,
+	};
+
+	const float sampleRate = m_effectiveSampleRate;
+	const float reflectionsDelay = ReflectionsDelay();
+	const float reverbDelay = std::max(ReverbDelay(), 5.0f / 1000.0f);
+	m_earlyTaps[0][0] = static_cast<int32>((reverbDelay + reflectionsDelay + 7.0f / 1000.0f) * sampleRate);
+	for(uint32 i = 1; i < 12; i++)
+	{
+		m_earlyTaps[i % 2u][i / 2u] = static_cast<int32>((reverbDelay * delays[i] + reflectionsDelay) * sampleRate);
+	}
+
+	// Late reflections
+	float density = std::min((Density() / 100.0f + 0.1f) * 0.9091f, 1.0f);
+	float delayL = density * 67.0f / 1000.0f * sampleRate;
+	float delayR = density * 75.0f / 1000.0f * sampleRate;
+	for(int i = 0, power = 0; i < 6; i++)
+	{
+		power += i;
+		float factor = std::pow(0.93f, power);
+		m_delayTaps[i + 0] = static_cast<int32>(delayL * factor);
+		m_delayTaps[i + 6] = static_cast<int32>(delayR * factor);
+	}
+	m_delayTaps[12] = static_cast<int32>(10.0f / 1000.0f * sampleRate);
+	// Early reflections (extra delay lines)
+	m_delayTaps[13] = static_cast<int32>(3.25f / 1000.0f * sampleRate);
+	m_delayTaps[14] = static_cast<int32>(3.53f / 1000.0f * sampleRate);
+
+	for(std::size_t d = 0; d < mpt::size(m_delayTaps); d++)
+		m_delayLines[d].SetDelayTap(m_delayTaps[d]);
+}
+
+
+void I3DL2Reverb::SetDecayCoeffs()
+{
+	float levelLtmp = 1.0f, levelRtmp = 1.0f;
+	float levelL = 0.0f, levelR = 0.0f;
+
+	levelLtmp *= CalcDecayCoeffs(5);
+	levelRtmp *= CalcDecayCoeffs(11);
+	levelL += levelLtmp * 0.0225f;
+	levelR += levelRtmp * 0.0225f;
+
+	levelLtmp *= CalcDecayCoeffs(4);
+	levelRtmp *= CalcDecayCoeffs(10);
+	levelL += levelLtmp * 0.04f;
+	levelR += levelRtmp * 0.04f;
+	
+	if(m_quality & kMoreDelayLines)
+	{
+		levelLtmp *= CalcDecayCoeffs(3);
+		levelRtmp *= CalcDecayCoeffs(9);
+		levelL += levelLtmp * 0.1225f;
+		levelR += levelRtmp * 0.1225f;
+
+		levelLtmp *= CalcDecayCoeffs(2);
+		levelRtmp *= CalcDecayCoeffs(8);
+		levelL += levelLtmp * 0.1444f;
+		levelR += levelRtmp * 0.1444f;
+	}
+	CalcDecayCoeffs(12);
+	levelLtmp *= m_delayCoeffs[12][0] * m_delayCoeffs[12][0];
+	levelRtmp *= m_delayCoeffs[12][0] * m_delayCoeffs[12][0];
+
+	levelLtmp *= CalcDecayCoeffs(1);
+	levelRtmp *= CalcDecayCoeffs(7);
+	levelL += levelRtmp * 0.1444f;
+	levelR += levelLtmp * 0.1444f;
+
+	levelLtmp *= CalcDecayCoeffs(0);
+	levelRtmp *= CalcDecayCoeffs(6);
+	levelL += levelLtmp * 0.1444f;
+	levelR += levelRtmp * 0.1444f;
+
+	// Final Reverb Level
+	float level = std::min(std::pow(10.0f, (Room() + Reverb()) / (100.0f * 20.0f)), 1.0f);
+	float monoInv = 1.0f - ((levelLtmp + levelRtmp) * 0.5f);
+	m_ReverbLevelL = level * std::sqrt(monoInv / levelL);
+	m_ReverbLevelR = level * std::sqrt(monoInv / levelR);
+}
+
+
+float I3DL2Reverb::CalcDecayCoeffs(int32 index)
+{
+	float hfRef = static_cast<float>(2.0 * M_PI) / m_effectiveSampleRate * HFReference();
+	float decayHFRatio = DecayHFRatio();
+	if(decayHFRatio > 1.0f)
+		hfRef = static_cast<float>(M_PI);
+
+	float c1 = std::pow(10.0f, ((m_delayTaps[index] / m_effectiveSampleRate) * -60.0f / DecayTime()) / 20.0f);
+	float c2 = 0.0f;
+
+	float c21 = (std::pow(c1, 2.0f - 2.0f / decayHFRatio) - 1.0f) / (1.0f - std::cos(hfRef));
+	if(c21 != 0)
+	{
+		float c22 = -2.0f * c21 - 2.0f;
+		float c23 = std::sqrt(c22 * c22 - c21 * c21 * 4.0f);
+		c2 = (c23 - c22) / (c21 + c21);
+		if(mpt::abs(c2) > 1.0)
+			c2 = (-c22 - c23) / (c21 + c21);
+	}
+	m_delayCoeffs[index][0] = c1;
+	m_delayCoeffs[index][1] = c2;
+
+	c1 *= c1;
+	float diff2 = m_diffusion * m_diffusion;
+	return diff2 + c1 / (1.0f - diff2 * c1) * (1.0f - diff2) * (1.0f - diff2);
+}
+
+} // namespace DMO
+
+#else
+MPT_MSVC_WORKAROUND_LNK4221(I3DL2Reverb)
+
+#endif // !NO_PLUGINS
+
+OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/I3DL2Reverb.h b/soundlib/plugins/dmo/I3DL2Reverb.h
new file mode 100644
index 0000000..7616e66
--- /dev/null
+++ b/soundlib/plugins/dmo/I3DL2Reverb.h
@@ -0,0 +1,165 @@
+/*
+ * I3DL2Reverb.h
+ * -------------
+ * Purpose: Implementation of the DMO I3DL2Reverb DSP (for non-Windows platforms)
+ * Notes  : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#ifndef NO_PLUGINS
+
+#include "../PlugInterface.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+namespace DMO
+{
+
+class I3DL2Reverb : public IMixPlugin
+{
+protected:
+	enum Parameters
+	{
+		kI3DL2ReverbRoom = 0,
+		kI3DL2ReverbRoomHF,
+		kI3DL2ReverbRoomRolloffFactor,	// Doesn't actually do anything :)
+		kI3DL2ReverbDecayTime,
+		kI3DL2ReverbDecayHFRatio,
+		kI3DL2ReverbReflections,
+		kI3DL2ReverbReflectionsDelay,
+		kI3DL2ReverbReverb,
+		kI3DL2ReverbReverbDelay,
+		kI3DL2ReverbDiffusion,
+		kI3DL2ReverbDensity,
+		kI3DL2ReverbHFReference,
+		kI3DL2ReverbQuality,
+		kI3DL2ReverbNumParameters
+	};
+
+	enum QualityFlags
+	{
+		kMoreDelayLines = 0x01,
+		kFullSampleRate = 0x02,
+	};
+
+	class DelayLine : private std::vector<float>
+	{
+		int32 m_length;
+		int32 m_position;
+		int32 m_delayPosition;
+
+	public:
+		void Init(int32 ms, int32 padding, uint32 sampleRate, int32 delayTap = 0);
+		void SetDelayTap(int32 delayTap);
+		void Advance();
+		void Set(float value);
+		float Get(int32 offset) const;
+		float Get() const;
+	};
+
+	float m_param[kI3DL2ReverbNumParameters];
+
+	// Calculated parameters
+	uint32 m_quality;
+	float m_effectiveSampleRate;
+	float m_diffusion;
+	float m_roomFilter;
+	float m_ERLevel;
+	float m_ReverbLevelL;
+	float m_ReverbLevelR;
+
+	int32 m_delayTaps[15];	// 6*L + 6*R + LR + Early L + Early R
+	int32 m_earlyTaps[2][6];
+	float m_delayCoeffs[13][2];
+
+	// State
+	DelayLine m_delayLines[19];
+	float m_filterHist[19];
+
+	// Remaining frame for downsampled reverb
+	float m_prevL;
+	float m_prevR;
+	bool m_remain;
+
+	bool m_ok, m_recalcParams;
+
+public:
+	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+	I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
+
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0xEF985E71; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
+
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
+
+	float RenderSilence(uint32) override { return 0.0f; }
+
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
+
+	PlugParamIndex GetNumParameters() const override { return kI3DL2ReverbNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
+
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
+
+#ifdef MODPLUG_TRACKER
+	CString GetDefaultEffectName() override { return _T("I3DL2Reverb"); }
+
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
+
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
+
+	bool HasEditor() const override { return false; }
+#endif
+
+	void BeginSetProgram(int32) override { }
+	void EndSetProgram() override { }
+
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
+
+protected:
+	float Room() const { return -10000.0f + m_param[kI3DL2ReverbRoom] * 10000.0f; }
+	float RoomHF() const { return -10000.0f + m_param[kI3DL2ReverbRoomHF] * 10000.0f; }
+	float RoomRolloffFactor() const { return m_param[kI3DL2ReverbRoomRolloffFactor] * 10.0f; }
+	float DecayTime() const { return 0.1f + m_param[kI3DL2ReverbDecayTime] * 19.9f; }
+	float DecayHFRatio() const { return 0.1f + m_param[kI3DL2ReverbDecayHFRatio] * 1.9f; }
+	float Reflections() const { return -10000.0f + m_param[kI3DL2ReverbReflections] * 11000.0f; };
+	float ReflectionsDelay() const { return m_param[kI3DL2ReverbReflectionsDelay] * 0.3f; }
+	float Reverb() const { return -10000.0f + m_param[kI3DL2ReverbReverb] * 12000.0f; };
+	float ReverbDelay() const { return m_param[kI3DL2ReverbReverbDelay] * 0.1f; }
+	float Diffusion() const { return m_param[kI3DL2ReverbDiffusion] * 100.0f; }
+	float Density() const { return m_param[kI3DL2ReverbDensity] * 100.0f; }
+	float HFReference() const { return 20.0f + m_param[kI3DL2ReverbHFReference] * 19980.0f; }
+	uint32 Quality() const { return Util::Round<uint32>(m_param[kI3DL2ReverbQuality] * 3.0f); }
+
+	void RecalculateI3DL2ReverbParams();
+
+	void SetDelayTaps();
+	void SetDecayCoeffs();
+	float CalcDecayCoeffs(int32 index);
+};
+
+} // namespace DMO
+
+OPENMPT_NAMESPACE_END
+
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/ParamEq.cpp b/soundlib/plugins/dmo/ParamEq.cpp
index 8d7840d..7d5dceb 100644
--- a/soundlib/plugins/dmo/ParamEq.cpp
+++ b/soundlib/plugins/dmo/ParamEq.cpp
@@ -10,20 +10,19 @@
 
 #include "stdafx.h"
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 #include "../../Sndfile.h"
 #include "ParamEq.h"
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 namespace DMO
 {
 
 IMixPlugin* ParamEq::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//----------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) ParamEq(factory, sndFile, mixStruct);
 }
@@ -31,7 +30,6 @@ IMixPlugin* ParamEq::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPL
 
 ParamEq::ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	: IMixPlugin(factory, sndFile, mixStruct)
-//-----------------------------------------------------------------------------------
 {
 	m_param[kEqCenter] = 0.497487f;
 	m_param[kEqBandwidth] = 0.314286f;
@@ -43,7 +41,6 @@ ParamEq::ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixSt
 
 
 void ParamEq::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//-----------------------------------------------------------------
 {
 	if(!m_mixBuffer.Ok())
 		return;
@@ -79,7 +76,6 @@ void ParamEq::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 
 PlugParamValue ParamEq::GetParameter(PlugParamIndex index)
-//--------------------------------------------------------
 {
 	if(index < kEqNumParameters)
 	{
@@ -90,7 +86,6 @@ PlugParamValue ParamEq::GetParameter(PlugParamIndex index)
 
 
 void ParamEq::SetParameter(PlugParamIndex index, PlugParamValue value)
-//--------------------------------------------------------------------
 {
 	if(index < kEqNumParameters)
 	{
@@ -102,11 +97,15 @@ void ParamEq::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void ParamEq::Resume()
-//--------------------
 {
 	m_isResumed = true;
 	RecalculateEqParams();
+	PositionChanged();
+}
+
 
+void ParamEq::PositionChanged()
+{
 	// Reset filter state
 	x1[0] = x2[0] = 0;
 	x1[1] = x2[1] = 0;
@@ -118,7 +117,6 @@ void ParamEq::Resume()
 #ifdef MODPLUG_TRACKER
 
 CString ParamEq::GetParamName(PlugParamIndex param)
-//-------------------------------------------------
 {
 	switch(param)
 	{
@@ -131,7 +129,6 @@ CString ParamEq::GetParamName(PlugParamIndex param)
 
 
 CString ParamEq::GetParamLabel(PlugParamIndex param)
-//--------------------------------------------------
 {
 	switch(param)
 	{
@@ -144,7 +141,6 @@ CString ParamEq::GetParamLabel(PlugParamIndex param)
 
 
 CString ParamEq::GetParamDisplay(PlugParamIndex param)
-//----------------------------------------------------
 {
 	float value = 0.0f;
 	switch(param)
@@ -160,7 +156,7 @@ CString ParamEq::GetParamDisplay(PlugParamIndex param)
 		break;
 	}
 	CString s;
-	s.Format("%.2f", value);
+	s.Format(_T("%.2f"), value);
 	return s;
 }
 
@@ -168,10 +164,9 @@ CString ParamEq::GetParamDisplay(PlugParamIndex param)
 
 
 void ParamEq::RecalculateEqParams()
-//---------------------------------
 {
 	const float freq = std::min(FreqInHertz() / m_SndFile.GetSampleRate(), 0.5f);
-	const float a = std::pow(10, GainInDecibel() / 40.0f);
+	const float a = std::pow(10.0f, GainInDecibel() / 40.0f);
 	const float w0 = 2.0f * float(M_PI) * freq;
 	const float sinW0 = std::sin(w0);
 	const float cosW0 = std::cos(w0);
@@ -196,6 +191,6 @@ void ParamEq::RecalculateEqParams()
 #else
 MPT_MSVC_WORKAROUND_LNK4221(ParamEq)
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/ParamEq.h b/soundlib/plugins/dmo/ParamEq.h
index f0ea662..e56defd 100644
--- a/soundlib/plugins/dmo/ParamEq.h
+++ b/soundlib/plugins/dmo/ParamEq.h
@@ -8,7 +8,7 @@
  */
 
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 #include "../PlugInterface.h"
 
@@ -17,11 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 namespace DMO
 {
 
-//===============================
 class ParamEq : public IMixPlugin
-//===============================
 {
-public:
+protected:
 	enum Parameters
 	{
 		kEqCenter = 0,
@@ -30,7 +28,6 @@ public:
 		kEqNumParameters
 	};
 
-protected:
 	float m_param[kEqNumParameters];
 
 	// Equalizer coefficients
@@ -43,67 +40,48 @@ public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return 0x120CED89; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0x120CED89; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual PlugParamIndex GetNumParameters() const { return kEqNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
+	PlugParamIndex GetNumParameters() const override { return kEqNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
 
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
 
 #ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("ParamEq"); }
-
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	CString GetDefaultEffectName() override { return _T("ParamEq"); }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual bool HasEditor() const { return false; }
+	bool HasEditor() const override { return false; }
 #endif
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
-
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
-
-	virtual bool ProgramsAreChunks() const { return false; }
-
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
 protected:
 	float BandwidthInSemitones() const { return 1.0f + m_param[kEqBandwidth] * 35.0f; }
@@ -116,4 +94,4 @@ protected:
 
 OPENMPT_NAMESPACE_END
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
diff --git a/soundlib/plugins/dmo/WavesReverb.cpp b/soundlib/plugins/dmo/WavesReverb.cpp
index 1b0c1c5..8f43044 100644
--- a/soundlib/plugins/dmo/WavesReverb.cpp
+++ b/soundlib/plugins/dmo/WavesReverb.cpp
@@ -10,20 +10,19 @@
 
 #include "stdafx.h"
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 #include "../../Sndfile.h"
 #include "WavesReverb.h"
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_BEGIN
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 namespace DMO
 {
 
 IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
-//--------------------------------------------------------------------------------------------------
 {
 	return new (std::nothrow) WavesReverb(factory, sndFile, mixStruct);
 }
@@ -31,7 +30,6 @@ IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDM
 
 WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 	: IMixPlugin(factory, sndFile, mixStruct)
-//-------------------------------------------------------------------------------------------
 {
 	m_param[kRvbInGain] = 1.0f;
 	m_param[kRvbReverbMix] = 1.0f;
@@ -44,7 +42,6 @@ WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGI
 
 
 void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
-//---------------------------------------------------------------------
 {
 	if(!m_mixBuffer.Ok())
 		return;
@@ -52,14 +49,17 @@ void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
 	const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
 	float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
 
-	uint32 delay0 = (m_delay[0] + m_state.combPos + 4) & 0x3FFF;
-	uint32 delay1 = (m_delay[1] + m_state.combPos + 4) & 0x3FFF;
-	uint32 delay2 = (m_delay[2] + m_state.combPos + 4) & 0x3FFF;
-	uint32 delay3 = (m_delay[3] + m_state.combPos + 4) & 0x3FFF;
-	float delay0old = m_state.comb[delay0    ];
-	float delay1old = m_state.comb[delay1 + 1];
-	float delay2old = m_state.comb[delay2 + 2];
-	float delay3old = m_state.comb[delay3 + 3];
+	uint32 combPos = m_state.combPos, allpassPos = m_state.allpassPos;
+	uint32 delay0 = (m_delay[0] + combPos + 1) & 0xFFF;
+	uint32 delay1 = (m_delay[1] + combPos + 1) & 0xFFF;
+	uint32 delay2 = (m_delay[2] + combPos + 1) & 0xFFF;
+	uint32 delay3 = (m_delay[3] + combPos + 1) & 0xFFF;
+	uint32 delay4 = (m_delay[4] + allpassPos) & 0x3FF;
+	uint32 delay5 = (m_delay[5] + allpassPos) & 0x3FF;
+	float delay0old = m_state.comb[delay0][0];
+	float delay1old = m_state.comb[delay1][1];
+	float delay2old = m_state.comb[delay2][2];
+	float delay3old = m_state.comb[delay3][3];
 
 	for(uint32 i = numFrames; i != 0; i--)
 	{
@@ -67,31 +67,28 @@ void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
 		const float rightIn = *(in[1])++ + 1e-30f;	// Prevent denormals
 
 		// Advance buffer index for the four comb filters
-		delay0 = (delay0 - 4) & 0x3FFF;
-		delay1 = (delay1 - 4) & 0x3FFF;
-		delay2 = (delay2 - 4) & 0x3FFF;
-		delay3 = (delay3 - 4) & 0x3FFF;
-		float &delay0new = m_state.comb[delay0    ];
-		float &delay1new = m_state.comb[delay1 + 1];
-		float &delay2new = m_state.comb[delay2 + 2];
-		float &delay3new = m_state.comb[delay3 + 3];
-
-		uint32 pos;
+		delay0 = (delay0 - 1) & 0xFFF;
+		delay1 = (delay1 - 1) & 0xFFF;
+		delay2 = (delay2 - 1) & 0xFFF;
+		delay3 = (delay3 - 1) & 0xFFF;
+		float &delay0new = m_state.comb[delay0][0];
+		float &delay1new = m_state.comb[delay1][1];
+		float &delay2new = m_state.comb[delay2][2];
+		float &delay3new = m_state.comb[delay3][3];
+
 		float r1, r2;
 		
-		pos = (m_state.allpassPos + m_delay[4]) & 0x7FF;
-		r1 = delay1new * 0.61803401f + m_state.allpass1[pos] * m_coeffs[0];
-		r2 = m_state.allpass1[pos + 1] * m_coeffs[0] - delay0new * 0.61803401f;
-		m_state.allpass1[m_state.allpassPos    ] = r2 * 0.61803401f + delay0new;
-		m_state.allpass1[m_state.allpassPos + 1] = delay1new - r1 * 0.61803401f;
+		r1 = delay1new * 0.61803401f + m_state.allpass1[delay4][0] * m_coeffs[0];
+		r2 = m_state.allpass1[delay4][1] * m_coeffs[0] - delay0new * 0.61803401f;
+		m_state.allpass1[allpassPos][0] = r2 * 0.61803401f + delay0new;
+		m_state.allpass1[allpassPos][1] = delay1new - r1 * 0.61803401f;
 		delay0new = r1;
 		delay1new = r2;
 
-		pos = (m_state.allpassPos + m_delay[5]) & 0x7FF;
-		r1 = delay3new * 0.61803401f + m_state.allpass2[pos] * m_coeffs[1];
-		r2 = m_state.allpass2[pos + 1] * m_coeffs[1] - delay2new * 0.61803401f;
-		m_state.allpass2[m_state.allpassPos    ] = r2 * 0.61803401f + delay2new;
-		m_state.allpass2[m_state.allpassPos + 1] = delay3new - r1 * 0.61803401f;
+		r1 = delay3new * 0.61803401f + m_state.allpass2[delay5][0] * m_coeffs[1];
+		r2 = m_state.allpass2[delay5][1] * m_coeffs[1] - delay2new * 0.61803401f;
+		m_state.allpass2[allpassPos][0] = r2 * 0.61803401f + delay2new;
+		m_state.allpass2[allpassPos][1] = delay3new - r1 * 0.61803401f;
 		delay2new = r1;
 		delay3new = r2;
 
@@ -100,10 +97,10 @@ void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
 
 		const float leftWet  = leftIn  * m_wetFactor;
 		const float rightWet = rightIn * m_wetFactor;
-		m_state.comb[m_state.combPos    ] = (delay0new * m_coeffs[2]) + (delay0old * m_coeffs[3]) + leftWet;
-		m_state.comb[m_state.combPos + 1] = (delay1new * m_coeffs[4]) + (delay1old * m_coeffs[5]) + rightWet;
-		m_state.comb[m_state.combPos + 2] = (delay2new * m_coeffs[6]) + (delay2old * m_coeffs[7]) - rightWet;
-		m_state.comb[m_state.combPos + 3] = (delay3new * m_coeffs[8]) + (delay3old * m_coeffs[9]) + leftWet;
+		m_state.comb[combPos][0] = (delay0new * m_coeffs[2]) + (delay0old * m_coeffs[3]) + leftWet;
+		m_state.comb[combPos][1] = (delay1new * m_coeffs[4]) + (delay1old * m_coeffs[5]) + rightWet;
+		m_state.comb[combPos][2] = (delay2new * m_coeffs[6]) + (delay2old * m_coeffs[7]) - rightWet;
+		m_state.comb[combPos][3] = (delay3new * m_coeffs[8]) + (delay3old * m_coeffs[9]) + leftWet;
 
 		delay0old = delay0new;
 		delay1old = delay1new;
@@ -111,16 +108,19 @@ void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
 		delay3old = delay3new;
 
 		// Advance buffer index
-		m_state.combPos = (m_state.combPos - 4) & 0x3FFF;
-		m_state.allpassPos = (m_state.allpassPos - 2) & 0x7FF;
+		combPos = (combPos - 1) & 0xFFF;
+		allpassPos = (allpassPos - 1) & 0x3FF;
+		delay4 = (delay4 - 1) & 0x3FF;
+		delay5 = (delay5 - 1) & 0x3FF;
 	}
+	m_state.combPos = combPos;
+	m_state.allpassPos = allpassPos;
 
 	ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
 }
 
 
 PlugParamValue WavesReverb::GetParameter(PlugParamIndex index)
-//------------------------------------------------------------
 {
 	if(index < kDistNumParameters)
 	{
@@ -131,7 +131,6 @@ PlugParamValue WavesReverb::GetParameter(PlugParamIndex index)
 
 
 void WavesReverb::SetParameter(PlugParamIndex index, PlugParamValue value)
-//------------------------------------------------------------------------
 {
 	if(index < kDistNumParameters)
 	{
@@ -143,26 +142,31 @@ void WavesReverb::SetParameter(PlugParamIndex index, PlugParamValue value)
 
 
 void WavesReverb::Resume()
-//------------------------
 {
 	m_isResumed = true;
 	// Recalculate delays
-	uint32 delay0 = Util::Round<uint32>(m_SndFile.GetSampleRate() * 0.045);
-	uint32 delay1 = Util::Round<uint32>(delay0 * 1.189207077026367);	// 2^0.25
-	uint32 delay2 = Util::Round<uint32>(delay1 * 1.189207077026367);
-	uint32 delay3 = Util::Round<uint32>(delay2 * 1.189207077026367);
-	uint32 delay4 = Util::Round<uint32>((delay0 + delay2) * 0.1154666692018509);
-	uint32 delay5 = Util::Round<uint32>((delay1 + delay3) * 0.1154666692018509);
+	uint32 delay0 = Util::Round<uint32>(m_SndFile.GetSampleRate() * 0.045f);
+	uint32 delay1 = Util::Round<uint32>(delay0 * 1.18920707f);	// 2^0.25
+	uint32 delay2 = Util::Round<uint32>(delay1 * 1.18920707f);
+	uint32 delay3 = Util::Round<uint32>(delay2 * 1.18920707f);
+	uint32 delay4 = Util::Round<uint32>((delay0 + delay2) * 0.11546667f);
+	uint32 delay5 = Util::Round<uint32>((delay1 + delay3) * 0.11546667f);
 	// Comb delays
-	m_delay[0] = (delay0 - delay4) * 4;
-	m_delay[1] = (delay2 - delay4) * 4;
-	m_delay[2] = (delay1 - delay5) * 4;
-	m_delay[3] = (delay3 - delay5) * 4;
+	m_delay[0] = delay0 - delay4;
+	m_delay[1] = delay2 - delay4;
+	m_delay[2] = delay1 - delay5;
+	m_delay[3] = delay3 - delay5;
 	// Allpass delays
-	m_delay[4] = delay4 * 2;
-	m_delay[5] = delay5 * 2;
+	m_delay[4] = delay4;
+	m_delay[5] = delay5;
 
 	RecalculateWavesReverbParams();
+	PositionChanged();
+}
+
+
+void WavesReverb::PositionChanged()
+{
 	MemsetZero(m_state);
 }
 
@@ -170,7 +174,6 @@ void WavesReverb::Resume()
 #ifdef MODPLUG_TRACKER
 
 CString WavesReverb::GetParamName(PlugParamIndex param)
-//-----------------------------------------------------
 {
 	switch(param)
 	{
@@ -184,7 +187,6 @@ CString WavesReverb::GetParamName(PlugParamIndex param)
 
 
 CString WavesReverb::GetParamLabel(PlugParamIndex param)
-//------------------------------------------------------
 {
 	switch(param)
 	{
@@ -199,7 +201,6 @@ CString WavesReverb::GetParamLabel(PlugParamIndex param)
 
 
 CString WavesReverb::GetParamDisplay(PlugParamIndex param)
-//--------------------------------------------------------
 {
 	float value = m_param[param];
 	switch(param)
@@ -216,7 +217,7 @@ CString WavesReverb::GetParamDisplay(PlugParamIndex param)
 		break;
 	}
 	CString s;
-	s.Format("%.2f", value);
+	s.Format(_T("%.2f"), value);
 	return s;
 }
 
@@ -224,20 +225,19 @@ CString WavesReverb::GetParamDisplay(PlugParamIndex param)
 
 
 void WavesReverb::RecalculateWavesReverbParams()
-//----------------------------------------------
 {
 	// Recalculate filters
 	const double ReverbTimeSmp = -3000.0 / (m_SndFile.GetSampleRate() * ReverbTime());
 	const double ReverbTimeSmpHF = ReverbTimeSmp * (1.0 / HighFreqRTRatio() - 1.0);
 
-	m_coeffs[0] = static_cast<float>(std::pow(10.0, (m_delay[4] / 2) * ReverbTimeSmp));
-	m_coeffs[1] = static_cast<float>(std::pow(10.0, (m_delay[5] / 2) * ReverbTimeSmp));
+	m_coeffs[0] = static_cast<float>(std::pow(10.0, m_delay[4] * ReverbTimeSmp));
+	m_coeffs[1] = static_cast<float>(std::pow(10.0, m_delay[5] * ReverbTimeSmp));
 
 	double sum = 0.0;
 	for(uint32 pair = 0; pair < 4; pair++)
 	{
-		double gain1 = std::pow(10.0, (m_delay[pair] / 4) * ReverbTimeSmp);
-		double gain2 = (1.0 - std::pow(10.0, ((m_delay[pair] / 4) + (m_delay[4 + pair / 2] / 2)) * ReverbTimeSmpHF)) * 0.5;
+		double gain1 = std::pow(10.0, m_delay[pair] * ReverbTimeSmp);
+		double gain2 = (1.0 - std::pow(10.0, (m_delay[pair] + m_delay[4 + pair / 2]) * ReverbTimeSmpHF)) * 0.5;
 		double gain3 = gain1 * m_coeffs[pair / 2];
 		double gain4 = gain3 * (((gain3 + 1.0) * gain3 + 1.0) * gain3 + 1.0) + 1.0;
 		m_coeffs[2 + pair * 2] = static_cast<float>(gain1 * (1.0 - gain2));
@@ -256,6 +256,6 @@ void WavesReverb::RecalculateWavesReverbParams()
 #else
 MPT_MSVC_WORKAROUND_LNK4221(WavesReverb)
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/plugins/dmo/WavesReverb.h b/soundlib/plugins/dmo/WavesReverb.h
index beb5c83..a732d1c 100644
--- a/soundlib/plugins/dmo/WavesReverb.h
+++ b/soundlib/plugins/dmo/WavesReverb.h
@@ -8,7 +8,7 @@
  */
 
 
-#if !defined(NO_PLUGINS) && defined(NO_DMO)
+#ifndef NO_PLUGINS
 
 #include "../PlugInterface.h"
 
@@ -17,11 +17,9 @@ OPENMPT_NAMESPACE_BEGIN
 namespace DMO
 {
 
-//===================================
 class WavesReverb : public IMixPlugin
-//===================================
 {
-public:
+protected:
 	enum Parameters
 	{
 		kRvbInGain = 0,
@@ -31,7 +29,6 @@ public:
 		kDistNumParameters
 	};
 
-protected:
 	float m_param[kDistNumParameters];
 
 	// Parameters and coefficients
@@ -44,76 +41,57 @@ protected:
 	struct ReverbState
 	{
 		uint32 combPos, allpassPos;
-		float comb[16384];
-		float allpass1[2048];
-		float allpass2[2048];
+		float comb[4096][4];
+		float allpass1[1024][2];
+		float allpass2[1024][2];
 	} m_state;
 
 public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 	WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
 
-	virtual void Release() { delete this; }
-	virtual int32 GetUID() const { return 0x87FC0268; }
-	virtual int32 GetVersion() const { return 0; }
-	virtual void Idle() { }
-	virtual uint32 GetLatency() const { return 0; }
+	void Release() override { delete this; }
+	int32 GetUID() const override { return 0x87FC0268; }
+	int32 GetVersion() const override { return 0; }
+	void Idle() override { }
+	uint32 GetLatency() const override { return 0; }
 
-	virtual void Process(float *pOutL, float *pOutR, uint32 numFrames);
+	void Process(float *pOutL, float *pOutR, uint32 numFrames) override;
 
-	virtual float RenderSilence(uint32) { return 0.0f; }
-	virtual bool MidiSend(uint32) { return true; }
-	virtual bool MidiSysexSend(const void *, uint32) { return true; }
-	virtual void MidiCC(uint8, MIDIEvents::MidiCC, uint8, CHANNELINDEX) { }
-	virtual void MidiPitchBend(uint8, int32, int8) { }
-	virtual void MidiVibrato(uint8, int32, int8) { }
-	virtual void MidiCommand(uint8, uint8, uint16, uint16, uint16, CHANNELINDEX) { }
-	virtual void HardAllNotesOff() { }
-	virtual bool IsNotePlaying(uint32, uint32, uint32) { return false; }
+	float RenderSilence(uint32) override { return 0.0f; }
 
-	virtual int32 GetNumPrograms() const { return 0; }
-	virtual int32 GetCurrentProgram() { return 0; }
-	virtual void SetCurrentProgram(int32) { }
+	int32 GetNumPrograms() const override { return 0; }
+	int32 GetCurrentProgram() override { return 0; }
+	void SetCurrentProgram(int32) override { }
 
-	virtual PlugParamIndex GetNumParameters() const { return kDistNumParameters; }
-	virtual PlugParamValue GetParameter(PlugParamIndex index);
-	virtual void SetParameter(PlugParamIndex index, PlugParamValue value);
+	PlugParamIndex GetNumParameters() const override { return kDistNumParameters; }
+	PlugParamValue GetParameter(PlugParamIndex index) override;
+	void SetParameter(PlugParamIndex index, PlugParamValue value) override;
 
-	virtual void Resume();
-	virtual void Suspend() { m_isResumed = false; }
-	virtual void PositionChanged() { }
+	void Resume() override;
+	void Suspend() override { m_isResumed = false; }
+	void PositionChanged() override;
 
-	virtual bool IsInstrument() const { return false; }
-	virtual bool CanRecieveMidiEvents() { return false; }
-	virtual bool ShouldProcessSilence() { return true; }
+	bool IsInstrument() const override { return false; }
+	bool CanRecieveMidiEvents() override { return false; }
+	bool ShouldProcessSilence() override { return true; }
 
 #ifdef MODPLUG_TRACKER
-	virtual CString GetDefaultEffectName() { return _T("WavesReverb"); }
-
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
+	CString GetDefaultEffectName() override { return _T("WavesReverb"); }
 
-	virtual CString GetParamName(PlugParamIndex param);
-	virtual CString GetParamLabel(PlugParamIndex);
-	virtual CString GetParamDisplay(PlugParamIndex param);
+	CString GetParamName(PlugParamIndex param) override;
+	CString GetParamLabel(PlugParamIndex) override;
+	CString GetParamDisplay(PlugParamIndex param) override;
 
-	virtual CString GetCurrentProgramName() { return CString(); }
-	virtual void SetCurrentProgramName(const CString &) { }
-	virtual CString GetProgramName(int32) { return CString(); }
+	CString GetCurrentProgramName() override { return CString(); }
+	void SetCurrentProgramName(const CString &) override { }
+	CString GetProgramName(int32) override { return CString(); }
 
-	virtual bool HasEditor() const { return false; }
+	bool HasEditor() const override { return false; }
 #endif
 
-	virtual void BeginSetProgram(int32) { }
-	virtual void EndSetProgram() { }
-
-	virtual int GetNumInputChannels() const { return 2; }
-	virtual int GetNumOutputChannels() const { return 2; }
-
-	virtual bool ProgramsAreChunks() const { return false; }
-
-	virtual size_t GetChunk(char *(&), bool) { return 0; }
-	virtual void SetChunk(size_t, char *, bool) { }
+	int GetNumInputChannels() const override { return 2; }
+	int GetNumOutputChannels() const override { return 2; }
 
 protected:
 	static float GainInDecibel(float param) { return -96.0f + param * 96.0f; }
@@ -126,4 +104,4 @@ protected:
 
 OPENMPT_NAMESPACE_END
 
-#endif // !NO_PLUGINS && NO_DMO
+#endif // !NO_PLUGINS
diff --git a/soundlib/tuning.cpp b/soundlib/tuning.cpp
index 0828787..d276039 100644
--- a/soundlib/tuning.cpp
+++ b/soundlib/tuning.cpp
@@ -13,31 +13,27 @@
 #include "tuning.h"
 #include "../common/mptIO.h"
 #include "../common/serialization_utils.h"
-#ifdef MODPLUG_TRACKER
-#include "../mptrack/Reporting.h"
-#endif
 #include "../common/misc_util.h"
 #include <string>
+#include <cmath>
+
 
 OPENMPT_NAMESPACE_BEGIN
 
-typedef CTuningRTI::RATIOTYPE RATIOTYPE;
-typedef CTuningRTI::NOTEINDEXTYPE NOTEINDEXTYPE;
-typedef CTuningRTI::UNOTEINDEXTYPE UNOTEINDEXTYPE;
-typedef CTuningRTI::STEPINDEXTYPE STEPINDEXTYPE;
-typedef CTuningRTI::USTEPINDEXTYPE USTEPINDEXTYPE;
+
+namespace Tuning {
+
 
 namespace CTuningS11n
 {
 	void ReadStr(std::istream& iStrm, std::string& str, const size_t);
-	void ReadNoteMap(std::istream& iStrm, CTuning::NOTENAMEMAP& m, const size_t);
-	void ReadRatioTable(std::istream& iStrm, std::vector<CTuningRTI::RATIOTYPE>& v, const size_t);
+	void ReadNoteMap(std::istream& iStrm, std::map<NOTEINDEXTYPE, std::string>& m, const size_t);
+	void ReadRatioTable(std::istream& iStrm, std::vector<RATIOTYPE>& v, const size_t);
 
-	void WriteNoteMap(std::ostream& oStrm, const CTuning::NOTENAMEMAP& m);
+	void WriteNoteMap(std::ostream& oStrm, const std::map<NOTEINDEXTYPE, std::string>& m);
 	void WriteStr(std::ostream& oStrm, const std::string& str);
 
 	struct RatioWriter
-	//================
 	{
 		RatioWriter(uint16 nWriteCount = s_nDefaultWriteCount) : m_nWriteCount(nWriteCount) {}
 
@@ -58,28 +54,10 @@ Version changes:
 */
 
 
-static RATIOTYPE Pow(const RATIOTYPE r, const STEPINDEXTYPE s)
-//------------------------------------------------------------
-{
-	if(s == 0) return 1;
-	RATIOTYPE result = r;
-	STEPINDEXTYPE absS = mpt::abs(s);
-	for(STEPINDEXTYPE i = 1; i < absS; i++) result *= r;
-	return (s > 0) ? result : 1/result;
-}
-
-
-CTuningRTI::CTuningRTI(const CTuning* const pTun)
-//-----------------------------------------------
+CTuningRTI::CTuningRTI()
+	: m_TuningType(TT_GENERAL)
+	, m_FineStepCount(0)
 {
-	SetDummyValues();
-	if(pTun) TuningCopy(*this, *pTun);
-}
-
-void CTuningRTI::SetDummyValues()
-//-------------------------------
-{
-	if(MayEdit(EM_RATIOS))
 	{
 		m_RatioTable.clear();
 		m_StepMin = s_StepMinDefault;
@@ -91,8 +69,7 @@ void CTuningRTI::SetDummyValues()
 }
 
 
-bool CTuningRTI::CreateRatioTableGG(const std::vector<RATIOTYPE>& v, const RATIOTYPE r, const VRPAIR& vr, const NOTEINDEXTYPE ratiostartpos)
-//------------------------------------------------------------------------------------------------------------------------------------------
+bool CTuningRTI::ProCreateGroupGeometric(const std::vector<RATIOTYPE>& v, const RATIOTYPE& r, const VRPAIR& vr, const NOTEINDEXTYPE& ratiostartpos)
 {
 	if(v.size() == 0
 		|| r <= 0
@@ -103,8 +80,8 @@ bool CTuningRTI::CreateRatioTableGG(const std::vector<RATIOTYPE>& v, const RATIO
 	}
 
 	m_StepMin = vr.first;
-	ProSetGroupSize(static_cast<UNOTEINDEXTYPE>(v.size()));
-	ProSetGroupRatio(r);
+	m_GroupSize = mpt::saturate_cast<NOTEINDEXTYPE>(v.size());
+	m_GroupRatio = std::fabs(r);
 
 	m_RatioTable.resize(vr.second-vr.first+1);
 	std::copy(v.begin(), v.end(), m_RatioTable.begin() + (ratiostartpos - vr.first));
@@ -122,56 +99,58 @@ bool CTuningRTI::CreateRatioTableGG(const std::vector<RATIOTYPE>& v, const RATIO
 }
 
 
-bool CTuningRTI::ProCreateGroupGeometric(const std::vector<RATIOTYPE>& v, const RATIOTYPE& r, const VRPAIR& vr, const NOTEINDEXTYPE ratiostartpos)
-//------------------------------------------------------------------------------------------------------------------------------------------------
-{
-	//Note: Setting finestep is handled by base class when CreateGroupGeometric is called.
-	if(CreateRatioTableGG(v, r, vr, ratiostartpos)) return true;
-	else return false;
-}
-
-
 bool CTuningRTI::ProCreateGeometric(const UNOTEINDEXTYPE& s, const RATIOTYPE& r, const VRPAIR& vr)
-//------------------------------------------------------------------------------------------------
 {
 	if(vr.second - vr.first + 1 > NOTEINDEXTYPE_MAX) return true;
 	//Note: Setting finestep is handled by base class when CreateGeometric is called.
-	SetDummyValues();
+	{
+		m_RatioTable.clear();
+		m_StepMin = s_StepMinDefault;
+		m_RatioTable.resize(s_RatioTableSizeDefault, static_cast<RATIOTYPE>(1.0));
+		m_GroupSize = 0;
+		m_GroupRatio = 0;
+		m_RatioTableFine.clear();
+	}
 	m_StepMin = vr.first;
-	ProSetGroupSize(s);
-	ProSetGroupRatio(r);
-	const RATIOTYPE stepRatio = pow(r, static_cast<RATIOTYPE>(1)/s);
+	
+	m_GroupSize = mpt::saturate_cast<NOTEINDEXTYPE>(s);
+	m_GroupRatio = std::fabs(r);
+	const RATIOTYPE stepRatio = std::pow(m_GroupRatio, static_cast<RATIOTYPE>(1.0)/ static_cast<RATIOTYPE>(m_GroupSize));
 
 	m_RatioTable.resize(vr.second - vr.first + 1);
 	for(int32 i = vr.first; i<=vr.second; i++)
 	{
-		m_RatioTable[i-m_StepMin] = Pow(stepRatio, i);
+		m_RatioTable[i-m_StepMin] = std::pow(stepRatio, static_cast<RATIOTYPE>(i));
 	}
 	return false;
 }
 
-CTuningRTI::NOTESTR CTuningRTI::ProGetNoteName(const NOTEINDEXTYPE& x, bool addOctave) const
-//------------------------------------------------------------------------------------------
+std::string CTuningRTI::GetNoteName(const NOTEINDEXTYPE& x, bool addOctave) const
 {
+	if(!IsValidNote(x))
+	{
+		return std::string();
+	}
 	if(GetGroupSize() < 1)
 	{
-		return CTuning::ProGetNoteName(x, addOctave);
+		const auto i = m_NoteNameMap.find(x);
+		if(i != m_NoteNameMap.end())
+			return i->second;
+		else
+			return mpt::fmt::val(x);
 	}
 	else
 	{
-		const NOTEINDEXTYPE pos = ((x % m_GroupSize) + m_GroupSize) % m_GroupSize;
+		const NOTEINDEXTYPE pos = static_cast<NOTEINDEXTYPE>(mpt::wrapping_modulo(x, m_GroupSize));
 		const NOTEINDEXTYPE middlePeriodNumber = 5;
 		std::string rValue;
-		NNM_CITER nmi = m_NoteNameMap.find(pos);
+		const auto nmi = m_NoteNameMap.find(pos);
 		if(nmi != m_NoteNameMap.end())
 		{
 			rValue = nmi->second;
 			if(addOctave)
 			{
-				if(x >= 0)
-					rValue += mpt::ToString(middlePeriodNumber + x / m_GroupSize);
-				else
-					rValue += mpt::ToString(middlePeriodNumber + (x + 1) / m_GroupSize - 1);
+				rValue += mpt::fmt::val(middlePeriodNumber + mpt::wrapping_divide(x, m_GroupSize));
 			}
 		}
 		else
@@ -179,16 +158,21 @@ CTuningRTI::NOTESTR CTuningRTI::ProGetNoteName(const NOTEINDEXTYPE& x, bool addO
 			//By default, using notation nnP for notes; nn <-> note character starting
 			//from 'A' with char ':' as fill char, and P is period integer. For example:
 			//C:5, D:3, R:7
-			rValue = std::string(1, static_cast<char>(pos + 'A'));
-
-			rValue += ":";
-
+			if(m_GroupSize <= 26)
+			{
+				rValue = std::string(1, static_cast<char>(pos + 'A'));
+				rValue += ":";
+			} else
+			{
+				rValue = mpt::fmt::HEX0<1>(pos % 16) + mpt::fmt::HEX0<1>((pos / 16) % 16);
+				if(pos > 0xff)
+				{
+					rValue = mpt::ToLowerCaseAscii(rValue);
+				}
+			}
 			if(addOctave)
 			{
-				if(x >= 0)
-					rValue += mpt::ToString(middlePeriodNumber + x/m_GroupSize);
-				else
-					rValue += mpt::ToString(middlePeriodNumber + (x+1)/m_GroupSize - 1);
+				rValue += mpt::fmt::val(middlePeriodNumber + mpt::wrapping_divide(x, m_GroupSize));
 			}
 		}
 		return rValue;
@@ -200,8 +184,7 @@ const RATIOTYPE CTuningRTI::s_DefaultFallbackRatio = 1.0f;
 
 
 //Without finetune
-CTuning::RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& stepsFromCentre) const
-//---------------------------------------------------------------------------------
+RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& stepsFromCentre) const
 {
 	if(stepsFromCentre < m_StepMin) return s_DefaultFallbackRatio;
 	if(stepsFromCentre >= m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size())) return s_DefaultFallbackRatio;
@@ -210,8 +193,7 @@ CTuning::RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& stepsFromCentre) co
 
 
 //With finetune
-CTuning::RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& baseNote, const STEPINDEXTYPE& baseStepDiff) const
-//-------------------------------------------------------------------------------------------------------------
+RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& baseNote, const STEPINDEXTYPE& baseStepDiff) const
 {
 	const STEPINDEXTYPE fsCount = static_cast<STEPINDEXTYPE>(GetFineStepCount());
 	if(fsCount == 0 || baseStepDiff == 0)
@@ -227,16 +209,8 @@ CTuning::RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& baseNote, const STE
 	//next note.
 	NOTEINDEXTYPE note;
 	STEPINDEXTYPE fineStep;
-	if(baseStepDiff >= 0)
-	{
-		note = static_cast<NOTEINDEXTYPE>(baseNote + baseStepDiff / (fsCount+1));
-		fineStep = baseStepDiff % (fsCount+1);
-	}
-	else
-	{
-		note = static_cast<NOTEINDEXTYPE>(baseNote + ((baseStepDiff+1) / (fsCount+1)) - 1);
-		fineStep = ((fsCount + 1) - (mpt::abs(baseStepDiff) % (fsCount+1))) % (fsCount+1);
-	}
+	note = static_cast<NOTEINDEXTYPE>(baseNote + mpt::wrapping_divide(baseStepDiff, (fsCount+1)));
+	fineStep = mpt::wrapping_modulo(baseStepDiff, (fsCount+1));
 
 	if(note < m_StepMin) return s_DefaultFallbackRatio;
 	if(note >= m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size())) return s_DefaultFallbackRatio;
@@ -246,8 +220,7 @@ CTuning::RATIOTYPE CTuningRTI::GetRatio(const NOTEINDEXTYPE& baseNote, const STE
 }
 
 
-CTuning::RATIOTYPE CTuningRTI::GetRatioFine(const NOTEINDEXTYPE& note, USTEPINDEXTYPE sd) const
-//---------------------------------------------------------------------------------------------
+RATIOTYPE CTuningRTI::GetRatioFine(const NOTEINDEXTYPE& note, USTEPINDEXTYPE sd) const
 {
 	if(GetFineStepCount() <= 0)
 		return 1;
@@ -278,48 +251,55 @@ CTuning::RATIOTYPE CTuningRTI::GetRatioFine(const NOTEINDEXTYPE& note, USTEPINDE
 }
 
 
-bool CTuningRTI::ProSetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r)
-//----------------------------------------------------------------------
+bool CTuningRTI::SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r)
 {
+	if(GetType() != TT_GROUPGEOMETRIC && GetType() != TT_GENERAL)
+	{
+		return false;
+	}
 	//Creating ratio table if doesn't exist.
 	if(m_RatioTable.empty())
 	{
 		m_RatioTable.assign(s_RatioTableSizeDefault, 1);
 		m_StepMin = s_StepMinDefault;
 	}
-
-	//If note is not within the table, at least for now
-	//simply don't change anything.
 	if(!IsNoteInTable(s))
-		return true;
-
-	m_RatioTable[s - m_StepMin] = fabs(r);
-	return false;
+	{
+		return false;
+	}
+	m_RatioTable[s - m_StepMin] = std::fabs(r);
+	if(GetType() == TT_GROUPGEOMETRIC)
+	{ // update other groups
+		for(NOTEINDEXTYPE n = m_StepMin; n < m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()); ++n)
+		{
+			if(n == s)
+			{
+				// nothing
+			} else if(mpt::abs(n - s) % m_GroupSize == 0)
+			{
+				m_RatioTable[n - m_StepMin] = std::pow(m_GroupRatio, static_cast<RATIOTYPE>(n - s) / static_cast<RATIOTYPE>(m_GroupSize)) * m_RatioTable[s - m_StepMin];
+			}
+		}
+		UpdateFineStepTable();
+	}
+	return true;
 }
 
 
-CTuningRTI::VRPAIR CTuningRTI::ProSetValidityRange(const VRPAIR&)
-//---------------------------------------------------------------
+void CTuningRTI::SetFineStepCount(const USTEPINDEXTYPE& fs)
 {
-	//TODO: Implementation. Things to note:
-	//		-If validity range is smaller than period, various methods such as ProSetFinestepcount
-	//			might create wrong ratios.
-	return GetValidityRange();
+	m_FineStepCount = mpt::clamp(mpt::saturate_cast<STEPINDEXTYPE>(fs), 0, FINESTEPCOUNT_MAX);
+	UpdateFineStepTable();
 }
 
 
-void CTuningRTI::ProSetFineStepCount(const USTEPINDEXTYPE& fs)
-//------------------------------------------------------------
+void CTuningRTI::UpdateFineStepTable()
 {
-	if(fs <= 0)
+	if(m_FineStepCount <= 0)
 	{
-		m_FineStepCount = 0;
 		m_RatioTableFine.clear();
 		return;
 	}
-
-	m_FineStepCount = (fs > static_cast<UNOTEINDEXTYPE>(NOTEINDEXTYPE_MAX)) ? static_cast<UNOTEINDEXTYPE>(NOTEINDEXTYPE_MAX) : fs;
-
 	if(GetType() == TT_GEOMETRIC)
 	{
 		if(m_FineStepCount > s_RatioTableFineSizeMaxDefault)
@@ -331,7 +311,7 @@ void CTuningRTI::ProSetFineStepCount(const USTEPINDEXTYPE& fs)
 		const RATIOTYPE q = GetRatio(GetValidityRange().first + 1) / GetRatio(GetValidityRange().first);
 		const RATIOTYPE rFineStep = pow(q, static_cast<RATIOTYPE>(1)/(m_FineStepCount+1));
 		for(USTEPINDEXTYPE i = 1; i<=m_FineStepCount; i++)
-			m_RatioTableFine[i-1] = Pow(rFineStep, i);
+			m_RatioTableFine[i-1] = std::pow(rFineStep, static_cast<RATIOTYPE>(i));
 		return;
 	}
 	if(GetType() == TT_GROUPGEOMETRIC)
@@ -375,103 +355,102 @@ void CTuningRTI::ProSetFineStepCount(const USTEPINDEXTYPE& fs)
 }
 
 
-CTuningRTI::NOTEINDEXTYPE CTuningRTI::GetRefNote(const NOTEINDEXTYPE note) const
-//------------------------------------------------------------------------------
+NOTEINDEXTYPE CTuningRTI::GetRefNote(const NOTEINDEXTYPE note) const
 {
-	if(!IsOfType(TT_GROUPGEOMETRIC)) return 0;
-
-	if(note >= 0) return note % GetGroupSize();
-	else return (GetGroupSize() - (mpt::abs(static_cast<int>(note)) % GetGroupSize())) % GetGroupSize();
+	if((GetType() != TT_GROUPGEOMETRIC) && (GetType() != TT_GEOMETRIC)) return 0;
+	return static_cast<NOTEINDEXTYPE>(mpt::wrapping_modulo(note, GetGroupSize()));
 }
 
 
-CTuning* CTuningRTI::Deserialize(std::istream& iStrm)
-//---------------------------------------------------
+SerializationResult CTuningRTI::InitDeserialize(std::istream& iStrm)
 {
-	if(iStrm.fail())
-		return nullptr;
+	// Note: OpenMPT since at least r323 writes version number (4<<24)+4 while it
+	// reads version number (5<<24)+4 or earlier.
+	// We keep this behaviour.
 
-	CTuningRTI* pTuning = new CTuningRTI;
+	if(iStrm.fail())
+		return SerializationResult::Failure;
 
 	srlztn::SsbRead ssb(iStrm);
-	ssb.BeginRead("CTB244RTI", (CTuning::GetVersion() << 24) + GetVersion());
-	ssb.ReadItem(pTuning->m_TuningName, "0", ReadStr);
-	ssb.ReadItem(pTuning->m_EditMask, "1");
-	ssb.ReadItem(pTuning->m_TuningType, "2");
-	ssb.ReadItem(pTuning->m_NoteNameMap, "3", ReadNoteMap);
-	ssb.ReadItem(pTuning->m_FineStepCount, "4");
+	ssb.BeginRead("CTB244RTI", (5 << 24) + 4); // version
+	ssb.ReadItem(m_TuningName, "0", ReadStr);
+	uint16 dummyEditMask = 0xffff;
+	ssb.ReadItem(dummyEditMask, "1");
+	ssb.ReadItem(m_TuningType, "2");
+	ssb.ReadItem(m_NoteNameMap, "3", ReadNoteMap);
+	ssb.ReadItem(m_FineStepCount, "4");
 
 	// RTI entries.
-	ssb.ReadItem(pTuning->m_RatioTable, "RTI0", ReadRatioTable);
-	ssb.ReadItem(pTuning->m_StepMin, "RTI1");
-	ssb.ReadItem(pTuning->m_GroupSize, "RTI2");
-	ssb.ReadItem(pTuning->m_GroupRatio, "RTI3");
+	ssb.ReadItem(m_RatioTable, "RTI0", ReadRatioTable);
+	ssb.ReadItem(m_StepMin, "RTI1");
+	ssb.ReadItem(m_GroupSize, "RTI2");
+	ssb.ReadItem(m_GroupRatio, "RTI3");
 	UNOTEINDEXTYPE ratiotableSize = 0;
 	ssb.ReadItem(ratiotableSize, "RTI4");
 
 	// If reader status is ok and m_StepMin is somewhat reasonable, process data.
-	if ((ssb.GetStatus() & srlztn::SNT_FAILURE) == 0 && pTuning->m_StepMin >= -300 && pTuning->m_StepMin <= 300)
+	if(!((ssb.GetStatus() & srlztn::SNT_FAILURE) == 0 && m_StepMin >= -300 && m_StepMin <= 300))
 	{
-		EDITMASK temp = pTuning->GetEditMask();
-		pTuning->m_EditMask = EM_ALLOWALL; //Allowing all while processing data.
-		if (pTuning->ProProcessUnserializationdata(ratiotableSize))
-		{
-#ifdef MODPLUG_TRACKER
-			Reporting::Error(("Processing loaded data for tuning \"" + pTuning->GetName() + "\" failed.").c_str(), "Tuning load failure");
-#else
-			MPT_LOG(LogError, "tuning", MPT_USTRING("Processing loaded data for tuning \"") + mpt::ToUnicode(mpt::CharsetISO8859_1, pTuning->GetName()) + MPT_USTRING("\" failed."));
-#endif
-			delete pTuning; pTuning = nullptr;
-		}
-		else
-		{
-			USTEPINDEXTYPE fsTemp = pTuning->m_FineStepCount;
-			pTuning->m_FineStepCount = 0;
-			pTuning->SetFineStepCount(fsTemp);
-			pTuning->SetEditMask(temp);
-		}
+		return SerializationResult::Failure;
 	}
-	else
-		{delete pTuning; pTuning = nullptr;}
-	return pTuning;
-}
 
-
-bool CTuningRTI::ProProcessUnserializationdata(UNOTEINDEXTYPE ratiotableSize)
-//---------------------------------------------------------------------------
-{
-	if (m_GroupSize < 0) {m_GroupSize = 0; return true;}
-	if (m_RatioTable.size() > static_cast<size_t>(NOTEINDEXTYPE_MAX)) return true;
-	if (IsOfType(TT_GROUPGEOMETRIC))
+	// reject unknown types
+	if(m_TuningType != TT_GENERAL && m_TuningType != TT_GROUPGEOMETRIC && m_TuningType != TT_GEOMETRIC)
 	{
-		if (ratiotableSize < 1 || ratiotableSize > NOTEINDEXTYPE_MAX) return true;
-		if (GetType() == TT_GEOMETRIC)
-			return CTuning::CreateGeometric(GetGroupSize(), GetGroupRatio(), VRPAIR(m_StepMin, m_StepMin+ratiotableSize-1));
-		else
+		return SerializationResult::Failure;
+	}
+	if(m_GroupSize < 0)
+	{
+		return SerializationResult::Failure;
+	}
+	if(m_RatioTable.size() > static_cast<size_t>(NOTEINDEXTYPE_MAX))
+	{
+		return SerializationResult::Failure;
+	}
+	if((GetType() == TT_GROUPGEOMETRIC) || (GetType() == TT_GEOMETRIC))
+	{
+		if(ratiotableSize < 1 || ratiotableSize > NOTEINDEXTYPE_MAX)
 		{
-			return CreateGroupGeometric(m_RatioTable, GetGroupRatio(), VRPAIR(m_StepMin, m_StepMin+ratiotableSize-1), m_StepMin);
+			return SerializationResult::Failure;
 		}
+		if(GetType() == TT_GEOMETRIC)
+		{
+			if(CreateGeometric(GetGroupSize(), GetGroupRatio(), VRPAIR(m_StepMin, static_cast<NOTEINDEXTYPE>(m_StepMin + ratiotableSize - 1))) != false)
+			{
+				return SerializationResult::Failure;
+			}
+		} else
+		{
+			if(CreateGroupGeometric(m_RatioTable, GetGroupRatio(), VRPAIR(m_StepMin, static_cast<NOTEINDEXTYPE>(m_StepMin+ratiotableSize-1)), m_StepMin) != false)
+			{
+				return SerializationResult::Failure;
+			}
+		}
+	} else
+	{
+		UpdateFineStepTable();
 	}
-	return false;
+	return SerializationResult::Success;
 }
 
 
-template<class T, class SIZETYPE>
-bool VectorFromBinaryStream(std::istream& inStrm, std::vector<T>& v, const SIZETYPE maxSize = (std::numeric_limits<SIZETYPE>::max)())
-//-----------------------------------------------------------------------------------------------------------------------------------
+template<class T, class SIZETYPE, class Tdst>
+static bool VectorFromBinaryStream(std::istream& inStrm, std::vector<Tdst>& v, const SIZETYPE maxSize = (std::numeric_limits<SIZETYPE>::max)())
 {
 	if(!inStrm.good()) return true;
 
-	SIZETYPE size;
-	inStrm.read(reinterpret_cast<char*>(&size), sizeof(size));
+	SIZETYPE size = 0;
+	mpt::IO::ReadIntLE<SIZETYPE>(inStrm, size);
 
 	if(size > maxSize)
 		return true;
 
 	v.resize(size);
-	for(size_t i = 0; i<size; i++)
+	for(std::size_t i = 0; i<size; i++)
 	{
-		inStrm.read(reinterpret_cast<char*>(&v[i]), sizeof(T));
+		T tmp = T();
+		mpt::IO::Read(inStrm, tmp);
+		v[i] = tmp;
 	}
 	if(inStrm.good())
 		return false;
@@ -480,14 +459,240 @@ bool VectorFromBinaryStream(std::istream& inStrm, std::vector<T>& v, const SIZET
 }
 
 
-CTuning::SERIALIZATION_RETURN_TYPE CTuningRTI::Serialize(std::ostream& outStrm) const
-//-----------------------------------------------------------------------------------
+SerializationResult CTuningRTI::InitDeserializeOLD(std::istream& inStrm)
 {
+	if(!inStrm.good())
+		return SerializationResult::Failure;
+
+	const std::streamoff startPos = inStrm.tellg();
+
+	//First checking is there expected begin sequence.
+	char begin[8];
+	MemsetZero(begin);
+	inStrm.read(begin, sizeof(begin));
+	if(std::memcmp(begin, "CTRTI_B.", 8))
+	{
+		//Returning stream position if beginmarker was not found.
+		inStrm.seekg(startPos);
+		return SerializationResult::Failure;
+	}
+
+	//Version
+	int16 version = 0;
+	mpt::IO::ReadIntLE<int16>(inStrm, version);
+	if(version != 2 && version != 3)
+		return SerializationResult::Failure;
+
+	char begin2[8];
+	MemsetZero(begin2);
+	inStrm.read(begin2, sizeof(begin2));
+	if(std::memcmp(begin2, "CT<sfs>B", 8))
+	{
+		return SerializationResult::Failure;
+	}
+
+	int16 version2 = 0;
+	mpt::IO::ReadIntLE<int16>(inStrm, version2);
+	if(version2 != 3 && version2 != 4)
+	{
+		return SerializationResult::Failure;
+	}
+
+	//Tuning name
+	if(version2 <= 3)
+	{
+		if(!mpt::IO::ReadSizedStringLE<uint32>(inStrm, m_TuningName, 0xffff))
+		{
+			return SerializationResult::Failure;
+		}
+	} else
+	{
+		if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, m_TuningName))
+		{
+			return SerializationResult::Failure;
+		}
+	}
+
+	//Const mask
+	int16 em = 0;
+	mpt::IO::ReadIntLE<int16>(inStrm, em);
+
+	//Tuning type
+	int16 tt = 0;
+	mpt::IO::ReadIntLE<int16>(inStrm, tt);
+	m_TuningType = tt;
+
+	//Notemap
+	uint16 size = 0;
+	if(version2 <= 3)
+	{
+		uint32 tempsize = 0;
+		mpt::IO::ReadIntLE<uint32>(inStrm, tempsize);
+		if(tempsize > 0xffff)
+		{
+			return SerializationResult::Failure;
+		}
+		size = mpt::saturate_cast<uint16>(tempsize);
+	} else
+	{
+		mpt::IO::ReadIntLE<uint16>(inStrm, size);
+	}
+	for(UNOTEINDEXTYPE i = 0; i<size; i++)
+	{
+		std::string str;
+		int16 n = 0;
+		mpt::IO::ReadIntLE<int16>(inStrm, n);
+		if(version2 <= 3)
+		{
+			if(!mpt::IO::ReadSizedStringLE<uint32>(inStrm, str, 0xffff))
+			{
+				return SerializationResult::Failure;
+			}
+		} else
+		{
+			if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, str))
+			{
+				return SerializationResult::Failure;
+			}
+		}
+		m_NoteNameMap[n] = str;
+	}
+
+	//End marker
+	char end2[8];
+	MemsetZero(end2);
+	inStrm.read(end2, sizeof(end2));
+	if(std::memcmp(end2, "CT<sfs>E", 8))
+	{
+		return SerializationResult::Failure;
+	}
+
+	// reject unknown types
+	if(m_TuningType != TT_GENERAL && m_TuningType != TT_GROUPGEOMETRIC && m_TuningType != TT_GEOMETRIC)
+	{
+		return SerializationResult::Failure;
+	}
+
+	//Ratiotable
+	if(version <= 2)
+	{
+		if(VectorFromBinaryStream<IEEE754binary32LE, uint32>(inStrm, m_RatioTable, 0xffff))
+		{
+			return SerializationResult::Failure;
+		}
+	} else
+	{
+		if(VectorFromBinaryStream<IEEE754binary32LE, uint16>(inStrm, m_RatioTable))
+		{
+			return SerializationResult::Failure;
+		}
+	}
+
+	//Fineratios
+	if(version <= 2)
+	{
+		if(VectorFromBinaryStream<IEEE754binary32LE, uint32>(inStrm, m_RatioTableFine, 0xffff))
+		{
+			return SerializationResult::Failure;
+		}
+	} else
+	{
+		if(VectorFromBinaryStream<IEEE754binary32LE, uint16>(inStrm, m_RatioTableFine))
+		{
+			return SerializationResult::Failure;
+		}
+	}
+	m_FineStepCount = mpt::saturate_cast<USTEPINDEXTYPE>(m_RatioTableFine.size());
+
+	//m_StepMin
+	int16 stepmin = 0;
+	mpt::IO::ReadIntLE<int16>(inStrm, stepmin);
+	m_StepMin = stepmin;
+	if(m_StepMin < -200 || m_StepMin > 200)
+	{
+		return SerializationResult::Failure;
+	}
+
+	//m_GroupSize
+	int16 groupsize = 0;
+	mpt::IO::ReadIntLE<int16>(inStrm, groupsize);
+	m_GroupSize = groupsize;
+	if(m_GroupSize < 0)
+	{
+		return SerializationResult::Failure;
+	}
+
+	//m_GroupRatio
+	IEEE754binary32LE groupratio = IEEE754binary32LE(0.0f);
+	mpt::IO::Read(inStrm, groupratio);
+	m_GroupRatio = groupratio;
+	if(m_GroupRatio < 0)
+	{
+		return SerializationResult::Failure;
+	}
+
+	char end[8];
+	MemsetZero(end);
+	inStrm.read(reinterpret_cast<char*>(&end), sizeof(end));
+	if(std::memcmp(end, "CTRTI_E.", 8))
+	{
+		return SerializationResult::Failure;
+	}
+
+	// reject corrupt tunings
+	if(m_RatioTable.size() > static_cast<std::size_t>(NOTEINDEXTYPE_MAX))
+	{
+		return SerializationResult::Failure;
+	}
+	if((m_GroupSize <= 0 || m_GroupRatio <= 0) && m_TuningType != TT_GENERAL)
+	{
+		return SerializationResult::Failure;
+	}
+	if(m_TuningType == TT_GROUPGEOMETRIC || m_TuningType == TT_GEOMETRIC)
+	{
+		if(m_RatioTable.size() < static_cast<std::size_t>(m_GroupSize))
+		{
+			return SerializationResult::Failure;
+		}
+	}
+
+	// convert old finestepcount
+	if(m_FineStepCount > 0)
+	{
+		m_FineStepCount -= 1;
+	}
+	UpdateFineStepTable();
+
+	if(m_TuningType == TT_GEOMETRIC)
+	{
+		// Convert old geometric to new groupgeometric because old geometric tunings
+		// can have ratio(0) != 1.0, which would get lost when saving nowadays.
+		if(mpt::saturate_cast<NOTEINDEXTYPE>(m_RatioTable.size()) >= m_GroupSize - m_StepMin)
+		{
+			std::vector<RATIOTYPE> ratios;
+			for(NOTEINDEXTYPE n = 0; n < m_GroupSize; ++n)
+			{
+				ratios.push_back(m_RatioTable[n - m_StepMin]);
+			}
+			CreateGroupGeometric(ratios, m_GroupRatio, GetValidityRange(), 0);
+		}
+	}
+
+	return SerializationResult::Success;
+}
+
+
+Tuning::SerializationResult CTuningRTI::Serialize(std::ostream& outStrm) const
+{
+	// Note: OpenMPT since at least r323 writes version number (4<<24)+4 while it
+	// reads version number (5<<24)+4.
+	// We keep this behaviour.
 	srlztn::SsbWrite ssb(outStrm);
-	ssb.BeginWrite("CTB244RTI", (GetVersion() << 24) + GetClassVersion());
+	ssb.BeginWrite("CTB244RTI", (4 << 24) + 4); // version
 	if (m_TuningName.length() > 0)
 		ssb.WriteItem(m_TuningName, "0", WriteStr);
-	ssb.WriteItem(m_EditMask, "1");
+	uint16 dummyEditMask = 0xffff;
+	ssb.WriteItem(dummyEditMask, "1");
 	ssb.WriteItem(m_TuningType, "2");
 	if (m_NoteNameMap.size() > 0)
 		ssb.WriteItem(m_NoteNameMap, "3", WriteNoteMap);
@@ -515,15 +720,84 @@ CTuning::SERIALIZATION_RETURN_TYPE CTuningRTI::Serialize(std::ostream& outStrm)
 
 	ssb.FinishWrite();
 
-	return ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) ? SERIALIZATION_FAILURE : SERIALIZATION_SUCCESS;
+	return ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) ? Tuning::SerializationResult::Failure : Tuning::SerializationResult::Success;
 }
 
 
+#ifdef MODPLUG_TRACKER
+
+bool CTuningRTI::WriteSCL(std::ostream &f, const mpt::PathString &filename) const
+{
+	mpt::IO::WriteTextCRLF(f, mpt::format("! %1")(mpt::ToCharset(mpt::CharsetISO8859_1, (filename.GetFileName() + filename.GetFileExt()).ToUnicode())));
+	mpt::IO::WriteTextCRLF(f, "!");
+	std::string name = mpt::ToCharset(mpt::CharsetISO8859_1, mpt::CharsetLocale, GetName());
+	for(auto & c : name) { if(c < 32) c = ' '; } // remove control characters
+	if(name.length() >= 1 && name[0] == '!') name[0] = '?'; // do not confuse description with comment
+	mpt::IO::WriteTextCRLF(f, name);
+	if(GetType() == TT_GEOMETRIC)
+	{
+		mpt::IO::WriteTextCRLF(f, mpt::format(" %1")(m_GroupSize));
+		mpt::IO::WriteTextCRLF(f, "!");
+		for(NOTEINDEXTYPE n = 0; n < m_GroupSize; ++n)
+		{
+			double ratio = std::pow(static_cast<double>(m_GroupRatio), static_cast<double>(n + 1) / static_cast<double>(m_GroupSize));
+			double cents = std::log2(ratio) * 1200.0;
+			mpt::IO::WriteTextCRLF(f, mpt::format(" %1 ! %2")(
+				mpt::fmt::fix(cents),
+				mpt::ToCharset(mpt::CharsetISO8859_1, mpt::CharsetLocale, GetNoteName((n + 1) % m_GroupSize, false))
+				));
+		}
+	} else if(GetType() == TT_GROUPGEOMETRIC)
+	{
+		mpt::IO::WriteTextCRLF(f, mpt::format(" %1")(m_GroupSize));
+		mpt::IO::WriteTextCRLF(f, "!");
+		for(NOTEINDEXTYPE n = 0; n < m_GroupSize; ++n)
+		{
+			bool last = (n == (m_GroupSize - 1));
+			double baseratio = static_cast<double>(GetRatio(0));
+			double ratio = static_cast<double>(last ? m_GroupRatio : GetRatio(n + 1)) / baseratio;
+			double cents = std::log2(ratio) * 1200.0;
+			mpt::IO::WriteTextCRLF(f, mpt::format(" %1 ! %2")(
+				mpt::fmt::fix(cents),
+				mpt::ToCharset(mpt::CharsetISO8859_1, mpt::CharsetLocale, GetNoteName((n + 1) % m_GroupSize, false))
+				));
+		}
+	} else if(GetType() == TT_GENERAL)
+	{
+		mpt::IO::WriteTextCRLF(f, mpt::format(" %1")(m_RatioTable.size() + 1));
+		mpt::IO::WriteTextCRLF(f, "!");
+		double baseratio = 1.0;
+		for(NOTEINDEXTYPE n = 0; n < mpt::saturate_cast<NOTEINDEXTYPE>(m_RatioTable.size()); ++n)
+		{
+			baseratio = std::min(baseratio, static_cast<double>(m_RatioTable[n]));
+		}
+		for(NOTEINDEXTYPE n = 0; n < mpt::saturate_cast<NOTEINDEXTYPE>(m_RatioTable.size()); ++n)
+		{
+			double ratio = static_cast<double>(m_RatioTable[n]) / baseratio;
+			double cents = std::log2(ratio) * 1200.0;
+			mpt::IO::WriteTextCRLF(f, mpt::format(" %1 ! %2")(
+				mpt::fmt::fix(cents),
+				mpt::ToCharset(mpt::CharsetISO8859_1, mpt::CharsetLocale, GetNoteName(n + m_StepMin, false))
+				));
+		}
+		mpt::IO::WriteTextCRLF(f, mpt::format(" %1 ! %2")(
+			mpt::fmt::val(1),
+			std::string()
+			));
+	} else
+	{
+		return false;
+	}
+	return true;
+}
+
+#endif
+
+
 namespace CTuningS11n
 {
 
 void RatioWriter::operator()(std::ostream& oStrm, const std::vector<float>& v)
-//----------------------------------------------------------------------------
 {
 	const size_t nWriteCount = MIN(v.size(), m_nWriteCount);
 	mpt::IO::WriteAdaptiveInt64LE(oStrm, nWriteCount);
@@ -532,8 +806,7 @@ void RatioWriter::operator()(std::ostream& oStrm, const std::vector<float>& v)
 }
 
 
-void ReadNoteMap(std::istream& iStrm, CTuning::NOTENAMEMAP& m, const size_t)
-//--------------------------------------------------------------------------
+void ReadNoteMap(std::istream& iStrm, std::map<NOTEINDEXTYPE,std::string>& m, const size_t)
 {
 	uint64 val;
 	mpt::IO::ReadAdaptiveInt64LE(iStrm, val);
@@ -549,8 +822,7 @@ void ReadNoteMap(std::istream& iStrm, CTuning::NOTENAMEMAP& m, const size_t)
 }
 
 
-void ReadRatioTable(std::istream& iStrm, std::vector<CTuningRTI::RATIOTYPE>& v, const size_t)
-//-------------------------------------------------------------------------------------------
+void ReadRatioTable(std::istream& iStrm, std::vector<RATIOTYPE>& v, const size_t)
 {
 	uint64 val;
 	mpt::IO::ReadAdaptiveInt64LE(iStrm, val);
@@ -565,33 +837,33 @@ void ReadRatioTable(std::istream& iStrm, std::vector<CTuningRTI::RATIOTYPE>& v,
 
 
 void ReadStr(std::istream& iStrm, std::string& str, const size_t)
-//---------------------------------------------------------------
 {
 	uint64 val;
 	mpt::IO::ReadAdaptiveInt64LE(iStrm, val);
 	size_t nSize = (val > 255) ? 255 : static_cast<size_t>(val); // Read 255 characters at max.
+	str.clear();
 	str.resize(nSize);
 	for(size_t i = 0; i < nSize; i++)
 		mpt::IO::ReadIntLE(iStrm, str[i]);
+	if(str.find_first_of('\0') != std::string::npos)
+	{ // trim \0 at the end
+		str.resize(str.find_first_of('\0'));
+	}
 }
 
 
-void WriteNoteMap(std::ostream& oStrm, const CTuning::NOTENAMEMAP& m)
-//-------------------------------------------------------------------
+void WriteNoteMap(std::ostream& oStrm, const std::map<NOTEINDEXTYPE, std::string>& m)
 {
 	mpt::IO::WriteAdaptiveInt64LE(oStrm, m.size());
-	CTuning::NNM_CITER iter = m.begin();
-	CTuning::NNM_CITER end = m.end();
-	for(; iter != end; iter++)
+	for(auto &mi : m)
 	{
-		mpt::IO::WriteIntLE<int16>(oStrm, iter->first);
-		mpt::IO::WriteSizedStringLE<uint8>(oStrm, iter->second);
+		mpt::IO::WriteIntLE<int16>(oStrm, mi.first);
+		mpt::IO::WriteSizedStringLE<uint8>(oStrm, mi.second);
 	}
 }
 
 
 void WriteStr(std::ostream& oStrm, const std::string& str)
-//--------------------------------------------------------
 {
 	mpt::IO::WriteAdaptiveInt64LE(oStrm, str.size());
 	oStrm.write(str.c_str(), str.size());
@@ -600,4 +872,7 @@ void WriteStr(std::ostream& oStrm, const std::string& str)
 } // namespace CTuningS11n.
 
 
+} // namespace Tuning
+
+
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/tuning.h b/soundlib/tuning.h
index 32c3b5a..57467c4 100644
--- a/soundlib/tuning.h
+++ b/soundlib/tuning.h
@@ -10,132 +10,205 @@
 
 #pragma once
 
+#include <map>
+
 #include "tuningbase.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
 
 
-typedef CTuningBase CTuning;
-
+namespace Tuning {
 
 
-//================================
-class CTuningRTI : public CTuning //RTI <-> Ratio Table Implementation
-//================================
+class CTuningRTI
 {
 
 public:
-//BEGIN STATIC CONST MEMBERS:
+
+	static const char s_FileExtension[5];
+
+	enum
+	{
+		TT_GENERAL        = 0,
+		TT_GROUPGEOMETRIC = 1,
+		TT_GEOMETRIC      = 3,
+	};
+
 	static const RATIOTYPE s_DefaultFallbackRatio;
 	static const NOTEINDEXTYPE s_StepMinDefault = -64;
 	static const UNOTEINDEXTYPE s_RatioTableSizeDefault = 128;
 	static const USTEPINDEXTYPE s_RatioTableFineSizeMaxDefault = 1000;
-	static const SERIALIZATION_VERSION s_SerializationVersion = 4;
-//END STATIC CONST MEMBERS
-
 
 public:
-//BEGIN TUNING INTERFACE METHODS:
-	virtual RATIOTYPE GetRatio(const NOTEINDEXTYPE& stepsFromCentre) const;
 
-	virtual RATIOTYPE GetRatio(const NOTEINDEXTYPE& stepsFromCentre, const STEPINDEXTYPE& fineSteps) const;
+	//To return ratio of certain note.
+	RATIOTYPE GetRatio(const NOTEINDEXTYPE& stepsFromCentre) const;
+
+	//To return ratio from a 'step'(noteindex + stepindex)
+	RATIOTYPE GetRatio(const NOTEINDEXTYPE& stepsFromCentre, const STEPINDEXTYPE& fineSteps) const;
 
-	virtual UNOTEINDEXTYPE GetRatioTableSize() const {return static_cast<UNOTEINDEXTYPE>(m_RatioTable.size());}
+	UNOTEINDEXTYPE GetRatioTableSize() const {return static_cast<UNOTEINDEXTYPE>(m_RatioTable.size());}
 
-	virtual NOTEINDEXTYPE GetRatioTableBeginNote() const {return m_StepMin;}
+	NOTEINDEXTYPE GetRatioTableBeginNote() const {return m_StepMin;}
 
-	VRPAIR GetValidityRange() const {return VRPAIR(m_StepMin, m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()) - 1);}
+	//Tuning might not be valid for arbitrarily large range,
+	//so this can be used to ask where it is valid. Tells the lowest and highest
+	//note that are valid.
+	VRPAIR GetValidityRange() const {return VRPAIR(m_StepMin, static_cast<NOTEINDEXTYPE>(m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()) - 1));}
+
+	//Return true if note is within validity range - false otherwise.
+	bool IsValidNote(const NOTEINDEXTYPE n) const {return (n >= GetValidityRange().first && n <= GetValidityRange().second);}
 
 	UNOTEINDEXTYPE GetGroupSize() const {return m_GroupSize;}
 
 	RATIOTYPE GetGroupRatio() const {return m_GroupRatio;}
 
-	virtual STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& from, const NOTEINDEXTYPE& to) const
+	//To return (fine)stepcount between two consecutive mainsteps.
+	USTEPINDEXTYPE GetFineStepCount() const {return m_FineStepCount;}
+
+	//To return 'directed distance' between given notes.
+	STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& from, const NOTEINDEXTYPE& to) const
 		{return (to - from)*(static_cast<NOTEINDEXTYPE>(GetFineStepCount())+1);}
 
-	virtual STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& noteFrom, const STEPINDEXTYPE& stepDistFrom, const NOTEINDEXTYPE& noteTo, const STEPINDEXTYPE& stepDistTo) const
+	//To return 'directed distance' between given steps.
+	STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& noteFrom, const STEPINDEXTYPE& stepDistFrom, const NOTEINDEXTYPE& noteTo, const STEPINDEXTYPE& stepDistTo) const
 		{return GetStepDistance(noteFrom, noteTo) + stepDistTo - stepDistFrom;}
 
-	static CTuning* Deserialize(std::istream& inStrm);
+	//To set finestepcount between two consecutive mainsteps.
+	//Finestep count == 0 means that
+	//stepdistances become the same as note distances.
+	void SetFineStepCount(const USTEPINDEXTYPE& fs);
 
-	static uint32 GetVersion() {return s_SerializationVersion;}
+	//Multiply all ratios by given number.
+	bool Multiply(const RATIOTYPE&);
 
-	//Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr.
-	static CTuningRTI* DeserializeOLD(std::istream&) {return 0;}
+	bool SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r);
 
-	SERIALIZATION_RETURN_TYPE Serialize(std::ostream& out) const;
+	TUNINGTYPE GetType() const {return m_TuningType;}
 
+	std::string GetNoteName(const NOTEINDEXTYPE& x, bool addOctave = true) const;
 
-public:
-	//PUBLIC CONSTRUCTORS/DESTRUCTORS:
-	CTuningRTI(const std::vector<RATIOTYPE>& ratios,
-				const NOTEINDEXTYPE& stepMin = s_StepMinDefault,
-				const std::string& name = "")
-				: CTuning(name)
+	void SetNoteName(const NOTEINDEXTYPE&, const std::string&);
+
+	static CTuningRTI* CreateDeserialize(std::istream & f)
+	{
+		CTuningRTI *pT = new CTuningRTI();
+		if(pT->InitDeserialize(f) != SerializationResult::Success)
+		{
+			delete pT;
+			return nullptr;
+		}
+		return pT;
+	}
+
+	//Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr.
+	static CTuningRTI* CreateDeserializeOLD(std::istream & f)
 	{
-		SetDummyValues();
-		m_StepMin = stepMin;
-		m_RatioTable = ratios;
+		CTuningRTI *pT = new CTuningRTI();
+		if(pT->InitDeserializeOLD(f) != SerializationResult::Success)
+		{
+			delete pT;
+			return nullptr;
+		}
+		return pT;
 	}
 
-	//Copy tuning.
-	CTuningRTI(const CTuning* const pTun);
+	static CTuningRTI* CreateGeneral(const std::string &name)
+	{
+		CTuningRTI *pT = new CTuningRTI();
+		pT->SetName(name);
+		return pT;
+	}
 
-	CTuningRTI() {SetDummyValues();}
+	static CTuningRTI* CreateGroupGeometric(const std::string &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
+	{
+		CTuningRTI *pT = new CTuningRTI();
+		pT->SetName(name);
+		if(pT->CreateGroupGeometric(groupsize, groupratio, 0) != false)
+		{
+			delete pT;
+			return nullptr;
+		}
+		pT->SetFineStepCount(finestepcount);
+		return pT;
+	}
 
-	CTuningRTI(const std::string& name) : CTuning(name) {SetDummyValues();}
+	static CTuningRTI* CreateGroupGeometric(const std::string &name, const std::vector<RATIOTYPE> &ratios, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
+	{
+		CTuningRTI *pT = new CTuningRTI();
+		pT->SetName(name);
+		VRPAIR range = std::make_pair(s_StepMinDefault, static_cast<NOTEINDEXTYPE>(s_StepMinDefault + s_RatioTableSizeDefault - 1));
+		range.second = std::max(range.second, mpt::saturate_cast<NOTEINDEXTYPE>(ratios.size() - 1));
+		range.first = 0 - range.second - 1;
+		if(pT->CreateGroupGeometric(ratios, groupratio, range, 0) != false)
+		{
+			delete pT;
+			return nullptr;
+		}
+		pT->SetFineStepCount(finestepcount);
+		return pT;
+	}
 
-	CTuningRTI(const NOTEINDEXTYPE& stepMin, const std::string& name) : CTuning(name)
+	static CTuningRTI* CreateGeometric(const std::string &name, UNOTEINDEXTYPE groupsize, RATIOTYPE groupratio, USTEPINDEXTYPE finestepcount)
 	{
-		SetDummyValues();
-		m_StepMin = stepMin;
+		CTuningRTI *pT = new CTuningRTI();
+		pT->SetName(name);
+		if(pT->CreateGeometric(groupsize, groupratio) != false)
+		{
+			delete pT;
+			return nullptr;
+		}
+		pT->SetFineStepCount(finestepcount);
+		return pT;
 	}
 
-	virtual ~CTuningRTI() {}
+	Tuning::SerializationResult Serialize(std::ostream& out) const;
 
-//BEGIN PROTECTED VIRTUALS:
-protected:
-	bool ProSetRatio(const NOTEINDEXTYPE&, const RATIOTYPE&);
-	bool ProCreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR&, const NOTEINDEXTYPE ratiostartpos);
-	bool ProCreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR&);
-	void ProSetFineStepCount(const USTEPINDEXTYPE&);
+#ifdef MODPLUG_TRACKER
+	bool WriteSCL(std::ostream &f, const mpt::PathString &filename) const;
+#endif
+
+	bool ChangeGroupsize(const NOTEINDEXTYPE&);
+	bool ChangeGroupRatio(const RATIOTYPE&);
 
-	virtual NOTESTR ProGetNoteName(const NOTEINDEXTYPE& xi, bool addOctave) const;
+	void SetName(const std::string& s) { m_TuningName = s; }
+	std::string GetName() const {return m_TuningName;}
 
-	//Not implemented.
-	VRPAIR ProSetValidityRange(const VRPAIR&);
+private:
+
+	CTuningRTI();
 
-	//Note: Groupsize is restricted to interval [0, NOTEINDEXTYPE_MAX]
-	NOTEINDEXTYPE ProSetGroupSize(const UNOTEINDEXTYPE& p) {return m_GroupSize = (p<=static_cast<UNOTEINDEXTYPE>(NOTEINDEXTYPE_MAX)) ? static_cast<NOTEINDEXTYPE>(p) : NOTEINDEXTYPE_MAX;}
-	RATIOTYPE ProSetGroupRatio(const RATIOTYPE& pr) {return m_GroupRatio = (pr >= 0) ? pr : -pr;}
+	SerializationResult InitDeserialize(std::istream& inStrm);
 
-	virtual uint32 GetClassVersion() const {return GetVersion();}
+	//Try to read old version (v.3) and return pointer to new instance if succesfull, else nullptr.
+	SerializationResult InitDeserializeOLD(std::istream&);
 
-	virtual bool ProProcessUnserializationdata(UNOTEINDEXTYPE ratiotableSize);
+	//Create GroupGeometric tuning of *this using virtual ProCreateGroupGeometric.
+	bool CreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR vr, const NOTEINDEXTYPE ratiostartpos);
 
+	//Create GroupGeometric of *this using ratios from 'itself' and ratios starting from
+	//position given as third argument.
+	bool CreateGroupGeometric(const NOTEINDEXTYPE&, const RATIOTYPE&, const NOTEINDEXTYPE&);
 
-//END PROTECTED VIRTUALS
+	//Create geometric tuning of *this using ratio(0) = 1.
+	bool CreateGeometric(const UNOTEINDEXTYPE& p, const RATIOTYPE& r) {return CreateGeometric(p,r,GetValidityRange());}
+	bool CreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR vr);
+
+	//The two methods below return false if action was done, true otherwise.
+	bool ProCreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR&, const NOTEINDEXTYPE& ratiostartpos);
+	bool ProCreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR&);
 
-protected:
-//BEGIN PROTECTED CLASS SPECIFIC METHODS:
-	//GroupGeometric.
-	bool CreateRatioTableGG(const std::vector<RATIOTYPE>&, const RATIOTYPE, const VRPAIR& vr, const NOTEINDEXTYPE ratiostartpos);
+	void UpdateFineStepTable();
 
 	//Note: Stepdiff should be in range [1, finestepcount]
-	virtual RATIOTYPE GetRatioFine(const NOTEINDEXTYPE& note, USTEPINDEXTYPE stepDiff) const;
+	RATIOTYPE GetRatioFine(const NOTEINDEXTYPE& note, USTEPINDEXTYPE stepDiff) const;
 
 	//GroupPeriodic-specific.
 	//Get the corresponding note in [0, period-1].
 	//For example GetRefNote(-1) is to return note :'groupsize-1'.
 	NOTEINDEXTYPE GetRefNote(NOTEINDEXTYPE note) const;
 
-private:
-	//PRIVATE METHODS:
-
-	//Sets dummy values for *this.
-	void SetDummyValues();
-
 	bool IsNoteInTable(const NOTEINDEXTYPE& s) const
 	{
 		if(s < m_StepMin || s >= m_StepMin + static_cast<NOTEINDEXTYPE>(m_RatioTable.size()))
@@ -145,8 +218,8 @@ private:
 	}
 
 private:
-	//ACTUAL DATA MEMBERS
-	//NOTE: Update SetDummyValues when adding members.
+
+	TUNINGTYPE m_TuningType;
 
 	//Noteratios
 	std::vector<RATIOTYPE> m_RatioTable;
@@ -162,9 +235,19 @@ private:
 	NOTEINDEXTYPE m_GroupSize;
 	RATIOTYPE m_GroupRatio;
 
-	//<----Actual data members
+	USTEPINDEXTYPE m_FineStepCount;
+
+	std::string m_TuningName;
+
+	std::map<NOTEINDEXTYPE, std::string> m_NoteNameMap;
+
+}; // class CTuningRTI
+
+
+typedef CTuningRTI CTuning;
+
 
-}; //End: CTuningRTI declaration.
+} // namespace Tuning
 
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/tuningCollection.cpp b/soundlib/tuningCollection.cpp
index a5f428b..6ecaa60 100644
--- a/soundlib/tuningCollection.cpp
+++ b/soundlib/tuningCollection.cpp
@@ -13,13 +13,16 @@
 #include "../common/mptIO.h"
 #include "../common/serialization_utils.h"
 #include <algorithm>
-#include <bitset>
 #include "../common/mptFileIO.h"
+#include "Loaders.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
 
 
+namespace Tuning {
+
+
 /*
 Version history:
 	2->3: Serialization revamp(August 2007)
@@ -27,90 +30,62 @@ Version history:
 		  to uint8. (March 2007)
 */
 
-/*
-TODOS:
--Handle const-status better(e.g. status check in unserialization)
-*/
 
 const char CTuningCollection::s_FileExtension[4] = ".tc";
 
+
 namespace CTuningS11n
 {
-	void WriteNoteMap(std::ostream& oStrm, const CTuning::NOTENAMEMAP& m);
 	void ReadStr(std::istream& iStrm, std::string& str, const size_t);
-
-	void ReadNoteMap(std::istream& iStrm, CTuning::NOTENAMEMAP& m, const size_t);
-	void ReadRatioTable(std::istream& iStrm, std::vector<CTuningRTI::RATIOTYPE>& v, const size_t);
 	void WriteStr(std::ostream& oStrm, const std::string& str);
-
-	void ReadTuning(std::istream& iStrm, CTuningCollection& Tc, const size_t) {Tc.AddTuning(iStrm, true);}
-	void WriteTuning(std::ostream& oStrm, const CTuning& t) {t.Serialize(oStrm);}
 } // namespace CTuningS11n
 
 using namespace CTuningS11n;
 
 
-CTuningCollection::CTuningCollection(const std::string& name) : m_Name(name), m_EditMask(EM_ALLOWALL)
-//---------------------------------------------------------------------------------------------------
-{
-	if(m_Name.size() > GetNameLengthMax()) m_Name.resize(GetNameLengthMax());
-}
-
-
-CTuningCollection::~CTuningCollection()
-//-------------------------------------
+static void ReadTuning(std::istream& iStrm, CTuningCollection& Tc, const size_t)
 {
-	for(TITER i = m_Tunings.begin(); i != m_Tunings.end(); i++)
-	{
-		delete *i;
-	}
-	m_Tunings.clear();
-
-	for(TITER i = m_DeletedTunings.begin(); i != m_DeletedTunings.end(); i++)
-	{
-		delete *i;
-	}
-	m_DeletedTunings.clear();
+	Tc.AddTuning(iStrm);
 }
 
-CTuning* CTuningCollection::FindTuning(const std::string& name) const
-//-------------------------------------------------------------------
+static void WriteTuning(std::ostream& oStrm, const CTuning& t)
 {
-	for(size_t i = 0; i<m_Tunings.size(); i++)
-	{
-		if(m_Tunings[i]->GetName() == name) return m_Tunings[i];
-	}
-	return NULL;
-}
-
-size_t CTuningCollection::FindTuning(const CTuning* const pT) const
-//-----------------------------------------------------------------
-{
-	CTITER citer = find(m_Tunings.begin(), m_Tunings.end(), pT);
-		return citer - m_Tunings.begin();
+	t.Serialize(oStrm);
 }
 
 
 CTuning* CTuningCollection::GetTuning(const std::string& name)
-//------------------------------------------------------------
 {
-	return FindTuning(name);
+	for(std::size_t i = 0; i<m_Tunings.size(); i++)
+	{
+		if(m_Tunings[i]->GetName() == name)
+		{
+			return m_Tunings[i].get();
+		}
+	}
+	return nullptr;
 }
 
 const CTuning* CTuningCollection::GetTuning(const std::string& name) const
-//------------------------------------------------------------------------
 {
-	return FindTuning(name);
+	for(std::size_t i = 0; i<m_Tunings.size(); i++)
+	{
+		if(m_Tunings[i]->GetName() == name)
+		{
+			return m_Tunings[i].get();
+		}
+	}
+	return nullptr;
 }
 
 
-CTuningCollection::SERIALIZATION_RETURN_TYPE CTuningCollection::Serialize(std::ostream& oStrm) const
-//--------------------------------------------------------------------------------------------------
+Tuning::SerializationResult CTuningCollection::Serialize(std::ostream& oStrm, const std::string &name) const
 {
 	srlztn::SsbWrite ssb(oStrm);
-	ssb.BeginWrite("TC", s_SerializationVersion);
-	ssb.WriteItem(m_Name, "0", &WriteStr);
-	ssb.WriteItem(m_EditMask, "1");
+	ssb.BeginWrite("TC", 3); // version
+	ssb.WriteItem(name, "0", &WriteStr);
+	uint16 dummyEditMask = 0xffff;
+	ssb.WriteItem(dummyEditMask, "1");
 
 	const size_t tcount = m_Tunings.size();
 	for(size_t i = 0; i<tcount; i++)
@@ -118,117 +93,75 @@ CTuningCollection::SERIALIZATION_RETURN_TYPE CTuningCollection::Serialize(std::o
 	ssb.FinishWrite();
 		
 	if(ssb.GetStatus() & srlztn::SNT_FAILURE)
-		return true;
+		return Tuning::SerializationResult::Failure;
 	else
-		return false;
+		return Tuning::SerializationResult::Success;
 }
 
 
-#ifndef MODPLUG_NO_FILESAVE
-
-CTuningCollection::SERIALIZATION_RETURN_TYPE CTuningCollection::Serialize() const
-//-------------------------------------------------------------------------------
-{
-	if(m_SavefilePath.empty())
-		return SERIALIZATION_FAILURE;
-	mpt::ofstream fout(m_SavefilePath, std::ios::binary);
-	if(!fout.good())
-		return SERIALIZATION_FAILURE;
-
-	if(Serialize(fout) == SERIALIZATION_FAILURE)
-		return SERIALIZATION_FAILURE;
-
-	return SERIALIZATION_SUCCESS;
-}
-
-CTuningCollection::SERIALIZATION_RETURN_TYPE CTuningCollection::Deserialize()
-//---------------------------------------------------------------------------
-{
-	if(m_SavefilePath.empty())
-		return SERIALIZATION_FAILURE;
-	mpt::ifstream fin(m_SavefilePath, std::ios::binary);
-	if(!fin.good())
-		return SERIALIZATION_FAILURE;
-
-	if(Deserialize(fin) == SERIALIZATION_FAILURE)
-		return SERIALIZATION_FAILURE;
-
-	return SERIALIZATION_SUCCESS;
-}
-
-#endif // MODPLUG_NO_FILESAVE
-
-
-CTuningCollection::SERIALIZATION_RETURN_TYPE CTuningCollection::Deserialize(std::istream& iStrm)
-//----------------------------------------------------------------------------------------------
+Tuning::SerializationResult CTuningCollection::Deserialize(std::istream& iStrm, std::string &name)
 {
 	std::istream::pos_type startpos = iStrm.tellg();
-	bool oldLoadingSuccess = false;
+	
+	const Tuning::SerializationResult oldLoadingResult = DeserializeOLD(iStrm, name);
 
-	if(DeserializeOLD(iStrm, oldLoadingSuccess))
+	if(oldLoadingResult == Tuning::SerializationResult::NoMagic)
 	{	// An old version was not recognised - trying new version.
 		iStrm.clear();
 		iStrm.seekg(startpos);
 		srlztn::SsbRead ssb(iStrm);
-		ssb.BeginRead("TC", s_SerializationVersion);
+		ssb.BeginRead("TC", 3); // version
 
 		const srlztn::SsbRead::ReadIterator iterBeg = ssb.GetReadBegin();
 		const srlztn::SsbRead::ReadIterator iterEnd = ssb.GetReadEnd();
 		for(srlztn::SsbRead::ReadIterator iter = iterBeg; iter != iterEnd; iter++)
 		{
+			uint16 dummyEditMask = 0xffff;
 			if (ssb.CompareId(iter, "0") == srlztn::SsbRead::IdMatch)
-				ssb.ReadIterItem(iter, m_Name, &ReadStr);
+				ssb.ReadIterItem(iter, name, &ReadStr);
 			else if (ssb.CompareId(iter, "1") == srlztn::SsbRead::IdMatch)
-				ssb.ReadIterItem(iter, m_EditMask);
+				ssb.ReadIterItem(iter, dummyEditMask);
 			else if (ssb.CompareId(iter, "2") == srlztn::SsbRead::IdMatch)
 				ssb.ReadIterItem(iter, *this, &ReadTuning);
 		}
 
 		if(ssb.GetStatus() & srlztn::SNT_FAILURE)
-			return true;
+			return Tuning::SerializationResult::Failure;
 		else
-			return false;
+			return Tuning::SerializationResult::Success;
 	}
 	else
 	{
-		if(oldLoadingSuccess)
-			return false;
-		else
-			return true;
+		return oldLoadingResult;
 	}
 }
 
-//Returns false if stream content was recognised to be right kind of file(by beginmarker),
-//else true, and sets bool parameter to true if loading was successful
-bool CTuningCollection::DeserializeOLD(std::istream& inStrm, bool& loadingSuccessful)
-//-----------------------------------------------------------------------------------
-{
-	//s_SerializationBeginMarker = 0x54435348;  //ascii of TCSH
-	//s_SerializationEndMarker = 0x54435346; //ascii of TCSF(TuningCollectionSerialisationFooter) in hex.
 
-	loadingSuccessful = false;
+Tuning::SerializationResult CTuningCollection::DeserializeOLD(std::istream& inStrm, std::string &name)
+{
 
 	//1. begin marker:
 	int32 beginMarker = 0;
 	mpt::IO::ReadIntLE<int32>(inStrm, beginMarker);
-	if(beginMarker != 0x54435348) return true;
+	if(beginMarker != MAGIC4BE('T','C','S','H'))
+		return Tuning::SerializationResult::NoMagic;
 
 	//2. version
 	int32 version = 0;
 	mpt::IO::ReadIntLE<int32>(inStrm, version);
 	if(version > 2 || version < 1)
-		return false;
+		return Tuning::SerializationResult::Failure;
 
 	//3. Name
 	if(version < 2)
 	{
-		if(!mpt::IO::ReadSizedStringLE<uint32>(inStrm, m_Name, 256))
-			return false;
+		if(!mpt::IO::ReadSizedStringLE<uint32>(inStrm, name, 256))
+			return Tuning::SerializationResult::Failure;
 	}
 	else
 	{
-		if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, m_Name))
-			return false;
+		if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, name))
+			return Tuning::SerializationResult::Failure;
 	}
 
 	//4. Editmask
@@ -237,136 +170,133 @@ bool CTuningCollection::DeserializeOLD(std::istream& inStrm, bool& loadingSucces
 	//Not assigning the value yet, for if it sets some property const,
 	//further loading might fail.
 
-    //5. Tunings
+	//5. Tunings
 	{
 		uint32 s = 0;
 		mpt::IO::ReadIntLE<uint32>(inStrm, s);
-		if(s > 50) return false;
+		if(s > 50)
+			return Tuning::SerializationResult::Failure;
 		for(size_t i = 0; i<s; i++)
 		{
 			if(AddTuning(inStrm))
-				return false;
+				return Tuning::SerializationResult::Failure;
 		}
 	}
 
 	//6. End marker
 	int32 endMarker = 0;
 	mpt::IO::ReadIntLE<int32>(inStrm, endMarker);
-	if(endMarker != 0x54435346) return false;
-
-	m_EditMask = em;
-
-	loadingSuccessful = true;
-
-	return false;
+	if(endMarker != MAGIC4BE('T','C','S','F'))
+		return Tuning::SerializationResult::Failure;
+	
+	return Tuning::SerializationResult::Success;
 }
 
 
 
-bool CTuningCollection::Remove(const CTuning* pT)
-//-----------------------------------------------
+bool CTuningCollection::Remove(const CTuning *pT)
 {
-	TITER iter = find(m_Tunings.begin(), m_Tunings.end(), pT);
-	if(iter != m_Tunings.end())
-		return Remove(iter);
-	else
-		return true;
-}
-
-bool CTuningCollection::Remove(TITER removable, bool moveToTrashBin)
-//------------------------------------------------------------------
-{
-	//Behavior:
-	//By default, moves tuning to carbage bin(m_DeletedTunings) so that
-	//it gets deleted in destructor. This way
-	//the tuning address remains valid until the destruction of the collection.
-	//Optinally only removing the pointer without deleting or moving
-	//it to trashbin(e.g. when transferring tuning to other collection)
-	if((m_EditMask & EM_REMOVE) != 0)
+	const auto it = std::find_if(m_Tunings.begin(), m_Tunings.end(),
+		[&] (const std::unique_ptr<CTuning> & upT) -> bool
+		{
+			return upT.get() == pT;
+		}
+		);
+	if(it == m_Tunings.end())
 	{
-		if(moveToTrashBin) m_DeletedTunings.push_back(*removable);
-		m_Tunings.erase(removable);
 		return false;
 	}
-	else
-		return true;
+	m_Tunings.erase(it);
+	return true;
 }
 
-bool CTuningCollection::Remove(const size_t i)
-//--------------------------------------------
+
+bool CTuningCollection::Remove(const std::size_t i)
 {
 	if(i >= m_Tunings.size())
-			return true;
-
-	return Remove(m_Tunings.begin()+i);
+	{
+		return false;
+	}
+	m_Tunings.erase(m_Tunings.begin() + i);
+	return true;
 }
 
 
-bool CTuningCollection::AddTuning(CTuning* const pT)
-//--------------------------------------------------
+bool CTuningCollection::AddTuning(CTuning *pT)
 {
-	if((m_EditMask & EM_ADD) == 0 || m_Tunings.size() >= s_nMaxTuningCount)
+	if(m_Tunings.size() >= s_nMaxTuningCount)
 		return true;
 
 	if(pT == NULL)
 		return true;
 
-	m_Tunings.push_back(pT);
+	m_Tunings.push_back(std::unique_ptr<CTuning>(pT));
 
 	return false;
 }
 
 
-bool CTuningCollection::AddTuning(std::istream& inStrm, const bool ignoreEditmask)
-//--------------------------------------------------------------------------------
+bool CTuningCollection::AddTuning(std::istream& inStrm)
 {
-	if((!ignoreEditmask && (m_EditMask & EM_ADD) == 0) || m_Tunings.size() >= s_nMaxTuningCount)
+	if(m_Tunings.size() >= s_nMaxTuningCount)
 		return true;
 
 	if(!inStrm.good()) return true;
 
-	CTuning* pT = CTuningRTI::DeserializeOLD(inStrm);
-	if(pT == 0) pT = CTuningRTI::Deserialize(inStrm);
+	CTuning* pT = CTuning::CreateDeserializeOLD(inStrm);
+	if(pT == 0) pT = CTuning::CreateDeserialize(inStrm);
 
 	if(pT == 0)
 		return true;
 	else
 	{
-		m_Tunings.push_back(pT);
+		m_Tunings.push_back(std::unique_ptr<CTuning>(pT));
 		return false;
 	}
 }
 
-//Static
-bool CTuningCollection::TransferTuning(CTuningCollection* pTCsrc, CTuningCollection* pTCdest, CTuning* pT)
-//--------------------------------------------------------------------------------------------------------
-{
-	if(pTCsrc == NULL || pTCdest == NULL || pT == NULL)
-		return true;
 
-	if(pTCsrc == pTCdest)
-		return true;
+#ifdef MODPLUG_TRACKER
 
-	size_t i = pTCsrc->FindTuning(pT);
-	if(i >= pTCsrc->m_Tunings.size()) //Tuning not found?
-		return true;
 
-	if(pTCdest->AddTuning(pTCsrc->m_Tunings[i]))
-		return true;
+bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString &prefix)
+{
+	bool error = false;
+	auto numberFmt = mpt::FormatSpec().Dec().FillNul().Width(1 + static_cast<int>(std::log10(tc.GetNumTunings())));
+	for(std::size_t i = 0; i < tc.GetNumTunings(); ++i)
+	{
+		const CTuning & tuning = tc.GetTuning(i);
+		mpt::PathString fn;
+		fn += prefix;
+		mpt::ustring tuningName = mpt::ToUnicode(mpt::CharsetLocale, tuning.GetName());
+		if(tuningName.empty())
+		{
+			tuningName = MPT_USTRING("untitled");
+		}
+		SanitizeFilename(tuningName);
+		fn += mpt::PathString::FromUnicode(mpt::format(MPT_USTRING("%1 - %2"))(numberFmt.ToWString(i + 1), tuningName));
+		fn += mpt::PathString::FromUTF8(CTuning::s_FileExtension);
+		if(fn.FileOrDirectoryExists())
+		{
+			error = true;
+		} else
+		{
+			mpt::ofstream fout(fn, std::ios::binary);
+			if(tuning.Serialize(fout) != Tuning::SerializationResult::Success)
+			{
+				error = true;
+			}
+			fout.close();
+		}
+	}
+	return !error;
+}
 
-	if(pTCsrc->Remove(pTCsrc->m_Tunings.begin()+i, false))
-		return true;
 
-	return false;
+#endif
 
-}
 
-std::string CTuningCollection::GetEditMaskString() const
-//------------------------------------------------------
-{
-	std::bitset<16> mask(m_EditMask);
-	return mask.to_string<char, std::char_traits<char>, std::allocator<char> >();
-}
+} // namespace Tuning
 
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/tuningbase.cpp b/soundlib/tuningbase.cpp
index b85d393..58428ac 100644
--- a/soundlib/tuningbase.cpp
+++ b/soundlib/tuningbase.cpp
@@ -10,9 +10,12 @@
 
 #include "stdafx.h"
 #include "tuningbase.h"
+#include "tuning.h"
 #include "../common/mptIO.h"
 #include "../common/serialization_utils.h"
 
+#include <cmath>
+
 #include <istream>
 #include <ostream>
 
@@ -20,25 +23,9 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-const char* CTuningBase::s_TuningDescriptionGeneral = "No ratio restrictions";
-
-
-const char* CTuningBase::s_TuningDescriptionGroupGeometric = "Ratio of ratios with distance of 'groupsize' is constant.";
-
-
-const char* CTuningBase::s_TuningDescriptionGeometric = "Ratio of successive ratios is constant.";
-
-
-const char* CTuningBase::s_TuningTypeStrGeneral = "\"General\"";
-
-
-const char* CTuningBase::s_TuningTypeStrGroupGeometric = "\"GroupGeometric\"";
+namespace Tuning {
 
 
-const char* CTuningBase::s_TuningTypeStrGeometric = "\"Geometric\"";
-
-
-const CTuningBase::SERIALIZATION_VERSION CTuningBase::s_SerializationVersion(5);
 /*
 Version history:
 	4->5: Lots of changes, finestep interpretation revamp, fileformat revamp.
@@ -48,240 +35,43 @@ Version history:
 
 
 
-const CTuningBase::SERIALIZATION_RETURN_TYPE CTuningBase::SERIALIZATION_SUCCESS = false;
-
-
-const CTuningBase::SERIALIZATION_RETURN_TYPE CTuningBase::SERIALIZATION_FAILURE = true;
-
-
-const char CTuningBase::s_FileExtension[5] = ".tun";
-
-
-const CTuningBase::EDITMASK CTuningBase::EM_RATIOS = 1; //1b
-
-const CTuningBase::EDITMASK CTuningBase::EM_NOTENAME = 1 << 1; //10b
-
-const CTuningBase::EDITMASK CTuningBase::EM_TYPE = 1 << 2; //100b
-
-const CTuningBase::EDITMASK CTuningBase::EM_NAME = 1 << 3; //1000b
-
-const CTuningBase::EDITMASK CTuningBase::EM_FINETUNE = 1 << 4; //10000b
-
-const CTuningBase::EDITMASK CTuningBase::EM_VALIDITYRANGE = 1 << 5; //100000b
-
-
-const CTuningBase::EDITMASK CTuningBase::EM_ALLOWALL = 0xFFFF; //All editing allowed.
-
-const CTuningBase::EDITMASK CTuningBase::EM_EDITMASK = 0x8000; //Whether to allow modifications to editmask.
-
-const CTuningBase::EDITMASK CTuningBase::EM_CONST = 0x8000;  //All editing except changing const status disable.
-
-const CTuningBase::EDITMASK CTuningBase::EM_CONST_STRICT = 0; //All bits are zero - even the const status can't be changed.
-
-
-
-const CTuningBase::TUNINGTYPE CTuningBase::TT_GENERAL = 0; //0...00b
-
-const CTuningBase::TUNINGTYPE CTuningBase::TT_GROUPGEOMETRIC = 1; //0...10b
-
-const CTuningBase::TUNINGTYPE CTuningBase::TT_GEOMETRIC = 3; //0...11b
-
-
-
-void CTuningBase::TuningCopy(CTuningBase& to, const CTuningBase& from, const bool allowExactnamecopy)
-//---------------------------------------------------------------------------------------------------
-{
-	if(!to.MayEdit(EM_ALLOWALL))
-		return;
-
-	if(allowExactnamecopy)
-		to.m_TuningName = from.m_TuningName;
-	else
-		to.m_TuningName = std::string("Copy of ") + from.m_TuningName;
-
-	to.m_NoteNameMap = from.m_NoteNameMap;
-	to.m_EditMask = from.m_EditMask;
-	to.m_EditMask |= EM_EDITMASK; //Not copying possible strict-const-status.
-
-	to.m_TuningType = from.m_TuningType;
-
-	//Copying ratios.
-	const VRPAIR rp = to.ProSetValidityRange(from.GetValidityRange());
-
-	//Copying ratios
-	for(NOTEINDEXTYPE i = rp.first; i<=rp.second; i++)
-	{
-		to.ProSetRatio(i, from.GetRatio(i));
-	}
-	to.ProSetGroupSize(from.GetGroupSize());
-	to.ProSetGroupRatio(from.GetGroupRatio());
-	to.ProSetFineStepCount(from.GetFineStepCount());
-}
-
-
-
-bool CTuningBase::SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r)
-//--------------------------------------------------------------------
-{
-	if(MayEdit(EM_RATIOS))
-	{
-		if(ProSetRatio(s, r))
-			return true;
-		else
-			SetType(TT_GENERAL);
-
-		return false;
-	}
-	return true;
+const char CTuningRTI::s_FileExtension[5] = ".tun";
 
-}
 
 
-CTuningBase::USTEPINDEXTYPE CTuningBase::SetFineStepCount(const USTEPINDEXTYPE& fs)
-//---------------------------------------------------------------------------------
+void CTuningRTI::SetNoteName(const NOTEINDEXTYPE& n, const std::string& str)
 {
-	VRPAIR vrp = GetValidityRange();
-
-	if( (vrp.first > vrp.second)
-		||
-		(!IsStepCountRangeSufficient(fs, vrp))
-		||
-		(!MayEdit(EM_FINETUNE))
-	  ) return GetFineStepCount();
-	else
-	{
-		ProSetFineStepCount(fs);
-		return GetFineStepCount();
-	}
-}
-
-
-CTuningBase::TUNINGTYPE CTuningBase::GetTuningType(const char* str)
-//-----------------------------------------------------------------
-{
-	if(!strcmp(str, s_TuningTypeStrGroupGeometric))
-		return TT_GROUPGEOMETRIC;
-	if(!strcmp(str, s_TuningTypeStrGeometric))
-		return TT_GEOMETRIC;
-
-	return TT_GENERAL;
-}
-
-
-std::string CTuningBase::GetTuningTypeStr(const TUNINGTYPE& tt)
-//-------------------------------------------------------------
-{
-	if(tt == TT_GENERAL)
-		return s_TuningTypeStrGeneral;
-	if(tt == TT_GROUPGEOMETRIC)
-		return s_TuningTypeStrGroupGeometric;
-	if(tt == TT_GEOMETRIC)
-		return s_TuningTypeStrGeometric;
-	return "Unknown";
-}
-
-
-
-
-CTuningBase::NOTESTR CTuningBase::GetNoteName(const NOTEINDEXTYPE& x, bool addOctave) const
-//-----------------------------------------------------------------------------------------
-{
-	if(!IsValidNote(x)) return "";
-	else return ProGetNoteName(x, addOctave);
-}
-
-
-CTuningBase::NOTESTR CTuningBase::ProGetNoteName(const NOTEINDEXTYPE& x, bool /*addOctave*/) const
-//------------------------------------------------------------------------------------------------
-{
-	NNM_CITER i = m_NoteNameMap.find(x);
-	if(i != m_NoteNameMap.end())
-		return i->second;
-	else
-		return mpt::ToString(x);
-}
-
-
-
-bool CTuningBase::IsOfType(const TUNINGTYPE& type) const
-//------------------------------------------------------
-{
-	if(type == TT_GENERAL)
-		return true;
-	//Using interpretation that every tuning is also
-	//a general tuning.
-
-	//Note: Here type != TT_GENERAL
-	if(m_TuningType == TT_GENERAL)
-		return false;
-	//Every non-general tuning should not include all tunings.
-
-	if( (m_TuningType & type) == type)
-		return true;
-	else
-		return false;
-}
-
-
-bool CTuningBase::SetNoteName(const NOTEINDEXTYPE& n, const std::string& str)
-//---------------------------------------------------------------------------
-{
-	if(MayEdit(EM_NOTENAME))
+	if(!str.empty())
 	{
 		m_NoteNameMap[n] = str;
-		return false;
-	}
-	return true;
-}
-
-
-
-
-bool CTuningBase::ClearNoteName(const NOTEINDEXTYPE& n, const bool eraseAll)
-//--------------------------------------------------------------------------
-{
-	if(MayEdit(EM_NOTENAME))
+	} else
 	{
-		if(eraseAll)
-		{
-			m_NoteNameMap.clear();
-			return false;
-		}
-
-		NNM_ITER iter = m_NoteNameMap.find(n);
+		const auto iter = m_NoteNameMap.find(n);
 		if(iter != m_NoteNameMap.end())
 		{
 			m_NoteNameMap.erase(iter);
-			return false;
 		}
-		else
-			return true;
 	}
-	return true;
 }
 
 
 
-bool CTuningBase::Multiply(const RATIOTYPE& r)
-//--------------------------------------------
+bool CTuningRTI::Multiply(const RATIOTYPE& r)
 {
-	if(r <= 0 || !MayEdit(EM_RATIOS))
+	if(r <= 0)
 		return true;
 
 	//Note: Multiplying ratios by constant doesn't
 	//change, e.g. 'geometricness' status.
-	VRPAIR vrp = GetValidityRange();
-	for(NOTEINDEXTYPE i = vrp.first; i<vrp.second; i++)
+	for(auto & ratio : m_RatioTable)
 	{
-		if(ProSetRatio(i, r*GetRatio(i)))
-			return true;
+		ratio *= r;
 	}
 	return false;
 }
 
 
-bool CTuningBase::CreateGroupGeometric(const NOTEINDEXTYPE& s, const RATIOTYPE& r, const NOTEINDEXTYPE& startindex)
-//-----------------------------------------------------------------------------------------------------------------
+bool CTuningRTI::CreateGroupGeometric(const NOTEINDEXTYPE& s, const RATIOTYPE& r, const NOTEINDEXTYPE& startindex)
 {
 	if(s < 1 || r <= 0 || startindex < GetValidityRange().first)
 		return true;
@@ -294,36 +84,28 @@ bool CTuningBase::CreateGroupGeometric(const NOTEINDEXTYPE& s, const RATIOTYPE&
 }
 
 
-bool CTuningBase::CreateGroupGeometric(const std::vector<RATIOTYPE>& v, const RATIOTYPE& r, const VRPAIR vr, const NOTEINDEXTYPE ratiostartpos)
-//---------------------------------------------------------------------------------------------------------------------------------------------
+bool CTuningRTI::CreateGroupGeometric(const std::vector<RATIOTYPE>& v, const RATIOTYPE& r, const VRPAIR vr, const NOTEINDEXTYPE ratiostartpos)
 {
-	if(MayEdit(EM_RATIOS) &&
-		(MayEdit(EM_TYPE) || GetType() == TT_GROUPGEOMETRIC))
 	{
 		if(vr.first > vr.second || v.size() == 0) return true;
 		if(ratiostartpos < vr.first || vr.second < ratiostartpos || static_cast<UNOTEINDEXTYPE>(vr.second - ratiostartpos) < static_cast<UNOTEINDEXTYPE>(v.size() - 1)) return true;
-		if(!IsStepCountRangeSufficient(GetFineStepCount(), vr)) return true;
+		if(GetFineStepCount() > FINESTEPCOUNT_MAX) return true;
 		for(size_t i = 0; i<v.size(); i++) {if(v[i] < 0) return true;}
 		if(ProCreateGroupGeometric(v,r, vr, ratiostartpos))
 			return true;
 		else
 		{
-			SetType(TT_GROUPGEOMETRIC);
-			ProSetFineStepCount(GetFineStepCount());
+			m_TuningType = TT_GROUPGEOMETRIC;
+			UpdateFineStepTable();
 			return false;
 		}
 	}
-	else
-		return true;
 }
 
 
 
-bool CTuningBase::CreateGeometric(const UNOTEINDEXTYPE& s, const RATIOTYPE& r, const VRPAIR vr)
-//---------------------------------------------------------------------------------------------
+bool CTuningRTI::CreateGeometric(const UNOTEINDEXTYPE& s, const RATIOTYPE& r, const VRPAIR vr)
 {
-	if(MayEdit(EM_RATIOS) &&
-	  (MayEdit(EM_TYPE) || GetType() == TT_GEOMETRIC))
 	{
 		if(vr.first > vr.second) return true;
 		if(s < 1 || r <= 0) return true;
@@ -331,22 +113,19 @@ bool CTuningBase::CreateGeometric(const UNOTEINDEXTYPE& s, const RATIOTYPE& r, c
 			return true;
 		else
 		{
-			SetType(TT_GEOMETRIC);
-			ProSetFineStepCount(GetFineStepCount());
+			m_TuningType = TT_GEOMETRIC;
+			UpdateFineStepTable();
 			return false;
 		}
 	}
-	else
-		return true;
 }
 
 
 
 
-bool CTuningBase::ChangeGroupsize(const NOTEINDEXTYPE& s)
-//-------------------------------------------------------
+bool CTuningRTI::ChangeGroupsize(const NOTEINDEXTYPE& s)
 {
-	if(!MayEdit(EM_RATIOS) || s < 1)
+	if(s < 1)
 		return true;
 
 	if(m_TuningType == TT_GROUPGEOMETRIC)
@@ -360,10 +139,9 @@ bool CTuningBase::ChangeGroupsize(const NOTEINDEXTYPE& s)
 
 
 
-bool CTuningBase::ChangeGroupRatio(const RATIOTYPE& r)
-//----------------------------------------------------
+bool CTuningRTI::ChangeGroupRatio(const RATIOTYPE& r)
 {
-	if(!MayEdit(EM_RATIOS) || r <= 0)
+	if(r <= 0)
 		return true;
 
 	if(m_TuningType == TT_GROUPGEOMETRIC)
@@ -376,104 +154,7 @@ bool CTuningBase::ChangeGroupRatio(const RATIOTYPE& r)
 }
 
 
-
-const char* CTuningBase::GetTuningTypeDescription(const TUNINGTYPE& type)
-//-----------------------------------------------------------------------
-{
-	if(type == TT_GENERAL)
-		return s_TuningDescriptionGeneral;
-	if(type == TT_GROUPGEOMETRIC)
-		return s_TuningDescriptionGroupGeometric;
-	if(type == TT_GEOMETRIC)
-		return s_TuningDescriptionGeometric;
-	return "Unknown";
-}
-
-
-CTuningBase::VRPAIR CTuningBase::SetValidityRange(const VRPAIR& vrp)
-//------------------------------------------------------------------
-{
-	if(vrp.second < vrp.first) return GetValidityRange();
-	if(IsStepCountRangeSufficient(GetFineStepCount(), vrp)
-		&&
-		MayEdit(EM_VALIDITYRANGE)
-	   )
-		return ProSetValidityRange(vrp);
-	else
-		return GetValidityRange();
-}
-
-
-
-bool CTuningBase::SetType(const TUNINGTYPE& tt)
-//---------------------------------------------
-{
-	//Note: This doesn't check whether the tuning ratios
-	//are consistent with given type.
-	if(MayEdit(EM_TYPE))
-	{
-		m_TuningType = tt;
-
-		if(m_TuningType == TT_GENERAL)
-		{
-			ProSetGroupSize(0);
-			ProSetGroupRatio(0);
-		}
-
-		return false;
-	}
-	else
-		return true;
-}
-
-
-
-bool CTuningBase::DeserializeOLD(std::istream& inStrm)
-//----------------------------------------------------
-{
-	char begin[8];
-	int16 version;
-
-	inStrm.read(begin, sizeof(begin));
-	if(memcmp(begin, "CT<sfs>B", 8)) return SERIALIZATION_FAILURE;
-
-	inStrm.read(reinterpret_cast<char*>(&version), sizeof(version));
-	if(version != 4) return SERIALIZATION_FAILURE;
-
-	//Tuning name
-	if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, m_TuningName))
-		return SERIALIZATION_FAILURE;
-
-	//Const mask
-	int16 em = 0;
-	inStrm.read(reinterpret_cast<char*>(&em), sizeof(em));
-	m_EditMask = em;
-
-	//Tuning type
-	int16 tt = 0;
-	inStrm.read(reinterpret_cast<char*>(&tt), sizeof(tt));
-	m_TuningType = tt;
-
-	//Notemap
-	UNOTEINDEXTYPE size;
-	inStrm.read(reinterpret_cast<char*>(&size), sizeof(size));
-	for(size_t i = 0; i<size; i++)
-	{
-		NOTEINDEXTYPE n;
-		std::string str;
-		inStrm.read(reinterpret_cast<char*>(&n), sizeof(n));
-		if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, str))
-			return SERIALIZATION_FAILURE;
-		m_NoteNameMap[n] = str;
-	}
-
-	//End marker
-	char end[8];
-	inStrm.read(end, sizeof(end));
-	if(memcmp(end, "CT<sfs>E", 8)) return SERIALIZATION_FAILURE;
-
-	return SERIALIZATION_SUCCESS;
-}
+} // namespace Tuning
 
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/tuningbase.h b/soundlib/tuningbase.h
index fcbc56a..7a94be1 100644
--- a/soundlib/tuningbase.h
+++ b/soundlib/tuningbase.h
@@ -11,11 +11,6 @@
 #pragma once
 
 
-#include <string>
-#include <vector>
-#include <cmath>
-#include <iosfwd>
-#include <map>
 #include <limits>
 #include "../common/typedefs.h"
 
@@ -23,13 +18,16 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-namespace srlztn {class Ssb;}
+namespace Tuning {
+
+
+enum class SerializationResult : int {
+	Success = 1,
+	NoMagic = 0,
+	Failure = -1
+};
 
 
-//Tuning baseclass; basic functionality is to map note to ratio.
-class CTuningBase
-//===============
-{
 	//NOTEINDEXTYPE: Some signed integer-type.
 	//UNOTEINDEXTYPE: Unsigned NOTEINDEXTYPE
 	//RATIOTYPE: Some 'real figure' type able to present ratios.
@@ -38,243 +36,21 @@ class CTuningBase
 			//same as differences in NOTEINDEXTYPE. In a way similar to ticks and rows in pattern -
 			//ticks <-> STEPINDEX, rows <-> NOTEINDEX
 
-public:
-//BEGIN TYPEDEFS:
 	typedef int16 NOTEINDEXTYPE;
 	typedef uint16 UNOTEINDEXTYPE;
 	typedef float32 RATIOTYPE; //If changing RATIOTYPE, serialization methods may need modifications.
 	typedef int32 STEPINDEXTYPE;
 	typedef uint32 USTEPINDEXTYPE;
-	typedef void (*MESSAGEHANDLER)(const char*, const char*);
 
-	typedef int16 SERIALIZATION_VERSION;
-	typedef bool SERIALIZATION_RETURN_TYPE;
-
-	//Validity Range PAIR.
 	typedef std::pair<NOTEINDEXTYPE, NOTEINDEXTYPE> VRPAIR;
 
-	typedef uint16 EDITMASK;
-
 	typedef uint16 TUNINGTYPE;
 
-	typedef std::string NOTESTR;
-	typedef std::map<NOTEINDEXTYPE, NOTESTR> NOTENAMEMAP;
-	typedef NOTENAMEMAP::iterator NNM_ITER;
-	typedef NOTENAMEMAP::const_iterator NNM_CITER;
-
-//END TYPEDEFS
-
-
-//BEGIN PUBLIC STATICS
-	static const SERIALIZATION_VERSION s_SerializationVersion;
-
-	static const SERIALIZATION_RETURN_TYPE SERIALIZATION_SUCCESS;
-	static const SERIALIZATION_RETURN_TYPE SERIALIZATION_FAILURE;
-
-	static const char s_FileExtension[5];
-
-	static const EDITMASK EM_RATIOS;
-	static const EDITMASK EM_NOTENAME;
-	static const EDITMASK EM_TYPE;
-	static const EDITMASK EM_NAME;
-	static const EDITMASK EM_FINETUNE;
-	static const EDITMASK EM_EDITMASK;
-	static const EDITMASK EM_VALIDITYRANGE;
-
-	static const EDITMASK EM_ALLOWALL;
-	static const EDITMASK EM_CONST;
-	static const EDITMASK EM_CONST_STRICT; //This won't allow even changing const status
-	//NOTE: When adding editmasks, check definition of EDITMASK -
-	//might need to be modified.
-
-	static const TUNINGTYPE TT_GENERAL;
-	static const TUNINGTYPE TT_GROUPGEOMETRIC;
-	static const TUNINGTYPE TT_GEOMETRIC;
-
-//END PUBLIC STATICS
-
-
-public:
-//BEGIN TUNING INTERFACE
-
-	//To return ratio of certain note.
-	virtual RATIOTYPE GetRatio(const NOTEINDEXTYPE&) const {return 0;}
-
-	//To return ratio from a 'step'(noteindex + stepindex)
-	virtual RATIOTYPE GetRatio(const NOTEINDEXTYPE& s, const STEPINDEXTYPE&) const {return GetRatio(s);}
-
-	//To return (fine)stepcount between two consecutive mainsteps.
-	virtual USTEPINDEXTYPE GetFineStepCount() const {return m_FineStepCount;}
-
-	//To return 'directed distance' between given notes.
-	virtual STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE& /*from*/, const NOTEINDEXTYPE& /*to*/) const {return 0;}
-
-	//To return 'directed distance' between given steps.
-	virtual STEPINDEXTYPE GetStepDistance(const NOTEINDEXTYPE&, const STEPINDEXTYPE&, const NOTEINDEXTYPE&, const STEPINDEXTYPE&) const {return 0;}
-
-
-	//To set finestepcount between two consecutive mainsteps and
-	//return GetFineStepCount(). This might not be the same as
-	//parameter fs if something fails. Finestep count == 0 means that
-	//stepdistances become the same as note distances.
-	USTEPINDEXTYPE SetFineStepCount(const USTEPINDEXTYPE& fs);
-
-	//Multiply all ratios by given number.
-	virtual bool Multiply(const RATIOTYPE&);
-
-	//Create GroupGeometric tuning of *this using virtual ProCreateGroupGeometric.
-	bool CreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR vr, const NOTEINDEXTYPE ratiostartpos);
-
-	//Create GroupGeometric of *this using ratios from 'itself' and ratios starting from
-	//position given as third argument.
-	bool CreateGroupGeometric(const NOTEINDEXTYPE&, const RATIOTYPE&, const NOTEINDEXTYPE&);
-
-	//Create geometric tuning of *this using ratio(0) = 1.
-	bool CreateGeometric(const UNOTEINDEXTYPE& p, const RATIOTYPE& r) {return CreateGeometric(p,r,GetValidityRange());}
-	bool CreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR vr);
-
-	virtual SERIALIZATION_RETURN_TYPE Serialize(std::ostream& /*out*/) const {return false;}
-
-	NOTESTR GetNoteName(const NOTEINDEXTYPE& x, bool addOctave = true) const;
-
-	void SetName(const std::string& s);
-
-	std::string GetName() const {return m_TuningName;}
-
-	bool SetNoteName(const NOTEINDEXTYPE&, const std::string&);
-
-	bool ClearNoteName(const NOTEINDEXTYPE& n, const bool clearAll = false);
-
-	bool SetRatio(const NOTEINDEXTYPE& s, const RATIOTYPE& r);
-
-	TUNINGTYPE GetTuningType() const {return m_TuningType;}
-
-	static std::string GetTuningTypeStr(const TUNINGTYPE& tt);
-	static TUNINGTYPE GetTuningType(const char* str);
-
-	bool IsOfType(const TUNINGTYPE& type) const;
-
-	bool ChangeGroupsize(const NOTEINDEXTYPE&);
-	bool ChangeGroupRatio(const RATIOTYPE&);
-
-	static uint32 GetVersion() {return s_SerializationVersion;}
-
-	virtual UNOTEINDEXTYPE GetGroupSize() const {return 0;}
-	virtual RATIOTYPE GetGroupRatio() const {return 0;}
 
+// Derived from old IsStepCountRangeSufficient(), this is actually a more
+// sensible value than what was calculated in earlier versions.
+static MPT_CONSTEXPR11_VAR STEPINDEXTYPE FINESTEPCOUNT_MAX = 0xffff;
 
-	//Tuning might not be valid for arbitrarily large range,
-	//so this can be used to ask where it is valid. Tells the lowest and highest
-	//note that are valid.
-	virtual VRPAIR GetValidityRange() const {return VRPAIR(0,0);}
-
-
-	//To try to set validity range to given range; returns
-	//the range valid after trying to set the new range.
-	VRPAIR SetValidityRange(const VRPAIR& vrp);
-
-	//Return true if note is within validity range - false otherwise.
-	bool IsValidNote(const NOTEINDEXTYPE n) const {return (n >= GetValidityRange().first && n <= GetValidityRange().second);}
-
-	//Checking that step distances can be presented with
-	//value range of STEPINDEXTYPE with given finestepcount and validityrange.
-	bool IsStepCountRangeSufficient(USTEPINDEXTYPE fs, VRPAIR vrp);
-
-	virtual const char* GetTuningTypeDescription() const;
-
-	static const char* GetTuningTypeDescription(const TUNINGTYPE&);
-
-	bool MayEdit(const EDITMASK& em) const {return (em & m_EditMask) != 0;}
-
-	bool SetEditMask(const EDITMASK& em);
-
-	EDITMASK GetEditMask() const {return m_EditMask;}
-
-	bool DeserializeOLD(std::istream&);
-
-	virtual ~CTuningBase() {};
-
-//END TUNING INTERFACE
-
-//BEGIN PROTECTED VIRTUALS
-protected:
-	//Return value: true if change was not done, and false otherwise, in case which
-	//tuningtype is automatically changed to general.
-	virtual bool ProSetRatio(const NOTEINDEXTYPE&, const RATIOTYPE&) {return true;}
-
-	virtual NOTESTR ProGetNoteName(const NOTEINDEXTYPE&, bool) const;
-
-	//The two methods below return false if action was done, true otherwise.
-	virtual bool ProCreateGroupGeometric(const std::vector<RATIOTYPE>&, const RATIOTYPE&, const VRPAIR&, const NOTEINDEXTYPE /*ratiostartpos*/) {return true;}
-	virtual bool ProCreateGeometric(const UNOTEINDEXTYPE&, const RATIOTYPE&, const VRPAIR&) {return true;}
-
-	virtual VRPAIR ProSetValidityRange(const VRPAIR&) {return GetValidityRange();}
-
-	virtual void ProSetFineStepCount(const USTEPINDEXTYPE&) {}
-
-	virtual NOTEINDEXTYPE ProSetGroupSize(const UNOTEINDEXTYPE&) {return 0;}
-	virtual RATIOTYPE ProSetGroupRatio(const RATIOTYPE&) {return 0;}
-
-	virtual uint32 GetClassVersion() const = 0;
-
-//END PROTECTED VIRTUALS
-
-
-
-//PROTECTED INTERFACE
-protected:
-	static void TuningCopy(CTuningBase& to, const CTuningBase& from, const bool allowExactnamecopy = false);
-
-	TUNINGTYPE GetType() const {return m_TuningType;}
-
-	//Return true if data loading failed, false otherwise.
-	virtual bool ProProcessUnserializationdata(UNOTEINDEXTYPE ratiotableSize) = 0;
-
-
-//END PROTECTED INTERFACE
-
-
-//BEGIN PRIVATE METHODS
-private:
-	bool SetType(const TUNINGTYPE& tt);
-//END PRIVATE METHODS
-
-
-//BEGIN: DATA MEMBERS
-protected:
-	std::string m_TuningName;
-	EDITMASK m_EditMask; //Behavior: true <~> allow modification
-	TUNINGTYPE m_TuningType;
-	NOTENAMEMAP m_NoteNameMap;
-	USTEPINDEXTYPE m_FineStepCount;
-	//NOTE: If adding new members, TuningCopy might need to be modified.
-
-//END DATA MEMBERS
-
-protected:
-	CTuningBase(const std::string name = "Unnamed") :
-		m_TuningName(name),
-		m_EditMask(uint16_max), //All bits to true - allow all by default.
-		m_TuningType(TT_GENERAL), //Unspecific tuning by default.
-		m_FineStepCount(0)
-		{}
-private:
-	CTuningBase(CTuningBase&) {}
-	CTuningBase& operator=(const CTuningBase&) {return *this;}
-	static void ReadNotenamemapPair(std::istream& iStrm, NOTENAMEMAP::value_type& val, const size_t);
-	static void WriteNotenamemappair(std::ostream& oStrm, const NOTENAMEMAP::value_type& val, const size_t);
-
-public:
-	static const char* s_TuningDescriptionGeneral;
-	static const char* s_TuningDescriptionGroupGeometric;
-	static const char* s_TuningDescriptionGeometric;
-	static const char* s_TuningTypeStrGeneral;
-	static const char* s_TuningTypeStrGroupGeometric;
-	static const char* s_TuningTypeStrGeometric;
-
-private:
-	static void DefaultMessageHandler(const char*, const char*) {}
-};
 
 #define NOTEINDEXTYPE_MIN (std::numeric_limits<NOTEINDEXTYPE>::min)()
 #define NOTEINDEXTYPE_MAX (std::numeric_limits<NOTEINDEXTYPE>::max)()
@@ -284,42 +60,14 @@ private:
 #define USTEPINDEXTYPE_MAX (std::numeric_limits<USTEPINDEXTYPE>::max)()
 
 
-
-inline const char* CTuningBase::GetTuningTypeDescription() const
-//----------------------------------------------------------------------
-{
-	return GetTuningTypeDescription(GetType());
-}
-
-
-inline void CTuningBase::SetName(const std::string& s)
-//-----------------------------------------------
-{
-	if(MayEdit(EM_NAME)) m_TuningName = s;
-}
+class CTuningRTI;
+typedef CTuningRTI CTuning;
 
 
-inline bool CTuningBase::IsStepCountRangeSufficient(USTEPINDEXTYPE fs, VRPAIR vrp)
-//--------------------------------------------------------------------------------
-{
-	{ // avoid integer overload
-		//if(vrp.first == STEPINDEXTYPE_MIN && vrp.second == STEPINDEXTYPE_MAX) return true;
-		MPT_ASSERT(NOTEINDEXTYPE_MIN / 2 < vrp.first && vrp.second < NOTEINDEXTYPE_MAX / 2);
-		if(NOTEINDEXTYPE_MIN / 2 >= vrp.first || vrp.second >= NOTEINDEXTYPE_MAX / 2) return true;
-	}
-	if(fs > static_cast<USTEPINDEXTYPE>(STEPINDEXTYPE_MAX) / (vrp.second - vrp.first + 1)) return false;
-	else return true;
-}
+} // namespace Tuning
 
 
-inline bool CTuningBase::SetEditMask(const EDITMASK& em)
-//------------------------------------------------------
-{
-	if(MayEdit(EM_EDITMASK))
-		{m_EditMask = em; return false;}
-	else
-		return true;
-}
+typedef Tuning::CTuning CTuning;
 
 
 OPENMPT_NAMESPACE_END
diff --git a/soundlib/tuningcollection.h b/soundlib/tuningcollection.h
index 69d65bc..7e4b4ff 100644
--- a/soundlib/tuningcollection.h
+++ b/soundlib/tuningcollection.h
@@ -18,147 +18,68 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-class CTuningCollection;
-
-namespace CTuningS11n
-{
-	void ReadTuning(std::istream& iStrm, CTuningCollection& Tc, const size_t);
-	void WriteTuning(std::ostream& oStrm, const CTuning& t);
-}
+namespace Tuning {
 
 
-//=====================
-class CTuningCollection //To contain tuning objects.
-//=====================
+class CTuningCollection
 {
-	friend class CTuningstreamer;
-public:
-
-//BEGIN TYPEDEFS
-	typedef uint16 EDITMASK;
-	//If changing this, see whether serialization should be 
-	//modified as well.
-
-	typedef std::vector<CTuning*> TUNINGVECTOR;
-	typedef TUNINGVECTOR::iterator TITER; //Tuning ITERator.
-	typedef TUNINGVECTOR::const_iterator CTITER;
-
-	typedef uint16 SERIALIZATION_VERSION;
-
-	typedef bool SERIALIZATION_RETURN_TYPE;
 
-//END TYPEDEFS
-
-//BEGIN PUBLIC STATIC CONSTS
 public:
-	enum 
-	{
-		EM_ADD = 1, //true <~> allowed
-		EM_REMOVE = 2,
-		EM_ALLOWALL = 0xffff,
-		EM_CONST = 0,
-
-	    s_SerializationVersion = 3,
-
-		SERIALIZATION_SUCCESS = false,
-		SERIALIZATION_FAILURE = true
-	};
 
 	static const char s_FileExtension[4];
-	static const size_t s_nMaxTuningCount = 255;
 
-//END PUBLIC STATIC CONSTS
+	// OpenMPT <= 1.26 had to following limits:
+	//  *  255 built-in tunings (only 2 were ever actually provided)
+	//  *  255 local tunings
+	//  *  255 tune-specific tunings
+	// As 1.27 copies all used tunings into the module, the limit of 255 is no
+	// longer sufficient. In the worst case scenario, the module contains 255
+	// unused tunings and uses 255 local ones. In addition to that, allow the
+	// user to additionally import both built-in tunings.
+	// Older OpenMPT versions will silently skip loading tunings beyond index
+	// 255.
+	static const size_t s_nMaxTuningCount = 255 + 255 + 2;
 
-//BEGIN INTERFACE:
 public:
-	CTuningCollection(const std::string& name = "");
-	~CTuningCollection();
-	
+
 	//Note: Given pointer is deleted by CTuningCollection
 	//at some point.
-	bool AddTuning(CTuning* const pT);
-	bool AddTuning(std::istream& inStrm) {return AddTuning(inStrm, false);}
+	bool AddTuning(CTuning *pT);
+	bool AddTuning(std::istream& inStrm);
 	
-	bool Remove(const size_t i);
-	bool Remove(const CTuning*);
-
-	bool CanEdit(const EDITMASK& em) const {return (m_EditMask & em) != 0;}
-
-	void SetConstStatus(const EDITMASK& em) {m_EditMask = em;}
+	bool Remove(const std::size_t i);
+	bool Remove(const CTuning *pT);
 
-	const EDITMASK& GetEditMask() const {return m_EditMask;}
-
-	std::string GetEditMaskString() const;
-
-	CTuning& GetTuning(size_t i) {return *m_Tunings.at(i);}
-	const CTuning& GetTuning(size_t i) const {return *m_Tunings.at(i);}
+	CTuning& GetTuning(size_t i) {return *m_Tunings.at(i).get();}
+	const CTuning& GetTuning(size_t i) const {return *m_Tunings.at(i).get();}
 	CTuning* GetTuning(const std::string& name);
 	const CTuning* GetTuning(const std::string& name) const;
 
 	size_t GetNumTunings() const {return m_Tunings.size();}
 
-	std::string GetName() const {return m_Name;}
-
-#ifndef MODPLUG_NO_FILESAVE
-	void SetSavefilePath(const mpt::PathString &psz) {m_SavefilePath = psz;}
-	mpt::PathString GetSaveFilePath() const {return m_SavefilePath;}
-#endif // MODPLUG_NO_FILESAVE
-
-	std::string GetVersionString() const {return mpt::ToString(static_cast<int>(s_SerializationVersion));}
+	Tuning::SerializationResult Serialize(std::ostream&, const std::string &name) const;
+	Tuning::SerializationResult Deserialize(std::istream&, std::string &name);
 
-	size_t GetNameLengthMax() const {return 256;}
-
-	//Serialization/unserialisation
-	bool Serialize(std::ostream&) const;
-	bool Deserialize(std::istream&);
-#ifndef MODPLUG_NO_FILESAVE
-	bool Serialize() const;
-	bool Deserialize();
-#endif // MODPLUG_NO_FILESAVE
-
-	//Transfer tuning pT from pTCsrc to pTCdest
-	static bool TransferTuning(CTuningCollection* pTCsrc, CTuningCollection* pTCdest, CTuning* pT);
-	
+private:
 
-//END INTERFACE
-	
+	std::vector<std::unique_ptr<CTuning> > m_Tunings;
 
-//BEGIN: DATA MEMBERS
 private:
-	//BEGIN: SERIALIZABLE DATA MEMBERS
-	TUNINGVECTOR m_Tunings; //The actual tuningobjects are stored as deletable pointers here.
-	std::string m_Name;
-	EDITMASK m_EditMask;
-	//END: SERIALIZABLE DATA MEMBERS
-
-	//BEGIN: NONSERIALIZABLE DATA MEMBERS
-	TUNINGVECTOR m_DeletedTunings; //See Remove()-method for explanation of this.
-#ifndef MODPLUG_NO_FILESAVE
-	mpt::PathString m_SavefilePath;
-#endif // MODPLUG_NO_FILESAVE
-	//END: NONSERIALIZABLE DATA MEMBERS
-	
-//END: DATA MEMBERS
 
-	friend void CTuningS11n::ReadTuning(std::istream& iStrm, CTuningCollection& Tc, const size_t);
+	Tuning::SerializationResult DeserializeOLD(std::istream&, std::string &name);
 
-//BEGIN PRIVATE METHODS
-private:
-	CTuning* FindTuning(const std::string& name) const;
-	size_t FindTuning(const CTuning* const) const;
+};
 
-	bool AddTuning(std::istream& inStrm, const bool ignoreEditmask);
 
-	bool Remove(TITER removable, bool moveToTrashBin = true);
+#ifdef MODPLUG_TRACKER
+bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString &prefix);
+#endif
 
-	//Hiding default operators because default meaning might not work right.
-	CTuningCollection& operator=(const CTuningCollection&) {return *this;}
-	CTuningCollection(const CTuningCollection&) {}
 
-	bool DeserializeOLD(std::istream&, bool& loadingSuccessful);
+} // namespace Tuning
 
-//END PRIVATE METHODS.
-};
+
+typedef Tuning::CTuningCollection CTuningCollection;
 
 
 OPENMPT_NAMESPACE_END
diff --git a/test/TestToolsLib.cpp b/test/TestToolsLib.cpp
index c9097c7..2ce811b 100644
--- a/test/TestToolsLib.cpp
+++ b/test/TestToolsLib.cpp
@@ -65,7 +65,7 @@ Testcase::Testcase(Fatality fatality, Verbosity verbosity, const char * const de
 
 std::string Testcase::AsString() const
 {
-	return mpt::String::Print("%1(%2): %3", context.file, context.line, remove_newlines(desc));
+	return mpt::format(std::string("%1(%2): %3"))(context.file, context.line, remove_newlines(desc));
 }
 
 
@@ -196,7 +196,6 @@ void Testcase::ReportException()
 #if defined(MPT_ASSERT_HANDLER_NEEDED)
 
 MPT_NOINLINE void AssertHandler(const char *file, int line, const char *function, const char *expr, const char *msg)
-//------------------------------------------------------------------------------------------------------------------
 {
 	Test::fail_count++;
 	if(msg)
diff --git a/test/TestToolsLib.h b/test/TestToolsLib.h
index 7097d94..bbac760 100644
--- a/test/TestToolsLib.h
+++ b/test/TestToolsLib.h
@@ -16,7 +16,12 @@
 #ifndef MODPLUG_TRACKER
 
 
+//#define MPT_TEST_CXX11
+
+
+#include "../common/Endianness.h"
 #include "../common/FlagSet.h"
+#include "../soundlib/Snd_defs.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
@@ -69,7 +74,18 @@ struct ToStringHelper
 {
 	std::string operator () (const T &x)
 	{
-		return mpt::ToString(x);
+		return mpt::fmt::val(x);
+	}
+};
+
+#ifdef MPT_TEST_CXX11
+
+template<>
+struct ToStringHelper<mpt::endian_type>
+{
+	std::string operator () (const mpt::endian_type &x)
+	{
+		return mpt::fmt::val(x.value);
 	}
 };
 
@@ -78,23 +94,62 @@ struct ToStringHelper<FlagSet<enum_t, store_t> >
 {
 	std::string operator () (const FlagSet<enum_t, store_t> &x)
 	{
-		return mpt::ToString(x.GetRaw());
+		return mpt::fmt::val(x.GetRaw());
+	}
+};
+
+template<typename enum_t>
+struct ToStringHelper<enum_value_type<enum_t> >
+{
+	std::string operator () (const enum_value_type<enum_t> &x)
+	{
+		return mpt::fmt::val(x.as_bits());
+	}
+};
+
+template<typename Ta, typename Tb>
+struct ToStringHelper<std::pair<Ta, Tb> >
+{
+	std::string operator () (const std::pair<Ta, Tb> &x)
+	{
+		return std::string("{") + mpt::fmt::val(x.first) + std::string(",") + mpt::fmt::val(x.second) + std::string("}");
+	}
+};
+
+template<std::size_t FRACT, typename T>
+struct ToStringHelper<FPInt<FRACT, T> >
+{
+	std::string operator () (const FPInt<FRACT, T> &x)
+	{
+		return std::string("FPInt<") + mpt::fmt::val(FRACT) + std::string(",") + mpt::fmt::val(typeid(T).name()) + std::string(">{") + mpt::fmt::val(x.GetInt()) + std::string(".") + mpt::fmt::val(x.GetFract()) + std::string("}");
+	}
+};
+
+template<>
+struct ToStringHelper<SamplePosition>
+{
+	std::string operator () (const SamplePosition &x)
+	{
+		return mpt::fmt::val(x.GetInt()) + std::string(".") + std::string("0x") + mpt::fmt::hex0<8>(x.GetFract());
 	}
 };
 
+#endif // MPT_TEST_CXX11
+
+
 namespace Test {
 
 // We do not generally have type_traits from C++03-TR1
 // and std::numeric_limits does not provide a is_integer which is useable as template argument.
-template <typename T> struct is_integer : public mpt::false_type { };
-template <> struct is_integer<signed short>     : public mpt::true_type { };
-template <> struct is_integer<signed int>       : public mpt::true_type { };
-template <> struct is_integer<signed long>      : public mpt::true_type { };
-template <> struct is_integer<signed long long> : public mpt::true_type { };
-template <> struct is_integer<unsigned short>     : public mpt::true_type { };
-template <> struct is_integer<unsigned int>       : public mpt::true_type { };
-template <> struct is_integer<unsigned long>      : public mpt::true_type { };
-template <> struct is_integer<unsigned long long> : public mpt::true_type { };
+template <typename T> struct is_integer : public std::false_type { };
+template <> struct is_integer<signed short>     : public std::true_type { };
+template <> struct is_integer<signed int>       : public std::true_type { };
+template <> struct is_integer<signed long>      : public std::true_type { };
+template <> struct is_integer<signed long long> : public std::true_type { };
+template <> struct is_integer<unsigned short>     : public std::true_type { };
+template <> struct is_integer<unsigned int>       : public std::true_type { };
+template <> struct is_integer<unsigned long>      : public std::true_type { };
+template <> struct is_integer<unsigned long long> : public std::true_type { };
 
 class Testcase
 {
@@ -127,25 +182,25 @@ public:
 private:
 
 	template <typename Tx, typename Ty>
-	inline bool IsEqual(const Tx &x, const Ty &y, mpt::false_type, mpt::false_type)
+	inline bool IsEqual(const Tx &x, const Ty &y, std::false_type, std::false_type)
 	{
 		return (x == y);
 	}
 
 	template <typename Tx, typename Ty>
-	inline bool IsEqual(const Tx &x, const Ty &y, mpt::false_type, mpt::true_type)
+	inline bool IsEqual(const Tx &x, const Ty &y, std::false_type, std::true_type)
 	{
 		return (x == y);
 	}
 
 	template <typename Tx, typename Ty>
-	inline bool IsEqual(const Tx &x, const Ty &y, mpt::true_type, mpt::false_type)
+	inline bool IsEqual(const Tx &x, const Ty &y, std::true_type, std::false_type)
 	{
 		return (x == y);
 	}
 
 	template <typename Tx, typename Ty>
-	inline bool IsEqual(const Tx &x, const Ty &y, mpt::true_type /* is_integer */, mpt::true_type /* is_integer */ )
+	inline bool IsEqual(const Tx &x, const Ty &y, std::true_type /* is_integer */, std::true_type /* is_integer */ )
 	{
 		// Avoid signed-unsigned-comparison warnings and test equivalence in case of either type conversion direction.
 		return ((x == static_cast<Tx>(y)) && (static_cast<Ty>(x) == y));
@@ -159,7 +214,7 @@ private:
 
 public:
 
-#if 0 // C++11 version
+#ifdef MPT_TEST_CXX11
 
 private:
 
@@ -168,17 +223,17 @@ private:
 	{
 		if(!IsEqual(x, y, is_integer<Tx>(), is_integer<Ty>()))
 		{
-			throw TestFailed(mpt::String::Print("%1 != %2", ToStringHelper<Tx>()(x), ToStringHelper<Ty>()(y)));
+			throw TestFailed(mpt::format(std::string("%1 != %2"))(ToStringHelper<Tx>()(x), ToStringHelper<Ty>()(y)));
 			//throw TestFailed();
 		}
 	}
 
-	template <typename Tx, typename Ty>
-	MPT_NOINLINE void TypeCompareHelper(const Tx &x, const Ty &y, const Tesp &eps)
+	template <typename Tx, typename Ty, typename Teps>
+	MPT_NOINLINE void TypeCompareHelper(const Tx &x, const Ty &y, const Teps &eps)
 	{
 		if(!IsEqualEpsilon(x, y, eps))
 		{
-			throw TestFailed(mpt::String::Print("%1 != %2", ToStringHelper<Tx>()(x), ToStringHelper<Ty>()(y)));
+			throw TestFailed(mpt::format(std::string("%1 != %2"))(ToStringHelper<Tx>()(x), ToStringHelper<Ty>()(y)));
 			//throw TestFailed();
 		}
 	}
@@ -227,7 +282,7 @@ public:
 	#define VERIFY_EQUAL_NONCONT(x,y)       Test::Testcase(Test::FatalityStop    , Test::VerbosityNormal, #x " == " #y , MPT_TEST_CONTEXT_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;} )
 	#define VERIFY_EQUAL_QUIET_NONCONT(x,y) Test::Testcase(Test::FatalityStop    , Test::VerbosityQuiet , #x " == " #y , MPT_TEST_CONTEXT_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;} )
 
-	#define VERIFY_EQUAL_EPS(x,y)               Test::Testcase(Test::FatalityContinue, Test::VerbosityNormal, #x " == " #y , MPT_TEST_CONTEXT_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;}, (eps) )
+	#define VERIFY_EQUAL_EPS(x,y,eps)       Test::Testcase(Test::FatalityContinue, Test::VerbosityNormal, #x " == " #y , MPT_TEST_CONTEXT_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;}, (eps) )
 
 #else
 
@@ -241,7 +296,7 @@ public:
 		{
 			if(!IsEqual(x, y, is_integer<Tx>(), is_integer<Ty>()))
 			{
-				//throw TestFailed(mpt::String::Print("%1 != %2", x, y));
+				//throw TestFailed(mpt::format(std::string("%1 != %2"))(x, y));
 				throw TestFailed();
 			}
 			ReportPassed();
@@ -259,7 +314,7 @@ public:
 		{
 			if(!IsEqualEpsilon(x, y, eps))
 			{
-				//throw TestFailed(mpt::String::Print("%1 != %2", x, y));
+				//throw TestFailed(mpt::format(std::string("%1 != %2"))(x, y));
 				throw TestFailed();
 			}
 			ReportPassed();
diff --git a/test/test.cpp b/test/test.cpp
index 3b253df..6d654bb 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -20,12 +20,15 @@
 #include "../common/mptCRC.h"
 #include "../common/StringFixer.h"
 #include "../common/serialization_utils.h"
+#include "../common/mptUUID.h"
 #include "../soundlib/Sndfile.h"
 #include "../common/FileReader.h"
 #include "../soundlib/mod_specifications.h"
 #include "../soundlib/MIDIEvents.h"
 #include "../soundlib/MIDIMacros.h"
-#include "../soundlib/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatConverters.h"
+#include "../soundbase/SampleFormatCopy.h"
+#include "../soundlib/ModSampleCopy.h"
 #include "../soundlib/ITCompression.h"
 #include "../soundlib/tuningcollection.h"
 #include "../soundlib/tuning.h"
@@ -35,9 +38,10 @@
 #include "../mptrack/MainFrm.h"
 #include "../mptrack/Settings.h"
 #endif // MODPLUG_TRACKER
-#ifndef MODPLUG_TRACKER
 #include "../common/mptFileIO.h"
-#endif // !MODPLUG_TRACKER
+#ifdef LIBOPENMPT_BUILD
+#include "../libopenmpt/libopenmpt_version.h"
+#endif // LIBOPENMPT_BUILD
 #ifndef NO_PLUGINS
 #include "../soundlib/plugins/PlugInterface.h"
 #endif
@@ -56,7 +60,7 @@
 #include <zlib.h>
 #elif defined(MPT_WITH_MINIZ)
 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
-#include <miniz/miniz.c>
+#include <miniz/miniz.h>
 #endif
 
 #ifdef _DEBUG
@@ -83,7 +87,8 @@ namespace Test {
 
 static MPT_NOINLINE void TestVersion();
 static MPT_NOINLINE void TestTypes();
-static MPT_NOINLINE void TestMisc();
+static MPT_NOINLINE void TestMisc1();
+static MPT_NOINLINE void TestMisc2();
 static MPT_NOINLINE void TestRandom();
 static MPT_NOINLINE void TestCharsets();
 static MPT_NOINLINE void TestStringFormatting();
@@ -95,6 +100,7 @@ static MPT_NOINLINE void TestITCompression();
 static MPT_NOINLINE void TestTunings();
 static MPT_NOINLINE void TestPCnoteSerialization();
 static MPT_NOINLINE void TestLoadSaveFile();
+static MPT_NOINLINE void TestEditing();
 
 
 
@@ -104,7 +110,6 @@ static mpt::prng * s_PRNG = nullptr;
 
 
 mpt::PathString GetPathPrefix()
-//-----------------------------
 {
 	if((*PathPrefix).empty())
 	{
@@ -115,7 +120,6 @@ mpt::PathString GetPathPrefix()
 
 
 void DoTests()
-//------------
 {
 
 	#if MPT_OS_WINDOWS
@@ -128,12 +132,15 @@ void DoTests()
 			libopenmpt = true;
 		#endif
 
+#if !MPT_OS_WINDOWS_WINRT
 		// set path prefix for test files (if provided)
 		std::vector<WCHAR> buf(GetEnvironmentVariableW(L"srcdir", NULL, 0) + 1);
-		if(GetEnvironmentVariableW(L"srcdir", &buf[0], static_cast<DWORD>(buf.size())) > 0)
+		if(GetEnvironmentVariableW(L"srcdir", buf.data(), static_cast<DWORD>(buf.size())) > 0)
 		{
-			pathprefix = &buf[0];
-		} else if(libopenmpt && IsDebuggerPresent())
+			pathprefix = buf.data();
+		} else
+#endif
+		if(libopenmpt && IsDebuggerPresent())
 		{
 			pathprefix = L"../../";
 		}
@@ -160,7 +167,8 @@ void DoTests()
 
 	DO_TEST(TestVersion);
 	DO_TEST(TestTypes);
-	DO_TEST(TestMisc);
+	DO_TEST(TestMisc1);
+	DO_TEST(TestMisc2);
 	DO_TEST(TestRandom);
 	DO_TEST(TestCharsets);
 	DO_TEST(TestStringFormatting);
@@ -174,6 +182,7 @@ void DoTests()
 	// slower tests, require opening a CModDoc
 	DO_TEST(TestPCnoteSerialization);
 	DO_TEST(TestLoadSaveFile);
+	DO_TEST(TestEditing);
 
 	delete s_PRNG;
 	s_PRNG = nullptr;
@@ -183,8 +192,10 @@ void DoTests()
 }
 
 
+static mpt::PathString GetTempFilenameBase();
+
+
 static void RemoveFile(const mpt::PathString &filename)
-//-----------------------------------------------------
 {
 	#if MPT_OS_WINDOWS
 		for(int retry=0; retry<10; retry++)
@@ -204,7 +215,6 @@ static void RemoveFile(const mpt::PathString &filename)
 
 // Test if functions related to program version data work
 static MPT_NOINLINE void TestVersion()
-//------------------------------------
 {
 	//Verify that macros and functions work.
 	{
@@ -241,41 +251,31 @@ static MPT_NOINLINE void TestVersion()
 	//Verify that the version obtained from the executable file is the same as
 	//defined in MptVersion.
 	{
-		char  szFullPath[MAX_PATH];
+		WCHAR szFullPath[MAX_PATH];
 		DWORD dwVerHnd;
 		DWORD dwVerInfoSize;
 
 		// Get version information from the application
-		::GetModuleFileName(NULL, szFullPath, sizeof(szFullPath));
-		dwVerInfoSize = ::GetFileVersionInfoSize(szFullPath, &dwVerHnd);
+		::GetModuleFileNameW(NULL, szFullPath, mpt::size(szFullPath));
+		dwVerInfoSize = ::GetFileVersionInfoSizeW(szFullPath, &dwVerHnd);
 		if (!dwVerInfoSize)
 			throw std::runtime_error("!dwVerInfoSize is true");
 
-		char *pVersionInfo;
-		try
-		{
-			pVersionInfo = new char[dwVerInfoSize];
-		} catch(MPTMemoryException)
-		{
-			throw std::runtime_error("Could not allocate memory for pVersionInfo");
-		}
+		std::vector<TCHAR> pVersionInfo(dwVerInfoSize);
 
-		char* szVer = NULL;
+		WCHAR *szVer = nullptr;
 		UINT uVerLength;
-		if (!(::GetFileVersionInfo((LPTSTR)szFullPath, (DWORD)dwVerHnd,
-								   (DWORD)dwVerInfoSize, (LPVOID)pVersionInfo)))
+		if (!(::GetFileVersionInfoW(szFullPath, (DWORD)dwVerHnd,
+								   (DWORD)dwVerInfoSize, pVersionInfo.data())))
 		{
-			delete[] pVersionInfo;
 			throw std::runtime_error("GetFileVersionInfo() returned false");
 		}
-		if (!(::VerQueryValue(pVersionInfo, TEXT("\\StringFileInfo\\040904b0\\FileVersion"),
+		if (!(::VerQueryValueW(pVersionInfo.data(), L"\\StringFileInfo\\040904b0\\FileVersion",
 							  (LPVOID*)&szVer, &uVerLength))) {
-			delete[] pVersionInfo;
 			throw std::runtime_error("VerQueryValue() returned false");
 		}
 
-		std::string version = szVer;
-		delete[] pVersionInfo;
+		std::string version = mpt::ToCharset(mpt::CharsetASCII, szVer);
 
 		//version string should be like: 1,17,2,38  Change ',' to '.' to get format 1.17.2.38
 		version = mpt::String::Replace(version, ",", ".");
@@ -284,12 +284,47 @@ static MPT_NOINLINE void TestVersion()
 		VERIFY_EQUAL( MptVersion::ToNum(version), MptVersion::num );
 	}
 #endif
+
+#ifdef LIBOPENMPT_BUILD
+	mpt::PathString version_mk = GetPathPrefix() + MPT_PATHSTRING("libopenmpt/libopenmpt_version.mk");
+	mpt::ifstream f(version_mk, std::ios::in);
+	VERIFY_EQUAL(f ? true : false, true);
+	std::map<std::string, std::string> fields;
+	std::string line;
+	while(std::getline(f, line))
+	{
+		line = mpt::String::Trim(line);
+		if(line.empty())
+		{
+			continue;
+		}
+		std::vector<std::string> line_fields = mpt::String::Split<std::string>(line, std::string("="));
+		VERIFY_EQUAL_NONCONT(line_fields.size(), 2u);
+		line_fields[0] = mpt::String::Trim(line_fields[0]);
+		line_fields[1] = mpt::String::Trim(line_fields[1]);
+		VERIFY_EQUAL_NONCONT(line_fields[0].length() > 0, true);
+		fields[line_fields[0]] = line_fields[1];
+	}
+	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_MAJOR"], mpt::fmt::val(OPENMPT_API_VERSION_MAJOR));
+	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_MINOR"], mpt::fmt::val(OPENMPT_API_VERSION_MINOR));
+	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_PATCH"], mpt::fmt::val(OPENMPT_API_VERSION_PATCH));
+	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_PREREL"], mpt::fmt::val(OPENMPT_API_VERSION_PREREL));
+	if(std::string(OPENMPT_API_VERSION_PREREL).length() > 0)
+	{
+		VERIFY_EQUAL(std::string(OPENMPT_API_VERSION_PREREL).substr(0, 1), "-");
+	}
+	VERIFY_EQUAL(OPENMPT_API_VERSION_IS_PREREL, (std::string(OPENMPT_API_VERSION_PREREL).length() > 0) ? 1 : 0);
+	
+	VERIFY_EQUAL(fields["LIBOPENMPT_LTVER_CURRENT"].length() > 0, true);
+	VERIFY_EQUAL(fields["LIBOPENMPT_LTVER_REVISION"].length() > 0, true);
+	VERIFY_EQUAL(fields["LIBOPENMPT_LTVER_AGE"].length() > 0, true);
+#endif // LIBOPENMPT_BUILD
+
 }
 
 
 // Test if data types are interpreted correctly
 static MPT_NOINLINE void TestTypes()
-//----------------------------------
 {
 	VERIFY_EQUAL(int8_min, (std::numeric_limits<int8>::min)());
 	VERIFY_EQUAL(int8_max, (std::numeric_limits<int8>::max)());
@@ -359,8 +394,8 @@ static void TestFloatFormat(double x, const char * format, mpt::FormatFlags f, s
 #ifdef MODPLUG_TRACKER
 	std::string str_sprintf = StringFormat(format, x);
 #endif
-	std::string str_iostreams = mpt::Format().SetFlags(f).SetWidth(width).SetPrecision(precision).ToString(x);
-	std::string str_parsed = mpt::Format().ParsePrintf(format).ToString(x);
+	std::string str_iostreams = mpt::FormatSpec().SetFlags(f).SetWidth(width).SetPrecision(precision).ToString(x);
+	std::string str_parsed = mpt::FormatSpec().ParsePrintf(format).ToString(x);
 	//Log("%s", str_sprintf.c_str());
 	//Log("%s", str_iostreams.c_str());
 	//Log("%s", str_iostreams.c_str());
@@ -426,27 +461,17 @@ static bool EndsWith(const mpt::ustring &str, const mpt::ustring &match)
 
 
 
-#ifdef MODPLUG_TRACKER
-static bool IsEqualUUID(const UUID &lhs, const UUID &rhs)
-{
-	return std::memcmp(&lhs, &rhs, sizeof(UUID)) == 0;
-}
-#endif
-
-
 static MPT_NOINLINE void TestStringFormatting()
-//---------------------------------------------
 {
+	VERIFY_EQUAL(mpt::fmt::val(1.5f), "1.5");
+	VERIFY_EQUAL(mpt::fmt::val(true), "1");
+	VERIFY_EQUAL(mpt::fmt::val(false), "0");
+	//VERIFY_EQUAL(mpt::fmt::val('A'), "A"); // deprecated
+	//VERIFY_EQUAL(mpt::fmt::val(L'A'), "A"); // deprecated
 
-	VERIFY_EQUAL(mpt::ToString(1.5f), "1.5");
-	VERIFY_EQUAL(mpt::ToString(true), "1");
-	VERIFY_EQUAL(mpt::ToString(false), "0");
-	//VERIFY_EQUAL(mpt::ToString('A'), "A"); // deprecated
-	//VERIFY_EQUAL(mpt::ToString(L'A'), "A"); // deprecated
-
-	VERIFY_EQUAL(mpt::ToString(0), "0");
-	VERIFY_EQUAL(mpt::ToString(-23), "-23");
-	VERIFY_EQUAL(mpt::ToString(42), "42");
+	VERIFY_EQUAL(mpt::fmt::val(0), "0");
+	VERIFY_EQUAL(mpt::fmt::val(-23), "-23");
+	VERIFY_EQUAL(mpt::fmt::val(42), "42");
 
 	VERIFY_EQUAL(mpt::fmt::hex<3>((int32)-1), "ffffffff");
 	VERIFY_EQUAL(mpt::fmt::hex(0x123e), "123e");
@@ -460,16 +485,17 @@ static MPT_NOINLINE void TestStringFormatting()
 	VERIFY_EQUAL(mpt::wfmt::hex0<2>(0x123e), L"123e");
 #endif
 
-	VERIFY_EQUAL(mpt::ToString(-87.0f), "-87");
-	if(mpt::ToString(-0.5e-6) != "-5e-007"
-		&& mpt::ToString(-0.5e-6) != "-5e-07"
-		&& mpt::ToString(-0.5e-6) != "-5e-7"
+	VERIFY_EQUAL(mpt::fmt::val(-87.0f), "-87");
+	if(mpt::fmt::val(-0.5e-6) != "-5e-007"
+		&& mpt::fmt::val(-0.5e-6) != "-5e-07"
+		&& mpt::fmt::val(-0.5e-6) != "-5e-7"
 		)
 	{
 		VERIFY_EQUAL(true, false);
 	}
-	VERIFY_EQUAL(mpt::ToString(58.65403492763), "58.654");
-	VERIFY_EQUAL(mpt::Format("%3.1f").ToString(23.42), "23.4");
+	VERIFY_EQUAL(mpt::fmt::val(58.65403492763), "58.654");
+	VERIFY_EQUAL(mpt::FormatSpec("%3.1f").ToString(23.42), "23.4");
+	VERIFY_EQUAL(mpt::fmt::f("%3.1f", 23.42), "23.4");
 
 	VERIFY_EQUAL(ConvertStrTo<uint32>("586"), 586u);
 	VERIFY_EQUAL(ConvertStrTo<uint32>("2147483647"), (uint32)int32_max);
@@ -487,8 +513,8 @@ static MPT_NOINLINE void TestStringFormatting()
 	VERIFY_EQUAL(ConvertStrTo<double>("-0.5e-6"), -0.5e-6);
 	VERIFY_EQUAL(ConvertStrTo<double>("58.65403492763"), 58.65403492763);
 
-	VERIFY_EQUAL(ConvertStrTo<float>(mpt::ToString(-87.0)), -87.0);
-	VERIFY_EQUAL(ConvertStrTo<double>(mpt::ToString(-0.5e-6)), -0.5e-6);
+	VERIFY_EQUAL(ConvertStrTo<float>(mpt::fmt::val(-87.0)), -87.0);
+	VERIFY_EQUAL(ConvertStrTo<double>(mpt::fmt::val(-0.5e-6)), -0.5e-6);
 
 	VERIFY_EQUAL(mpt::String::Parse::Hex<unsigned char>("fe"), 254);
 #if MPT_WSTRING_FORMAT
@@ -512,11 +538,12 @@ static MPT_NOINLINE void TestStringFormatting()
 	TestFloatFormats(1234567890000000.0);
 	TestFloatFormats(0.0000001234567890);
 
-	VERIFY_EQUAL(mpt::Format().ParsePrintf("%7.3f").ToString(6.12345), "  6.123");
+	VERIFY_EQUAL(mpt::FormatSpec().ParsePrintf("%7.3f").ToString(6.12345), "  6.123");
+	VERIFY_EQUAL(mpt::fmt::f("%7.3f", 6.12345), "  6.123");
 	VERIFY_EQUAL(mpt::fmt::flt(6.12345, 7, 3), "  6.123");
 	VERIFY_EQUAL(mpt::fmt::fix(6.12345, 7, 3), "  6.123");
 	VERIFY_EQUAL(mpt::fmt::flt(6.12345, 0, 4), "6.123");
-	#if !MPT_OS_EMSCRIPTEN
+	#if !(MPT_OS_EMSCRIPTEN && MPT_OS_EMSCRIPTEN_ANCIENT)
 	VERIFY_EQUAL(mpt::fmt::fix(6.12345, 0, 4), "6.1235");
 	#else
 	// emscripten(1.21)/nodejs(v0.10.25) print 6.1234 instead of 6.1235 for unknown reasons.
@@ -554,8 +581,8 @@ static MPT_NOINLINE void TestStringFormatting()
 	VERIFY_EQUAL(mpt::format("%b")("a"), "%b");
 
 #if defined(_MFC_VER)
-	VERIFY_EQUAL(mpt::ToUString(CString(_T("foobar"))), MPT_USTRING("foobar"));
-	VERIFY_EQUAL(mpt::ToUString(CString(_T("foobar"))), MPT_USTRING("foobar"));
+	VERIFY_EQUAL(mpt::ufmt::val(CString(_T("foobar"))), MPT_USTRING("foobar"));
+	VERIFY_EQUAL(mpt::ufmt::val(CString(_T("foobar"))), MPT_USTRING("foobar"));
 	VERIFY_EQUAL(mpt::format(CString(_T("%1%2%3")))(1,2,3), _T("123"));
 	VERIFY_EQUAL(mpt::format(CString(_T("%1%2%3")))(1,mpt::tfmt::dec0<3>(2),3), _T("10023"));
 #endif
@@ -565,8 +592,6 @@ static MPT_NOINLINE void TestStringFormatting()
 
 struct Gregorian {
 	int Y,M,D,h,m,s;
-	Gregorian() {}
-	Gregorian(int Y, int M, int D, int h, int m, int s) : Y(Y), M(M), D(D), h(h), m(m), s(s) {}
 	static Gregorian FromTM(tm t) {
 		Gregorian g;
 		g.Y = t.tm_year + 1900;
@@ -599,18 +624,20 @@ bool operator !=(Gregorian a, Gregorian b) {
 }
 
 int64 TestDate1(int s, int m, int h, int D, int M, int Y) {
-	return mpt::Date::Unix::FromUTC(Gregorian::ToTM(Gregorian(Y,M,D,h,m,s)));
+	return mpt::Date::Unix::FromUTC(Gregorian::ToTM(Gregorian{Y,M,D,h,m,s}));
 }
 
 Gregorian TestDate2(int s, int m, int h, int D, int M, int Y) {
-	return Gregorian(Y,M,D,h,m,s);
+	return Gregorian{Y,M,D,h,m,s};
 }
 
-static MPT_NOINLINE void TestMisc()
-//---------------------------------
+static MPT_NOINLINE void TestMisc1()
 {
 
-#define SwapBytesReturn(x) SwapBytesReturnLE(SwapBytesReturnBE(x))
+	VERIFY_EQUAL(mpt::endian(), mpt::detail::endian_probe());
+	VERIFY_EQUAL((mpt::endian() == mpt::endian_big) || (mpt::endian() == mpt::endian_little), true);	
+
+#define SwapBytesReturn(x) SwapBytesLE(SwapBytesBE(x))
 
 	VERIFY_EQUAL(SwapBytesReturn(uint8(0x12)), 0x12);
 	VERIFY_EQUAL(SwapBytesReturn(uint16(0x1234)), 0x3412);
@@ -658,6 +685,34 @@ static MPT_NOINLINE void TestMisc()
 	VERIFY_EQUAL(IEEE754binary64LE(1.0), IEEE754binary64LE(0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f));
 	VERIFY_EQUAL(IEEE754binary64BE(1.0), IEEE754binary64BE(0x3f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00));
 
+	// Packed integers with defined endianness
+	{
+		int8le le8; le8.set(-128);
+		int8be be8; be8.set(-128);
+		VERIFY_EQUAL(le8, -128);
+		VERIFY_EQUAL(be8, -128);
+		VERIFY_EQUAL(memcmp(&le8, "\x80", 1), 0);
+		VERIFY_EQUAL(memcmp(&be8, "\x80", 1), 0);
+		int16le le16; le16.set(0x1234);
+		int16be be16; be16.set(0x1234);
+		VERIFY_EQUAL(le16, 0x1234);
+		VERIFY_EQUAL(be16, 0x1234);
+		VERIFY_EQUAL(memcmp(&le16, "\x34\x12", 2), 0);
+		VERIFY_EQUAL(memcmp(&be16, "\x12\x34", 2), 0);
+		uint32le le32; le32.set(0xFFEEDDCCu);
+		uint32be be32; be32.set(0xFFEEDDCCu);
+		VERIFY_EQUAL(le32, 0xFFEEDDCCu);
+		VERIFY_EQUAL(be32, 0xFFEEDDCCu);
+		VERIFY_EQUAL(memcmp(&le32, "\xCC\xDD\xEE\xFF", 4), 0);
+		VERIFY_EQUAL(memcmp(&be32, "\xFF\xEE\xDD\xCC", 4), 0);
+		uint64le le64; le64.set(0xDEADC0DE15C0FFEEull);
+		uint64be be64; be64.set(0xDEADC0DE15C0FFEEull);
+		VERIFY_EQUAL(le64, 0xDEADC0DE15C0FFEEull);
+		VERIFY_EQUAL(be64, 0xDEADC0DE15C0FFEEull);
+		VERIFY_EQUAL(memcmp(&le64, "\xEE\xFF\xC0\x15\xDE\xC0\xAD\xDE", 8), 0);
+		VERIFY_EQUAL(memcmp(&be64, "\xDE\xAD\xC0\xDE\x15\xC0\xFF\xEE", 8), 0);
+	}
+
 	VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_MAX), false);
 	VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_PC), true);
 	VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_PCS), true);
@@ -757,6 +812,422 @@ static MPT_NOINLINE void TestMisc()
 	
 	VERIFY_EQUAL( mpt::saturate_cast<uint32>(static_cast<double>(std::numeric_limits<int64>::max())), std::numeric_limits<uint32>::max() );
 
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32768,  1), mpt::rshift_signed_standard<int16>(-32768,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32767,  1), mpt::rshift_signed_standard<int16>(-32767,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32766,  1), mpt::rshift_signed_standard<int16>(-32766,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -2,  1), mpt::rshift_signed_standard<int16>(    -2,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -1,  1), mpt::rshift_signed_standard<int16>(    -1,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     0,  1), mpt::rshift_signed_standard<int16>(     0,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     1,  1), mpt::rshift_signed_standard<int16>(     1,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     2,  1), mpt::rshift_signed_standard<int16>(     2,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32766,  1), mpt::rshift_signed_standard<int16>( 32766,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32767,  1), mpt::rshift_signed_standard<int16>( 32767,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32768, 14), mpt::rshift_signed_standard<int16>(-32768, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32767, 14), mpt::rshift_signed_standard<int16>(-32767, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32766, 14), mpt::rshift_signed_standard<int16>(-32766, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -2, 14), mpt::rshift_signed_standard<int16>(    -2, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -1, 14), mpt::rshift_signed_standard<int16>(    -1, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     0, 14), mpt::rshift_signed_standard<int16>(     0, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     1, 14), mpt::rshift_signed_standard<int16>(     1, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     2, 14), mpt::rshift_signed_standard<int16>(     2, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32766, 14), mpt::rshift_signed_standard<int16>( 32766, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32767, 14), mpt::rshift_signed_standard<int16>( 32767, 14));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32768, 15), mpt::rshift_signed_standard<int16>(-32768, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32767, 15), mpt::rshift_signed_standard<int16>(-32767, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32766, 15), mpt::rshift_signed_standard<int16>(-32766, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -2, 15), mpt::rshift_signed_standard<int16>(    -2, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -1, 15), mpt::rshift_signed_standard<int16>(    -1, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     0, 15), mpt::rshift_signed_standard<int16>(     0, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     1, 15), mpt::rshift_signed_standard<int16>(     1, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     2, 15), mpt::rshift_signed_standard<int16>(     2, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32766, 15), mpt::rshift_signed_standard<int16>( 32766, 15));
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32767, 15), mpt::rshift_signed_standard<int16>( 32767, 15));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32768,  1), mpt::lshift_signed_standard<int16>(-32768,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32767,  1), mpt::lshift_signed_standard<int16>(-32767,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32766,  1), mpt::lshift_signed_standard<int16>(-32766,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -2,  1), mpt::lshift_signed_standard<int16>(    -2,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -1,  1), mpt::lshift_signed_standard<int16>(    -1,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     0,  1), mpt::lshift_signed_standard<int16>(     0,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     1,  1), mpt::lshift_signed_standard<int16>(     1,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     2,  1), mpt::lshift_signed_standard<int16>(     2,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32766,  1), mpt::lshift_signed_standard<int16>( 32766,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32767,  1), mpt::lshift_signed_standard<int16>( 32767,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32768, 14), mpt::lshift_signed_standard<int16>(-32768, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32767, 14), mpt::lshift_signed_standard<int16>(-32767, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32766, 14), mpt::lshift_signed_standard<int16>(-32766, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -2, 14), mpt::lshift_signed_standard<int16>(    -2, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -1, 14), mpt::lshift_signed_standard<int16>(    -1, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     0, 14), mpt::lshift_signed_standard<int16>(     0, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     1, 14), mpt::lshift_signed_standard<int16>(     1, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     2, 14), mpt::lshift_signed_standard<int16>(     2, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32766, 14), mpt::lshift_signed_standard<int16>( 32766, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32767, 14), mpt::lshift_signed_standard<int16>( 32767, 14));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32768, 15), mpt::lshift_signed_standard<int16>(-32768, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32767, 15), mpt::lshift_signed_standard<int16>(-32767, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32766, 15), mpt::lshift_signed_standard<int16>(-32766, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -2, 15), mpt::lshift_signed_standard<int16>(    -2, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -1, 15), mpt::lshift_signed_standard<int16>(    -1, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     0, 15), mpt::lshift_signed_standard<int16>(     0, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     1, 15), mpt::lshift_signed_standard<int16>(     1, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     2, 15), mpt::lshift_signed_standard<int16>(     2, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32766, 15), mpt::lshift_signed_standard<int16>( 32766, 15));
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32767, 15), mpt::lshift_signed_standard<int16>( 32767, 15));
+
+#if MPT_COMPILER_SHIFT_SIGNED
+
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32768,  1), (-32768) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32767,  1), (-32767) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32766,  1), (-32766) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -2,  1), (    -2) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -1,  1), (    -1) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     0,  1), (     0) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     1,  1), (     1) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     2,  1), (     2) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32766,  1), ( 32766) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32767,  1), ( 32767) >>  1);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32768, 14), (-32768) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32767, 14), (-32767) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32766, 14), (-32766) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -2, 14), (    -2) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -1, 14), (    -1) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     0, 14), (     0) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     1, 14), (     1) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     2, 14), (     2) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32766, 14), ( 32766) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32767, 14), ( 32767) >> 14);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32768, 15), (-32768) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32767, 15), (-32767) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(-32766, 15), (-32766) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -2, 15), (    -2) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(    -1, 15), (    -1) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     0, 15), (     0) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     1, 15), (     1) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>(     2, 15), (     2) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32766, 15), ( 32766) >> 15);
+	VERIFY_EQUAL(mpt::rshift_signed<int16>( 32767, 15), ( 32767) >> 15);
+
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32768,  1), (-32768) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32767,  1), (-32767) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32766,  1), (-32766) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -2,  1), (    -2) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -1,  1), (    -1) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     0,  1), (     0) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     1,  1), (     1) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     2,  1), (     2) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32766,  1), ( 32766) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32767,  1), ( 32767) <<  1);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32768, 14), (-32768) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32767, 14), (-32767) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32766, 14), (-32766) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -2, 14), (    -2) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -1, 14), (    -1) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     0, 14), (     0) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     1, 14), (     1) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     2, 14), (     2) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32766, 14), ( 32766) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32767, 14), ( 32767) << 14);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32768, 15), (-32768) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32767, 15), (-32767) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(-32766, 15), (-32766) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -2, 15), (    -2) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(    -1, 15), (    -1) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     0, 15), (     0) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     1, 15), (     1) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>(     2, 15), (     2) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32766, 15), ( 32766) << 15);
+	VERIFY_EQUAL(mpt::lshift_signed<int16>( 32767, 15), ( 32767) << 15);
+
+#endif
+
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(0-0x80000000,  1), mpt::rshift_signed_standard<int32>(0-0x80000000,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7fffffff,  1), mpt::rshift_signed_standard<int32>(-0x7fffffff,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7ffffffe,  1), mpt::rshift_signed_standard<int32>(-0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(         -1,  1), mpt::rshift_signed_standard<int32>(         -1,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          0,  1), mpt::rshift_signed_standard<int32>(          0,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          1,  1), mpt::rshift_signed_standard<int32>(          1,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7ffffffe,  1), mpt::rshift_signed_standard<int32>( 0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7fffffff,  1), mpt::rshift_signed_standard<int32>( 0x7fffffff,  1));
+
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(0-0x80000000, 31), mpt::rshift_signed_standard<int32>(0-0x80000000, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7fffffff, 31), mpt::rshift_signed_standard<int32>(-0x7fffffff, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7ffffffe, 31), mpt::rshift_signed_standard<int32>(-0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(         -1, 31), mpt::rshift_signed_standard<int32>(         -1, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          0, 31), mpt::rshift_signed_standard<int32>(          0, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          1, 31), mpt::rshift_signed_standard<int32>(          1, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7ffffffe, 31), mpt::rshift_signed_standard<int32>( 0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7fffffff, 31), mpt::rshift_signed_standard<int32>( 0x7fffffff, 31));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(0-0x80000000,  1), mpt::lshift_signed_standard<int32>(0-0x80000000,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7fffffff,  1), mpt::lshift_signed_standard<int32>(-0x7fffffff,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7ffffffe,  1), mpt::lshift_signed_standard<int32>(-0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(         -1,  1), mpt::lshift_signed_standard<int32>(         -1,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          0,  1), mpt::lshift_signed_standard<int32>(          0,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          1,  1), mpt::lshift_signed_standard<int32>(          1,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7ffffffe,  1), mpt::lshift_signed_standard<int32>( 0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7fffffff,  1), mpt::lshift_signed_standard<int32>( 0x7fffffff,  1));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(0-0x80000000, 31), mpt::lshift_signed_standard<int32>(0-0x80000000, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7fffffff, 31), mpt::lshift_signed_standard<int32>(-0x7fffffff, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7ffffffe, 31), mpt::lshift_signed_standard<int32>(-0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(         -1, 31), mpt::lshift_signed_standard<int32>(         -1, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          0, 31), mpt::lshift_signed_standard<int32>(          0, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          1, 31), mpt::lshift_signed_standard<int32>(          1, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7ffffffe, 31), mpt::lshift_signed_standard<int32>( 0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7fffffff, 31), mpt::lshift_signed_standard<int32>( 0x7fffffff, 31));
+
+#if MPT_COMPILER_SHIFT_SIGNED
+
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(0-0x80000000,  1), mpt::rshift_signed_undefined<int32>(0-0x80000000,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7fffffff,  1), mpt::rshift_signed_undefined<int32>(-0x7fffffff,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7ffffffe,  1), mpt::rshift_signed_undefined<int32>(-0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(         -1,  1), mpt::rshift_signed_undefined<int32>(         -1,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          0,  1), mpt::rshift_signed_undefined<int32>(          0,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          1,  1), mpt::rshift_signed_undefined<int32>(          1,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7ffffffe,  1), mpt::rshift_signed_undefined<int32>( 0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7fffffff,  1), mpt::rshift_signed_undefined<int32>( 0x7fffffff,  1));
+
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(0-0x80000000, 31), mpt::rshift_signed_undefined<int32>(0-0x80000000, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7fffffff, 31), mpt::rshift_signed_undefined<int32>(-0x7fffffff, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(-0x7ffffffe, 31), mpt::rshift_signed_undefined<int32>(-0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(         -1, 31), mpt::rshift_signed_undefined<int32>(         -1, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          0, 31), mpt::rshift_signed_undefined<int32>(          0, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>(          1, 31), mpt::rshift_signed_undefined<int32>(          1, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7ffffffe, 31), mpt::rshift_signed_undefined<int32>( 0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::rshift_signed<int32>( 0x7fffffff, 31), mpt::rshift_signed_undefined<int32>( 0x7fffffff, 31));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(0-0x80000000,  1), mpt::lshift_signed_undefined<int32>(0-0x80000000,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7fffffff,  1), mpt::lshift_signed_undefined<int32>(-0x7fffffff,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7ffffffe,  1), mpt::lshift_signed_undefined<int32>(-0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(         -1,  1), mpt::lshift_signed_undefined<int32>(         -1,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          0,  1), mpt::lshift_signed_undefined<int32>(          0,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          1,  1), mpt::lshift_signed_undefined<int32>(          1,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7ffffffe,  1), mpt::lshift_signed_undefined<int32>( 0x7ffffffe,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7fffffff,  1), mpt::lshift_signed_undefined<int32>( 0x7fffffff,  1));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(0-0x80000000, 31), mpt::lshift_signed_undefined<int32>(0-0x80000000, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7fffffff, 31), mpt::lshift_signed_undefined<int32>(-0x7fffffff, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(-0x7ffffffe, 31), mpt::lshift_signed_undefined<int32>(-0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(         -1, 31), mpt::lshift_signed_undefined<int32>(         -1, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          0, 31), mpt::lshift_signed_undefined<int32>(          0, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>(          1, 31), mpt::lshift_signed_undefined<int32>(          1, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7ffffffe, 31), mpt::lshift_signed_undefined<int32>( 0x7ffffffe, 31));
+	VERIFY_EQUAL(mpt::lshift_signed<int32>( 0x7fffffff, 31), mpt::lshift_signed_undefined<int32>( 0x7fffffff, 31));
+
+#endif
+	
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x8000000000000000ll,  1), mpt::rshift_signed_standard<int64>(-0x8000000000000000ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7fffffffffffffffll,  1), mpt::rshift_signed_standard<int64>(-0x7fffffffffffffffll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7ffffffffffffffell,  1), mpt::rshift_signed_standard<int64>(-0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                 -1ll,  1), mpt::rshift_signed_standard<int64>(                 -1ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  0ll,  1), mpt::rshift_signed_standard<int64>(                  0ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  1ll,  1), mpt::rshift_signed_standard<int64>(                  1ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7ffffffffffffffell,  1), mpt::rshift_signed_standard<int64>( 0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7fffffffffffffffll,  1), mpt::rshift_signed_standard<int64>( 0x7fffffffffffffffll,  1));
+
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x8000000000000000ll, 63), mpt::rshift_signed_standard<int64>(-0x8000000000000000ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7fffffffffffffffll, 63), mpt::rshift_signed_standard<int64>(-0x7fffffffffffffffll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7ffffffffffffffell, 63), mpt::rshift_signed_standard<int64>(-0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                 -1ll, 63), mpt::rshift_signed_standard<int64>(                 -1ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  0ll, 63), mpt::rshift_signed_standard<int64>(                  0ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  1ll, 63), mpt::rshift_signed_standard<int64>(                  1ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7ffffffffffffffell, 63), mpt::rshift_signed_standard<int64>( 0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7fffffffffffffffll, 63), mpt::rshift_signed_standard<int64>( 0x7fffffffffffffffll, 63));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x8000000000000000ll,  1), mpt::lshift_signed_standard<int64>(-0x8000000000000000ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7fffffffffffffffll,  1), mpt::lshift_signed_standard<int64>(-0x7fffffffffffffffll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7ffffffffffffffell,  1), mpt::lshift_signed_standard<int64>(-0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                 -1ll,  1), mpt::lshift_signed_standard<int64>(                 -1ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  0ll,  1), mpt::lshift_signed_standard<int64>(                  0ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  1ll,  1), mpt::lshift_signed_standard<int64>(                  1ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7ffffffffffffffell,  1), mpt::lshift_signed_standard<int64>( 0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7fffffffffffffffll,  1), mpt::lshift_signed_standard<int64>( 0x7fffffffffffffffll,  1));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x8000000000000000ll, 63), mpt::lshift_signed_standard<int64>(-0x8000000000000000ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7fffffffffffffffll, 63), mpt::lshift_signed_standard<int64>(-0x7fffffffffffffffll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7ffffffffffffffell, 63), mpt::lshift_signed_standard<int64>(-0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                 -1ll, 63), mpt::lshift_signed_standard<int64>(                 -1ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  0ll, 63), mpt::lshift_signed_standard<int64>(                  0ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  1ll, 63), mpt::lshift_signed_standard<int64>(                  1ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7ffffffffffffffell, 63), mpt::lshift_signed_standard<int64>( 0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7fffffffffffffffll, 63), mpt::lshift_signed_standard<int64>( 0x7fffffffffffffffll, 63));
+
+#if MPT_COMPILER_SHIFT_SIGNED
+
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x8000000000000000ll,  1), mpt::rshift_signed_undefined<int64>(-0x8000000000000000ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7fffffffffffffffll,  1), mpt::rshift_signed_undefined<int64>(-0x7fffffffffffffffll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7ffffffffffffffell,  1), mpt::rshift_signed_undefined<int64>(-0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                 -1ll,  1), mpt::rshift_signed_undefined<int64>(                 -1ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  0ll,  1), mpt::rshift_signed_undefined<int64>(                  0ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  1ll,  1), mpt::rshift_signed_undefined<int64>(                  1ll,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7ffffffffffffffell,  1), mpt::rshift_signed_undefined<int64>( 0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7fffffffffffffffll,  1), mpt::rshift_signed_undefined<int64>( 0x7fffffffffffffffll,  1));
+
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x8000000000000000ll, 63), mpt::rshift_signed_undefined<int64>(-0x8000000000000000ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7fffffffffffffffll, 63), mpt::rshift_signed_undefined<int64>(-0x7fffffffffffffffll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(-0x7ffffffffffffffell, 63), mpt::rshift_signed_undefined<int64>(-0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                 -1ll, 63), mpt::rshift_signed_undefined<int64>(                 -1ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  0ll, 63), mpt::rshift_signed_undefined<int64>(                  0ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>(                  1ll, 63), mpt::rshift_signed_undefined<int64>(                  1ll, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7ffffffffffffffell, 63), mpt::rshift_signed_undefined<int64>( 0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::rshift_signed<int64>( 0x7fffffffffffffffll, 63), mpt::rshift_signed_undefined<int64>( 0x7fffffffffffffffll, 63));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x8000000000000000ll,  1), mpt::lshift_signed_undefined<int64>(-0x8000000000000000ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7fffffffffffffffll,  1), mpt::lshift_signed_undefined<int64>(-0x7fffffffffffffffll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7ffffffffffffffell,  1), mpt::lshift_signed_undefined<int64>(-0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                 -1ll,  1), mpt::lshift_signed_undefined<int64>(                 -1ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  0ll,  1), mpt::lshift_signed_undefined<int64>(                  0ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  1ll,  1), mpt::lshift_signed_undefined<int64>(                  1ll,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7ffffffffffffffell,  1), mpt::lshift_signed_undefined<int64>( 0x7ffffffffffffffell,  1));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7fffffffffffffffll,  1), mpt::lshift_signed_undefined<int64>( 0x7fffffffffffffffll,  1));
+
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x8000000000000000ll, 63), mpt::lshift_signed_undefined<int64>(-0x8000000000000000ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7fffffffffffffffll, 63), mpt::lshift_signed_undefined<int64>(-0x7fffffffffffffffll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(-0x7ffffffffffffffell, 63), mpt::lshift_signed_undefined<int64>(-0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                 -1ll, 63), mpt::lshift_signed_undefined<int64>(                 -1ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  0ll, 63), mpt::lshift_signed_undefined<int64>(                  0ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>(                  1ll, 63), mpt::lshift_signed_undefined<int64>(                  1ll, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7ffffffffffffffell, 63), mpt::lshift_signed_undefined<int64>( 0x7ffffffffffffffell, 63));
+	VERIFY_EQUAL(mpt::lshift_signed<int64>( 0x7fffffffffffffffll, 63), mpt::lshift_signed_undefined<int64>( 0x7fffffffffffffffll, 63));
+
+#endif
+
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(-25, 12), 11);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-24, 12), 0);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-23, 12), 1);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-8, 7), 6);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-7, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-6, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-5, 7), 2);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-4, 7), 3);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-3, 7), 4);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-2, 7), 5);
+	VERIFY_EQUAL(mpt::wrapping_modulo(-1, 7), 6);
+	VERIFY_EQUAL(mpt::wrapping_modulo(0, 12), 0);
+	VERIFY_EQUAL(mpt::wrapping_modulo(0, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_modulo(1, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_modulo(2, 7), 2);
+	VERIFY_EQUAL(mpt::wrapping_modulo(3, 7), 3);
+	VERIFY_EQUAL(mpt::wrapping_modulo(4, 7), 4);
+	VERIFY_EQUAL(mpt::wrapping_modulo(5, 7), 5);
+	VERIFY_EQUAL(mpt::wrapping_modulo(6, 7), 6);
+	VERIFY_EQUAL(mpt::wrapping_modulo(7, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_modulo(8, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_modulo(23, 12), 11);
+	VERIFY_EQUAL(mpt::wrapping_modulo(24, 12), 0);
+	VERIFY_EQUAL(mpt::wrapping_modulo(25, 12), 1);
+	VERIFY_EQUAL(mpt::wrapping_modulo(uint32(0x7fffffff), uint32(0x80000000)), uint32(0x7fffffff));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(0x7ffffffe), int32(0x7fffffff)), int32(0x7ffffffe));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(1)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(2)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(1)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), int32(2)), int32(1));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(1)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), int32(2)), int32(0));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(0x7fffffff)), int32(0x7ffffffe));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , int32(0x7fffffff)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , int32(0x7fffffff)), int32(1));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(0x7ffffffe)), int32(0x7ffffffc));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , int32(0x7ffffffe)), int32(0x7ffffffd));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , int32(0x7ffffffe)), int32(0));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), int32(0x7ffffffd)), int32(0x7ffffffa));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , int32(0x7ffffffd)), int32(0x7ffffffb));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , int32(0x7ffffffd)), int32(0x7ffffffc));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(0) , int32(0x7fffffff)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-1), int32(0x7fffffff)), int32(0x7ffffffe));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-2), int32(0x7fffffff)), int32(0x7ffffffd));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(0) , int32(0x7ffffffe)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-1), int32(0x7ffffffe)), int32(0x7ffffffd));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-2), int32(0x7ffffffe)), int32(0x7ffffffc));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(1)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(2)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(1)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff), uint32(2)), int32(1));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(1)), int32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe), uint32(2)), int32(0));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x40000001)  , uint32(0xffffffff)), uint32(0xbffffffe));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x40000000)  , uint32(0xffffffff)), uint32(0xbfffffff));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x3fffffff)  , uint32(0xffffffff)), uint32(0xc0000000));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x80000000)), uint32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , uint32(0x80000000)), uint32(1));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , uint32(0x80000000)), uint32(2));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x80000001)), uint32(1));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , uint32(0x80000001)), uint32(2));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , uint32(0x80000001)), uint32(3));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x80000000)), uint32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , uint32(0x80000000)), uint32(1));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , uint32(0x80000000)), uint32(2));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x7fffffff)), uint32(0x7ffffffe));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , uint32(0x7fffffff)), uint32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , uint32(0x7fffffff)), uint32(1));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x7ffffffe)), uint32(0x7ffffffc));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , uint32(0x7ffffffe)), uint32(0x7ffffffd));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , uint32(0x7ffffffe)), uint32(0));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x80000000ll), uint32(0x7ffffffd)), uint32(0x7ffffffa));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7fffffff)  , uint32(0x7ffffffd)), uint32(0x7ffffffb));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-0x7ffffffe)  , uint32(0x7ffffffd)), uint32(0x7ffffffc));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(0) , uint32(0x7fffffff)), uint32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-1), uint32(0x7fffffff)), uint32(0x7ffffffe));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-2), uint32(0x7fffffff)), uint32(0x7ffffffd));
+
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(0) , uint32(0x7ffffffe)), uint32(0));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-1), uint32(0x7ffffffe)), uint32(0x7ffffffd));
+	VERIFY_EQUAL(mpt::wrapping_modulo(int32(-2), uint32(0x7ffffffe)), uint32(0x7ffffffc));
+
+	VERIFY_EQUAL(mpt::wrapping_divide(-15, 7), -3);
+	VERIFY_EQUAL(mpt::wrapping_divide(-14, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-13, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-12, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-11, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-10, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-9, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-8, 7), -2);
+	VERIFY_EQUAL(mpt::wrapping_divide(-7, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(-6, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(-5, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(-4, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(-3, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(-2, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(-1, 7), -1);
+	VERIFY_EQUAL(mpt::wrapping_divide(0, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(1, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(2, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(3, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(4, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(5, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(6, 7), 0);
+	VERIFY_EQUAL(mpt::wrapping_divide(7, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(8, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(9, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(10, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(11, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(12, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(13, 7), 1);
+	VERIFY_EQUAL(mpt::wrapping_divide(14, 7), 2);
+	VERIFY_EQUAL(mpt::wrapping_divide(15, 7), 2);
+
+}
+
+
+static MPT_NOINLINE void TestMisc2()
+{
+
 	VERIFY_EQUAL( mpt::String::LTrim(std::string(" ")), "" );
 	VERIFY_EQUAL( mpt::String::RTrim(std::string(" ")), "" );
 	VERIFY_EQUAL( mpt::String::Trim(std::string(" ")), "" );
@@ -775,29 +1246,135 @@ static MPT_NOINLINE void TestMisc()
 	//VERIFY_EQUAL( Util::Round<int8>(-129), 0 );
 
 	// Check for completeness of supported effect list in mod specifications
-	for(size_t i = 0; i < CountOf(ModSpecs::Collection); i++)
+	for(const auto &spec : ModSpecs::Collection)
 	{
-		VERIFY_EQUAL(strlen(ModSpecs::Collection[i]->commands), (size_t)MAX_EFFECTS);
-		VERIFY_EQUAL(strlen(ModSpecs::Collection[i]->volcommands), (size_t)MAX_VOLCMDS);
+		VERIFY_EQUAL(strlen(spec->commands), (size_t)MAX_EFFECTS);
+		VERIFY_EQUAL(strlen(spec->volcommands), (size_t)MAX_VOLCMDS);
 	}
 
 	// UUID
-#ifdef MODPLUG_TRACKER
+	{
+		VERIFY_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull).ToUString(), MPT_USTRING("2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32"));
+		#if defined(MODPLUG_TRACKER) || !defined(NO_DMO)
+			VERIFY_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), MPT_UUID(2ed6593a,dfe6,4cf8,b2e5,75ad7f600c32));
+			VERIFY_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), mpt::UUID(Util::StringToGUID(L"{2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32}")));
+			VERIFY_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), mpt::UUID(Util::StringToCLSID(L"{2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32}")));
+		#endif
+
+#if defined(MODPLUG_TRACKER) || !defined(NO_DMO)
 	VERIFY_EQUAL(Util::IsValid(Util::CreateGUID()), true);
-	UUID uuid = mpt::UUID::Generate();
-	VERIFY_EQUAL(IsEqualUUID(uuid, mpt::UUID::FromString(mpt::UUID(uuid).ToUString())), true);
-	VERIFY_EQUAL(IsEqualUUID(uuid, Util::StringToUUID(Util::UUIDToString(uuid))), true);
-	VERIFY_EQUAL(IsEqualUUID(uuid, Util::StringToGUID(Util::GUIDToString(uuid))), true);
-	VERIFY_EQUAL(IsEqualUUID(uuid, Util::StringToIID(Util::IIDToString(uuid))), true);
-	VERIFY_EQUAL(IsEqualUUID(uuid, Util::StringToCLSID(Util::CLSIDToString(uuid))), true);
+	{
+		mpt::UUID uuid = mpt::UUID::Generate();
+		VERIFY_EQUAL(uuid, mpt::UUID::FromString(mpt::UUID(uuid).ToUString()));
+		VERIFY_EQUAL(uuid, mpt::UUID(Util::StringToUUID(Util::UUIDToString(uuid))));
+		VERIFY_EQUAL(uuid, mpt::UUID(Util::StringToGUID(Util::GUIDToString(uuid))));
+		VERIFY_EQUAL(uuid, mpt::UUID(Util::StringToIID(Util::IIDToString(uuid))));
+		VERIFY_EQUAL(uuid, mpt::UUID(Util::StringToCLSID(Util::CLSIDToString(uuid))));
+	}
+	{
+		GUID guid = mpt::UUID::Generate();
+		VERIFY_EQUAL(IsEqualGUID(guid, static_cast<GUID>(mpt::UUID::FromString(mpt::UUID(guid).ToUString()))), TRUE);
+		VERIFY_EQUAL(IsEqualGUID(guid, Util::StringToUUID(Util::UUIDToString(guid))), TRUE);
+		VERIFY_EQUAL(IsEqualGUID(guid, Util::StringToGUID(Util::GUIDToString(guid))), TRUE);
+		VERIFY_EQUAL(IsEqualGUID(guid, Util::StringToIID(Util::IIDToString(guid))), TRUE);
+		VERIFY_EQUAL(IsEqualGUID(guid, Util::StringToCLSID(Util::CLSIDToString(guid))), TRUE);
+	}
 #endif
 	VERIFY_EQUAL(mpt::UUID::Generate().IsValid(), true);
 	VERIFY_EQUAL(mpt::UUID::GenerateLocalUseOnly().IsValid(), true);
 	VERIFY_EQUAL(mpt::UUID::Generate() != mpt::UUID::Generate(), true);
 	mpt::UUID a = mpt::UUID::Generate();
 	VERIFY_EQUAL(a, mpt::UUID::FromString(a.ToUString()));
+	mpt::byte uuiddata[16];
+	for(std::size_t i = 0; i < 16; ++i)
+	{
+		uuiddata[i] = static_cast<uint8>(i);
+	}
+	STATIC_ASSERT(sizeof(mpt::UUID) == 16);
+	mpt::UUID uuid2;
+	std::memcpy(&uuid2, uuiddata, 16);
+	VERIFY_EQUAL(uuid2.ToString(), std::string("00010203-0405-0607-0809-0a0b0c0d0e0f"));
+	}
+
+	// check that empty stringstream behaves correctly with our MSVC workarounds when using iostream interface directly
+
+	{ mpt::ostringstream ss; VERIFY_EQUAL(ss.tellp(), std::streampos(0)); }
+	{ mpt::ostringstream ss; ss.seekp(0); VERIFY_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); }
+	{ mpt::ostringstream ss; ss.seekp(0, std::ios_base::beg); VERIFY_EQUAL(!ss.fail(), true); }
+	{ mpt::ostringstream ss; ss.seekp(0, std::ios_base::cur); VERIFY_EQUAL(!ss.fail(), true); }
+	{ mpt::istringstream ss; VERIFY_EQUAL(ss.tellg(), std::streampos(0)); }
+	{ mpt::istringstream ss; ss.seekg(0); VERIFY_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); }
+	{ mpt::istringstream ss; ss.seekg(0, std::ios_base::beg); VERIFY_EQUAL(!ss.fail(), true); }
+	{ mpt::istringstream ss; ss.seekg(0, std::ios_base::cur); VERIFY_EQUAL(!ss.fail(), true); }
+
+	{
+		mpt::ostringstream s;
+		char b = 23;
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellp(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekp(0, std::ios_base::beg);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellp(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.write(&b, 1);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellp(), std::streampos(1));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekp(0, std::ios_base::beg);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellp(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekp(0, std::ios_base::end);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellp(), std::streampos(1));
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.str(), std::string(1, b));
+	}
+
+	{
+		mpt::istringstream s;
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekg(0, std::ios_base::beg);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekg(0, std::ios_base::end);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+	}
+
+	{
+		mpt::istringstream s("a");
+		char a = 0;
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekg(0, std::ios_base::beg);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.read(&a, 1);
+		VERIFY_EQUAL(a, 'a');
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(1));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekg(0, std::ios_base::beg);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(0));
+		VERIFY_EQUAL(!s.fail(), true);
+		s.seekg(0, std::ios_base::end);
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(s.tellg(), std::streampos(1));
+		VERIFY_EQUAL(!s.fail(), true);
+		VERIFY_EQUAL(std::string(1, a), std::string(1, 'a'));
+	}
+
+	// check that empty native and fixed stringstream both behaves correctly with out IO functions
 
-	// check that empty stringstream behaves correctly with our MSVC workarounds
 	{ mpt::ostringstream ss; VERIFY_EQUAL(mpt::IO::TellWrite(ss), 0); }
 	{ mpt::ostringstream ss; VERIFY_EQUAL(mpt::IO::SeekBegin(ss), true); }
 	{ mpt::ostringstream ss; VERIFY_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); }
@@ -878,7 +1455,7 @@ static MPT_NOINLINE void TestMisc()
 		VERIFY_EQUAL(mpt::IO::IsValid(s), true);
 		VERIFY_EQUAL(mpt::IO::TellRead(s), 1);
 		VERIFY_EQUAL(mpt::IO::IsValid(s), true);
-		VERIFY_EQUAL(a, 'a');
+		VERIFY_EQUAL(std::string(1, a), std::string(1, 'a'));
 	}
 
 	{
@@ -943,9 +1520,33 @@ static MPT_NOINLINE void TestMisc()
 		VERIFY_EQUAL(mpt::IO::IsValid(s), true);
 		VERIFY_EQUAL(mpt::IO::TellRead(s), 1);
 		VERIFY_EQUAL(mpt::IO::IsValid(s), true);
-		VERIFY_EQUAL(a, 'a');
+		VERIFY_EQUAL(std::string(1, a), std::string(1, 'a'));
 	}
 
+#ifdef MPT_ENABLE_FILEIO
+
+	{
+		std::vector<mpt::byte> data;
+		data.push_back(0);
+		data.push_back(255);
+		data.push_back(1);
+		data.push_back(2);
+		mpt::PathString fn = GetTempFilenameBase() + MPT_PATHSTRING("lazy");
+		RemoveFile(fn);
+		mpt::LazyFileRef f(fn);
+		f = data;
+		std::vector<mpt::byte> data2;
+		data2 = f;
+		VERIFY_EQUAL(data.size(), data2.size());
+		for(std::size_t i = 0; i < data.size() && i < data2.size(); ++i)
+		{
+			VERIFY_EQUAL(data[i], data2[i]);
+		}
+		RemoveFile(fn);
+	}
+
+#endif
+
 #ifdef MPT_WITH_ZLIB
 	VERIFY_EQUAL(crc32(0, mpt::byte_cast<const unsigned char*>(std::string("123456789").c_str()), 9), 0xCBF43926u);
 #endif
@@ -973,6 +1574,49 @@ static MPT_NOINLINE void TestMisc()
 		for(int32 finetune = -128; finetune < 128; finetune += 64, freqIndex++)
 			VERIFY_EQUAL_EPS(transposeToFrequency[freqIndex], static_cast<int32>(ModSample::TransposeToFrequency(transpose, finetune)), 1);
 
+	{
+		ModSample smp;
+		smp.nC5Speed = 9999;
+		smp.Transpose(1.5);
+		VERIFY_EQUAL_EPS(28281, static_cast<int32>(smp.nC5Speed), 1);
+		smp.Transpose(-1.3);
+		VERIFY_EQUAL_EPS(11486, static_cast<int32>(smp.nC5Speed), 1);
+	}
+
+	// Check SamplePosition fixed-point type
+	VERIFY_EQUAL(SamplePosition(1).GetRaw(), 1);
+	VERIFY_EQUAL(SamplePosition(2).Set(1), SamplePosition(1, 0));
+	VERIFY_EQUAL(SamplePosition(2).SetInt(1), SamplePosition(1, 2));
+	VERIFY_EQUAL(SamplePosition(1).IsPositive(), true);
+	VERIFY_EQUAL(SamplePosition(0).IsZero(), true);
+	VERIFY_EQUAL(SamplePosition(1, 0).IsUnity(), true);
+	VERIFY_EQUAL(SamplePosition(1, 1).IsUnity(), false);
+	VERIFY_EQUAL(SamplePosition(-1).IsNegative(), true);
+	VERIFY_EQUAL(SamplePosition(int64_max).GetRaw(), int64_max);
+	VERIFY_EQUAL(SamplePosition(2, SamplePosition::fractMax).GetInt(), 2);
+	VERIFY_EQUAL(SamplePosition(2, SamplePosition::fractMax).GetFract(), SamplePosition::GetFractMax());
+	VERIFY_EQUAL(SamplePosition(1, SamplePosition::fractMax).GetInvertedFract(), SamplePosition(0, 1));
+	VERIFY_EQUAL(SamplePosition(1, 0).GetInvertedFract(), SamplePosition(1, 0));
+	VERIFY_EQUAL(SamplePosition(2, 0).Negate(), SamplePosition(-2, 0));
+	VERIFY_EQUAL(SamplePosition::Ratio(10, 5), SamplePosition(2, 0));
+	VERIFY_EQUAL(SamplePosition(1, 1) + SamplePosition(2, 2), SamplePosition(3, 3));
+	VERIFY_EQUAL(SamplePosition(1, 0) * 3, SamplePosition(3, 0));
+	VERIFY_EQUAL((SamplePosition(6, 0) / SamplePosition(2, 0)), 3);
+	
+	VERIFY_EQUAL(srlztn::ID::FromInt(static_cast<uint32>(0x87654321u)).AsString(), srlztn::ID("\x21\x43\x65\x87").AsString());
+
+#if defined(MODPLUG_TRACKER)
+
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("1.1.44" )).AsString() , MPT_USTRING("1.1.44"));
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("1.6.2"  )).AsString() , MPT_USTRING("1.6.2" ));
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("1.8"    )).AsString() , MPT_USTRING("1.8.0" ));
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("2.0-rc" )).AsString() , MPT_USTRING("2.0.0" ));
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("2.0-rc4")).AsString() , MPT_USTRING("2.0.0" ));
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("2.0"    )).AsString() , MPT_USTRING("2.0.0" ));
+	VERIFY_EQUAL(mpt::Wine::Version(MPT_USTRING("2.4"    )).AsString() , MPT_USTRING("2.4.0" ));
+
+#endif // MODPLUG_TRACKER
+
 	// date
 
 	VERIFY_EQUAL(             0, TestDate1(  0,  0,  0,  1,  1, 1970 ));
@@ -1029,7 +1673,6 @@ static MPT_NOINLINE void TestMisc()
 
 
 static MPT_NOINLINE void TestRandom()
-//-----------------------------------
 {
 	mpt::prng & prng = *s_PRNG;
 	for(std::size_t i = 0; i < 10000; ++i)
@@ -1107,7 +1750,6 @@ static MPT_NOINLINE void TestRandom()
 
 
 static MPT_NOINLINE void TestCharsets()
-//-------------------------------------
 {
 
 	// MPT_UTF8 version
@@ -1427,6 +2069,22 @@ static MPT_NOINLINE void TestCharsets()
 	VERIFY_EQUAL(MPT_PATHSTRING("\\foo").RelativePathToAbsolute(exePath), MPT_PATHSTRING("C:\\foo"));
 	VERIFY_EQUAL(MPT_PATHSTRING("\\\\server\\path\\file").AbsolutePathToRelative(exePath), MPT_PATHSTRING("\\\\server\\path\\file"));
 	VERIFY_EQUAL(MPT_PATHSTRING("\\\\server\\path\\file").RelativePathToAbsolute(exePath), MPT_PATHSTRING("\\\\server\\path\\file"));
+
+	VERIFY_EQUAL(MPT_PATHSTRING("").Simplify(), MPT_PATHSTRING(""));
+	VERIFY_EQUAL(MPT_PATHSTRING(" ").Simplify(), MPT_PATHSTRING(" "));
+	VERIFY_EQUAL(MPT_PATHSTRING("foo\\bar").Simplify(), MPT_PATHSTRING("foo\\bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING(".\\foo\\bar").Simplify(), MPT_PATHSTRING(".\\foo\\bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING(".\\\\foo\\bar").Simplify(), MPT_PATHSTRING(".\\foo\\bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING("./\\foo\\bar").Simplify(), MPT_PATHSTRING(".\\foo\\bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING("\\foo\\bar").Simplify(), MPT_PATHSTRING("\\foo\\bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING("A:\\name_1\\.\\name_2\\..\\name_3\\").Simplify(), MPT_PATHSTRING("A:\\name_1\\name_3"));
+	VERIFY_EQUAL(MPT_PATHSTRING("A:\\name_1\\..\\name_2\\./name_3").Simplify(), MPT_PATHSTRING("A:\\name_2\\name_3"));
+	VERIFY_EQUAL(MPT_PATHSTRING("A:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..").Simplify(), MPT_PATHSTRING("A:\\name_1\\name_2"));
+	VERIFY_EQUAL(MPT_PATHSTRING("A:foo\\\\bar").Simplify(), MPT_PATHSTRING("A:\\foo\\bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING("C:\\..").Simplify(), MPT_PATHSTRING("C:\\"));
+	VERIFY_EQUAL(MPT_PATHSTRING("C:\\.").Simplify(), MPT_PATHSTRING("C:\\"));
+	VERIFY_EQUAL(MPT_PATHSTRING("\\\\foo\\..\\.bar").Simplify(), MPT_PATHSTRING("\\\\.bar"));
+	VERIFY_EQUAL(MPT_PATHSTRING("\\\\foo\\..\\..\\bar").Simplify(), MPT_PATHSTRING("\\\\bar"));
 #endif
 
 
@@ -1526,32 +2184,6 @@ static MPT_NOINLINE void TestCharsets()
 #endif
 
 
-
-#if defined(MODPLUG_TRACKER)
-
-	VERIFY_EQUAL(mpt::strnicmp("f", "f", 6) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("f", "F", 6) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("F", "f", 6) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("f", "g", 6) < 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("h", "g", 6) > 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("fgh", "FgH", 6) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("012345678", "012345678", 9) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("", "012345678", 9) < 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "", 6) > 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "F", 6) > 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "Fg", 6) > 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "fg", 6) > 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("0123456789", "FgH", 0) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "fgh", 1) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "fgh", 2) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "fgh", 3) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "fghi", 3) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FgH", "fghi", 4) < 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FIH", "fghi", 1) == 0, true);
-	VERIFY_EQUAL(mpt::strnicmp("FIH", "fghi", 2) > 0, true);
-
-#endif // MODPLUG_TRACKER
-
 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("f", "f", 6) == 0, true);
 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("f", "F", 6) == 0, true);
 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("F", "f", 6) == 0, true);
@@ -1606,7 +2238,7 @@ inline Test::CustomSettingsTestType FromSettingValue(const SettingValue &val)
 template <>
 inline SettingValue ToSettingValue(const Test::CustomSettingsTestType &val)
 {
-	return SettingValue(mpt::ToString(val.x) + "|" + mpt::ToString(val.y), "myType");
+	return SettingValue(mpt::fmt::val(val.x) + "|" + mpt::fmt::val(val.y), "myType");
 }
 
 namespace Test {
@@ -1614,7 +2246,6 @@ namespace Test {
 #endif // MODPLUG_TRACKER
 
 static MPT_NOINLINE void TestSettings()
-//-------------------------------------
 {
 
 #ifdef MODPLUG_TRACKER
@@ -1694,7 +2325,6 @@ static MPT_NOINLINE void TestSettings()
 
 // Test MIDI Event generating / reading
 static MPT_NOINLINE void TestMIDIEvents()
-//---------------------------------------
 {
 	uint32 midiEvent;
 
@@ -1738,10 +2368,11 @@ static MPT_NOINLINE void TestMIDIEvents()
 
 // Check if our test file was loaded correctly.
 static void TestLoadXMFile(const CSoundFile &sndFile)
-//---------------------------------------------------
 {
 #ifdef MODPLUG_TRACKER
 	const CModDoc *pModDoc = sndFile.GetpModDoc();
+	VERIFY_EQUAL_NONCONT(pModDoc->IsChannelUnused(0), true);
+	VERIFY_EQUAL_NONCONT(pModDoc->IsChannelUnused(1), false);
 #endif // MODPLUG_TRACKER
 
 	// Global Variables
@@ -1752,7 +2383,7 @@ static void TestLoadXMFile(const CSoundFile &sndFile)
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 128);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 42);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 23);
-	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_EMBEDMIDICFG | SONG_LINEARSLIDES | SONG_EXFILTERRANGE);
+	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_LINEARSLIDES | SONG_EXFILTERRANGE);
 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[MSF_COMPATIBLE_PLAY], true);
 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMIDICCBugEmulation], false);
 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMPTOldSwingBehaviour], false);
@@ -1762,7 +2393,7 @@ static void TestLoadXMFile(const CSoundFile &sndFile)
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MAKE_VERSION_NUMERIC(1, 19, 02, 05));
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetRestartPos(), 1);
+	VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 1);
 
 	// Macros
 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetParameteredMacroType(0), sfx_reso);
@@ -1887,8 +2518,8 @@ static void TestLoadXMFile(const CSoundFile &sndFile)
 
 	// Sequences
 	VERIFY_EQUAL_NONCONT(sndFile.Order.GetNumSequences(), 1);
-	VERIFY_EQUAL_NONCONT(sndFile.Order[0], 0);
-	VERIFY_EQUAL_NONCONT(sndFile.Order[1], 1);
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[0], 0);
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[1], 1);
 
 	// Patterns
 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 2);
@@ -1942,7 +2573,6 @@ static void TestLoadXMFile(const CSoundFile &sndFile)
 
 // Check if our test file was loaded correctly.
 static void TestLoadMPTMFile(const CSoundFile &sndFile)
-//-----------------------------------------------------
 {
 
 	// Global Variables
@@ -1953,7 +2583,7 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile)
 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 128);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 42);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 23);
-	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_EMBEDMIDICFG | SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS);
+	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS);
 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[MSF_COMPATIBLE_PLAY], true);
 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMIDICCBugEmulation], false);
 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMPTOldSwingBehaviour], false);
@@ -2186,19 +2816,19 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile)
 	// Sequences
 	VERIFY_EQUAL_NONCONT(sndFile.Order.GetNumSequences(), 2);
 
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(0).GetLengthTailTrimmed(), 3);
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(0).GetName(), "First Sequence");
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(0)[0], sndFile.Order.GetIgnoreIndex());
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(0)[1], 0);
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(0)[2], sndFile.Order.GetIgnoreIndex());
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(0).GetRestartPos(), 1);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(0).GetLengthTailTrimmed(), 3);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(0).GetName(), "First Sequence");
+	VERIFY_EQUAL_NONCONT(sndFile.Order(0)[0], sndFile.Order.GetIgnoreIndex());
+	VERIFY_EQUAL_NONCONT(sndFile.Order(0)[1], 0);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(0)[2], sndFile.Order.GetIgnoreIndex());
+	VERIFY_EQUAL_NONCONT(sndFile.Order(0).GetRestartPos(), 1);
 
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(1).GetLengthTailTrimmed(), 3);
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(1).GetName(), "Second Sequence");
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(1)[0], 1);
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(1)[1], 2);
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(1)[2], 3);
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetSequence(1).GetRestartPos(), 2);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(1).GetLengthTailTrimmed(), 3);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(1).GetName(), "Second Sequence");
+	VERIFY_EQUAL_NONCONT(sndFile.Order(1)[0], 1);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(1)[1], 2);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(1)[2], 3);
+	VERIFY_EQUAL_NONCONT(sndFile.Order(1).GetRestartPos(), 2);
 
 	// Patterns
 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 2);
@@ -2273,12 +2903,14 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile)
 	VERIFY_EQUAL_NONCONT(mapping.GetController(), MIDIEvents::MIDICC_ModulationWheel_Coarse);
 #endif
 
+	VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(0)), 0);
+	VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(80)), 80);
+	VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(127)), 127);
 }
 
 
 // Check if our test file was loaded correctly.
 static void TestLoadS3MFile(const CSoundFile &sndFile, bool resaved)
-//------------------------------------------------------------------
 {
 
 	// Global Variables
@@ -2292,7 +2924,7 @@ static void TestLoadS3MFile(const CSoundFile &sndFile, bool resaved)
 	VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), mixLevelsCompatible);
 	VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, tempoModeClassic);
 	VERIFY_EQUAL_NONCONT(sndFile.m_dwLastSavedWithVersion, resaved ? (MptVersion::num & 0xFFFF0000) : MAKE_VERSION_NUMERIC(1, 20, 00, 00));
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetRestartPos(), 0);
+	VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 0);
 
 	// Channels
 	VERIFY_EQUAL_NONCONT(sndFile.GetNumChannels(), 4);
@@ -2367,12 +2999,12 @@ static void TestLoadS3MFile(const CSoundFile &sndFile, bool resaved)
 	}
 
 	// Orders
-	VERIFY_EQUAL_NONCONT(sndFile.Order.GetLengthTailTrimmed(), 5);
-	VERIFY_EQUAL_NONCONT(sndFile.Order[0], 0);
-	VERIFY_EQUAL_NONCONT(sndFile.Order[1], sndFile.Order.GetIgnoreIndex());
-	VERIFY_EQUAL_NONCONT(sndFile.Order[2], sndFile.Order.GetInvalidPatIndex());
-	VERIFY_EQUAL_NONCONT(sndFile.Order[3], 1);
-	VERIFY_EQUAL_NONCONT(sndFile.Order[4], 0);
+	VERIFY_EQUAL_NONCONT(sndFile.Order().GetLengthTailTrimmed(), 5);
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[0], 0);
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[1], sndFile.Order.GetIgnoreIndex());
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[2], sndFile.Order.GetInvalidPatIndex());
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[3], 1);
+	VERIFY_EQUAL_NONCONT(sndFile.Order()[4], 0);
 
 	// Patterns
 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 2);
@@ -2402,26 +3034,21 @@ static void TestLoadS3MFile(const CSoundFile &sndFile, bool resaved)
 
 #ifdef MODPLUG_TRACKER
 
-static const char * debugPaths [] = { "mptrack\\Debug\\", "bin\\Win32-Debug\\", "bin\\x64-Debug\\" };
-
-static bool PathEndsIn(const mpt::PathString &path_, const mpt::PathString &match_)
-{
-	std::wstring path = path_.ToWide();
-	std::wstring match = match_.ToWide();
-	return path.rfind(match) == (path.length() - match.length());
-}
-
 static bool ShouldRunTests()
 {
 	mpt::PathString theFile = theApp.GetAppDirPath();
 	// Only run the tests when we're in the project directory structure.
-	for(std::size_t i = 0; i < CountOf(debugPaths); ++i)
+	std::size_t pathComponents = mpt::String::Split<mpt::ustring>(theFile.ToUnicode(), MPT_USTRING("\\")).size() - 1;
+	for(std::size_t i = 0; i < pathComponents; ++i)
 	{
-		const mpt::PathString debugPath = mpt::PathString::FromUTF8(debugPaths[i]);
-		if(PathEndsIn(theFile, debugPath))
+		if(theFile.IsDirectory() && (theFile + MPT_PATHSTRING("test")).IsDirectory())
 		{
-			return true;
+			if((theFile + MPT_PATHSTRING("test\\test.mptm")).IsFile())
+			{
+				return true;
+			}
 		}
+		theFile += MPT_PATHSTRING("..\\");
 	}
 	return false;
 }
@@ -2429,14 +3056,17 @@ static bool ShouldRunTests()
 static mpt::PathString GetTestFilenameBase()
 {
 	mpt::PathString theFile = theApp.GetAppDirPath();
-	for(std::size_t i = 0; i < CountOf(debugPaths); ++i)
+	std::size_t pathComponents = mpt::String::Split<mpt::ustring>(theFile.ToUnicode(), MPT_USTRING("\\")).size() - 1;
+	for(std::size_t i = 0; i < pathComponents; ++i)
 	{
-		const mpt::PathString debugPath = mpt::PathString::FromUTF8(debugPaths[i]);
-		if(PathEndsIn(theFile, debugPath))
+		if(theFile.IsDirectory() && (theFile + MPT_PATHSTRING("test")).IsDirectory())
 		{
-			theFile = mpt::PathString::FromWide(theFile.ToWide().substr(0, theFile.ToWide().length() - debugPath.ToWide().length()));
-			break;
+			if((theFile + MPT_PATHSTRING("test\\test.mptm")).IsFile())
+			{
+				break;
+			}
 		}
+		theFile += MPT_PATHSTRING("..\\");
 	}
 	theFile += MPT_PATHSTRING("test/test.");
 	return theFile;
@@ -2504,7 +3134,7 @@ static mpt::PathString GetTempFilenameBase()
 	return MPT_PATHSTRING("./test.");
 }
 
-typedef MPT_SHARED_PTR<CSoundFile> TSoundFileContainer;
+typedef std::shared_ptr<CSoundFile> TSoundFileContainer;
 
 static CSoundFile &GetrSoundFile(TSoundFileContainer &sndFile)
 {
@@ -2514,8 +3144,8 @@ static CSoundFile &GetrSoundFile(TSoundFileContainer &sndFile)
 static TSoundFileContainer CreateSoundFileContainer(const mpt::PathString &filename)
 {
 	mpt::ifstream stream(filename, std::ios::binary);
-	FileReader file(&stream);
-	MPT_SHARED_PTR<CSoundFile> pSndFile = mpt::make_shared<CSoundFile>();
+	FileReader file = make_FileReader(&stream);
+	std::shared_ptr<CSoundFile> pSndFile = std::make_shared<CSoundFile>();
 	pSndFile->Create(file, CSoundFile::loadCompleteModule);
 	return pSndFile;
 }
@@ -2550,12 +3180,17 @@ static void SaveS3M(const TSoundFileContainer &sndFile, const mpt::PathString &f
 
 // Test file loading and saving
 static MPT_NOINLINE void TestLoadSaveFile()
-//-----------------------------------------
 {
 	if(!ShouldRunTests())
 	{
 		return;
 	}
+
+#ifdef MODPLUG_TRACKER
+	bool saveMutedChannels = TrackerSettings::Instance().MiscSaveChannelMuteStatus;
+	TrackerSettings::Instance().MiscSaveChannelMuteStatus = true;
+#endif
+
 	mpt::PathString filenameBaseSrc = GetTestFilenameBase();
 	mpt::PathString filenameBase = GetTempFilenameBase();
 
@@ -2673,17 +3308,102 @@ static MPT_NOINLINE void TestLoadSaveFile()
 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 65535);
 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 0xFFFFFFFFFFFFFFFFull);
 	}
+	{
+		// Verify that writing arrays does not confuse the compiler.
+		// This is both, compile-time and run-time cheking.
+		// Run-time in case some weird compiler gets confused by our templates
+		// and only writes the first array element.
+		mpt::ostringstream f;
+		uint16be data[2];
+		data[0] = 0x1234;
+		data[1] = 0x5678;
+		mpt::IO::Write(f, data);
+		VERIFY_EQUAL(f.str(), std::string("\x12\x34\x56\x78"));
+	}
+
+#ifdef MODPLUG_TRACKER
+	TrackerSettings::Instance().MiscSaveChannelMuteStatus = saveMutedChannels;
+#endif
+}
+
+
+// Test various editing features
+static MPT_NOINLINE void TestEditing()
+{
+#ifdef MODPLUG_TRACKER
+	auto modDoc = static_cast<CModDoc *>(theApp.GetModDocTemplate()->CreateNewDocument());
+	auto &sndFile = modDoc->GetrSoundFile();
+	sndFile.Create(FileReader(), CSoundFile::loadCompleteModule, modDoc);
+	sndFile.m_nChannels = 4;
+	sndFile.ChangeModTypeTo(MOD_TYPE_MPT);
+
+	// Rearrange channels
+	sndFile.Patterns.ResizeArray(2);
+	sndFile.Patterns.Insert(0, 32);
+	sndFile.Patterns.Insert(1, 48);
+	sndFile.Patterns[1].SetName("Pattern");
+	sndFile.Patterns[1].SetSignature(2, 4);
+	TempoSwing swing;
+	swing.resize(2);
+	sndFile.Patterns[1].SetTempoSwing(swing);
+	sndFile.Patterns[1].GetpModCommand(37, 0)->instr = 1;
+	sndFile.Patterns[1].GetpModCommand(37, 1)->instr = 2;
+	sndFile.Patterns[1].GetpModCommand(37, 2)->instr = 3;
+	sndFile.Patterns[1].GetpModCommand(37, 3)->instr = 4;
+	modDoc->ReArrangeChannels({ 3, 2, CHANNELINDEX_INVALID, 0 });
+	modDoc->ReArrangeChannels({ 0, 1, 1, CHANNELINDEX_INVALID, 3 });
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetName(), "Pattern");
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerBeat(), 2);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerMeasure(), 4);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetTempoSwing(), swing);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 0)->instr, 4);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 1)->instr, 3);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 2)->instr, 3);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 3)->instr, 0);
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 1);
+
+	// Rearrange samples
+	sndFile.m_nSamples = 2;
+	mpt::String::Copy(sndFile.GetSample(1).filename, "1");
+	mpt::String::Copy(sndFile.m_szNames[1], "1");
+	mpt::String::Copy(sndFile.GetSample(2).filename, "2");
+	mpt::String::Copy(sndFile.m_szNames[2], "2");
+	sndFile.GetSample(2).nLength = 16;
+	sndFile.GetSample(2).AllocateSample();
+	modDoc->ReArrangeSamples({ 2, SAMPLEINDEX_INVALID, 1 });
+	VERIFY_EQUAL_NONCONT(sndFile.GetSample(1).pSample != nullptr, true);
+	VERIFY_EQUAL_NONCONT(sndFile.GetSample(1).filename, std::string("2"));
+	VERIFY_EQUAL_NONCONT(sndFile.m_szNames[1], std::string("2"));
+	VERIFY_EQUAL_NONCONT(sndFile.GetSample(2).filename, std::string());
+	VERIFY_EQUAL_NONCONT(sndFile.m_szNames[2], std::string());
+	VERIFY_EQUAL_NONCONT(sndFile.GetSample(3).filename, std::string("1"));
+	VERIFY_EQUAL_NONCONT(sndFile.m_szNames[3], std::string("1"));
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 3);
+
+	// Convert / rearrange instruments
+	modDoc->ConvertSamplesToInstruments();
+	modDoc->ReArrangeInstruments({ INSTRUMENTINDEX_INVALID, 2, 1, 3 });
+	VERIFY_EQUAL_NONCONT(sndFile.Instruments[1]->name, std::string());
+	VERIFY_EQUAL_NONCONT(sndFile.Instruments[2]->name, std::string());
+	VERIFY_EQUAL_NONCONT(sndFile.Instruments[3]->name, std::string("2"));
+	VERIFY_EQUAL_NONCONT(sndFile.Instruments[4]->name, std::string("1"));
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 4);
+	modDoc->ConvertInstrumentsToSamples();
+	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 3);
+
+	sndFile.Destroy();
+	modDoc->OnCloseDocument();
+#endif
 }
 
 
 static void RunITCompressionTest(const std::vector<int8> &sampleData, FlagSet<ChannelFlags> smpFormat, bool it215)
-//----------------------------------------------------------------------------------------------------------------
 {
 
 	ModSample smp;
 	smp.uFlags = smpFormat;
-	smp.pSample = const_cast<int8 *>(&sampleData[0]);
-	smp.nLength = sampleData.size() / smp.GetBytesPerSample();
+	smp.pSample = const_cast<int8 *>(sampleData.data());
+	smp.nLength = mpt::saturate_cast<SmpLength>(sampleData.size() / smp.GetBytesPerSample());
 
 	std::string data;
 
@@ -2697,16 +3417,15 @@ static void RunITCompressionTest(const std::vector<int8> &sampleData, FlagSet<Ch
 		FileReader file(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(data)));
 
 		std::vector<int8> sampleDataNew(sampleData.size(), 0);
-		smp.pSample = &sampleDataNew[0];
+		smp.pSample = sampleDataNew.data();
 
 		ITDecompression decompression(file, smp, it215);
-		VERIFY_EQUAL_NONCONT(memcmp(&sampleData[0], &sampleDataNew[0], sampleData.size()), 0);
+		VERIFY_EQUAL_NONCONT(memcmp(sampleData.data(), sampleDataNew.data(), sampleData.size()), 0);
 	}
 }
 
 
 static MPT_NOINLINE void TestITCompression()
-//------------------------------------------
 {
 	// Test loading / saving of IT-compressed samples
 	const int sampleDataSize = 65536;
@@ -2729,8 +3448,9 @@ static MPT_NOINLINE void TestITCompression()
 
 
 
+#if 0
+
 static bool RatioEqual(CTuningBase::RATIOTYPE a, CTuningBase::RATIOTYPE b)
-//------------------------------------------------------------------------
 {
 	if(a == CTuningBase::RATIOTYPE(0) && b == CTuningBase::RATIOTYPE(0))
 	{
@@ -2745,14 +3465,13 @@ static bool RatioEqual(CTuningBase::RATIOTYPE a, CTuningBase::RATIOTYPE b)
 
 
 static void CheckEqualTuningCollections(const CTuningCollection &a, const CTuningCollection &b)
-//--------------------------------------------------------------------------------------------
 {
 	VERIFY_EQUAL(a.GetName(), b.GetName());
 	VERIFY_EQUAL(a.GetNumTunings(), b.GetNumTunings());
 	for(std::size_t tuning = 0; tuning < std::min(a.GetNumTunings(), b.GetNumTunings()); ++tuning)
 	{
 		VERIFY_EQUAL(a.GetTuning(tuning).GetName(), b.GetTuning(tuning).GetName());
-		VERIFY_EQUAL(a.GetTuning(tuning).GetTuningType(), b.GetTuning(tuning).GetTuningType());
+		VERIFY_EQUAL(a.GetTuning(tuning).GetType(), b.GetTuning(tuning).GetType());
 		VERIFY_EQUAL(a.GetTuning(tuning).GetGroupSize(), b.GetTuning(tuning).GetGroupSize());
 		VERIFY_EQUAL(a.GetTuning(tuning).GetFineStepCount(), b.GetTuning(tuning).GetFineStepCount());
 		VERIFY_EQUAL(RatioEqual(a.GetTuning(tuning).GetGroupRatio(), b.GetTuning(tuning).GetGroupRatio()), true);
@@ -2765,69 +3484,14 @@ static void CheckEqualTuningCollections(const CTuningCollection &a, const CTunin
 	}
 }
 
+#endif
+
 
 static MPT_NOINLINE void TestTunings()
-//------------------------------------
 {
 
-	// check that the generated builtin tunings match the old resource data
-
-	CSoundFile *emptyFile = new CSoundFile();
-	emptyFile->Create(FileReader(), CSoundFile::loadCompleteModule);
-
-	static const size_t built_inTunings_tc_size = 244;
-	static const unsigned char built_inTunings_tc_data[244]=
-	{
-		0x32,0x32,0x38,0x02,0x54,0x43,0x1F,0x08,0x00,0x01,0x0C,
-		0x01,0x0D,0x00,0x9F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
-		0x40,0x42,0x75,0x69,0x6C,0x74,0x2D,0x69,0x6E,0x20,0x74,
-		0x75,0x6E,0x69,0x6E,0x67,0x73,0xFF,0xFF,0x32,0x32,0x38,
-		0x09,0x43,0x54,0x42,0x32,0x34,0x34,0x52,0x54,0x49,0x1F,
-		0x08,0x00,0x01,0x12,0x00,0x00,0x10,0x01,0x25,0x00,0x27,
-		0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x31,0x32,0x54,
-		0x45,0x54,0x20,0x5B,0x5B,0x66,0x73,0x31,0x35,0x20,0x31,
-		0x2E,0x31,0x37,0x2E,0x30,0x32,0x2E,0x34,0x39,0x5D,0x5D,
-		0x00,0x00,0x03,0x00,0x30,0x00,0x00,0x02,0x43,0x2D,0x01,
-		0x00,0x02,0x43,0x23,0x02,0x00,0x02,0x44,0x2D,0x03,0x00,
-		0x02,0x44,0x23,0x04,0x00,0x02,0x45,0x2D,0x05,0x00,0x02,
-		0x46,0x2D,0x06,0x00,0x02,0x46,0x23,0x07,0x00,0x02,0x47,
-		0x2D,0x08,0x00,0x02,0x47,0x23,0x09,0x00,0x02,0x41,0x2D,
-		0x0A,0x00,0x02,0x41,0x23,0x0B,0x00,0x02,0x42,0x2D,0x0F,
-		0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x0C,0x00,0x80,0x00,
-		0xC0,0xFF,0x02,0x30,0x80,0x68,0x02,0x31,0xE8,0x08,0x02,
-		0x32,0xF0,0x08,0x02,0x33,0xF8,0xF4,0x02,0x34,0xED,0x01,
-		0x10,0x08,0x52,0x54,0x49,0x33,0xFD,0x01,0x10,0x08,0x52,
-		0x54,0x49,0x32,0x0D,0x02,0x08,0x08,0x52,0x54,0x49,0x34,
-		0x15,0x02,0x08,0x08,0x52,0x54,0x49,0x31,0x1D,0x02,0x08,
-		0x02,0x30,0x58,0x44,0x02,0x31,0x9C,0x08,0x02,0x32,0xA4,
-		0xF9,0x02
-	};
-	CTuningCollection *oldBuiltin = new CTuningCollection();
-	std::string builtindata(built_inTunings_tc_data, built_inTunings_tc_data + built_inTunings_tc_size);
-	mpt::istringstream iStrm(builtindata);
-	oldBuiltin->Deserialize(iStrm);
-
-	CheckEqualTuningCollections(emptyFile->GetBuiltInTunings(), *oldBuiltin);
-
-#if MPT_COMPILER_MSVC
-
-	// Test that the serialization exactly matches the old data.
-	// This depends on exactly identical floating point representations (and thus rounding), which is why we limit this test to MSVC.
-
-	mpt::ostringstream stream;
-	stream.imbue(std::locale::classic());
-	emptyFile->GetBuiltInTunings().Serialize(stream);
-	std::string str = stream.str();
-	std::vector<char> data = std::vector<char>(str.data(), str.data() + str.size());
-
-	VERIFY_EQUAL(data, std::vector<char>(built_inTunings_tc_data, built_inTunings_tc_data + built_inTunings_tc_size));
-
-#endif
+	// nothing for now
 
-	delete oldBuiltin;
-
-	emptyFile->Destroy();
-	delete emptyFile;
 }
 
 
@@ -2844,36 +3508,33 @@ T Rand(const T min, const T max)
 }
 
 static void GenerateCommands(CPattern& pat, const double dProbPcs, const double dProbPc)
-//--------------------------------------------------------------------------------------
 {
 	const double dPcxProb = dProbPcs + dProbPc;
-	const CPattern::const_iterator end = pat.End();
-	for(CPattern::iterator i = pat.Begin(); i != end; i++)
+	for(auto &m : pat)
 	{
 		const double rand = Rand01();
 		if(rand < dPcxProb)
 		{
 			if(rand < dProbPcs)
-				i->note = NOTE_PCS;
+				m.note = NOTE_PCS;
 			else
-				i->note = NOTE_PC;
+				m.note = NOTE_PC;
 
-			i->instr = Rand<ModCommand::INSTR>(0, MAX_MIXPLUGINS);
-			i->SetValueVolCol(Rand<uint16>(0, ModCommand::maxColumnValue));
-			i->SetValueEffectCol(Rand<uint16>(0, ModCommand::maxColumnValue));
+			m.instr = Rand<ModCommand::INSTR>(0, MAX_MIXPLUGINS);
+			m.SetValueVolCol(Rand<uint16>(0, ModCommand::maxColumnValue));
+			m.SetValueEffectCol(Rand<uint16>(0, ModCommand::maxColumnValue));
 		}
 		else
-			i->Clear();
+			m.Clear();
 	}
 }
 
 
 // Test PC note serialization
 static MPT_NOINLINE void TestPCnoteSerialization()
-//------------------------------------------------
 {
 	FileReader file;
-	MPT_SHARED_PTR<CSoundFile> pSndFile = mpt::make_shared<CSoundFile>();
+	std::unique_ptr<CSoundFile> pSndFile = mpt::make_unique<CSoundFile>();
 	CSoundFile &sndFile = *pSndFile.get();
 	sndFile.m_nType = MOD_TYPE_MPT;
 	sndFile.Patterns.DestroyPatterns();
@@ -2885,21 +3546,8 @@ static MPT_NOINLINE void TestPCnoteSerialization()
 	sndFile.Patterns.Insert(2, ModSpecs::mptm.patternRowsMax);
 	GenerateCommands(sndFile.Patterns[2], 0.5, 0.5);
 
-	//
-	std::vector<ModCommand> pat[3];
-	const size_t numCommands[] = {	sndFile.GetNumChannels() * sndFile.Patterns[0].GetNumRows(),
-									sndFile.GetNumChannels() * sndFile.Patterns[1].GetNumRows(),
-									sndFile.GetNumChannels() * sndFile.Patterns[2].GetNumRows()
-								 };
-	pat[0].resize(numCommands[0]);
-	pat[1].resize(numCommands[1]);
-	pat[2].resize(numCommands[2]);
-
-	for(int i = 0; i < 3; i++) // Copy pattern data for comparison.
-	{
-		CPattern::const_iterator iter = sndFile.Patterns[i].Begin();
-		for(size_t j = 0; j < numCommands[i]; j++, iter++) pat[i][j] = *iter;
-	}
+	// Copy pattern data for comparison.
+	CPatternContainer patterns{ sndFile.Patterns };
 
 	mpt::stringstream mem;
 	WriteModPatterns(mem, sndFile.Patterns);
@@ -2920,24 +3568,13 @@ static MPT_NOINLINE void TestPCnoteSerialization()
 	VERIFY_EQUAL_NONCONT( sndFile.Patterns[2].GetNumRows(), ModSpecs::mptm.patternRowsMax);
 	for(int i = 0; i < 3; i++)
 	{
-		bool bPatternDataMatch = true;
-		CPattern::const_iterator iter = sndFile.Patterns[i].Begin();
-		for(size_t j = 0; j < numCommands[i]; j++, iter++)
-		{
-			if(pat[i][j] != *iter)
-			{
-				bPatternDataMatch = false;
-				break;
-			}
-		}
-		VERIFY_EQUAL( bPatternDataMatch, true);
+		VERIFY_EQUAL(sndFile.Patterns[i], patterns[i]);
 	}
 }
 
 
 // Test String I/O functionality
 static MPT_NOINLINE void TestStringIO()
-//-------------------------------------
 {
 	char src0[4] = { '\0', 'X', ' ', 'X' };		// Weird empty buffer
 	char src1[4] = { 'X', ' ', '\0', 'X' };		// Weird buffer (hello Impulse Tracker)
@@ -3176,7 +3813,6 @@ static MPT_NOINLINE void TestStringIO()
 
 
 static MPT_NOINLINE void TestSampleConversion()
-//---------------------------------------------
 {
 	std::vector<uint8> sourceBufContainer(65536 * 4);
 	std::vector<uint8> targetBufContainer(65536 * 6);
@@ -3346,7 +3982,6 @@ OPENMPT_NAMESPACE_BEGIN
 namespace Test {
 
 void DoTests()
-//------------
 {
 	return;
 }

-- 
libopenmpt packaging



More information about the pkg-multimedia-commits mailing list