aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/libopenmpt
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/libopenmpt
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/libopenmpt')
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/.clang-format169
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/Doxyfile2632
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt.bi1637
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt_ext.bi408
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/doc/in_openmpt.txt17
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/doc/xmp-openmpt.txt16
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/dox/changelog.md1087
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/dox/dependencies.md122
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/dox/gettingstarted.md207
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/dox/index.dox43
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/dox/packaging.md38
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/dox/tests.md44
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/in_openmpt.cpp587
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.h1552
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.hpp1185
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.pc.in14
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_c.cpp1881
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_config.h205
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_cxx.cpp500
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.h405
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.hpp404
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.cpp352
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.hpp122
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.cpp2162
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.hpp280
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_internal.h25
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.cpp497
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.hpp36
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.rc147
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_settings.hpp130
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_buffer.h198
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_fd.h101
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_file.h132
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_test.cpp69
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.h79
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.mk8
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.rc216
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/resource.h27
-rw-r--r--Src/external_dependencies/openmpt-trunk/libopenmpt/xmp-openmpt.cpp1893
39 files changed, 19627 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/.clang-format b/Src/external_dependencies/openmpt-trunk/libopenmpt/.clang-format
new file mode 100644
index 00000000..ca83758a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/.clang-format
@@ -0,0 +1,169 @@
+# clang-format 14
+
+Language: Cpp
+Standard: c++20
+
+AccessModifierOffset: -2 #?
+AlignAfterOpenBracket: AlwaysBreak
+AlignArrayOfStructures: Left
+AlignConsecutiveAssignments: false
+AlignConsecutiveBitFields: false
+AlignConsecutiveDeclarations: false
+AlignConsecutiveMacros: true
+AlignEscapedNewlines: DontAlign
+AlignOperands: AlignAfterOperator
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortEnumsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Empty
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLambdasOnASingleLine: Inline
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros: []
+BinPackArguments: true
+BinPackParameters: false
+BitFieldColonSpacing: Both
+BraceWrapping:
+ AfterCaseLabel: true
+ AfterClass: false
+ AfterControlStatement: MultiLine
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ #AfterObjCDeclaration
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: true
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: true
+#BreakAfterJavaFieldAnnotations
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Custom
+BreakBeforeConceptDeclarations: true
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeComma
+BreakInheritanceList: BeforeComma
+BreakStringLiterals: false
+ColumnLimit: 0
+CommentPragmas: '' #?
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 2 #?
+ContinuationIndentWidth: 2 #?
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: false
+EmptyLineAfterAccessModifier: Leave
+EmptyLineBeforeAccessModifier: Leave
+FixNamespaceComments: true
+ForEachMacros: []
+IfMacros: ['MPT_MAYBE_CONSTANT_IF']
+IncludeBlocks: Preserve
+IncludeCategories: [] #?
+IncludeIsMainRegex: '' #?
+IncludeIsMainSourceRegex: '' #?
+IndentAccessModifiers: false
+IndentCaseBlocks: true
+IndentCaseLabels: true
+IndentExternBlock: NoIndent
+IndentGotoLabels: false
+IndentPPDirectives: None
+#IndentRequiresClause: true
+#BeforeHash
+IndentWidth: 2
+IndentWrappedFunctionNames: true
+InsertTrailingCommas: None
+#JavaImportGroups
+#JavaScriptQuotes
+#JavaScriptWrapImports
+KeepEmptyLinesAtTheStartOfBlocks: true
+LambdaBodyIndentation: OuterScope
+MacroBlockBegin: '' #?
+MacroBlockEnd: '' #?
+MaxEmptyLinesToKeep: 3
+NamespaceIndentation: None
+NamespaceMacros: [] #?
+#ObjCBinPackProtocolList
+#ObjCBlockIndentWidth
+#ObjCBreakBeforeNestedBlockParam
+#ObjCSpaceAfterProperty
+#ObjCSpaceBeforeProtocolList
+PackConstructorInitializers: Never
+#PenaltyBreakAssignment
+#PenaltyBreakBeforeFirstCallParameter
+#PenaltyBreakComment
+#PenaltyBreakFirstLessLess
+#PenaltyBreakOpenParenthesis
+#PenaltyBreakString
+#PenaltyBreakTemplateDeclaration
+#PenaltyExcessCharacter
+#PenaltyIndentedWhitespace
+#PenaltyReturnTypeOnItsOwnLine
+PointerAlignment: Middle
+PPIndentWidth: -1
+#RawStringFormats
+QualifierAlignment: Leave
+#QualifierOrder: ['static', 'inline', 'constexpr', 'volatile', 'const', 'restrict', 'type']
+ReferenceAlignment: Pointer
+ReflowComments: false
+RemoveBracesLLVM: false
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SortIncludes: false
+#SortJavaStaticImport
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDeclarationName: false
+ AfterFunctionDefinitionName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ #AfterRequiresInClause: false
+ #AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: true
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: true
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParentheses: true
+SpacesInSquareBrackets: false
+StatementAttributeLikeMacros: []
+StatementMacros: [ 'MPT_WARNING', 'MPT_TEST_GROUP_INLINE_IDENTIFIER', 'MPT_TEST_GROUP_INLINE', 'MPT_TEST_GROUP_STATIC' ] #?
+TabWidth: 2
+TypenameMacros: [] #?
+UseCRLF: false
+UseTab: ForContinuationAndIndentation
+WhitespaceSensitiveMacros:
+ - MPT_PP_STRINGIFY
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/Doxyfile b/Src/external_dependencies/openmpt-trunk/libopenmpt/Doxyfile
new file mode 100644
index 00000000..aa13040b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/Doxyfile
@@ -0,0 +1,2632 @@
+# Doxyfile 1.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = libopenmpt
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = unknown
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "cross-platform C++ and C library to decode tracked music files"
+
+# 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 =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = bin/docs
+
+# 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
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION = None
+
+# 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
+# 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
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# 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.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH = .
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+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.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For 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 that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+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: 5.
+# 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 putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+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
+# 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
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which efficively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# 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.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# 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_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# 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
+# 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,
+# 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. 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.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+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.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# 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
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+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
+# 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.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+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.
+# 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
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: 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 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 default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# 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 deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+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 default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+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
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# 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.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+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. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# 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. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# 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
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# 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. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = libopenmpt/dox/index.dox \
+ README.md \
+ libopenmpt/dox/dependencies.md \
+ libopenmpt/dox/gettingstarted.md \
+ libopenmpt/dox/packaging.md \
+ doc/contributing.md \
+ doc/libopenmpt_styleguide.md \
+ doc/openmpt_styleguide.md \
+ libopenmpt/dox/tests.md \
+ libopenmpt/dox/changelog.md \
+ doc/module_formats.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 \
+ libopenmpt/libopenmpt_version.h \
+ libopenmpt/libopenmpt_ext.hpp \
+ libopenmpt/libopenmpt_ext.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+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.
+#
+# 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.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# 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 (to be provided as doxygen C comment),
+# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
+# *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = LIBOPENMPT_API \
+ LIBOPENMPT_CXX_API \
+ LIBOPENMPT_API_HELPER_EXPORT \
+ LIBOPENMPT_API_HELPER_IMPORT \
+ LIBOPENMPT_API_HELPER_PUBLIC \
+ LIBOPENMPT_API_HELPER_LOCAL \
+ OPENMPT_API_VERSION_HELPER_STRINGIZE \
+ OPENMPT_API_VERSION_STRINGIZE \
+ openmpt::detail
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = examples/ \
+ LICENSE
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# 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 =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=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
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: 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
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# 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
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
+# YES then doxygen will add the directory of each input to the include path.
+# The default value is: YES.
+
+CLANG_ADD_INC_PATHS = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# 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 therefore more robust against future updates.
+# 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). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# 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
+# https://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
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+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 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
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see:
+# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+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,
+# 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 main .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)
+# 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
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# 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 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
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# 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.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# 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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# 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
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+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
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# 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.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+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. 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.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# 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 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 =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+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
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX 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_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+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
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# 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.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = 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.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+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
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+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
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# 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.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# 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.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# 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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+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.sourceforge.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
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# 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.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# 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.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# 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
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# 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
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# 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.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+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
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+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.
+# 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
+# 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
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# 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
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# 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.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# 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.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# 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. 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.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# 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. 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.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# 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, 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.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# 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.
+
+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
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# 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.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc and
+# plantuml temporary files.
+# The default value is: YES.
+
+DOT_CLEANUP = YES
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt.bi b/Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt.bi
new file mode 100644
index 00000000..9b50bb4d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt.bi
@@ -0,0 +1,1637 @@
+/'
+ ' libopenmpt.bi
+ ' -------------
+ ' Purpose: libopenmpt public interface for FreeBASIC
+ ' Notes : (currently none)
+ ' Authors: Johannes Schultz
+ ' OpenMPT Devs
+ ' The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ '/
+
+#Include Once "crt/stdio.bi"
+#Include Once "file.bi"
+
+#Inclib "openmpt"
+
+/'*
+ \page libopenmpt_freebasic_overview FreeBASIC API
+
+ \section libopenmpt_freebasic_error Error Handling
+
+ - Functions with no return value in the corresponding C++ API return 0 on
+ 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
+
+ - All strings returned from libopenmpt are encoded in UTF-8.
+ - All strings passed to libopenmpt should also be encoded in UTF-8.
+ Behaviour in case of invalid UTF-8 is unspecified.
+ - libopenmpt does not enforce or expect any particular Unicode
+ normalization form.
+ - Some libopenmpt functions return strings and are provided in two flavours:
+ The raw libopenmpt function (with a trailing underscore) and a FreeBASIC
+ wrapper function that completely takes care of memory handling (recommended).
+ All strings returned from raw libopenmpt functions are dynamically
+ allocated and must be freed with openmpt_free_string().
+ When using the FreeBASIC wrappers (which is the recommended way), FreeBASIC
+ automatically takes care of this.
+ - All strings passed to libopenmpt are copied. No ownership is assumed or
+ transferred.
+
+ \section libopenmpt_freebasic_outputformat Output Format
+
+ libopenmpt supports a wide range of PCM output formats:
+ [8000..192000]/[mono|stereo|quad]/[f32|i16].
+
+ Unless you have some very specific requirements demanding a particular aspect
+ of the output format, you should always prefer 48000/stereo/f32 as the
+ libopenmpt PCM format.
+
+ - Please prefer 48000Hz unless the user explicitly demands something else.
+ Practically all audio equipment and file formats use 48000Hz nowadays.
+ - Practically all module formats are made for stereo output. Mono will not
+ give you any measurable speed improvements and can trivially be obtained from
+ the stereo output anyway. Quad is not expected by almost all modules and even
+ if they do use surround effects, they expect the effects to be mixed to
+ stereo.
+ - Floating point output provides headroom instead of hard clipping if the
+ module is louder than 0dBFs, will give you a better signal-to-noise ratio
+ than int16 output, and avoid the need to apply an additional dithering to the
+ output by libopenmpt. Unless your platform has no floating point unit at all,
+ floating point will thus also be slightly faster.
+
+ \section libopenmpt_freebasic_threads libopenmpt in multi-threaded environments
+
+ - 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.
+ - You must ensure to only ever access a particular libopenmpt object from a
+ single thread at a time.
+ - Consecutive accesses can happen from different threads.
+ - Different objects can be accessed concurrently from different threads.
+
+ \section libopenmpt_freebasic_detailed Detailed documentation
+
+ \ref libopenmpt_freebasic
+'/
+
+Extern "C"
+
+'* API version of this header file
+Const OPENMPT_API_VERSION_MAJOR = 0
+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 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
+
+/'* \brief Get the core version number
+
+ Return the OpenMPT core version number.
+ \return The value represents (majormajor << 24 + major << 16 + minor << 8 + minorminor).
+'/
+Declare Function openmpt_get_core_version() As ULong
+
+'* Return a verbose library version string from openmpt_get_string(). \deprecated Please use \code "library_version" \endcode directly.
+#Define OPENMPT_STRING_LIBRARY_VERSION "library_version"
+'* Return a verbose library features string from openmpt_get_string(). \deprecated Please use \code "library_features" \endcode directly.
+#Define OPENMPT_STRING_LIBRARY_FEATURES "library_features"
+'* Return a verbose OpenMPT core version string from openmpt_get_string(). \deprecated Please use \code "core_version" \endcode directly.
+#Define OPENMPT_STRING_CORE_VERSION "core_version"
+'* Return information about the current build (e.g. the build date or compiler used) from openmpt_get_string(). \deprecated Please use \code "build" \endcode directly.
+#Define OPENMPT_STRING_BUILD "build"
+'* Return all contributors from openmpt_get_string(). \deprecated Please use \code "credits" \endcode directly.
+#Define OPENMPT_STRING_CREDITS "credits"
+'* Return contact information about libopenmpt from openmpt_get_string(). \deprecated Please use \code "contact" \endcode directly.
+#Define OPENMPT_STRING_CONTACT "contact"
+'* Return the libopenmpt license from openmpt_get_string(). \deprecated Please use \code "license" \endcode directly.
+#Define OPENMPT_STRING_LICENSE "license"
+
+/'* \brief Free a string returned by libopenmpt
+
+ Frees any string that got returned by libopenmpt.
+'/
+Declare Sub openmpt_free_string(ByVal Str As Const ZString Ptr)
+
+/'* \brief Get library related metadata.
+
+ \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
+ - "contact": contact information about libopenmpt
+ - "license": the libopenmpt license
+ - "url": libopenmpt website URL
+ - "support_forum_url": libopenmpt support and discussions forum URL
+ - "bugtracker_url": libopenmpt bug and issue tracker URL
+ \return A (possibly multi-line) string containing the queried information. If no information is available, the string is empty.
+ \remarks Use openmpt_get_string to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_get_string_ Alias "openmpt_get_string" (ByVal key As Const ZString Ptr) As Const ZString Ptr
+
+/'* \brief Get a list of supported file extensions
+
+ \return The semicolon-separated list of extensions supported by this libopenmpt build. The extensions are returned lower-case without a leading dot.
+ \remarks Use openmpt_get_supported_extensions to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_get_supported_extensions() As Const ZString Ptr
+
+/'* \brief Query whether a file extension is supported
+
+ \param extension file extension to query without a leading dot. The case is ignored.
+ \return 1 if the extension is supported by libopenmpt, 0 otherwise.
+'/
+Declare Function openmpt_is_extension_supported(ByVal extension As Const ZString Ptr) As Long
+
+'* Seek to the given offset relative to the beginning of the file.
+Const OPENMPT_STREAM_SEEK_SET = 0
+'* Seek to the given offset relative to the current position in the file.
+Const OPENMPT_STREAM_SEEK_CUR = 1
+'* Seek to the given offset relative to the end of the file.
+Const OPENMPT_STREAM_SEEK_END = 2
+
+/'* \brief Read bytes from stream
+
+ Read bytes data from stream to dst.
+ \param stream Stream to read data from
+ \param dst Target where to copy data.
+ \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
+
+/'* \brief Seek stream position
+
+ Seek to stream position offset at whence.
+ \param stream Stream to operate on.
+ \param offset Offset to seek to.
+ \param whence OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR, OPENMPT_STREAM_SEEK_END. See C89 documentation.
+ \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
+
+/'* \brief Tell stream position
+
+ Tell position of stream.
+ \param stream Stream to operate on.
+ \return Current position in stream.
+ \retval -1 Failure.
+'/
+Type openmpt_stream_tell_func As Function(ByVal stream As Any Ptr) As LongInt
+
+/'* \brief Stream callbacks
+
+ Stream callbacks used by libopenmpt for stream operations.
+'/
+Type openmpt_stream_callbacks
+ /'* \brief Read callback.
+
+ \sa openmpt_stream_read_func
+ '/
+ read_func As openmpt_stream_read_func
+
+ /'* \brief Seek callback.
+ Seek callback can be NULL if seeking is not supported.
+ \sa openmpt_stream_seek_func
+ '/
+ seek_func As openmpt_stream_seek_func
+
+ /'* \brief Tell callback.
+ Tell callback can be NULL if seeking is not supported.
+ \sa openmpt_stream_tell_func
+ '/
+ tell_func As openmpt_stream_tell_func
+End Type
+
+/'* \brief Logging function
+
+ \param message UTF-8 encoded log message.
+ \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)
+
+/'* \brief Default logging function
+
+ Default logging function that logs anything to stderr.
+'/
+Declare Sub openmpt_log_func_default(ByVal message As Const ZString Ptr, ByVal user As Any Ptr)
+
+/'* \brief Silent logging function
+
+ Silent logging function that throws any log message away.
+'/
+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. May be NULL.
+ \param user Logging function user context.
+ \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 openmpt_stream_callbacks
+ \deprecated Please use openmpt_module_could_open_probability2().
+ \since 0.3.0
+'/
+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 Bit 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 interface that might be required 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 Bit 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_probe_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 interface that might be required 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 Bit 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 interface that might be required 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
+ opaque As Any Ptr
+End Type
+
+Type openmpt_module_initial_ctl
+ ctl As Const ZString Ptr
+ value As Const ZString Ptr
+End Type
+
+/'* \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.
+ \param user 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
+'/
+Declare Function openmpt_module_create(ByVal stream_callbacks As openmpt_stream_callbacks, ByVal stream As Any Ptr, 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 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.
+ \param user 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.
+'/
+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)
+
+/'*
+ \defgroup openmpt_module_render_param Render param indices
+
+ \brief Parameter index to use with openmpt_module_get_render_param() and openmpt_module_set_render_param()
+ @{
+'/
+/'* \brief Master Gain
+
+ The related value represents a relative gain in milliBel.\n
+ The default value is 0.\n
+ The supported value range is unlimited.\n
+'/
+Const OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL = 1
+/'* \brief Stereo Separation
+
+ The related value represents the stereo separation generated by the libopenmpt mixer in percent.\n
+ The default value is 100.\n
+ The supported value range is [0,200].\n
+'/
+Const OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT = 2
+/'* \brief Interpolation Filter
+
+ The related value represents the interpolation filter length used by the libopenmpt mixer.\n
+ The default value is 0, which indicates a recommended default value.\n
+ The supported value range is [0,inf). Values greater than the implementation limit are clamped to the maximum supported value.\n
+ Currently supported values:
+ - 0: internal default
+ - 1: no interpolation (zero order hold)
+ - 2: linear interpolation
+ - 4: cubic interpolation
+ - 8: windowed sinc with 8 taps
+'/
+Const OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH = 3
+/'* \brief Volume Ramping Strength
+
+ The related value represents the amount of volume ramping done by the libopenmpt mixer.\n
+ The default value is -1, which indicates a recommended default value.\n
+ The meaningful value range is [-1..10].\n
+ A value of 0 completely disables volume ramping. This might cause clicks in sound output.\n
+ Higher values imply slower/softer volume ramps.
+'/
+Const OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH = 4
+'* @}
+
+/'*
+ \defgroup openmpt_module_command_index Pattern cell indices
+
+ \brief Parameter index to use with openmpt_module_get_pattern_row_channel_command(), openmpt_module_format_pattern_row_channel_command() and openmpt_module_highlight_pattern_row_channel_command()
+ @{
+'/
+Const OPENMPT_MODULE_COMMAND_NOTE = 0
+Const OPENMPT_MODULE_COMMAND_INSTRUMENT = 1
+Const OPENMPT_MODULE_COMMAND_VOLUMEEFFECT = 2
+Const OPENMPT_MODULE_COMMAND_EFFECT = 3
+Const OPENMPT_MODULE_COMMAND_VOLUME = 4
+Const OPENMPT_MODULE_COMMAND_PARAMETER = 5
+'* @}
+
+/'* \brief Select a sub-song from a multi-song module
+
+ \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_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.
+ \param repeat_count Repeat Count
+ - -1: repeat forever
+ - 0: play once, repeat zero times (the default)
+ - n>0: play once and repeat n times after that
+ \return 1 on success, 0 on failure.
+ \sa openmpt_module_get_repeat_count
+'/
+Declare Function openmpt_module_set_repeat_count(ByVal module As openmpt_module Ptr, ByVal repeat_count As Long) As Long
+
+/'* \brief Get Repeat Count
+
+ \param module The module handle to work on.
+ \return Repeat Count
+ - -1: repeat forever
+ - 0: play once, repeat zero times (the default)
+ - n>0: play once and repeat n times after that
+ \sa openmpt_module_set_repeat_count
+'/
+Declare Function openmpt_module_get_repeat_count(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief approximate song duration
+
+ \param module The module handle to work on.
+ \return Approximate duration of current sub-song in seconds.
+ \remarks The function may return infinity if the pattern data is too complex to evaluate.
+'/
+Declare Function openmpt_module_get_duration_seconds(ByVal module As openmpt_module Ptr) As Double
+
+/'* \brief Set approximate current song position
+
+ \param module The module handle to work on.
+ \param seconds Seconds to seek to. If seconds is out of range, the position gets set to song start or end respectively.
+ \return Approximate new song position in seconds.
+ \sa openmpt_module_get_position_seconds
+'/
+Declare Function openmpt_module_set_position_seconds(ByVal module As openmpt_module Ptr, ByVal seconds As Double) As Double
+
+/'* \brief Get current song position
+
+ \param module The module handle to work on.
+ \return Current song position in seconds.
+ \sa openmpt_module_set_position_seconds
+'/
+Declare Function openmpt_module_get_position_seconds(ByVal module As openmpt_module Ptr) As Double
+
+/'* \brief Set approximate current song position
+
+ If order or row are out of range, to position is not modified and the current position is returned.
+ \param module The module handle to work on.
+ \param order Pattern order number to seek to.
+ \param row Pattern row number to seek to.
+ \return Approximate new song position in seconds.
+ \sa openmpt_module_set_position_seconds
+ \sa openmpt_module_get_position_seconds
+'/
+Declare Function openmpt_module_set_position_order_row(ByVal module As openmpt_module Ptr, ByVal order As Long, ByVal row As Long) As Double
+
+/'* \brief Get render parameter
+
+ \param module The module handle to work on.
+ \param param Parameter to query. See \ref openmpt_module_render_param
+ \param value Pointer to the variable that receives the current value of the parameter.
+ \return 1 on success, 0 on failure (invalid param or value is NULL).
+ \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL
+ \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT
+ \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH
+ \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH
+ \sa openmpt_module_set_render_param
+'/
+Declare Function openmpt_module_get_render_param(ByVal module As openmpt_module Ptr, ByVal param As Long, ByVal value As Long Ptr) As Long
+
+/'* \brief Set render parameter
+
+ \param module The module handle to work on.
+ \param param Parameter to set. See \ref openmpt_module_render_param
+ \param value The value to set param to.
+ \return 1 on success, 0 on failure (invalid param).
+ \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL
+ \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT
+ \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH
+ \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH
+ \sa openmpt_module_get_render_param
+'/
+Declare Function openmpt_module_set_render_param(ByVal module As openmpt_module Ptr, ByVal param As Long, ByVal value As Long) As Long
+
+'*@{
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param mono Pointer to a buffer of at least count elements that receives the mono/center output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_mono(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal mono As Short Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Short Ptr, ByVal Right As Short Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \param rear_left Pointer to a buffer of at least count elements that receives the rear left output.
+ \param rear_right Pointer to a buffer of at least count elements that receives the rear right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Short Ptr, ByVal Right As Short Ptr, ByVal rear_left As Short Ptr, ByVal rear_right As Short Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param mono Pointer to a buffer of at least count elements that receives the mono/center output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_float_mono(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal mono As Single Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_float_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Single Ptr, ByVal Right As Single Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \param rear_left Pointer to a buffer of at least count elements that receives the rear left output.
+ \param rear_right Pointer to a buffer of at least count elements that receives the rear right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_float_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal Left As Single Ptr, ByVal Right As Single Ptr, ByVal rear_left As Single Ptr, ByVal rear_right As Single Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_interleaved_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_stereo As Short Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_interleaved_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_quad As Short Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_interleaved_float_stereo(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_stereo As Single Ptr) As UInteger
+
+/'* \brief Render audio data
+
+ \param module The module handle to work on.
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_freebasic_outputformat
+'/
+Declare Function openmpt_module_read_interleaved_float_quad(ByVal module As openmpt_module Ptr, ByVal samplerate As Long, ByVal count As UInteger, ByVal interleaved_quad As Single Ptr) As UInteger
+'*@}
+
+/'* \brief Get the list of supported metadata item keys
+
+ \param module The module handle to work on.
+ \return Metadata item keys supported by openmpt_module_get_metadata, as a semicolon-separated list.
+ \sa openmpt_module_get_metadata
+ \remarks Use openmpt_module_get_metadata_keys to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_metadata_keys_ Alias "openmpt_module_get_metadata_keys" (ByVal module As openmpt_module Ptr) As Const ZString Ptr
+
+/'* \brief Get a metadata item value
+
+ \param module The module handle to work on.
+ \param key Metadata item key to query. Use openmpt_module_get_metadata_keys to check for available keys.
+ Possible keys are:
+ - type: Module format extension (e.g. it) or another similar identifier for modules formats that typically do not use a file extension
+ - type_long: Format name associated with the module format (e.g. Impulse Tracker)
+ - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
+ - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
+ - container: Container format the module file is embedded in, if any (e.g. umx)
+ - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music)
+ - tracker: Tracker that was (most likely) used to save the module file, if known
+ - artist: Author of the module
+ - title: Module title
+ - date: Date the module was last saved, in ISO-8601 format.
+ - message: Song message. If the song message is empty or the module format does not support song messages, a list of instrument and sample names is returned instead.
+ - message_raw: Song message. If the song message is empty or the module format does not support song messages, an empty string is returned.
+ - warnings: A list of warnings that were generated while loading the module.
+ \return The associated value for key.
+ \sa openmpt_module_get_metadata_keys
+ \remarks Use openmpt_module_get_metadata to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_metadata_ Alias "openmpt_module_get_metadata" (ByVal module As openmpt_module Ptr, ByVal key As Const ZString Ptr) As Const ZString Ptr
+
+/'* \brief Get the current estimated beats per minute (BPM).
+
+ \param module The module handle to work on.
+ \remarks Many module formats lack time signature metadata. It is common that this estimate is off by a factor of two, but other multipliers are also possible.
+ \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate.
+ \return The current estimated BPM.
+'/
+Declare Function openmpt_module_get_current_estimated_bpm(ByVal module As openmpt_module Ptr) As Double
+
+/'* \brief Get the current speed
+
+ \param module The module handle to work on.
+ \return The current speed in ticks per row.
+'/
+Declare Function openmpt_module_get_current_speed(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the current tempo
+
+ \param module The module handle to work on.
+ \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used.
+'/
+Declare Function openmpt_module_get_current_tempo(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the current order
+
+ \param module The module handle to work on.
+ \return The current order at which the module is being played back.
+'/
+Declare Function openmpt_module_get_current_order(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the current pattern
+
+ \param module The module handle to work on.
+ \return The current pattern that is being played.
+'/
+Declare Function openmpt_module_get_current_pattern(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the current row
+
+ \param module The module handle to work on.
+ \return The current row at which the current pattern is being played.
+'/
+Declare Function openmpt_module_get_current_row(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the current amount of playing channels.
+
+ \param module The module handle to work on.
+ \return The amount of sample channels that are currently being rendered.
+'/
+Declare Function openmpt_module_get_current_playing_channels(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get an approximate indication of the channel volume.
+
+ \param module The module handle to work on.
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+'/
+Declare Function openmpt_module_get_current_channel_vu_mono(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single
+
+/'* \brief Get an approximate indication of the channel volume on the front-left speaker.
+
+ \param module The module handle to work on.
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+'/
+Declare Function openmpt_module_get_current_channel_vu_left(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single
+
+/'* \brief Get an approximate indication of the channel volume on the front-right speaker.
+
+ \param module The module handle to work on.
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+'/
+Declare Function openmpt_module_get_current_channel_vu_right(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single
+
+/'* \brief Get an approximate indication of the channel volume on the rear-left speaker.
+
+ \param module The module handle to work on.
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+'/
+Declare Function openmpt_module_get_current_channel_vu_rear_left(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single
+
+/'* \brief Get an approximate indication of the channel volume on the rear-right speaker.
+
+ \param module The module handle to work on.
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+'/
+Declare Function openmpt_module_get_current_channel_vu_rear_right(ByVal module As openmpt_module Ptr, ByVal channel As Long) As Single
+
+/'* \brief Get the number of sub-songs
+
+ \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_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
+
+/'* \brief Get the number of pattern channels
+
+ \param module The module handle to work on.
+ \return The number of pattern channels in the module. Not all channels do necessarily contain data.
+ \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes.
+'/
+Declare Function openmpt_module_get_num_channels(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the number of orders
+
+ \param module The module handle to work on.
+ \return The number of orders in the current sequence of the module.
+'/
+Declare Function openmpt_module_get_num_orders(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the number of patterns
+
+ \param module The module handle to work on.
+ \return The number of distinct patterns in the module.
+'/
+Declare Function openmpt_module_get_num_patterns(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the number of instruments
+
+ \param module The module handle to work on.
+ \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats.
+'/
+Declare Function openmpt_module_get_num_instruments(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get the number of samples
+
+ \param module The module handle to work on.
+ \return The number of sample slots in the module.
+'/
+Declare Function openmpt_module_get_num_samples(ByVal module As openmpt_module Ptr) As Long
+
+/'* \brief Get a sub-song name
+
+ \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, 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
+
+/'* \brief Get a channel name
+
+ \param module The module handle to work on.
+ \param index The channel whose name should be retrieved
+ \return The channel name.
+ \sa openmpt_module_get_num_channels
+ \remarks Use openmpt_module_get_channel_name to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_channel_name_ Alias "openmpt_module_get_channel_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr
+
+/'* \brief Get an order name
+
+ \param module The module handle to work on.
+ \param index The order whose name should be retrieved
+ \return The order name.
+ \sa openmpt_module_get_num_orders
+ \remarks Use openmpt_module_get_order_name to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_order_name_ Alias "openmpt_module_get_order_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr
+
+/'* \brief Get a pattern name
+
+ \param module The module handle to work on.
+ \param index The pattern whose name should be retrieved
+ \return The pattern name.
+ \sa openmpt_module_get_num_patterns
+ \remarks Use openmpt_module_get_pattern_name to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_pattern_name_ Alias "openmpt_module_get_pattern_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr
+
+/'* \brief Get an instrument name
+
+ \param module The module handle to work on.
+ \param index The instrument whose name should be retrieved
+ \return The instrument name.
+ \sa openmpt_module_get_num_instruments
+ \remarks Use openmpt_module_get_instrument_name to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_instrument_name_ Alias "openmpt_module_get_instrument_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr
+
+/'* \brief Get a sample name
+
+ \param module The module handle to work on.
+ \param index The sample whose name should be retrieved
+ \return The sample name.
+ \sa openmpt_module_get_num_samples
+ \remarks Use openmpt_module_get_sample_name to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_sample_name_ Alias "openmpt_module_get_sample_name" (ByVal module As openmpt_module Ptr, ByVal index As Long) As Const ZString Ptr
+
+/'* \brief Get pattern at order position
+
+ \param module The module handle to work on.
+ \param order The order item whose pattern index should be retrieved.
+ \return The pattern index found at the given order position of the current sequence.
+'/
+Declare Function openmpt_module_get_order_pattern(ByVal module As openmpt_module Ptr, ByVal order As Long) As Long
+
+/'* \brief Get the number of rows in a pattern
+
+ \param module The module handle to work on.
+ \param pattern The pattern whose row count should be retrieved.
+ \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned.
+'/
+Declare Function openmpt_module_get_pattern_num_rows(ByVal module As openmpt_module Ptr, ByVal pattern As Long) As Long
+
+/'* \brief Get raw pattern content
+
+ \param module 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.
+ \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index
+ \return The internal, raw pattern data at the given pattern position.
+'/
+Declare Function openmpt_module_get_pattern_row_channel_command_(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As UByte
+
+/'* \brief Get formatted (human-readable) pattern content
+
+ \param module 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.
+ \param command The cell index at which the data should be retrieved.
+ \return The formatted pattern data at the given pattern position. See \ref openmpt_module_command_index
+ \sa openmpt_module_highlight_pattern_row_channel_command
+ \remarks Use openmpt_module_format_pattern_row_channel_command to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_format_pattern_row_channel_command_ Alias "openmpt_module_format_pattern_row_channel_command" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As Const ZString Ptr
+
+/'* \brief Get highlighting information for formatted pattern content
+
+ \param module 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.
+ \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index
+ \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_get_pattern_row_channel_command at the given pattern position.
+ \remarks The returned string will map each character position of the string returned by openmpt_module_get_pattern_row_channel_command to a highlighting instruction.
+ Possible highlighting characters are:
+ - " " : empty/space
+ - "." : empty/dot
+ - "n" : generic note
+ - "m" : special note
+ - "i" : generic instrument
+ - "u" : generic volume column effect
+ - "v" : generic volume column parameter
+ - "e" : generic effect column effect
+ - "f" : generic effect column parameter
+ \sa openmpt_module_get_pattern_row_channel_command
+ \remarks Use openmpt_module_highlight_pattern_row_channel_command to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_highlight_pattern_row_channel_command_ Alias "openmpt_module_highlight_pattern_row_channel_command" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As Const ZString Ptr
+
+/'* \brief Get formatted (human-readable) pattern content
+
+ \param module 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.
+ \param width The maximum number of characters the string should contain. 0 means no limit.
+ \param pad If true, the string will be resized to the exact length provided in the width parameter.
+ \return The formatted pattern data at the given pattern position.
+ \sa openmpt_module_highlight_pattern_row_channel
+ \remarks Use openmpt_module_format_pattern_row_channel to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_format_pattern_row_channel_ Alias "openmpt_module_format_pattern_row_channel" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As Const ZString Ptr
+
+/'* \brief Get highlighting information for formatted pattern content
+
+ \param module 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.
+ \param width The maximum number of characters the string should contain. 0 means no limit.
+ \param pad If true, the string will be resized to the exact length provided in the width parameter.
+ \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_format_pattern_row_channel at the given pattern position.
+ \sa openmpt_module_format_pattern_row_channel
+ \remarks Use openmpt_module_highlight_pattern_row_channel to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_highlight_pattern_row_channel_ Alias "openmpt_module_highlight_pattern_row_channel" (ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As Const ZString Ptr
+
+/'* \brief Retrieve supported ctl keys
+
+ \param module The module handle to work on.
+ \return A semicolon-separated list containing all supported ctl keys.
+ \remarks Currently supported ctl values are:
+ - load.skip_samples: Set to "1" to avoid loading samples into memory
+ - load.skip_patterns: Set to "1" to avoid loading patterns into memory
+ - load.skip_plugins: Set to "1" to avoid loading plugins
+ - load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking.
+ - seek.sync_samples: Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row.
+ - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong.
+ - play.at_end: Chooses the behaviour when the end of song is reached:
+ - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames.
+ - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start.
+ - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames.
+ - 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.
+ - render.resampler.emulate_amiga_type: Configures the filter type to use for the Amiga resampler. Supported values are:
+ - "auto": Filter type is chosen by the library and might change. This is the default.
+ - "a500": Amiga A500 filter.
+ - "a1200": Amiga A1200 filter.
+ - "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future.
+ - render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume.
+ - 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.
+ - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker).
+ - 3: Rectangular, 1 bit depth, simple 1st order noise shaping
+ \remarks Use openmpt_module_get_ctls to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_get_ctls_ Alias "openmpt_module_get_ctls" (ByVal module As openmpt_module Ptr) As Const ZString Ptr
+
+/'* \brief Get current ctl value
+
+ \param module The module handle to work on.
+ \param ctl The ctl key whose value should be retrieved.
+ \return The associated ctl value, or NULL on failure.
+ \sa openmpt_module_get_ctls
+ \remarks Use openmpt_module_ctl_get to automatically handle the lifetime of the returned pointer.
+'/
+Declare Function openmpt_module_ctl_get_ Alias "openmpt_module_ctl_get" (ByVal module As openmpt_module Ptr, ByVal ctl As Const ZString Ptr) As Const ZString Ptr
+
+/'* \brief Set ctl value
+
+ \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
+
+'* Callbacks for CRT FILE* handling
+Function openmpt_stream_read_func(ByVal stream As Any Ptr, ByVal dst As Any Ptr, ByVal bytes As UInteger) As UInteger
+ Dim retval As UInteger = 0
+ Var f = Cast( FILE Ptr, stream )
+ If ( f = 0 ) Then Return 0
+ retval = fread( dst, 1, bytes, f )
+ If ( retval <= 0 ) Then Return 0
+ Return retval
+End Function
+
+'* Callbacks for CRT FILE* handling
+Function openmpt_stream_seek_func(ByVal stream As Any Ptr, ByVal offset As LongInt, ByVal whence As Long) As Long
+ Var f = Cast( FILE Ptr, stream )
+ If ( f = 0 ) Then Return -1
+ Dim fwhence As Long
+ Select Case whence
+ Case OPENMPT_STREAM_SEEK_SET
+ fwhence = SEEK_SET
+ Case OPENMPT_STREAM_SEEK_CUR
+ fwhence = SEEK_CUR
+ Case OPENMPT_STREAM_SEEK_END
+ fwhence = SEEK_END
+ Case Else
+ Return -1
+ End Select
+ Return IIf(fseek( f, offset, fwhence ) <> 0, -1, 0)
+End Function
+
+'* Callbacks for CRT FILE* handling
+Function openmpt_stream_tell_func(ByVal stream As Any Ptr) As LongInt
+ Dim retval As LongInt = 0
+ Var f = Cast( FILE Ptr, stream )
+ If ( f = 0 ) Then
+ Return -1
+ EndIf
+ retval = ftell( f )
+ If ( retval < 0 ) Then Return -1
+ Return retval
+End Function
+
+End Extern
+
+'* Retrieve the set of stream callbacks for CRT FILE*
+Function openmpt_stream_get_file_callbacks() As openmpt_stream_callbacks
+ Static callbacks As openmpt_stream_callbacks = (@openmpt_stream_read_func, @openmpt_stream_seek_func, @openmpt_stream_tell_func)
+ Return callbacks
+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 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 loguser As Any Ptr = 0,_
+ ByVal ctls As Const openmpt_module_initial_ctl Ptr = 0) As openmpt_module Ptr
+ 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 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_filename2(_
+ ByRef filename As String,_
+ 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
+ Var file = fopen(filename, "rb")
+ Var retval = CPtr(openmpt_module Ptr, 0)
+ If(file <> 0) Then
+ 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 ""
+ Dim As String s = *sz
+ openmpt_free_string(sz)
+ Return s
+End Function
+
+'* \sa openmpt_get_string_
+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))
+End Function
+
+'* \sa openmpt_module_get_metadata_
+Function openmpt_module_get_metadata(ByVal module As openmpt_module Ptr, ByVal key As Const ZString Ptr) As String
+ Return openmpt_get_zstring(openmpt_module_get_metadata_(module, key))
+End Function
+
+'* \sa openmpt_module_get_subsong_name_
+Function openmpt_module_get_subsong_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String
+ Return openmpt_get_zstring(openmpt_module_get_subsong_name_(module, index))
+End Function
+
+'* \sa openmpt_module_get_channel_name_
+Function openmpt_module_get_channel_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String
+ Return openmpt_get_zstring(openmpt_module_get_channel_name_(module, index))
+End Function
+
+'* \sa openmpt_module_get_order_name_
+Function openmpt_module_get_order_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String
+ Return openmpt_get_zstring(openmpt_module_get_order_name_(module, index))
+End Function
+
+'* \sa openmpt_module_get_pattern_name_
+Function openmpt_module_get_pattern_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String
+ Return openmpt_get_zstring(openmpt_module_get_pattern_name_(module, index))
+End Function
+
+'* \sa openmpt_module_get_instrument_name_
+Function openmpt_module_get_instrument_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String
+ Return openmpt_get_zstring(openmpt_module_get_instrument_name_(module, index))
+End Function
+
+'* \sa openmpt_module_get_sample_name_
+Function openmpt_module_get_sample_name(ByVal module As openmpt_module Ptr, ByVal index As Long) As String
+ Return openmpt_get_zstring(openmpt_module_get_sample_name_(module, index))
+End Function
+
+'* \sa openmpt_module_format_pattern_row_channel_command_
+Function openmpt_module_format_pattern_row_channel_command(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As String
+ Return openmpt_get_zstring(openmpt_module_format_pattern_row_channel_command_(module, pattern, row, channel, command_))
+End Function
+
+'* \sa openmpt_module_highlight_pattern_row_channel_command_
+Function openmpt_module_highlight_pattern_row_channel_command(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal command_ As Long) As String
+ Return openmpt_get_zstring(openmpt_module_highlight_pattern_row_channel_command_(module, pattern, row, channel, command_))
+End Function
+
+'* \sa openmpt_module_format_pattern_row_channel_
+Function openmpt_module_format_pattern_row_channel(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As String
+ Return openmpt_get_zstring(openmpt_module_format_pattern_row_channel_(module, pattern, row, channel, width_, pad))
+End Function
+
+'* \sa openmpt_module_highlight_pattern_row_channel_
+Function openmpt_module_highlight_pattern_row_channel(ByVal module As openmpt_module Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long, ByVal width_ As UInteger, ByVal pad As Long) As String
+ Return openmpt_get_zstring(openmpt_module_highlight_pattern_row_channel_(module, pattern, row, channel, width_, pad))
+End Function
+
+'* \sa openmpt_module_get_ctls_
+Function openmpt_module_get_ctls(ByVal module As openmpt_module Ptr) As String
+ Return openmpt_get_zstring(openmpt_module_get_ctls_(module))
+End Function
+
+'* \sa openmpt_module_ctl_get_
+Function openmpt_module_ctl_get(ByVal module As openmpt_module Ptr, ByVal ctl As Const ZString Ptr) As String
+ Return openmpt_get_zstring(openmpt_module_ctl_get_(module, ctl))
+End Function
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt_ext.bi b/Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt_ext.bi
new file mode 100644
index 00000000..789acc8d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/bindings/freebasic/libopenmpt_ext.bi
@@ -0,0 +1,408 @@
+/'
+ ' libopenmpt_ext.bi
+ ' -----------------
+ ' Purpose: libopenmpt public FreeBASIC interface for libopenmpt extensions
+ ' Notes : (currently none)
+ ' Authors: Johannes Schultz
+ ' OpenMPT Devs
+ ' The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ '/
+
+#Pragma Once
+
+#Include Once "libopenmpt.bi"
+
+Extern "C"
+
+'* \brief Opaque type representing a libopenmpt extension module
+Type openmpt_module_ext
+ opaque As Any Ptr
+End Type
+
+/'* \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.
+ \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_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
+ \since 0.3.0
+'/
+Declare Function openmpt_module_ext_create(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, ByVal ctls As Const openmpt_module_initial_ctl Ptr) As openmpt_module_ext Ptr
+
+/'* \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.
+ \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_ext, or NULL on failure.
+ \remarks The input data can be discarded after an openmpt_module_ext has been constructed successfully.
+ \since 0.3.0
+'/
+Declare Function openmpt_module_ext_create_from_memory(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 Error As Long Ptr, ByVal error_message As Const ZString Ptr Ptr, ByVal ctls As Const openmpt_module_initial_ctl Ptr) As openmpt_module_ext Ptr
+
+/'* \brief Unload a previously created openmpt_module_ext from memory.
+
+ \param mod_ext The module to unload.
+ \since 0.3.0
+'/
+Declare Sub openmpt_module_ext_destroy(ByVal mod_ext As openmpt_module_ext Ptr)
+
+/'* \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
+'/
+Declare Function openmpt_module_ext_get_module(ByVal mod_ext As openmpt_module_ext Ptr) As openmpt_module Ptr
+
+/'* 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
+'/
+Declare Function openmpt_module_ext_get_interface(ByVal mod_ext As openmpt_module_ext Ptr, ByVal interface_id As Const ZString Ptr, ByVal interface As Any Ptr, ByVal interface_size As UInteger) As Long
+
+#define LIBOPENMPT_EXT_C_INTERFACE_PATTERN_VIS "pattern_vis"
+
+'* Pattern command type
+Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_UNKNOWN = 0
+Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GENERAL = 1
+Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_GLOBAL = 2
+Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_VOLUME = 3
+Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PANNING = 4
+Const OPENMPT_MODULE_EXT_INTERFACE_PATTERN_VIS_EFFECT_TYPE_PITCH = 5
+
+Type 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 get_pattern_row_channel_effect_type
+ '/
+ get_pattern_row_channel_volume_effect_type As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long) As Long
+
+ /'* 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 get_pattern_row_channel_volume_effect_type
+ '/
+ get_pattern_row_channel_effect_type As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal pattern As Long, ByVal row As Long, ByVal channel As Long) As Long
+End Type
+
+#define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE "interactive"
+
+Type 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].
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the speed is outside the specified range.
+ \return 1 on success, 0 on failure.
+ \sa openmpt_module_get_current_speed
+ '/
+ set_current_speed As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal speed As Long) As Long
+
+ /'* 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 set_tempo_factor to apply a tempo factor that is independent of pattern commands.
+ \sa openmpt_module_get_current_tempo
+ '/
+ set_current_tempo As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal tempo As Long) As Long
+
+ /'* 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 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
+ '/
+ set_tempo_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal factor As Double) As Long
+
+ /'* 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
+ '/
+ get_tempo_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr) As Double
+
+ /'* 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 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: `2.0 ^ ( n / 12.0 )`
+ \sa openmpt_module_ext_interface_interactive.get_pitch_factor
+ '/
+ set_pitch_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal factor As Double) As Long
+
+ /'* 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
+ '/
+ get_pitch_factor As Function(ByVal mod_ext As openmpt_module_ext Ptr) As Double
+
+ /'* 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
+ '/
+ set_global_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal volume As Double) As Long
+
+ /'* 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
+ '/
+ get_global_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr) As Double
+
+ /'* 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
+ '/
+ set_channel_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal volume As Double) As Long
+
+ /'* 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
+ '/
+ get_channel_volume As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double
+
+ /'* 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
+ '/
+ set_channel_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal mute As Long) As Long
+
+ /'* 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. true is muted, false is unmuted.
+ \sa openmpt_module_ext_interface_interactive.set_channel_mute_status
+ '/
+ get_channel_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long
+
+ /'* 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
+ '/
+ set_instrument_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal instrument As Long, ByVal mute As Long) As Long
+
+ /'* 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
+ '/
+ get_instrument_mute_status As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal instrument As Long) As Long
+
+ /'* 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 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
+ \sa openmpt_module_ext_interface_interactive2.note_off
+ \sa openmpt_module_ext_interface_interactive2.note_fade
+ '/
+ play_note As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal instrument As Long, ByVal note As Long, ByVal volume As Double, ByVal panning As Double) As Long
+
+ /'* 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. This is the value returned by a previous play_note call.
+ \return 1 on success, 0 on failure (channel out of range).
+ \sa openmpt_module_ext_interface_interactive.play_note
+ \sa openmpt_module_ext_interface_interactive.note_off
+ \sa openmpt_module_ext_interface_interactive2.note_fade
+ '/
+ stop_note As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long
+End Type
+
+#define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 "interactive2"
+
+Type openmpt_module_ext_interface_interactive2
+
+ /'* Sends a key-off command for the note playing on the specified channel
+
+ \param mod_ext The module handle to work on.
+ \param channel The channel on which the key-off event should be triggered. This is the value returned by a previous play_note call.
+ \return 1 on success, 0 on failure (channel out of range).
+ \remarks This method releases envelopes and sample sustain loops. If the sample has no sustain loop, or if the module does not use instruments, it does nothing.
+ \sa openmpt_module_ext_interface_interactive.play_note
+ \sa openmpt_module_ext_interface_interactive.stop_note
+ \sa note_fade
+ '/
+ note_off As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long
+
+ /'* Sends a note fade command for 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 faded. This is the value returned by a previous play_note call.
+ \return 1 on success, 0 on failure (channel out of range).
+ \remarks This method uses the instrument's fade-out value. If the module does not use instruments, or the instrument's fade-out value is 0, it does nothing.
+ \sa openmpt_module_ext_interface_interactive.play_note
+ \sa openmpt_module_ext_interface_interactive.stop_note
+ \sa note_fade
+ '/
+ note_fade As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Long
+
+ /'* Set the current panning for a channel
+
+ \param mod_ext The module handle to work on.
+ \param channel The channel that should be panned. This is the value returned by a previous play_note call.
+ \param panning The panning position to set on the channel, in range [-1.0, 1.0], 0.0 is center.
+ \return 1 on success, 0 on failure (channel out of range).
+ \remarks This command affects subsequent notes played on the same channel, and may itself be overridden by subsequent panning commands encountered in the module itself.
+ \sa openmpt_module_ext_interface_interactive2.get_channel_panning
+ '/
+ set_channel_panning As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal panning As Double) As Long
+
+ /'* Get the current panning position for a channel
+
+ \param mod_ext The module handle to work on.
+ \param channel The channel whose panning should be retrieved. This is the value returned by a previous play_note call.
+ \return The current channel panning, in range [-1.0, 1.0], 0.0 is center.
+ \sa openmpt_module_ext_interface_interactive2.set_channel_panning
+ '/
+ get_channel_panning As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double
+
+ /'* Set the finetune for the currently playing note on a channel
+
+ \param mod_ext The module handle to work on.
+ \param channel The channel whose finetune will be changed, in range [0, openmpt::module::get_num_channels()[
+ \param finetune The finetune to set on the channel, in range [-1.0, 1.0], 0.0 is center.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone.
+ \remarks This command does not affect subsequent notes played on the same channel, but may itself be overridden by subsequent finetune commands encountered in the module itself.
+ \sa openmpt_module_ext_interface_interactive2.get_note_finetune
+ '/
+ set_note_finetune As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long, ByVal finetune As Double) As Long
+
+ /'* Get the finetune for the currently playing note on a channel
+
+ \param mod_ext The module handle to work on.
+ \param channel The channel whose finetune should be retrieved, in range [0, openmpt::module::get_num_channels()[
+ \return The current channel finetune, in range [-1.0, 1.0], 0.0 is center.
+ \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ \sa openmpt_module_ext_interface_interactive2.set_note_finetune
+ '/
+ get_note_finetune As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double
+End Type
+
+End Extern
+
+/'* \brief Construct an openmpt_module_ext
+
+ \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 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_ext_create
+'/
+Function openmpt_module_ext_create_from_fbhandle(_
+ 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_ext Ptr
+ Return openmpt_module_ext_create(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_ext
+
+ \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 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_ext_create
+'/
+Function openmpt_module_ext_create_from_filename(_
+ ByRef filename As String,_
+ 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_ext Ptr
+ Var file = fopen(filename, "rb")
+ Var retval = CPtr(openmpt_module Ptr, 0)
+ If(file <> 0) Then
+ retval = openmpt_module_ext_create(openmpt_stream_get_file_callbacks(), file, logfunc, loguser, errfunc, erruser, errorcode, error_message, ctls)
+ fclose(file)
+ EndIf
+ Return retval
+End Function
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/doc/in_openmpt.txt b/Src/external_dependencies/openmpt-trunk/libopenmpt/doc/in_openmpt.txt
new file mode 100644
index 00000000..277f9ba5
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/doc/in_openmpt.txt
@@ -0,0 +1,17 @@
+
+in_openmpt
+==========
+
+in_openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input
+plugin for Winamp >= 2.0 (or compatible players). in_openmpt is based on
+libopenmpt.
+
+
+Installation
+------------
+
+"in_openmpt.dll" must be placed into the Winamp "Plugins" directory, and
+"openmpt-mpg123.dll" must be placed into the Winamp directory.
+
+
+See https://lib.openmpt.org/ for documentation, FAQ and other details.
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/doc/xmp-openmpt.txt b/Src/external_dependencies/openmpt-trunk/libopenmpt/doc/xmp-openmpt.txt
new file mode 100644
index 00000000..ffc54c0a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/doc/xmp-openmpt.txt
@@ -0,0 +1,16 @@
+
+xmp-openmpt
+===========
+
+xmp-openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input
+plugin for XMPlay >= 3.8.0.0. xmp-openmpt is based on libopenmpt.
+
+
+Installation
+------------
+
+"xmp-openmpt.dll" and "openmpt-mpg123.dll" must both be placed into the XMPlay
+plugins directory.
+
+
+See https://lib.openmpt.org/ for documentation, FAQ and other details.
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/changelog.md b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/changelog.md
new file mode 100644
index 00000000..4973dda6
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/changelog.md
@@ -0,0 +1,1087 @@
+
+Changelog {#changelog}
+=========
+
+For fully detailed change log, please see the source repository directly. This
+is just a high-level summary.
+
+### libopenmpt 0.6.6 (2022-09-25)
+
+ * [**Sec**] Possible crash when playing manipulated IT / MPTM files with a T00
+ command. (r17789)
+
+ * MTM: In MultiTracker, setting speed and tempo are mutually exclusive
+ commands. Still, some MultiTracker modules were made to be played with
+ external players such as DMP, so they actually rely on "standard" speed /
+ tempo behaviour. Decide which behaviour to use by checking of speed and
+ tempo commands are found on the same row.
+ * MTM: Ignore sample loops if the loop end is <= 2.
+ * Echo DMO: Migrate left and right delay values in modules made with OpenMPT
+ versions between 1.27.01.00 and 1.30.05.00 to the correct interpretation.
+
+ * FLAC: Update to v1.4.1 (2022-09-22).
+
+### libopenmpt 0.6.5 (2022-08-21)
+
+ * [**Bug**] `Makefile` now also uses `CC`, `CXX`, `LD`, and `AR` when set as
+ environment variables.
+ * [**Bug**] libopenmpt can now be built to target macOS down to version 10.13
+ again.
+
+ * [**New**] `Makefile` now uses `PKG_CONFIG` as path to `pkg-config`.
+
+ * DBM: Sample middle-C frequencies were slightly off.
+ laffik_-_marynarze.dbm sounds much more bearable now.
+ * DBM: Fixed pattern break parameter interpretation.
+ * Echo DMO: Setting the delay parameter to 0 yielded a 2-second echo delay
+ instead of 1ms.
+ * Digi Booster Echo: Setting the delay parameter to 0 yielded a 510ms echo
+ delay instead of approximately 334ms.
+
+ * mpg123: Update to v1.30.2 (2022-08-01).
+
+### libopenmpt 0.6.4 (2022-06-12)
+
+ * [**Bug**] openmpt123: Linking failed when using Autotools build system
+ targeting MinGW.
+ * [**Bug**] tests: Linking failed when using Autotools build system targeting
+ MinGW.
+ * [**Bug**] examples: Linking failed when using Autotools build system
+ targeting MinGW.
+
+ * [**Change**] Support for mingw-std-threads when building for MinGW targets
+ is now deprecated because this is not supported for GCC 11 or later (see
+ <https://github.com/meganz/mingw-std-threads/issues/79>).
+
+ * Ping-pong sample loops sometimes stopped playing at the end of the loop.
+
+### libopenmpt 0.6.3 (2022-04-24)
+
+ * Pitch / Pan Separation and Random Variation instrument properties were not
+ resetting properly when seeking, potentially causing instruments to be
+ played e.g. at a vastly different pan position compared to playing the
+ module continuously.
+ * MED: Stereo samples were not imported correctly.
+
+ * zlib: Update to v1.2.12 (2022-03-27).
+
+### libopenmpt 0.6.2 (2022-03-13)
+
+ * [**Sec**] Possible out-of-bounds write in malformed IT / XM / MPTM files
+ using the internal LFO plugin. (r17076)
+ * [**Sec**] Possible out-of-bounds read when using Amiga BLEP interpolation
+ with extremely high-pitched notes. (r17078, r17079)
+
+ * ISO-8859-1-related charsets from Amiga OS and RISC OS are now handled more
+ accurately, thus avoiding some unwanted control characters.
+ * MO3: Pattern indices 254 / 255 were not treated as playable patterns even if
+ the original file was a MOD / XM.
+ * Correctly apply ST3-style effect memory when seeking in S3M files.
+ * Command S (S3M / IT style) effect memory was not applied when seeking.
+ * Initial channel mute status was not reported correctly in `get_channel_mute_status`
+ since libopenmpt 0.6.0.
+
+ * FLAC: Update to v1.3.4 (2022-02-21).
+ * pugixml: Update to v1.12.1 (2022-02-16).
+
+### libopenmpt 0.6.1 (2022-01-30)
+
+ * [**Bug**] Linking libmpg123 no longer fails on OpenBSD.
+ * [**Bug**] Possible hang with malformed DMF, DSM, MED, MUS, OKT and SymMOD
+ files containing 65536 or more patterns when destroying the module.
+ * [**Bug**] Avoid NaNs and infinite values with custom tunings and in the
+ I3DL2Reverb plugin.
+
+ * MIDI macros are now evaluated when seeking.
+ * The letter "z" is now evaluated in fixed MIDI macros (Z80...ZFF) the same
+ way as in Impulse Tracker.
+ * MOD: Loosened VBlank timing heuristics so that "frame of mind" by Dascon
+ plays correctly.
+ * MOD: Validate the contents of "hidden" patterns beyond the end of the order
+ list when the file size matches the expected size when only taken "official"
+ patterns into account. This fixes Shofixti Ditty.mod from Star Control 2
+ while keeping other (partly broken) modules working.
+ * MED: Command 20 (reverse sample) is now only applied when it's next to a
+ note.
+ * S3M: Introducing the "Send OPL key-off when triggering notes" compatibility
+ setting broke retrigger for OPL notes again (they retriggered rather than
+ not retriggering).
+ * S3M: Retriggering a note no longer resets its pitch after a portamento.
+ * S3M: Partially implement retrigger behaviour for stopped notes in
+ SoundBlaster mode: Like in IT, it is not possible to retrigger a sample that
+ has already stopped playing.
+ * DIGI: Improve compatibility with E3x reverse sample command.
+ * DSym: Tempos < 32 were treated as tempo slides.
+ * SymMOD: Key-off command was not implemented properly.
+
+### libopenmpt 0.6.0 (2021-12-23)
+
+ * [**New**] `MUS` files from Psycho Pinball and Micro Machines 2 are now
+ supported.
+ * [**New**] `SymMOD` files created with Symphonie / Symphonie Pro are now
+ supported.
+ * [**New**] `FMT` files created with Davey W Taylor's FM Tracker are now
+ supported.
+ * [**New**] `DSYM` files created with Digital Symphony are now supported.
+ * [**New**] `STX` files (transitional format between Scream Tracker 2 and 3)
+ are now supported.
+ * [**New**] TakeTracker MODs with `TDZ1` to `TDZ3` magic bytes are now
+ supported.
+ * [**New**] openmpt123: openmpt123 will now expand file wildcards passed on
+ the command line in Windows when built with MSVC.
+ * [**New**] libopenmpt_ext: New interface `interactive2` adding
+ `openmpt::ext::interactive2::note_off()`,
+ `openmpt::ext::interactive2::note_fade()`,
+ `openmpt::ext::interactive2::set_channel_panning()`,
+ `openmpt::ext::interactive2::get_channel_panning()`,
+ `openmpt::ext::interactive2::set_note_finetune()`, and
+ `openmpt::ext::interactive2::get_note_finetune()` (C++) and
+ `openmpt_module_ext_interface_interactive2.note_off()`,
+ `openmpt_module_ext_interface_interactive2.note_fade()`,
+ `openmpt_module_ext_interface_interactive2.set_channel_panning()`,
+ `openmpt_module_ext_interface_interactive2.get_channel_panning()`,
+ `openmpt_module_ext_interface_interactive2.set_note_finetune()`, and
+ `openmpt_module_ext_interface_interactive2.get_note_finetune()` (C).
+ * [**New**] `Makefile` `CONFIG=emscripten` now supports
+ `EMSCRIPTEN_TARGET=audioworkletprocessor` which builds an ES6 module in
+ a single file with reduced dependencies suitable to be used in an
+ AudioWorkletProcessor.
+ * [**New**] `Makefile` `CONFIG=emscripten` now supports `EMSCRIPTEN_PORTS=1`
+ which uses dependencies (zlib, mp123, ogg, and vorbis) from Emscripten Ports
+ instead of using miniz, minimp3, and stb_vorbis locally or building zlib,
+ mp123, ogg, and vorbis locally.
+ * [**New**] `Makefile` `CONFIG=emscripten` and `CONFIG=djgpp` can now build
+ zlib, mpg123, and vorbis locally instead of only supporting miniz, minimp3,
+ and stb_vorbis via `ALLOW_LGPL=1`.
+
+ * [**Change**] `Makefile` `CONFIG=emscripten` now supports
+ `EMSCRIPTEN_TARGET=all` which provides WebAssembly as well as fallback to
+ JavaScript in a single build.
+ * [**Change**] openmpt123: DOS builds now use the Mercury fork of
+ `liballegro 4.2` for improved hardware compatibility.
+ * [**Change**] libopenmpt no longer generates internal interpolation tables on
+ library load time, but instead only on first module load time.
+
+ * [**Regression**] `Makefile` `CONFIG=emscripten` does not support
+ `EMSCRIPTEN_TARGET=asmjs` or `EMSCRIPTEN_TARGET=asmjs128m` any more because
+ support has been removed from current Emscripten versions.
+ * [**Regression**] Support for GCC 7 has been removed.
+ * [**Regression**] Support for Clang 5, 6 has been removed.
+ * [**Regression**] Support for Emscripten versions older than 1.39.7 has been
+ removed.
+ * [**Regression**] Building with Android NDK older than NDK r19c is not
+ supported any more.
+
+ * libopenmpt can now detect infinite pattern loops and treats them as the song
+ end. This means that setting a repeat count other than -1 now always
+ guarantees that playback will eventually end. The song loop counter is
+ decremented each time it ends up at the start of the infinite loop, so the
+ song does not restart from the beginning even if the repeat count is not 0.
+ * `openmpt::module::set_position_seconds()` accuracy has been improved for
+ modules with pattern loops.
+ * Samples played at the wrong volume when rendering modules in mono.
+ * IT: Portamentos in files with Linear Slides disabled are now more accurate.
+ * IT: Pitch/Pan Separation was affected by note-off commands, and wasn't reset
+ by panning commands like in Impulse Tracker.
+ * IT: Even after libopenmpt 0.5.14 the filter reset logic was still not 100%
+ identical to Impulse Tracker: A note triggered on tick 0 of a row with a
+ Pattern Delay effect still caused the filter to be reset on repetitions of
+ that row even though the note wasn't retriggered.
+ * IT: Added read-only support for BeRoTracker commands 1 and 2 (equivalent to
+ XM commands K and L).
+ * XM: BeRoTracker saves smooth MIDI macros in a different way from OpenMPT.
+ This command is now imported correctly.
+ * XM: Emulate FT2 Tone Portamento quirk that inverts portamento direction
+ after the target was reached (if target note was higher than previous note).
+ * S3M files saved with Impulse Tracker and latest Schism Tracker now also
+ compute sample playback speed in Hertz.
+ * Depending on whether an S3M file was last saved in Scream Tracker with the
+ Sound Blaster or Gravis Ultrasound drivers loaded, different compatibility
+ flags are now applied. For files saved with the GUS, the sample volume
+ factor is now also ignored (fixes volume levels in S3Ms made on the GUS, in
+ particular if they use both samples and OPL instruments).
+ * S3M: Enforce the lower frequency bound.
+ * MOD: Loosened VBlank timing heuristics so that the original copy of
+ Guitar Slinger from Dizzy Tunes II plays correctly.
+ * FAR: Correct portamento depth is now used.
+ * DMF / IMF: Improved accuracy of finetune commands.
+ * MDL: Implemented finetune command.
+ * OKT: Various accuracy improvements such as: Sharing volume between mixed
+ channels, volume commands on mixed channels are permanent (not reset with
+ new notes), mixed channels do not support default sample volume, 7-bit
+ samples are actually supposed to be played as-is (not amplified to full
+ 8-bit range), reject speed command parameters >= 20.
+
+ * zlib: v1.2.11 (2017-01-15).
+ * mpg123: v1.29.3 (2021-12-11).
+ * ogg: v1.3.5 (2021-06-04).
+ * vorbis: v1.3.7 (2020-07-04).
+ * miniz: v2.2.0 (2021-06-27).
+ * minimp3: commit 50d2aaf360a53653b718fead8e258d654c3a7e41 (2021-11-27).
+ * stb_vorbis: v1.22 commit 5a0bb8b1c1b1ca3f4e2485f4114c1c8ea021b781
+ (2021-07-12).
+ * FLAC: v1.3.3 (2019-08-04).
+ * PortAudio: v19.7.0 (2021-04-06).
+
+### libopenmpt 0.5.0 (2020-05-24)
+
+ * [**New**] OggMod compressed FastTracker 2 XM (OXM) modules are now
+ supported.
+ * [**New**] The emulated Amiga type when Amiga resampler emulation is enabled
+ can now be selected via ctl `render.resampler.emulate_amiga_type`. Possible
+ values are: `"auto"`, `"a500"`, `"a1200"`, and an experimental option
+ `"unfiltered"`.
+ * [**New**] libopenmpt: New API `openmpt::module::get_current_estimated_bpm()`
+ (C++), and `openmpt_module_get_current_estimated_bpm()` (C) which provides
+ accurate beats per minute information for module formats with time signature
+ and an educated guess based on speed and tempo for others.
+ * [**New**] libopenmpt: New type-aware ctl APIs that do not require memory
+ allocations and are thus realtime-safe:
+ `openmpt::module::ctl_get_boolean()`, `openmpt::module::ctl_get_integer()`,
+ `openmpt::module::ctl_get_floatingpoint()`,
+ `openmpt::module::ctl_get_text()`, `openmpt::module::ctl_set_boolean()`,
+ `openmpt::module::ctl_set_integer()`,
+ `openmpt::module::ctl_set_floatingpoint()` (C++), and
+ `openmpt_module_ctl_get_boolean()`, `openmpt_module_ctl_get_integer()`,
+ `openmpt_module_ctl_get_floatingpoint()`, `openmpt_module_ctl_get_text()`,
+ `openmpt_module_ctl_set_boolean()`, `openmpt_module_ctl_set_integer()`,
+ `openmpt_module_ctl_set_floatingpoint()` (C).
+ * [**New**] libopenmpt C++ New API `openmpt::is_extension_supported2()` which
+ takes a `std::string_view` parameter instead of `std::string`.
+ * [**New**] libopenmpt C++: New API
+ `openmpt::module::module(std::vector<std::byte> data)`,
+ `openmpt::module::module(const std::byte * data, std::size_t size)`,
+ `openmpt::module::module(const std::byte * beg, const std::byte * end)`.
+ * [**New**] libopenmpt C++: New API
+ `openmpt::probe_file_header(flags, const std::byte * data, std::size_t size, filesize)`,
+ `openmpt::probe_file_header(flags, const std::byte * data, std::size_t size)`.
+ * [**New**] libopenmpt_ext C++: New API
+ `openmpt::module_ext::module_ext(std::vector<std::byte> data)`,
+ `openmpt::module_ext::module_ext(const std::byte * data, std::size_t size)`,
+ `openmpt::module_ext::module_ext(std::vector<std::uint8_t> data)`,
+ `openmpt::module_ext::module_ext(const std::uint8_t * data, std::size_t size)`.
+
+ * [**Change**] std::istream based file I/O has been speed up.
+ * [**Change**] Dependency on iconv on Linux has been removed.
+
+ * [**Regression**] libmodplug: The libmodplug emulation layer has been removed
+ from the libopenmpt tree. Please use the separate `libopenmpt-modplug`
+ package instead.
+ * [**Regression**] foo_openmpt: foo_openmpt is discontinued. Please use
+ Kode54's fork foo_openmpt54:
+ <https://www.foobar2000.org/components/view/foo_openmpt54>.
+ * [**Regression**] Support for building with C++11 or C++14 has been removed.
+ C++17 is now required to build libopenmpt.
+ * [**Regression**] Support for client code using C++11 or C++ 14 has been
+ removed. C++17 is now required to build libopenmpt client applications.
+ * [**Regression**] Support for Visual Studio 2015 has been removed.
+ * [**Regression**] Support for GCC 4.8, 4.9, 5, 6 has been removed.
+ * [**Regression**] Support for Clang 3.6, 3.7, 3.8, 3.9, 4 has been removed.
+ * [**Regression**] Support for Emscripten versions older than 1.39.1 has been
+ removed.
+ * [**Regression**] Building with Android NDK older than NDK r18b is not
+ supported any more.
+ * [**Regression**] openmpt123: Support for SDL1 (but not SDL2) output has been
+ removed.
+ * [**Regression**] openmpt123: Support for SDL2 older than 2.0.4 has been
+ removed.
+ * [**Regression**] Windows XP and Windows Vista are no longer supported.
+ * [**Regression**] It is no longer possible to optionally use iconv for
+ character set conversions.
+
+ * [**Bug**] openmpt123: openmpt123 now honors the current locale and outputs
+ text appropriately.
+ * [**Bug**] openmpt123: Piping text output to other than console window
+ targets on Windows has been fixed.
+
+ * Greatly improved MED import. Synthesized instruments are still not supported
+ but support was added for: Multisampled instruments, delta samples, more
+ pattern commands, Hold and Decay, multiple songs and many other small
+ changes.
+ * Improved OPL channel allocation when more than 18 notes are active, so that
+ channels that have completely faded out are prioritized over channels that
+ have already been released but have not faded out yet.
+ * Interactively triggering an OPL instrument could cause the first pattern
+ channel to no longer be played back correctly.
+ * Fix some inaccuracies in OPL emulator.
+ * Fix overflow of OPL amplification happening at a synth volume level of 510.
+ * End-of-sample pop reduction of surround channels was applied to front
+ channels instead, causing a pop on the front channels instead of removing it
+ on the back channels.
+ * IT: Disable retrigger with short notes quirk for modules saved with
+ Chibi Tracker, as it does not implement that quirk.
+ * IT: Instrument and sample panning should not override channel panning for
+ following notes.
+ * IT: SBx is now prioritized over Bxx commands that are to the left of it.
+ * IT: Duplicate Check Type "Sample" should only be applied if the instruments
+ match, too.
+ * IT: Duplicate Check Type "Note" should compare pattern notes, but it was
+ comparing the new pattern note against the old translated note.
+ * IT: Various fixes for envelope resetting.
+ * IT / S3M: When combining SBx and EEx effects, don't skip the first row of
+ the loop like in FastTracker 2.
+ * S3M: Empty pattern commands now affect effect memory as well.
+ * S3M: Offset beyond loop end wraps around to loop start like in
+ Scream Tracker 3 + GUS (previously it just keep playing from the loop start,
+ which is neither what GUS nor Sound Blaster drivers do).
+ * S3M: Notes cannot be retriggered after they have been cut.
+ * S3M: Fix portamento after note cut (fixes antediluvian_song.s3m).
+ * S3M / MOD: Previous note offset is no longer used for retriggered notes if
+ there was no instrument number next to the Qxy effect.
+ * MOD: Sample swapping now also works if the sample that is being swapped from
+ does not loop. Swapping to a non-looped sample now stops playback once the
+ swapped-from sample reaches its (loop) end.
+ * MOD: Fix early song ending due to ProTracker pattern jump quirk
+ (EEx + Dxx on same row) if infinite looping is disabled.
+ Fixes Haunted Tracks.mod by Triace.
+ * MOD: Previous note offset is no longer used for retriggered notes if there
+ was no instrument number next to the E9x effect.
+ * MOD: Vibrato type "ramp down" was upside down.
+ * XM: If a file contains patterns longer than 1024 rows, they are now clamped
+ to 1024 rows instead of 64 rows.
+ * XM: Do not reset note-off status on portamento if there is no instrument
+ number.
+
+ * mpg123: v1.26rc3.
+ * ogg: v1.3.4.
+ * vorbis: v1.3.6.
+ * zlib: v1.2.11.
+ * minimp3: commit 55da78cbeea5fb6757f8df672567714e1e8ca3e9 (2020-03-04).
+ * stb_vorbis: v1.19 commit 37b9b20fdec06c75a0493e0bb59e2d0f288bfb51
+ (2020-02-05).
+ * miniz: v2.1.0.
+ * FLAC: v1.3.3.
+ * PortAudio: commit 799a6834a58592eadc5712cba73b35956dc51579 (2020-03-26).
+
+### libopenmpt 0.4.0 (2018-12-23)
+
+ * [**New**] libopenmpt now includes emulation of the OPL chip and thus plays
+ OPL instruments in S3M, C67 and MPTM files. OPL chip emulation volume can be
+ changed with the new ctl `render.opl.volume_factor`.
+ * [**New**] libopenmpt now supports CDFM / Composer 670 module files.
+ * [**New**] Autotools `configure` and plain `Makefile` now honor the variable
+ `CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing the
+ standard library (or libraries) required for static linking. The contents of
+ this variable will be put in `libopenmpt.pc` `Libs.private` and used for
+ nothing else. See \ref libopenmpt_c_staticlinking .
+ * [**New**] foo_openmpt: foo_openmpt now also works on Windows XP.
+ * [**New**] libopenmpt Emscripten builds now ship with MP3 support by
+ default, based on minimp3 by Lion (github.com/lieff).
+ * [**New**] libopenmpt: New ctl `play.at_end` can be used to change what
+ happens when the song end is reached:
+ * "fadeout": Fades the module out for a short while. Subsequent reads
+ after the fadeout will return 0 rendered frames. This is the default and
+ identical to the behaviour in previous libopenmpt versions.
+ * "continue": Returns 0 rendered frames when the song end is reached.
+ Subsequent reads will continue playing from the song start or loop
+ start. This can be used for custom loop logic, such as loop
+ auto-detection and longer fadeouts.
+ * "stop": Returns 0 rendered frames when the song end is reached.
+ Subsequent reads will return 0 rendered frames.
+ * [**New**] Add new metadata fields `"originaltype"` and `"originaltype_long"`
+ which allow more clearly reflecting what is going on with converted formats
+ like MO3 and GDM.
+ * [**New**] `Makefile` `CONFIG=emscripten` now can generate WebAssembly via
+ the additional option `EMSCRIPTEN_TARGET=wasm`.
+ * [**New**] Compiling for DOS is now experimentally supported via DJGPP GCC
+ 7.2 or later.
+
+ * [**Change**] minimp3: Instead of the LGPL-2.1-licensed minimp3 by KeyJ,
+ libopenmpt now uses the CC0-1.0-licensed minimp3 by Lion (github.com/lieff)
+ as a fallback if libmpg123 is unavailable. The `USE_MINIMP3` `Makefile`
+ option is gone and minimp3 will be used automatically in the `Makefile`
+ build system if libmpg123 is not available.
+ * [**Change**] openmpt123: openmpt123 now rejects `--output-type` in `--ui`
+ and `--batch` modes and also rejects `--output` in `--render` mode. These
+ combinations of options really made no sense and were rather confusing.
+ * [**Change**] Android NDK build system now uses libc++ (`c++_shared`) instead
+ of GNU libstdc++ (`gnustl_shared`), as recommended by Android NDK r16b.
+ * [**Change**] xmp-openmpt: `openmpt-mpg123.dll` is no longer optional and
+ must be placed into the same directory as `xmp-openmpt.dll`.
+ * [**Change**] in_openmpt: `openmpt-mpg123.dll` is no longer optional and must
+ be placed either into the directory of the player itself or into the same
+ directory as `in_openmpt.dll`. This is dependent on how the player loads its
+ plugins. For WinAMP 5, `openmpt-mpg123.dll` needs to be in the directory
+ which contains `winamp.exe`. `in_openmpt.dll` needs to be in the `Plugins`
+ directory.
+ * [**Change**] foo_openmpt: foo_openmpt is now packaged as a fb2k-component
+ package for easier installation.
+ * [**Change**] When building libopenmpt with MinGW-w64, it is now recommended
+ to use the posix thread model (as opposed to the win32 threading model),
+ because the former does support std::mutex while the latter does not. When
+ building with win32 threading model with the Autotools build system, it is
+ recommended to provide the `mingw-std-threads` package. Building libopenmpt
+ with MinGW-w64 without any `std::thread`/`std::mutex` support is deprecated
+ and support for such configurations will be removed in libopenmpt 0.5.
+ * [**Change**] `Makefile` `CONFIG=emscripten` now has 4 `EMSCRIPTEN_TARGET=`
+ settings: `wasm` generates WebAssembly, `asmjs128m` generates asm.js with a
+ fixed size 128MB heap, `asmjs` generates asm.js with a fixed default size
+ heap (as of Emscripten 1.38.11, this amounts to 16MB), `js` generates
+ JavaScript with dynamic heap growth and with compatibility for older VMs.
+ * [**Change**] libmodplug: Update public headers to libmodplug 0.8.8.5. This
+ adds support for kind-of automatic MODPLUG_EXPORT decoration on Windows.
+
+ * [**Regression**] Support for Clang 3.4, 3.5 has been removed.
+ * [**Regression**] Building with Android NDK older than NDK r16b is not
+ supported any more.
+ * [**Regression**] Support for Emscripten versions older than 1.38.5 has been
+ removed.
+ * [**Regression**] Support for libmpg123 older than 1.14.0 has been removed.
+ * [**Regression**] Using MediaFoundation to decode MP3 samples is no longer
+ supported. Use libmpg123 or minimp3 instead.
+ * [**Regression**] libmodplug: Support for emulating libmodplug 0.8.7 API/ABI
+ has been removed.
+
+ * [**Bug**] xmp-openmpt: Sample rate and number of output channels were not
+ applied correctly when using per-file settings.
+ * [**Bug**] Internal mixer state was not initialized properly when initially
+ rendering in 44100kHz stereo format.
+ * [**Bug**] openmpt123: Prevent libsdl2 and libsdl from being enabled at the
+ same time because they conflict with each other.
+ * [**Bug**] libmodplug: Setting `SNDMIX_NORESAMPLING` in the C++ API always
+ resulted in linear interpolation instead of nearest neighbour
+
+ * IT: In Compatible Gxx mode, allow sample changes next to a tone portamento
+ effect if a previous sample has already stopped playing.
+ * IT: Fix broken volume envelopes with negative values as found in breakdwn.it
+ by Elysis.
+ * MOD: Slides and delayed notes are executed on every repetition of a row with
+ row delay (fixes "ode to protracker").
+ * XM: If the sustain point of the panning envelope is reached before key-off,
+ it is never released.
+ * XM: Do not default recall volume / panning for delayed instrument-less notes
+ * XM :E60 loop bug was not considered in song length calucation.
+ * S3M: Notes without instrument number use previous note's sample offset.
+ * Tighten M15 and MOD file rejection heuristics.
+ * J2B: Ignore frequency limits from file header. Fixes Medivo.j2b, broken
+ since libopenmpt-0.2.6401-beta17.
+ * STM: More accurate tempo calculation.
+ * STM: Better support for early format revisions (no such files have been
+ found in the wild, though).
+ * STM: Last character of sample name was missing.
+ * SFX: Work around bad conversions of the "Operation Stealth" soundtrack by
+ turning pattern breaks into note stops.
+ * IMF: Filter cutoff was upside down and the cutoff range was too small.
+ * ParamEq plugin center frequency was not limited correctly.
+ * Keep track of active SFx macro during seeking.
+ * The "note cut" duplicate note action did not volume-ramp the previously
+ playing sample.
+ * A song starting with non-existing patterns could not be played.
+ * DSM: Support restart position and 16-bit samples.
+ * DTM: Import global volume.
+ * MOD: Support notes in octave 2, like in FastTracker 2 (fixes DOPE.MOD).
+ * Do not apply Amiga playback heuristics to MOD files that have clearly been
+ written with a PC tracker.
+ * MPTM: More logical release node behaviour.
+ * Subsong search is now less thorough. It could previously find many subsongs
+ that are technically correct (unplayed rows at the beginning of patterns
+ that have been jumped over due to pattern breaks), but so far no real-world
+ module that would require such a thorough subsong detection was found. The
+ old mechanism caused way more false positives than intended with real-world
+ modules, though.
+ * Restrict the unpacked size of compressed DMF, IT, MDL and MO3 samples to
+ avoid huge allocations with malformed small files.
+
+### libopenmpt 0.3 (2017-09-27)
+
+ * [**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**] 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**] 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
+ beginning of the sample to not be ignored. Since we need to ignore them in
+ some (non-ProTracker) modules, we heuristically disable the old loop
+ 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.
+ * 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.
+
+ * 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.
+ * Samples in DSM files were sometimes detuned and some pattern commands were
+ not imported correctly.
+ * More accurate import of MDL 7-bit panning command.
+ * Only import pattern commands supported by the UltraTracker version that was
+ used to save ULT files. Add support for command 5-C (end loop).
+ * DMF sample loop lengths were off by one.
+ * Unis 669 pan slide effect was too deep.
+ * Several valid (but slightly corrupted possibly due to disk failures or data
+ transfer errors) SoundTracker files were no longer loading since libopenmpt
+ 0.2-beta18.
+
+### libopenmpt 0.2-beta19 (2016-07-23)
+
+ * [**Change**] libopenmpt now uses C++14 `[[deprecated]]` attribute instead
+ of compiler-specific solutions when appropriate.
+ * [**Change**] libopenmpt C++ header now uses C++11 `noexcept` instead of
+ C++98 `throw()` exception specification when supported. `throw()` is
+ deprecated since C++11. This does not change API or ABI as they are
+ equivalent. Use `LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT` to override the
+ default.
+ * [**Change**] The preprocessor macro `LIBOPENMPT_ANCIENT_COMPILER_STDINT` is
+ gone. Please use `LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT instead`.
+ Additionally, the typedefs moved from illegal namespace ::std into somewhat
+ less dangerous namespace ::openmpt::std. You can test
+ `#ifdef LIBOPENMPT_QUIRK_NO_CSTDINT` client-side to check whether
+ `libopenmpt.hpp` used the non-standard types. (Note: Of all supported
+ compilers, this change only affects the 3 compilers with only limited
+ support: MSVC 2008, GCC 4.1, GCC 4.2.)
+
+ * [**Bug**] xmp-openmpt: Crash when viewing sample texts.
+
+ * The public libopenmpt C++ header has auto-detection logic for the used C++
+ standard now. In case your client code compiler misreports the standard
+ version or you want to override it for other reasons,
+ `#define LIBOPENMPT_ASSUME_CPLUSPLUS` to the value of the standard version
+ you desire to be used. There is also a macro for each individual aspect,
+ like `LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT`,
+ `LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED`,
+ `LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT` which take precedence over the
+ general macro.
+ * Portamento with sample swap behaviour was wrong for ProTracker MODs.
+ * Rewritten loader and various playback fixes for MDL files.
+ * libopenmpt 0.2-beta18 broke import of many pattern commands in DBM, DMF and
+ ULT files.
+ * ADPCM samples in MOD files were broken since libopenmpt 0.2-beta17.
+
+### libopenmpt 0.2-beta18 (2016-07-11)
+
+ * [**Change**] openmpt123: Add PulseAudio output support. Autotools and
+ `Makefile` build systems now depend on `libpulse` and `libpulse-simple` by
+ default. Disable with `--without-pulseaudio` or `NO_PULSEAUDIO=1`
+ respectively. When enabled, PulseAudio will be the default output driver,
+ * [**Change**] xmp-openmpt: Settings are now stored in xmplay.ini like with
+ every other plugin.
+
+ * [**Regression**] openmpt123: Support for FLAC < 1.3.0 has been removed. FLAC
+ before 1.3.0 is broken beyond repair as it provides `assert.h` in the
+ include path.
+
+ * [**Bug**] Generated pkg-config file libopenmpt.pc by both `Makefile` and
+ Autotools build systems was totally broken.
+ * [**Bug**] libopenmpt no longer uses the non-thread-safe global std::rand()
+ function.
+ * [**Bug**] Sample loops in GDM modules did not work when using Emscripten.
+ * [**Bug**] XM and MO3 loaders could crash due to unaligned memory accesses.
+ * [**Bug**] Fixed incorrect handling of custom MPTM tunings on big endian
+ platforms.
+ * [**Bug**] Fixed various problems found with clang 3.8 static analyzer,
+ address sanitizer and undefined behaviour sanitizer.
+ * [**Bug**] File header probing functionality was broken for most formats.
+ * [**Bug**] With non-seekable streams, the entire file was almost always
+ cached even if it was not of any supported module type.
+
+ * Seeking in allsubsongs-mode now works correctly.
+ * openmpt123: Added subsong support.
+ * Various playback fixes for 669, IT, MT2 and MTM files.
+ * Some MOD files with more than 128 patterns (e.g. NIETNU.MOD) were not loaded
+ correctly.
+ * A new example `libopenmpt_example_c_probe` has been added which demonstrates
+ the usage and flexibility of openmpt_could_open_propability() in the C API
+ under various constraints.
+
+### libopenmpt 0.2-beta17 (2016-05-21)
+
+ * [**Change**] The Makefile and Autotools build systems now require to
+ explicitly specify `NO_LTDL=1` or `--without-ltdl` respectively if no
+ support for dynamic loading of third party libraries via libtool libltdl is
+ desired.
+ * [**Change**] In the Makefile build system option `USE_MO3` and the Autotools
+ build system option `--enable-mo3` are gone. Dynamic loading of un4seen
+ unmo3 is now always enabled when dynamic loading is possible and built-in
+ MO3 support is not possible because either a MP3 or a Vorbis decoder is
+ missing.
+ * [**Change**] The MSVC build system changed. The `libopenmptDLL` project is
+ gone. Use the new `ReleaseShared` configuration of the `libopenmpt` project
+ instead. libopenmpt now links against zlib by default. A separate project
+ with smaller footprint linking against miniz is still available as
+ `libopenmpt-small`.
+ * [**Change**] The constants used to query library information from
+ `openmpt_get_string()` and `openmpt::string::get()` (i.e. OPENMPT_STRING_FOO
+ and openmpt::string::FOO) have been deprecated because having syntactic
+ constants for theses keys makes extending the API in a backwards and
+ forwards compatible way harder than it should be. Please just use the string
+ literals directly.
+ * [**Change**] Deprecated API identifiers will now cause deprecation warnings
+ with MSVC, GCC and clang. `#define LIBOPENMPT_NO_DEPRECATE` to disable the
+ warnings.
+ * [**Change**] openmpt123: `--[no-]shuffle` option has been renamed to
+ `--[no-]randomize`. A new `--[no-]shuffle` option has been added which
+ shuffles randomly through the playlist as opposed to randomizing the
+ playlist upfront.
+ * [**Change**] Support for Un4seen unmo3 has generally been deprecated in
+ favour of the new internal mo3 decoder. Un4seen unmo3 support will be
+ removed on 2018-01-01.
+
+ * [**Bug**] Memory consumption during loading has been reduced by about 1/3 in
+ case a seekable input stream is provided (either via C API callback open
+ functions or via C++ API iostream constructors).
+ * [**Bug**] Some samples in AMS modules were detuned when using Emscripten.
+ * [**Bug**] Possible crash with excessive portamento down in some formats.
+ * [**Bug**] Possible crashes with malformed AMF, AMS, DBM, IT, MDL, MED, MPTM,
+ MT2, PSM and MMCMP-, XPK- and PP20-compressed files.
+ * [**Bug**] `openmpt::module::format_pattern_row_channel` with `width == 0`
+ was returning an empty string instead of an string with unconstrained
+ length.
+
+ * Support for ProTracker 3.6 IFF-style modules and SoundFX / MultiMedia Sound
+ (SFX / MMS) modules.
+ * libopenmpt now has support for DMO plugins on Windows when built with MSVC.
+ Additionally, the DMO Compression, Distortion, Echo, Gargle, ParamEQ and
+ WavesReverb DSPs are emulated on on all other platforms.
+ * libopenmpt now supports the DigiBooster Echo DSP.
+ * To avoid any of the aforementioned plugins to be used, the load.skip_plugins
+ ctl can be passed when loading a module.
+ * libopenmpt got native MO3 support with MP3 decoding either via libmpg123 or
+ MediaFoundation (on Windows 7 and up) and Vorbis decoding via libogg,
+ libvorbis, libvorbisfile or stb_vorbis.
+ * libopenmpt MSVC builds with Visual Studio 2010 or later on Windows 7 or
+ later now use an internal MO3 decoder with libogg, libvorbis, libvorbisfile,
+ and libmpg123 or minimp3 or MediaFoundation suppport by default. Visual
+ Studio 2008 builds still use unmo3.dll by default but also support the
+ built-in decoder in which case libmpg123 is required.
+ * libopenmpt with Makefile or Autotools build system can now also use
+ glibc/libdl instead of libtool/libltdl for dynamic loading of third-party
+ libraries. Options `NO_DL=1` and `--without-dl` have been added
+ respectively.
+ * The `Makefile` build system got 4 new options NO_MPG123, NO_OGG, NO_VORBIS,
+ NO_VORBISFILE. The default is to use the new dependencies automatically.
+ * The `Autotools` build system got 4 new options --without-mpg123,
+ --without-ogg, --without-vorbis, --without-vorbisfile. The default is to use
+ the new dependencies automatically.
+ * Makefile and Android builds got support for using minimp3 instead of
+ libmpg123. For Android, use `Android-minimp3-stbvorbis.mk`, for Makefile use
+ `USE_MINIMP3=1`. You have to download
+ [minimp3](http://keyj.emphy.de/minimp3/) yourself and put its contents into
+ `include/minimp3/`.
+ * `"source_url"`, `"source_date"` and `"build_compiler"` keys have been added
+ to `openmpt_string_get()` and `openmpt::string::get()`.
+ * openmpt123: Add new `--[no-]restart]` option which restarts the playlist
+ when finished.
+ * Improved Ultimate SoundTracker version detection heuristics.
+ * Playing a sample at a sample rate close to the mix rate could lead to small
+ clicks when using vibrato.
+ * More fine-grained internal legacy module compatibility settings to correctly
+ play back modules made with older versions of OpenMPT and a few other
+ trackers.
+ * The tail of compressed MDL samples was slightly off.
+ * Some probably hex-edited XM files (e.g. cybernostra weekend.xm) were not
+ loaded correctly.
+ * Countless other playback fixes for MOD, XM, S3M, IT and MT2 files.
+
+### libopenmpt 0.2-beta16 (2015-11-22)
+
+ * [**Change**] The Autotools build system does strict checking of all
+ dependencies now. Instead of best effort auto-magic detection of all
+ potentially optional dependencies, the default set of dependencies is now
+ enforced unless each individual dependency gets explicitely disabled via
+ `--without-foo` or `--disable-foo` `./configure` switches. Run
+ `./configure --help` for the full list of options.
+
+ * [**Bug**] Some MOD files were erroneously detected as 669 files.
+ * [**Bug**] Some malformed AMF files could result in very long loading times.
+ * [**Bug**] Fixed crashes in IMF and MT2 loaders.
+ * [**Bug**] MTM files generated by UNMO3 were not loaded properly.
+
+ * Improved MTM playback.
+ * `make CONFIG=haiku` for Haiku has been added.
+ * Language bindings for FreeBASIC have been added (see
+ `libopenmpt/bindings/`).
+
+### libopenmpt 0.2-beta15 (2015-10-31)
+
+ * [**Change**] openmpt123: SDL2 is now supported and preferred to SDL1 if
+ available with the `Makefile` build system.
+
+ * [**Bug**] Emscripten support for older emscripten versions broke in -beta14.
+ These are now supported again when using `make CONFIG=emscripten-old`.
+ * [**Bug**] Fixed crashes in MED loader.
+
+ * Playback improvements and loader fixes for MOD, MT2 and MED.
+
+### libopenmpt 0.2-beta14 (2015-09-13)
+
+ * [**Change**] The C++ API example now uses the PortAudio C++ bindings
+ instead of the C API.
+ * [**Change**] Default compiler options for Emscripten have been changed to
+ more closely match the Emscripten recommendations.
+
+ * [**Bug**] Client code compilation with C89 compilers was broken in beta13.
+ * [**Bug**] Test suite failed on certain Emscripten/node.js combinations.
+ * [**Bug**] Fixed various crashes or hangs in DMF, OKT, PLM, IT and MPTM
+ loaders.
+
+ * Implemented error handling in the libopenmpt API examples.
+ * Various playback improvements and fixes for OKT, IT and MOD.
+
+### libopenmpt 0.2-beta13 (2015-08-16)
+
+ * [**Change**] The MSVC build system has been redone. Solutions are now
+ located in `build/vsVERSION/`.
+
+ * [**Bug**] get_current_channel_vu_left and get_current_channel_vu_right only
+ return the volume of the front left and right channels now.
+ get_current_channel_vu_rear_left and get_current_channel_vu_rear_right
+ do now actually work and return non-zero values.
+ * [**Bug**] Fix crashes and hangs in MED and MDL loaders and with some
+ truncated compressed IT samples.
+ * [**Bug**] Fix crash when playing extremely high-pitched samples.
+
+ * Completed C and C++ documentation
+ * Added new key for openmpt::module::get_metadata, "message_raw", which
+ returns an empty string if there is no song message rather than a list of
+ instrument names.
+ * in_openmpt: Support for compiling with VS2008.
+ * xmp-openmpt: Support for compiling with VS2008.
+ * in_openmpt: Add a more readable file information window.
+
+### libopenmpt 0.2-beta12 (2015-04-19)
+
+ * Playback fix when row delay effect is used together with offset command.
+ * A couple of fixes for the seek.sync_samples=1 case.
+ * IT compatibility fix for IT note delay.
+ * ProTracker MOD playback compatibility improvement.
+
+### libopenmpt 0.2-beta11 (2015-04-18)
+
+ * [**Change**] openmpt_stream_seek_func() now gets called with
+ OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR and
+ OPENMPT_STREAM_SEEK_END whence parameter instead of SEEK_SET, SEEK_CUR and
+ SEEK_END. These are defined to 0, 1 and 2 respectively which corresponds to
+ the definition in all common C libraries. If your C library uses different
+ constants, this theoretically breaks binary compatibility. The old
+ libopenmpt code, however, never actually called the seek function, thus,
+ there will be no problem in practice.
+ * [**Change**] openmpt123: When both SDL1.2 and PortAudio are available,
+ SDL is now the preferred backend because SDL is more widespread and better
+ tested on all kinds of different platforms, and in general, SDL is just
+ more reliable.
+
+ * [**Bug**] libopenmpt now also compiles with GCC 4.3.
+
+ * libopenmpt now supports PLM (Disorder Tracker 2) files.
+ * Various playback improvements and fixes for IT, S3M, XM, MOD, PTM and 669
+ files.
+
+### libopenmpt 0.2-beta10 (2015-02-17)
+
+ * [**Change**] Makefile configuration filenames changed from
+ `build/make/Makefile.config.*` to `build/make/config-*.mk`.
+ * [**Change**] libopenmpt for Android now supports unmo3 from un4seen. See
+ `build/android_ndk/README.AndroidNDK.txt` for details.
+
+ * [**Bug**] Fix out-of-bounds read in mixer code for ProTracker-compatible
+ MOD files which was introduced back in r4223 / beta6.
+
+ * Vibrato effect was too weak in beta8 and beta9 in IT linear slide mode.
+ * Very small fine portamento was wrong in beta8 and beta9 in IT linear slide
+ mode.
+ * Tiny IT playback compatibility improvements.
+ * STM playback improvements.
+
+### libopenmpt 0.2-beta9 (2014-12-21)
+
+ * [**Bug**] libopenmpt_ext.hpp was missing from the Windows binary zip files.
+
+### libopenmpt 0.2-beta8 (2014-12-21)
+
+ * [**Change**] foo_openmpt: Settings are now accessible via foobar2000
+ advanced settings.
+ * [**Change**] Autotools based build now supports libunmo3. Specify
+ --enable-unmo3.
+ * [**Change**] Support for dynamic loading of libunmo3 on MacOS X.
+ * [**Change**] libopenmpt now uses libltld (from libtool) for dynamic loading
+ of libunmo3 on all non-Windows platforms.
+ * [**Change**] Support for older compilers:
+ * GCC 4.1.x to 4.3.x (use `make ANCIENT=1`)
+ * Microsoft Visual Studio 2008 (with latest Service Pack)
+ (see `build/vs2008`)
+ * [**Change**] libopenmpt_ext.hpp is now distributed by default. The API is
+ still considered experimental and not guaranteed to stay API or ABI
+ compatible.
+ * [**Change**] xmp-openmpt / in_openmpt: No more libopenmpt_settings.dll.
+ The settings dialog now uses a statically linked copy of MFC.
+
+ * [**Bug**] The -autotools tarballs were not working at all.
+
+ * Vastly improved MT2 loader.
+ * Improved S3M playback compatibility.
+ * Added openmpt::ext::interactive, an extension which adds a whole bunch of
+ new functionality to change playback in some way or another.
+ * Added possibility to sync sample playback when using
+ openmpt::module::set_position_* by setting the ctl value
+ seek.sync_samples=1
+ * Support for "hidden" subsongs has been added.
+ They are accessible through the same interface as ordinary subsongs, i.e.
+ use openmpt::module::select_subsong to switch between any kind of subsongs.
+ * All subsongs can now be played consecutively by passing -1 as the subsong
+ index in openmpt::module::select_subsong.
+ * Added documentation for a couple of more functions.
+
+### libopenmpt 0.2-beta7 (2014-09-07)
+
+ * [**Change**] libopenmpt now has an GNU Autotools based build system (in
+ addition to all previously supported ways of building libopenmpt).
+ Autotools support is packaged separately as tarballs ending in
+ `-autotools.tar.gz`.
+
+ * [**Bug**] The distributed windows .zip file did not include pugixml.
+
+ * [**Regression**] openmpt123: Support for writing WavPack (.wv) files has
+ been removed.
+
+ Reasoning:
+ 1. WavPack support was incomplete and did not include support for writing
+ WavPack metadata at all.
+ 2. openmpt123 already supports libSndFile which can be used to write
+ uncompressed lossless WAV files which can then be encoded to whatever
+ format the user desires with other tools.
+
+### libopenmpt 0.2-beta6 (2014-09-06)
+
+ * [**Change**] openmpt123: SDL is now also used by default if availble, in
+ addition to PortAudio.
+ * [**Change**] Support for emscripten is no longer experimental.
+ * [**Change**] libopenmpt itself can now also be compiled with VS2008.
+
+ * [**Bug**] Fix all known crashes on platforms that do not support unaligned
+ memory access.
+ * [**Bug**] openmpt123: Effect column was always missing in pattern display.
+
+### libopenmpt 0.2-beta5 (2014-06-15)
+
+ * [**Change**] Add unmo3 support for non-Windows builds.
+ * [**Change**] Namespace all internal functions in order to allow statically
+ linking against libopenmpt without risking duplicate symbols.
+ * [**Change**] Iconv is now completely optional and only used on Linux
+ systems by default.
+ * [**Change**] Added libopenmpt_example_c_stdout.c, an example without
+ requiring PortAudio.
+ * [**Change**] Add experimental support for building libopenmpt with
+ emscripten.
+
+ * [**Bug**] Fix ping-pong loop behaviour which broke in 0.2-beta3.
+ * [**Bug**] Fix crashes when accessing invalid patterns through libopenmpt
+ API.
+ * [**Bug**] Makefile: Support building with missing optional dependencies
+ without them being stated explicitely.
+ * [**Bug**] openmpt123: Crash when quitting while playback is stopped.
+ * [**Bug**] openmpt123: Crash when writing output to a file in interactive UI
+ mode.
+ * [**Bug**] openmpt123: Wrong FLAC output filename in --render mode.
+
+ * Various smaller playback accuracy improvements.
+
+### libopenmpt 0.2-beta4 (2014-02-25)
+
+ * [**Bug**] Makefile: Dependency tracking for the test suite did not work.
+
+### libopenmpt 0.2-beta3 (2014-02-21)
+
+ * [**Change**] The test suite is now built by default with Makefile based
+ builds. Use `TEST=0` to skip building the tests. `make check` runs the test
+ suite.
+
+ * [**Bug**] Crash in MOD and XM loaders on architectures not supporting
+ unaligned memory access.
+ * [**Bug**] MMCMP, PP20 and XPK unpackers should now work on non-x86 hardware
+ and implement proper bounds checking.
+ * [**Bug**] openmpt_module_get_num_samples() returned the wrong value.
+ * [**Bug**] in_openmpt: DSP plugins did not work properly.
+ * [**Bug**] in_openmpt/xmp-openmpt: Setting name for stereo separation was
+ misspelled. This version will revert your stereo separation settings to
+ default.
+ * [**Bug**] Crash when loading some corrupted modules with stereo samples.
+
+ * Support building on Android NDK.
+ * Avoid clicks in sample loops when using interpolation.
+ * IT filters are now done in integer instead of floating point. This improves
+ performance, especially on architectures with no or a slow FPU.
+ * MOD pattern break handling fixes.
+ * Various XM playback improvements.
+ * Improved and switchable dithering when using 16bit integer API.
+
+### libopenmpt 0.2-beta2 (2014-01-12)
+
+ * [**Bug**] MT2 loader crash.
+ * [**Bug**] Saving settings in in_openmpt and xmp-openmpt did not work.
+ * [**Bug**] Load libopenmpt_settings.dll also from below Plugins directory in
+ Winamp.
+
+ * DBM playback improvements.
+
+### libopenmpt 0.2-beta1 (2013-12-31)
+
+ * First release.
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/dependencies.md b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/dependencies.md
new file mode 100644
index 00000000..ab5c257b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/dependencies.md
@@ -0,0 +1,122 @@
+
+Dependencies {#dependencies}
+============
+
+
+Dependencies
+------------
+
+### libopenmpt
+
+ * Supported compilers for building libopenmpt:
+ * **Microsoft Visual Studio 2017** or higher, running on a amd64 build
+ system (other target systems are supported)
+
+ Please note that we do not support building with a later Visual Studio
+ installation with an earlier compiler version. This is because, while
+ later Visual Studio versions allow installing earlier compilers to be
+ available via the later version's environment, in this configuration,
+ the earlier compiler will still use the later C and C++ runtime's
+ headers and implementation, which significantly increases the matrix of
+ possible configurations to test.
+
+ * **GCC 8.1** or higher
+ * **Clang 7** or higher
+ * **MinGW-W64 8.1** or higher (it is recommended to preferably use
+ posix threading model as opposed to win32 threading model)
+ * **emscripten 1.39.1** or higher
+ * **DJGPP GCC 8.1** or higher
+ * any other **C++17 compliant** compiler
+
+ libopenmpt makes the following assumptions about the C++ implementation
+ used for building:
+ * `std::numeric_limits<unsigned char>::digits == 8` (enforced by
+ static_assert)
+ * existence of `std::uintptr_t` (enforced by static_assert)
+ * in C++20 mode, `std::endian::little != std::endian::big` (enforced
+ by static_assert)
+ * `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
+ * `signed` integer overflow is undefined
+ * `float` and `double` can be non-IEEE754
+
+ libopenmpt can optionally support certain incomplete C++
+ implementations:
+ * platforms without `wchar_t` support (like DJGPP)
+ * platforms without working `std::random_device` (like Emscripten when
+ running in `AudioWorkletProcessor` context)
+ * platforms without working `std::high_resolution_clock` (like
+ Emscripten when running in `AudioWorkletProcessor` context)
+
+ * 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++17** compatible compiler should work with the C++ API.
+ * **J2B** support requires an inflate (deflate decompression) implementation:
+ * **zlib** (or **miniz** can be used internally)
+ * **MO3** support requires:
+ * **libmpg123 >= 1.14.0** (or **minimp3 by Lion (github.com/lieff)** can
+ be used internally)
+ * **libogg**, **libvorbis**, and **libvorbisfile** (or **stb_vorbis** can
+ be used internally)
+ * Building on Unix-like systems requires:
+ * **GNU make**
+ * **pkg-config**
+ * The Autotools-based build system requires:
+ * **pkg-config 0.24** or higher
+ * **zlib**
+ * **doxygen**
+
+### openmpt123
+
+ * Live sound output requires one of:
+ * **PulseAudio**
+ * **SDL 2**
+ * **PortAudio v19**
+ * **Win32**
+ * **liballegro 4.2** on DJGPP/DOS
+
+
+Optional dependencies
+---------------------
+
+### libopenmpt
+
+ * **doxygen 1.8** or higher is required to build the documentation.
+
+### openmpt123
+
+ * Rendering to PCM files can use:
+ * **FLAC 1.2** or higher
+ * **libsndfile**
+ * **Win32** for WAVE
+ * raw PCM has no external dependencies
+ * **help2man** is required to build the documentation.
+
+
+Source packages
+---------------
+
+Building the source packages additionally requires:
+ * 7z (7-zip)
+ * autoconf
+ * autoconf-archive
+ * automake
+ * awk (mawk)
+ * git
+ * gzip
+ * help2man
+ * libtool
+ * subversion
+ * tar
+ * xpath (libxml-xpath-perl)
+ * zip
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/gettingstarted.md b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/gettingstarted.md
new file mode 100644
index 00000000..decf32e6
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/gettingstarted.md
@@ -0,0 +1,207 @@
+
+Getting Started {#gettingstarted}
+===============
+
+
+How to compile
+--------------
+
+
+### libopenmpt and openmpt123
+
+ - Autotools
+
+ Grab a `libopenmpt-VERSION-autotools.tar.gz` tarball.
+
+ ./configure
+ make
+ make check
+ sudo make install
+
+ Cross-compilation is generally supported (although only tested for
+ targetting MinGW-w64).
+
+ Note that some MinGW-w64 distributions come with the `win32` threading model
+ enabled by default instead of the `posix` threading model. The `win32`
+ threading model lacks proper support for C++11 `<thread>` and `<mutex>` as
+ well as thread-safe magic statics. It is recommended to use the `posix`
+ threading model for libopenmpt for this reason. On Debian, the appropriate
+ configure command is
+ `./configure --host=x86_64-w64-mingw32 CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix`
+ for 64bit, or
+ `./configure --host=i686-w64-mingw32 CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix`
+ for 32bit. Other MinGW-w64 distributions may differ.
+
+ - Visual Studio:
+
+ - You will find solutions for Visual Studio in the matching
+ `build/vsVERSIONwinWINDOWSVERSION/` folder.
+ Minimal projects that target Windows 10 UWP are available in
+ `build/vsVERSIONuwp/`.
+ Most projects are supported with any of the mentioned Visual Studio
+ verions, with the following exceptions:
+
+ - in_openmpt: Requires Visual Studio with MFC.
+
+ - xmp-openmpt: Requires Visual Studio with MFC.
+
+ - libopenmpt requires the compile host system to be amd64 or ARM64 when
+ building with Visual Studio.
+
+ - In order to build libopenmpt for Windows XP, the Visual Studio 2017 XP
+ targetting toolset as well as the Windows 8.1 SDK need to be installed.
+ The SDK is optionally included with Visual Studio 2017, but must be
+ separately installed with later Visual Studio versions.
+
+ The Windows 8.1 SDK is available from
+ <https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/>
+ or directly from
+ <https://download.microsoft.com/download/B/0/C/B0C80BA3-8AD6-4958-810B-6882485230B5/standalonesdk/sdksetup.exe>
+ .
+
+ - 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 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:
+
+ To build libopenmpt as a winamp input plugin, copy the contents of
+ `WA5.55_SDK.exe` to include/winamp/.
+
+ Please visit
+ [winamp.com](http://wiki.winamp.com/wiki/Plug-in_Developer) to
+ download the SDK.
+ You can disable in_openmpt in the solution configuration.
+
+ - XMPlay SDK:
+
+ To build libopenmpt with XMPlay input plugin support, copy the
+ contents of xmp-sdk.zip into include/xmplay/.
+
+ Please visit [un4seen.com](https://www.un4seen.com/xmplay.html) to
+ download the SDK.
+ You can disable xmp-openmpt in the solution configuration.
+
+ - 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
+ because the makefile cleans only intermediates and target that are active
+ for the current config and no configuration state is kept around across
+ invocations.
+
+ - native build:
+
+ Simply run
+
+ make
+
+ which will try to guess the compiler based on your operating system.
+
+ - gcc or clang (on Unix-like systems, including Mac OS X with MacPorts,
+ and Haiku (32-bit Hybrid and 64-bit)):
+
+ The Makefile requires pkg-config for native builds.
+ For sound output in openmpt123, PortAudio or SDL is required.
+ openmpt123 can optionally use libflac and libsndfile to render PCM
+ files to disk.
+
+ When you want to use gcc, run:
+
+ make CONFIG=gcc
+
+ When you want to use clang, it is recommended to do:
+
+ make CONFIG=clang
+
+ - mingw-w64:
+
+ make CONFIG=mingw64-win32 # for win32
+
+ make CONFIG=mingw64-win64 # for win64
+
+ - emscripten (on Unix-like systems):
+
+ Run:
+
+ # generates WebAssembly with JavaScript fallback
+ make CONFIG=emscripten EMSCRIPTEN_TARGET=all
+
+ or
+
+ # generates WebAssembly
+ make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm
+
+ or
+
+ # generates JavaScript with compatibility for older VMs
+ make CONFIG=emscripten EMSCRIPTEN_TARGET=js
+
+ Running the test suite on the command line is also supported by using
+ node.js. Depending on how your distribution calls the `node.js` binary,
+ you might have to edit `build/make/config-emscripten.mk`.
+
+ - DJGPP / DOS
+
+ Cross-compilation from Linux systems is supported with DJGPP GCC via
+
+ make CONFIG=djgpp
+
+ `openmpt123` can use liballegro 4.2 for sound output on DJGPP/DOS.
+ liballegro can either be installed system-wide in the DJGPP environment
+ or downloaded into the `libopenmpt` source tree.
+
+ make CONFIG=djgpp USE_ALLEGRO42=1 # use installed liballegro
+
+ or
+
+ ./build/download_externals.sh # download liballegro source
+ make CONFIG=djgpp USE_ALLEGRO42=1 BUNDLED_ALLEGRO42=1
+
+ - 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 compile libopenmpt with other 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
+ best be implemented via new `config-*.mk` files.
+
+ The `Makefile` also supports building doxygen documentation by using
+
+ make doc
+
+ Binaries and documentation can be installed systen-wide with
+
+ make PREFIX=/yourprefix install
+ make PREFIX=/yourprefix install-doc
+
+ Some systems (i.e. Linux) require running
+
+ sudo ldconfig
+
+ in order for the system linker to be able to pick up newly installed
+ libraries.
+
+ `PREFIX` defaults to `/usr/local`. A `DESTDIR=` parameter is also
+ supported.
+
+ - Android NDK
+
+ See `build/android_ndk/README.AndroidNDK.txt`.
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/index.dox b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/index.dox
new file mode 100644
index 00000000..4a73d7f1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/index.dox
@@ -0,0 +1,43 @@
+
+/*!
+ * \mainpage Contents
+ *
+ * libopenmpt is a cross-platform C++ and C library to decode <a href="https://en.wikipedia.org/wiki/Module_file">tracked music files (modules)</a> into a raw PCM audio stream.
+ *
+ * libopenmpt is based on the player code of the Open ModPlug Tracker project (OpenMPT, <a href="https://openmpt.org/">https://openmpt.org/</a>)
+ *
+ * \section toc Contents
+ * - \ref md_README "README"
+ * - \ref dependencies "Dependencies"
+ * - \ref gettingstarted "Getting Started"
+ * - \ref packaging "Packaging"
+ * - \ref md_doc_contributing "Contributing"
+ * - \ref md_doc_libopenmpt_styleguide "libopenmpt Style Guide"
+ * - \ref md_doc_openmpt_styleguide "OpenMPT Style Guide"
+ * - \ref tests "Tests"
+ * - \ref changelog "Changelog"
+ * - \ref md_doc_module_formats "Implementing new Module Formats"
+ * - <a href="https://bugs.openmpt.org/">Issue Tracker</a>
+ * \subsection toc_apis APIs
+ * - libopenmpt
+ * - \ref libopenmpt "Common Details"
+ * - libopenmpt C++
+ * - \ref libopenmpt_cpp_overview "Overview"
+ * - \ref libopenmpt_cpp "Details"
+ * - libopenmpt C
+ * - \ref libopenmpt_c_overview "Overview"
+ * - \ref libopenmpt_c "Details"
+ * - libopenmpt_ext C++
+ * - \ref libopenmpt_ext_cpp_overview "Overview"
+ * - \ref libopenmpt_ext_cpp "Details"
+ * - libopenmpt_ext C
+ * - \ref libopenmpt_ext_c_overview "Overview"
+ * - \ref libopenmpt_ext_c "Details"
+ *
+ * \section toc_website Website
+ * https://lib.openmpt.org/
+ *
+ * \section toc_license License
+ * \include LICENSE
+ *
+ */
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/packaging.md b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/packaging.md
new file mode 100644
index 00000000..f8cf97ba
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/packaging.md
@@ -0,0 +1,38 @@
+Packaging {#packaging}
+=========
+
+
+Packaging
+---------
+
+
+### Packaging recommendations for distribution package maintainers
+
+ * libopenmpt (since 0.3) uses SemVer 2.0.0 versioning. See
+ [semver.org](https://semver.org/spec/v2.0.0.html). Clause 4 is ignored for
+ libopenmpt, which means that libopenmpt will also provide API/ABI
+ compatibility semantics for pre-1.0.0 versions as required by SemVer 2.0.0
+ 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.
+ * Read \ref libopenmpt_c_staticlinking and thus possibly pass
+ `CXXSTDLIB_PCLIBSPRIVATE` variable to `configure` if appropriate and/or
+ desired.
+ * Run the test suite in your build process.
+ * Send any build system improvement patches upstream.
+ * Do not include the libmodplug emulation layer in the default libopenmpt
+ binary package. Either do not package it at all, or provide a separate
+ package named libopenmpt-modplug or libmodplug-openmpt (or similar), which
+ depends on libopenmpt, provides libmodplug, and conflicts with original
+ libmodplug.
+ * Split openmpt123 into its own binary package because it has more
+ dependencies than libopenmpt itself.
+ * Consider providing an additional openmpt123 package (in addition to the
+ default openmpt123 package with all audio output drivers), built with fewer
+ audio output drivers so it does not transitively depend on X11. Name that
+ package and its executable openmpt123-nox (or whatever else may be common
+ practice in your distribution).
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/tests.md b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/tests.md
new file mode 100644
index 00000000..5b1c9595
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/dox/tests.md
@@ -0,0 +1,44 @@
+
+Tests {#tests}
+=====
+
+
+libopenmpt provides some basic unit tests that check the platform for general
+sanity and do some basic internal functionality testing. The test suite
+requires a special libopenmpt build that includes file saving functionality
+which is not included in normal builds. This is handled by all provided build
+systems automatically.
+
+### Running Tests
+
+#### On Unix-like systems
+
+Compile with
+
+ make $YOURMAKEOPTIONS clean
+ make $YOURMAKEOPTIONS
+
+and run
+
+ make $YOURMAKEOPTIONS check
+
+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
+
+ ./configure
+ make check
+
+#### On Windows
+
+Using Visual Studio 20??, compile
+
+ build\vs20??\libopenmpt_test.sln
+
+and run
+
+ bin\$ARCH\libopenmpt_test.exe
+
+from the root of the source tree.
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/in_openmpt.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/in_openmpt.cpp
new file mode 100644
index 00000000..b4015955
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/in_openmpt.cpp
@@ -0,0 +1,587 @@
+/*
+ * in_openmpt.cpp
+ * --------------
+ * Purpose: libopenmpt winamp input plugin implementation
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef NO_WINAMP
+
+#if defined(_MFC_VER) || 1
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#if !defined(WINVER) && !defined(_WIN32_WINDOWS)
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
+#endif
+#endif
+#if !defined(MPT_BUILD_RETRO)
+#if defined(_MSC_VER)
+#define MPT_WITH_MFC
+#endif
+#else
+#if defined(_WIN32_WINNT)
+#if (_WIN32_WINNT >= 0x0501)
+#if defined(_MSC_VER)
+#define MPT_WITH_MFC
+#endif
+#endif
+#endif
+#endif
+#if defined(MPT_WITH_MFC)
+#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls
+#endif // MPT_WITH_MFC
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#if defined(MPT_WITH_MFC)
+#include <afxwin.h>
+#include <afxcmn.h>
+#endif // MPT_WITH_MFC
+#include <windows.h>
+#endif // _MFC_VER
+
+#ifdef LIBOPENMPT_BUILD_DLL
+#undef LIBOPENMPT_BUILD_DLL
+#endif
+
+#ifdef _MSC_VER
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#ifndef _SCL_SECURE_NO_WARNINGS
+#define _SCL_SECURE_NO_WARNINGS
+#endif
+#endif // _MSC_VER
+
+#include "libopenmpt.hpp"
+
+#include "libopenmpt_plugin_settings.hpp"
+
+#include "libopenmpt_plugin_gui.hpp"
+
+#include "svn_version.h"
+#if defined(OPENMPT_VERSION_REVISION)
+static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION);
+#else
+static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING;
+#endif
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+
+#ifdef UNICODE
+#define UNICODE_INPUT_PLUGIN
+#endif
+#ifndef _MSC_VER
+#define _MSC_VER 1300
+#endif
+#include "winamp/Winamp/IN2.H"
+#include "winamp/Winamp/wa_ipc.h"
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+
+#include <cstring>
+
+#include <tchar.h>
+
+#define BPS 16
+
+#define WINAMP_DSP_HEADROOM_FACTOR 2
+#define WINAMP_BUFFER_SIZE_FRAMES 576
+
+#define WM_OPENMPT_SEEK (WM_USER+3)
+
+#define SHORT_TITLE "in_openmpt"
+
+static void apply_options();
+
+static std::string StringEncode( const std::wstring &src, UINT codepage )
+{
+ int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, NULL, 0, NULL, NULL );
+ if(required_size <= 0)
+ {
+ return std::string();
+ }
+ std::vector<CHAR> encoded_string( required_size );
+ WideCharToMultiByte( codepage, 0, src.c_str(), -1, &encoded_string[0], encoded_string.size(), NULL, NULL );
+ return &encoded_string[0];
+}
+
+static std::wstring StringDecode( const std::string & src, UINT codepage )
+{
+ int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, NULL, 0 );
+ if(required_size <= 0)
+ {
+ return std::wstring();
+ }
+ std::vector<WCHAR> decoded_string( required_size );
+ MultiByteToWideChar( codepage, 0, src.c_str(), -1, &decoded_string[0], decoded_string.size() );
+ return &decoded_string[0];
+}
+
+#if defined(UNICODE)
+
+static std::wstring StringToWINAPI( const std::wstring & src )
+{
+ return src;
+}
+
+#else
+
+static std::string StringToWINAPI( const std::wstring & src )
+{
+ return StringEncode( src, CP_ACP );
+}
+
+#endif
+
+template <typename Tstring, typename Tstring2, typename Tstring3>
+static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) {
+ std::size_t pos = 0;
+ const Tstring oldStr = oldStr_;
+ const Tstring newStr = newStr_;
+ while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) {
+ str.replace( pos, oldStr.length(), newStr );
+ pos += newStr.length();
+ }
+ return str;
+}
+
+struct self_winamp_t {
+ std::vector<char> filetypes_string;
+ libopenmpt::plugin::settings settings;
+ int samplerate;
+ int channels;
+ std::basic_string<TCHAR> cached_filename;
+ std::basic_string<TCHAR> cached_title;
+ int cached_length;
+ std::basic_string<TCHAR> cached_infotext;
+ std::int64_t decode_position_frames;
+ openmpt::module * mod;
+ HANDLE PlayThread;
+ DWORD PlayThreadID;
+ bool paused;
+ std::vector<std::int16_t> buffer;
+ std::vector<std::int16_t> interleaved_buffer;
+ self_winamp_t() : settings(TEXT(SHORT_TITLE), true) {
+ filetypes_string.clear();
+ settings.changed = apply_options;
+ settings.load();
+ std::vector<std::string> extensions = openmpt::get_supported_extensions();
+ for ( std::vector<std::string>::iterator ext = extensions.begin(); ext != extensions.end(); ++ext ) {
+ std::copy( (*ext).begin(), (*ext).end(), std::back_inserter( filetypes_string ) );
+ filetypes_string.push_back('\0');
+ std::copy( SHORT_TITLE, SHORT_TITLE + std::strlen(SHORT_TITLE), std::back_inserter( filetypes_string ) );
+ filetypes_string.push_back('\0');
+ }
+ filetypes_string.push_back('\0');
+ samplerate = settings.samplerate;
+ channels = settings.channels;
+ cached_filename = std::basic_string<TCHAR>();
+ cached_title = std::basic_string<TCHAR>();
+ cached_length = 0;
+ cached_infotext = std::basic_string<TCHAR>();
+ decode_position_frames = 0;
+ mod = 0;
+ PlayThread = 0;
+ PlayThreadID = 0;
+ paused = false;
+ buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels );
+ interleaved_buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels * WINAMP_DSP_HEADROOM_FACTOR );
+ }
+ ~self_winamp_t() {
+ return;
+ }
+};
+
+static self_winamp_t * self = 0;
+
+static void apply_options() {
+ if ( self->mod ) {
+ self->mod->set_repeat_count( self->settings.repeatcount );
+ self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel );
+ self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation );
+ self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength );
+ self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping );
+ self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false );
+ switch ( self->settings.amiga_filter_type ) {
+ case 0:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" );
+ break;
+ case 1:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" );
+ break;
+ case 0xA500:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" );
+ break;
+ case 0xA1200:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" );
+ break;
+ }
+ }
+ self->settings.save();
+}
+
+extern In_Module inmod;
+
+static DWORD WINAPI DecodeThread( LPVOID );
+
+static std::basic_string<TCHAR> generate_infotext( const std::basic_string<TCHAR> & filename, const openmpt::module & mod ) {
+ std::basic_ostringstream<TCHAR> str;
+ str << TEXT("filename: ") << filename << std::endl;
+ str << TEXT("duration: ") << mod.get_duration_seconds() << TEXT("seconds") << std::endl;
+ std::vector<std::string> metadatakeys = mod.get_metadata_keys();
+ for ( std::vector<std::string>::iterator key = metadatakeys.begin(); key != metadatakeys.end(); ++key ) {
+ if ( *key == "message_raw" ) {
+ continue;
+ }
+ str << StringToWINAPI( StringDecode( *key, CP_UTF8 ) ) << TEXT(": ") << StringToWINAPI( StringDecode( mod.get_metadata(*key), CP_UTF8 ) ) << std::endl;
+ }
+ return str.str();
+}
+
+static void config( HWND hwndParent ) {
+#if 1
+ libopenmpt::plugin::gui_edit_settings( &self->settings, hwndParent, TEXT(SHORT_TITLE) );
+#else
+ static_cast<void>(hwndParent);
+#endif
+ apply_options();
+}
+
+static void about( HWND hwndParent ) {
+ std::ostringstream about;
+ about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
+ about << " Copyright (c) 2013-2022 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl;
+ about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
+ about << std::endl;
+ about << openmpt::string::get( "contact" ) << std::endl;
+ about << std::endl;
+ about << "Show full credits?" << std::endl;
+ if ( MessageBox( hwndParent, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) {
+ return;
+ }
+ std::ostringstream credits;
+ credits << openmpt::string::get( "credits" );
+#if 1
+ libopenmpt::plugin::gui_show_file_info( hwndParent, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) );
+#else
+ MessageBox( hwndParent, StringToWINAPI( StringReplace(StringDecode(credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK );
+#endif
+}
+
+static void init() {
+ if ( !self ) {
+ self = new self_winamp_t();
+ inmod.FileExtensions = &(self->filetypes_string[0]);
+ }
+}
+
+static void quit() {
+ if ( self ) {
+ inmod.FileExtensions = NULL;
+ delete self;
+ self = 0;
+ }
+}
+
+static int isourfile( const in_char * /* fn */ ) {
+ return 0;
+}
+
+static int play( const in_char * fn ) {
+ if ( !fn ) {
+ return -1;
+ }
+ try {
+ std::ifstream s( fn, std::ios::binary );
+ std::map< std::string, std::string > ctls;
+ ctls["seek.sync_samples"] = "1";
+ self->mod = new openmpt::module( s, std::clog, ctls );
+ self->cached_filename = fn;
+ self->cached_title = StringToWINAPI( StringDecode( self->mod->get_metadata( "title" ), CP_UTF8 ) );
+ self->cached_length = static_cast<int>( self->mod->get_duration_seconds() * 1000.0 );
+ self->cached_infotext = generate_infotext( self->cached_filename, *self->mod );
+ apply_options();
+ self->samplerate = self->settings.samplerate;
+ self->channels = self->settings.channels;
+ int maxlatency = inmod.outMod->Open( self->samplerate, self->channels, BPS, -1, -1 );
+ std::ostringstream str;
+ str << maxlatency;
+ inmod.SetInfo( self->mod->get_num_channels(), self->samplerate/1000, self->channels, 1 );
+ inmod.SAVSAInit( maxlatency, self->samplerate );
+ inmod.VSASetInfo( self->channels, self->samplerate );
+ inmod.outMod->SetVolume( -666 );
+ inmod.outMod->SetPan( 0 );
+ self->paused = false;
+ self->decode_position_frames = 0;
+ self->PlayThread = CreateThread( NULL, 0, DecodeThread, NULL, 0, &self->PlayThreadID );
+ return 0;
+ } catch ( ... ) {
+ if ( self->mod ) {
+ delete self->mod;
+ self->mod = 0;
+ }
+ return -1;
+ }
+}
+
+static void pause() {
+ self->paused = true;
+ inmod.outMod->Pause( 1 );
+}
+
+static void unpause() {
+ self->paused = false;
+ inmod.outMod->Pause( 0 );
+}
+
+static int ispaused() {
+ return self->paused ? 1 : 0;
+}
+
+static void stop() {
+ PostThreadMessage( self->PlayThreadID, WM_QUIT, 0, 0 );
+ WaitForSingleObject( self->PlayThread, INFINITE );
+ CloseHandle( self->PlayThread );
+ self->PlayThread = 0;
+ self->PlayThreadID = 0;
+ delete self->mod;
+ self->mod = 0;
+ inmod.outMod->Close();
+ inmod.SAVSADeInit();
+}
+
+static int getlength() {
+ return self->cached_length;
+}
+
+static int getoutputtime() {
+ //return (int)( self->decode_position_frames * 1000 / self->mod->get_render_param( openmpt::module::RENDER_SAMPLERATE_HZ ) /* + ( inmod.outMod->GetOutputTime() - inmod.outMod->GetWrittenTime() ) */ );
+ return inmod.outMod->GetOutputTime();
+}
+
+static void setoutputtime( int time_in_ms ) {
+ PostThreadMessage( self->PlayThreadID, WM_OPENMPT_SEEK, 0, time_in_ms );
+}
+
+static void setvolume( int volume ) {
+ inmod.outMod->SetVolume( volume );
+}
+
+static void setpan( int pan ) {
+ inmod.outMod->SetPan( pan );
+}
+
+static int infobox( const in_char * fn, HWND hWndParent ) {
+ if ( fn && fn[0] != '\0' && self->cached_filename != std::basic_string<TCHAR>(fn) ) {
+ try {
+ std::ifstream s( fn, std::ios::binary );
+ openmpt::module mod( s );
+#if 1
+ libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ) );
+#else
+ MessageBox( hWndParent, StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK );
+#endif
+ } catch ( ... ) {
+ }
+ } else {
+#if 1
+ libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ) );
+#else
+ MessageBox( hWndParent, StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK );
+#endif
+ }
+ return INFOBOX_UNCHANGED;
+}
+
+
+static void getfileinfo( const in_char * filename, in_char * title, int * length_in_ms ) {
+ if ( !filename || *filename == '\0' ) {
+ if ( length_in_ms ) {
+ *length_in_ms = self->cached_length;
+ }
+ if ( title ) {
+ std::basic_string<TCHAR> truncated_title = self->cached_title;
+ if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) {
+ truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 );
+ }
+ _tcscpy( title, truncated_title.c_str() );
+ }
+ } else {
+ try {
+ std::ifstream s( filename, std::ios::binary );
+ openmpt::module mod( s );
+ if ( length_in_ms ) {
+ *length_in_ms = static_cast<int>( mod.get_duration_seconds() * 1000.0 );
+ }
+ if ( title ) {
+ std::basic_string<TCHAR> truncated_title = StringToWINAPI( StringDecode( mod.get_metadata("title"), CP_UTF8 ) );
+ if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) {
+ truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 );
+ }
+ _tcscpy( title, truncated_title.c_str() );
+ }
+ } catch ( ... ) {
+ }
+ }
+}
+
+static void eq_set( int /* on */ , char /* data */ [10], int /* preamp */ ) {
+ return;
+}
+
+static DWORD WINAPI DecodeThread( LPVOID ) {
+ MSG msg;
+ PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE );
+ bool eof = false;
+ while ( true ) {
+ bool quit = false;
+ while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
+ if ( msg.message == WM_QUIT ) {
+ quit = true;
+ } else if ( msg.message == WM_OPENMPT_SEEK ) {
+ double pos_seconds = self->mod->set_position_seconds( msg.lParam * 0.001 );
+ self->decode_position_frames = (std::int64_t)( pos_seconds * (double)self->samplerate);
+ eof = false;
+ inmod.outMod->Flush( (int)( pos_seconds * 1000.0 ) );
+ }
+ }
+ if ( quit ) {
+ break;
+ }
+ if ( eof ) {
+ inmod.outMod->CanWrite(); // update output plugin state
+ if ( !inmod.outMod->IsPlaying() ) {
+ PostMessage( inmod.hMainWindow, WM_WA_MPEG_EOF, 0, 0 );
+ return 0;
+ }
+ Sleep( 10 );
+ } else {
+ bool dsp_active = inmod.dsp_isactive() ? true : false;
+ if ( inmod.outMod->CanWrite() >= (int)( WINAMP_BUFFER_SIZE_FRAMES * self->channels * sizeof( signed short ) ) * ( dsp_active ? WINAMP_DSP_HEADROOM_FACTOR : 1 ) ) {
+ int frames = 0;
+ switch ( self->channels ) {
+ case 1:
+ frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES );
+ for ( int frame = 0; frame < frames; frame++ ) {
+ self->interleaved_buffer[frame*1+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ }
+ break;
+ case 2:
+ frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES );
+ for ( int frame = 0; frame < frames; frame++ ) {
+ self->interleaved_buffer[frame*2+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ self->interleaved_buffer[frame*2+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ }
+ break;
+ case 4:
+ frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+2*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+3*WINAMP_BUFFER_SIZE_FRAMES );
+ for ( int frame = 0; frame < frames; frame++ ) {
+ self->interleaved_buffer[frame*4+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ self->interleaved_buffer[frame*4+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ self->interleaved_buffer[frame*4+2] = self->buffer[2*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ self->interleaved_buffer[frame*4+3] = self->buffer[3*WINAMP_BUFFER_SIZE_FRAMES+frame];
+ }
+ break;
+ }
+ if ( frames == 0 ) {
+ eof = true;
+ } else {
+ self->decode_position_frames += frames;
+ std::int64_t decode_pos_ms = (self->decode_position_frames * 1000 / self->samplerate );
+ inmod.SAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms );
+ inmod.VSAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms );
+ if ( dsp_active ) {
+ frames = inmod.dsp_dosamples( &( self->interleaved_buffer[0] ), frames, BPS, self->channels, self->samplerate );
+ }
+ int bytes = frames * self->channels * sizeof( signed short );
+ inmod.outMod->Write( (char*)&( self->interleaved_buffer[0] ), bytes );
+ }
+ } else {
+ Sleep( 10 );
+ }
+ }
+ }
+ return 0;
+}
+
+#if defined(__GNUC__)
+extern In_Module inmod;
+#endif
+In_Module inmod = {
+ IN_VER,
+ const_cast< char * >( in_openmpt_string ), // SHORT_TITLE,
+ 0, // hMainWindow
+ 0, // hDllInstance
+ NULL, // filled later in Init() "mptm\0ModPlug Tracker Module (*.mptm)\0",
+ 1, // is_seekable
+ 1, // uses output
+ config,
+ about,
+ init,
+ quit,
+ getfileinfo,
+ infobox,
+ isourfile,
+ play,
+ pause,
+ unpause,
+ ispaused,
+ stop,
+ getlength,
+ getoutputtime,
+ setoutputtime,
+ setvolume,
+ setpan,
+ 0,0,0,0,0,0,0,0,0, // vis
+ 0,0, // dsp
+ eq_set,
+ NULL, // setinfo
+ 0 // out_mod
+};
+
+extern "C" __declspec(dllexport) In_Module * winampGetInModule2();
+extern "C" __declspec(dllexport) In_Module * winampGetInModule2() {
+ return &inmod;
+}
+
+
+#if defined(MPT_WITH_MFC)
+
+#ifdef _MFC_VER
+
+namespace libopenmpt {
+namespace plugin {
+
+void DllMainAttach() {
+ // nothing
+}
+
+void DllMainDetach() {
+ // nothing
+}
+
+} // namespace plugin
+} // namespace libopenmpt
+
+#else
+
+// nothing
+
+#endif
+
+#endif // MPT_WITH_MFC
+
+
+#endif // NO_WINAMP
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.h
new file mode 100644
index 00000000..a795a1a7
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.h
@@ -0,0 +1,1552 @@
+/*
+ * libopenmpt.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_H
+#define LIBOPENMPT_H
+
+#include "libopenmpt_config.h"
+#include <stddef.h>
+#include <stdint.h>
+
+/*!
+ * \page libopenmpt_c_overview C API
+ *
+ * \section libopenmpt_c_error Error Handling
+ *
+ * - Functions with no return value in the corresponding C++ API return 0 on
+ * failure and 1 on success.
+ * - Functions that return a string in the corresponding C++ API return a
+ * dynamically allocated const char *. In case of failure or memory allocation
+ * 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 \ref openmpt_module object will call an
+ * \ref 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 \ref openmpt_module object take
+ * an explicit \ref openmpt_error_func error function callback and a pointer to
+ * an int and behave analog to the functions working on an \ref openmpt_module
+ * object.
+ *
+ * \section libopenmpt_c_strings Strings
+ *
+ * - All strings returned from libopenmpt are encoded in UTF-8.
+ * - All strings passed to libopenmpt should also be encoded in UTF-8.
+ * Behaviour in case of invalid UTF-8 is unspecified.
+ * - libopenmpt does not enforce or expect any particular Unicode
+ * normalization form.
+ * - All strings returned from libopenmpt are dynamically allocated and must
+ * be freed with openmpt_free_string(). Do NOT use the C standard library
+ * free() for libopenmpt strings as that would make your code invalid on
+ * windows when dynamically linking against libopenmpt which itself statically
+ * links to the C runtime.
+ * - All strings passed to libopenmpt are copied. No ownership is assumed or
+ * transferred.
+ *
+ * \section libopenmpt_c_fileio File I/O
+ *
+ * libopenmpt can use 3 different strategies for file I/O.
+ *
+ * - openmpt_module_create_from_memory2() will load the module from the provided
+ * memory buffer, which will require loading all data upfront by the library
+ * caller.
+ * - openmpt_module_create2() 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 which means the callbacks are assumed
+ * to be performant even with small i/o sizes.
+ * - openmpt_module_create2() with an unseekable stream will load the module via
+ * callbacks to the stream interface. libopempt will make an internal copy as
+ * it goes along, and sometimes have to pre-cache the whole file in case it
+ * needs to know the complete file size. This strategy is intended to be used
+ * if the file is located on a high latency network.
+ *
+ * | create function | speed | memory consumption |
+ * | ----------------------------------------------: | :----: | :----------------: |
+ * | openmpt_module_create_from_memory2() | <p style="background-color:green" >fast </p> | <p style="background-color:yellow">medium</p> |
+ * | openmpt_module_create2() with seekable stream | <p style="background-color:red" >slow </p> | <p style="background-color:green" >low </p> |
+ * | openmpt_module_create2() 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 openmpt_module has been created and can be freed by the
+ * caller.
+ *
+ * \section libopenmpt_c_outputformat Output Format
+ *
+ * libopenmpt supports a wide range of PCM output formats:
+ * [8000..192000]/[mono|stereo|quad]/[f32|i16].
+ *
+ * Unless you have some very specific requirements demanding a particular aspect
+ * of the output format, you should always prefer 48000/stereo/f32 as the
+ * libopenmpt PCM format.
+ *
+ * - Please prefer 48000Hz unless the user explicitly demands something else.
+ * Practically all audio equipment and file formats use 48000Hz nowadays.
+ * - Practically all module formats are made for stereo output. Mono will not
+ * give you any measurable speed improvements and can trivially be obtained from
+ * the stereo output anyway. Quad is not expected by almost all modules and even
+ * if they do use surround effects, they expect the effects to be mixed to
+ * stereo.
+ * - Floating point output provides headroom instead of hard clipping if the
+ * module is louder than 0dBFs, will give you a better signal-to-noise ratio
+ * than int16 output, and avoid the need to apply an additional dithering to the
+ * output by libopenmpt. Unless your platform has no floating point unit at all,
+ * floating point will thus also be slightly faster.
+ *
+ * \section libopenmpt_c_threads libopenmpt in multi-threaded environments
+ *
+ * - 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.
+ * - You must ensure to only ever access a particular libopenmpt object from a
+ * single thread at a time.
+ * - Consecutive accesses can happen from different threads.
+ * - Different objects can be accessed concurrently from different threads.
+ *
+ * \section libopenmpt_c_staticlinking Statically linking to libopenmpt
+ *
+ * libopenmpt is implemented in C++. This implies that linking to libopenmpt
+ * statically requires linking to the C++ runtime and standard library. The
+ * **highly preferred and recommended** way to do this is by using the C++
+ * compiler instead of the platform linker to do the linking. This will do all
+ * necessary things that are C++ specific (in particular, it will pull in the
+ * appropriate runtime and/or library). If for whatever reason it is not
+ * possible to use the C++ compiler for statically linking against libopenmpt,
+ * the libopenmpt build system can list the required libraries in the pkg-config
+ * file `libopenmpt.pc`. However, there is no reliable way to determine the name
+ * of the required library or libraries from within the build system. The
+ * libopenmpt autotools `configure` and plain `Makefile` honor the custom
+ * variable `CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing
+ * the standard library (or libraries) required for static linking. The contents
+ * of this variable will be put in `libopenmpt.pc` `Libs.private` and used for
+ * nothing else.
+ *
+ * This problem is inherent to libraries implemented in C++ that can also be used
+ * without a C++ compiler. Other libraries try to solve that by listing
+ * `-lstdc++` unconditionally in `Libs.private`. However, that will break
+ * platforms that use a different C++ standard library (in particular FreeBSD).
+ *
+ * See https://lists.freedesktop.org/archives/pkg-config/2016-August/001055.html .
+ *
+ * Dymically linking to libopenmpt does not require anything special and will
+ * work as usual (and exactly as done for libraries implemented in C).
+ *
+ * Note: This section does not apply when using Microsoft Visual Studio or
+ * Andriod NDK ndk-build build systems.
+ *
+ * \section libopenmpt_c_detailed Detailed documentation
+ *
+ * \ref libopenmpt_c
+ *
+ * In case a function is not documented here, you might want to look at the
+ * \ref libopenmpt_cpp documentation. The C and C++ APIs are kept semantically
+ * as close as possible.
+ *
+ * \section libopenmpt_c_examples Examples
+ *
+ * \subsection libopenmpt_c_example_unsafe Unsafe, simplified example without any error checking to get a first idea of the API
+ * \include libopenmpt_example_c_unsafe.c
+ * \subsection libopenmpt_c_example_file FILE*
+ * \include libopenmpt_example_c.c
+ * \subsection libopenmpt_c_example_inmemory in memory
+ * \include libopenmpt_example_c_mem.c
+ * \subsection libopenmpt_c_example_stdout reading FILE* and writing PCM data to STDOUT (usable without PortAudio)
+ * \include libopenmpt_example_c_stdout.c
+ *
+ */
+
+/*! \defgroup libopenmpt_c libopenmpt C */
+
+/*! \addtogroup libopenmpt_c
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! \brief Get the libopenmpt version number
+ *
+ * Returns the libopenmpt version number.
+ * \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);
+
+/*! \brief Get the core version number
+ *
+ * Return the OpenMPT core version number.
+ * \return The value represents (majormajor << 24 + major << 16 + minor << 8 + minorminor).
+ */
+LIBOPENMPT_API uint32_t openmpt_get_core_version(void);
+
+/*! Return a verbose library version string from openmpt_get_string(). \deprecated Please use `"library_version"` directly. */
+#define OPENMPT_STRING_LIBRARY_VERSION LIBOPENMPT_DEPRECATED_STRING( "library_version" )
+/*! Return a verbose library features string from openmpt_get_string(). \deprecated Please use `"library_features"` directly. */
+#define OPENMPT_STRING_LIBRARY_FEATURES LIBOPENMPT_DEPRECATED_STRING( "library_features" )
+/*! Return a verbose OpenMPT core version string from openmpt_get_string(). \deprecated Please use `"core_version"` directly. */
+#define OPENMPT_STRING_CORE_VERSION LIBOPENMPT_DEPRECATED_STRING( "core_version" )
+/*! Return information about the current build (e.g. the build date or compiler used) from openmpt_get_string(). \deprecated Please use `"build"` directly. */
+#define OPENMPT_STRING_BUILD LIBOPENMPT_DEPRECATED_STRING( "build" )
+/*! Return all contributors from openmpt_get_string(). \deprecated Please use `"credits"` directly. */
+#define OPENMPT_STRING_CREDITS LIBOPENMPT_DEPRECATED_STRING( "credits" )
+/*! Return contact information about libopenmpt from openmpt_get_string(). \deprecated Please use `"contact"` directly. */
+#define OPENMPT_STRING_CONTACT LIBOPENMPT_DEPRECATED_STRING( "contact" )
+/*! Return the libopenmpt license from openmpt_get_string(). \deprecated Please use `"license"` directly. */
+#define OPENMPT_STRING_LICENSE LIBOPENMPT_DEPRECATED_STRING( "license" )
+
+/*! \brief Free a string returned by libopenmpt
+ *
+ * Frees any string that got returned by libopenmpt.
+ */
+LIBOPENMPT_API void openmpt_free_string( const char * str );
+
+/*! \brief Get library related metadata.
+ *
+ * \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
+ * - "contact": contact information about libopenmpt
+ * - "license": the libopenmpt license
+ * - "url": libopenmpt website URL
+ * - "support_forum_url": libopenmpt support and discussions forum URL
+ * - "bugtracker_url": libopenmpt bug and issue tracker URL
+ * \return A (possibly multi-line) string containing the queried information. If no information is available, the string is empty.
+ */
+LIBOPENMPT_API const char * openmpt_get_string( const char * key );
+
+/*! \brief Get a list of supported file extensions
+ *
+ * \return The semicolon-separated list of extensions supported by this libopenmpt build. The extensions are returned lower-case without a leading dot.
+ */
+LIBOPENMPT_API const char * openmpt_get_supported_extensions(void);
+
+/// <summary>
+/// From version: 0.7.0
+/// Hakan DANISIK
+/// </summary>
+/// <param name="extension"></param>
+/// <returns></returns>
+LIBOPENMPT_API const char * openmpt_get_tracker_name( const char * extension );
+
+
+/*! \brief Query whether a file extension is supported
+ *
+ * \param extension file extension to query without a leading dot. The case is ignored.
+ * \return 1 if the extension is supported by libopenmpt, 0 otherwise.
+ */
+LIBOPENMPT_API int openmpt_is_extension_supported( const char * extension );
+
+/*! Seek to the given offset relative to the beginning of the file. */
+#define OPENMPT_STREAM_SEEK_SET 0
+/*! Seek to the given offset relative to the current position in the file. */
+#define OPENMPT_STREAM_SEEK_CUR 1
+/*! Seek to the given offset relative to the end of the file. */
+#define OPENMPT_STREAM_SEEK_END 2
+
+/*! \brief Read bytes from stream
+ *
+ * Read bytes data from stream to dst.
+ * \param stream Stream to read data from
+ * \param dst Target where to copy data.
+ * \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 );
+
+/*! \brief Seek stream position
+ *
+ * Seek to stream position offset at whence.
+ * \param stream Stream to operate on.
+ * \param offset Offset to seek to.
+ * \param whence OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR, OPENMPT_STREAM_SEEK_END. See C89 documentation.
+ * \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 );
+
+/*! \brief Tell stream position
+ *
+ * Tell position of stream.
+ * \param stream Stream to operate on.
+ * \return Current position in stream.
+ * \retval -1 Failure.
+ */
+typedef int64_t (*openmpt_stream_tell_func)( void * stream );
+
+/*! \brief Stream callbacks
+ *
+ * Stream callbacks used by libopenmpt for stream operations.
+ * \sa openmpt_stream_get_file_callbacks
+ * \sa openmpt_stream_get_fd_callbacks
+ * \sa openmpt_stream_get_buffer_callbacks
+ */
+typedef struct openmpt_stream_callbacks {
+
+ /*! \brief Read callback.
+ *
+ * \sa openmpt_stream_read_func
+ */
+ openmpt_stream_read_func read;
+
+ /*! \brief Seek callback.
+ *
+ * Seek callback can be NULL if seeking is not supported.
+ * \sa openmpt_stream_seek_func
+ */
+ openmpt_stream_seek_func seek;
+
+ /*! \brief Tell callback.
+ *
+ * Tell callback can be NULL if seeking is not supported.
+ * \sa openmpt_stream_tell_func
+ */
+ openmpt_stream_tell_func tell;
+
+} openmpt_stream_callbacks;
+
+/*! \brief Logging function
+ *
+ * \param message UTF-8 encoded log message.
+ * \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 );
+
+/*! \brief Default logging function
+ *
+ * Default logging function that logs anything to stderr.
+ */
+LIBOPENMPT_API void openmpt_log_func_default( const char * message, void * user );
+
+/*! \brief Silent logging function
+ *
+ * Silent logging function that throws any log message away.
+ */
+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. 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_could_open_probability2().
+ * \since 0.3.0
+ */
+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_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 0x1ull
+/*! 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 0x2ull
+
+/*! 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 0x0ull
+
+/*! 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 Bit 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 interface that might be required 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 Bit 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_probe_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 interface that might be required 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 Bit 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 interface that might be required 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
+ */
+typedef struct openmpt_module openmpt_module;
+
+typedef struct openmpt_module_initial_ctl {
+ const char * ctl;
+ const char * value;
+} openmpt_module_initial_ctl;
+
+/*! \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 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 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 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_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.
+ *
+ * \param mod The module to unload.
+ */
+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 );
+
+/**
+ * \defgroup openmpt_module_render_param Render param indices
+ *
+ * \brief Parameter index to use with openmpt_module_get_render_param() and openmpt_module_set_render_param()
+ * @{
+ */
+/*! \brief Master Gain
+ *
+ * The related value represents a relative gain in milliBel.\n
+ * The default value is 0.\n
+ * The supported value range is unlimited.\n
+ */
+#define OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL 1
+/*! \brief Stereo Separation
+ *
+ * The related value represents the stereo separation generated by the libopenmpt mixer in percent.\n
+ * The default value is 100.\n
+ * The supported value range is [0,200].\n
+ */
+#define OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT 2
+/*! \brief Interpolation Filter
+ *
+ * The related value represents the interpolation filter length used by the libopenmpt mixer.\n
+ * The default value is 0, which indicates a recommended default value.\n
+ * The supported value range is [0,inf). Values greater than the implementation limit are clamped to the maximum supported value.\n
+ * Currently supported values:
+ * - 0: internal default
+ * - 1: no interpolation (zero order hold)
+ * - 2: linear interpolation
+ * - 4: cubic interpolation
+ * - 8: windowed sinc with 8 taps
+ */
+#define OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH 3
+/*! \brief Volume Ramping Strength
+ *
+ * The related value represents the amount of volume ramping done by the libopenmpt mixer.\n
+ * The default value is -1, which indicates a recommended default value.\n
+ * The meaningful value range is [-1..10].\n
+ * A value of 0 completely disables volume ramping. This might cause clicks in sound output.\n
+ * Higher values imply slower/softer volume ramps.
+ */
+#define OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH 4
+/** @}*/
+
+/**
+ * \defgroup openmpt_module_command_index Pattern cell indices
+ *
+ * \brief Parameter index to use with openmpt_module_get_pattern_row_channel_command(), openmpt_module_format_pattern_row_channel_command() and openmpt_module_highlight_pattern_row_channel_command()
+ * @{
+ */
+#define OPENMPT_MODULE_COMMAND_NOTE 0
+#define OPENMPT_MODULE_COMMAND_INSTRUMENT 1
+#define OPENMPT_MODULE_COMMAND_VOLUMEEFFECT 2
+#define OPENMPT_MODULE_COMMAND_EFFECT 3
+#define OPENMPT_MODULE_COMMAND_VOLUME 4
+#define OPENMPT_MODULE_COMMAND_PARAMETER 5
+/** @}*/
+
+/*! \brief Select a sub-song from a multi-song module
+ *
+ * \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_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.
+ * \param repeat_count Repeat Count
+ * - -1: repeat forever
+ * - 0: play once, repeat zero times (the default)
+ * - n>0: play once and repeat n times after that
+ * \return 1 on success, 0 on failure.
+ * \sa openmpt_module_get_repeat_count
+ */
+LIBOPENMPT_API int openmpt_module_set_repeat_count( openmpt_module * mod, int32_t repeat_count );
+/*! \brief Get Repeat Count
+ *
+ * \param mod The module handle to work on.
+ * \return Repeat Count
+ * - -1: repeat forever
+ * - 0: play once, repeat zero times (the default)
+ * - n>0: play once and repeat n times after that
+ * \sa openmpt_module_set_repeat_count
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_repeat_count( openmpt_module * mod );
+
+/*! \brief approximate song duration
+ *
+ * \param mod The module handle to work on.
+ * \return Approximate duration of current sub-song in seconds.
+ * \remarks The function may return infinity if the pattern data is too complex to evaluate.
+ */
+LIBOPENMPT_API double openmpt_module_get_duration_seconds( openmpt_module * mod );
+
+/*! \brief Set approximate current song position
+ *
+ * \param mod The module handle to work on.
+ * \param seconds Seconds to seek to. If seconds is out of range, the position gets set to song start or end respectively.
+ * \return Approximate new song position in seconds.
+ * \sa openmpt_module_get_position_seconds
+ */
+LIBOPENMPT_API double openmpt_module_set_position_seconds( openmpt_module * mod, double seconds );
+/*! \brief Get current song position
+ *
+ * \param mod The module handle to work on.
+ * \return Current song position in seconds.
+ * \sa openmpt_module_set_position_seconds
+ */
+LIBOPENMPT_API double openmpt_module_get_position_seconds( openmpt_module * mod );
+
+/*! \brief Set approximate current song position
+ *
+ * If order or row are out of range, to position is not modified and the current position is returned.
+ * \param mod The module handle to work on.
+ * \param order Pattern order number to seek to.
+ * \param row Pattern row number to seek to.
+ * \return Approximate new song position in seconds.
+ * \sa openmpt_module_set_position_seconds
+ * \sa openmpt_module_get_position_seconds
+ */
+LIBOPENMPT_API double openmpt_module_set_position_order_row( openmpt_module * mod, int32_t order, int32_t row );
+
+/*! \brief Get render parameter
+ *
+ * \param mod The module handle to work on.
+ * \param param Parameter to query. See \ref openmpt_module_render_param
+ * \param value Pointer to the variable that receives the current value of the parameter.
+ * \return 1 on success, 0 on failure (invalid param or value is NULL).
+ * \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL
+ * \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT
+ * \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH
+ * \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH
+ * \sa openmpt_module_set_render_param
+ */
+LIBOPENMPT_API int openmpt_module_get_render_param( openmpt_module * mod, int param, int32_t * value );
+/*! \brief Set render parameter
+ *
+ * \param mod The module handle to work on.
+ * \param param Parameter to set. See \ref openmpt_module_render_param
+ * \param value The value to set param to.
+ * \return 1 on success, 0 on failure (invalid param).
+ * \sa OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL
+ * \sa OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT
+ * \sa OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH
+ * \sa OPENMPT_MODULE_RENDER_VOLUMERAMPING_STRENGTH
+ * \sa openmpt_module_get_render_param
+ */
+LIBOPENMPT_API int openmpt_module_set_render_param( openmpt_module * mod, int param, int32_t value );
+
+/*@{*/
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param mono Pointer to a buffer of at least count elements that receives the mono/center output.
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_mono( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * mono );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param left Pointer to a buffer of at least count elements that receives the left output.
+ * \param right Pointer to a buffer of at least count elements that receives the right output.
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param left Pointer to a buffer of at least count elements that receives the left output.
+ * \param right Pointer to a buffer of at least count elements that receives the right output.
+ * \param rear_left Pointer to a buffer of at least count elements that receives the rear left output.
+ * \param rear_right Pointer to a buffer of at least count elements that receives the rear right output.
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right, int16_t * rear_left, int16_t * rear_right );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param mono Pointer to a buffer of at least count elements that receives the mono/center output.
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_float_mono( openmpt_module * mod, int32_t samplerate, size_t count, float * mono );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param left Pointer to a buffer of at least count elements that receives the left output.
+ * \param right Pointer to a buffer of at least count elements that receives the right output.
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param left Pointer to a buffer of at least count elements that receives the left output.
+ * \param right Pointer to a buffer of at least count elements that receives the right output.
+ * \param rear_left Pointer to a buffer of at least count elements that receives the rear left output.
+ * \param rear_right Pointer to a buffer of at least count elements that receives the rear right output.
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right, float * rear_left, float * rear_right );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R).
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_interleaved_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_stereo );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_interleaved_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_quad );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R).
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ * \sa \ref libopenmpt_c_outputformat
+ */
+LIBOPENMPT_API size_t openmpt_module_read_interleaved_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_stereo );
+/*! \brief Render audio data
+ *
+ * \param mod The module handle to work on.
+ * \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ * \param count Number of audio frames to render per channel.
+ * \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
+ * \return The number of frames actually rendered.
+ * \retval 0 The end of song has been reached.
+ * \remarks The output buffers are only written to up to the returned number of elements.
+ * \remarks You can freely switch between any of the "openmpt_module_read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ * \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ * \sa \ref libopenmpt_c_outputformat
+*/
+LIBOPENMPT_API size_t openmpt_module_read_interleaved_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_quad );
+/*@}*/
+
+/*! \brief Get the list of supported metadata item keys
+ *
+ * \param mod The module handle to work on.
+ * \return Metadata item keys supported by openmpt_module_get_metadata, as a semicolon-separated list.
+ * \sa openmpt_module_get_metadata
+ */
+LIBOPENMPT_API const char * openmpt_module_get_metadata_keys( openmpt_module * mod );
+/*! \brief Get a metadata item value
+ *
+ * \param mod The module handle to work on.
+ * \param key Metadata item key to query. Use openmpt_module_get_metadata_keys to check for available keys.
+ * Possible keys are:
+ * - type: Module format extension (e.g. it) or another similar identifier for modules formats that typically do not use a file extension
+ * - type_long: Format name associated with the module format (e.g. Impulse Tracker)
+ * - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
+ * - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
+ * - container: Container format the module file is embedded in, if any (e.g. umx)
+ * - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music)
+ * - tracker: Tracker that was (most likely) used to save the module file, if known
+ * - artist: Author of the module
+ * - title: Module title
+ * - date: Date the module was last saved, in ISO-8601 format.
+ * - message: Song message. If the song message is empty or the module format does not support song messages, a list of instrument and sample names is returned instead.
+ * - message_raw: Song message. If the song message is empty or the module format does not support song messages, an empty string is returned.
+ * - warnings: A list of warnings that were generated while loading the module.
+ * \return The associated value for key.
+ * \sa openmpt_module_get_metadata_keys
+ */
+LIBOPENMPT_API const char * openmpt_module_get_metadata( openmpt_module * mod, const char * key );
+
+/*! Get the current estimated beats per minute (BPM).
+ *
+ * \param mod The module handle to work on.
+ * \remarks Many module formats lack time signature metadata. It is common that this estimate is off by a factor of two, but other multipliers are also possible.
+ * \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate.
+ * \return The current estimated BPM.
+ */
+LIBOPENMPT_API double openmpt_module_get_current_estimated_bpm( openmpt_module * mod );
+/*! \brief Get the current speed
+ *
+ * \param mod The module handle to work on.
+ * \return The current speed in ticks per row.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_current_speed( openmpt_module * mod );
+/*! \brief Get the current tempo
+ *
+ * \param mod The module handle to work on.
+ * \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_current_tempo( openmpt_module * mod );
+/*! \brief Get the current order
+ *
+ * \param mod The module handle to work on.
+ * \return The current order at which the module is being played back.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_current_order( openmpt_module * mod );
+/*! \brief Get the current pattern
+ *
+ * \param mod The module handle to work on.
+ * \return The current pattern that is being played.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_current_pattern( openmpt_module * mod );
+/*! \brief Get the current row
+ *
+ * \param mod The module handle to work on.
+ * \return The current row at which the current pattern is being played.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_current_row( openmpt_module * mod );
+/*! \brief Get the current amount of playing channels.
+ *
+ * \param mod The module handle to work on.
+ * \return The amount of sample channels that are currently being rendered.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_current_playing_channels( openmpt_module * mod );
+
+/*! \brief Get an approximate indication of the channel volume.
+ *
+ * \param mod The module handle to work on.
+ * \param channel The channel whose volume should be retrieved.
+ * \return The approximate channel volume.
+ * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+LIBOPENMPT_API float openmpt_module_get_current_channel_vu_mono( openmpt_module * mod, int32_t channel );
+/*! \brief Get an approximate indication of the channel volume on the front-left speaker.
+ *
+ * \param mod The module handle to work on.
+ * \param channel The channel whose volume should be retrieved.
+ * \return The approximate channel volume.
+ * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+LIBOPENMPT_API float openmpt_module_get_current_channel_vu_left( openmpt_module * mod, int32_t channel );
+/*! \brief Get an approximate indication of the channel volume on the front-right speaker.
+ *
+ * \param mod The module handle to work on.
+ * \param channel The channel whose volume should be retrieved.
+ * \return The approximate channel volume.
+ * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+LIBOPENMPT_API float openmpt_module_get_current_channel_vu_right( openmpt_module * mod, int32_t channel );
+/*! \brief Get an approximate indication of the channel volume on the rear-left speaker.
+ *
+ * \param mod The module handle to work on.
+ * \param channel The channel whose volume should be retrieved.
+ * \return The approximate channel volume.
+ * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+LIBOPENMPT_API float openmpt_module_get_current_channel_vu_rear_left( openmpt_module * mod, int32_t channel );
+/*! \brief Get an approximate indication of the channel volume on the rear-right speaker.
+ *
+ * \param mod The module handle to work on.
+ * \param channel The channel whose volume should be retrieved.
+ * \return The approximate channel volume.
+ * \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+LIBOPENMPT_API float openmpt_module_get_current_channel_vu_rear_right( openmpt_module * mod, int32_t channel );
+
+/*! \brief Get the number of sub-songs
+ *
+ * \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_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
+ *
+ * \param mod The module handle to work on.
+ * \return The number of pattern channels in the module. Not all channels do necessarily contain data.
+ * \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_num_channels( openmpt_module * mod );
+/*! \brief Get the number of orders
+ *
+ * \param mod The module handle to work on.
+ * \return The number of orders in the current sequence of the module.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_num_orders( openmpt_module * mod );
+/*! \brief Get the number of patterns
+ *
+ * \param mod The module handle to work on.
+ * \return The number of distinct patterns in the module.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_num_patterns( openmpt_module * mod );
+/*! \brief Get the number of instruments
+ *
+ * \param mod The module handle to work on.
+ * \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_num_instruments( openmpt_module * mod );
+/*! \brief Get the number of samples
+ *
+ * \param mod The module handle to work on.
+ * \return The number of sample slots in the module.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_num_samples( openmpt_module * mod );
+
+/*! \brief Get a sub-song name
+ *
+ * \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, 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
+ *
+ * \param mod The module handle to work on.
+ * \param index The channel whose name should be retrieved
+ * \return The channel name.
+ * \sa openmpt_module_get_num_channels
+ */
+LIBOPENMPT_API const char * openmpt_module_get_channel_name( openmpt_module * mod, int32_t index );
+/*! \brief Get an order name
+ *
+ * \param mod The module handle to work on.
+ * \param index The order whose name should be retrieved
+ * \return The order name.
+ * \sa openmpt_module_get_num_orders
+ */
+LIBOPENMPT_API const char * openmpt_module_get_order_name( openmpt_module * mod, int32_t index );
+/*! \brief Get a pattern name
+ *
+ * \param mod The module handle to work on.
+ * \param index The pattern whose name should be retrieved
+ * \return The pattern name.
+ * \sa openmpt_module_get_num_patterns
+ */
+LIBOPENMPT_API const char * openmpt_module_get_pattern_name( openmpt_module * mod, int32_t index );
+/*! \brief Get an instrument name
+ *
+ * \param mod The module handle to work on.
+ * \param index The instrument whose name should be retrieved
+ * \return The instrument name.
+ * \sa openmpt_module_get_num_instruments
+ */
+LIBOPENMPT_API const char * openmpt_module_get_instrument_name( openmpt_module * mod, int32_t index );
+/*! \brief Get a sample name
+ *
+ * \param mod The module handle to work on.
+ * \param index The sample whose name should be retrieved
+ * \return The sample name.
+ * \sa openmpt_module_get_num_samples
+ */
+LIBOPENMPT_API const char * openmpt_module_get_sample_name( openmpt_module * mod, int32_t index );
+
+/*! \brief Get pattern at order position
+ *
+ * \param mod The module handle to work on.
+ * \param order The order item whose pattern index should be retrieved.
+ * \return The pattern index found at the given order position of the current sequence.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_order_pattern( openmpt_module * mod, int32_t order );
+/*! \brief Get the number of rows in a pattern
+ *
+ * \param mod The module handle to work on.
+ * \param pattern The pattern whose row count should be retrieved.
+ * \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned.
+ */
+LIBOPENMPT_API int32_t openmpt_module_get_pattern_num_rows( openmpt_module * mod, int32_t pattern );
+
+/*! \brief Get raw pattern content
+ *
+ * \param mod 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.
+ * \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index
+ * \return The internal, raw pattern data at the given pattern position.
+ */
+LIBOPENMPT_API uint8_t openmpt_module_get_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command );
+
+/*! \brief Get formatted (human-readable) pattern content
+ *
+ * \param mod 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.
+ * \param command The cell index at which the data should be retrieved.
+ * \return The formatted pattern data at the given pattern position. See \ref openmpt_module_command_index
+ * \sa openmpt_module_highlight_pattern_row_channel_command
+ */
+LIBOPENMPT_API const char * openmpt_module_format_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command );
+/*! \brief Get highlighting information for formatted pattern content
+ *
+ * \param mod 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.
+ * \param command The cell index at which the data should be retrieved. See \ref openmpt_module_command_index
+ * \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_get_pattern_row_channel_command at the given pattern position.
+ * \remarks The returned string will map each character position of the string returned by openmpt_module_get_pattern_row_channel_command to a highlighting instruction.
+ * Possible highlighting characters are:
+ * - " " : empty/space
+ * - "." : empty/dot
+ * - "n" : generic note
+ * - "m" : special note
+ * - "i" : generic instrument
+ * - "u" : generic volume column effect
+ * - "v" : generic volume column parameter
+ * - "e" : generic effect column effect
+ * - "f" : generic effect column parameter
+ * \sa openmpt_module_get_pattern_row_channel_command
+ */
+LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command );
+
+/*! \brief Get formatted (human-readable) pattern content
+ *
+ * \param mod 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.
+ * \param width The maximum number of characters the string should contain. 0 means no limit.
+ * \param pad If true, the string will be resized to the exact length provided in the width parameter.
+ * \return The formatted pattern data at the given pattern position.
+ * \sa openmpt_module_highlight_pattern_row_channel
+ */
+LIBOPENMPT_API const char * openmpt_module_format_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad );
+/*! \brief Get highlighting information for formatted pattern content
+ *
+ * \param mod 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.
+ * \param width The maximum number of characters the string should contain. 0 means no limit.
+ * \param pad If true, the string will be resized to the exact length provided in the width parameter.
+ * \return The highlighting string for the formatted pattern data as retrieved by openmpt_module_format_pattern_row_channel at the given pattern position.
+ * \sa openmpt_module_format_pattern_row_channel
+ */
+LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad );
+
+/*! \brief Retrieve supported ctl keys
+ *
+ * \param mod The module handle to work on.
+ * \return A semicolon-separated list containing all supported ctl keys.
+ * \remarks Currently supported ctl values are:
+ * - load.skip_samples (boolean): Set to "1" to avoid loading samples into memory
+ * - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory
+ * - load.skip_plugins (boolean): Set to "1" to avoid loading plugins
+ * - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking.
+ * - seek.sync_samples (boolean): Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row.
+ * - subsong (integer): The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong.
+ * - play.at_end (text): Chooses the behaviour when the end of song is reached:
+ * - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames.
+ * - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start.
+ * - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames.
+ * - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo.
+ * - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch.
+ * - render.resampler.emulate_amiga (boolean): 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.
+ * - render.resampler.emulate_amiga_type (string): Configures the filter type to use for the Amiga resampler. Supported values are:
+ * - "auto": Filter type is chosen by the library and might change. This is the default.
+ * - "a500": Amiga A500 filter.
+ * - "a1200": Amiga A1200 filter.
+ * - "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future.
+ * - render.opl.volume_factor (floatingpoint): Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume.
+ * - dither (integer): 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.
+ * - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker).
+ * - 3: Rectangular, 1 bit depth, simple 1st order noise shaping
+ */
+LIBOPENMPT_API const char * openmpt_module_get_ctls( openmpt_module * mod );
+
+/*! \brief Get current ctl value
+ *
+ * \param mod The module handle to work on.
+ * \param ctl The ctl key whose value should be retrieved.
+ * \return The associated ctl value, or NULL on failure.
+ * \sa openmpt_module_get_ctls
+ * \deprecated Please use openmpt_module_ctl_get_boolean(), openmpt_module_ctl_get_integer(), openmpt_module_ctl_get_floatingpoint(), or openmpt_module_ctl_get_text().
+ */
+LIBOPENMPT_API LIBOPENMPT_DEPRECATED const char * openmpt_module_ctl_get( openmpt_module * mod, const char * ctl );
+/*! \brief Get current ctl boolean value
+ *
+ * \param mod The module handle to work on.
+ * \param ctl The ctl key whose value should be retrieved.
+ * \return The associated ctl value, or NULL on failure.
+ * \sa openmpt_module_get_ctls
+ * \since 0.5.0
+ */
+LIBOPENMPT_API int openmpt_module_ctl_get_boolean( openmpt_module * mod, const char * ctl );
+/*! \brief Get current ctl integer value
+ *
+ * \param mod The module handle to work on.
+ * \param ctl The ctl key whose value should be retrieved.
+ * \return The associated ctl value, or NULL on failure.
+ * \sa openmpt_module_get_ctls
+ * \since 0.5.0
+ */
+LIBOPENMPT_API int64_t openmpt_module_ctl_get_integer( openmpt_module * mod, const char * ctl );
+/*! \brief Get current ctl floatingpoint value
+ *
+ * \param mod The module handle to work on.
+ * \param ctl The ctl key whose value should be retrieved.
+ * \return The associated ctl value, or NULL on failure.
+ * \sa openmpt_module_get_ctls
+ * \since 0.5.0
+ */
+LIBOPENMPT_API double openmpt_module_ctl_get_floatingpoint( openmpt_module * mod, const char * ctl );
+/*! \brief Get current ctl string value
+ *
+ * \param mod The module handle to work on.
+ * \param ctl The ctl key whose value should be retrieved.
+ * \return The associated ctl value, or NULL on failure.
+ * \sa openmpt_module_get_ctls
+ * \since 0.5.0
+ */
+LIBOPENMPT_API const char * openmpt_module_ctl_get_text( openmpt_module * mod, const char * ctl );
+
+/*! \brief Set ctl value
+ *
+ * \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
+ * \deprecated Please use openmpt_module_ctl_set_boolean(), openmpt_module_ctl_set_integer(), openmpt_module_ctl_set_floatingpoint(), or openmpt_module_ctl_set_text().
+ */
+LIBOPENMPT_API LIBOPENMPT_DEPRECATED int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value );
+/*! \brief Set ctl boolean value
+ *
+ * \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
+ * \since 0.5.0
+ */
+LIBOPENMPT_API int openmpt_module_ctl_set_boolean( openmpt_module * mod, const char * ctl, int value );
+/*! \brief Set ctl integer value
+ *
+ * \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
+ * \since 0.5.0
+ */
+LIBOPENMPT_API int openmpt_module_ctl_set_integer( openmpt_module * mod, const char * ctl, int64_t value );
+/*! \brief Set ctl floatingpoint value
+ *
+ * \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
+ * \since 0.5.0
+ */
+LIBOPENMPT_API int openmpt_module_ctl_set_floatingpoint( openmpt_module * mod, const char * ctl, double value );
+/*! \brief Set ctl string value
+ *
+ * \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
+ * \since 0.5.0
+ */
+LIBOPENMPT_API int openmpt_module_ctl_set_text( openmpt_module * mod, const char * ctl, const char * value );
+
+/* remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR */
+
+#ifdef __cplusplus
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* LIBOPENMPT_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.hpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.hpp
new file mode 100644
index 00000000..b0e62da0
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.hpp
@@ -0,0 +1,1185 @@
+/*
+ * libopenmpt.hpp
+ * --------------
+ * 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_HPP
+#define LIBOPENMPT_HPP
+
+#include "libopenmpt_config.h"
+
+#include <exception>
+#include <iosfwd>
+#include <iostream>
+#include <map>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include <cstddef>
+#include <cstdint>
+
+/*!
+ * \page libopenmpt_cpp_overview C++ API
+ *
+ * \section libopenmpt_cpp_error Error Handling
+ *
+ * libopenmpt C++ uses C++ exception handling for errror reporting.
+ *
+ * Unless otherwise noted, any libopenmpt function may throw exceptions and
+ * all exceptions thrown by libopenmpt itself are derived from
+ * openmpt::exception.
+ * In addition, any libopenmpt function may also throw any exception specified
+ * by the C++ language and C++ standard library. These are all derived from
+ * std::exception.
+ *
+ * \section libopenmpt_cpp_strings Strings
+ *
+ * - All strings returned from libopenmpt are encoded in UTF-8.
+ * - All strings passed to libopenmpt should also be encoded in UTF-8.
+ * Behaviour in case of invalid UTF-8 is unspecified.
+ * - libopenmpt does not enforce or expect any particular Unicode
+ * normalization form.
+ *
+ * \section libopenmpt_cpp_fileio File I/O
+ *
+ * libopenmpt can use 3 different strategies for file I/O.
+ *
+ * - openmpt::module::module() with any kind of memory buffer as parameter will
+ * load the module from the provided memory buffer, which will require loading
+ * all data upfront by the library
+ * caller.
+ * - openmpt::module::module() with a seekable std::istream as parameter will
+ * load the module via the stream interface. libopenmpt will not implement an
+ * additional buffering layer in this case whih means the callbacks are assumed
+ * to be performant even with small i/o sizes.
+ * - openmpt::module::module() with an unseekable std::istream as parameter
+ * will load the module via the stream interface. libopempt will make an
+ * internal copy as it goes along, and sometimes have to pre-cache the whole
+ * file in case it needs to know the complete file size. This strategy is
+ * intended to be used if the file is located on a high latency network.
+ *
+ * | constructor | speed | memory consumption |
+ * | ----------------: | :----: | :----------------: |
+ * | memory buffer | <p style="background-color:green" >fast </p> | <p style="background-color:yellow">medium</p> |
+ * | seekable stream | <p style="background-color:red" >slow </p> | <p style="background-color:green" >low </p> |
+ * | 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 constructor is no longer
+ * needed after the openmpt::module has been constructed and can be destroyed
+ * by the caller.
+ *
+ * \section libopenmpt_cpp_outputformat Output Format
+ *
+ * libopenmpt supports a wide range of PCM output formats:
+ * [8000..192000]/[mono|stereo|quad]/[f32|i16].
+ *
+ * Unless you have some very specific requirements demanding a particular aspect
+ * of the output format, you should always prefer 48000/stereo/f32 as the
+ * libopenmpt PCM format.
+ *
+ * - Please prefer 48000Hz unless the user explicitly demands something else.
+ * Practically all audio equipment and file formats use 48000Hz nowadays.
+ * - Practically all module formats are made for stereo output. Mono will not
+ * give you any measurable speed improvements and can trivially be obtained from
+ * the stereo output anyway. Quad is not expected by almost all modules and even
+ * if they do use surround effects, they expect the effects to be mixed to
+ * stereo.
+ * - Floating point output provides headroom instead of hard clipping if the
+ * module is louder than 0dBFs, will give you a better signal-to-noise ratio
+ * than int16 output, and avoid the need to apply an additional dithering to the
+ * output by libopenmpt. Unless your platform has no floating point unit at all,
+ * floating point will thus also be slightly faster.
+ *
+ * \section libopenmpt_cpp_threads libopenmpt in multi-threaded environments
+ *
+ * - 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.
+ * - You must ensure to only ever access a particular libopenmpt object via
+ * non-const member functions from a single thread at a time.
+ * - You may access a particular libopenmpt object concurrently from different
+ * threads when using only const member functions from all threads.
+ * - Consecutive accesses can happen from different threads.
+ * - Different objects can be accessed concurrently from different threads.
+ *
+ * \section libopenmpt-cpp-windows Windows support
+ *
+ * Using the libopenmpt C++ API when libopenmpt is compiled as a DLL on Windows
+ * requires `#define LIBOPENMPT_USE_DLL` (or some equivalent build system
+ * configuration) before `#include <libopenmpt/libopenmpt.hpp>` in order to
+ * correctly import the symbols from the DLL.
+ *
+ * \section libopenmpt-cpp-detailed Detailed documentation
+ *
+ * \ref libopenmpt_cpp
+ *
+ * \section libopenmpt_cpp_examples Example
+ *
+ * \include libopenmpt_example_cxx.cpp
+ *
+ */
+
+/*! \defgroup libopenmpt_cpp libopenmpt C++ */
+
+namespace openmpt {
+
+/*! \addtogroup libopenmpt_cpp
+ @{
+*/
+
+#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 ) noexcept;
+ exception( const exception & other ) noexcept;
+ exception( exception && other ) noexcept;
+ exception & operator = ( const exception & other ) noexcept;
+ exception & operator = ( exception && other ) noexcept;
+ virtual ~exception() noexcept;
+ const char * what() const noexcept override;
+}; // 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 + 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();
+
+//! Get the core version number
+/*!
+ Return the OpenMPT core version number.
+ \return The value represents (majormajor << 24 + major << 16 + minor << 8 + minorminor).
+*/
+LIBOPENMPT_CXX_API std::uint32_t get_core_version();
+
+namespace string {
+
+//! Return a verbose library version string from openmpt::string::get(). \deprecated Please use `"library_version"` directly.
+static const char library_version LIBOPENMPT_ATTR_DEPRECATED [] = "library_version";
+//! Return a verbose library features string from openmpt::string::get(). \deprecated Please use `"library_features"` directly.
+static const char library_features LIBOPENMPT_ATTR_DEPRECATED [] = "library_features";
+//! Return a verbose OpenMPT core version string from openmpt::string::get(). \deprecated Please use `"core_version"` directly.
+static const char core_version LIBOPENMPT_ATTR_DEPRECATED [] = "core_version";
+//! Return information about the current build (e.g. the build date or compiler used) from openmpt::string::get(). \deprecated Please use `"build"` directly.
+static const char build LIBOPENMPT_ATTR_DEPRECATED [] = "build";
+//! Return all contributors from openmpt::string::get(). \deprecated Please use `"credits"` directly.
+static const char credits LIBOPENMPT_ATTR_DEPRECATED [] = "credits";
+//! Return contact information about libopenmpt from openmpt::string::get(). \deprecated Please use `"contact"` directly.
+static const char contact LIBOPENMPT_ATTR_DEPRECATED [] = "contact";
+//! Return the libopenmpt license from openmpt::string::get(). \deprecated Please use `"license"` directly.
+static const char license LIBOPENMPT_ATTR_DEPRECATED [] = "license";
+
+//! Get library related metadata.
+/*!
+ \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
+ - "contact": contact information about libopenmpt
+ - "license": the libopenmpt license
+ - "url": libopenmpt website URL
+ - "support_forum_url": libopenmpt support and discussions forum URL
+ - "bugtracker_url": libopenmpt bug and issue tracker URL
+
+ \return A (possibly multi-line) string containing the queried information. If no information is available, the string is empty.
+*/
+LIBOPENMPT_CXX_API std::string get( const std::string & key );
+
+} // namespace string
+
+//! Get a list of supported file extensions
+/*!
+ \return The list of extensions supported by this libopenmpt build. The extensions are returned lower-case without a leading dot.
+*/
+LIBOPENMPT_CXX_API std::vector<std::string> get_supported_extensions();
+
+//! Query whether a file extension is supported
+/*!
+ \param extension file extension to query without a leading dot. The case is ignored.
+ \return true if the extension is supported by libopenmpt, false otherwise.
+ \deprecated Please use openmpt::is_extension_supported2().
+*/
+LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API bool is_extension_supported( const std::string & extension );
+//! Query whether a file extension is supported
+/*!
+ \param extension file extension to query without a leading dot. The case is ignored.
+ \return true if the extension is supported by libopenmpt, false otherwise.
+ \since 0.5.0
+*/
+LIBOPENMPT_CXX_API bool is_extension_supported2( std::string_view extension );
+
+//! Roughly scan the input stream to find out whether libopenmpt might be able to open it
+/*!
+ \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 log Log where warning and errors are written.
+ \return Probability between 0.0 and 1.0.
+ \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::could_open_probability().
+*/
+LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API 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 \deprecated Please use openmpt::probe_file_header_flags_modules2.
+static const std::uint64_t probe_file_header_flags_modules LIBOPENMPT_ATTR_DEPRECATED = 0x1ull;
+
+//! Probe for module-specific container formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_containers2.
+static const std::uint64_t probe_file_header_flags_containers LIBOPENMPT_ATTR_DEPRECATED = 0x2ull;
+
+//! Probe for the default set of formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_default2.
+static const std::uint64_t probe_file_header_flags_default LIBOPENMPT_ATTR_DEPRECATED = 0x1ull | 0x2ull;
+
+//! Probe for no formats in openmpt::probe_file_header(). \since 0.3.0 \deprecated Please use openmpt::probe_file_header_flags_none2.
+static const std::uint64_t probe_file_header_flags_none LIBOPENMPT_ATTR_DEPRECATED = 0x0ull;
+
+//! Possible values for openmpt::probe_file_header() flags parameter. \since 0.6.0
+enum probe_file_header_flags : std::uint64_t {
+ //! Probe for module formats in openmpt::probe_file_header(). \since 0.6.0
+ probe_file_header_flags_modules2 = 0x1ull,
+ //! Probe for module-specific container formats in openmpt::probe_file_header(). \since 0.6.0
+ probe_file_header_flags_containers2 = 0x2ull,
+ //! Probe for the default set of formats in openmpt::probe_file_header(). \since 0.6.0
+ probe_file_header_flags_default2 = probe_file_header_flags_modules2 | probe_file_header_flags_containers2,
+ //! Probe for no formats in openmpt::probe_file_header(). \since 0.6.0
+ probe_file_header_flags_none2 = 0x0ull
+};
+
+//! 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 Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2.
+ \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 interface that might be required 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.5.0
+*/
+LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::byte * 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 Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2.
+ \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 interface that might be required 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, 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 Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2.
+ \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 interface that might be required 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.5.0
+*/
+LIBOPENMPT_CXX_API int probe_file_header( std::uint64_t flags, const std::byte * 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 Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2.
+ \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 interface that might be required 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 Bit mask of openmpt::probe_file_header_flags_modules2 and openmpt::probe_file_header_flags_containers2, or openmpt::probe_file_header_flags_default2.
+ \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 interface that might be required 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;
+
+class module_ext;
+
+namespace detail {
+
+typedef std::map< std::string, std::string > initial_ctls_map;
+
+} // namespace detail
+
+class LIBOPENMPT_CXX_API module {
+
+ friend class module_ext;
+
+public:
+
+ //! Parameter index to use with openmpt::module::get_render_param and openmpt::module::set_render_param
+ enum render_param {
+ //! Master Gain
+ /*!
+ The related value represents a relative gain in milliBel.\n
+ The default value is 0.\n
+ The supported value range is unlimited.\n
+ */
+ RENDER_MASTERGAIN_MILLIBEL = 1,
+ //! Stereo Separation
+ /*!
+ The related value represents the stereo separation generated by the libopenmpt mixer in percent.\n
+ The default value is 100.\n
+ The supported value range is [0,200].\n
+ */
+ RENDER_STEREOSEPARATION_PERCENT = 2,
+ //! Interpolation Filter
+ /*!
+ The related value represents the interpolation filter length used by the libopenmpt mixer.\n
+ The default value is 0, which indicates a recommended default value.\n
+ The supported value range is [0,inf). Values greater than the implementation limit are clamped to the maximum supported value.\n
+ Currently supported values:
+ - 0: internal default
+ - 1: no interpolation (zero order hold)
+ - 2: linear interpolation
+ - 4: cubic interpolation
+ - 8: windowed sinc with 8 taps
+ */
+ RENDER_INTERPOLATIONFILTER_LENGTH = 3,
+ //! Volume Ramping Strength
+ /*!
+ The related value represents the amount of volume ramping done by the libopenmpt mixer.\n
+ The default value is -1, which indicates a recommended default value.\n
+ The meaningful value range is [-1..10].\n
+ A value of 0 completely disables volume ramping. This might cause clicks in sound output.\n
+ Higher values imply slower/softer volume ramps.
+ */
+ RENDER_VOLUMERAMPING_STRENGTH = 4
+ };
+
+ //! Parameter index to use with openmpt::module::get_pattern_row_channel_command, openmpt::module::format_pattern_row_channel_command and openmpt::module::highlight_pattern_row_channel_command
+ enum command_index {
+ command_note = 0,
+ command_instrument = 1,
+ command_volumeffect = 2,
+ command_effect = 3,
+ command_volume = 4,
+ command_parameter = 5
+ };
+
+private:
+ module_impl * impl;
+private:
+ // non-copyable
+ module( const module & );
+ void operator = ( const module & );
+private:
+ // for module_ext
+ module();
+ void set_impl( module_impl * i );
+public:
+ //! Construct an openmpt::module
+ /*!
+ \param stream Input stream from which the module is loaded. After the constructor has finished successfully, the input position of stream is set to the byte after the last byte that has been read. If the constructor fails, the state of the input position of stream is undefined.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ \since 0.5.0
+ */
+ module( const std::vector<std::byte> & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param beg Begin of data to load the module from.
+ \param end End of data to load the module from.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ \since 0.5.0
+ */
+ module( const std::byte * beg, const std::byte * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param size Amount of data available.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ \since 0.5.0
+ */
+ module( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const std::vector<std::uint8_t> & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param beg Begin of data to load the module from.
+ \param end End of data to load the module from.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const std::uint8_t * beg, const std::uint8_t * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param size Amount of data available.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const std::vector<char> & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param beg Begin of data to load the module from.
+ \param end End of data to load the module from.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const char * beg, const char * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param size Amount of data available.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ /*!
+ \param data Data to load the module from.
+ \param size Amount of data available.
+ \param log 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 ctls A map of initial ctl values, see openmpt::module::get_ctls.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception in case the provided file cannot be opened.
+ \remarks The input data can be discarded after an openmpt::module has been constructed successfully.
+ \sa \ref libopenmpt_cpp_fileio
+ */
+ module( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ virtual ~module();
+public:
+
+ //! Select a sub-song from a multi-song module
+ /*!
+ \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_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
+ - -1: repeat forever
+ - 0: play once, repeat zero times (the default)
+ - n>0: play once and repeat n times after that
+ \sa openmpt::module::get_repeat_count
+ */
+ void set_repeat_count( std::int32_t repeat_count );
+ //! Get Repeat Count
+ /*!
+ \return Repeat Count
+ - -1: repeat forever
+ - 0: play once, repeat zero times (the default)
+ - n>0: play once and repeat n times after that
+ \sa openmpt::module::set_repeat_count
+ */
+ std::int32_t get_repeat_count() const;
+
+ //! Get approximate song duration
+ /*!
+ \return Approximate duration of current sub-song in seconds.
+ \remarks The function may return infinity if the pattern data is too complex to evaluate.
+ */
+ double get_duration_seconds() const;
+
+ //! Set approximate current song position
+ /*!
+ \param seconds Seconds to seek to. If seconds is out of range, the position gets set to song start or end respectively.
+ \return Approximate new song position in seconds.
+ \sa openmpt::module::get_position_seconds
+ */
+ double set_position_seconds( double seconds );
+ //! Get current song position
+ /*!
+ \return Current song position in seconds.
+ \sa openmpt::module::set_position_seconds
+ */
+ double get_position_seconds() const;
+
+ //! Set approximate current song position
+ /*!
+ If order or row are out of range, to position is not modified and the current position is returned.
+ \param order Pattern order number to seek to.
+ \param row Pattern row number to seek to.
+ \return Approximate new song position in seconds.
+ \sa openmpt::module::set_position_seconds
+ \sa openmpt::module::get_position_seconds
+ */
+ double set_position_order_row( std::int32_t order, std::int32_t row );
+
+ //! Get render parameter
+ /*!
+ \param param Parameter to query. See openmpt::module::render_param.
+ \return The current value of the parameter.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if param is invalid.
+ \sa openmpt::module::render_param
+ \sa openmpt::module::set_render_param
+ */
+ std::int32_t get_render_param( int param ) const;
+ //! Set render parameter
+ /*!
+ \param param Parameter to set. See openmpt::module::render_param.
+ \param value The value to set param to.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if param is invalid or value is out of range.
+ \sa openmpt::module::render_param
+ \sa openmpt::module::get_render_param
+ */
+ void set_render_param( int param, std::int32_t value );
+
+ /*@{*/
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param mono Pointer to a buffer of at least count elements that receives the mono/center output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * mono );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \param rear_left Pointer to a buffer of at least count elements that receives the rear left output.
+ \param rear_right Pointer to a buffer of at least count elements that receives the rear right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param mono Pointer to a buffer of at least count elements that receives the mono/center output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read( std::int32_t samplerate, std::size_t count, float * mono );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param left Pointer to a buffer of at least count elements that receives the left output.
+ \param right Pointer to a buffer of at least count elements that receives the right output.
+ \param rear_left Pointer to a buffer of at least count elements that receives the rear left output.
+ \param rear_right Pointer to a buffer of at least count elements that receives the rear right output.
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_stereo Pointer to a buffer of at least count*2 elements that receives the interleaved stereo output in the order (L,R).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo );
+ //! Render audio data
+ /*!
+ \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced.
+ \param count Number of audio frames to render per channel.
+ \param interleaved_quad Pointer to a buffer of at least count*4 elements that receives the interleaved quad surround output in the order (L,R,RL,RR).
+ \return The number of frames actually rendered.
+ \retval 0 The end of song has been reached.
+ \remarks The output buffers are only written to up to the returned number of elements.
+ \remarks You can freely switch between any of the "read*" variants if you see a need to do so. libopenmpt tries to introduce as little switching annoyances as possible. Normally, you would only use a single one of these functions for rendering a particular module.
+ \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot.
+ \sa \ref libopenmpt_cpp_outputformat
+ */
+ std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad );
+ /*@}*/
+
+ //! Get the list of supported metadata item keys
+ /*!
+ \return Metadata item keys supported by openmpt::module::get_metadata
+ \sa openmpt::module::get_metadata
+ */
+ std::vector<std::string> get_metadata_keys() const;
+ //! Get a metadata item value
+ /*!
+ \param key Metadata item key to query. Use openmpt::module::get_metadata_keys to check for available keys.
+ Possible keys are:
+ - type: Module format extension (e.g. it) or another similar identifier for modules formats that typically do not use a file extension
+ - type_long: Format name associated with the module format (e.g. Impulse Tracker)
+ - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
+ - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
+ - container: Container format the module file is embedded in, if any (e.g. umx)
+ - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music)
+ - tracker: Tracker that was (most likely) used to save the module file, if known
+ - artist: Author of the module
+ - title: Module title
+ - date: Date the module was last saved, in ISO-8601 format.
+ - message: Song message. If the song message is empty or the module format does not support song messages, a list of instrument and sample names is returned instead.
+ - message_raw: Song message. If the song message is empty or the module format does not support song messages, an empty string is returned.
+ - warnings: A list of warnings that were generated while loading the module.
+ \return The associated value for key.
+ \sa openmpt::module::get_metadata_keys
+ */
+ std::string get_metadata( const std::string & key ) const;
+
+ //! Get the current estimated beats per minute (BPM).
+ /*!
+ \remarks Many module formats lack time signature metadata. It is common that this estimate is off by a factor of two, but other multipliers are also possible.
+ \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate.
+ \return The current estimated BPM.
+ */
+ double get_current_estimated_bpm() const;
+ //! Get the current speed
+ /*!
+ \return The current speed in ticks per row.
+ */
+ std::int32_t get_current_speed() const;
+ //! Get the current tempo
+ /*!
+ \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used.
+ */
+ std::int32_t get_current_tempo() const;
+ //! Get the current order
+ /*!
+ \return The current order at which the module is being played back.
+ */
+ std::int32_t get_current_order() const;
+ //! Get the current pattern
+ /*!
+ \return The current pattern that is being played.
+ */
+ std::int32_t get_current_pattern() const;
+ //! Get the current row
+ /*!
+ \return The current row at which the current pattern is being played.
+ */
+ std::int32_t get_current_row() const;
+ //! Get the current amount of playing channels.
+ /*!
+ \return The amount of sample channels that are currently being rendered.
+ */
+ std::int32_t get_current_playing_channels() const;
+
+ //! Get an approximate indication of the channel volume.
+ /*!
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+ float get_current_channel_vu_mono( std::int32_t channel ) const;
+ //! Get an approximate indication of the channel volume on the front-left speaker.
+ /*!
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+ float get_current_channel_vu_left( std::int32_t channel ) const;
+ //! Get an approximate indication of the channel volume on the front-right speaker.
+ /*!
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+ float get_current_channel_vu_right( std::int32_t channel ) const;
+ //! Get an approximate indication of the channel volume on the rear-left speaker.
+ /*!
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+ float get_current_channel_vu_rear_left( std::int32_t channel ) const;
+ //! Get an approximate indication of the channel volume on the rear-right speaker.
+ /*!
+ \param channel The channel whose volume should be retrieved.
+ \return The approximate channel volume.
+ \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account.
+ */
+ float get_current_channel_vu_rear_right( std::int32_t channel ) const;
+
+ //! 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, openmpt::module::get_selected_subsong
+ */
+ std::int32_t get_num_subsongs() const;
+ //! Get the number of pattern channels
+ /*!
+ \return The number of pattern channels in the module. Not all channels do necessarily contain data.
+ \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes.
+ */
+ std::int32_t get_num_channels() const;
+ //! Get the number of orders
+ /*!
+ \return The number of orders in the current sequence of the module.
+ */
+ std::int32_t get_num_orders() const;
+ //! Get the number of patterns
+ /*!
+ \return The number of distinct patterns in the module.
+ */
+ std::int32_t get_num_patterns() const;
+ //! Get the number of instruments
+ /*!
+ \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats.
+ */
+ std::int32_t get_num_instruments() const;
+ //! Get the number of samples
+ /*!
+ \return The number of sample slots in the module.
+ */
+ std::int32_t get_num_samples() const;
+
+ //! Get a list of sub-song names
+ /*!
+ \return All sub-song names.
+ \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
+ /*!
+ \return All channel names.
+ \sa openmpt::module::get_num_channels
+ */
+ std::vector<std::string> get_channel_names() const;
+ //! Get a list of order names
+ /*!
+ \return All order names.
+ \sa openmpt::module::get_num_orders
+ */
+ std::vector<std::string> get_order_names() const;
+ //! Get a list of pattern names
+ /*!
+ \return All pattern names.
+ \sa openmpt::module::get_num_patterns
+ */
+ std::vector<std::string> get_pattern_names() const;
+ //! Get a list of instrument names
+ /*!
+ \return All instrument names.
+ \sa openmpt::module::get_num_instruments
+ */
+ std::vector<std::string> get_instrument_names() const;
+ //! Get a list of sample names
+ /*!
+ \return All sample names.
+ \sa openmpt::module::get_num_samples
+ */
+ std::vector<std::string> get_sample_names() const;
+
+ //! Get pattern at order position
+ /*!
+ \param order The order item whose pattern index should be retrieved.
+ \return The pattern index found at the given order position of the current sequence.
+ */
+ std::int32_t get_order_pattern( std::int32_t order ) const;
+
+ //! Get the number of rows in a pattern
+ /*!
+ \param pattern The pattern whose row count should be retrieved.
+ \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned.
+ */
+ std::int32_t get_pattern_num_rows( std::int32_t pattern ) const;
+
+ //! Get raw pattern content
+ /*!
+ \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.
+ \param command The cell index at which the data should be retrieved. See openmpt::module::command_index
+ \return The internal, raw pattern data at the given pattern position.
+ */
+ std::uint8_t get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const;
+
+ //! Get formatted (human-readable) pattern content
+ /*!
+ \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.
+ \param command The cell index at which the data should be retrieved.
+ \return The formatted pattern data at the given pattern position. See openmpt::module::command_index
+ \sa openmpt::module::highlight_pattern_row_channel_command
+ */
+ std::string format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const;
+
+ //! Get highlighting information for formatted pattern content
+ /*!
+ \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.
+ \param command The cell index at which the data should be retrieved. See openmpt::module::command_index
+ \return The highlighting string for the formatted pattern data as retrieved by openmpt::module::get_pattern_row_channel_command at the given pattern position.
+ \remarks The returned string will map each character position of the string returned by openmpt::module::get_pattern_row_channel_command to a highlighting instruction.
+ Possible highlighting characters are:
+ - " " : empty/space
+ - "." : empty/dot
+ - "n" : generic note
+ - "m" : special note
+ - "i" : generic instrument
+ - "u" : generic volume column effect
+ - "v" : generic volume column parameter
+ - "e" : generic effect column effect
+ - "f" : generic effect column parameter
+ \sa openmpt::module::get_pattern_row_channel_command
+ */
+ std::string highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const;
+
+ //! Get formatted (human-readable) pattern content
+ /*!
+ \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.
+ \param width The maximum number of characters the string should contain. 0 means no limit.
+ \param pad If true, the string will be resized to the exact length provided in the width parameter.
+ \return The formatted pattern data at the given pattern position.
+ \sa openmpt::module::highlight_pattern_row_channel
+ */
+ std::string format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const;
+ //! Get highlighting information for formatted pattern content
+ /*!
+ \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.
+ \param width The maximum number of characters the string should contain. 0 means no limit.
+ \param pad If true, the string will be resized to the exact length provided in the width parameter.
+ \return The highlighting string for the formatted pattern data as retrieved by openmpt::module::format_pattern_row_channel at the given pattern position.
+ \sa openmpt::module::format_pattern_row_channel
+ */
+ std::string highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const;
+
+ //! Retrieve supported ctl keys
+ /*!
+ \return A vector containing all supported ctl keys.
+ \remarks Currently supported ctl values are:
+ - load.skip_samples (boolean): Set to "1" to avoid loading samples into memory
+ - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory
+ - load.skip_plugins (boolean): Set to "1" to avoid loading plugins
+ - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking.
+ - seek.sync_samples (boolean): Set to "1" to sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row.
+ - subsong (integer): The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong.
+ - play.at_end (text): Chooses the behaviour when the end of song is reached:
+ - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames.
+ - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start.
+ - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames.
+ - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo.
+ - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch.
+ - render.resampler.emulate_amiga (boolean): 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.
+ - render.resampler.emulate_amiga_type (string): Configures the filter type to use for the Amiga resampler. Supported values are:
+ - "auto": Filter type is chosen by the library and might change. This is the default.
+ - "a500": Amiga A500 filter.
+ - "a1200": Amiga A1200 filter.
+ - "unfiltered": BLEP synthesis without model-specific filters. The LED filter is ignored by this setting. This filter mode is considered to be experimental and might change in the future.
+ - render.opl.volume_factor (floatingpoint): Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume.
+ - dither (integer): 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.
+ - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker).
+ - 3: Rectangular, 1 bit depth, simple 1st order noise shaping
+
+ An exclamation mark ("!") or a question mark ("?") can be appended to any ctl key in order to influence the behaviour in case of an unknown ctl key. "!" causes an exception to be thrown; "?" causes the ctl to be silently ignored. In case neither is appended to the key name, unknown init_ctls are ignored by default and other ctls throw an exception by default.
+ */
+ std::vector<std::string> get_ctls() const;
+
+ //! Get current ctl value
+ /*!
+ \param ctl The ctl key whose value should be retrieved.
+ \return The associated ctl value.
+ \sa openmpt::module::get_ctls
+ \deprecated Please use openmpt::module::ctl_get_boolean(), openmpt::module::ctl_get_integer(), openmpt::module::ctl_get_floatingpoint(), or openmpt::module::ctl_get_text().
+ */
+ LIBOPENMPT_ATTR_DEPRECATED std::string ctl_get( const std::string & ctl ) const;
+ //! Get current ctl boolean value
+ /*!
+ \param ctl The ctl key whose value should be retrieved.
+ \return The associated ctl value.
+ \sa openmpt::module::get_ctls
+ \since 0.5.0
+ */
+ bool ctl_get_boolean( std::string_view ctl ) const;
+ //! Get current ctl integer value
+ /*!
+ \param ctl The ctl key whose value should be retrieved.
+ \return The associated ctl value.
+ \sa openmpt::module::get_ctls
+ \since 0.5.0
+ */
+ std::int64_t ctl_get_integer( std::string_view ctl ) const;
+ //! Get current ctl floatingpoint value
+ /*!
+ \param ctl The ctl key whose value should be retrieved.
+ \return The associated ctl value.
+ \sa openmpt::module::get_ctls
+ \since 0.5.0
+ */
+ double ctl_get_floatingpoint( std::string_view ctl ) const;
+ //! Get current ctl text value
+ /*!
+ \param ctl The ctl key whose value should be retrieved.
+ \return The associated ctl value.
+ \sa openmpt::module::get_ctls
+ \since 0.5.0
+ */
+ std::string ctl_get_text( std::string_view ctl ) const;
+
+ //! Set ctl value
+ /*!
+ \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
+ \deprecated Please use openmpt::module::ctl_set_bool(), openmpt::module::ctl_set_int(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_string().
+ */
+ LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value );
+ //! Set ctl boolean value
+ /*!
+ \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
+ \since 0.5.0
+ */
+ void ctl_set_boolean( std::string_view ctl, bool value );
+ //! Set ctl integer value
+ /*!
+ \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
+ \since 0.5.0
+ */
+ void ctl_set_integer( std::string_view ctl, std::int64_t value );
+ //! Set ctl floatingpoint value
+ /*!
+ \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
+ \since 0.5.0
+ */
+ void ctl_set_floatingpoint( std::string_view ctl, double value );
+ //! Set ctl text value
+ /*!
+ \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
+ \since 0.5.0
+ */
+ void ctl_set_text( std::string_view ctl, std::string_view value );
+
+ // remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR
+
+}; // class module
+
+/*!
+ @}
+*/
+
+} // namespace openmpt
+
+#endif // LIBOPENMPT_HPP
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.pc.in b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.pc.in
new file mode 100644
index 00000000..5d480a82
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt.pc.in
@@ -0,0 +1,14 @@
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+Name: libopenmpt
+Description: Tracker module player based on OpenMPT
+Version: @VERSION@
+Requires.private: @LIBOPENMPT_REQUIRES_PRIVATE@
+Libs: -L${libdir} -lopenmpt
+Libs.private: @LIBOPENMPT_LIBS_PRIVATE@
+Cflags: -I${includedir}
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_c.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_c.cpp
new file mode 100644
index 00000000..4d5c8794
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_c.cpp
@@ -0,0 +1,1881 @@
+/*
+ * libopenmpt_c.cpp
+ * ----------------
+ * Purpose: libopenmpt C interface implementation
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#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>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#if defined(_MSC_VER)
+#pragma warning(disable:4702) /* unreachable code */
+#endif
+
+namespace openmpt {
+
+static const char * strdup( const char * src ) {
+ char * dst = (char*)std::calloc( std::strlen( src ) + 1, sizeof( char ) );
+ if ( !dst ) {
+ return NULL;
+ }
+ std::strcpy( dst, src );
+ return dst;
+}
+
+class logfunc_logger : public log_interface {
+private:
+ openmpt_log_func m_logfunc;
+ void * m_user;
+public:
+ logfunc_logger( openmpt_log_func func, void * user ) : m_logfunc(func), m_user(user) {
+ return;
+ }
+ void log( const std::string & message ) const override {
+ if ( m_logfunc ) {
+ m_logfunc( message.c_str(), m_user );
+ } else {
+ openmpt_log_func_default( message.c_str(), m_user );
+ }
+ }
+}; // class logfunc_logger
+
+namespace interface {
+
+class invalid_module_pointer : public openmpt::exception {
+public:
+ invalid_module_pointer()
+ : openmpt::exception("module * not valid")
+ {
+ return;
+ }
+ invalid_module_pointer(const invalid_module_pointer&) = default;
+ virtual ~invalid_module_pointer() noexcept = default;
+};
+
+class argument_null_pointer : public openmpt::exception {
+public:
+ argument_null_pointer()
+ : openmpt::exception("argument null pointer")
+ {
+ return;
+ }
+ argument_null_pointer(const argument_null_pointer&) = default;
+ virtual ~argument_null_pointer() noexcept = default;
+};
+
+} // namespace interface
+
+static std::string format_exception( const char * const function ) {
+ std::string err;
+ try {
+ // cppcheck false-positive
+ // cppcheck-suppress rethrowNoCurrentException
+ throw;
+ } catch ( const openmpt::exception & e ) {
+ err += function;
+ err += ": ";
+ err += "ERROR: ";
+ const char * what = e.what();
+ err += what ? what : "";
+ } catch ( const std::bad_alloc & e ) {
+ err += function;
+ err += ": ";
+ err += "OUT OF MEMORY: ";
+ const char * what = e.what();
+ err += what ? what : "";
+ } catch ( const std::exception & e ) {
+ err += function;
+ err += ": ";
+ err += "INTERNAL ERROR: ";
+ const char * what = e.what();
+ err += what ? what : "";
+ } catch ( ... ) {
+ err += function;
+ err += ": ";
+ err += "UNKNOWN INTERNAL ERROR";
+ }
+ 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 {
+ // cppcheck false-positive
+ // cppcheck-suppress rethrowNoCurrentException
+ 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 * 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 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 : "", reinterpret_cast<void*>( logfunc ), loguser, reinterpret_cast<void*>( errfunc ), erruser, static_cast<void*>( impl ) );
+ fflush( stderr );
+ }
+ }
+}
+
+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 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 {
+
+template < typename T >
+void check_soundfile( T * mod ) {
+ if ( !mod ) {
+ throw openmpt::interface::invalid_module_pointer();
+ }
+}
+
+template < typename T >
+void check_pointer( T * p ) {
+ if ( !p ) {
+ throw openmpt::interface::argument_null_pointer();
+ }
+}
+
+} // namespace interface
+
+} // namespace openmpt
+
+extern "C" {
+
+uint32_t openmpt_get_library_version(void) {
+ try {
+ return openmpt::get_library_version();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return 0;
+}
+
+uint32_t openmpt_get_core_version(void) {
+ try {
+ return openmpt::get_core_version();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return 0;
+}
+
+void openmpt_free_string( const char * str ) {
+ try {
+ std::free( const_cast< char * >( str ) );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return;
+}
+
+const char * openmpt_get_string( const char * key ) {
+ try {
+ if ( !key ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( openmpt::string::get( key ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return NULL;
+}
+
+const char * openmpt_get_supported_extensions(void) {
+ try {
+ std::string retval;
+ bool first = true;
+ std::vector<std::string> supported_extensions = openmpt::module_impl::get_supported_extensions();
+ for ( std::vector<std::string>::iterator i = supported_extensions.begin(); i != supported_extensions.end(); ++i ) {
+ if ( first ) {
+ first = false;
+ } else {
+ retval += ";";
+ }
+ retval += *i;
+ }
+ return openmpt::strdup( retval.c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return NULL;
+}
+
+/// <summary>
+/// From version 0.7.0
+/// Hakan DANISIK
+/// </summary>
+/// <param name="extension"></param>
+/// <returns></returns>
+const char * openmpt_get_tracker_name( const char * extension ) {
+ try {
+ std::string retval;
+ if ( !extension ) {
+ return NULL;
+ }
+ retval = openmpt::module_impl::get_tracker_name( extension );
+ return openmpt::strdup( retval.c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return NULL;
+}
+
+int openmpt_is_extension_supported( const char * extension ) {
+ try {
+ if ( !extension ) {
+ return 0;
+ }
+ return openmpt::module_impl::is_extension_supported( extension ) ? 1 : 0;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__ );
+ }
+ return 0;
+}
+
+void openmpt_log_func_default( const char * message, void * /*user*/ ) {
+ fprintf( stderr, "openmpt: %s\n", message );
+ fflush( stderr );
+}
+
+void openmpt_log_func_silent( const char * /*message*/ , void * /*user*/ ) {
+ return;
+}
+
+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 = "unknown 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 };
+ 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( __func__, 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( __func__ );
+ }
+ 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( __func__, 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( __func__, 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( __func__, 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::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->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->impl = new openmpt::module_impl( istream, openmpt::helper::make_unique<openmpt::logfunc_logger>( mod->logfunc, mod->loguser ), ctls_map );
+ return mod;
+ } catch ( ... ) {
+ #if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod'.
+ #endif // _MSC_VER
+ openmpt::report_exception( __func__, mod, error, error_message );
+ #if defined(_MSC_VER)
+ #pragma warning(pop)
+ #endif // _MSC_VER
+ }
+ 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( __func__, 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::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->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->impl = new openmpt::module_impl( filedata, filesize, openmpt::helper::make_unique<openmpt::logfunc_logger>( mod->logfunc, mod->loguser ), ctls_map );
+ return mod;
+ } catch ( ... ) {
+ #if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod'.
+ #endif // _MSC_VER
+ openmpt::report_exception( __func__, mod, error, error_message );
+ #if defined(_MSC_VER)
+ #pragma warning(pop)
+ #endif // _MSC_VER
+ }
+ 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( __func__, 0, error, error_message );
+ }
+ return NULL;
+}
+
+void openmpt_module_destroy( openmpt_module * mod ) {
+ try {
+ 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;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, 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( __func__, 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( __func__, mod );
+ }
+ return;
+}
+
+int openmpt_module_error_get_last( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->error;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, 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( __func__, 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( __func__, 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( __func__, mod );
+ }
+ return;
+}
+
+int openmpt_module_select_subsong( openmpt_module * mod, int32_t subsong ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ mod->impl->select_subsong( subsong );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ 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( __func__, mod );
+ }
+ return -1;
+}
+
+int openmpt_module_set_repeat_count( openmpt_module * mod, int32_t repeat_count ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ mod->impl->set_repeat_count( repeat_count );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_repeat_count( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_repeat_count();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+double openmpt_module_get_duration_seconds( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_duration_seconds();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+
+double openmpt_module_set_position_seconds( openmpt_module * mod, double seconds ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->set_position_seconds( seconds );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+double openmpt_module_get_position_seconds( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_position_seconds();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+
+double openmpt_module_set_position_order_row( openmpt_module * mod, int32_t order, int32_t row ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->set_position_order_row( order, row );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+
+int openmpt_module_get_render_param( openmpt_module * mod, int param, int32_t * value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( value );
+ *value = mod->impl->get_render_param( (openmpt::module::render_param)param );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int openmpt_module_set_render_param( openmpt_module * mod, int param, int32_t value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ mod->impl->set_render_param( (openmpt::module::render_param)param, value );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+size_t openmpt_module_read_mono( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * mono ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read( samplerate, count, mono );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read( samplerate, count, left, right );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * left, int16_t * right, int16_t * rear_left, int16_t * rear_right ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read( samplerate, count, left, right, rear_left, rear_right );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_float_mono( openmpt_module * mod, int32_t samplerate, size_t count, float * mono ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read( samplerate, count, mono );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read( samplerate, count, left, right );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * left, float * right, float * rear_left, float * rear_right ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read( samplerate, count, left, right, rear_left, rear_right );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_interleaved_stereo( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_stereo ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read_interleaved_stereo( samplerate, count, interleaved_stereo );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_interleaved_quad( openmpt_module * mod, int32_t samplerate, size_t count, int16_t * interleaved_quad ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read_interleaved_quad( samplerate, count, interleaved_quad );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_interleaved_float_stereo( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_stereo ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read_interleaved_stereo( samplerate, count, interleaved_stereo );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+size_t openmpt_module_read_interleaved_float_quad( openmpt_module * mod, int32_t samplerate, size_t count, float * interleaved_quad ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->read_interleaved_quad( samplerate, count, interleaved_quad );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_get_metadata_keys( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::string retval;
+ bool first = true;
+ std::vector<std::string> metadata_keys = mod->impl->get_metadata_keys();
+ for ( std::vector<std::string>::iterator i = metadata_keys.begin(); i != metadata_keys.end(); ++i ) {
+ if ( first ) {
+ first = false;
+ } else {
+ retval += ";";
+ }
+ retval += *i;
+ }
+ return openmpt::strdup( retval.c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+const char * openmpt_module_get_metadata( openmpt_module * mod, const char * key ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( key );
+ return openmpt::strdup( mod->impl->get_metadata( key ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+
+double openmpt_module_get_current_estimated_bpm( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_estimated_bpm();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+int32_t openmpt_module_get_current_speed( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_speed();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_current_tempo( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_tempo();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_current_order( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_order();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_current_pattern( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_pattern();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_current_row( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_row();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_current_playing_channels( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_playing_channels();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+float openmpt_module_get_current_channel_vu_mono( openmpt_module * mod, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_channel_vu_mono( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+float openmpt_module_get_current_channel_vu_left( openmpt_module * mod, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_channel_vu_left( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+float openmpt_module_get_current_channel_vu_right( openmpt_module * mod, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_channel_vu_right( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+float openmpt_module_get_current_channel_vu_rear_left( openmpt_module * mod, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_channel_vu_rear_left( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+float openmpt_module_get_current_channel_vu_rear_right( openmpt_module * mod, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_current_channel_vu_rear_right( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+
+int32_t openmpt_module_get_num_subsongs( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_num_subsongs();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_num_channels( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_num_channels();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_num_orders( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_num_orders();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_num_patterns( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_num_patterns();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_num_instruments( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_num_instruments();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int32_t openmpt_module_get_num_samples( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_num_samples();
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_get_subsong_name( openmpt_module * mod, int32_t index ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::vector<std::string> names = mod->impl->get_subsong_names();
+ if ( names.size() >= (std::size_t)std::numeric_limits<int32_t>::max() ) {
+ throw std::runtime_error("too many names");
+ }
+ if ( index < 0 || index >= (int32_t)names.size() ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( names[index].c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+const char * openmpt_module_get_channel_name( openmpt_module * mod, int32_t index ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::vector<std::string> names = mod->impl->get_channel_names();
+ if ( names.size() >= (std::size_t)std::numeric_limits<int32_t>::max() ) {
+ throw std::runtime_error("too many names");
+ }
+ if ( index < 0 || index >= (int32_t)names.size() ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( names[index].c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+const char * openmpt_module_get_order_name( openmpt_module * mod, int32_t index ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::vector<std::string> names = mod->impl->get_order_names();
+ if ( names.size() >= (std::size_t)std::numeric_limits<int32_t>::max() ) {
+ throw std::runtime_error("too many names");
+ }
+ if ( index < 0 || index >= (int32_t)names.size() ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( names[index].c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+const char * openmpt_module_get_pattern_name( openmpt_module * mod, int32_t index ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::vector<std::string> names = mod->impl->get_pattern_names();
+ if ( names.size() >= (std::size_t)std::numeric_limits<int32_t>::max() ) {
+ throw std::runtime_error("too many names");
+ }
+ if ( index < 0 || index >= (int32_t)names.size() ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( names[index].c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+const char * openmpt_module_get_instrument_name( openmpt_module * mod, int32_t index ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::vector<std::string> names = mod->impl->get_instrument_names();
+ if ( names.size() >= (std::size_t)std::numeric_limits<int32_t>::max() ) {
+ throw std::runtime_error("too many names");
+ }
+ if ( index < 0 || index >= (int32_t)names.size() ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( names[index].c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+const char * openmpt_module_get_sample_name( openmpt_module * mod, int32_t index ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::vector<std::string> names = mod->impl->get_sample_names();
+ if ( names.size() >= (std::size_t)std::numeric_limits<int32_t>::max() ) {
+ throw std::runtime_error("too many names");
+ }
+ if ( index < 0 || index >= (int32_t)names.size() ) {
+ return openmpt::strdup( "" );
+ }
+ return openmpt::strdup( names[index].c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+
+int32_t openmpt_module_get_order_pattern( openmpt_module * mod, int32_t order ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_order_pattern( order );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+int32_t openmpt_module_get_pattern_num_rows( openmpt_module * mod, int32_t pattern ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_pattern_num_rows( pattern );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+uint8_t openmpt_module_get_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return mod->impl->get_pattern_row_channel_command( pattern, row, channel, command );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_format_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return openmpt::strdup( mod->impl->format_pattern_row_channel_command( pattern, row, channel, command ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_highlight_pattern_row_channel_command( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, int command ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return openmpt::strdup( mod->impl->highlight_pattern_row_channel_command( pattern, row, channel, command ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_format_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return openmpt::strdup( mod->impl->format_pattern_row_channel( pattern, row, channel, width, pad ? true : false ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_highlight_pattern_row_channel( openmpt_module * mod, int32_t pattern, int32_t row, int32_t channel, size_t width, int pad ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ return openmpt::strdup( mod->impl->highlight_pattern_row_channel( pattern, row, channel, width, pad ? true : false ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+
+const char * openmpt_module_get_ctls( openmpt_module * mod ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ std::string retval;
+ bool first = true;
+ std::vector<std::string> ctls = mod->impl->get_ctls();
+ for ( std::vector<std::string>::iterator i = ctls.begin(); i != ctls.end(); ++i ) {
+ if ( first ) {
+ first = false;
+ } else {
+ retval += ";";
+ }
+ retval += *i;
+ }
+ return openmpt::strdup( retval.c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+
+const char * openmpt_module_ctl_get( openmpt_module * mod, const char * ctl ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ return openmpt::strdup( mod->impl->ctl_get( ctl ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+int openmpt_module_ctl_get_boolean( openmpt_module * mod, const char * ctl ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ return mod->impl->ctl_get_boolean( ctl );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int64_t openmpt_module_ctl_get_integer( openmpt_module * mod, const char * ctl ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ return mod->impl->ctl_get_integer( ctl );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+double openmpt_module_ctl_get_floatingpoint( openmpt_module * mod, const char * ctl ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ return mod->impl->ctl_get_floatingpoint( ctl );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0.0;
+}
+const char * openmpt_module_ctl_get_text( openmpt_module * mod, const char * ctl ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ return openmpt::strdup( mod->impl->ctl_get_text( ctl ).c_str() );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return NULL;
+}
+
+int openmpt_module_ctl_set( openmpt_module * mod, const char * ctl, const char * value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ openmpt::interface::check_pointer( value );
+ mod->impl->ctl_set( ctl, value );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int openmpt_module_ctl_set_boolean( openmpt_module * mod, const char * ctl, int value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ mod->impl->ctl_set_boolean( ctl, value ? true : false );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int openmpt_module_ctl_set_integer( openmpt_module * mod, const char * ctl, int64_t value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ mod->impl->ctl_set_integer( ctl, value );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int openmpt_module_ctl_set_floatingpoint( openmpt_module * mod, const char * ctl, double value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ mod->impl->ctl_set_floatingpoint( ctl, value );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ return 0;
+}
+int openmpt_module_ctl_set_text( openmpt_module * mod, const char * ctl, const char * value ) {
+ try {
+ openmpt::interface::check_soundfile( mod );
+ openmpt::interface::check_pointer( ctl );
+ openmpt::interface::check_pointer( value );
+ mod->impl->ctl_set_text( ctl, value );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod );
+ }
+ 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( __func__, mod, error, error_message );
+ }
+ #if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod_ext'.
+ #endif // _MSC_VER
+ delete mod_ext->impl;
+ #if defined(_MSC_VER)
+ #pragma warning(pop)
+ #endif // _MSC_VER
+ 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( __func__, 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( __func__, mod, error, error_message );
+ }
+ #if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable:6001) // false-positive: Using uninitialized memory 'mod_ext'.
+ #endif // _MSC_VER
+ delete mod_ext->impl;
+ #if defined(_MSC_VER)
+ #pragma warning(pop)
+ #endif // _MSC_VER
+ 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( __func__, 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( __func__, 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( __func__, 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( __func__, 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return -1;
+}
+
+
+
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0.0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0.0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0.0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0.0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return -1;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return -1;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return -1;
+}
+static 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( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+
+
+
+static int note_off( openmpt_module_ext * mod_ext, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod_ext );
+ mod_ext->impl->note_off(channel );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static int note_fade( openmpt_module_ext * mod_ext, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod_ext );
+ mod_ext->impl->note_fade(channel );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static int set_channel_panning( openmpt_module_ext * mod_ext, int32_t channel, double panning ) {
+ try {
+ openmpt::interface::check_soundfile( mod_ext );
+ mod_ext->impl->set_channel_panning( channel, panning );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static double get_channel_panning( openmpt_module_ext * mod_ext, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod_ext );
+ return mod_ext->impl->get_channel_panning( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0.0;
+}
+static int set_note_finetune( openmpt_module_ext * mod_ext, int32_t channel, double finetune ) {
+ try {
+ openmpt::interface::check_soundfile( mod_ext );
+ mod_ext->impl->set_note_finetune( channel, finetune );
+ return 1;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+static double get_note_finetune( openmpt_module_ext * mod_ext, int32_t channel ) {
+ try {
+ openmpt::interface::check_soundfile( mod_ext );
+ return mod_ext->impl->get_note_finetune( channel );
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0.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 ( !std::strcmp( interface_id, "" ) ) {
+ result = 0;
+
+
+
+ } else if ( !std::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 ( !std::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;
+
+
+
+ } else if ( !std::strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive2 ) ) ) {
+ openmpt_module_ext_interface_interactive2 * i = static_cast< openmpt_module_ext_interface_interactive2 * >( interface );
+ i->note_off = &note_off;
+ i->note_fade = &note_fade;
+ i->set_channel_panning = &set_channel_panning;
+ i->get_channel_panning = &get_channel_panning;
+ i->set_note_finetune = &set_note_finetune;
+ i->get_note_finetune = &get_note_finetune;
+ result = 1;
+
+
+
+/* add stuff here */
+
+
+
+ } else {
+ result = 0;
+ }
+ return result;
+ } catch ( ... ) {
+ openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL );
+ }
+ return 0;
+}
+
+} // extern "C"
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_config.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_config.h
new file mode 100644
index 00000000..562cf20d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_config.h
@@ -0,0 +1,205 @@
+/*
+ * libopenmpt_config.h
+ * -------------------
+ * Purpose: libopenmpt public interface configuration
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_CONFIG_H
+#define LIBOPENMPT_CONFIG_H
+
+/* clang-format off */
+
+/*! \defgroup libopenmpt libopenmpt */
+
+/*! \addtogroup libopenmpt
+ @{
+*/
+
+/* provoke warnings if already defined */
+#define LIBOPENMPT_API
+#undef LIBOPENMPT_API
+#define LIBOPENMPT_CXX_API
+#undef LIBOPENMPT_CXX_API
+
+/*!
+ @}
+*/
+
+/*! \addtogroup libopenmpt_c
+ @{
+*/
+
+/*! \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
+
+/*!
+ @}
+*/
+
+/*! \addtogroup libopenmpt
+ @{
+*/
+
+#if defined(__DOXYGEN__)
+
+#define LIBOPENMPT_API_HELPER_EXPORT
+#define LIBOPENMPT_API_HELPER_IMPORT
+#define LIBOPENMPT_API_HELPER_PUBLIC
+#define LIBOPENMPT_API_HELPER_LOCAL
+
+#elif defined(_MSC_VER)
+
+#define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport)
+#define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport)
+#define LIBOPENMPT_API_HELPER_PUBLIC
+#define LIBOPENMPT_API_HELPER_LOCAL
+
+#elif defined(__EMSCRIPTEN__)
+
+#define LIBOPENMPT_API_HELPER_EXPORT __attribute__((visibility("default"))) __attribute__((used))
+#define LIBOPENMPT_API_HELPER_IMPORT __attribute__((visibility("default"))) __attribute__((used))
+#define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) __attribute__((used))
+#define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden")))
+
+#elif (defined(__GNUC__) || defined(__clang__)) && defined(_WIN32)
+
+#define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport)
+#define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport)
+#define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default")))
+#define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden")))
+
+#elif defined(__GNUC__) || defined(__clang__)
+
+#define LIBOPENMPT_API_HELPER_EXPORT __attribute__((visibility("default")))
+#define LIBOPENMPT_API_HELPER_IMPORT __attribute__((visibility("default")))
+#define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default")))
+#define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden")))
+
+#elif defined(_WIN32)
+
+#define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport)
+#define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport)
+#define LIBOPENMPT_API_HELPER_PUBLIC
+#define LIBOPENMPT_API_HELPER_LOCAL
+
+#else
+
+#define LIBOPENMPT_API_HELPER_EXPORT
+#define LIBOPENMPT_API_HELPER_IMPORT
+#define LIBOPENMPT_API_HELPER_PUBLIC
+#define LIBOPENMPT_API_HELPER_LOCAL
+
+#endif
+
+#if defined(LIBOPENMPT_BUILD_DLL)
+#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_EXPORT
+#elif defined(LIBOPENMPT_USE_DLL)
+#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_IMPORT
+#else
+#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_PUBLIC
+#endif
+
+#ifdef __cplusplus
+
+#define LIBOPENMPT_CXX_API LIBOPENMPT_API
+
+#if defined(LIBOPENMPT_USE_DLL)
+#if defined(_MSC_VER) && !defined(_DLL)
+#error "C++ interface is disabled if libopenmpt is built as a DLL and the runtime is statically linked. This is not supported by microsoft and cannot possibly work. Ever."
+#undef LIBOPENMPT_CXX_API
+#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL
+#endif
+#endif
+
+#if defined(__EMSCRIPTEN__)
+
+/* Only the C API is supported for emscripten. Disable the C++ API. */
+#undef LIBOPENMPT_CXX_API
+#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL
+#endif
+
+#endif
+
+/*!
+ @}
+*/
+
+
+/* C */
+
+#if !defined(LIBOPENMPT_NO_DEPRECATE)
+#if defined(__clang__)
+#define LIBOPENMPT_DEPRECATED __attribute__((deprecated))
+#elif defined(__GNUC__)
+#define LIBOPENMPT_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+#define LIBOPENMPT_DEPRECATED __declspec(deprecated)
+#else
+#define LIBOPENMPT_DEPRECATED
+#endif
+#else
+#define LIBOPENMPT_DEPRECATED
+#endif
+
+#ifndef __cplusplus
+#if !defined(LIBOPENMPT_NO_DEPRECATE)
+LIBOPENMPT_DEPRECATED static const int LIBOPENMPT_DEPRECATED_STRING_CONSTANT = 0;
+#define LIBOPENMPT_DEPRECATED_STRING( str ) ( LIBOPENMPT_DEPRECATED_STRING_CONSTANT ? ( str ) : ( str ) )
+#else
+#define LIBOPENMPT_DEPRECATED_STRING( str ) str
+#endif
+#else
+#define LIBOPENMPT_DEPRECATED_STRING( str ) str
+#endif
+
+
+/* C++ */
+
+#ifdef __cplusplus
+
+#if defined(LIBOPENMPT_ASSUME_CPLUSPLUS)
+#endif
+
+#if !defined(LIBOPENMPT_NO_DEPRECATE)
+#define LIBOPENMPT_ATTR_DEPRECATED [[deprecated]]
+#else
+#define LIBOPENMPT_ATTR_DEPRECATED
+#endif
+
+#endif
+
+
+/* clang-format on */
+
+#include "libopenmpt_version.h"
+
+#endif /* LIBOPENMPT_CONFIG_H */
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_cxx.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_cxx.cpp
new file mode 100644
index 00000000..7b743c37
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_cxx.cpp
@@ -0,0 +1,500 @@
+/*
+ * libopenmpt_cxx.cpp
+ * ------------------
+ * Purpose: libopenmpt C++ interface implementation
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#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_ ) noexcept
+ : std::exception()
+ , text(0)
+{
+ text = static_cast<char*>( std::malloc( text_.length() + 1 ) );
+ if ( text ) {
+ std::memcpy( text, text_.c_str(), text_.length() + 1 );
+ }
+}
+
+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 noexcept {
+ if ( text ) {
+ return text;
+ } else {
+ return "out of memory";
+ }
+}
+
+std::uint32_t get_library_version() {
+ return openmpt::version::get_library_version();
+}
+
+std::uint32_t get_core_version() {
+ return openmpt::version::get_core_version();
+}
+
+namespace string {
+
+std::string get( const std::string & key ) {
+ return openmpt::version::get_string( key );
+}
+
+} // namespace string
+
+} // namespace openmpt
+
+namespace openmpt {
+
+std::vector<std::string> get_supported_extensions() {
+ return openmpt::module_impl::get_supported_extensions();
+}
+
+bool is_extension_supported( const std::string & extension ) {
+ return openmpt::module_impl::is_extension_supported( extension );
+}
+bool is_extension_supported2( std::string_view 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 ) {
+ 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::byte * 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, 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::byte * data, std::size_t size ) {
+ return openmpt::module_impl::probe_file_header( flags, data, size );
+}
+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 & ) : impl(nullptr) {
+ throw exception("openmpt::module is non-copyable");
+}
+
+// cppcheck-suppress operatorEqVarError
+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;
+}
+
+void module::set_impl( module_impl * i ) {
+ impl = i;
+}
+
+module::module( std::istream & stream, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
+ impl = new module_impl( stream, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+}
+
+module::module( const std::vector<std::byte> & data, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
+ impl = new module_impl( data, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+}
+
+module::module( const std::byte * beg, const std::byte * end, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
+ impl = new module_impl( beg, end - beg, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+}
+
+module::module( const std::byte * data, std::size_t size, std::ostream & log, const std::map< std::string, std::string > & ctls ) : impl(0) {
+ impl = new module_impl( data, size, 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ impl = new module_impl( data, size, openmpt::helper::make_unique<std_ostream_log>( log ), ctls );
+}
+
+module::~module() {
+ delete impl;
+ impl = 0;
+}
+
+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 );
+}
+std::int32_t module::get_repeat_count() const {
+ return impl->get_repeat_count();
+}
+
+double module::get_duration_seconds() const {
+ return impl->get_duration_seconds();
+}
+
+double module::set_position_seconds( double seconds ) {
+ return impl->set_position_seconds( seconds );
+}
+double module::get_position_seconds() const {
+ return impl->get_position_seconds();
+}
+
+double module::set_position_order_row( std::int32_t order, std::int32_t row ) {
+ return impl->set_position_order_row( order, row );
+}
+
+std::int32_t module::get_render_param( int param ) const {
+ return impl->get_render_param( param );
+}
+void module::set_render_param( int param, std::int32_t value ) {
+ impl->set_render_param( param, value );
+}
+
+std::size_t module::read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ) {
+ return impl->read( samplerate, count, mono );
+}
+std::size_t module::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ) {
+ return impl->read( samplerate, count, left, right );
+}
+std::size_t module::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ) {
+ return impl->read( samplerate, count, left, right, rear_left, rear_right );
+}
+std::size_t module::read( std::int32_t samplerate, std::size_t count, float * mono ) {
+ return impl->read( samplerate, count, mono );
+}
+std::size_t module::read( std::int32_t samplerate, std::size_t count, float * left, float * right ) {
+ return impl->read( samplerate, count, left, right );
+}
+std::size_t module::read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ) {
+ return impl->read( samplerate, count, left, right, rear_left, rear_right );
+}
+std::size_t module::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ) {
+ return impl->read_interleaved_stereo( samplerate, count, interleaved_stereo );
+}
+std::size_t module::read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ) {
+ return impl->read_interleaved_quad( samplerate, count, interleaved_quad );
+}
+std::size_t module::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ) {
+ return impl->read_interleaved_stereo( samplerate, count, interleaved_stereo );
+}
+std::size_t module::read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ) {
+ return impl->read_interleaved_quad( samplerate, count, interleaved_quad );
+}
+
+std::vector<std::string> module::get_metadata_keys() const {
+ return impl->get_metadata_keys();
+}
+std::string module::get_metadata( const std::string & key ) const {
+ return impl->get_metadata( key );
+}
+
+double module::get_current_estimated_bpm() const {
+ return impl->get_current_estimated_bpm();
+}
+std::int32_t module::get_current_speed() const {
+ return impl->get_current_speed();
+}
+std::int32_t module::get_current_tempo() const {
+ return impl->get_current_tempo();
+}
+std::int32_t module::get_current_order() const {
+ return impl->get_current_order();
+}
+std::int32_t module::get_current_pattern() const {
+ return impl->get_current_pattern();
+}
+std::int32_t module::get_current_row() const {
+ return impl->get_current_row();
+}
+std::int32_t module::get_current_playing_channels() const {
+ return impl->get_current_playing_channels();
+}
+
+float module::get_current_channel_vu_mono( std::int32_t channel ) const {
+ return impl->get_current_channel_vu_mono( channel );
+}
+float module::get_current_channel_vu_left( std::int32_t channel ) const {
+ return impl->get_current_channel_vu_left( channel );
+}
+float module::get_current_channel_vu_right( std::int32_t channel ) const {
+ return impl->get_current_channel_vu_right( channel );
+}
+float module::get_current_channel_vu_rear_left( std::int32_t channel ) const {
+ return impl->get_current_channel_vu_rear_left( channel );
+}
+float module::get_current_channel_vu_rear_right( std::int32_t channel ) const {
+ return impl->get_current_channel_vu_rear_right( channel );
+}
+
+std::int32_t module::get_num_subsongs() const {
+ return impl->get_num_subsongs();
+}
+std::int32_t module::get_num_channels() const {
+ return impl->get_num_channels();
+}
+std::int32_t module::get_num_orders() const {
+ return impl->get_num_orders();
+}
+std::int32_t module::get_num_patterns() const {
+ return impl->get_num_patterns();
+}
+std::int32_t module::get_num_instruments() const {
+ return impl->get_num_instruments();
+}
+std::int32_t module::get_num_samples() const {
+ return impl->get_num_samples();
+}
+
+std::vector<std::string> module::get_subsong_names() const {
+ return impl->get_subsong_names();
+}
+std::vector<std::string> module::get_channel_names() const {
+ return impl->get_channel_names();
+}
+std::vector<std::string> module::get_order_names() const {
+ return impl->get_order_names();
+}
+std::vector<std::string> module::get_pattern_names() const {
+ return impl->get_pattern_names();
+}
+std::vector<std::string> module::get_instrument_names() const {
+ return impl->get_instrument_names();
+}
+std::vector<std::string> module::get_sample_names() const {
+ return impl->get_sample_names();
+}
+
+std::int32_t module::get_order_pattern( std::int32_t order ) const {
+ return impl->get_order_pattern( order );
+}
+std::int32_t module::get_pattern_num_rows( std::int32_t pattern ) const {
+ return impl->get_pattern_num_rows( pattern );
+}
+
+std::uint8_t module::get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const {
+ return impl->get_pattern_row_channel_command( pattern, row, channel, command );
+}
+
+std::string module::format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const {
+ return impl->format_pattern_row_channel_command( pattern, row, channel, command );
+}
+std::string module::highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const {
+ return impl->highlight_pattern_row_channel_command( pattern, row, channel, command );
+}
+
+std::string module::format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width, bool pad ) const {
+ return impl->format_pattern_row_channel( pattern, row, channel, width, pad );
+}
+std::string module::highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width, bool pad ) const {
+ return impl->highlight_pattern_row_channel( pattern, row, channel, width, pad );
+}
+
+std::vector<std::string> module::get_ctls() const {
+ return impl->get_ctls();
+}
+
+std::string module::ctl_get( const std::string & ctl ) const {
+ return impl->ctl_get( ctl );
+}
+bool module::ctl_get_boolean( std::string_view ctl ) const {
+ return impl->ctl_get_boolean( ctl );
+}
+std::int64_t module::ctl_get_integer( std::string_view ctl ) const {
+ return impl->ctl_get_integer( ctl );
+}
+double module::ctl_get_floatingpoint( std::string_view ctl ) const {
+ return impl->ctl_get_floatingpoint( ctl );
+}
+std::string module::ctl_get_text( std::string_view ctl ) const {
+ return impl->ctl_get_text( ctl );
+}
+
+void module::ctl_set( const std::string & ctl, const std::string & value ) {
+ impl->ctl_set( ctl, value );
+}
+void module::ctl_set_boolean( std::string_view ctl, bool value ) {
+ impl->ctl_set_boolean( ctl, value );
+}
+void module::ctl_set_integer( std::string_view ctl, std::int64_t value ) {
+ impl->ctl_set_integer( ctl, value );
+}
+void module::ctl_set_floatingpoint( std::string_view ctl, double value ) {
+ impl->ctl_set_floatingpoint( ctl, value );
+}
+void module::ctl_set_text( std::string_view ctl, std::string_view value ) {
+ impl->ctl_set_text( 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<std::uint8_t> & 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 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 std::vector<std::byte> & 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 std::uint8_t * 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 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 std::byte * 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), ext_impl(nullptr) {
+ throw std::runtime_error("openmpt::module_ext is non-copyable");
+}
+// cppcheck-suppress operatorEqVarError
+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
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.h
new file mode 100644
index 00000000..82f500f2
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.h
@@ -0,0 +1,405 @@
+/*
+ * 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
+
+/*!
+ * \page libopenmpt_ext_c_overview libopenmpt_ext C API
+ *
+ * libopenmpt_ext is included in all builds by default.
+ *
+ * \section libopenmpt-ext-c-detailed Detailed documentation
+ *
+ * \ref libopenmpt_ext_c
+ *
+ */
+
+/*! \defgroup libopenmpt_ext_c libopenmpt_ext C */
+
+/*! \addtogroup libopenmpt_ext_c
+ * @{
+ */
+
+/*! \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_ext 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
+ * \sa openmpt_module_ext_interface_interactive2::note_off
+ * \sa openmpt_module_ext_interface_interactive2::note_fade
+ */
+ 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. This is the value returned by a previous play_note call.
+ * \return 1 on success, 0 on failure (channel out of range).
+ * \sa openmpt_module_ext_interface_interactive::play_note
+ * \sa openmpt_module_ext_interface_interactive2::note_off
+ * \sa openmpt_module_ext_interface_interactive2::note_fade
+ */
+ int ( * stop_note ) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+} openmpt_module_ext_interface_interactive;
+
+
+
+#ifndef LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2
+#define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE2 "interactive2"
+#endif
+
+typedef struct openmpt_module_ext_interface_interactive2 {
+ //! Sends a key-off command for the note playing on the specified channel
+ /*!
+ * \param mod_ext The module handle to work on.
+ * \param channel The channel on which the key-off event should be triggered. This is the value returned by a previous play_note call.
+ * \return 1 on success, 0 on failure (channel out of range).
+ * \remarks This method releases envelopes and sample sustain loops. If the sample has no sustain loop, or if the module does not use instruments, it does nothing.
+ * \sa openmpt_module_ext_interface_interactive::play_note
+ * \sa openmpt_module_ext_interface_interactive::stop_note
+ * \sa openmpt_module_ext_interface_interactive2::note_fade
+ * \since 0.6.0
+ */
+ int ( *note_off ) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+ //! Sends a note fade command for 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 faded. This is the value returned by a previous play_note call.
+ * \return 1 on success, 0 on failure (channel out of range).
+ * \remarks This method uses the instrument's fade-out value. If the module does not use instruments, or the instrument's fade-out value is 0, it does nothing.
+ * \sa openmpt_module_ext_interface_interactive::play_note
+ * \sa openmpt_module_ext_interface_interactive::stop_note
+ * \sa openmpt_module_ext_interface_interactive2::note_fade
+ * \since 0.6.0
+ */
+ int ( *note_fade ) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+ //! Set the current panning for a channel
+ /*!
+ * \param mod_ext The module handle to work on.
+ * \param channel The channel that should be panned. This is the value returned by a previous play_note call.
+ * \param panning The panning position to set on the channel, in range [-1.0, 1.0], 0.0 is center.
+ * \return 1 on success, 0 on failure (channel out of range).
+ * \remarks This command affects subsequent notes played on the same channel, and may itself be overridden by subsequent panning commands encountered in the module itself.
+ * \sa openmpt_module_ext_interface_interactive2::get_channel_panning
+ * \since 0.6.0
+ */
+ int ( *set_channel_panning) ( openmpt_module_ext * mod_ext, int32_t channel, double panning );
+
+ //! Get the current panning position for a channel
+ /*!
+ * \param mod_ext The module handle to work on.
+ * \param channel The channel whose panning should be retrieved. This is the value returned by a previous play_note call.
+ * \return The current channel panning, in range [-1.0, 1.0], 0.0 is center.
+ * \sa openmpt_module_ext_interface_interactive2::set_channel_panning
+ * \since 0.6.0
+ */
+ double (*get_channel_panning) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+ //! Set the finetune for the currently playing note on a channel
+ /*!
+ * \param mod_ext The module handle to work on.
+ * \param channel The channel whose finetune will be changed, in range [0, openmpt::module::get_num_channels()[
+ * \param finetune The finetune to set on the channel, in range [-1.0, 1.0], 0.0 is center.
+ * \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ * \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone.
+ * \remarks This command does not affect subsequent notes played on the same channel, but may itself be overridden by subsequent finetune commands encountered in the module itself.
+ * \sa openmpt_module_ext_interface_interactive2::get_note_finetune
+ * \since 0.6.0
+ */
+ int ( *set_note_finetune) ( openmpt_module_ext * mod_ext, int32_t channel, double finetune );
+
+ //! Get the finetune for the currently playing note on a channel
+ /*!
+ * \param mod_ext The module handle to work on.
+ * \param channel The channel whose finetune should be retrieved, in range [0, openmpt::module::get_num_channels()[
+ * \return The current channel finetune, in range [-1.0, 1.0], 0.0 is center.
+ * \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone.
+ * \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ * \sa openmpt_module_ext_interface_interactive2::set_note_finetune
+ * \since 0.6.0
+ */
+ double (*get_note_finetune) ( openmpt_module_ext * mod_ext, int32_t channel );
+
+} openmpt_module_ext_interface_interactive2;
+
+
+
+/* add stuff here */
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* LIBOPENMPT_EXT_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.hpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.hpp
new file mode 100644
index 00000000..85577d95
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext.hpp
@@ -0,0 +1,404 @@
+/*
+ * libopenmpt_ext.hpp
+ * ------------------
+ * 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_HPP
+#define LIBOPENMPT_EXT_HPP
+
+#include "libopenmpt_config.h"
+#include "libopenmpt.hpp"
+
+/*!
+ * \page libopenmpt_ext_cpp_overview libopenmpt_ext C++ API
+ *
+ * libopenmpt_ext is now included in all builds by default.
+ *
+ * \section libopenmpt-ext-cpp-detailed Detailed documentation
+ *
+ * \ref libopenmpt_ext_cpp
+ *
+ */
+
+/*! \defgroup libopenmpt_ext_cpp libopenmpt_ext C++ */
+
+namespace openmpt {
+
+/*! \addtogroup libopenmpt_ext_cpp
+ @{
+*/
+
+class module_ext_impl;
+
+class LIBOPENMPT_CXX_API module_ext : public module {
+
+private:
+ module_ext_impl * ext_impl;
+private:
+ // non-copyable
+ module_ext( const module_ext & );
+ void operator = ( const module_ext & );
+public:
+ module_ext( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const std::vector<std::byte> & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const std::vector<std::uint8_t> & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const std::vector<char> & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ module_ext( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() );
+ virtual ~module_ext();
+
+public:
+
+ //! Retrieve a libopenmpt extension.
+ /*! Example: Retrieving the interactive extension to change the tempo of a module:
+ \code{.cpp}
+ openmpt::module_ext *mod = new openmpt::module_ext( stream );
+ #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.
+ */
+ void * get_interface( const std::string & interface_id );
+
+}; // class module_ext
+
+/*!
+ @}
+*/
+
+namespace ext {
+
+/*! \addtogroup libopenmpt_ext_cpp
+ @{
+*/
+
+#define LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(name) \
+ static const char name ## _id [] = # name ; \
+ class name; \
+/**/
+
+#define LIBOPENMPT_EXT_CXX_INTERFACE(name) \
+ protected: \
+ name () {} \
+ virtual ~ name () {} \
+ public: \
+/**/
+
+
+#ifndef LIBOPENMPT_EXT_INTERFACE_PATTERN_VIS
+#define LIBOPENMPT_EXT_INTERFACE_PATTERN_VIS
+#endif
+
+LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(pattern_vis)
+
+class pattern_vis {
+
+ LIBOPENMPT_EXT_CXX_INTERFACE(pattern_vis)
+
+ //! Pattern command type
+ enum effect_type {
+
+ effect_unknown = 0,
+ effect_general = 1,
+ effect_global = 2,
+ effect_volume = 3,
+ effect_panning = 4,
+ effect_pitch = 5
+
+ }; // enum effect_type
+
+ //! Get pattern command type for pattern highlighting
+ /*!
+ \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::ext::pattern_vis::effect_type)
+ \sa openmpt::ext::pattern_vis::get_pattern_row_channel_effect_type
+ */
+ virtual effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const = 0;
+
+ //! Get pattern command type for pattern highlighting
+ /*!
+ \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 volume column at the given pattern position (see openmpt::ext::pattern_vis::effect_type)
+ \sa openmpt::ext::pattern_vis::get_pattern_row_channel_volume_effect_type
+ */
+ virtual effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const = 0;
+
+}; // class pattern_vis
+
+
+#ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE
+#define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE
+#endif
+
+LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive)
+
+class interactive {
+
+ LIBOPENMPT_EXT_CXX_INTERFACE(interactive)
+
+ //! Set the current ticks per row (speed)
+ /*!
+ \param speed The new tick count in range [1, 65535].
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the speed is outside the specified range.
+ \remarks The tick count may be reset by pattern commands at any time.
+ \sa openmpt::module::get_current_speed
+ */
+ virtual void set_current_speed( std::int32_t speed ) = 0;
+
+ //! Set the current module tempo
+ /*!
+ \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the tempo is outside the specified range.
+ \remarks The tempo may be reset by pattern commands at any time. Use openmpt::ext:interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands.
+ \sa openmpt::module::get_current_tempo
+ */
+ virtual void set_current_tempo( std::int32_t tempo ) = 0;
+
+ //! Set the current module tempo factor without affecting playback pitch
+ /*!
+ \param factor The new tempo factor in range ]0.0, 4.0] - 1.0 means unmodified tempo.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the factor is outside the specified range.
+ \remarks Modifying the tempo without applying the same pitch factor using openmpt::ext::interactive::set_pitch_factor may cause rhythmic samples (e.g. drum loops) to go out of sync.
+ \sa openmpt::ext::interactive::get_tempo_factor
+ */
+ virtual void set_tempo_factor( double factor ) = 0;
+
+ //! Gets the current module tempo factor
+ /*!
+ \return The current tempo factor.
+ \sa openmpt::ext::interactive::set_tempo_factor
+ */
+ virtual double get_tempo_factor( ) const = 0;
+
+ //! Set the current module pitch factor without affecting playback speed
+ /*!
+ \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 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
+ */
+ virtual void set_pitch_factor( double factor ) = 0;
+
+ //! Gets the current module pitch factor
+ /*!
+ \return The current pitch factor.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the pitch is outside the specified range.
+ \sa openmpt::ext::interactive::set_pitch_factor
+ */
+ virtual double get_pitch_factor( ) const = 0;
+
+ //! Set the current global volume
+ /*!
+ \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.
+ \sa openmpt::ext::interactive::get_global_volume
+ */
+ virtual void set_global_volume( double volume ) = 0;
+
+ //! Get the current global volume
+ /*!
+ \return The current global volume in range [0.0, 1.0]
+ \sa openmpt::ext::interactive::set_global_volume
+ */
+ virtual double get_global_volume( ) const = 0;
+
+ //! Set the current channel volume for a channel
+ /*!
+ \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]
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel or volume is outside the specified range.
+ \remarks The channel volume may be reset by pattern commands at any time.
+ \sa openmpt::ext::interactive::get_channel_volume
+ */
+ virtual void set_channel_volume( std::int32_t channel, double volume ) = 0;
+
+ //! Get the current channel volume for a channel
+ /*!
+ \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]
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ \sa openmpt::ext::interactive::set_channel_volume
+ */
+ virtual double get_channel_volume( std::int32_t channel ) const = 0;
+
+ //! Set the current mute status for a channel
+ /*!
+ \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.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ \sa openmpt::ext::interactive::get_channel_mute_status
+ */
+ virtual void set_channel_mute_status( std::int32_t channel, bool mute ) = 0;
+
+ //! Get the current mute status for a channel
+ /*!
+ \param channel The channel whose mute status should be retrieved, in range [0, openmpt::module::get_num_channels()[
+ \return The current channel mute status. true is muted, false is unmuted.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ \sa openmpt::ext::interactive::set_channel_mute_status
+ */
+ virtual bool get_channel_mute_status( std::int32_t channel ) const = 0;
+
+ //! Set the current mute status for an instrument
+ /*!
+ \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.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the instrument is outside the specified range.
+ \sa openmpt::ext::interactive::get_instrument_mute_status
+ */
+ virtual void set_instrument_mute_status( std::int32_t instrument, bool mute ) = 0;
+
+ //! 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 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
+ */
+ virtual bool get_instrument_mute_status( std::int32_t instrument ) const = 0;
+
+ //! Play a note using the specified instrument
+ /*!
+ \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::ext::interactive::stop_note to stop the note.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the instrument or note is outside the specified range.
+ \sa openmpt::ext::interactive::stop_note
+ \sa openmpt::ext::interactive2::note_off
+ \sa openmpt::ext::interactive2::note_fade
+ */
+ virtual std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) = 0;
+
+ //! Stop the note playing on the specified channel
+ /*!
+ \param channel The channel on which the note should be stopped. This is the value returned by a previous play_note call.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ \sa openmpt::ext::interactive::play_note
+ \sa openmpt::ext::interactive2::note_off
+ \sa openmpt::ext::interactive2::note_fade
+ */
+ virtual void stop_note( std::int32_t channel ) = 0;
+
+}; // class interactive
+
+
+#ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE2
+#define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE2
+#endif
+
+LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive2)
+
+class interactive2 {
+
+ LIBOPENMPT_EXT_CXX_INTERFACE(interactive2)
+
+ //! Sends a key-off command for the note playing on the specified channel
+ /*!
+ \param channel The channel on which the key-off event should be triggered. This is the value returned by a previous play_note call.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ \remarks This method releases envelopes and sample sustain loops. If the sample has no sustain loop, or if the module does not use instruments, it does nothing.
+ \sa openmpt::ext::interactive::play_note
+ \sa openmpt::ext::interactive::stop_note
+ \sa openmpt::ext::interactive2::note_fade
+ \since 0.6.0
+ */
+ virtual void note_off(int32_t channel ) = 0;
+
+ //! Sends a note fade command for the note playing on the specified channel
+ /*!
+ \param channel The channel on which the note should be faded. This is the value returned by a previous play_note call.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ \remarks This method uses the instrument's fade-out value. If the module does not use instruments, or the instrument's fade-out value is 0, it does nothing.
+ \sa openmpt::ext::interactive::play_note
+ \sa openmpt::ext::interactive::stop_note
+ \sa openmpt::ext::interactive2::note_off
+ \since 0.6.0
+ */
+ virtual void note_fade(int32_t channel) = 0;
+
+ //! Set the current panning position for a channel
+ /*!
+ \param channel The channel whose panning will be changed, in range [0, openmpt::module::get_num_channels()[
+ \param panning The panning position to set on the channel, in range [-1.0, 1.0], 0.0 is center.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ \remarks This command affects subsequent notes played on the same channel, and may itself be overridden by subsequent panning commands encountered in the module itself.
+ \sa openmpt::ext::interactive2::get_channel_panning
+ \since 0.6.0
+ */
+ virtual void set_channel_panning(int32_t channel, double panning ) = 0;
+
+ //! Get the current panning position for a channel
+ /*!
+ \param channel The channel whose panning should be retrieved, in range [0, openmpt::module::get_num_channels()[
+ \return The current channel panning, in range [-1.0, 1.0], 0.0 is center.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ \sa openmpt::ext::interactive2::set_channel_panning
+ \since 0.6.0
+ */
+ virtual double get_channel_panning( int32_t channel ) = 0;
+
+ //! Set the finetune for the currently playing note on a channel
+ /*!
+ \param channel The channel whose finetune will be changed, in range [0, openmpt::module::get_num_channels()[
+ \param finetune The finetune to set on the channel, in range [-1.0, 1.0], 0.0 is center.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel index is invalid.
+ \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone.
+ \remarks This command does not affect subsequent notes played on the same channel, but may itself be overridden by subsequent finetune commands encountered in the module itself.
+ \sa openmpt::ext::interactive2::get_note_finetune
+ \since 0.6.0
+ */
+ virtual void set_note_finetune(int32_t channel, double finetune ) = 0;
+
+ //! Get the finetune for the currently playing note on a channel
+ /*!
+ \param channel The channel whose finetune should be retrieved, in range [0, openmpt::module::get_num_channels()[
+ \return The current channel finetune, in range [-1.0, 1.0], 0.0 is center.
+ \throws openmpt::exception Throws an exception derived from openmpt::exception if the channel is outside the specified range.
+ \remarks The finetune range depends on the pitch wheel depth of the instrument playing on the current channel; for sample-based modules, the depth of this command is fixed to +/-1 semitone.
+ \sa openmpt::ext::interactive2::set_note_finetune
+ \since 0.6.0
+ */
+ virtual double get_note_finetune( int32_t channel ) = 0;
+
+}; // class interactive
+
+
+/* add stuff here */
+
+
+
+#undef LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE
+#undef LIBOPENMPT_EXT_CXX_INTERFACE
+
+/*!
+ @}
+*/
+
+} // namespace ext
+
+} // namespace openmpt
+
+#endif // LIBOPENMPT_EXT_HPP
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.cpp
new file mode 100644
index 00000000..1de804bb
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.cpp
@@ -0,0 +1,352 @@
+/*
+ * 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"
+
+#include "libopenmpt_internal.h"
+#include "libopenmpt_ext.hpp"
+
+#include "libopenmpt_ext_impl.hpp"
+
+#include "mpt/base/saturate_round.hpp"
+
+#include "soundlib/Sndfile.h"
+
+// assume OPENMPT_NAMESPACE is OpenMPT
+
+namespace openmpt {
+
+ 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();
+ }
+ 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();
+ }
+ module_ext_impl::module_ext_impl( const std::vector<std::byte> & 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::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();
+ }
+ 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::byte * 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 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();
+ }
+
+
+
+ void module_ext_impl::ctor() {
+
+
+
+ /* add stuff here */
+
+
+
+ }
+
+
+
+ module_ext_impl::~module_ext_impl() {
+
+
+
+ /* add stuff here */
+
+
+
+ }
+
+
+
+ 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 ) {
+ return dynamic_cast< ext::pattern_vis * >( this );
+ } else if ( interface_id == ext::interactive_id ) {
+ return dynamic_cast< ext::interactive * >( this );
+ } else if ( interface_id == ext::interactive2_id ) {
+ return dynamic_cast< ext::interactive2 * >( this );
+
+
+
+ /* add stuff here */
+
+
+
+ } else {
+ return 0;
+ }
+ }
+
+ // pattern_vis
+
+ 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 ( OpenMPT::ModCommand::GetVolumeEffectType( byte ) ) {
+ case OpenMPT::EFFECT_TYPE_NORMAL : return effect_general; break;
+ case OpenMPT::EFFECT_TYPE_GLOBAL : return effect_global ; break;
+ case OpenMPT::EFFECT_TYPE_VOLUME : return effect_volume ; break;
+ case OpenMPT::EFFECT_TYPE_PANNING: return effect_panning; break;
+ case OpenMPT::EFFECT_TYPE_PITCH : return effect_pitch ; break;
+ default: return effect_unknown; break;
+ }
+ }
+
+ 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 (OpenMPT::ModCommand::GetEffectType( byte ) ) {
+ case OpenMPT::EFFECT_TYPE_NORMAL : return effect_general; break;
+ case OpenMPT::EFFECT_TYPE_GLOBAL : return effect_global ; break;
+ case OpenMPT::EFFECT_TYPE_VOLUME : return effect_volume ; break;
+ case OpenMPT::EFFECT_TYPE_PANNING: return effect_panning; break;
+ case OpenMPT::EFFECT_TYPE_PITCH : return effect_pitch ; break;
+ default: return effect_unknown; break;
+ }
+ }
+
+ // interactive
+
+ 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;
+ }
+
+ 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 );
+ }
+
+ void module_ext_impl::set_tempo_factor( double factor ) {
+ if ( factor <= 0.0 || factor > 4.0 ) {
+ throw openmpt::exception("invalid tempo factor");
+ }
+ m_sndFile->m_nTempoFactor = mpt::saturate_round<uint32_t>( 65536.0 / factor );
+ m_sndFile->RecalculateSamplesPerTick();
+ }
+
+ double module_ext_impl::get_tempo_factor( ) const {
+ return 65536.0 / m_sndFile->m_nTempoFactor;
+ }
+
+ void module_ext_impl::set_pitch_factor( double factor ) {
+ if ( factor <= 0.0 || factor > 4.0 ) {
+ throw openmpt::exception("invalid pitch factor");
+ }
+ m_sndFile->m_nFreqFactor = mpt::saturate_round<uint32_t>( 65536.0 * factor );
+ m_sndFile->RecalculateSamplesPerTick();
+ }
+
+ double module_ext_impl::get_pitch_factor( ) const {
+ return m_sndFile->m_nFreqFactor / 65536.0;
+ }
+
+ 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 = mpt::saturate_round<uint32_t>( volume * MAX_GLOBAL_VOLUME );
+ }
+
+ double module_ext_impl::get_global_volume( ) const {
+ return m_sndFile->m_PlayState.m_nGlobalVolume / static_cast<double>( MAX_GLOBAL_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");
+ }
+ if ( volume < 0.0 || volume > 1.0 ) {
+ throw openmpt::exception("invalid global volume");
+ }
+ m_sndFile->m_PlayState.Chn[channel].nGlobalVol = mpt::saturate_round<std::int32_t>(volume * 64.0);
+ }
+
+ 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;
+ }
+
+ 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");
+ }
+ m_sndFile->ChnSettings[channel].dwFlags.set( OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE , mute );
+ m_sndFile->m_PlayState.Chn[channel].dwFlags.set( OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE , mute );
+
+ // Also update NNA channels
+ for ( OpenMPT::CHANNELINDEX i = m_sndFile->GetNumChannels(); i < OpenMPT::MAX_CHANNELS; i++)
+ {
+ if ( m_sndFile->m_PlayState.Chn[i].nMasterChn == channel + 1)
+ {
+ m_sndFile->m_PlayState.Chn[i].dwFlags.set( OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE, mute );
+ }
+ }
+ }
+
+ 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[OpenMPT::CHN_MUTE | OpenMPT::CHN_SYNCMUTE];
+ }
+
+ void module_ext_impl::set_instrument_mute_status( std::int32_t instrument, bool mute ) {
+ const bool instrument_mode = get_num_instruments() != 0;
+ const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
+ if ( instrument < 0 || instrument >= max_instrument ) {
+ throw openmpt::exception("invalid instrument");
+ }
+ if ( instrument_mode ) {
+ if ( m_sndFile->Instruments[instrument + 1] != nullptr ) {
+ m_sndFile->Instruments[instrument + 1]->dwFlags.set( OpenMPT::INS_MUTE, mute );
+ }
+ } else {
+ m_sndFile->GetSample( static_cast<OpenMPT::SAMPLEINDEX>( instrument + 1 ) ).uFlags.set( OpenMPT::CHN_MUTE, mute ) ;
+ }
+ }
+
+ bool module_ext_impl::get_instrument_mute_status( std::int32_t instrument ) const {
+ const bool instrument_mode = get_num_instruments() != 0;
+ const std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
+ if ( instrument < 0 || instrument >= max_instrument ) {
+ throw openmpt::exception("invalid instrument");
+ }
+ if ( instrument_mode ) {
+ if ( m_sndFile->Instruments[instrument + 1] != nullptr ) {
+ return m_sndFile->Instruments[instrument + 1]->dwFlags[OpenMPT::INS_MUTE];
+ }
+ return true;
+ } else {
+ return m_sndFile->GetSample( static_cast<OpenMPT::SAMPLEINDEX>( instrument + 1 ) ).uFlags[OpenMPT::CHN_MUTE];
+ }
+ }
+
+ 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 std::int32_t max_instrument = instrument_mode ? get_num_instruments() : get_num_samples();
+ if ( instrument < 0 || instrument >= max_instrument ) {
+ throw openmpt::exception("invalid instrument");
+ }
+ note += OpenMPT::NOTE_MIN;
+ if ( note < OpenMPT::NOTE_MIN || note > OpenMPT::NOTE_MAX ) {
+ throw openmpt::exception("invalid note");
+ }
+
+ // Find a free channel
+ OpenMPT::CHANNELINDEX free_channel = m_sndFile->GetNNAChannel( OpenMPT::CHANNELINDEX_INVALID );
+ if ( free_channel == OpenMPT::CHANNELINDEX_INVALID ) {
+ free_channel = OpenMPT::MAX_CHANNELS - 1;
+ }
+
+ OpenMPT::ModChannel &chn = m_sndFile->m_PlayState.Chn[free_channel];
+ chn.Reset( OpenMPT::ModChannel::resetTotal, *m_sndFile, OpenMPT::CHANNELINDEX_INVALID, OpenMPT::CHN_MUTE );
+ chn.nMasterChn = 0; // remove NNA association
+ chn.nNewNote = chn.nLastNote = static_cast<std::uint8_t>(note);
+ chn.ResetEnvelopes();
+ m_sndFile->InstrumentChange(chn, instrument + 1);
+ chn.nFadeOutVol = 0x10000;
+ m_sndFile->NoteChange(chn, note, false, true, true);
+ chn.nPan = mpt::saturate_round<std::int32_t>( OpenMPT::Clamp( panning * 128.0, -128.0, 128.0 ) + 128.0 );
+ chn.nVolume = mpt::saturate_round<std::int32_t>( OpenMPT::Clamp( volume * 256.0, 0.0, 256.0 ) );
+
+ // Remove channel from list of mixed channels to fix https://bugs.openmpt.org/view.php?id=209
+ // This is required because a previous note on the same channel might have just stopped playing,
+ // but the channel is still in the mix list.
+ // Since the channel volume / etc is only updated every tick in CSoundFile::ReadNote, and we
+ // do not want to duplicate mixmode-dependant logic here, CSoundFile::CreateStereoMix may already
+ // try to mix our newly set up channel at volume 0 if we don't remove it from the list.
+ auto mix_begin = std::begin( m_sndFile->m_PlayState.ChnMix );
+ auto mix_end = std::remove( mix_begin, mix_begin + m_sndFile->m_nMixChannels, free_channel );
+ m_sndFile->m_nMixChannels = static_cast<OpenMPT::CHANNELINDEX>( std::distance( mix_begin, mix_end ) );
+
+ return free_channel;
+ }
+
+ void module_ext_impl::stop_note( std::int32_t channel ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception("invalid channel");
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ chn.nLength = 0;
+ chn.pCurrentSample = nullptr;
+ }
+
+ void module_ext_impl::note_off(int32_t channel ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception( "invalid channel" );
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ chn.dwFlags |= OpenMPT::CHN_KEYOFF;
+ }
+
+ void module_ext_impl::note_fade(int32_t channel ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception( "invalid channel" );
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ chn.dwFlags |= OpenMPT::CHN_NOTEFADE;
+ }
+
+ void module_ext_impl::set_channel_panning( int32_t channel, double panning ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception( "invalid channel" );
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ chn.nPan = mpt::saturate_round<int32_t>( std::clamp( panning, -1.0, 1.0 ) * 128.0 + 128.0 );
+ }
+
+ double module_ext_impl::get_channel_panning( int32_t channel ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception( "invalid channel" );
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ return ( chn.nPan - 128 ) / 128.0;
+ }
+
+ void module_ext_impl::set_note_finetune( int32_t channel, double finetune ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception( "invalid channel" );
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ chn.microTuning = mpt::saturate_round<int16_t>( finetune * 32768.0 );
+ }
+
+ double module_ext_impl::get_note_finetune( int32_t channel ) {
+ if ( channel < 0 || channel >= OpenMPT::MAX_CHANNELS ) {
+ throw openmpt::exception( "invalid channel" );
+ }
+ auto & chn = m_sndFile->m_PlayState.Chn[channel];
+ return chn.microTuning / 32768.0;
+ }
+
+ /* add stuff here */
+
+
+
+} // namespace openmpt
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.hpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.hpp
new file mode 100644
index 00000000..afc6520b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_ext_impl.hpp
@@ -0,0 +1,122 @@
+/*
+ * 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"
+
+namespace openmpt {
+
+class module_ext_impl
+ : public module_impl
+ , public ext::pattern_vis
+ , public ext::interactive
+ , public ext::interactive2
+
+
+
+ /* 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::byte> & data, 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::byte * data, std::size_t size, 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
+
+ effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const override;
+
+ effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const override;
+
+ // interactive
+
+ void set_current_speed( std::int32_t speed ) override;
+
+ void set_current_tempo( std::int32_t tempo ) override;
+
+ void set_tempo_factor( double factor ) override;
+
+ double get_tempo_factor( ) const override;
+
+ void set_pitch_factor( double factor ) override;
+
+ double get_pitch_factor( ) const override;
+
+ void set_global_volume( double volume ) override;
+
+ double get_global_volume( ) const override;
+
+ void set_channel_volume( std::int32_t channel, double volume ) override;
+
+ double get_channel_volume( std::int32_t channel ) const override;
+
+ void set_channel_mute_status( std::int32_t channel, bool mute ) override;
+
+ bool get_channel_mute_status( std::int32_t channel ) const override;
+
+ void set_instrument_mute_status( std::int32_t instrument, bool mute ) override;
+
+ bool get_instrument_mute_status( std::int32_t instrument ) const override;
+
+ std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) override;
+
+ void stop_note( std::int32_t channel ) override;
+
+ void note_off( std::int32_t channel ) override;
+
+ void note_fade( std::int32_t channel ) override;
+
+ void set_channel_panning( std::int32_t channel, double panning ) override;
+
+ double get_channel_panning( std::int32_t channel ) override;
+
+ void set_note_finetune( std::int32_t channel, double finetune ) override;
+
+ double get_note_finetune( std::int32_t channel ) override;
+
+ /* add stuff here */
+
+}; // class module_ext_impl
+
+} // namespace openmpt
+
+#endif // LIBOPENMPT_EXT_IMPL_HPP
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.cpp
new file mode 100644
index 00000000..332164c5
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.cpp
@@ -0,0 +1,2162 @@
+/*
+ * libopenmpt_impl.cpp
+ * -------------------
+ * Purpose: libopenmpt private interface implementation
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#include "common/stdafx.h"
+
+#include "libopenmpt_internal.h"
+#include "libopenmpt.hpp"
+
+#include "libopenmpt_impl.hpp"
+
+#include <algorithm>
+#include <iostream>
+#include <istream>
+#include <iterator>
+#include <limits>
+#include <ostream>
+
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+
+#include "mpt/audio/span.hpp"
+#include "mpt/base/algorithm.hpp"
+#include "mpt/base/saturate_cast.hpp"
+#include "mpt/base/saturate_round.hpp"
+#include "mpt/format/default_integer.hpp"
+#include "mpt/format/default_floatingpoint.hpp"
+#include "mpt/format/default_string.hpp"
+#include "mpt/io_read/callbackstream.hpp"
+#include "mpt/io_read/filecursor_callbackstream.hpp"
+#include "mpt/io_read/filecursor_memory.hpp"
+#include "mpt/io_read/filecursor_stdstream.hpp"
+#include "mpt/mutex/mutex.hpp"
+#include "mpt/parse/parse.hpp"
+#include "mpt/string/types.hpp"
+#include "mpt/string/utility.hpp"
+#include "mpt/string_transcode/transcode.hpp"
+
+#include "common/version.h"
+#include "common/misc_util.h"
+#include "common/Dither.h"
+#include "common/FileReader.h"
+#include "common/Logging.h"
+#include "soundlib/Sndfile.h"
+#include "soundlib/mod_specifications.h"
+#include "soundlib/AudioReadTarget.h"
+
+#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+#include <windows.h>
+#endif // MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+
+OPENMPT_NAMESPACE_BEGIN
+
+#if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS)
+
+#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+#if defined(NTDDI_VERSION)
+#if (NTDDI_VERSION < 0x06020000)
+MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define NTDDI_VERSION 0x0602000.")
+#endif
+#elif defined(_WIN32_WINNT)
+#if (_WIN32_WINNT < 0x0602)
+MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define _WIN32_WINNT 0x0602.")
+#endif // _WIN32_WINNT
+#endif // _WIN32_WINNT
+#endif // MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
+
+#if defined(MPT_BUILD_MSVC) || defined(MPT_BUILD_VCPKG)
+#if MPT_OS_WINDOWS_WINRT
+#pragma comment(lib, "ole32.lib")
+#else
+#pragma comment(lib, "rpcrt4.lib")
+#endif
+#endif // MPT_BUILD_MSVC
+
+#if MPT_PLATFORM_MULTITHREADED && MPT_MUTEX_NONE
+MPT_WARNING("Warning: libopenmpt built in non thread-safe mode because mutexes are not supported by the C++ standard library available.")
+#endif // MPT_MUTEX_NONE
+
+#if (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS)
+#if defined(MPT_WITH_MINGWSTDTHREADS)
+MPT_WARNING("Warning: Building with mingw-std-threads is deprecated because this is not supported with GCC 11 or later.")
+#else // !MINGWSTDTHREADS
+MPT_WARNING("Warning: Platform (Windows) supports multi-threading, however the toolchain (MinGW/GCC) does not. The resulting libopenmpt may not be thread-safe. This is a MinGW/GCC issue. You can avoid this warning by using a MinGW toolchain built with posix threading model as opposed to win32 threading model.")
+#endif // MINGWSTDTHREADS
+#endif // MINGW
+
+#if MPT_CLANG_AT_LEAST(5,0,0) && MPT_CLANG_BEFORE(11,0,0) && defined(__powerpc__) && !defined(__powerpc64__)
+MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Clang 5..10 on powerpc (32bit) when using -O3. See <https://bugs.llvm.org/show_bug.cgi?id=46683>.")
+#endif
+
+#endif // !MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS
+
+#if defined(MPT_ASSERT_HANDLER_NEEDED) && !defined(ENABLE_TESTS)
+
+MPT_NOINLINE void AssertHandler(const mpt::source_location &loc, const char *expr, const char *msg) {
+ if(msg) {
+ mpt::log::GlobalLogger().SendLogMessage(loc, LogError, "ASSERT",
+ MPT_USTRING("ASSERTION FAILED: ") + mpt::ToUnicode(mpt::CharsetSource, msg) + MPT_USTRING(" (") + mpt::ToUnicode(mpt::CharsetSource, expr) + MPT_USTRING(")")
+ );
+ } else {
+ mpt::log::GlobalLogger().SendLogMessage(loc, LogError, "ASSERT",
+ MPT_USTRING("ASSERTION FAILED: ") + mpt::ToUnicode(mpt::CharsetSource, expr)
+ );
+ }
+ #if defined(MPT_BUILD_FATAL_ASSERTS)
+ std::abort();
+ #endif // MPT_BUILD_FATAL_ASSERTS
+}
+
+#endif // MPT_ASSERT_HANDLER_NEEDED && !ENABLE_TESTS
+
+OPENMPT_NAMESPACE_END
+
+// assume OPENMPT_NAMESPACE is OpenMPT
+
+namespace openmpt {
+
+namespace version {
+
+std::uint32_t get_library_version() {
+ return OPENMPT_API_VERSION;
+}
+
+std::uint32_t get_core_version() {
+ return OpenMPT::Version::Current().GetRawVersion();
+}
+
+static std::string get_library_version_string() {
+ std::string str;
+ const OpenMPT::SourceInfo sourceInfo = OpenMPT::SourceInfo::Current();
+ str += mpt::format_value_default<std::string>(OPENMPT_API_VERSION_MAJOR);
+ str += ".";
+ str += mpt::format_value_default<std::string>(OPENMPT_API_VERSION_MINOR);
+ str += ".";
+ str += mpt::format_value_default<std::string>(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::format_value_default<std::string>( sourceInfo.Revision() ) );
+ }
+ if ( sourceInfo.IsDirty() ) {
+ fields.push_back( "modified" );
+ } else if ( sourceInfo.HasMixedRevisions() ) {
+ fields.push_back( "mixed" );
+ }
+ if ( sourceInfo.IsPackage() ) {
+ fields.push_back( "pkg" );
+ }
+ if ( !fields.empty() ) {
+ str += "+";
+ str += OpenMPT::mpt::String::Combine( fields, std::string(".") );
+ }
+ return str;
+}
+
+static std::string get_library_features_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, mpt::trim(OpenMPT::Build::GetBuildFeaturesString()));
+}
+
+static std::string get_core_version_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetVersionStringExtended());
+}
+
+static std::string get_source_url_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().GetUrlWithRevision());
+}
+
+static std::string get_source_date_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().Date());
+}
+
+static std::string get_source_revision_string() {
+ const OpenMPT::SourceInfo sourceInfo = OpenMPT::SourceInfo::Current();
+ return sourceInfo.Revision() ? mpt::format_value_default<std::string>(sourceInfo.Revision()) : std::string();
+}
+
+static std::string get_build_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildDateString());
+}
+
+static std::string get_build_compiler_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildCompilerString());
+}
+
+static std::string get_credits_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetFullCreditsString());
+}
+
+static std::string get_contact_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, MPT_USTRING("Forum: ") + OpenMPT::Build::GetURL(OpenMPT::Build::Url::Forum));
+}
+
+static std::string get_license_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetLicenseString());
+}
+
+static std::string get_url_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetURL(OpenMPT::Build::Url::Website));
+}
+
+static std::string get_support_forum_url_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetURL(OpenMPT::Build::Url::Forum));
+}
+
+static std::string get_bugtracker_url_string() {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::Build::GetURL(OpenMPT::Build::Url::Bugtracker));
+}
+
+std::string get_string( const std::string & key ) {
+ if ( key == "" ) {
+ return std::string();
+ } else if ( key == "library_version" ) {
+ return get_library_version_string();
+ } else if ( key == "library_version_major" ) {
+ return mpt::format_value_default<std::string>(OPENMPT_API_VERSION_MAJOR);
+ } else if ( key == "library_version_minor" ) {
+ return mpt::format_value_default<std::string>(OPENMPT_API_VERSION_MINOR);
+ } else if ( key == "library_version_patch" ) {
+ return mpt::format_value_default<std::string>(OPENMPT_API_VERSION_PATCH);
+ } else if ( key == "library_version_prerel" ) {
+ return mpt::format_value_default<std::string>(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" ) {
+ return get_core_version_string();
+ } else if ( key == "source_url" ) {
+ 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 OpenMPT::SourceInfo::Current().IsDirty() ? "1" : "0";
+ } else if ( key == "source_has_mixed_revision" ) {
+ return OpenMPT::SourceInfo::Current().HasMixedRevisions() ? "1" : "0";
+ } else if ( key == "source_is_package" ) {
+ return OpenMPT::SourceInfo::Current().IsPackage() ? "1" : "0";
+ } else if ( key == "build" ) {
+ return get_build_string();
+ } else if ( key == "build_compiler" ) {
+ return get_build_compiler_string();
+ } else if ( key == "credits" ) {
+ return get_credits_string();
+ } else if ( key == "contact" ) {
+ return get_contact_string();
+ } else if ( key == "license" ) {
+ return get_license_string();
+ } else if ( key == "url" ) {
+ return get_url_string();
+ } else if ( key == "support_forum_url" ) {
+ return get_support_forum_url_string();
+ } else if ( key == "bugtracker_url" ) {
+ return get_bugtracker_url_string();
+ } else {
+ return std::string();
+ }
+}
+
+} // namespace version
+
+log_interface::log_interface() {
+ return;
+}
+log_interface::~log_interface() {
+ return;
+}
+
+std_ostream_log::std_ostream_log( std::ostream & dst ) : destination(dst) {
+ return;
+}
+std_ostream_log::~std_ostream_log() {
+ return;
+}
+void std_ostream_log::log( const std::string & message ) const {
+ destination.flush();
+ destination << message << std::endl;
+ destination.flush();
+}
+
+class log_forwarder : public OpenMPT::ILog {
+private:
+ log_interface & destination;
+public:
+ log_forwarder( log_interface & dest ) : destination(dest) {
+ return;
+ }
+private:
+ void AddToLog( OpenMPT::LogLevel level, const mpt::ustring & text ) const override {
+ destination.log( mpt::transcode<std::string>( mpt::common_encoding::utf8, LogLevelToString( level ) + MPT_USTRING(": ") + text ) );
+ }
+}; // class log_forwarder
+
+class loader_log : public OpenMPT::ILog {
+private:
+ mutable std::vector<std::pair<OpenMPT::LogLevel,std::string> > m_Messages;
+public:
+ std::vector<std::pair<OpenMPT::LogLevel,std::string> > GetMessages() const;
+private:
+ void AddToLog( OpenMPT::LogLevel level, const mpt::ustring & text ) const override;
+}; // class loader_log
+
+std::vector<std::pair<OpenMPT::LogLevel,std::string> > loader_log::GetMessages() const {
+ return m_Messages;
+}
+void loader_log::AddToLog( OpenMPT::LogLevel level, const mpt::ustring & text ) const {
+ m_Messages.push_back( std::make_pair( level, mpt::transcode<std::string>( mpt::common_encoding::utf8, text ) ) );
+}
+
+void module_impl::PushToCSoundFileLog( const std::string & text ) const {
+ m_sndFile->AddToLog( OpenMPT::LogError, mpt::transcode<mpt::ustring>( mpt::common_encoding::utf8, text ) );
+}
+void module_impl::PushToCSoundFileLog( int loglevel, const std::string & text ) const {
+ m_sndFile->AddToLog( static_cast<OpenMPT::LogLevel>( loglevel ), mpt::transcode<mpt::ustring>( mpt::common_encoding::utf8, text ) );
+}
+
+module_impl::subsong_data::subsong_data( double duration, std::int32_t start_row, std::int32_t start_order, std::int32_t sequence )
+ : duration(duration)
+ , start_row(start_row)
+ , start_order(start_order)
+ , sequence(sequence)
+{
+ return;
+}
+
+static OpenMPT::ResamplingMode filterlength_to_resamplingmode(std::int32_t length) {
+ OpenMPT::ResamplingMode result = OpenMPT::SRCMODE_SINC8LP;
+ if ( length == 0 ) {
+ result = OpenMPT::SRCMODE_SINC8LP;
+ } else if ( length >= 8 ) {
+ result = OpenMPT::SRCMODE_SINC8LP;
+ } else if ( length >= 3 ) {
+ result = OpenMPT::SRCMODE_CUBIC;
+ } else if ( length >= 2 ) {
+ result = OpenMPT::SRCMODE_LINEAR;
+ } else if ( length >= 1 ) {
+ result = OpenMPT::SRCMODE_NEAREST;
+ } else {
+ throw openmpt::exception("negative filter length");
+ }
+ return result;
+}
+static std::int32_t resamplingmode_to_filterlength(OpenMPT::ResamplingMode mode) {
+ switch ( mode ) {
+ case OpenMPT::SRCMODE_NEAREST:
+ return 1;
+ break;
+ case OpenMPT::SRCMODE_LINEAR:
+ return 2;
+ break;
+ case OpenMPT::SRCMODE_CUBIC:
+ return 4;
+ break;
+ case OpenMPT::SRCMODE_SINC8:
+ case OpenMPT::SRCMODE_SINC8LP:
+ case OpenMPT::SRCMODE_DEFAULT:
+ return 8;
+ default:
+ throw openmpt::exception("unknown interpolation filter length set internally");
+ break;
+ }
+}
+
+template < typename sample_type >
+static inline std::size_t valid_channels( sample_type * const * buffers, std::size_t max_channels ) {
+ std::size_t channel;
+ for ( channel = 0; channel < max_channels; ++channel ) {
+ if ( !buffers[ channel ] ) {
+ break;
+ }
+ }
+ return channel;
+}
+
+static OpenMPT::Resampling::AmigaFilter translate_amiga_filter_type( module_impl::amiga_filter_type amiga_type ) {
+ switch (amiga_type ) {
+ case module_impl::amiga_filter_type::a500:
+ return OpenMPT::Resampling::AmigaFilter::A500;
+ case module_impl::amiga_filter_type::a1200:
+ case module_impl::amiga_filter_type::auto_filter:
+ default:
+ return OpenMPT::Resampling::AmigaFilter::A1200;
+ case module_impl::amiga_filter_type::unfiltered:
+ return OpenMPT::Resampling::AmigaFilter::Unfiltered;
+ }
+}
+
+static void ramping_to_mixersettings( OpenMPT::MixerSettings & settings, int ramping ) {
+ if ( ramping == -1 ) {
+ settings.SetVolumeRampUpMicroseconds( OpenMPT::MixerSettings().GetVolumeRampUpMicroseconds() );
+ settings.SetVolumeRampDownMicroseconds( OpenMPT::MixerSettings().GetVolumeRampDownMicroseconds() );
+ } else if ( ramping <= 0 ) {
+ settings.SetVolumeRampUpMicroseconds( 0 );
+ settings.SetVolumeRampDownMicroseconds( 0 );
+ } else {
+ settings.SetVolumeRampUpMicroseconds( ramping * 1000 );
+ settings.SetVolumeRampDownMicroseconds( ramping * 1000 );
+ }
+}
+static void mixersettings_to_ramping( int & ramping, const OpenMPT::MixerSettings & settings ) {
+ std::int32_t ramp_us = std::max( settings.GetVolumeRampUpMicroseconds(), settings.GetVolumeRampDownMicroseconds() );
+ if ( ( settings.GetVolumeRampUpMicroseconds() == OpenMPT::MixerSettings().GetVolumeRampUpMicroseconds() ) && ( settings.GetVolumeRampDownMicroseconds() == OpenMPT::MixerSettings().GetVolumeRampDownMicroseconds() ) ) {
+ ramping = -1;
+ } else if ( ramp_us <= 0 ) {
+ ramping = 0;
+ } else {
+ ramping = ( ramp_us + 500 ) / 1000;
+ }
+}
+
+std::string module_impl::mod_string_to_utf8( const std::string & encoded ) const {
+ return OpenMPT::mpt::ToCharset( OpenMPT::mpt::Charset::UTF8, 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;
+ bool channels_changed = static_cast<int>( m_sndFile->m_MixerSettings.gnChannels ) != channels;
+ if ( samplerate_changed || channels_changed ) {
+ OpenMPT::MixerSettings mixersettings = m_sndFile->m_MixerSettings;
+ std::int32_t volrampin_us = mixersettings.GetVolumeRampUpMicroseconds();
+ std::int32_t volrampout_us = mixersettings.GetVolumeRampDownMicroseconds();
+ mixersettings.gdwMixingFreq = samplerate;
+ mixersettings.gnChannels = channels;
+ mixersettings.SetVolumeRampUpMicroseconds( volrampin_us );
+ mixersettings.SetVolumeRampDownMicroseconds( volrampout_us );
+ m_sndFile->SetMixerSettings( mixersettings );
+ } else if ( !m_mixer_initialized ) {
+ m_sndFile->InitPlayer( true );
+ }
+ if ( samplerate_changed ) {
+ m_sndFile->SuspendPlugins();
+ m_sndFile->ResumePlugins();
+ }
+ m_mixer_initialized = true;
+}
+void module_impl::apply_libopenmpt_defaults() {
+ set_render_param( module::RENDER_STEREOSEPARATION_PERCENT, 100 );
+ m_sndFile->Order.SetSequence( 0 );
+}
+module_impl::subsongs_type module_impl::get_subsongs() const {
+ std::vector<subsong_data> subsongs;
+ if ( m_sndFile->Order.GetNumSequences() == 0 ) {
+ throw openmpt::exception("module contains no songs");
+ }
+ for ( OpenMPT::SEQUENCEINDEX seq = 0; seq < m_sndFile->Order.GetNumSequences(); ++seq ) {
+ const std::vector<OpenMPT::GetLengthType> lengths = m_sndFile->GetLength( OpenMPT::eNoAdjust, OpenMPT::GetLengthTarget( true ).StartPos( seq, 0, 0 ) );
+ for ( const auto & l : lengths ) {
+ subsongs.push_back( subsong_data( l.duration, l.startRow, l.startOrder, seq ) );
+ }
+ }
+ return subsongs;
+}
+void module_impl::init_subsongs( subsongs_type & subsongs ) const {
+ subsongs = get_subsongs();
+}
+bool module_impl::has_subsongs_inited() const {
+ return !m_subsongs.empty();
+}
+void module_impl::ctor( const std::map< std::string, std::string > & ctls ) {
+ m_sndFile = std::make_unique<OpenMPT::CSoundFile>();
+ m_loaded = false;
+ m_mixer_initialized = false;
+ m_Dithers = std::make_unique<OpenMPT::DithersWrapperOpenMPT>( OpenMPT::mpt::global_prng(), OpenMPT::DithersWrapperOpenMPT::DefaultDither, 4 );
+ m_LogForwarder = std::make_unique<log_forwarder>( *m_Log );
+ m_sndFile->SetCustomLog( m_LogForwarder.get() );
+ m_current_subsong = 0;
+ m_currentPositionSeconds = 0.0;
+ m_Gain = 1.0f;
+ m_ctl_play_at_end = song_end_action::fadeout_song;
+ m_ctl_load_skip_samples = false;
+ m_ctl_load_skip_patterns = false;
+ m_ctl_load_skip_plugins = false;
+ m_ctl_load_skip_subsongs_init = false;
+ m_ctl_seek_sync_samples = false;
+ // init member variables that correspond to ctls
+ for ( const auto & ctl : ctls ) {
+ ctl_set( ctl.first, ctl.second, false );
+ }
+}
+void module_impl::load( const OpenMPT::FileCursor & file, const std::map< std::string, std::string > & ctls ) {
+ loader_log loaderlog;
+ m_sndFile->SetCustomLog( &loaderlog );
+ {
+ int load_flags = OpenMPT::CSoundFile::loadCompleteModule;
+ if ( m_ctl_load_skip_samples ) {
+ load_flags &= ~OpenMPT::CSoundFile::loadSampleData;
+ }
+ if ( m_ctl_load_skip_patterns ) {
+ load_flags &= ~OpenMPT::CSoundFile::loadPatternData;
+ }
+ if ( m_ctl_load_skip_plugins ) {
+ load_flags &= ~(OpenMPT::CSoundFile::loadPluginData | OpenMPT::CSoundFile::loadPluginInstance);
+ }
+ if ( !m_sndFile->Create( file, static_cast<OpenMPT::CSoundFile::ModLoadingFlags>( load_flags ) ) ) {
+ throw openmpt::exception("error loading file");
+ }
+ if ( !m_ctl_load_skip_subsongs_init ) {
+ init_subsongs( m_subsongs );
+ }
+ m_loaded = true;
+ }
+ m_sndFile->SetCustomLog( m_LogForwarder.get() );
+ std::vector<std::pair<OpenMPT::LogLevel,std::string> > loaderMessages = loaderlog.GetMessages();
+ for ( const auto & msg : loaderMessages ) {
+ PushToCSoundFileLog( msg.first, msg.second );
+ m_loaderMessages.push_back( mpt::transcode<std::string>( mpt::common_encoding::utf8, LogLevelToString( msg.first ) ) + std::string(": ") + msg.second );
+ }
+ // init CSoundFile state that corresponds to ctls
+ for ( const auto & ctl : ctls ) {
+ ctl_set( ctl.first, ctl.second, false );
+ }
+}
+bool module_impl::is_loaded() const {
+ return m_loaded;
+}
+std::size_t module_impl::read_wrapper( std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ) {
+ m_sndFile->ResetMixStat();
+ m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song );
+ std::size_t count_read = 0;
+ std::int16_t * const buffers[4] = { left, right, rear_left, rear_right };
+ OpenMPT::AudioTargetBufferWithGain<mpt::audio_span_planar<std::int16_t>> target( mpt::audio_span_planar<std::int16_t>( buffers, valid_channels( buffers, std::size( buffers ) ), count ), *m_Dithers, m_Gain );
+ while ( count > 0 ) {
+ std::size_t count_chunk = m_sndFile->Read(
+ static_cast<OpenMPT::CSoundFile::samplecount_t>( std::min( static_cast<std::uint64_t>( count ), static_cast<std::uint64_t>( std::numeric_limits<OpenMPT::CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels
+ target
+ );
+ if ( count_chunk == 0 ) {
+ break;
+ }
+ count -= count_chunk;
+ count_read += count_chunk;
+ }
+ if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) {
+ // This is the song end, but allow the song or loop to restart on the next call
+ m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED);
+ }
+ return count_read;
+}
+std::size_t module_impl::read_wrapper( std::size_t count, float * left, float * right, float * rear_left, float * rear_right ) {
+ m_sndFile->ResetMixStat();
+ m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song );
+ std::size_t count_read = 0;
+ float * const buffers[4] = { left, right, rear_left, rear_right };
+ OpenMPT::AudioTargetBufferWithGain<mpt::audio_span_planar<float>> target( mpt::audio_span_planar<float>( buffers, valid_channels( buffers, std::size( buffers ) ), count ), *m_Dithers, m_Gain );
+ while ( count > 0 ) {
+ std::size_t count_chunk = m_sndFile->Read(
+ static_cast<OpenMPT::CSoundFile::samplecount_t>( std::min( static_cast<std::uint64_t>( count ), static_cast<std::uint64_t>( std::numeric_limits<OpenMPT::CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels
+ target
+ );
+ if ( count_chunk == 0 ) {
+ break;
+ }
+ count -= count_chunk;
+ count_read += count_chunk;
+ }
+ if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) {
+ // This is the song end, but allow the song or loop to restart on the next call
+ m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED);
+ }
+ return count_read;
+}
+std::size_t module_impl::read_interleaved_wrapper( std::size_t count, std::size_t channels, std::int16_t * interleaved ) {
+ m_sndFile->ResetMixStat();
+ m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song );
+ std::size_t count_read = 0;
+ OpenMPT::AudioTargetBufferWithGain<mpt::audio_span_interleaved<std::int16_t>> target( mpt::audio_span_interleaved<std::int16_t>( interleaved, channels, count ), *m_Dithers, m_Gain );
+ while ( count > 0 ) {
+ std::size_t count_chunk = m_sndFile->Read(
+ static_cast<OpenMPT::CSoundFile::samplecount_t>( std::min( static_cast<std::uint64_t>( count ), static_cast<std::uint64_t>( std::numeric_limits<OpenMPT::CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels
+ target
+ );
+ if ( count_chunk == 0 ) {
+ break;
+ }
+ count -= count_chunk;
+ count_read += count_chunk;
+ }
+ if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) {
+ // This is the song end, but allow the song or loop to restart on the next call
+ m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED);
+ }
+ return count_read;
+}
+std::size_t module_impl::read_interleaved_wrapper( std::size_t count, std::size_t channels, float * interleaved ) {
+ m_sndFile->ResetMixStat();
+ m_sndFile->m_bIsRendering = ( m_ctl_play_at_end != song_end_action::fadeout_song );
+ std::size_t count_read = 0;
+ OpenMPT::AudioTargetBufferWithGain<mpt::audio_span_interleaved<float>> target( mpt::audio_span_interleaved<float>( interleaved, channels, count ), *m_Dithers, m_Gain );
+ while ( count > 0 ) {
+ std::size_t count_chunk = m_sndFile->Read(
+ static_cast<OpenMPT::CSoundFile::samplecount_t>( std::min( static_cast<std::uint64_t>( count ), static_cast<std::uint64_t>( std::numeric_limits<OpenMPT::CSoundFile::samplecount_t>::max() / 2 / 4 / 4 ) ) ), // safety margin / samplesize / channels
+ target
+ );
+ if ( count_chunk == 0 ) {
+ break;
+ }
+ count -= count_chunk;
+ count_read += count_chunk;
+ }
+ if ( count_read == 0 && m_ctl_play_at_end == song_end_action::continue_song ) {
+ // This is the song end, but allow the song or loop to restart on the next call
+ m_sndFile->m_SongFlags.reset(OpenMPT::SONG_ENDREACHED);
+ }
+ return count_read;
+}
+
+std::vector<std::string> module_impl::get_supported_extensions() {
+ std::vector<std::string> retval;
+ std::vector<const char *> extensions = OpenMPT::CSoundFile::GetSupportedExtensions( false );
+ std::copy( extensions.begin(), extensions.end(), std::back_insert_iterator<std::vector<std::string> >( retval ) );
+ return retval;
+}
+bool module_impl::is_extension_supported( std::string_view extension ) {
+ return OpenMPT::CSoundFile::IsExtensionSupported( extension );
+}
+/// <summary>
+/// From version: 0.7.0
+/// Hakan DANISIK
+/// </summary>
+/// <param name="extension"></param>
+/// <returns></returns>
+std::string module_impl::get_tracker_name( const std::string & extension ) {
+ std::string lowercase_ext = extension;
+ std::transform( lowercase_ext.begin(), lowercase_ext.end(), lowercase_ext.begin(), tolower );
+ return OpenMPT::CSoundFile::ExtensionToTracker( lowercase_ext );
+}
+double module_impl::could_open_probability( const OpenMPT::FileCursor & file, double effort, std::unique_ptr<log_interface> log ) {
+ try {
+ if ( effort >= 0.8 ) {
+ std::unique_ptr<OpenMPT::CSoundFile> sndFile = std::make_unique<OpenMPT::CSoundFile>();
+ std::unique_ptr<log_forwarder> logForwarder = std::make_unique<log_forwarder>( *log );
+ sndFile->SetCustomLog( logForwarder.get() );
+ if ( !sndFile->Create( file, OpenMPT::CSoundFile::loadCompleteModule ) ) {
+ return 0.0;
+ }
+ sndFile->Destroy();
+ return 1.0;
+ } else if ( effort >= 0.6 ) {
+ std::unique_ptr<OpenMPT::CSoundFile> sndFile = std::make_unique<OpenMPT::CSoundFile>();
+ std::unique_ptr<log_forwarder> logForwarder = std::make_unique<log_forwarder>( *log );
+ sndFile->SetCustomLog( logForwarder.get() );
+ if ( !sndFile->Create( file, OpenMPT::CSoundFile::loadNoPatternOrPluginData ) ) {
+ return 0.0;
+ }
+ sndFile->Destroy();
+ return 0.8;
+ } else if ( effort >= 0.2 ) {
+ std::unique_ptr<OpenMPT::CSoundFile> sndFile = std::make_unique<OpenMPT::CSoundFile>();
+ std::unique_ptr<log_forwarder> logForwarder = std::make_unique<log_forwarder>( *log );
+ sndFile->SetCustomLog( logForwarder.get() );
+ if ( !sndFile->Create( file, OpenMPT::CSoundFile::onlyVerifyHeader ) ) {
+ return 0.0;
+ }
+ sndFile->Destroy();
+ return 0.6;
+ } else if ( effort >= 0.1 ) {
+ OpenMPT::FileCursor::PinnedView view = file.GetPinnedView( probe_file_header_get_recommended_size() );
+ int probe_file_header_result = probe_file_header( probe_file_header_flags_default2, 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;
+ }
+}
+double module_impl::could_open_probability( callback_stream_wrapper stream, double effort, std::unique_ptr<log_interface> log ) {
+ mpt::IO::CallbackStream fstream;
+ fstream.stream = stream.stream;
+ fstream.read = stream.read;
+ fstream.seek = stream.seek;
+ fstream.tell = stream.tell;
+ return could_open_probability( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( fstream ), effort, std::move(log) );
+}
+double module_impl::could_open_probability( std::istream & stream, double effort, std::unique_ptr<log_interface> log ) {
+ return could_open_probability(mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( stream ), effort, std::move(log) );
+}
+
+std::size_t module_impl::probe_file_header_get_recommended_size() {
+ return OpenMPT::CSoundFile::ProbeRecommendedSize;
+}
+int module_impl::probe_file_header( std::uint64_t flags, const std::byte * data, std::size_t size, std::uint64_t filesize ) {
+ int result = 0;
+ switch ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( data, size ), &filesize ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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, std::uint64_t filesize ) {
+ int result = 0;
+ switch ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( mpt::byte_cast<const std::byte*>( data ), size ), &filesize ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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 ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( mpt::void_cast<const std::byte*>( data ), size ), &filesize ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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::byte * data, std::size_t size ) {
+ int result = 0;
+ switch ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( data, size ), nullptr ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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 ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( mpt::byte_cast<const std::byte*>( data ), size ), nullptr ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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 ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( mpt::void_cast<const std::byte*>( data ), size ), nullptr ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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 ];
+ OpenMPT::MemsetZero( buffer );
+ std::size_t size_read = 0;
+ std::size_t size_toread = OpenMPT::CSoundFile::ProbeRecommendedSize;
+ if ( stream.bad() ) {
+ throw exception("error reading stream");
+ }
+ const bool seekable = mpt::IO::FileDataStdStream::IsSeekable( stream );
+ const std::uint64_t filesize = ( seekable ? mpt::IO::FileDataStdStream::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 ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( mpt::byte_cast<const std::byte*>( buffer ), size_read ), seekable ? &filesize : nullptr ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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 ];
+ OpenMPT::MemsetZero( buffer );
+ std::size_t size_read = 0;
+ std::size_t size_toread = OpenMPT::CSoundFile::ProbeRecommendedSize;
+ if ( !stream.read ) {
+ throw exception("error reading stream");
+ }
+ mpt::IO::CallbackStream fstream;
+ fstream.stream = stream.stream;
+ fstream.read = stream.read;
+ fstream.seek = stream.seek;
+ fstream.tell = stream.tell;
+ const bool seekable = mpt::IO::FileDataCallbackStream::IsSeekable( fstream );
+ const std::uint64_t filesize = ( seekable ? mpt::IO::FileDataCallbackStream::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 ( OpenMPT::CSoundFile::Probe( static_cast<OpenMPT::CSoundFile::ProbeFlags>( flags ), mpt::span<const std::byte>( mpt::byte_cast<const std::byte*>( buffer ), size_read ), seekable ? &filesize : nullptr ) ) {
+ case OpenMPT::CSoundFile::ProbeSuccess:
+ result = probe_file_header_result_success;
+ break;
+ case OpenMPT::CSoundFile::ProbeFailure:
+ result = probe_file_header_result_failure;
+ break;
+ case OpenMPT::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 );
+ mpt::IO::CallbackStream fstream;
+ fstream.stream = stream.stream;
+ fstream.read = stream.read;
+ fstream.seek = stream.seek;
+ fstream.tell = stream.tell;
+ load( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( fstream ), ctls );
+ apply_libopenmpt_defaults();
+}
+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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( stream ), ctls );
+ apply_libopenmpt_defaults();
+}
+module_impl::module_impl( const std::vector<std::byte> & data, std::unique_ptr<log_interface> log, const std::map< std::string, std::string > & ctls ) : m_Log(std::move(log)) {
+ ctor( ctls );
+ load( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::as_span( data ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::as_span( data ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::byte_cast< mpt::span< const std::byte > >( mpt::as_span( data ) ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+module_impl::module_impl( const std::byte * 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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::as_span( data, size ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::as_span( data, size ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::byte_cast< mpt::span< const std::byte > >( mpt::as_span( data, size ) ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+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( mpt::IO::make_FileCursor<OpenMPT::mpt::PathString>( mpt::as_span( mpt::void_cast< const std::byte * >( data ), size ) ), ctls );
+ apply_libopenmpt_defaults();
+}
+module_impl::~module_impl() {
+ m_sndFile->Destroy();
+}
+
+std::int32_t module_impl::get_render_param( int param ) const {
+ std::int32_t result = 0;
+ switch ( param ) {
+ case module::RENDER_MASTERGAIN_MILLIBEL: {
+ result = static_cast<std::int32_t>( 1000.0f * 2.0f * std::log10( m_Gain ) );
+ } break;
+ case module::RENDER_STEREOSEPARATION_PERCENT: {
+ result = m_sndFile->m_MixerSettings.m_nStereoSeparation * 100 / OpenMPT::MixerSettings::StereoSeparationScale;
+ } break;
+ case module::RENDER_INTERPOLATIONFILTER_LENGTH: {
+ result = resamplingmode_to_filterlength( m_sndFile->m_Resampler.m_Settings.SrcMode );
+ } break;
+ case module::RENDER_VOLUMERAMPING_STRENGTH: {
+ int ramping = 0;
+ mixersettings_to_ramping( ramping, m_sndFile->m_MixerSettings );
+ result = ramping;
+ } break;
+ default: throw openmpt::exception("unknown render param"); break;
+ }
+ return result;
+}
+void module_impl::set_render_param( int param, std::int32_t value ) {
+ switch ( param ) {
+ case module::RENDER_MASTERGAIN_MILLIBEL: {
+ m_Gain = static_cast<float>( std::pow( 10.0f, value * 0.001f * 0.5f ) );
+ } break;
+ case module::RENDER_STEREOSEPARATION_PERCENT: {
+ std::int32_t newvalue = value * OpenMPT::MixerSettings::StereoSeparationScale / 100;
+ if ( newvalue != static_cast<std::int32_t>( m_sndFile->m_MixerSettings.m_nStereoSeparation ) ) {
+ OpenMPT::MixerSettings settings = m_sndFile->m_MixerSettings;
+ settings.m_nStereoSeparation = newvalue;
+ m_sndFile->SetMixerSettings( settings );
+ }
+ } break;
+ case module::RENDER_INTERPOLATIONFILTER_LENGTH: {
+ OpenMPT::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 );
+ }
+ } break;
+ case module::RENDER_VOLUMERAMPING_STRENGTH: {
+ OpenMPT::MixerSettings newsettings = m_sndFile->m_MixerSettings;
+ ramping_to_mixersettings( newsettings, value );
+ if ( m_sndFile->m_MixerSettings.VolumeRampUpMicroseconds != newsettings.VolumeRampUpMicroseconds || m_sndFile->m_MixerSettings.VolumeRampDownMicroseconds != newsettings.VolumeRampDownMicroseconds ) {
+ m_sndFile->SetMixerSettings( newsettings );
+ }
+ } break;
+ default: throw openmpt::exception("unknown render param"); break;
+ }
+}
+
+std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ) {
+ if ( !mono ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 1 );
+ count = read_wrapper( count, mono, nullptr, nullptr, nullptr );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ) {
+ if ( !left || !right ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 2 );
+ count = read_wrapper( count, left, right, nullptr, nullptr );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ) {
+ if ( !left || !right || !rear_left || !rear_right ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 4 );
+ count = read_wrapper( count, left, right, rear_left, rear_right );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, float * mono ) {
+ if ( !mono ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 1 );
+ count = read_wrapper( count, mono, nullptr, nullptr, nullptr );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, float * left, float * right ) {
+ if ( !left || !right ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 2 );
+ count = read_wrapper( count, left, right, nullptr, nullptr );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ) {
+ if ( !left || !right || !rear_left || !rear_right ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 4 );
+ count = read_wrapper( count, left, right, rear_left, rear_right );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ) {
+ if ( !interleaved_stereo ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 2 );
+ count = read_interleaved_wrapper( count, 2, interleaved_stereo );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ) {
+ if ( !interleaved_quad ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 4 );
+ count = read_interleaved_wrapper( count, 4, interleaved_quad );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ) {
+ if ( !interleaved_stereo ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 2 );
+ count = read_interleaved_wrapper( count, 2, interleaved_stereo );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+std::size_t module_impl::read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ) {
+ if ( !interleaved_quad ) {
+ throw openmpt::exception("null pointer");
+ }
+ apply_mixer_settings( samplerate, 4 );
+ count = read_interleaved_wrapper( count, 4, interleaved_quad );
+ m_currentPositionSeconds += static_cast<double>( count ) / static_cast<double>( samplerate );
+ return count;
+}
+
+
+double module_impl::get_duration_seconds() const {
+ std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ? std::unique_ptr<subsongs_type>() : std::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.
+ double total_duration = 0.0;
+ for ( const auto & subsong : subsongs ) {
+ total_duration += subsong.duration;
+ }
+ return total_duration;
+ }
+ return subsongs[m_current_subsong].duration;
+}
+void module_impl::select_subsong( std::int32_t subsong ) {
+ std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ? std::unique_ptr<subsongs_type>() : std::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");
+ }
+ m_current_subsong = subsong;
+ m_sndFile->m_SongFlags.set( OpenMPT::SONG_PLAYALLSONGS, subsong == all_subsongs );
+ if ( subsong == all_subsongs ) {
+ subsong = 0;
+ }
+ m_sndFile->Order.SetSequence( static_cast<OpenMPT::SEQUENCEINDEX>( subsongs[subsong].sequence ) );
+ 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 );
+}
+std::int32_t module_impl::get_repeat_count() const {
+ return m_sndFile->GetRepeatCount();
+}
+double module_impl::get_position_seconds() const {
+ return m_currentPositionSeconds;
+}
+double module_impl::set_position_seconds( double seconds ) {
+ std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ? std::unique_ptr<subsongs_type>() : std::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;
+ if ( m_current_subsong == all_subsongs ) {
+ // When playing all subsongs, find out which subsong this time would belong to.
+ subsong = &subsongs.back();
+ for ( std::size_t i = 0; i < subsongs.size(); ++i ) {
+ if ( base_seconds + subsongs[i].duration > seconds ) {
+ subsong = &subsongs[i];
+ break;
+ }
+ base_seconds += subsong->duration;
+ }
+ seconds -= base_seconds;
+ } else {
+ subsong = &subsongs[m_current_subsong];
+ }
+ m_sndFile->SetCurrentOrder( static_cast<OpenMPT::ORDERINDEX>( subsong->start_order ) );
+ OpenMPT::GetLengthType t = m_sndFile->GetLength( m_ctl_seek_sync_samples ? OpenMPT::eAdjustSamplePositions : OpenMPT::eAdjust, OpenMPT::GetLengthTarget( seconds ).StartPos( static_cast<OpenMPT::SEQUENCEINDEX>( subsong->sequence ), static_cast<OpenMPT::ORDERINDEX>( subsong->start_order ), static_cast<OpenMPT::ROWINDEX>( subsong->start_row ) ) ).back();
+ m_sndFile->m_PlayState.m_nNextOrder = m_sndFile->m_PlayState.m_nCurrentOrder = t.targetReached ? t.lastOrder : t.endOrder;
+ m_sndFile->m_PlayState.m_nNextRow = t.targetReached ? t.lastRow : t.endRow;
+ m_sndFile->m_PlayState.m_nTickCount = OpenMPT::CSoundFile::TICKS_ROW_FINISHED;
+ m_currentPositionSeconds = base_seconds + t.duration;
+ 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() ) {
+ return m_currentPositionSeconds;
+ }
+ OpenMPT::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;
+ }
+ } else {
+ row = 0;
+ }
+ m_sndFile->m_PlayState.m_nCurrentOrder = static_cast<OpenMPT::ORDERINDEX>( order );
+ m_sndFile->SetCurrentOrder( static_cast<OpenMPT::ORDERINDEX>( order ) );
+ m_sndFile->m_PlayState.m_nNextRow = static_cast<OpenMPT::ROWINDEX>( row );
+ m_sndFile->m_PlayState.m_nTickCount = OpenMPT::CSoundFile::TICKS_ROW_FINISHED;
+ m_currentPositionSeconds = m_sndFile->GetLength( m_ctl_seek_sync_samples ? OpenMPT::eAdjustSamplePositions : OpenMPT::eAdjust, OpenMPT::GetLengthTarget( static_cast<OpenMPT::ORDERINDEX>( order ), static_cast<OpenMPT::ROWINDEX>( row ) ) ).back().duration;
+ return m_currentPositionSeconds;
+}
+std::vector<std::string> module_impl::get_metadata_keys() const {
+ return
+ {
+ "type",
+ "type_long",
+ "originaltype",
+ "originaltype_long",
+ "container",
+ "container_long",
+ "tracker",
+ "artist",
+ "title",
+ "date",
+ "message",
+ "message_raw",
+ "warnings",
+ };
+}
+std::string module_impl::get_message_instruments() const {
+ std::string retval;
+ std::string tmp;
+ bool valid = false;
+ for ( OpenMPT::INSTRUMENTINDEX i = 1; i <= m_sndFile->GetNumInstruments(); ++i ) {
+ std::string instname = m_sndFile->GetInstrumentName( i );
+ if ( !instname.empty() ) {
+ valid = true;
+ }
+ tmp += instname;
+ tmp += "\n";
+ }
+ if ( valid ) {
+ retval = tmp;
+ }
+ return retval;
+}
+std::string module_impl::get_message_samples() const {
+ std::string retval;
+ std::string tmp;
+ bool valid = false;
+ for ( OpenMPT::SAMPLEINDEX i = 1; i <= m_sndFile->GetNumSamples(); ++i ) {
+ std::string samplename = m_sndFile->GetSampleName( i );
+ if ( !samplename.empty() ) {
+ valid = true;
+ }
+ tmp += samplename;
+ tmp += "\n";
+ }
+ if ( valid ) {
+ retval = tmp;
+ }
+ return retval;
+}
+std::string module_impl::get_metadata( const std::string & key ) const {
+ if ( key == std::string("type") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->m_modFormat.type );
+ } else if ( key == std::string("type_long") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->m_modFormat.formatName );
+ } else if ( key == std::string("originaltype") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->m_modFormat.originalType );
+ } else if ( key == std::string("originaltype_long") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->m_modFormat.originalFormatName );
+ } else if ( key == std::string("container") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() ) );
+ } else if ( key == std::string("container_long") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, OpenMPT::CSoundFile::ModContainerTypeToTracker( m_sndFile->GetContainerType() ) );
+ } else if ( key == std::string("tracker") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->m_modFormat.madeWithTracker );
+ } else if ( key == std::string("artist") ) {
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->m_songArtist );
+ } else if ( key == std::string("title") ) {
+ return mod_string_to_utf8( m_sndFile->GetTitle() );
+ } else if ( key == std::string("date") ) {
+ if ( m_sndFile->GetFileHistory().empty() || !m_sndFile->GetFileHistory().back().HasValidDate() ) {
+ return std::string();
+ }
+ return mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->GetFileHistory().back().AsISO8601() );
+ } else if ( key == std::string("message") ) {
+ std::string retval = m_sndFile->m_songMessage.GetFormatted( OpenMPT::SongMessage::leLF );
+ if ( retval.empty() ) {
+ switch ( m_sndFile->GetMessageHeuristic() ) {
+ case OpenMPT::ModMessageHeuristicOrder::Instruments:
+ retval = get_message_instruments();
+ break;
+ case OpenMPT::ModMessageHeuristicOrder::Samples:
+ retval = get_message_samples();
+ break;
+ case OpenMPT::ModMessageHeuristicOrder::InstrumentsSamples:
+ if ( retval.empty() ) {
+ retval = get_message_instruments();
+ }
+ if ( retval.empty() ) {
+ retval = get_message_samples();
+ }
+ break;
+ case OpenMPT::ModMessageHeuristicOrder::SamplesInstruments:
+ if ( retval.empty() ) {
+ retval = get_message_samples();
+ }
+ if ( retval.empty() ) {
+ retval = get_message_instruments();
+ }
+ break;
+ case OpenMPT::ModMessageHeuristicOrder::BothInstrumentsSamples:
+ {
+ std::string message_instruments = get_message_instruments();
+ std::string message_samples = get_message_samples();
+ if ( !message_instruments.empty() ) {
+ retval += std::move( message_instruments );
+ }
+ if ( !message_samples.empty() ) {
+ retval += std::move( message_samples );
+ }
+ }
+ break;
+ case OpenMPT::ModMessageHeuristicOrder::BothSamplesInstruments:
+ {
+ std::string message_instruments = get_message_instruments();
+ std::string message_samples = get_message_samples();
+ if ( !message_samples.empty() ) {
+ retval += std::move( message_samples );
+ }
+ if ( !message_instruments.empty() ) {
+ retval += std::move( message_instruments );
+ }
+ }
+ break;
+ }
+ }
+ return mod_string_to_utf8( retval );
+ } else if ( key == std::string("message_raw") ) {
+ std::string retval = m_sndFile->m_songMessage.GetFormatted( OpenMPT::SongMessage::leLF );
+ return mod_string_to_utf8( retval );
+ } else if ( key == std::string("warnings") ) {
+ std::string retval;
+ bool first = true;
+ for ( const auto & msg : m_loaderMessages ) {
+ if ( !first ) {
+ retval += "\n";
+ } else {
+ first = false;
+ }
+ retval += msg;
+ }
+ return retval;
+ }
+ return "";
+}
+
+double module_impl::get_current_estimated_bpm() const {
+ return m_sndFile->GetCurrentBPM();
+}
+std::int32_t module_impl::get_current_speed() const {
+ return m_sndFile->m_PlayState.m_nMusicSpeed;
+}
+std::int32_t module_impl::get_current_tempo() const {
+ return static_cast<std::int32_t>( m_sndFile->m_PlayState.m_nMusicTempo.GetInt() );
+}
+std::int32_t module_impl::get_current_order() const {
+ return m_sndFile->GetCurrentOrder();
+}
+std::int32_t module_impl::get_current_pattern() const {
+ std::int32_t order = m_sndFile->GetCurrentOrder();
+ if ( order < 0 || order >= m_sndFile->Order().GetLengthTailTrimmed() ) {
+ return m_sndFile->GetCurrentPattern();
+ }
+ std::int32_t pattern = m_sndFile->Order()[order];
+ if ( !m_sndFile->Patterns.IsValidIndex( static_cast<OpenMPT::PATTERNINDEX>( pattern ) ) ) {
+ return -1;
+ }
+ return pattern;
+}
+std::int32_t module_impl::get_current_row() const {
+ return m_sndFile->m_PlayState.m_nRow;
+}
+std::int32_t module_impl::get_current_playing_channels() const {
+ return m_sndFile->GetMixStat();
+}
+
+float module_impl::get_current_channel_vu_mono( std::int32_t channel ) const {
+ if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) {
+ return 0.0f;
+ }
+ const float left = m_sndFile->m_PlayState.Chn[channel].nLeftVU * (1.0f/128.0f);
+ const float right = m_sndFile->m_PlayState.Chn[channel].nRightVU * (1.0f/128.0f);
+ return std::sqrt(left*left + right*right);
+}
+float module_impl::get_current_channel_vu_left( std::int32_t channel ) const {
+ if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) {
+ return 0.0f;
+ }
+ return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? 0.0f : m_sndFile->m_PlayState.Chn[channel].nLeftVU * (1.0f/128.0f);
+}
+float module_impl::get_current_channel_vu_right( std::int32_t channel ) const {
+ if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) {
+ return 0.0f;
+ }
+ return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? 0.0f : m_sndFile->m_PlayState.Chn[channel].nRightVU * (1.0f/128.0f);
+}
+float module_impl::get_current_channel_vu_rear_left( std::int32_t channel ) const {
+ if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) {
+ return 0.0f;
+ }
+ return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? m_sndFile->m_PlayState.Chn[channel].nLeftVU * (1.0f/128.0f) : 0.0f;
+}
+float module_impl::get_current_channel_vu_rear_right( std::int32_t channel ) const {
+ if ( channel < 0 || channel >= m_sndFile->GetNumChannels() ) {
+ return 0.0f;
+ }
+ return m_sndFile->m_PlayState.Chn[channel].dwFlags[OpenMPT::CHN_SURROUND] ? m_sndFile->m_PlayState.Chn[channel].nRightVU * (1.0f/128.0f) : 0.0f;
+}
+
+std::int32_t module_impl::get_num_subsongs() const {
+ std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ? std::unique_ptr<subsongs_type>() : std::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() );
+}
+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();
+}
+std::int32_t module_impl::get_num_patterns() const {
+ return m_sndFile->Patterns.GetNumPatterns();
+}
+std::int32_t module_impl::get_num_instruments() const {
+ return m_sndFile->GetNumInstruments();
+}
+std::int32_t module_impl::get_num_samples() const {
+ return m_sndFile->GetNumSamples();
+}
+
+std::vector<std::string> module_impl::get_subsong_names() const {
+ std::vector<std::string> retval;
+ std::unique_ptr<subsongs_type> subsongs_temp = has_subsongs_inited() ? std::unique_ptr<subsongs_type>() : std::make_unique<subsongs_type>( get_subsongs() );
+ const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp;
+ retval.reserve( subsongs.size() );
+ for ( const auto & subsong : subsongs ) {
+ const auto & order = m_sndFile->Order( static_cast<OpenMPT::SEQUENCEINDEX>( subsong.sequence ) );
+ retval.push_back( mpt::transcode<std::string>( mpt::common_encoding::utf8, order.GetName() ) );
+ if ( retval.back().empty() ) {
+ // use first pattern name instead
+ if ( order.IsValidPat( static_cast<OpenMPT::SEQUENCEINDEX>( subsong.start_order ) ) )
+ retval.back() = OpenMPT::mpt::ToCharset( OpenMPT::mpt::Charset::UTF8, m_sndFile->GetCharsetInternal(), m_sndFile->Patterns[ order[ subsong.start_order ] ].GetName() );
+ }
+ }
+ return retval;
+}
+std::vector<std::string> module_impl::get_channel_names() const {
+ std::vector<std::string> retval;
+ for ( OpenMPT::CHANNELINDEX i = 0; i < m_sndFile->GetNumChannels(); ++i ) {
+ retval.push_back( mod_string_to_utf8( m_sndFile->ChnSettings[i].szName ) );
+ }
+ return retval;
+}
+std::vector<std::string> module_impl::get_order_names() const {
+ std::vector<std::string> retval;
+ OpenMPT::ORDERINDEX num_orders = m_sndFile->Order().GetLengthTailTrimmed();
+ retval.reserve( num_orders );
+ for ( OpenMPT::ORDERINDEX i = 0; i < num_orders; ++i ) {
+ OpenMPT::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() ) );
+ } else {
+ if ( pat == m_sndFile->Order.GetIgnoreIndex() ) {
+ retval.push_back( "+++ skip" );
+ } else if ( pat == m_sndFile->Order.GetInvalidPatIndex() ) {
+ retval.push_back( "--- stop" );
+ } else {
+ retval.push_back( "???" );
+ }
+ }
+ }
+ return retval;
+}
+std::vector<std::string> module_impl::get_pattern_names() const {
+ std::vector<std::string> retval;
+ retval.reserve( m_sndFile->Patterns.GetNumPatterns() );
+ for ( OpenMPT::PATTERNINDEX i = 0; i < m_sndFile->Patterns.GetNumPatterns(); ++i ) {
+ retval.push_back( mod_string_to_utf8( m_sndFile->Patterns[i].GetName() ) );
+ }
+ return retval;
+}
+std::vector<std::string> module_impl::get_instrument_names() const {
+ std::vector<std::string> retval;
+ retval.reserve( m_sndFile->GetNumInstruments() );
+ for ( OpenMPT::INSTRUMENTINDEX i = 1; i <= m_sndFile->GetNumInstruments(); ++i ) {
+ retval.push_back( mod_string_to_utf8( m_sndFile->GetInstrumentName( i ) ) );
+ }
+ return retval;
+}
+std::vector<std::string> module_impl::get_sample_names() const {
+ std::vector<std::string> retval;
+ retval.reserve( m_sndFile->GetNumSamples() );
+ for ( OpenMPT::SAMPLEINDEX i = 1; i <= m_sndFile->GetNumSamples(); ++i ) {
+ retval.push_back( mod_string_to_utf8( m_sndFile->GetSampleName( i ) ) );
+ }
+ return retval;
+}
+
+std::int32_t module_impl::get_order_pattern( std::int32_t o ) const {
+ if ( o < 0 || o >= m_sndFile->Order().GetLengthTailTrimmed() ) {
+ return -1;
+ }
+ return m_sndFile->Order()[o];
+}
+std::int32_t module_impl::get_pattern_num_rows( std::int32_t p ) const {
+ if ( !mpt::is_in_range( p, std::numeric_limits<OpenMPT::PATTERNINDEX>::min(), std::numeric_limits<OpenMPT::PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<OpenMPT::PATTERNINDEX>( p ) ) ) {
+ return 0;
+ }
+ return m_sndFile->Patterns[p].GetNumRows();
+}
+
+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 {
+ if ( !mpt::is_in_range( p, std::numeric_limits<OpenMPT::PATTERNINDEX>::min(), std::numeric_limits<OpenMPT::PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<OpenMPT::PATTERNINDEX>( p ) ) ) {
+ return 0;
+ }
+ const OpenMPT::CPattern & pattern = m_sndFile->Patterns[p];
+ if ( r < 0 || r >= static_cast<std::int32_t>( pattern.GetNumRows() ) ) {
+ return 0;
+ }
+ if ( c < 0 || c >= m_sndFile->GetNumChannels() ) {
+ return 0;
+ }
+ if ( cmd < module::command_note || cmd > module::command_parameter ) {
+ return 0;
+ }
+ const OpenMPT::ModCommand & cell = *pattern.GetpModCommand( static_cast<OpenMPT::ROWINDEX>( r ), static_cast<OpenMPT::CHANNELINDEX>( c ) );
+ switch ( cmd ) {
+ 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;
+}
+
+/*
+
+highlight chars explained:
+
+ : empty/space
+. : empty/dot
+n : generic note
+m : special note
+i : generic instrument
+u : generic volume column effect
+v : generic volume column parameter
+e : generic effect column effect
+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 {
+ if ( !mpt::is_in_range( p, std::numeric_limits<OpenMPT::PATTERNINDEX>::min(), std::numeric_limits<OpenMPT::PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<OpenMPT::PATTERNINDEX>( p ) ) ) {
+ return std::make_pair( std::string(), std::string() );
+ }
+ const OpenMPT::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 >= 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 OpenMPT::ModCommand & cell = *pattern.GetpModCommand( static_cast<OpenMPT::ROWINDEX>( r ), static_cast<OpenMPT::CHANNELINDEX>( c ) );
+ // clang-format off
+ switch ( cmd ) {
+ case module::command_note:
+ return std::make_pair(
+ ( cell.IsNote() || cell.IsSpecialNote() ) ? mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->GetNoteName( cell.note, cell.instr ) ) : std::string("...")
+ ,
+ ( cell.IsNote() ) ? std::string("nnn") : cell.IsSpecialNote() ? std::string("mmm") : std::string("...")
+ );
+ break;
+ case module::command_instrument:
+ return std::make_pair(
+ cell.instr ? OpenMPT::mpt::afmt::HEX0<2>( cell.instr ) : std::string("..")
+ ,
+ cell.instr ? std::string("ii") : std::string("..")
+ );
+ break;
+ case module::command_volumeffect:
+ return std::make_pair(
+ cell.IsPcNote() ? std::string(" ") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string( 1, m_sndFile->GetModSpecifications().GetVolEffectLetter( cell.volcmd ) ) : std::string(" ")
+ ,
+ cell.IsPcNote() ? std::string(" ") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string("u") : std::string(" ")
+ );
+ break;
+ case module::command_volume:
+ return std::make_pair(
+ cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<2>( cell.GetValueVolCol() & 0xff ) : cell.volcmd != OpenMPT::VOLCMD_NONE ? OpenMPT::mpt::afmt::HEX0<2>( cell.vol ) : std::string("..")
+ ,
+ cell.IsPcNote() ? std::string("vv") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string("vv") : std::string("..")
+ );
+ break;
+ case module::command_effect:
+ return std::make_pair(
+ cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<1>( ( cell.GetValueEffectCol() & 0x0f00 ) > 16 ) : cell.command != OpenMPT::CMD_NONE ? std::string( 1, m_sndFile->GetModSpecifications().GetEffectLetter( cell.command ) ) : std::string(".")
+ ,
+ cell.IsPcNote() ? std::string("e") : cell.command != OpenMPT::CMD_NONE ? std::string("e") : std::string(".")
+ );
+ break;
+ case module::command_parameter:
+ return std::make_pair(
+ cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<2>( cell.GetValueEffectCol() & 0x00ff ) : cell.command != OpenMPT::CMD_NONE ? OpenMPT::mpt::afmt::HEX0<2>( cell.param ) : std::string("..")
+ ,
+ cell.IsPcNote() ? std::string("ff") : cell.command != OpenMPT::CMD_NONE ? std::string("ff") : std::string("..")
+ );
+ break;
+ }
+ // clang-format on
+ return std::make_pair( std::string(), std::string() );
+}
+std::string module_impl::format_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const {
+ return format_and_highlight_pattern_row_channel_command( p, r, c, cmd ).first;
+}
+std::string module_impl::highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const {
+ return format_and_highlight_pattern_row_channel_command( p, r, c, cmd ).second;
+}
+
+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();
+ if ( !mpt::is_in_range( p, std::numeric_limits<OpenMPT::PATTERNINDEX>::min(), std::numeric_limits<OpenMPT::PATTERNINDEX>::max() ) || !m_sndFile->Patterns.IsValidPat( static_cast<OpenMPT::PATTERNINDEX>( p ) ) ) {
+ return std::make_pair( text, high );
+ }
+ const OpenMPT::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 >= m_sndFile->GetNumChannels() ) {
+ return std::make_pair( text, high );
+ }
+ // 0000000001111
+ // 1234567890123
+ // "NNN IIvVV EFF"
+ const OpenMPT::ModCommand & cell = *pattern.GetpModCommand( static_cast<OpenMPT::ROWINDEX>( r ), static_cast<OpenMPT::CHANNELINDEX>( c ) );
+ text.clear();
+ high.clear();
+ // clang-format off
+ text += ( cell.IsNote() || cell.IsSpecialNote() ) ? mpt::transcode<std::string>( mpt::common_encoding::utf8, m_sndFile->GetNoteName( cell.note, cell.instr ) ) : std::string("...");
+ high += ( cell.IsNote() ) ? std::string("nnn") : cell.IsSpecialNote() ? std::string("mmm") : std::string("...");
+ if ( ( width == 0 ) || ( width >= 6 ) ) {
+ text += std::string(" ");
+ high += std::string(" ");
+ text += cell.instr ? OpenMPT::mpt::afmt::HEX0<2>( cell.instr ) : std::string("..");
+ high += cell.instr ? std::string("ii") : std::string("..");
+ }
+ if ( ( width == 0 ) || ( width >= 9 ) ) {
+ text += cell.IsPcNote() ? std::string(" ") + OpenMPT::mpt::afmt::HEX0<2>( cell.GetValueVolCol() & 0xff ) : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string( 1, m_sndFile->GetModSpecifications().GetVolEffectLetter( cell.volcmd ) ) + OpenMPT::mpt::afmt::HEX0<2>( cell.vol ) : std::string(" ..");
+ high += cell.IsPcNote() ? std::string(" vv") : cell.volcmd != OpenMPT::VOLCMD_NONE ? std::string("uvv") : std::string(" ..");
+ }
+ if ( ( width == 0 ) || ( width >= 13 ) ) {
+ text += std::string(" ");
+ high += std::string(" ");
+ text += cell.IsPcNote() ? OpenMPT::mpt::afmt::HEX0<3>( cell.GetValueEffectCol() & 0x0fff ) : cell.command != OpenMPT::CMD_NONE ? std::string( 1, m_sndFile->GetModSpecifications().GetEffectLetter( cell.command ) ) + OpenMPT::mpt::afmt::HEX0<2>( cell.param ) : std::string("...");
+ high += cell.IsPcNote() ? std::string("eff") : cell.command != OpenMPT::CMD_NONE ? std::string("eff") : std::string("...");
+ }
+ if ( ( width != 0 ) && ( text.length() > width ) ) {
+ text = text.substr( 0, width );
+ } else if ( ( width != 0 ) && pad ) {
+ text += std::string( width - text.length(), ' ' );
+ }
+ if ( ( width != 0 ) && ( high.length() > width ) ) {
+ high = high.substr( 0, width );
+ } else if ( ( width != 0 ) && pad ) {
+ high += std::string( width - high.length(), ' ' );
+ }
+ // clang-format on
+ return std::make_pair( text, high );
+}
+std::string module_impl::format_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const {
+ return format_and_highlight_pattern_row_channel( p, r, c, width, pad ).first;
+}
+std::string module_impl::highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const {
+ return format_and_highlight_pattern_row_channel( p, r, c, width, pad ).second;
+}
+
+std::pair<const module_impl::ctl_info *, const module_impl::ctl_info *> module_impl::get_ctl_infos() const {
+ static constexpr ctl_info ctl_infos[] = {
+ { "load.skip_samples", ctl_type::boolean },
+ { "load.skip_patterns", ctl_type::boolean },
+ { "load.skip_plugins", ctl_type::boolean },
+ { "load.skip_subsongs_init", ctl_type::boolean },
+ { "seek.sync_samples", ctl_type::boolean },
+ { "subsong", ctl_type::integer },
+ { "play.tempo_factor", ctl_type::floatingpoint },
+ { "play.pitch_factor", ctl_type::floatingpoint },
+ { "play.at_end", ctl_type::text },
+ { "render.resampler.emulate_amiga", ctl_type::boolean },
+ { "render.resampler.emulate_amiga_type", ctl_type::text },
+ { "render.opl.volume_factor", ctl_type::floatingpoint },
+ { "dither", ctl_type::integer }
+ };
+ return std::make_pair(std::begin(ctl_infos), std::end(ctl_infos));
+}
+
+std::vector<std::string> module_impl::get_ctls() const {
+ std::vector<std::string> result;
+ auto ctl_infos = get_ctl_infos();
+ result.reserve(std::distance(ctl_infos.first, ctl_infos.second));
+ for ( std::ptrdiff_t i = 0; i < std::distance(ctl_infos.first, ctl_infos.second); ++i ) {
+ result.push_back(ctl_infos.first[i].name);
+ }
+ return result;
+}
+
+std::string module_impl::ctl_get( std::string ctl, bool throw_if_unknown ) const {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + ctl);
+ } else {
+ return std::string();
+ }
+ }
+ std::string result;
+ switch ( found_ctl->type ) {
+ case ctl_type::boolean:
+ return mpt::format_value_default<std::string>( ctl_get_boolean( ctl, throw_if_unknown ) );
+ break;
+ case ctl_type::integer:
+ return mpt::format_value_default<std::string>( ctl_get_integer( ctl, throw_if_unknown ) );
+ break;
+ case ctl_type::floatingpoint:
+ return mpt::format_value_default<std::string>( ctl_get_floatingpoint( ctl, throw_if_unknown ) );
+ break;
+ case ctl_type::text:
+ return ctl_get_text( ctl, throw_if_unknown );
+ break;
+ }
+ return result;
+}
+bool module_impl::ctl_get_boolean( std::string_view ctl, bool throw_if_unknown ) const {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl));
+ } else {
+ return false;
+ }
+ }
+ if ( found_ctl->type != ctl_type::boolean ) {
+ throw openmpt::exception("wrong ctl value type");
+ }
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) {
+ return m_ctl_load_skip_samples;
+ } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) {
+ return m_ctl_load_skip_patterns;
+ } else if ( ctl == "load.skip_plugins" ) {
+ return m_ctl_load_skip_plugins;
+ } else if ( ctl == "load.skip_subsongs_init" ) {
+ return m_ctl_load_skip_subsongs_init;
+ } else if ( ctl == "seek.sync_samples" ) {
+ return m_ctl_seek_sync_samples;
+ } else if ( ctl == "render.resampler.emulate_amiga" ) {
+ return ( m_sndFile->m_Resampler.m_Settings.emulateAmiga != OpenMPT::Resampling::AmigaFilter::Off );
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ return false;
+ }
+}
+std::int64_t module_impl::ctl_get_integer( std::string_view ctl, bool throw_if_unknown ) const {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl));
+ } else {
+ return 0;
+ }
+ }
+ if ( found_ctl->type != ctl_type::integer ) {
+ throw openmpt::exception("wrong ctl value type");
+ }
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( ctl == "subsong" ) {
+ return get_selected_subsong();
+ } else if ( ctl == "dither" ) {
+ return static_cast<std::int64_t>( m_Dithers->GetMode() );
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ return 0;
+ }
+}
+double module_impl::ctl_get_floatingpoint( std::string_view ctl, bool throw_if_unknown ) const {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl));
+ } else {
+ return 0.0;
+ }
+ }
+ if ( found_ctl->type != ctl_type::floatingpoint ) {
+ throw openmpt::exception("wrong ctl value type");
+ }
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( ctl == "play.tempo_factor" ) {
+ if ( !is_loaded() ) {
+ return 1.0;
+ }
+ return 65536.0 / m_sndFile->m_nTempoFactor;
+ } else if ( ctl == "play.pitch_factor" ) {
+ if ( !is_loaded() ) {
+ return 1.0;
+ }
+ return m_sndFile->m_nFreqFactor / 65536.0;
+ } else if ( ctl == "render.opl.volume_factor" ) {
+ return static_cast<double>( m_sndFile->m_OPLVolumeFactor ) / static_cast<double>( OpenMPT::CSoundFile::m_OPLVolumeFactorScale );
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ return 0.0;
+ }
+}
+std::string module_impl::ctl_get_text( std::string_view ctl, bool throw_if_unknown ) const {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl));
+ } else {
+ return std::string();
+ }
+ }
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl");
+ } else if ( ctl == "play.at_end" ) {
+ switch ( m_ctl_play_at_end )
+ {
+ case song_end_action::fadeout_song:
+ return "fadeout";
+ case song_end_action::continue_song:
+ return "continue";
+ case song_end_action::stop_song:
+ return "stop";
+ default:
+ return std::string();
+ }
+ } else if ( ctl == "render.resampler.emulate_amiga_type" ) {
+ switch ( m_ctl_render_resampler_emulate_amiga_type ) {
+ case amiga_filter_type::a500:
+ return "a500";
+ case amiga_filter_type::a1200:
+ return "a1200";
+ case amiga_filter_type::unfiltered:
+ return "unfiltered";
+ case amiga_filter_type::auto_filter:
+ return "auto";
+ default:
+ return std::string();
+ }
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ return std::string();
+ }
+}
+
+void module_impl::ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown ) {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + value);
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + ctl + " := " + value);
+ } else {
+ return;
+ }
+ }
+ switch ( found_ctl->type ) {
+ case ctl_type::boolean:
+ ctl_set_boolean( ctl, mpt::ConvertStringTo<bool>( value ), throw_if_unknown );
+ break;
+ case ctl_type::integer:
+ ctl_set_integer( ctl, mpt::ConvertStringTo<std::int64_t>( value ), throw_if_unknown );
+ break;
+ case ctl_type::floatingpoint:
+ ctl_set_floatingpoint( ctl, mpt::ConvertStringTo<double>( value ), throw_if_unknown );
+ break;
+ case ctl_type::text:
+ ctl_set_text( ctl, value, throw_if_unknown );
+ break;
+ }
+}
+void module_impl::ctl_set_boolean( std::string_view ctl, bool value, bool throw_if_unknown ) {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + mpt::format_value_default<std::string>( value ) );
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::format_value_default<std::string>(value));
+ } else {
+ return;
+ }
+ }
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + mpt::format_value_default<std::string>( value ) );
+ } else if ( ctl == "load.skip_samples" || ctl == "load_skip_samples" ) {
+ m_ctl_load_skip_samples = value;
+ } else if ( ctl == "load.skip_patterns" || ctl == "load_skip_patterns" ) {
+ m_ctl_load_skip_patterns = value;
+ } else if ( ctl == "load.skip_plugins" ) {
+ m_ctl_load_skip_plugins = value;
+ } else if ( ctl == "load.skip_subsongs_init" ) {
+ m_ctl_load_skip_subsongs_init = value;
+ } else if ( ctl == "seek.sync_samples" ) {
+ m_ctl_seek_sync_samples = value;
+ } else if ( ctl == "render.resampler.emulate_amiga" ) {
+ OpenMPT::CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings;
+ const bool enabled = value;
+ if ( enabled )
+ newsettings.emulateAmiga = translate_amiga_filter_type( m_ctl_render_resampler_emulate_amiga_type );
+ else
+ newsettings.emulateAmiga = OpenMPT::Resampling::AmigaFilter::Off;
+ if ( newsettings != m_sndFile->m_Resampler.m_Settings ) {
+ m_sndFile->SetResamplerSettings( newsettings );
+ }
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ }
+}
+void module_impl::ctl_set_integer( std::string_view ctl, std::int64_t value, bool throw_if_unknown ) {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + mpt::format_value_default<std::string>( value ) );
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::format_value_default<std::string>(value));
+ } else {
+ return;
+ }
+ }
+
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + mpt::format_value_default<std::string>( value ) );
+ } else if ( ctl == "subsong" ) {
+ select_subsong( mpt::saturate_cast<std::int32_t>( value ) );
+ } else if ( ctl == "dither" ) {
+ std::size_t dither = mpt::saturate_cast<std::size_t>( value );
+ if ( dither >= OpenMPT::DithersOpenMPT::GetNumDithers() ) {
+ dither = OpenMPT::DithersOpenMPT::GetDefaultDither();
+ }
+ m_Dithers->SetMode( dither );
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ }
+}
+void module_impl::ctl_set_floatingpoint( std::string_view ctl, double value, bool throw_if_unknown ) {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + mpt::format_value_default<std::string>( value ) );
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + mpt::format_value_default<std::string>(value));
+ } else {
+ return;
+ }
+ }
+
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + mpt::format_value_default<std::string>( value ) );
+ } else if ( ctl == "play.tempo_factor" ) {
+ if ( !is_loaded() ) {
+ return;
+ }
+ double factor = value;
+ if ( factor <= 0.0 || factor > 4.0 ) {
+ throw openmpt::exception("invalid tempo factor");
+ }
+ m_sndFile->m_nTempoFactor = mpt::saturate_round<uint32_t>( 65536.0 / factor );
+ m_sndFile->RecalculateSamplesPerTick();
+ } else if ( ctl == "play.pitch_factor" ) {
+ if ( !is_loaded() ) {
+ return;
+ }
+ double factor = value;
+ if ( factor <= 0.0 || factor > 4.0 ) {
+ throw openmpt::exception("invalid pitch factor");
+ }
+ m_sndFile->m_nFreqFactor = mpt::saturate_round<uint32_t>( 65536.0 * factor );
+ m_sndFile->RecalculateSamplesPerTick();
+ } else if ( ctl == "render.opl.volume_factor" ) {
+ m_sndFile->m_OPLVolumeFactor = mpt::saturate_round<std::int32_t>( value * static_cast<double>( OpenMPT::CSoundFile::m_OPLVolumeFactorScale ) );
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ }
+}
+void module_impl::ctl_set_text( std::string_view ctl, std::string_view value, bool throw_if_unknown ) {
+ if ( !ctl.empty() ) {
+ // cppcheck false-positive
+ // cppcheck-suppress containerOutOfBounds
+ char rightmost = ctl.back();
+ if ( rightmost == '!' || rightmost == '?' ) {
+ if ( rightmost == '!' ) {
+ throw_if_unknown = true;
+ } else if ( rightmost == '?' ) {
+ throw_if_unknown = false;
+ }
+ ctl = ctl.substr( 0, ctl.length() - 1 );
+ }
+ }
+ auto found_ctl = std::find_if(get_ctl_infos().first, get_ctl_infos().second, [&](const ctl_info & info) -> bool { return info.name == ctl; });
+ if ( found_ctl == get_ctl_infos().second ) {
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + std::string( value ) );
+ } else if ( throw_if_unknown ) {
+ throw openmpt::exception("unknown ctl: " + std::string(ctl) + " := " + std::string(value));
+ } else {
+ return;
+ }
+ }
+
+ if ( ctl == "" ) {
+ throw openmpt::exception("empty ctl: := " + std::string( value ) );
+ } else if ( ctl == "play.at_end" ) {
+ if ( value == "fadeout" ) {
+ m_ctl_play_at_end = song_end_action::fadeout_song;
+ } else if(value == "continue") {
+ m_ctl_play_at_end = song_end_action::continue_song;
+ } else if(value == "stop") {
+ m_ctl_play_at_end = song_end_action::stop_song;
+ } else {
+ throw openmpt::exception("unknown song end action:" + std::string(value));
+ }
+ } else if ( ctl == "render.resampler.emulate_amiga_type" ) {
+ if ( value == "a500" ) {
+ m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::a500;
+ } else if ( value == "a1200" ) {
+ m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::a1200;
+ } else if ( value == "unfiltered" ) {
+ m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::unfiltered;
+ } else if ( value == "auto" ) {
+ m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::auto_filter;
+ } else {
+ throw openmpt::exception( "invalid amiga filter type" );
+ }
+ if ( m_sndFile->m_Resampler.m_Settings.emulateAmiga != OpenMPT::Resampling::AmigaFilter::Off ) {
+ OpenMPT::CResamplerSettings newsettings = m_sndFile->m_Resampler.m_Settings;
+ newsettings.emulateAmiga = translate_amiga_filter_type( m_ctl_render_resampler_emulate_amiga_type );
+ if ( newsettings != m_sndFile->m_Resampler.m_Settings ) {
+ m_sndFile->SetResamplerSettings( newsettings );
+ }
+ }
+ } else {
+ MPT_ASSERT_NOTREACHED();
+ }
+}
+
+} // namespace openmpt
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.hpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.hpp
new file mode 100644
index 00000000..cd4b14f6
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_impl.hpp
@@ -0,0 +1,280 @@
+/*
+ * libopenmpt_impl.hpp
+ * -------------------
+ * Purpose: libopenmpt private interface
+ * Notes : This is not a public header. Do NOT ship in distributions dev packages.
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_IMPL_HPP
+#define LIBOPENMPT_IMPL_HPP
+
+#include "libopenmpt_internal.h"
+#include "libopenmpt.hpp"
+
+#include <iosfwd>
+#include <memory>
+#include <utility>
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4512) // assignment operator could not be generated
+#endif
+
+// forward declarations
+namespace mpt {
+inline namespace mpt_libopenmpt {
+namespace IO {
+class FileCursorTraitsFileData;
+template <typename Tpath>
+class FileCursorFilenameTraits;
+template <typename Ttraits, typename Tfilenametraits>
+class FileCursor;
+} // namespace IO
+} // namespace mpt_libopenmpt
+} // namespace mpt
+namespace OpenMPT {
+namespace detail {
+template <typename Ttraits, typename Tfilenametraits>
+using FileCursor = mpt::IO::FileCursor<Ttraits, Tfilenametraits>;
+} // namespace detail
+namespace mpt {
+class PathString;
+} // namespace mpt
+using FileCursor = detail::FileCursor<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>>;
+class CSoundFile;
+struct DithersWrapperOpenMPT;
+} // namespace OpenMPT
+
+namespace openmpt {
+
+namespace version {
+
+std::uint32_t get_library_version();
+std::uint32_t get_core_version();
+std::string get_string( const std::string & key );
+
+} // namespace version
+
+class log_interface {
+protected:
+ log_interface();
+public:
+ virtual ~log_interface();
+ virtual void log( const std::string & message ) const = 0;
+}; // class log_interface
+
+class std_ostream_log : public log_interface {
+private:
+ std::ostream & destination;
+public:
+ std_ostream_log( std::ostream & dst );
+ virtual ~std_ostream_log();
+ void log( const std::string & message ) const override;
+}; // class CSoundFileLog_std_ostream
+
+class log_forwarder;
+
+struct callback_stream_wrapper {
+ void * stream;
+ std::size_t (*read)( void * stream, void * dst, std::size_t bytes );
+ int (*seek)( void * stream, std::int64_t offset, int whence );
+ std::int64_t (*tell)( void * stream );
+}; // struct callback_stream_wrapper
+
+class module_impl {
+public:
+ enum class amiga_filter_type {
+ a500,
+ a1200,
+ unfiltered,
+ auto_filter,
+ };
+
+protected:
+ struct subsong_data {
+ double duration;
+ std::int32_t start_row;
+ std::int32_t start_order;
+ std::int32_t sequence;
+ subsong_data( double duration, std::int32_t start_row, std::int32_t start_order, std::int32_t sequence );
+ }; // struct subsong_data
+
+ typedef std::vector<subsong_data> subsongs_type;
+
+ enum class song_end_action {
+ fadeout_song,
+ continue_song,
+ stop_song,
+ };
+
+ static constexpr std::int32_t all_subsongs = -1;
+
+ enum class ctl_type {
+ boolean,
+ integer,
+ floatingpoint,
+ text,
+ };
+ struct ctl_info {
+ const char * name;
+ ctl_type type;
+ };
+
+ std::unique_ptr<log_interface> m_Log;
+ std::unique_ptr<log_forwarder> m_LogForwarder;
+ std::int32_t m_current_subsong;
+ double m_currentPositionSeconds;
+ std::unique_ptr<OpenMPT::CSoundFile> m_sndFile;
+ bool m_loaded;
+ bool m_mixer_initialized;
+ std::unique_ptr<OpenMPT::DithersWrapperOpenMPT> m_Dithers;
+ subsongs_type m_subsongs;
+ float m_Gain;
+ song_end_action m_ctl_play_at_end;
+ amiga_filter_type m_ctl_render_resampler_emulate_amiga_type = amiga_filter_type::auto_filter;
+ bool m_ctl_load_skip_samples;
+ bool m_ctl_load_skip_patterns;
+ bool m_ctl_load_skip_plugins;
+ bool m_ctl_load_skip_subsongs_init;
+ bool m_ctl_seek_sync_samples;
+ std::vector<std::string> m_loaderMessages;
+public:
+ void PushToCSoundFileLog( const std::string & text ) const;
+ void PushToCSoundFileLog( int loglevel, const std::string & text ) const;
+protected:
+ std::string mod_string_to_utf8( const std::string & encoded ) const;
+ void apply_mixer_settings( std::int32_t samplerate, int channels );
+ void apply_libopenmpt_defaults();
+ subsongs_type get_subsongs() const;
+ void init_subsongs( subsongs_type & subsongs ) const;
+ bool has_subsongs_inited() const;
+ void ctor( const std::map< std::string, std::string > & ctls );
+ void load( const OpenMPT::FileCursor & file, const std::map< std::string, std::string > & ctls );
+ bool is_loaded() const;
+ std::size_t read_wrapper( std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right );
+ std::size_t read_wrapper( std::size_t count, float * left, float * right, float * rear_left, float * rear_right );
+ std::size_t read_interleaved_wrapper( std::size_t count, std::size_t channels, std::int16_t * interleaved );
+ std::size_t read_interleaved_wrapper( std::size_t count, std::size_t channels, float * interleaved );
+ std::string get_message_instruments() const;
+ std::string get_message_samples() const;
+ 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;
+ static double could_open_probability( const OpenMPT::FileCursor & file, double effort, std::unique_ptr<log_interface> log );
+public:
+ static std::vector<std::string> get_supported_extensions();
+
+ /// <summary>
+ /// From version 0.7.0
+ /// Hakan DANISIK
+ /// </summary>
+ /// <param name="extension"></param>
+ /// <returns></returns>
+ static std::string get_tracker_name( const std::string & extension );
+
+ static bool is_extension_supported( std::string_view extension );
+ 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::byte * 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, 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::byte * data, std::size_t size );
+ 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::byte> & data, 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::byte * data, std::size_t size, 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;
+ double set_position_seconds( double seconds );
+ double get_position_seconds() const;
+ double set_position_order_row( std::int32_t order, std::int32_t row );
+ std::int32_t get_render_param( int param ) const;
+ void set_render_param( int param, std::int32_t value );
+ std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * mono );
+ std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right );
+ std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right );
+ std::size_t read( std::int32_t samplerate, std::size_t count, float * mono );
+ std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right );
+ std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right );
+ std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo );
+ std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad );
+ std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo );
+ std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad );
+ std::vector<std::string> get_metadata_keys() const;
+ std::string get_metadata( const std::string & key ) const;
+ double get_current_estimated_bpm() const;
+ std::int32_t get_current_speed() const;
+ std::int32_t get_current_tempo() const;
+ std::int32_t get_current_order() const;
+ std::int32_t get_current_pattern() const;
+ std::int32_t get_current_row() const;
+ std::int32_t get_current_playing_channels() const;
+ float get_current_channel_vu_mono( std::int32_t channel ) const;
+ float get_current_channel_vu_left( std::int32_t channel ) const;
+ float get_current_channel_vu_right( std::int32_t channel ) const;
+ float get_current_channel_vu_rear_left( std::int32_t channel ) const;
+ float get_current_channel_vu_rear_right( std::int32_t channel ) const;
+ std::int32_t get_num_subsongs() const;
+ std::int32_t get_num_channels() const;
+ std::int32_t get_num_orders() const;
+ std::int32_t get_num_patterns() const;
+ std::int32_t get_num_instruments() const;
+ std::int32_t get_num_samples() const;
+ std::vector<std::string> get_subsong_names() const;
+ std::vector<std::string> get_channel_names() const;
+ std::vector<std::string> get_order_names() const;
+ std::vector<std::string> get_pattern_names() const;
+ std::vector<std::string> get_instrument_names() const;
+ std::vector<std::string> get_sample_names() const;
+ std::int32_t get_order_pattern( std::int32_t o ) const;
+ std::int32_t get_pattern_num_rows( std::int32_t p ) const;
+ std::uint8_t get_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const;
+ std::string format_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const;
+ std::string highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int cmd ) const;
+ std::string format_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const;
+ std::string highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const;
+ std::pair<const module_impl::ctl_info *, const module_impl::ctl_info *> get_ctl_infos() const;
+ std::vector<std::string> get_ctls() const;
+ std::string ctl_get( std::string ctl, bool throw_if_unknown = true ) const;
+ bool ctl_get_boolean( std::string_view ctl, bool throw_if_unknown = true ) const;
+ std::int64_t ctl_get_integer( std::string_view ctl, bool throw_if_unknown = true ) const;
+ double ctl_get_floatingpoint( std::string_view ctl, bool throw_if_unknown = true ) const;
+ std::string ctl_get_text( std::string_view ctl, bool throw_if_unknown = true ) const;
+ void ctl_set( std::string ctl, const std::string & value, bool throw_if_unknown = true );
+ void ctl_set_boolean( std::string_view ctl, bool value, bool throw_if_unknown = true );
+ void ctl_set_integer( std::string_view ctl, std::int64_t value, bool throw_if_unknown = true );
+ void ctl_set_floatingpoint( std::string_view ctl, double value, bool throw_if_unknown = true );
+ void ctl_set_text( std::string_view ctl, std::string_view 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)
+#pragma warning(pop)
+#endif
+
+#endif // LIBOPENMPT_IMPL_HPP
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_internal.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_internal.h
new file mode 100644
index 00000000..dcb321d9
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_internal.h
@@ -0,0 +1,25 @@
+/*
+ * libopenmpt_internal.h
+ * ---------------------
+ * Purpose: libopenmpt internal interface configuration, overruling the public interface configuration (only used and needed when building libopenmpt)
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_INTERNAL_H
+#define LIBOPENMPT_INTERNAL_H
+
+#include "libopenmpt_config.h"
+
+#ifdef __cplusplus
+#if defined(LIBOPENMPT_BUILD_DLL) || defined(LIBOPENMPT_USE_DLL)
+#if defined(_MSC_VER) && !defined(_DLL)
+/* #pragma message( "libopenmpt C++ interface is disabled if libopenmpt is built as a DLL and the runtime is statically linked. This is not supported by microsoft and cannot possibly work. Ever." ) */
+#undef LIBOPENMPT_CXX_API
+#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL
+#endif
+#endif
+#endif
+
+#endif /* LIBOPENMPT_INTERNAL_H */
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.cpp
new file mode 100644
index 00000000..c185b21f
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.cpp
@@ -0,0 +1,497 @@
+/*
+ * libopenmpt_plugin_gui.cpp
+ * -------------------------
+ * Purpose: libopenmpt plugin GUI
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#if !defined(WINVER) && !defined(_WIN32_WINDOWS)
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
+#endif
+#endif
+#if !defined(MPT_BUILD_RETRO)
+#if defined(_MSC_VER)
+#define MPT_WITH_MFC
+#endif
+#else
+#if defined(_WIN32_WINNT)
+#if (_WIN32_WINNT >= 0x0501)
+#if defined(_MSC_VER)
+#define MPT_WITH_MFC
+#endif
+#endif
+#endif
+#endif
+#if defined(MPT_WITH_MFC)
+#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls
+#endif // MPT_WITH_MFC
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#if !defined(MPT_WITH_MFC)
+#include <fstream>
+#include <locale>
+#include <sstream>
+#include <string>
+#include <vector>
+#endif
+
+#if !defined(MPT_WITH_MFC)
+#include <windows.h>
+#endif
+
+#if defined(MPT_WITH_MFC)
+#include <afxwin.h>
+#include <afxcmn.h>
+#endif // MPT_WITH_MFC
+
+#if defined(MPT_WITH_MFC)
+#include "resource.h"
+#endif // MPT_WITH_MFC
+
+#include "libopenmpt_plugin_gui.hpp"
+
+
+namespace libopenmpt {
+namespace plugin {
+
+
+#if defined(MPT_WITH_MFC)
+
+
+class CSettingsApp : public CWinApp {
+
+public:
+
+ BOOL InitInstance() override {
+ if ( !CWinApp::InitInstance() )
+ {
+ return FALSE;
+ }
+ DllMainAttach();
+ return TRUE;
+ }
+
+ int ExitInstance() override {
+ DllMainDetach();
+ return CWinApp::ExitInstance();
+ }
+
+};
+
+
+CSettingsApp theApp;
+
+
+class CSettingsDialog : public CDialog {
+
+protected:
+
+ DECLARE_MESSAGE_MAP()
+
+ libopenmpt_settings * s;
+
+ CString m_Title;
+
+ CComboBox m_ComboBoxSamplerate;
+ CComboBox m_ComboBoxChannels;
+ CSliderCtrl m_SliderCtrlGain;
+ CComboBox m_ComboBoxInterpolation;
+ CButton m_CheckBoxAmigaResampler;
+ CComboBox m_ComboBoxAmigaFilter;
+ CComboBox m_ComboBoxRepeat;
+ CSliderCtrl m_SliderCtrlStereoSeparation;
+ CComboBox m_ComboBoxRamping;
+
+public:
+
+ CSettingsDialog( libopenmpt_settings * s_, CString title, CWnd * parent = nullptr )
+ : CDialog( IDD_SETTINGS, parent )
+ , s( s_ )
+ , m_Title( title )
+ {
+ return;
+ }
+
+protected:
+
+ void DoDataExchange( CDataExchange * pDX ) override
+ {
+ CDialog::DoDataExchange( pDX );
+ DDX_Control( pDX, IDC_COMBO_SAMPLERATE, m_ComboBoxSamplerate );
+ DDX_Control( pDX, IDC_COMBO_CHANNELS, m_ComboBoxChannels );
+ DDX_Control( pDX, IDC_SLIDER_GAIN, m_SliderCtrlGain );
+ DDX_Control( pDX, IDC_COMBO_INTERPOLATION, m_ComboBoxInterpolation );
+ DDX_Control( pDX, IDC_CHECK_AMIGA_RESAMPLER, m_CheckBoxAmigaResampler );
+ DDX_Control( pDX, IDC_COMBO_AMIGA_FILTER, m_ComboBoxAmigaFilter );
+ DDX_Control( pDX, IDC_COMBO_REPEAT, m_ComboBoxRepeat );
+ DDX_Control( pDX, IDC_SLIDER_STEREOSEPARATION, m_SliderCtrlStereoSeparation );
+ DDX_Control( pDX, IDC_COMBO_RAMPING, m_ComboBoxRamping );
+ }
+
+ afx_msg BOOL OnInitDialog() override {
+
+ CDialog::OnInitDialog();
+
+ SetWindowText( m_Title );
+ EnableToolTips();
+
+ bool selected = false;
+
+ selected = false;
+ if ( !s->no_default_format ) {
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"Default" ), 0 );
+ }
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"6000" ), 6000 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"8000" ), 8000 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"11025" ), 11025 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"16000" ), 16000 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"22050" ), 22050 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"32000" ), 32000 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"44100" ), 44100 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"48000" ), 48000 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"88200" ), 88200 );
+ m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"96000" ), 96000 );
+ if ( !s->no_default_format && s->samplerate == 0 ) {
+ m_ComboBoxSamplerate.SelectString( 0, L"Default" );
+ }
+ for ( int index = 0; index < m_ComboBoxSamplerate.GetCount(); ++index ) {
+ if ( static_cast<int>( m_ComboBoxSamplerate.GetItemData( index ) ) == s->samplerate ) {
+ m_ComboBoxSamplerate.SetCurSel( index );
+ selected = true;
+ }
+ }
+ if ( !selected ) {
+ m_ComboBoxSamplerate.SelectString( 0, L"48000" );
+ }
+
+ selected = false;
+ if ( !s->no_default_format ) {
+ m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Default" ), 0 );
+ }
+ m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Mono" ), 1 );
+ m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Stereo" ), 2 );
+ m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Quad" ), 4 );
+ if ( !s->no_default_format && s->channels == 0 ) {
+ m_ComboBoxChannels.SelectString( 0, L"Default" );
+ }
+ for ( int index = 0; index < m_ComboBoxChannels.GetCount(); ++index ) {
+ if ( static_cast<int>( m_ComboBoxChannels.GetItemData( index ) ) == s->channels ) {
+ m_ComboBoxChannels.SetCurSel( index );
+ selected = true;
+ }
+ }
+ if ( !selected ) {
+ m_ComboBoxChannels.SelectString( 0, L"Stereo" );
+ }
+
+ m_SliderCtrlGain.SetRange( -1200, 1200 );
+ m_SliderCtrlGain.SetTicFreq( 100 );
+ m_SliderCtrlGain.SetPageSize( 300 );
+ m_SliderCtrlGain.SetLineSize( 100 );
+ m_SliderCtrlGain.SetPos( s->mastergain_millibel );
+
+ selected = false;
+ m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"Off / 1 Tap (Nearest)" ), 1 );
+ m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"2 Tap (Linear)" ), 2 );
+ m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"4 Tap (Cubic)" ), 4 );
+ m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"8 Tap (Polyphase FIR)" ), 8 );
+ for ( int index = 0; index < m_ComboBoxInterpolation.GetCount(); ++index ) {
+ if ( static_cast<int>( m_ComboBoxInterpolation.GetItemData( index ) ) == s->interpolationfilterlength ) {
+ m_ComboBoxInterpolation.SetCurSel( index );
+ selected = true;
+ }
+ }
+ if ( !selected ) {
+ m_ComboBoxInterpolation.SelectString( 0, L"8 Tap (Polyphase FIR)" );
+ }
+
+ m_CheckBoxAmigaResampler.SetCheck( s->use_amiga_resampler ? BST_CHECKED : BST_UNCHECKED );
+ selected = false;
+ m_ComboBoxAmigaFilter.EnableWindow( s->use_amiga_resampler ? TRUE : FALSE );
+ m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Default" ), 0 );
+ m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A500 Filter" ), 0xA500 );
+ m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A1200 Filter" ), 0xA1200 );
+ m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Unfiltered" ), 1 );
+ for ( int index = 0; index < m_ComboBoxAmigaFilter.GetCount(); ++index ) {
+ if ( static_cast<int>( m_ComboBoxAmigaFilter.GetItemData( index ) ) == s->amiga_filter_type ) {
+ m_ComboBoxAmigaFilter.SetCurSel( index );
+ selected = true;
+ }
+ }
+ if ( !selected ) {
+ m_ComboBoxAmigaFilter.SelectString( 0, L"Default" );
+ }
+
+ selected = false;
+ m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Forever" ), static_cast<unsigned int>( -1 ) );
+ m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Never" ), 0 );
+ m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Once" ), 1 );
+ for ( int index = 0; index < m_ComboBoxRepeat.GetCount(); ++index ) {
+ if ( static_cast<int>( m_ComboBoxRepeat.GetItemData( index ) ) == s->repeatcount ) {
+ m_ComboBoxRepeat.SetCurSel( index );
+ selected = true;
+ }
+ }
+ if ( !selected ) {
+ m_ComboBoxRepeat.SelectString( 0, L"Never" );
+ }
+
+ m_SliderCtrlStereoSeparation.SetRange( 0, 200 );
+ m_SliderCtrlStereoSeparation.SetTicFreq( 100 );
+ m_SliderCtrlStereoSeparation.SetPageSize( 25 );
+ m_SliderCtrlStereoSeparation.SetLineSize( 5 );
+ m_SliderCtrlStereoSeparation.SetPos( s->stereoseparation );
+
+ selected = false;
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Default" ), static_cast<unsigned int>( -1 ) );
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Off" ), 0 );
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"1 ms" ), 1 );
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"2 ms" ), 2 );
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"3 ms" ), 3 );
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"5 ms" ), 5 );
+ m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"10 ms" ), 10 );
+ for ( int index = 0; index < m_ComboBoxRamping.GetCount(); ++index ) {
+ if ( static_cast<int>( m_ComboBoxRamping.GetItemData( index ) ) == s->ramping ) {
+ m_ComboBoxRamping.SetCurSel( index );
+ selected = true;
+ }
+ }
+ if ( !selected ) {
+ m_ComboBoxRamping.SelectString( 0, L"Default" );
+ }
+
+ return TRUE;
+
+ }
+
+ void OnOK() override {
+
+ s->samplerate = m_ComboBoxSamplerate.GetItemData( m_ComboBoxSamplerate.GetCurSel() );
+
+ s->channels = m_ComboBoxChannels.GetItemData( m_ComboBoxChannels.GetCurSel() );
+
+ s->mastergain_millibel = m_SliderCtrlGain.GetPos();
+
+ s->interpolationfilterlength = m_ComboBoxInterpolation.GetItemData( m_ComboBoxInterpolation.GetCurSel() );
+
+ s->use_amiga_resampler = ( m_CheckBoxAmigaResampler.GetCheck() != BST_UNCHECKED ) ? 1 : 0;
+ s->amiga_filter_type = m_ComboBoxAmigaFilter.GetItemData( m_ComboBoxAmigaFilter.GetCurSel() );
+
+ s->repeatcount = m_ComboBoxRepeat.GetItemData( m_ComboBoxRepeat.GetCurSel() );
+
+ s->stereoseparation = m_SliderCtrlStereoSeparation.GetPos();
+
+ s->ramping = m_ComboBoxRamping.GetItemData( m_ComboBoxRamping.GetCurSel() );
+
+ s->changed();
+
+ CDialog::OnOK();
+
+ }
+
+ BOOL OnToolTipText( UINT, NMHDR * pNMHDR, LRESULT * pResult ) {
+ TOOLTIPTEXT * pTTT = reinterpret_cast<TOOLTIPTEXT *>( pNMHDR );
+
+ UINT_PTR nID = pNMHDR->idFrom;
+ if( pTTT->uFlags & TTF_IDISHWND )
+ {
+ // idFrom is actually the HWND of the tool
+ nID = (UINT_PTR)::GetDlgCtrlID((HWND)nID);
+ }
+
+ switch ( nID ) {
+ case IDC_SLIDER_GAIN:
+ swprintf( pTTT->szText, _countof(pTTT->szText), L"%.02f dB", m_SliderCtrlGain.GetPos() * 0.01f );
+ break;
+
+ case IDC_SLIDER_STEREOSEPARATION:
+ swprintf( pTTT->szText, _countof(pTTT->szText), L"%d %%", m_SliderCtrlStereoSeparation.GetPos());
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ *pResult = 0;
+ return TRUE;
+ }
+
+ void OnAmigaResamplerChanged() {
+ m_ComboBoxAmigaFilter.EnableWindow( IsDlgButtonChecked( IDC_CHECK_AMIGA_RESAMPLER ) != BST_UNCHECKED ? TRUE : FALSE );
+ }
+
+};
+
+BEGIN_MESSAGE_MAP(CSettingsDialog, CDialog)
+ ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CSettingsDialog::OnToolTipText)
+ ON_COMMAND( IDC_CHECK_AMIGA_RESAMPLER, &CSettingsDialog::OnAmigaResamplerChanged )
+END_MESSAGE_MAP()
+
+
+
+class CInfoDialog : public CDialog {
+
+protected:
+
+ CString m_Title;
+ CString m_FileInfo;
+ CEdit m_EditFileInfo;
+
+public:
+
+ CInfoDialog( CString title, CString info, CWnd * parent = NULL )
+ : CDialog( IDD_FILEINFO, parent )
+ , m_Title( title )
+ , m_FileInfo( info )
+ {
+ return;
+ }
+
+protected:
+
+ void DoDataExchange( CDataExchange * pDX ) override
+ {
+ CDialog::DoDataExchange( pDX );
+ DDX_Control( pDX, IDC_FILEINFO, m_EditFileInfo );
+ }
+
+ afx_msg BOOL OnInitDialog() override {
+
+ if ( !CDialog::OnInitDialog() ) {
+ return false;
+ }
+
+ SetWindowText( m_Title );
+
+ m_EditFileInfo.SetWindowText( m_FileInfo );
+
+ return TRUE;
+
+ }
+
+};
+
+
+#endif // MPT_WITH_MFC
+
+
+#if defined(MPT_WITH_MFC)
+
+void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::wstring title ) {
+ AFX_MANAGE_STATE( AfxGetStaticModuleState() );
+ CSettingsDialog dlg( s, title.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr );
+ dlg.DoModal();
+}
+
+
+void gui_show_file_info( HWND parent, std::wstring title, std::wstring info ) {
+ AFX_MANAGE_STATE( AfxGetStaticModuleState() );
+ CInfoDialog dlg( title.c_str(), info.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr);
+ dlg.DoModal();
+}
+
+
+#else // !MPT_WITH_MFC
+
+
+static std::basic_string<TCHAR> GetTempDirectory() {
+ DWORD size = GetTempPath(0, nullptr);
+ if (size) {
+ std::vector<TCHAR> tempPath(size + 1);
+ if (GetTempPath(size + 1, tempPath.data())) {
+ return tempPath.data();
+ }
+ }
+ return {};
+}
+
+static std::basic_string<TCHAR> GetTempFilename( std::basic_string<TCHAR> prefix ) {
+ std::vector<TCHAR> buf(MAX_PATH);
+ if (GetTempFileName(GetTempDirectory().c_str(), prefix.c_str(), 0, buf.data()) == 0) {
+ return {};
+ }
+ return buf.data();
+}
+
+template <typename T>
+static std::basic_string<TCHAR> as_string( T x ) {
+ std::basic_ostringstream<TCHAR> s;
+ s.imbue(std::locale::classic());
+ s << x;
+ return s.str();
+}
+
+
+void gui_edit_settings( libopenmpt_settings * s, HWND /* parent */ , std::basic_string<TCHAR> title ) {
+ std::basic_string<TCHAR> filename = GetTempFilename( title );
+ WritePrivateProfileString( title.c_str(), TEXT("Samplerate_Hz"), as_string( s->samplerate ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("Channels"), as_string( s->channels ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("MasterGain_milliBel"), as_string( s->mastergain_millibel ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("StereoSeparation_Percent"), as_string( s->stereoseparation ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("RepeatCount"), as_string( s->repeatcount ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("InterpolationFilterLength"), as_string( s->interpolationfilterlength ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("UseAmigaResampler"), as_string( s->use_amiga_resampler ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("AmigaFilterType"), as_string( s->amiga_filter_type ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("VolumeRampingStrength"), as_string( s->ramping ).c_str(), filename.c_str() );
+ WritePrivateProfileString( title.c_str(), TEXT("VisAllowScroll"), as_string( s->vis_allow_scroll ).c_str(), filename.c_str() );
+ STARTUPINFO startupInfo = {};
+ startupInfo.cb = sizeof(startupInfo);
+ PROCESS_INFORMATION processInformation = {};
+ std::basic_string<TCHAR> command = std::basic_string<TCHAR>(TEXT("notepad.exe")) + TEXT(" ") + filename;
+ std::vector<TCHAR> commandBuf{ command.c_str(), command.c_str() + command.length() + 1 };
+ if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) {
+ MessageBox(NULL, as_string(GetLastError()).c_str(), TEXT("fail"), 0);
+ return;
+ }
+ CloseHandle( processInformation.hThread );
+ WaitForSingleObject( processInformation.hProcess, INFINITE );
+ CloseHandle( processInformation.hProcess );
+ s->samplerate = GetPrivateProfileInt( title.c_str(), TEXT("Samplerate_Hz"), libopenmpt_settings{}.samplerate, filename.c_str() );
+ s->channels = GetPrivateProfileInt( title.c_str(), TEXT("Channels"), libopenmpt_settings{}.channels, filename.c_str() );
+ s->mastergain_millibel = GetPrivateProfileInt( title.c_str(), TEXT("MasterGain_milliBel"), libopenmpt_settings{}.mastergain_millibel, filename.c_str() );
+ s->stereoseparation = GetPrivateProfileInt( title.c_str(), TEXT("StereoSeparation_Percent"), libopenmpt_settings{}.stereoseparation, filename.c_str() );
+ s->repeatcount = GetPrivateProfileInt( title.c_str(), TEXT("RepeatCount"), libopenmpt_settings{}.repeatcount, filename.c_str() );
+ s->interpolationfilterlength = GetPrivateProfileInt( title.c_str(), TEXT("InterpolationFilterLength"), libopenmpt_settings{}.interpolationfilterlength, filename.c_str() );
+ s->use_amiga_resampler = GetPrivateProfileInt( title.c_str(), TEXT("UseAmigaResampler"), libopenmpt_settings{}.use_amiga_resampler, filename.c_str() );
+ s->amiga_filter_type = GetPrivateProfileInt( title.c_str(), TEXT("AmigaFilterType"), libopenmpt_settings{}.amiga_filter_type, filename.c_str() );
+ s->ramping = GetPrivateProfileInt( title.c_str(), TEXT("VolumeRampingStrength"), libopenmpt_settings{}.ramping, filename.c_str() );
+ s->vis_allow_scroll = GetPrivateProfileInt( title.c_str(), TEXT("VisAllowScroll"), libopenmpt_settings{}.vis_allow_scroll, filename.c_str() );
+ DeleteFile( filename.c_str() );
+}
+
+
+void gui_show_file_info( HWND /* parent */ , std::basic_string<TCHAR> title, std::basic_string<TCHAR> info ) {
+ std::basic_string<TCHAR> filename = GetTempFilename( title );
+ {
+ std::basic_ofstream<TCHAR> f( filename.c_str(), std::ios::out );
+ f << info;
+ }
+ STARTUPINFO startupInfo = {};
+ startupInfo.cb = sizeof(startupInfo);
+ PROCESS_INFORMATION processInformation = {};
+ std::basic_string<TCHAR> command = std::basic_string<TCHAR>(TEXT("notepad.exe")) + TEXT(" ") + filename;
+ std::vector<TCHAR> commandBuf{ command.c_str(), command.c_str() + command.length() + 1 };
+ if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) {
+ return;
+ }
+ CloseHandle( processInformation.hThread );
+ WaitForSingleObject( processInformation.hProcess, INFINITE );
+ CloseHandle( processInformation.hProcess );
+ DeleteFile( filename.c_str() );
+}
+
+
+#endif // MPT_WITH_MFC
+
+
+} // namespace plugin
+} // namespace libopenmpt
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.hpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.hpp
new file mode 100644
index 00000000..1cc38786
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.hpp
@@ -0,0 +1,36 @@
+/*
+ * libopenmpt_plugin_gui.hpp
+ * -------------------------
+ * Purpose: libopenmpt plugin GUI
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_PLUGIN_GUI_HPP
+#define LIBOPENMPT_PLUGIN_GUI_HPP
+
+#include "libopenmpt_plugin_settings.hpp"
+
+#include <windows.h>
+
+#include <string>
+
+namespace libopenmpt {
+namespace plugin {
+
+#if defined(MPT_WITH_MFC)
+
+void DllMainAttach();
+void DllMainDetach();
+
+#endif // MPT_WITH_MFC
+
+void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::basic_string<TCHAR> title );
+
+void gui_show_file_info( HWND parent, std::basic_string<TCHAR> title, std::basic_string<TCHAR> info );
+
+} // namespace plugin
+} // namespace libopenmpt
+
+#endif // LIBOPENMPT_PLUGIN_GUI_HPP
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.rc b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.rc
new file mode 100644
index 00000000..78cebd0d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_gui.rc
@@ -0,0 +1,147 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Germany) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SETTINGS DIALOGEX 0, 0, 201, 200
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&OK",IDOK,78,180,54,14
+ PUSHBUTTON "&Cancel",IDCANCEL,138,180,54,14
+ LTEXT "&Samplerate",IDC_STATIC,6,6,60,12,SS_CENTERIMAGE
+ COMBOBOX IDC_COMBO_SAMPLERATE,72,6,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "C&hannels",IDC_STATIC,6,24,60,12,SS_CENTERIMAGE
+ COMBOBOX IDC_COMBO_CHANNELS,72,24,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "&Gain",IDC_STATIC,6,42,60,12,SS_CENTERIMAGE
+ CONTROL "",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,72,42,120,15
+ LTEXT "&Interpolation",IDC_STATIC,6,60,60,12,SS_CENTERIMAGE
+ COMBOBOX IDC_COMBO_INTERPOLATION,72,60,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Use &Amiga resampler for Amiga modules",IDC_CHECK_AMIGA_RESAMPLER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,78,186,12
+ LTEXT "Amiga &Filter Type:",IDC_STATIC,6,96,60,12,SS_CENTERIMAGE
+ COMBOBOX IDC_COMBO_AMIGA_FILTER,72,96,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "&Repeat",IDC_STATIC,6,114,60,12,SS_CENTERIMAGE
+ COMBOBOX IDC_COMBO_REPEAT,72,114,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "S&tereo Separation",IDC_STATIC,6,132,60,12,SS_CENTERIMAGE
+ CONTROL "",IDC_SLIDER_STEREOSEPARATION,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,72,132,126,15
+ LTEXT "&Volume Ramping",IDC_STATIC,6,151,60,12,SS_CENTERIMAGE
+ COMBOBOX IDC_COMBO_RAMPING,72,151,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,6,175,186,1
+END
+
+IDD_FILEINFO DIALOGEX 0, 0, 310, 174
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,258,156,48,12
+ EDITTEXT IDC_FILEINFO,6,6,300,144,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SETTINGS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 194
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 193
+ END
+
+ IDD_FILEINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 303
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 167
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_SETTINGS AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_FILEINFO AFX_DIALOG_LAYOUT
+BEGIN
+ 0,
+ 100, 100, 0, 0,
+ 0, 0, 100, 100
+END
+
+#endif // German (Germany) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_settings.hpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_settings.hpp
new file mode 100644
index 00000000..d77ca022
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_plugin_settings.hpp
@@ -0,0 +1,130 @@
+/*
+ * libopenmpt_plugin_settings.hpp
+ * ------------------------------
+ * Purpose: libopenmpt plugin settings
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_PLUGIN_SETTINGS_HPP
+#define LIBOPENMPT_PLUGIN_SETTINGS_HPP
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include <windows.h>
+
+#include <string>
+
+
+namespace libopenmpt {
+namespace plugin {
+
+
+typedef void (*changed_func)();
+
+struct libopenmpt_settings {
+ bool no_default_format = true;
+ int samplerate = 48000;
+ int channels = 2;
+ int mastergain_millibel = 0;
+ int stereoseparation = 100;
+ int use_amiga_resampler = 0;
+ int amiga_filter_type = 0;
+ int repeatcount = 0;
+ int interpolationfilterlength = 8;
+ int ramping = -1;
+ int vis_allow_scroll = 1;
+ changed_func changed = nullptr;
+};
+
+
+class settings : public libopenmpt_settings {
+private:
+ std::basic_string<TCHAR> subkey;
+protected:
+ virtual void read_setting( const std::string & /* key */ , const std::basic_string<TCHAR> & key, int & val ) {
+ HKEY regkey = HKEY();
+ if ( RegOpenKeyEx( HKEY_CURRENT_USER, ( TEXT("Software\\libopenmpt\\") + subkey ).c_str(), 0, KEY_READ, &regkey ) == ERROR_SUCCESS ) {
+ DWORD v = val;
+ DWORD type = REG_DWORD;
+ DWORD typesize = sizeof(v);
+ if ( RegQueryValueEx( regkey, key.c_str(), NULL, &type, (BYTE *)&v, &typesize ) == ERROR_SUCCESS )
+ {
+ val = v;
+ }
+ RegCloseKey( regkey );
+ regkey = HKEY();
+ }
+ }
+ virtual void write_setting( const std::string & /* key */, const std::basic_string<TCHAR> & key, int val ) {
+ HKEY regkey = HKEY();
+ if ( RegCreateKeyEx( HKEY_CURRENT_USER, ( TEXT("Software\\libopenmpt\\") + subkey ).c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &regkey, NULL ) == ERROR_SUCCESS ) {
+ DWORD v = val;
+ DWORD type = REG_DWORD;
+ DWORD typesize = sizeof(v);
+ if ( RegSetValueEx( regkey, key.c_str(), 0, type, (const BYTE *)&v, typesize ) == ERROR_SUCCESS )
+ {
+ // ok
+ }
+ RegCloseKey( regkey );
+ regkey = HKEY();
+ }
+ }
+public:
+ settings( const std::basic_string<TCHAR> & subkey, bool no_default_format_ )
+ : subkey(subkey)
+ {
+ no_default_format = no_default_format_;
+ }
+ void load()
+ {
+ #ifdef UNICODE
+ #define read_setting(a,b,c) read_setting( b , L ## b , c)
+ #else
+ #define read_setting(a,b,c) read_setting( b , b , c)
+ #endif
+ read_setting( subkey, "Samplerate_Hz", samplerate );
+ read_setting( subkey, "Channels", channels );
+ read_setting( subkey, "MasterGain_milliBel", mastergain_millibel );
+ read_setting( subkey, "StereoSeparation_Percent", stereoseparation );
+ read_setting( subkey, "RepeatCount", repeatcount );
+ read_setting( subkey, "InterpolationFilterLength", interpolationfilterlength );
+ read_setting( subkey, "UseAmigaResampler", use_amiga_resampler );
+ read_setting( subkey, "AmigaFilterType", amiga_filter_type );
+ read_setting( subkey, "VolumeRampingStrength", ramping );
+ read_setting( subkey, "VisAllowScroll", vis_allow_scroll );
+ #undef read_setting
+ }
+ void save()
+ {
+ #ifdef UNICODE
+ #define write_setting(a,b,c) write_setting( b , L ## b , c)
+ #else
+ #define write_setting(a,b,c) write_setting( b , b , c)
+ #endif
+ write_setting( subkey, "Samplerate_Hz", samplerate );
+ write_setting( subkey, "Channels", channels );
+ write_setting( subkey, "MasterGain_milliBel", mastergain_millibel );
+ write_setting( subkey, "StereoSeparation_Percent", stereoseparation );
+ write_setting( subkey, "RepeatCount", repeatcount );
+ write_setting( subkey, "InterpolationFilterLength", interpolationfilterlength );
+ write_setting( subkey, "UseAmigaResampler", use_amiga_resampler );
+ write_setting( subkey, "AmigaFilterType", amiga_filter_type );
+ write_setting( subkey, "VolumeRampingStrength", ramping );
+ write_setting( subkey, "VisAllowScroll", vis_allow_scroll );
+ #undef write_setting
+ }
+ virtual ~settings()
+ {
+ return;
+ }
+};
+
+
+} // namespace plugin
+} // namespace libopenmpt
+
+
+#endif // LIBOPENMPT_PLUGIN_SETTINGS_HPP
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_buffer.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_buffer.h
new file mode 100644
index 00000000..575049e4
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_buffer.h
@@ -0,0 +1,198 @@
+/*
+ * 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>
+
+/*! \addtogroup libopenmpt_c
+ * @{
+ */
+
+#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 )
+
+/*! \brief Provide openmpt_stream_callbacks for in-memoy buffers
+ *
+ * Fills openmpt_stream_callbacks suitable for passing an in-memory buffer as a stream parameter to functions doing file input/output.
+ *
+ * \remarks The stream argument must be passed as `(void*)(openmpt_stream_buffer*)stream_buffer`.
+ * \sa \ref libopenmpt_c_fileio
+ * \sa openmpt_stream_callbacks
+ * \sa openmpt_could_open_probability2
+ * \sa openmpt_probe_file_header_from_stream
+ * \sa openmpt_module_create2
+ */
+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/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_fd.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_fd.h
new file mode 100644
index 00000000..46b39f12
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_fd.h
@@ -0,0 +1,101 @@
+/*
+ * libopenmpt_stream_callbacks_fd.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_FD_H
+#define LIBOPENMPT_STREAM_CALLBACKS_FD_H
+
+#include "libopenmpt.h"
+
+#ifdef _MSC_VER
+#include <io.h>
+#endif
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+
+/*! \addtogroup libopenmpt_c
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This stuff has to be in a header file because of possibly different MSVC CRTs which cause problems for fd crossing CRT boundaries. */
+
+static size_t openmpt_stream_fd_read_func( void * stream, void * dst, size_t bytes ) {
+ int fd = 0;
+ #if defined(_MSC_VER)
+ size_t retval = 0;
+ int to_read = 0;
+ int ret_read = 0;
+ #else
+ ssize_t retval = 0;
+ #endif
+ fd = (int)(uintptr_t)stream;
+ if ( fd < 0 ) {
+ return 0;
+ }
+ #if defined(_MSC_VER)
+ retval = 0;
+ while ( bytes > 0 ) {
+ to_read = 0;
+ if ( bytes < (size_t)INT_MAX ) {
+ to_read = (int)bytes;
+ } else {
+ to_read = INT_MAX;
+ }
+ ret_read = _read( fd, dst, to_read );
+ if ( ret_read <= 0 ) {
+ return retval;
+ }
+ bytes -= ret_read;
+ retval += ret_read;
+ }
+ #else
+ retval = read( fd, dst, bytes );
+ #endif
+ if ( retval <= 0 ) {
+ return 0;
+ }
+ return retval;
+}
+
+/*! \brief Provide openmpt_stream_callbacks for standard POSIX file descriptors
+ *
+ * Fills openmpt_stream_callbacks suitable for passing a POSIX filer descriptor as a stream parameter to functions doing file input/output.
+ *
+ * \remarks The stream argument must be passed as `(void*)(uintptr_t)(int)fd`.
+ * \sa \ref libopenmpt_c_fileio
+ * \sa openmpt_stream_callbacks
+ * \sa openmpt_could_open_probability2
+ * \sa openmpt_probe_file_header_from_stream
+ * \sa openmpt_module_create2
+ */
+static openmpt_stream_callbacks openmpt_stream_get_fd_callbacks(void) {
+ openmpt_stream_callbacks retval;
+ memset( &retval, 0, sizeof( openmpt_stream_callbacks ) );
+ retval.read = openmpt_stream_fd_read_func;
+ return retval;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* LIBOPENMPT_STREAM_CALLBACKS_FD_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_file.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_file.h
new file mode 100644
index 00000000..64304915
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_stream_callbacks_file.h
@@ -0,0 +1,132 @@
+/*
+ * libopenmpt_stream_callbacks_file.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_FILE_H
+#define LIBOPENMPT_STREAM_CALLBACKS_FILE_H
+
+#include "libopenmpt.h"
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef _MSC_VER
+#include <wchar.h> /* off_t */
+#endif
+
+/*! \addtogroup libopenmpt_c
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This stuff has to be in a header file because of possibly different MSVC CRTs which cause problems for FILE * crossing CRT boundaries. */
+
+static size_t openmpt_stream_file_read_func( void * stream, void * dst, size_t bytes ) {
+ FILE * f = 0;
+ size_t retval = 0;
+ f = (FILE*)stream;
+ if ( !f ) {
+ return 0;
+ }
+ retval = fread( dst, 1, bytes, f );
+ if ( retval <= 0 ) {
+ return 0;
+ }
+ return retval;
+}
+
+static int openmpt_stream_file_seek_func( void * stream, int64_t offset, int whence ) {
+ FILE * f = 0;
+ int fwhence = 0;
+ f = (FILE*)stream;
+ if ( !f ) {
+ return -1;
+ }
+ switch ( whence ) {
+#if defined(SEEK_SET)
+ case OPENMPT_STREAM_SEEK_SET:
+ fwhence = SEEK_SET;
+ break;
+#endif
+#if defined(SEEK_CUR)
+ case OPENMPT_STREAM_SEEK_CUR:
+ fwhence = SEEK_CUR;
+ break;
+#endif
+#if defined(SEEK_END)
+ case OPENMPT_STREAM_SEEK_END:
+ fwhence = SEEK_END;
+ break;
+#endif
+ default:
+ return -1;
+ break;
+ }
+ #if defined(_MSC_VER)
+ return _fseeki64( f, offset, fwhence ) ? -1 : 0;
+ #elif defined(_POSIX_SOURCE) && (_POSIX_SOURCE == 1)
+ return fseeko( f, offset, fwhence ) ? -1 : 0;
+ #else
+ return fseek( f, offset, fwhence ) ? -1 : 0;
+ #endif
+}
+
+static int64_t openmpt_stream_file_tell_func( void * stream ) {
+ FILE * f = 0;
+ int64_t retval = 0;
+ f = (FILE*)stream;
+ if ( !f ) {
+ return -1;
+ }
+ #if defined(_MSC_VER)
+ retval = _ftelli64( f );
+ #elif defined(_POSIX_SOURCE) && (_POSIX_SOURCE == 1)
+ retval = ftello( f );
+ #else
+ retval = ftell( f );
+ #endif
+ if ( retval < 0 ) {
+ return -1;
+ }
+ return retval;
+}
+
+/*! \brief Provide openmpt_stream_callbacks for standard C FILE objects
+ *
+ * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output.
+ *
+ * \remarks The stream argument must be passed as `(void*)(FILE*)file`.
+ * \sa \ref libopenmpt_c_fileio
+ * \sa openmpt_stream_callbacks
+ * \sa openmpt_could_open_probability2
+ * \sa openmpt_probe_file_header_from_stream
+ * \sa openmpt_module_create2
+ */
+static openmpt_stream_callbacks openmpt_stream_get_file_callbacks(void) {
+ openmpt_stream_callbacks retval;
+ memset( &retval, 0, sizeof( openmpt_stream_callbacks ) );
+ retval.read = openmpt_stream_file_read_func;
+ retval.seek = openmpt_stream_file_seek_func;
+ retval.tell = openmpt_stream_file_tell_func;
+ return retval;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_test.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_test.cpp
new file mode 100644
index 00000000..90822c99
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * libopenmpt_test.cpp
+ * -------------------
+ * Purpose: libopenmpt test suite driver
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "libopenmpt_internal.h"
+
+#include "test/test.h"
+
+#include <iostream>
+#include <locale>
+
+#include <clocale>
+#include <cstdlib>
+
+using namespace OpenMPT;
+
+#if defined( LIBOPENMPT_BUILD_TEST )
+
+#if (defined(_WIN32) || defined(WIN32)) && (defined(_UNICODE) || defined(UNICODE))
+#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER))
+// mingw-w64 g++ does only default to special C linkage for "main", but not for "wmain" (see <https://sourceforge.net/p/mingw-w64/wiki2/Unicode%20apps/>).
+extern "C" int wmain( int /*argc*/ , wchar_t * /*argv*/ [] );
+extern "C"
+#endif
+int wmain( int /*argc*/ , wchar_t * /*argv*/ [] ) {
+#else
+int main( int /*argc*/ , char * /*argv*/ [] ) {
+#endif
+ try {
+
+ // run test with "C" / classic() locale
+ Test::DoTests();
+
+ // try setting the C locale to the user locale
+ setlocale( LC_ALL, "" );
+
+ // run all tests again with a set C locale
+ Test::DoTests();
+
+ // try to set the C and C++ locales to the user locale
+ try {
+ std::locale old = std::locale::global( std::locale( "" ) );
+ (void)old;
+ } catch ( ... ) {
+ // Setting c++ global locale does not work.
+ // This is no problem for libopenmpt, just continue.
+ }
+
+ // and now, run all tests once again
+ Test::DoTests();
+
+ } catch ( const std::exception & e ) {
+ std::cerr << "TEST ERROR: exception: " << ( e.what() ? e.what() : "" ) << std::endl;
+ return -1;
+ } catch ( ... ) {
+ std::cerr << "TEST ERROR: unknown exception" << std::endl;
+ return -1;
+ }
+ return 0;
+}
+
+#endif // LIBOPENMPT_BUILD_TEST
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.h
new file mode 100644
index 00000000..383df591
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.h
@@ -0,0 +1,79 @@
+/*
+ * libopenmpt_version.h
+ * --------------------
+ * Purpose: libopenmpt public interface version
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef LIBOPENMPT_VERSION_H
+#define LIBOPENMPT_VERSION_H
+
+/* clang-format off */
+
+/*! \addtogroup libopenmpt
+ @{
+*/
+
+/*! \brief libopenmpt major version number */
+#define OPENMPT_API_VERSION_MAJOR 0
+/*! \brief libopenmpt minor version number */
+#define OPENMPT_API_VERSION_MINOR 6
+/*! \brief libopenmpt patch version number */
+#define OPENMPT_API_VERSION_PATCH 6
+/*! \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_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) "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_API_VERSION_PATCH) OPENMPT_API_VERSION_PREREL
+
+/*!
+ @}
+*/
+
+/* clang-format on */
+
+#endif /* LIBOPENMPT_VERSION_H */
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.mk b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.mk
new file mode 100644
index 00000000..ab021b53
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.mk
@@ -0,0 +1,8 @@
+LIBOPENMPT_VERSION_MAJOR=0
+LIBOPENMPT_VERSION_MINOR=6
+LIBOPENMPT_VERSION_PATCH=6
+LIBOPENMPT_VERSION_PREREL=
+
+LIBOPENMPT_LTVER_CURRENT=3
+LIBOPENMPT_LTVER_REVISION=6
+LIBOPENMPT_LTVER_AGE=3
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.rc b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.rc
new file mode 100644
index 00000000..5b3eda8a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/libopenmpt_version.rc
@@ -0,0 +1,216 @@
+
+#include "svn_version.h"
+#include "libopenmpt_version.h"
+#include <winver.h>
+
+#if 0
+// defined externally by build system
+#define MPT_BUILD_VER_FILENAME "libopenmpt.dll"
+#define MPT_BUILD_VER_FILEDESC "libopenmpt"
+#undef MPT_BUILD_VER_EXE
+#define MPT_BUILD_VER_DLL 1
+#define MPT_BUILD_VER_SPECIAL_PREFIX ""
+#define MPT_BUILD_VER_SPECIAL_SUFFIX ""
+#endif
+
+#if defined(MPT_BUILD_VER_FILENAME) && (defined(MPT_BUILD_VER_EXE) || defined(MPT_BUILD_VER_DLL))
+//#if defined(OPENMPT_VERSION_REVISION) && defined(OPENMPT_VERSION_DIRTY) && defined(OPENMPT_VERSION_MIXEDREVISIONS) && defined(OPENMPT_VERSION_IS_PACKAGE)
+//#if (OPENMPT_VERSION_REVISION > 0)
+
+#if defined(OPENMPT_VERSION_REVISION)
+ #if (OPENMPT_VERSION_REVISION > 0)
+ #define OPENMPT_VERSION_HAVE_REVISION
+ #endif
+#endif
+
+#define VER_STRINGIZE_HELPER(x) #x
+#define VER_STRINGIZE(x) VER_STRINGIZE_HELPER(x)
+
+#if defined(OPENMPT_VERSION_DIRTY) && defined(OPENMPT_VERSION_MIXEDREVISIONS) && defined(OPENMPT_VERSION_IS_PACKAGE)
+ #if (OPENMPT_VERSION_DIRTY)
+ #define VER_FILEVERSION_SRC 2
+ #elif (OPENMPT_VERSION_MIXEDREVISIONS)
+ #define VER_FILEVERSION_SRC 1
+ #elif (OPENMPT_VERSION_IS_PACKAGE)
+ #define VER_FILEVERSION_SRC 0
+ #else
+ #define VER_FILEVERSION_SRC 0
+ #endif
+#else
+ #define VER_FILEVERSION_SRC 0
+#endif
+
+#if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION OPENMPT_API_VERSION_MAJOR,OPENMPT_API_VERSION_MINOR,OPENMPT_API_VERSION_PATCH,OPENMPT_VERSION_REVISION
+ #define VER_FILEVERSION1_STR OPENMPT_API_VERSION_STRING
+#else
+ #define VER_FILEVERSION OPENMPT_API_VERSION_MAJOR,OPENMPT_API_VERSION_MINOR,OPENMPT_API_VERSION_PATCH,0
+ #define VER_FILEVERSION1_STR OPENMPT_API_VERSION_STRING
+#endif
+
+#if defined(OPENMPT_VERSION_DIRTY) && defined(OPENMPT_VERSION_MIXEDREVISIONS) && defined(OPENMPT_VERSION_IS_PACKAGE)
+ #if (OPENMPT_VERSION_DIRTY)
+ #if (OPENMPT_VERSION_IS_PACKAGE)
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION) "modified.pkg"
+ #else
+ #define VER_FILEVERSION2_STR "+modified.pkg"
+ #endif
+ #else
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION) ".modified"
+ #else
+ #define VER_FILEVERSION2_STR "+modified"
+ #endif
+ #endif
+ #elif (OPENMPT_VERSION_MIXEDREVISIONS)
+ #if (OPENMPT_VERSION_IS_PACKAGE)
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION) ".modified.pkg"
+ #else
+ #define VER_FILEVERSION2_STR "+modified.pkg"
+ #endif
+ #else
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION) ".modified"
+ #else
+ #define VER_FILEVERSION2_STR "+modified"
+ #endif
+ #endif
+ #elif (OPENMPT_VERSION_IS_PACKAGE)
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION) "pkg"
+ #else
+ #define VER_FILEVERSION2_STR "+pkg"
+ #endif
+ #else
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION)
+ #else
+ #define VER_FILEVERSION2_STR ""
+ #endif
+ #endif
+#else
+ #if defined(OPENMPT_VERSION_HAVE_REVISION)
+ #define VER_FILEVERSION2_STR "+r" VER_STRINGIZE(OPENMPT_VERSION_REVISION)
+ #else
+ #define VER_FILEVERSION2_STR ""
+ #endif
+#endif
+
+#define VER_FILEVERSION_STR VER_FILEVERSION1_STR VER_FILEVERSION2_STR
+
+#ifdef _DEBUG
+ #define VER_DEBUG VS_FF_DEBUG
+#else
+ #define VER_DEBUG 0
+#endif
+
+#if defined(OPENMPT_VERSION_DIRTY) && defined(OPENMPT_VERSION_MIXEDREVISIONS)
+ #if ((OPENMPT_VERSION_DIRTY) || (OPENMPT_VERSION_MIXEDREVISIONS))
+ #define VER_PATCHED VS_FF_PATCHED
+ #else
+ #define VER_PATCHED 0
+ #endif
+#else
+ #define VER_PATCHED 0
+#endif
+
+#if (OPENMPT_API_VERSION_IS_PREREL)
+ #define VER_PRERELEASE VS_FF_PRERELEASE
+#else
+ #define VER_PRERELEASE 0
+#endif
+
+#if defined(OPENMPT_VERSION_REVISION) && defined(OPENMPT_VERSION_DIRTY) && defined(OPENMPT_VERSION_MIXEDREVISIONS) && defined(OPENMPT_VERSION_IS_PACKAGE)
+ #if (OPENMPT_VERSION_REVISION > 0)
+ #define VER_PRIVATEBUILD 0
+ #define VER_PRIVATEBUILD_STR ""
+ #else
+ #define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
+ #define VER_PRIVATEBUILD_STR "unknwon"
+ #endif
+#else
+ #define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
+ #define VER_PRIVATEBUILD_STR "unknwon"
+#endif
+
+#if defined(MPT_BUILD_RETRO) || defined(MPT_BUILD_VER_SPECIAL_PREFIX) || defined(MPT_BUILD_VER_SPECIAL_SUFFIX)
+ #ifndef MPT_BUILD_VER_SPECIAL_PREFIX
+ #define MPT_BUILD_VER_SPECIAL_PREFIX ""
+ #endif
+ #ifndef MPT_BUILD_VER_SPECIAL_SUFFIX
+ #define MPT_BUILD_VER_SPECIAL_SUFFIX ""
+ #endif
+ #define VER_SPECIALBUILD VS_FF_SPECIALBUILD
+ #if defined(MPT_BUILD_RETRO)
+ #define VER_SPECIALBUILD_STR MPT_BUILD_VER_SPECIAL_PREFIX "+retro" MPT_BUILD_VER_SPECIAL_SUFFIX
+ #else
+ #define VER_SPECIALBUILD_STR MPT_BUILD_VER_SPECIAL_PREFIX MPT_BUILD_VER_SPECIAL_SUFFIX
+ #endif
+#elif defined(MPT_BUILD_VER_SPECIAL_PREFIX) || defined(MPT_BUILD_VER_SPECIAL_SUFFIX)
+ #define VER_SPECIALBUILD 1
+ #define VER_SPECIALBUILD_STR MPT_BUILD_VER_SPECIAL_PREFIX MPT_BUILD_VER_SPECIAL_SUFFIX
+#else
+ #define VER_SPECIALBUILD 0
+ #define VER_SPECIALBUILD_STR ""
+#endif
+
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#define VER_FILEFLAGS (VER_DEBUG|VER_PATCHED|VER_PRERELEASE|VER_PRIVATEBUILD|VER_SPECIALBUILD)
+
+#if defined(MPT_BUILD_VER_EXE)
+ #define VER_FILETYPE VFT_APP
+#elif defined(MPT_BUILD_VER_DLL)
+ #define VER_FILETYPE VFT_DLL
+#else
+ #define VER_FILETYPE VFT_UNKNOWN
+#endif
+
+#define VER_FILENAME_STR MPT_BUILD_VER_FILENAME
+
+#if defined(MPT_BUILD_VER_FILEDESC)
+ #define VER_FILEDESC_STR MPT_BUILD_VER_FILEDESC
+#else
+ #define VER_FILEDESC_STR MPT_BUILD_VER_FILENAME
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VER_FILEVERSION
+ PRODUCTVERSION VER_FILEVERSION
+ FILEFLAGSMASK VER_FILEFLAGSMASK
+ FILEFLAGS VER_FILEFLAGS
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VER_FILETYPE
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "OpenMPT (https://openmpt.org)"
+ VALUE "FileDescription", VER_FILEDESC_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", VER_FILENAME_STR
+ VALUE "LegalCopyright", "Copyright © 2004-2022 OpenMPT Project Developers and Contributors, Copyright © 1997-2003 Olivier Lapicque"
+ VALUE "OriginalFilename", VER_FILENAME_STR
+ VALUE "ProductName", "libopenmpt"
+ VALUE "ProductVersion", VER_FILEVERSION_STR
+#if VER_PRIVATEBUILD
+ VALUE "PrivateBuild", VER_PRIVATEBUILD_STR
+#endif
+#if VER_SPECIALBUILD
+ VALUE "SpecialBuild", VER_SPECIALBUILD_STR
+#endif
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+//#endif
+//#endif
+#endif
+
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/resource.h b/Src/external_dependencies/openmpt-trunk/libopenmpt/resource.h
new file mode 100644
index 00000000..980115f2
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libopenmpt_plugin_gui.rc
+//
+#define IDD_SETTINGS 101
+#define IDD_FILEINFO 102
+#define IDC_COMBO_SAMPLERATE 1001
+#define IDC_COMBO_CHANNELS 1002
+#define IDC_SLIDER_GAIN 1003
+#define IDC_COMBO_INTERPOLATION 1004
+#define IDC_COMBO_REPEAT 1005
+#define IDC_SLIDER_STEREOSEPARATION 1006
+#define IDC_COMBO_RAMPING 1007
+#define IDC_FILEINFO 1008
+#define IDC_COMBO_AMIGA_FILTER 1008
+#define IDC_CHECK_AMIGA_RESAMPLER 1009
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1010
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/external_dependencies/openmpt-trunk/libopenmpt/xmp-openmpt.cpp b/Src/external_dependencies/openmpt-trunk/libopenmpt/xmp-openmpt.cpp
new file mode 100644
index 00000000..4221fe44
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/libopenmpt/xmp-openmpt.cpp
@@ -0,0 +1,1893 @@
+/*
+ * xmp-openmpt.cpp
+ * ---------------
+ * Purpose: libopenmpt xmplay input plugin implementation
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#ifndef NO_XMPLAY
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#if !defined(WINVER) && !defined(_WIN32_WINDOWS)
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP
+#endif
+#endif
+#if !defined(MPT_BUILD_RETRO)
+#if defined(_MSC_VER)
+#define MPT_WITH_MFC
+#endif
+#else
+#if defined(_WIN32_WINNT)
+#if (_WIN32_WINNT >= 0x0501)
+#if defined(_MSC_VER)
+#define MPT_WITH_MFC
+#endif
+#endif
+#endif
+#endif
+#if defined(MPT_WITH_MFC)
+#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls
+#endif // MPT_WITH_MFC
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#if defined(MPT_WITH_MFC)
+#include <afxwin.h>
+#include <afxcmn.h>
+#endif // MPT_WITH_MFC
+#include <windows.h>
+#include <WindowsX.h>
+
+#ifdef LIBOPENMPT_BUILD_DLL
+#undef LIBOPENMPT_BUILD_DLL
+#endif
+
+#ifdef _MSC_VER
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#ifndef _SCL_SECURE_NO_WARNINGS
+#define _SCL_SECURE_NO_WARNINGS
+#endif
+#endif // _MSC_VER
+
+#include <cctype>
+#include <cstring>
+
+#include <tchar.h>
+
+#include "libopenmpt.hpp"
+#include "libopenmpt_ext.hpp"
+
+#include "libopenmpt_plugin_settings.hpp"
+
+#include "libopenmpt_plugin_gui.hpp"
+
+#include "svn_version.h"
+#if defined(OPENMPT_VERSION_REVISION)
+static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION) ")";
+#else
+static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING ")";
+#endif
+
+#define USE_XMPLAY_FILE_IO
+
+#define USE_XMPLAY_ISTREAM
+
+#include "xmplay/xmpin.h"
+
+// Shortcut block assigned to the OpenMPT plugin by un4seen.
+enum {
+ openmpt_shortcut_first = 0x21000,
+ openmpt_shortcut_tempo_decrease = openmpt_shortcut_first,
+ openmpt_shortcut_tempo_increase,
+ openmpt_shortcut_pitch_decrease,
+ openmpt_shortcut_pitch_increase,
+ openmpt_shortcut_switch_interpolation,
+ openmpt_shortcut_last = 0x21fff,
+
+ openmpt_shortcut_ex = 0x80000000, // Use extended version of the shortcut callback
+};
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <queue>
+#include <sstream>
+#include <string>
+
+#include <cmath>
+
+#include <pugixml.hpp>
+
+#define SHORT_TITLE "xmp-openmpt"
+#define SHORTER_TITLE "openmpt"
+
+static CRITICAL_SECTION xmpopenmpt_mutex;
+class xmpopenmpt_lock {
+public:
+ xmpopenmpt_lock() {
+ EnterCriticalSection( &xmpopenmpt_mutex );
+ }
+ ~xmpopenmpt_lock() {
+ LeaveCriticalSection( &xmpopenmpt_mutex );
+ }
+};
+
+static XMPFUNC_IN * xmpfin = nullptr;
+static XMPFUNC_MISC * xmpfmisc = nullptr;
+static XMPFUNC_REGISTRY * xmpfregistry = nullptr;
+static XMPFUNC_FILE * xmpffile = nullptr;
+static XMPFUNC_TEXT * xmpftext = nullptr;
+static XMPFUNC_STATUS * xmpfstatus = nullptr;
+
+struct self_xmplay_t;
+
+static self_xmplay_t * self = 0;
+
+static void save_options();
+
+static void apply_and_save_options();
+
+
+static std::string convert_to_native( const std::string & str );
+
+static std::string StringEncode( const std::wstring &src, UINT codepage );
+
+static std::wstring StringDecode( const std::string & src, UINT codepage );
+
+#if defined(UNICODE)
+static std::wstring StringToWINAPI( const std::wstring & src );
+#else
+static std::string StringToWINAPI( const std::wstring & src );
+#endif
+
+class xmp_openmpt_settings
+ : public libopenmpt::plugin::settings
+{
+protected:
+ void read_setting( const std::string & key, const std::basic_string<TCHAR> & keyW, int & val ) override {
+ libopenmpt::plugin::settings::read_setting( key, keyW, val );
+ int storedVal = 0;
+ if ( xmpfregistry->GetInt( "OpenMPT", key.c_str(), &storedVal ) ) {
+ val = storedVal;
+ }
+ }
+ void write_setting( const std::string & key, const std::basic_string<TCHAR> & /* keyW */ , int val ) override {
+ if ( !xmpfregistry->SetInt( "OpenMPT", key.c_str(), &val ) ) {
+ // error
+ }
+ // ok
+ }
+public:
+ xmp_openmpt_settings()
+ : libopenmpt::plugin::settings(TEXT(SHORT_TITLE), false)
+ {
+ return;
+ }
+ virtual ~xmp_openmpt_settings()
+ {
+ return;
+ }
+};
+
+struct self_xmplay_t {
+ std::vector<float> subsong_lengths;
+ std::vector<std::string> subsong_names;
+ std::size_t samplerate = 48000;
+ std::size_t num_channels = 2;
+ xmp_openmpt_settings settings;
+ openmpt::module_ext * mod = nullptr;
+ bool set_format_called = false;
+ openmpt::ext::pattern_vis * pattern_vis = nullptr;
+ std::int32_t tempo_factor = 0, pitch_factor = 0;
+ bool single_subsong_mode = false;
+ self_xmplay_t() {
+ settings.changed = apply_and_save_options;
+ }
+ void on_new_mod() {
+ set_format_called = false;
+ self->pattern_vis = static_cast<openmpt::ext::pattern_vis *>( self->mod->get_interface( openmpt::ext::pattern_vis_id ) );
+ }
+ void delete_mod() {
+ if ( mod ) {
+ pattern_vis = 0;
+ set_format_called = false;
+ delete mod;
+ mod = 0;
+ }
+ }
+ ~self_xmplay_t() {
+ return;
+ }
+};
+
+static std::string convert_to_native( const std::string & str ) {
+ char * native_string = xmpftext->Utf8( str.c_str(), -1 );
+ std::string result = native_string ? native_string : "";
+ if ( native_string ) {
+ xmpfmisc->Free( native_string );
+ native_string = 0;
+ }
+ return result;
+}
+
+static std::string StringEncode( const std::wstring &src, UINT codepage )
+{
+ int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, nullptr, 0, nullptr, nullptr);
+ if(required_size <= 0)
+ {
+ return std::string();
+ }
+ std::vector<CHAR> encoded_string( required_size );
+ WideCharToMultiByte( codepage, 0, src.c_str(), -1, &encoded_string[0], encoded_string.size(), nullptr, nullptr);
+ return &encoded_string[0];
+}
+
+static std::wstring StringDecode( const std::string & src, UINT codepage )
+{
+ int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, nullptr, 0 );
+ if(required_size <= 0)
+ {
+ return std::wstring();
+ }
+ std::vector<WCHAR> decoded_string( required_size );
+ MultiByteToWideChar( codepage, 0, src.c_str(), -1, &decoded_string[0], decoded_string.size() );
+ return &decoded_string[0];
+}
+
+#if defined(UNICODE)
+
+static std::wstring StringToWINAPI( const std::wstring & src )
+{
+ return src;
+}
+
+#else
+
+static std::string StringToWINAPI( const std::wstring & src )
+{
+ return StringEncode( src, CP_ACP );
+}
+
+#endif
+
+template <typename Tstring, typename Tstring2, typename Tstring3>
+static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) {
+ std::size_t pos = 0;
+ const Tstring oldStr = oldStr_;
+ const Tstring newStr = newStr_;
+ while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) {
+ str.replace( pos, oldStr.length(), newStr );
+ pos += newStr.length();
+ }
+ return str;
+}
+
+static std::string StringUpperCase( std::string str ) {
+ std::transform( str.begin(), str.end(), str.begin(), []( char c ) { return static_cast<char>( std::toupper( c ) ); } );
+ return str;
+}
+
+static std::string seconds_to_string( float time ) {
+ std::int64_t time_ms = static_cast<std::int64_t>( time * 1000 );
+ std::int64_t seconds = ( time_ms / 1000 ) % 60;
+ std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 60;
+ std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) );
+ std::ostringstream str;
+ if ( hours > 0 ) {
+ str << hours << ":";
+ }
+ str << std::setfill('0') << std::setw(2) << minutes;
+ str << ":";
+ str << std::setfill('0') << std::setw(2) << seconds;
+ return str.str();
+}
+
+static void save_settings_to_map( std::map<std::string,int> & result, const libopenmpt::plugin::settings & s ) {
+ result.clear();
+ result[ "Samplerate_Hz" ] = s.samplerate;
+ result[ "Channels" ] = s.channels;
+ result[ "MasterGain_milliBel" ] = s.mastergain_millibel;
+ result[ "StereoSeparation_Percent" ] = s.stereoseparation;
+ result[ "RepeatCount" ] = s.repeatcount;
+ result[ "InterpolationFilterLength" ] = s.interpolationfilterlength;
+ result[ "UseAmigaResampler" ] = s.use_amiga_resampler;
+ result[ "AmigaFilterType" ] = s.amiga_filter_type;
+ result[ "VolumeRampingStrength" ] = s.ramping;
+}
+
+static inline void load_map_setting( const std::map<std::string,int> & map, const std::string & key, int & val ) {
+ auto it = map.find( key );
+ if ( it != map.end() ) {
+ val = it->second;
+ }
+}
+
+static void load_settings_from_map( libopenmpt::plugin::settings & s, const std::map<std::string,int> & map ) {
+ load_map_setting( map, "Samplerate_Hz", s.samplerate );
+ load_map_setting( map, "Channels", s.channels );
+ load_map_setting( map, "MasterGain_milliBel", s.mastergain_millibel );
+ load_map_setting( map, "StereoSeparation_Percent", s.stereoseparation );
+ load_map_setting( map, "RepeatCount", s.repeatcount );
+ load_map_setting( map, "InterpolationFilterLength", s.interpolationfilterlength );
+ load_map_setting( map, "UseAmigaResampler", s.use_amiga_resampler );
+ load_map_setting( map, "AmigaFilterType", s.amiga_filter_type );
+ load_map_setting( map, "VolumeRampingStrength", s.ramping );
+}
+
+static void load_settings_from_xml( libopenmpt::plugin::settings & s, const std::string & xml ) {
+ pugi::xml_document doc;
+ doc.load_string( xml.c_str() );
+ pugi::xml_node settings_node = doc.child( "settings" );
+ std::map<std::string,int> map;
+ for ( const auto & attr : settings_node.attributes() ) {
+ map[ attr.name() ] = attr.as_int();
+ }
+ load_settings_from_map( s, map );
+}
+
+static void save_settings_to_xml( std::string & xml, const libopenmpt::plugin::settings & s ) {
+ std::map<std::string,int> map;
+ save_settings_to_map( map, s );
+ pugi::xml_document doc;
+ pugi::xml_node settings_node = doc.append_child( "settings" );
+ for ( const auto & setting : map ) {
+ settings_node.append_attribute( setting.first.c_str() ).set_value( setting.second );
+ }
+ std::ostringstream buf;
+ doc.save( buf );
+ xml = buf.str();
+}
+
+static void apply_options() {
+ if ( self->mod ) {
+ if ( !self->set_format_called ) {
+ // SetFormat will only be called once after loading a file.
+ // We cannot apply samplerate or numchannels changes afterwards during playback.
+ self->samplerate = self->settings.samplerate;
+ self->num_channels = self->settings.channels;
+ }
+ self->mod->set_repeat_count( self->settings.repeatcount );
+ self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel );
+ self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation );
+ self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength );
+ self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping );
+ self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false );
+ switch ( self->settings.amiga_filter_type ) {
+ case 0:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" );
+ break;
+ case 1:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" );
+ break;
+ case 0xA500:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" );
+ break;
+ case 0xA1200:
+ self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" );
+ break;
+ }
+ }
+}
+
+static void save_options() {
+ self->settings.save();
+}
+
+static void apply_and_save_options() {
+ apply_options();
+ save_options();
+}
+
+static void reset_options() {
+ self->settings = xmp_openmpt_settings();
+ self->settings.changed = apply_and_save_options;
+ self->settings.load();
+}
+
+// get config (return size of config data) (OPTIONAL)
+static DWORD WINAPI openmpt_GetConfig( void * config ) {
+ std::string xml;
+ save_settings_to_xml( xml, self->settings );
+ if ( config ) {
+ std::memcpy( config, xml.c_str(), xml.length() + 1 );
+ }
+ return xml.length() + 1;
+}
+
+// apply config (OPTIONAL)
+static void WINAPI openmpt_SetConfig( void * config, DWORD size ) {
+ reset_options();
+ if ( config ) {
+ load_settings_from_xml( self->settings, std::string( (char*)config, (char*)config + size ) );
+ apply_options();
+ }
+}
+
+static void WINAPI ShortcutHandler( DWORD id ) {
+ if ( !self->mod ) {
+ return;
+ }
+
+ bool tempo_changed = false, pitch_changed = false;
+ switch ( id ) {
+ case openmpt_shortcut_tempo_decrease: self->tempo_factor--; tempo_changed = true; break;
+ case openmpt_shortcut_tempo_increase: self->tempo_factor++; tempo_changed = true; break;
+ case openmpt_shortcut_pitch_decrease: self->pitch_factor--; pitch_changed = true; break;
+ case openmpt_shortcut_pitch_increase: self->pitch_factor++; pitch_changed = true; break;
+ case openmpt_shortcut_switch_interpolation:
+ self->settings.interpolationfilterlength *= 2;
+ if ( self->settings.interpolationfilterlength > 8 ) {
+ self->settings.interpolationfilterlength = 1;
+ }
+ apply_and_save_options();
+ const char *s = nullptr;
+ switch ( self->settings.interpolationfilterlength )
+ {
+ case 1: s = "Interpolation: Off"; break;
+ case 2: s = "Interpolation: Linear"; break;
+ case 4: s = "Interpolation: Cubic"; break;
+ case 8: s = "Interpolation: Polyphase"; break;
+ }
+ if ( s ) {
+ xmpfmisc->ShowBubble( s, 0 );
+ }
+ break;
+ }
+
+ self->tempo_factor = std::min( 48, std::max( -48, self->tempo_factor ) );
+ self->pitch_factor = std::min( 48, std::max( -48, self->pitch_factor ) );
+ const double tempo_factor = std::pow( 2.0, self->tempo_factor / 24.0 );
+ const double pitch_factor = std::pow( 2.0, self->pitch_factor / 24.0 );
+
+ if ( tempo_changed ) {
+ std::ostringstream s;
+ s << "Tempo: " << static_cast<std::int32_t>( 100.0 * tempo_factor ) << "%";
+ xmpfmisc->ShowBubble( s.str().c_str(), 0 );
+ } else if ( pitch_changed) {
+ std::ostringstream s;
+ s << "Pitch: ";
+ if ( self->pitch_factor > 0 )
+ s << "+";
+ else if ( self->pitch_factor == 0 )
+ s << "+/-";
+ s << (self->pitch_factor * 0.5) << " semitones";
+ xmpfmisc->ShowBubble( s.str().c_str(), 0 );
+ }
+
+ openmpt::ext::interactive *interactive = static_cast<openmpt::ext::interactive *>( self->mod->get_interface( openmpt::ext::interactive_id ) );
+ interactive->set_tempo_factor( tempo_factor );
+ interactive->set_pitch_factor( pitch_factor );
+ xmpfin->SetLength( static_cast<float>( self->mod->get_duration_seconds() / tempo_factor ), TRUE );
+}
+
+
+static double timeinfo_position = 0.0;
+struct timeinfo {
+ bool valid;
+ double seconds;
+ std::int32_t pattern;
+ std::int32_t row;
+};
+static std::queue<timeinfo> timeinfos;
+static void reset_timeinfos( double position = 0.0 ) {
+ while ( !timeinfos.empty() ) {
+ timeinfos.pop();
+ }
+ timeinfo_position = position;
+}
+static void update_timeinfos( std::int32_t samplerate, std::int32_t count ) {
+ timeinfo_position += (double)count / (double)samplerate;
+ timeinfo info;
+ info.valid = true;
+ info.seconds = timeinfo_position;
+ info.pattern = self->mod->get_current_pattern();
+ info.row = self->mod->get_current_row();
+ timeinfos.push( info );
+}
+
+static timeinfo current_timeinfo;
+
+static timeinfo lookup_timeinfo( double seconds ) {
+ timeinfo info = current_timeinfo;
+#if 0
+ info.seconds = timeinfo_position;
+ info.pattern = self->mod->get_current_pattern();
+ info.row = self->mod->get_current_row();
+#endif
+ while ( timeinfos.size() > 0 && timeinfos.front().seconds <= seconds ) {
+ info = timeinfos.front();
+ timeinfos.pop();
+ }
+ current_timeinfo = info;
+ return current_timeinfo;
+}
+
+static void clear_current_timeinfo() {
+ current_timeinfo = timeinfo();
+}
+
+static void WINAPI openmpt_About( HWND win ) {
+ std::ostringstream about;
+ about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
+ about << " Copyright (c) 2013-2022 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl;
+ about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
+ about << std::endl;
+ about << openmpt::string::get( "contact" ) << std::endl;
+ about << std::endl;
+ about << "Show full credits?" << std::endl;
+ if ( MessageBox( win, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) {
+ return;
+ }
+ std::ostringstream credits;
+ credits << openmpt::string::get( "credits" );
+ credits << "Additional thanks to:" << std::endl;
+ credits << std::endl;
+ credits << "Arseny Kapoulkine for pugixml" << std::endl;
+ credits << "https://pugixml.org/" << std::endl;
+#if 1
+ libopenmpt::plugin::gui_show_file_info( win, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) );
+#else
+ MessageBox( win, StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK );
+#endif
+}
+
+static void WINAPI openmpt_Config( HWND win ) {
+#if 1
+ libopenmpt::plugin::gui_edit_settings( &self->settings, win, TEXT(SHORT_TITLE) );
+#else
+ static_cast<void>(win);
+#endif
+ apply_and_save_options();
+}
+
+#ifdef USE_XMPLAY_FILE_IO
+
+#ifdef USE_XMPLAY_ISTREAM
+
+class xmplay_streambuf : public std::streambuf {
+public:
+ explicit xmplay_streambuf( XMPFILE & file );
+private:
+ int_type underflow() override;
+ xmplay_streambuf( const xmplay_streambuf & );
+ xmplay_streambuf & operator = ( const xmplay_streambuf & );
+private:
+ XMPFILE & file;
+ static const std::size_t put_back = 4096;
+ static const std::size_t buf_size = 65536;
+ std::vector<char> buffer;
+}; // class xmplay_streambuf
+
+xmplay_streambuf::xmplay_streambuf( XMPFILE & file_ ) : file(file_), buffer(buf_size) {
+ char * end = &buffer.front() + buffer.size();
+ setg( end, end, end );
+}
+
+std::streambuf::int_type xmplay_streambuf::underflow() {
+ if ( gptr() < egptr() ) {
+ return traits_type::to_int_type( *gptr() );
+ }
+ char * base = &buffer.front();
+ char * start = base;
+ if ( eback() == base ) {
+ std::size_t put_back_count = std::min( put_back, static_cast<std::size_t>( egptr() - base ) );
+ std::memmove( base, egptr() - put_back_count, put_back_count );
+ start += put_back_count;
+ }
+ std::size_t n = xmpffile->Read( file, start, buffer.size() - ( start - base ) );
+ if ( n == 0 ) {
+ return traits_type::eof();
+ }
+ setg( base, start, start + n );
+ return traits_type::to_int_type( *gptr() );
+}
+
+class xmplay_istream : public std::istream {
+private:
+ xmplay_streambuf buf;
+private:
+ xmplay_istream( const xmplay_istream & );
+ xmplay_istream & operator = ( const xmplay_istream & );
+public:
+ xmplay_istream( XMPFILE & file ) : std::istream(&buf), buf(file) {
+ return;
+ }
+ ~xmplay_istream() {
+ return;
+ }
+}; // class xmplay_istream
+
+// Stream for memory-based files (required for could_open_probability)
+struct xmplay_membuf : std::streambuf {
+ xmplay_membuf( const char * base, size_t size ) {
+ char* p( const_cast<char *>( base ) );
+ setg(p, p, p + size);
+ }
+};
+
+struct xmplay_imemstream : virtual xmplay_membuf, std::istream {
+ xmplay_imemstream( const char * base, size_t size )
+ : xmplay_membuf( base, size )
+ , std::istream( static_cast<std::streambuf *>(this)) {
+ return;
+ }
+};
+
+#else // !USE_XMPLAY_ISTREAM
+
+static std::vector<char> read_XMPFILE_vector( XMPFILE & file ) {
+ std::vector<char> data( xmpffile->GetSize( file ) );
+ if ( data.size() != xmpffile->Read( file, data.data(), data.size() ) ) {
+ return std::vector<char>();
+ }
+ return data;
+}
+
+static std::string read_XMPFILE_string( XMPFILE & file ) {
+ std::vector<char> data = read_XMPFILE_vector( file );
+ return std::string( data.begin(), data.end() );
+}
+
+#endif // USE_XMPLAY_ISTREAM
+
+#endif // USE_XMPLAY_FILE_IO
+
+static std::string string_replace( std::string str, const std::string & oldStr, const std::string & newStr ) {
+ std::size_t pos = 0;
+ while((pos = str.find(oldStr, pos)) != std::string::npos)
+ {
+ str.replace(pos, oldStr.length(), newStr);
+ pos += newStr.length();
+ }
+ return str;
+}
+
+static void write_xmplay_string( char * dst, std::string src ) {
+ // xmplay buffers are ~40kB, be conservative and truncate at 32kB-2
+ if ( !dst ) {
+ return;
+ }
+ src = src.substr( 0, (1<<15) - 2 );
+ std::strcpy( dst, src.c_str() );
+}
+
+static std::string extract_date( const openmpt::module & mod ) {
+ std::string result = mod.get_metadata("date");
+ if ( result.empty() ) {
+ // Search the sample, instrument and message texts for possible release years.
+ // We'll look for things that may vaguely resemble a release year, such as 4-digit numbers
+ // or 2-digit numbers with a leading apostrophe. Generally, only years between
+ // 1988 (release of Ultimate SoundTracker) and the current year + 1 (safety margin) will
+ // be considered.
+ std::string s = " " + mod.get_metadata("message");
+ auto names = mod.get_sample_names();
+ for ( const auto & name : names ) {
+ s += " " + name;
+ }
+ names = mod.get_instrument_names();
+ for ( const auto & name : names ) {
+ s += " " + name;
+ }
+ s += " ";
+
+ int32_t best_year = 0;
+
+ SYSTEMTIME time;
+ GetSystemTime( &time );
+ const int32_t current_year = time.wYear + 1;
+
+#define MPT_NUMERIC( x ) ( ( x >= '0' ) && ( x <= '9' ) )
+ for ( auto i = s.cbegin(); i != s.cend(); ++i ) {
+ std::size_t len = s.length();
+ std::size_t idx = i - s.begin();
+ std::size_t remaining = len - idx;
+ if ( ( remaining >= 6 ) && !MPT_NUMERIC( i[0] ) && MPT_NUMERIC( i[1] ) && MPT_NUMERIC( i[2] ) && MPT_NUMERIC( i[3] ) && MPT_NUMERIC( i[4] ) && !MPT_NUMERIC( i[5] ) ) {
+ // Four-digit year
+ const int32_t year = ( i[1] - '0' ) * 1000 + ( i[2] - '0' ) * 100 + ( i[3] - '0' ) * 10 + ( i[4] - '0' );
+ if ( year >= 1988 && year <= current_year ) {
+ best_year = std::max( year, best_year );
+ }
+ } else if ( ( remaining >= 4 ) && ( i[0] == '\'' ) && MPT_NUMERIC( i[1] ) && MPT_NUMERIC( i[2] ) && !MPT_NUMERIC( i[3] ) ) {
+ // Apostrophe + two-digit year
+ const int32_t year = ( i[1] - '0' ) * 10 + ( i[2] - '0' );
+ if ( year >= 88 && year <= 99 ) {
+ best_year = std::max( 1900 + year, best_year );
+ } else if ( year >= 00 && ( 2000 + year ) <= current_year ) {
+ best_year = std::max( 2000 + year, best_year );
+ }
+ }
+ }
+#undef MPT_NUMERIC
+
+ if ( best_year != 0 ) {
+ std::ostringstream os;
+ os << best_year;
+ result = os.str();
+ }
+ }
+
+ return result;
+}
+
+static void append_xmplay_tag( std::string & tags, const std::string & tag, const std::string & val ) {
+ if ( tag.empty() ) {
+ return;
+ }
+ if ( val.empty() ) {
+ return;
+ }
+ tags.append( tag );
+ tags.append( 1, '\0' );
+ tags.append( val );
+ tags.append( 1, '\0' );
+}
+
+static char * build_xmplay_tags( const openmpt::module & mod, int32_t subsong = -1 ) {
+ std::string tags;
+ const std::string title = mod.get_metadata("title");
+
+ const auto subsong_names = mod.get_subsong_names();
+ auto first_subsong = subsong_names.cbegin(), last_subsong = subsong_names.cend();
+ if ( subsong >= 0 && static_cast<size_t>( subsong ) < subsong_names.size() ) {
+ first_subsong += subsong;
+ last_subsong = first_subsong + 1;
+ } else
+ {
+ last_subsong = first_subsong + 1;
+ }
+
+ for ( auto subsong_name = first_subsong; subsong_name != last_subsong; subsong_name++ ) {
+ append_xmplay_tag( tags, "filetype", convert_to_native( StringUpperCase( mod.get_metadata( "type" ) ) ) );
+ append_xmplay_tag( tags, "title", convert_to_native( ( subsong_name->empty() || subsong == -1 ) ? title : *subsong_name ) );
+ append_xmplay_tag( tags, "artist", convert_to_native( mod.get_metadata( "artist" ) ) );
+ append_xmplay_tag( tags, "album", convert_to_native( mod.get_metadata( "xmplay-album" ) ) ); // todo, libopenmpt does not support that
+ append_xmplay_tag( tags, "date", convert_to_native( extract_date( mod ) ) );
+ append_xmplay_tag( tags, "track", convert_to_native( mod.get_metadata( "xmplay-tracknumber" ) ) ); // todo, libopenmpt does not support that
+ append_xmplay_tag( tags, "genre", convert_to_native( mod.get_metadata( "xmplay-genre" ) ) ); // todo, libopenmpt does not support that
+ append_xmplay_tag( tags, "comment", convert_to_native( mod.get_metadata( "message" ) ) );
+ tags.append( 1, '\0' );
+ }
+ char * result = static_cast<char*>( xmpfmisc->Alloc( tags.size() ) );
+ if ( !result ) {
+ return nullptr;
+ }
+ std::copy( tags.data(), tags.data() + tags.size(), result );
+ return result;
+}
+
+static float * build_xmplay_length( const openmpt::module & /* mod */ ) {
+ float * result = static_cast<float*>( xmpfmisc->Alloc( sizeof( float ) * self->subsong_lengths.size() ) );
+ if ( !result ) {
+ return nullptr;
+ }
+ for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) {
+ result[i] = self->subsong_lengths[i];
+ }
+ return result;
+}
+
+static void clear_xmplay_string( char * str ) {
+ if ( !str ) {
+ return;
+ }
+ str[0] = '\0';
+}
+
+static std::string sanitize_xmplay_info_string( const std::string & str ) {
+ std::string result;
+ result.reserve(str.size());
+ for ( auto c : str ) {
+ switch ( c ) {
+ case '\0':
+ case '\t':
+ case '\r':
+ case '\n':
+ break;
+ default:
+ result.push_back( c );
+ break;
+ }
+ }
+ return result;
+}
+
+static std::string sanitize_xmplay_multiline_info_string( const std::string & str ) {
+ std::string result;
+ result.reserve(str.size());
+ for ( auto c : str ) {
+ switch ( c ) {
+ case '\0':
+ case '\t':
+ case '\r':
+ break;
+ case '\n':
+ result.push_back( '\r' );
+ result.push_back( '\t' );
+ break;
+ default:
+ result.push_back( c );
+ break;
+ }
+ }
+ return result;
+}
+
+static std::string sanitize_xmplay_multiline_string( const std::string & str ) {
+ std::string result;
+ result.reserve(str.size());
+ for ( auto c : str ) {
+ switch ( c ) {
+ case '\0':
+ case '\t':
+ break;
+ default:
+ result.push_back( c );
+ break;
+ }
+ }
+ return result;
+}
+
+// check if a file is playable by this plugin
+// more thorough checks can be saved for the GetFileInfo and Open functions
+static BOOL WINAPI openmpt_CheckFile( const char * filename, XMPFILE file ) {
+ static_cast<void>( filename );
+ try {
+ #ifdef USE_XMPLAY_FILE_IO
+ #ifdef USE_XMPLAY_ISTREAM
+ switch ( xmpffile->GetType( file ) ) {
+ case XMPFILE_TYPE_MEMORY:
+ {
+ xmplay_imemstream s( reinterpret_cast<const char *>( xmpffile->GetMemory( file ) ), xmpffile->GetSize( file ) );
+ return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE;
+ }
+ break;
+ case XMPFILE_TYPE_FILE:
+ case XMPFILE_TYPE_NETFILE:
+ case XMPFILE_TYPE_NETSTREAM:
+ default:
+ {
+ xmplay_istream s( file );
+ return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE;
+ }
+ break;
+ }
+ #else
+ if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) {
+ std::string data( reinterpret_cast<const char*>( xmpffile->GetMemory( file ) ), xmpffile->GetSize( file ) );
+ std::istringstream s( data );
+ return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE;
+ } else {
+ std::string data = read_XMPFILE_string( file );
+ std::istringstream s(data);
+ return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE;
+ }
+ #endif
+ #else
+ std::ifstream s( filename, std::ios_base::binary );
+ return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE;
+ #endif
+ } catch ( ... ) {
+ return FALSE;
+ }
+ return FALSE;
+}
+
+static DWORD WINAPI openmpt_GetFileInfo( const char * filename, XMPFILE file, float * * length, char * * tags ) {
+ static_cast<void>( filename );
+ try {
+ std::map< std::string, std::string > ctls
+ {
+ { "load.skip_plugins", "1" },
+ { "load.skip_samples", "1" },
+ };
+ #ifdef USE_XMPLAY_FILE_IO
+ #ifdef USE_XMPLAY_ISTREAM
+ switch ( xmpffile->GetType( file ) ) {
+ case XMPFILE_TYPE_MEMORY:
+ {
+ openmpt::module mod( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls );
+ if ( length ) {
+ *length = build_xmplay_length( mod );
+ }
+ if ( tags ) {
+ *tags = build_xmplay_tags( mod );
+ }
+ }
+ break;
+ case XMPFILE_TYPE_FILE:
+ case XMPFILE_TYPE_NETFILE:
+ case XMPFILE_TYPE_NETSTREAM:
+ default:
+ {
+ xmplay_istream s( file );
+ openmpt::module mod( s, std::clog, ctls );
+ if ( length ) {
+ *length = build_xmplay_length( mod );
+ }
+ if ( tags ) {
+ *tags = build_xmplay_tags( mod );
+ }
+ }
+ break;
+ }
+ #else
+ if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) {
+ openmpt::module mod( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls );
+ if ( length ) {
+ *length = build_xmplay_length( mod );
+ }
+ if ( tags ) {
+ *tags = build_xmplay_tags( mod );
+ }
+ } else {
+ openmpt::module mod( read_XMPFILE_vector( file ), std::clog, ctls );
+ if ( length ) {
+ *length = build_xmplay_length( mod );
+ }
+ if ( tags ) {
+ *tags = build_xmplay_tags( mod );
+ }
+ }
+ #endif
+ #else
+ std::ifstream s( filename, std::ios_base::binary );
+ openmpt::module mod( s, std::clog, ctls );
+ if ( length ) {
+ *length = build_xmplay_length( mod );
+ }
+ if ( tags ) {
+ *tags = build_xmplay_tags( mod );
+ }
+ #endif
+ } catch ( ... ) {
+ if ( length ) *length = nullptr;
+ if ( tags ) *tags = nullptr;
+ return 0;
+ }
+ return self->subsong_lengths.size() + XMPIN_INFO_NOSUBTAGS;
+}
+
+// open a file for playback
+// return: 0=failed, 1=success, 2=success and XMPlay can close the file
+static DWORD WINAPI openmpt_Open( const char * filename, XMPFILE file ) {
+ static_cast<void>( filename );
+ xmpopenmpt_lock guard;
+ reset_options();
+ try {
+ std::map< std::string, std::string > ctls
+ {
+ { "seek.sync_samples", "1" },
+ { "play.at_end", "continue" },
+ };
+ self->delete_mod();
+ #ifdef USE_XMPLAY_FILE_IO
+ #ifdef USE_XMPLAY_ISTREAM
+ switch ( xmpffile->GetType( file ) ) {
+ case XMPFILE_TYPE_MEMORY:
+ self->mod = new openmpt::module_ext( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls );
+ break;
+ case XMPFILE_TYPE_FILE:
+ case XMPFILE_TYPE_NETFILE:
+ case XMPFILE_TYPE_NETSTREAM:
+ default:
+ {
+ xmplay_istream s( file );
+ self->mod = new openmpt::module_ext( s, std::clog, ctls );
+ }
+ break;
+ }
+ #else
+ if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) {
+ self->mod = new openmpt::module_ext( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls );
+ } else {
+ self->mod = new openmpt::module_ext( read_XMPFILE_vector( file ), std::clog, ctls );
+ }
+ #endif
+ #else
+ self->mod = new openmpt::module_ext( std::ifstream( filename, std::ios_base::binary ), std::clog, ctls );
+ #endif
+ self->on_new_mod();
+ clear_current_timeinfo();
+ reset_timeinfos();
+ apply_options();
+
+ std::int32_t num_subsongs = self->mod->get_num_subsongs();
+ self->subsong_lengths.resize( num_subsongs );
+ for ( std::int32_t i = 0; i < num_subsongs; ++i ) {
+ self->mod->select_subsong( i );
+ self->subsong_lengths[i] = static_cast<float>( self->mod->get_duration_seconds() );
+ }
+ self->subsong_names = self->mod->get_subsong_names();
+ self->mod->select_subsong( 0 );
+ self->tempo_factor = 0;
+ self->pitch_factor = 0;
+
+ xmpfin->SetLength( self->subsong_lengths[0], TRUE );
+ return 2;
+ } catch ( ... ) {
+ self->delete_mod();
+ return 0;
+ }
+ return 0;
+}
+
+// close the file
+static void WINAPI openmpt_Close() {
+ xmpopenmpt_lock guard;
+ self->delete_mod();
+}
+
+// set the sample format (in=user chosen format, out=file format if different)
+static void WINAPI openmpt_SetFormat( XMPFORMAT * form ) {
+ if ( !form ) {
+ return;
+ }
+ // SetFormat will only be called once after loading a file.
+ // We cannot apply samplerate or numchannels changes afterwards during playback.
+ self->set_format_called = true;
+ if ( !self->mod ) {
+ form->rate = 0;
+ form->chan = 0;
+ form->res = 0;
+ return;
+ }
+ if ( self->settings.samplerate != 0 ) {
+ form->rate = self->samplerate;
+ } else {
+ if ( form->rate > 0 ) {
+ self->samplerate = form->rate;
+ } else {
+ form->rate = 48000;
+ self->samplerate = 48000;
+ }
+ }
+ if ( self->settings.channels != 0 ) {
+ form->chan = self->num_channels;
+ } else {
+ if ( form->chan > 0 ) {
+ if ( form->chan > 2 ) {
+ form->chan = 4;
+ self->num_channels = 4;
+ } else {
+ self->num_channels = form->chan;
+ }
+ } else {
+ form->chan = 2;
+ self->num_channels = 2;
+ }
+ }
+ form->res = 4; // float
+}
+
+// get the tags
+static char * WINAPI openmpt_GetTags() {
+ if ( !self->mod ) {
+ char * tags = static_cast<char*>( xmpfmisc->Alloc( 1 ) );
+ tags[0] = '\0';
+ return tags;
+ }
+ return build_xmplay_tags( *self->mod, std::max( 0, self->mod->get_selected_subsong() ) );
+}
+
+// get the main panel info text
+static void WINAPI openmpt_GetInfoText( char * format, char * length ) {
+ if ( !self->mod ) {
+ clear_xmplay_string( format );
+ clear_xmplay_string( length );
+ return;
+ }
+ if ( format ) {
+ std::ostringstream str;
+ str
+ << StringUpperCase( self->mod->get_metadata("type") )
+ << " - "
+ << self->mod->get_num_channels() << " ch"
+ << " - "
+ << "(via " << SHORTER_TITLE << ")"
+ ;
+ write_xmplay_string( format, sanitize_xmplay_info_string( str.str() ) );
+ }
+ if ( length ) {
+ std::ostringstream str;
+ str
+ << length
+ << " - "
+ << self->mod->get_num_orders() << " orders"
+ ;
+ write_xmplay_string( length, sanitize_xmplay_info_string( str.str() ) );
+ }
+}
+
+// get text for "General" info window
+// separate headings and values with a tab (\t), end each line with a carriage-return (\r)
+static void WINAPI openmpt_GetGeneralInfo( char * buf ) {
+ if ( !self->mod ) {
+ clear_xmplay_string( buf );
+ return;
+ }
+ std::ostringstream str;
+ str << "\r";
+ bool metadatainfo = false;
+ if ( !self->mod->get_metadata("artist").empty() ) {
+ metadatainfo = true;
+ str << "Artist" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("artist") ) << "\r";
+ }
+ const std::string date = extract_date( *self->mod );
+ if ( !date.empty() ) {
+ metadatainfo = true;
+ str << "Date" << "\t" << sanitize_xmplay_info_string( date ) << "\r";
+ }
+ if ( metadatainfo ) {
+ str << "\r";
+ }
+ str << "Format" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("type") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("type_long") ) << ")" << "\r";
+ if ( !self->mod->get_metadata("originaltype").empty() ) {
+ str << "Original Type" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("originaltype") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("originaltype_long") ) << ")" << "\r";
+ }
+ if ( !self->mod->get_metadata("container").empty() ) {
+ str << "Container" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("container") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("container_long") ) << ")" << "\r";
+ }
+ str
+ << "Channels" << "\t" << self->mod->get_num_channels() << "\r"
+ << "Orders" << "\t" << self->mod->get_num_orders() << "\r"
+ << "Patterns" << "\t" << self->mod->get_num_patterns() << "\r";
+ if ( self->mod->get_num_instruments() != 0 ) {
+ str << "Instruments" << "\t" << self->mod->get_num_instruments() << "\r";
+ }
+ str << "Samples" << "\t" << self->mod->get_num_samples() << "\r";
+
+ if( !self->single_subsong_mode && self->subsong_lengths.size() > 1 ) {
+ for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) {
+ str << ( i == 0 ? "Subsongs\t" : "\t" ) << (i + 1) << ". " << seconds_to_string( self->subsong_lengths[i]) << " " << self->subsong_names[i] << "\r";
+ }
+ }
+
+ str
+ << "\r"
+ << "Tracker" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("tracker") ) << "\r"
+ << "Player" << "\t" << "xmp-openmpt" << " version " << openmpt::string::get( "library_version" ) << "\r"
+ ;
+ std::string warnings = self->mod->get_metadata("warnings");
+ if ( !warnings.empty() ) {
+ str << "Warnings" << "\t" << sanitize_xmplay_multiline_info_string( warnings ) << "\r";
+ }
+ str << "\r";
+ write_xmplay_string( buf, str.str() );
+}
+
+// get text for "Message" info window
+// separate tag names and values with a tab (\t), and end each line with a carriage-return (\r)
+static void WINAPI openmpt_GetMessage( char * buf ) {
+ if ( !self->mod ) {
+ clear_xmplay_string( buf );
+ return;
+ }
+ write_xmplay_string( buf, convert_to_native( sanitize_xmplay_multiline_string( string_replace( self->mod->get_metadata("message"), "\n", "\r" ) ) ) );
+}
+
+// Seek to a position (in granularity units)
+// return the new position in seconds (-1 = failed)
+static double WINAPI openmpt_SetPosition( DWORD pos ) {
+ if ( !self->mod ) {
+ return -1.0;
+ }
+ if ( pos == static_cast<DWORD>(static_cast<LONG>(XMPIN_POS_LOOP)) ) {
+ // If the time of the loop start position is known, that should be returned, otherwise -2 can be returned to let the time run on.
+ // There is currently no way to easily figure out at which time the loop restarts.
+ return -2;
+ } else if ( pos == static_cast<DWORD>(static_cast<LONG>(XMPIN_POS_AUTOLOOP)) ) {
+ // In the auto-looping case, the function should only loop when a loop has been detected, and otherwise return -1
+ // If the time of the loop start position is known, that should be returned, otherwise -2 can be returned to let the time run on.
+ // There is currently no way to easily figure out at which time the loop restarts.
+ return -2;
+ }
+ if ( pos & XMPIN_POS_SUBSONG ) {
+ self->single_subsong_mode = ( pos & XMPIN_POS_SUBSONG1 ) != 0;
+ const int32_t subsong = pos & 0xffff;
+ try {
+ self->mod->select_subsong( subsong );
+ } catch ( ... ) {
+ return 0.0;
+ }
+ openmpt::ext::interactive *interactive = static_cast<openmpt::ext::interactive *>( self->mod->get_interface( openmpt::ext::interactive_id ) );
+ xmpfin->SetLength( static_cast<float>( self->subsong_lengths[ subsong ] / interactive->get_tempo_factor() ), TRUE );
+ xmpfin->UpdateTitle( nullptr );
+ reset_timeinfos( 0 );
+ return 0.0;
+ }
+ double new_position = self->mod->set_position_seconds( static_cast<double>( pos ) * 0.001 );
+ reset_timeinfos( new_position );
+ return new_position;
+}
+
+// Get the seeking granularity in seconds
+static double WINAPI openmpt_GetGranularity() {
+ return 0.001;
+}
+
+// get some sample data, always floating-point
+// count=number of floats to write (not bytes or samples)
+// return number of floats written. if it's less than requested, playback is ended...
+// so wait for more if there is more to come (use CheckCancel function to check if user wants to cancel)
+static DWORD WINAPI openmpt_Process( float * dstbuf, DWORD count ) {
+ xmpopenmpt_lock guard;
+ if ( !self->mod || self->num_channels == 0 ) {
+ return 0;
+ }
+ update_timeinfos( self->samplerate, 0 );
+ std::size_t frames = count / self->num_channels;
+ std::size_t frames_to_render = frames;
+ std::size_t frames_rendered = 0;
+ while ( frames_to_render > 0 ) {
+ std::size_t frames_chunk = std::min( frames_to_render, static_cast<std::size_t>( ( self->samplerate + 99 ) / 100 ) ); // 100 Hz timing info update interval
+ switch ( self->num_channels ) {
+ case 1:
+ {
+ frames_chunk = self->mod->read( self->samplerate, frames_chunk, dstbuf );
+ }
+ break;
+ case 2:
+ {
+ frames_chunk = self->mod->read_interleaved_stereo( self->samplerate, frames_chunk, dstbuf );
+ }
+ break;
+ case 4:
+ {
+ frames_chunk = self->mod->read_interleaved_quad( self->samplerate, frames_chunk, dstbuf );
+ }
+ break;
+ }
+ dstbuf += frames_chunk * self->num_channels;
+ if ( frames_chunk == 0 ) {
+ break;
+ }
+ update_timeinfos( self->samplerate, frames_chunk );
+ frames_to_render -= frames_chunk;
+ frames_rendered += frames_chunk;
+ }
+ if ( frames_rendered == 0 ) {
+ return 0;
+ }
+ return frames_rendered * self->num_channels;
+}
+
+static void add_names( std::ostream & str, const std::string & title, const std::vector<std::string> & names, int display_offset ) {
+ if ( names.size() > 0 ) {
+ bool valid = false;
+ for ( std::size_t i = 0; i < names.size(); i++ ) {
+ if ( names[i] != "" ) {
+ valid = true;
+ }
+ }
+ if ( !valid ) {
+ return;
+ }
+ str << title << " Names:" << "\r";
+ for ( std::size_t i = 0; i < names.size(); i++ ) {
+ str << std::setfill('0') << std::setw(2) << (display_offset + i) << std::setw(0) << "\t" << convert_to_native( names[i] ) << "\r";
+ }
+ str << "\r";
+ }
+}
+
+static void WINAPI openmpt_GetSamples( char * buf ) {
+ if ( !self->mod ) {
+ clear_xmplay_string( buf );
+ return;
+ }
+ std::ostringstream str;
+ add_names( str, "Instrument", self->mod->get_instrument_names(), 1 );
+ add_names( str, "Sample", self->mod->get_sample_names(), 1 );
+ add_names( str, "Channel", self->mod->get_channel_names(), 1 );
+ add_names( str, "Order", self->mod->get_order_names(), 0 );
+ add_names( str, "Pattern", self->mod->get_pattern_names(), 0 );
+ write_xmplay_string( buf, str.str() );
+}
+
+static DWORD WINAPI openmpt_GetSubSongs( float * length ) {
+ *length = 0.0f;
+ for ( auto sub_length : self->subsong_lengths ) {
+ *length += sub_length;
+ }
+
+ return static_cast<DWORD>( self->subsong_lengths.size() );
+}
+
+enum ColorIndex
+{
+ col_background = 0,
+ col_unknown,
+ col_text,
+ col_empty,
+ col_instr,
+ col_vol,
+ col_pitch,
+ col_global,
+
+ col_max
+};
+
+static ColorIndex effect_type_to_color_index( openmpt::ext::pattern_vis::effect_type effect_type ) {
+ switch ( effect_type ) {
+ case openmpt::ext::pattern_vis::effect_unknown: return col_unknown; break;
+ case openmpt::ext::pattern_vis::effect_general: return col_text ; break;
+ case openmpt::ext::pattern_vis::effect_global : return col_global ; break;
+ case openmpt::ext::pattern_vis::effect_volume : return col_vol ; break;
+ case openmpt::ext::pattern_vis::effect_panning: return col_instr ; break;
+ case openmpt::ext::pattern_vis::effect_pitch : return col_pitch ; break;
+ default: return col_unknown; break;
+ }
+}
+
+const struct Columns
+{
+ int num_chars;
+ int color;
+} pattern_columns[] = {
+ { 3, col_text }, // C-5
+ { 2, col_instr }, // 01
+ { 3, col_vol }, // v64
+ { 3, col_pitch }, // EFF
+};
+
+static const int max_cols = 4;
+
+static void assure_width( std::string & str, std::size_t width ) {
+ if ( str.length() == width ) {
+ return;
+ } else if ( str.length() < width ) {
+ str += std::string( width - str.length(), ' ' );
+ } else if ( str.length() > width ) {
+ str = str.substr( 0, width );
+ }
+}
+
+struct ColorRGBA
+{
+ uint8_t r, g, b, a;
+};
+
+union Color
+{
+ ColorRGBA rgba;
+ COLORREF dw;
+};
+
+static_assert(sizeof(Color) == 4);
+
+HDC visDC;
+HGDIOBJ visbitmap;
+
+Color viscolors[col_max];
+HPEN vispens[col_max];
+HBRUSH visbrushs[col_max];
+HFONT visfont;
+static int last_pattern = -1;
+
+static Color invert_color( Color c ) {
+ Color res;
+ res.rgba.a = c.rgba.a;
+ res.rgba.r = 255 - c.rgba.r;
+ res.rgba.g = 255 - c.rgba.g;
+ res.rgba.b = 255 - c.rgba.b;
+ return res;
+}
+
+static BOOL WINAPI VisOpen(DWORD colors[3]) {
+ xmpopenmpt_lock guard;
+ visDC = 0;
+ visbitmap = 0;
+ visfont = 0;
+
+ viscolors[col_background].dw = colors[0];
+ viscolors[col_unknown].dw = colors[1];
+ viscolors[col_text].dw = colors[2];
+
+ viscolors[col_global] = invert_color( viscolors[col_background] );
+
+ const int r = viscolors[col_text].rgba.r, g = viscolors[col_text].rgba.g, b = viscolors[col_text].rgba.b;
+ viscolors[col_empty].rgba.r = static_cast<std::uint8_t>( (r + viscolors[col_background].rgba.r) / 2 );
+ viscolors[col_empty].rgba.g = static_cast<std::uint8_t>( (g + viscolors[col_background].rgba.g) / 2 );
+ viscolors[col_empty].rgba.b = static_cast<std::uint8_t>( (b + viscolors[col_background].rgba.b) / 2 );
+ viscolors[col_empty].rgba.a = 0;
+
+#define MIXCOLOR(col, c1, c2, c3) { \
+ viscolors[col] = viscolors[col_text]; \
+ int mix = viscolors[col].rgba.c1 + 0xA0; \
+ viscolors[col].rgba.c1 = static_cast<std::uint8_t>( mix ); \
+ if ( mix > 0xFF ) { \
+ viscolors[col].rgba.c2 = std::max( static_cast<std::uint8_t>( c2 - viscolors[col].rgba.c1 / 2 ), std::uint8_t(0) ); \
+ viscolors[col].rgba.c3 = std::max( static_cast<std::uint8_t>( c3 - viscolors[col].rgba.c1 / 2 ), std::uint8_t(0) ); \
+ viscolors[col].rgba.c1 = 0xFF; \
+ } }
+
+ MIXCOLOR(col_instr, g, r, b);
+ MIXCOLOR(col_vol, b, r, g);
+ MIXCOLOR(col_pitch, r, g, b);
+#undef MIXCOLOR
+
+ for( int i = 0; i < col_max; ++i ) {
+ vispens[i] = CreatePen( PS_SOLID, 1, viscolors[i].dw );
+ visbrushs[i] = CreateSolidBrush( viscolors[i].dw );
+ }
+
+ clear_current_timeinfo();
+
+ if ( !self->mod ) {
+ return FALSE;
+ }
+ return TRUE;
+}
+static void WINAPI VisClose() {
+ xmpopenmpt_lock guard;
+
+ for( int i = 0; i < col_max; ++i ) {
+ DeletePen( vispens[i] );
+ DeleteBrush( visbrushs[i] );
+ }
+
+ DeleteFont( visfont );
+ DeleteBitmap( visbitmap );
+ if ( visDC ) {
+ DeleteDC( visDC );
+ }
+}
+static void WINAPI VisSize( HDC /* dc */ , SIZE * /* size */ ) {
+ xmpopenmpt_lock guard;
+ last_pattern = -1; // Force redraw
+}
+
+#if 0
+static BOOL WINAPI VisRender( DWORD * /* buf */ , SIZE /* size */ , DWORD /* flags */ ) {
+ xmpopenmpt_lock guard;
+ return FALSE;
+}
+#endif
+
+static int get_pattern_width( int chars_per_channel, int spaces_per_channel, int num_cols, int text_size, int channels )
+{
+ int pattern_width = ((chars_per_channel * channels + 4) * text_size) + (spaces_per_channel * channels + channels - (num_cols == 1 ? 1 : 2)) * (text_size / 2);
+ return pattern_width;
+}
+
+static BOOL WINAPI VisRenderDC( HDC dc, SIZE size, DWORD flags ) {
+ xmpopenmpt_lock guard;
+ RECT rect;
+
+ if ( !visfont ) {
+ // Force usage of a nice monospace font
+ LOGFONT logfont;
+ GetObject ( GetCurrentObject( dc, OBJ_FONT ), sizeof(logfont), &logfont );
+ _tcscpy( logfont.lfFaceName, TEXT("Lucida Console") );
+ visfont = CreateFontIndirect( &logfont );
+ }
+ SIZE text_size;
+ SelectFont( dc, visfont );
+ if ( GetTextExtentPoint32( dc, TEXT("W"), 1, &text_size ) == FALSE ) {
+ return FALSE;
+ }
+
+ if ( flags & XMPIN_VIS_INIT ) {
+ last_pattern = -1;
+ }
+
+ timeinfo info = lookup_timeinfo( xmpfstatus->GetTime() );
+
+ if ( !info.valid ) {
+ RECT bgrect;
+ bgrect.top = 0;
+ bgrect.left = 0;
+ bgrect.right = size.cx;
+ bgrect.bottom = size.cy;
+ FillRect(dc, &bgrect, visbrushs[col_background]);
+ return TRUE;
+ }
+
+ int pattern = info.pattern;
+ int current_row = info.row;
+
+ const std::size_t channels = self->mod->get_num_channels();
+ const std::size_t rows = self->mod->get_pattern_num_rows( pattern );
+
+ const std::size_t num_half_chars = std::max( static_cast<std::size_t>( 2 * size.cx / text_size.cx ), std::size_t(8) ) - 8;
+ //const std::size_t num_rows = size.cy / text_size.cy;
+
+ // Spaces between pattern components are half width, full space at channel end
+ const std::size_t half_chars_per_channel = num_half_chars / channels;
+ std::size_t chars_per_channel, spaces_per_channel;
+ std::size_t num_cols;
+ std::size_t col0_width = pattern_columns[0].num_chars;
+ for ( num_cols = sizeof ( pattern_columns ) / sizeof ( pattern_columns[0] ); num_cols >= 1; num_cols-- ) {
+ chars_per_channel = 0;
+ spaces_per_channel = num_cols > 1 ? num_cols : 0; // No extra space if we only display notes
+ for ( std::size_t i = 0; i < num_cols; i++ ) {
+ chars_per_channel += pattern_columns[i].num_chars;
+ }
+
+ if ( half_chars_per_channel >= chars_per_channel * 2 + spaces_per_channel + 1 || num_cols == 1 ) {
+ break;
+ }
+ }
+
+ if ( !self->settings.vis_allow_scroll ) {
+ if ( num_cols == 1 ) {
+ spaces_per_channel = 0;
+ while ( get_pattern_width( chars_per_channel, spaces_per_channel, num_cols, text_size.cx, channels ) > size.cx && chars_per_channel > 1 ) {
+ chars_per_channel -= 1;
+ }
+ col0_width = chars_per_channel;
+ chars_per_channel = col0_width;
+ }
+ }
+
+ int pattern_width = get_pattern_width( chars_per_channel, spaces_per_channel, num_cols, text_size.cx, channels );
+ int pattern_height = rows * text_size.cy;
+
+ if ( !visDC || last_pattern != pattern ) {
+ DeleteBitmap( visbitmap );
+ if ( visDC ) {
+ DeleteDC( visDC );
+ }
+
+ visDC = CreateCompatibleDC( dc );
+ visbitmap = CreateCompatibleBitmap( dc, pattern_width, pattern_height );
+ SelectBitmap( visDC, visbitmap );
+
+ SelectBrush( visDC, vispens[col_unknown] );
+ SelectBrush( visDC, visbrushs[col_background] );
+
+ SelectFont( visDC, visfont );
+
+ rect.top = 0;
+ rect.left = 0;
+ rect.right = pattern_width;
+ rect.bottom = pattern_height;
+ FillRect( visDC, &rect, visbrushs[col_background] );
+
+ SetBkColor( visDC, viscolors[col_background].dw );
+
+ POINT pos;
+ pos.y = 0;
+
+ for ( std::size_t row = 0; row < rows; row++ ) {
+ pos.x = 0;
+
+ std::ostringstream s;
+ s.imbue(std::locale::classic());
+ s << std::setfill('0') << std::setw(3) << row;
+ const std::string rowstr = s.str();
+
+ SetTextColor( visDC, viscolors[1].dw );
+ TextOutA( visDC, pos.x, pos.y, rowstr.c_str(), rowstr.length() );
+ pos.x += 4 * text_size.cx;
+
+ for ( std::size_t channel = 0; channel < channels; ++channel ) {
+
+ struct coldata {
+ std::string text;
+ bool is_empty;
+ ColorIndex color;
+ coldata()
+ : is_empty(false)
+ , color(col_unknown)
+ {
+ return;
+ }
+ };
+
+ coldata cols[max_cols];
+
+ for ( std::size_t col = 0; col < max_cols; ++col ) {
+ switch ( col ) {
+ case 0:
+ cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_note );
+ break;
+ case 1:
+ cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_instrument );
+ break;
+ case 2:
+ cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_volumeffect )
+ + self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_volume );
+ break;
+ case 3:
+ cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_effect )
+ + self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_parameter );
+ break;
+ }
+ int color = pattern_columns[col].color;
+ if ( self->pattern_vis && ( col == 2 || col == 3 ) ) {
+ if ( col == 2 ) {
+ color = effect_type_to_color_index( self->pattern_vis->get_pattern_row_channel_volume_effect_type( pattern, row, channel ) );
+ }
+ if ( col == 3 ) {
+ color = effect_type_to_color_index( self->pattern_vis->get_pattern_row_channel_effect_type( pattern, row, channel ) );
+ }
+ }
+ switch ( cols[col].text[0] ) {
+ case ' ':
+ [[fallthrough]];
+ case '.':
+ cols[col].is_empty = true;
+ [[fallthrough]];
+ case '^':
+ [[fallthrough]];
+ case '=':
+ [[fallthrough]];
+ case '~':
+ color = col_empty;
+ break;
+ }
+ cols[col].color = (ColorIndex)color;
+
+ }
+
+ if ( num_cols <= 3 && !cols[3].is_empty ) {
+ if ( cols[2].is_empty ) {
+ cols[2] = cols[3];
+ } else if ( cols[0].is_empty ) {
+ cols[0] = cols[3];
+ }
+ }
+
+ if ( num_cols <= 2 && !cols[2].is_empty ) {
+ if ( cols[0].is_empty ) {
+ cols[0] = cols[2];
+ }
+ }
+
+ for ( std::size_t col = 0; col < num_cols; ++col ) {
+
+ std::size_t col_width = ( num_cols > 1 ) ? pattern_columns[col].num_chars : col0_width;
+
+ assure_width( cols[col].text, col_width );
+
+ SetTextColor( visDC, viscolors[cols[col].color].dw );
+ TextOutA( visDC, pos.x, pos.y, cols[col].text.c_str(), cols[col].text.length() );
+ pos.x += col_width * text_size.cx + text_size.cx / 2;
+ }
+ // Extra padding
+ if ( num_cols > 1 ) {
+ pos.x += text_size.cx / 2;
+ }
+ }
+
+ pos.y += text_size.cy;
+ }
+ }
+
+ rect.top = 0;
+ rect.left = 0;
+ rect.right = size.cx;
+ rect.bottom = size.cy;
+ FillRect( dc, &rect, visbrushs[col_background] );
+
+ int offset_x = (size.cx - pattern_width) / 2;
+ int offset_y = (size.cy - text_size.cy) / 2 - current_row * text_size.cy;
+ int src_offset_x = 0;
+ int src_offset_y = 0;
+
+ if ( offset_x < 0 ) {
+ src_offset_x -= offset_x;
+ pattern_width = std::min( static_cast<int>( pattern_width + offset_x ), static_cast<int>( size.cx ) );
+ offset_x = 0;
+ }
+
+ if ( offset_y < 0 ) {
+ src_offset_y -= offset_y;
+ pattern_height = std::min( static_cast<int>( pattern_height + offset_y ), static_cast<int>( size.cy ) );
+ offset_y = 0;
+ }
+
+ BitBlt( dc, offset_x, offset_y, pattern_width, pattern_height, visDC, src_offset_x, src_offset_y , SRCCOPY );
+
+ // Highlight current row
+ rect.left = offset_x;
+ rect.top = (size.cy - text_size.cy) / 2;
+ rect.right = rect.left + pattern_width;
+ rect.bottom = rect.top + text_size.cy;
+ InvertRect( dc, &rect );
+
+ last_pattern = pattern;
+
+ return TRUE;
+}
+
+#if 0
+static void WINAPI VisButton( DWORD /* x */ , DWORD /* y */ ) {
+ //xmpopenmpt_lock guard;
+}
+#endif
+
+static XMPIN xmpin = {
+#ifdef USE_XMPLAY_FILE_IO
+ 0 |
+#else
+ XMPIN_FLAG_NOXMPFILE |
+#endif
+ XMPIN_FLAG_CONFIG | XMPIN_FLAG_LOOP,
+ xmp_openmpt_string,
+ nullptr, // "libopenmpt\0mptm/mptmz",
+ openmpt_About,
+ openmpt_Config,
+ openmpt_CheckFile,
+ openmpt_GetFileInfo,
+ openmpt_Open,
+ openmpt_Close,
+ nullptr, // reserved
+ openmpt_SetFormat,
+ openmpt_GetTags,
+ openmpt_GetInfoText,
+ openmpt_GetGeneralInfo,
+ openmpt_GetMessage,
+ openmpt_SetPosition,
+ openmpt_GetGranularity,
+ nullptr, // GetBuffering
+ openmpt_Process,
+ nullptr, // WriteFile
+ openmpt_GetSamples,
+ openmpt_GetSubSongs, // GetSubSongs
+ nullptr, // GetCues
+ nullptr, // GetDownloaded
+
+ "OpenMPT Pattern Display",
+ VisOpen,
+ VisClose,
+ VisSize,
+ /*VisRender,*/nullptr,
+ VisRenderDC,
+ /*VisButton,*/nullptr,
+
+ nullptr, // reserved2
+ openmpt_GetConfig,
+ openmpt_SetConfig
+};
+
+static const char * xmp_openmpt_default_exts = "OpenMPT\0mptm/mptmz";
+
+static char * file_formats;
+
+static void xmp_openmpt_on_dll_load() {
+ ZeroMemory( &xmpopenmpt_mutex, sizeof( xmpopenmpt_mutex ) );
+ #if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable:28125) // The function 'InitializeCriticalSection' must be called from within a try/except block: The requirement might be conditional.
+ #endif // _MSC_VER
+ InitializeCriticalSection( &xmpopenmpt_mutex );
+ #if defined(_MSC_VER)
+ #pragma warning(pop)
+ #endif // _MSC_VER
+ std::vector<std::string> extensions = openmpt::get_supported_extensions();
+ std::string filetypes_string = "OpenMPT";
+ filetypes_string.push_back('\0');
+ bool first = true;
+ for ( const auto & ext : extensions ) {
+ if ( first ) {
+ first = false;
+ } else {
+ filetypes_string.push_back('/');
+ }
+ filetypes_string += ext;
+ }
+ filetypes_string.push_back('\0');
+ file_formats = (char*)HeapAlloc( GetProcessHeap(), 0, filetypes_string.size() );
+ if ( file_formats ) {
+ std::copy( filetypes_string.begin(), filetypes_string.end(), file_formats );
+ xmpin.exts = file_formats;
+ } else {
+ xmpin.exts = xmp_openmpt_default_exts;
+ }
+ self = new self_xmplay_t();
+}
+
+static void xmp_openmpt_on_dll_unload() {
+ delete self;
+ self = nullptr;
+ if ( xmpin.exts != xmp_openmpt_default_exts ) {
+ HeapFree(GetProcessHeap(), 0, (LPVOID)const_cast<char*>(xmpin.exts));
+ }
+ xmpin.exts = nullptr;
+ DeleteCriticalSection( &xmpopenmpt_mutex );
+}
+
+static XMPIN * XMPIN_GetInterface_cxx( DWORD face, InterfaceProc faceproc ) {
+ if ( face != XMPIN_FACE ) return nullptr;
+ xmpfin=(XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE);
+ xmpfmisc=(XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE);
+ xmpfregistry=(XMPFUNC_REGISTRY*)faceproc(XMPFUNC_REGISTRY_FACE);
+ xmpffile=(XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE);
+ xmpftext=(XMPFUNC_TEXT*)faceproc(XMPFUNC_TEXT_FACE);
+ xmpfstatus=(XMPFUNC_STATUS*)faceproc(XMPFUNC_STATUS_FACE);
+
+ // Register keyboard shortcuts
+ static constexpr std::pair<DWORD, const char *> shortcuts[] = {
+ { openmpt_shortcut_ex | openmpt_shortcut_tempo_decrease, "OpenMPT - Decrease Tempo" },
+ { openmpt_shortcut_ex | openmpt_shortcut_tempo_increase, "OpenMPT - Increase Tempo" },
+ { openmpt_shortcut_ex | openmpt_shortcut_pitch_decrease, "OpenMPT - Decrease Pitch" },
+ { openmpt_shortcut_ex | openmpt_shortcut_pitch_increase, "OpenMPT - Increase Pitch" },
+ { openmpt_shortcut_ex | openmpt_shortcut_switch_interpolation, "OpenMPT - Switch Interpolation" },
+ };
+ XMPSHORTCUT cut;
+ cut.procex = &ShortcutHandler;
+ for ( const auto & shortcut : shortcuts ) {
+ cut.id = shortcut.first;
+ cut.text = shortcut.second;
+ xmpfmisc->RegisterShortcut( &cut );
+ }
+
+ self->settings.load();
+
+ return &xmpin;
+}
+
+extern "C" {
+
+// XMPLAY expects a WINAPI (which is __stdcall) function using an undecorated symbol name.
+#if defined(__GNUC__)
+XMPIN * WINAPI XMPIN_GetInterface_( DWORD face, InterfaceProc faceproc );
+XMPIN * WINAPI XMPIN_GetInterface_( DWORD face, InterfaceProc faceproc ) {
+ return XMPIN_GetInterface_cxx( face, faceproc );
+}
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattribute-alias"
+// clang-format off
+__declspec(dllexport) void XMPIN_GetInterface() __attribute__((alias("XMPIN_GetInterface_@8")));
+// clang-format on
+#pragma GCC diagnostic pop
+#else
+XMPIN * WINAPI XMPIN_GetInterface( DWORD face, InterfaceProc faceproc ) {
+ return XMPIN_GetInterface_cxx( face, faceproc );
+}
+#pragma comment(linker, "/EXPORT:XMPIN_GetInterface=_XMPIN_GetInterface@8")
+#endif
+
+} // extern "C"
+
+
+#if defined(MPT_WITH_MFC) && defined(_MFC_VER)
+
+namespace libopenmpt {
+namespace plugin {
+
+void DllMainAttach() {
+ xmp_openmpt_on_dll_load();
+}
+
+void DllMainDetach() {
+ xmp_openmpt_on_dll_unload();
+}
+
+} // namespace plugin
+} // namespace libopenmpt
+
+#else
+
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved );
+BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) {
+ static_cast<void>(hinstDLL);
+ static_cast<void>(lpvReserved);
+ switch ( fdwReason ) {
+ case DLL_PROCESS_ATTACH:
+ xmp_openmpt_on_dll_load();
+ break;
+ case DLL_PROCESS_DETACH:
+ xmp_openmpt_on_dll_unload();
+ break;
+ }
+ return TRUE;
+}
+
+#endif
+
+
+#endif // NO_XMPLAY