Updated libOpenMPT to version 0.7.2

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2023-06-30 23:28:42 -07:00
parent 69251314c4
commit b2657700eb
32 changed files with 269 additions and 125 deletions

View file

@ -1,4 +1,4 @@
MPT_SVNVERSION=19147
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.0
MPT_SVNDATE=2023-04-30T12:58:58.547157Z
MPT_SVNVERSION=19406
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.2
MPT_SVNDATE=2023-06-18T13:08:13.199805Z

View file

@ -48,8 +48,8 @@ LDFLAGS += -pthread
endif
ifeq ($(EMSCRIPTEN_PORTS),1)
CXXFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1 -DMPT_WITH_ZLIB -DMPT_WITH_MPG123 -DMPT_WITH_VORBIS -DMPT_WITH_VORBISFI
CFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1 -DMPT_WITH_ZLIB -DMPT_WITH_MPG123 -DMPT_WITH_VORBIS -DMPT_WITH_VORBISFI
CXXFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1 -DMPT_WITH_ZLIB -DMPT_WITH_MPG123 -DMPT_WITH_VORBIS -DMPT_WITH_VORBISFILE -DMPT_WITH_OGG
CFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1 -DMPT_WITH_ZLIB -DMPT_WITH_MPG123 -DMPT_WITH_VORBIS -DMPT_WITH_VORBISFILE -DMPT_WITH_OGG
LDFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1
NO_MINIZ=1
NO_MINIMP3=1

View file

@ -1,10 +1,10 @@
#pragma once
#define OPENMPT_VERSION_SVNVERSION "19147"
#define OPENMPT_VERSION_REVISION 19147
#define OPENMPT_VERSION_SVNVERSION "19406"
#define OPENMPT_VERSION_REVISION 19406
#define OPENMPT_VERSION_DIRTY 0
#define OPENMPT_VERSION_MIXEDREVISIONS 0
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.0"
#define OPENMPT_VERSION_DATE "2023-04-30T12:58:58.547157Z"
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.2"
#define OPENMPT_VERSION_DATE "2023-06-18T13:08:13.199805Z"
#define OPENMPT_VERSION_IS_PACKAGE 1

View file

@ -106,15 +106,13 @@
// Support for externally linked samples e.g. in MPTM files
#define MPT_EXTERNAL_SAMPLES
// Support mpt::ChartsetLocale
// Support mpt::CharsetLocale
#define MPT_ENABLE_CHARSET_LOCALE
// Use architecture-specific intrinsics
#define MPT_ENABLE_ARCH_INTRINSICS
#if !defined(MPT_BUILD_RETRO)
#define MPT_ENABLE_UPDATE
#endif // !MPT_BUILD_RETRO
// Disable unarchiving support
//#define NO_ARCHIVE_SUPPORT

View file

@ -30,6 +30,7 @@
#include <string>
#include <vector>
#include <cstddef>
#include <cstring>
#include "FileReaderFwd.h"

View file

@ -80,25 +80,18 @@ struct Gregorian
int64 seconds = 0;
friend bool operator==(const Gregorian<tz>& lhs, const Gregorian<tz>& rhs)
{
return true
&& lhs.year == rhs.year
&& lhs.month == rhs.month
&& lhs.day == rhs.day
&& lhs.hours == rhs.hours
&& lhs.minutes == rhs.minutes
&& lhs.seconds == rhs.seconds
;
return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, lhs.seconds)
== std::tie(rhs.year, rhs.month, rhs.day, rhs.hours, rhs.minutes, rhs.seconds);
}
friend bool operator!=(const Gregorian<tz>& lhs, const Gregorian<tz>& rhs)
{
return false
|| lhs.year != rhs.year
|| lhs.month != rhs.month
|| lhs.day != rhs.day
|| lhs.hours != rhs.hours
|| lhs.minutes != rhs.minutes
|| lhs.seconds != rhs.seconds
;
return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, lhs.seconds)
!= std::tie(rhs.year, rhs.month, rhs.day, rhs.hours, rhs.minutes, rhs.seconds);
}
friend bool operator<(const Gregorian<tz> &lhs, const Gregorian<tz> &rhs)
{
return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, lhs.seconds)
< std::tie(rhs.year, rhs.month, rhs.day, rhs.hours, rhs.minutes, rhs.seconds);
}
};
@ -256,7 +249,11 @@ inline mpt::Date::Unix UnixFromLocal(Local local)
std::chrono::hours{ local.hours } +
std::chrono::minutes{ local.minutes } +
std::chrono::seconds{ local.seconds };
#if defined(MPT_LIBCXX_QUIRK_CHRONO_DATE_BROKEN_ZONED_TIME)
return std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::current_zone()->to_sys(local_tp)}.get_sys_time();
#else
return std::chrono::zoned_time{std::chrono::current_zone(), local_tp}.get_sys_time();
#endif
} catch(const std::exception &)
{
return mpt::Date::UnixFromSeconds(mpt::Date::nochrono::UnixAsSeconds(mpt::Date::nochrono::UnixFromLocal(local)));

View file

@ -17,7 +17,7 @@ OPENMPT_NAMESPACE_BEGIN
// Version definitions. The only thing that needs to be changed when changing version number.
#define VER_MAJORMAJOR 1
#define VER_MAJOR 31
#define VER_MINOR 01
#define VER_MINOR 03
#define VER_MINORMINOR 00
OPENMPT_NAMESPACE_END

View file

@ -573,7 +573,7 @@ End Type
\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().
\param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
\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
@ -590,7 +590,7 @@ Declare Function openmpt_module_create(ByVal stream_callbacks As openmpt_stream_
\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().
\param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
\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
@ -604,7 +604,7 @@ Declare Function openmpt_module_create2(ByVal stream_callbacks As openmpt_stream
\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().
\param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
\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.
'/
@ -620,7 +620,7 @@ Declare Function openmpt_module_create_from_memory(ByVal filedata As Const Any P
\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().
\param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
\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

View file

@ -670,7 +670,7 @@ typedef struct openmpt_module_initial_ctl {
* \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()
* \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
* \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
@ -689,7 +689,7 @@ LIBOPENMPT_API LIBOPENMPT_DEPRECATED openmpt_module * openmpt_module_create( ope
* \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()
* \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
* \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
@ -704,7 +704,7 @@ LIBOPENMPT_API openmpt_module * openmpt_module_create2( openmpt_stream_callbacks
* \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()
* \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
* \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
@ -722,7 +722,7 @@ LIBOPENMPT_API LIBOPENMPT_DEPRECATED openmpt_module * openmpt_module_create_from
* \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()
* \param ctls An array of initial ctl and value pairs stored in \ref openmpt_module_initial_ctl, terminated by a pair of NULL and NULL. See \ref openmpt_module_get_ctls and \ref openmpt_module_ctl_set.
* \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

View file

@ -468,7 +468,7 @@ public:
/*!
\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.
\param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set.
\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
@ -477,7 +477,7 @@ public:
/*!
\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.
\param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set.
\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
@ -488,7 +488,7 @@ public:
\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.
\param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set.
\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
@ -509,7 +509,7 @@ public:
/*!
\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.
\param ctls A map of initial ctl values, see \ref openmpt::module::get_ctls and openmpt::module::ctl_set.
\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
@ -848,7 +848,7 @@ public:
\return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used.
\deprecated Please use openmpt::module::get_current_tempo2().
*/
LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_ATTR_DEPRECATED std::int32_t get_current_tempo() const;
LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_tempo() 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.
@ -1102,7 +1102,7 @@ public:
\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_CXX_API_MEMBER LIBOPENMPT_ATTR_DEPRECATED std::string ctl_get( const std::string & ctl ) const;
LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API_MEMBER std::string ctl_get( const std::string & ctl ) const;
//! Get current ctl boolean value
/*!
\param ctl The ctl key whose value should be retrieved.
@ -1144,7 +1144,7 @@ public:
\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_CXX_API_MEMBER LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value );
LIBOPENMPT_ATTR_DEPRECATED LIBOPENMPT_CXX_API_MEMBER 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.

View file

@ -21,7 +21,7 @@
/*! \brief libopenmpt minor version number */
#define OPENMPT_API_VERSION_MINOR 7
/*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 0
#define OPENMPT_API_VERSION_PATCH 2
/*! \brief libopenmpt pre-release tag */
#define OPENMPT_API_VERSION_PREREL ""
/*! \brief libopenmpt pre-release flag */

View file

@ -1,8 +1,8 @@
LIBOPENMPT_VERSION_MAJOR=0
LIBOPENMPT_VERSION_MINOR=7
LIBOPENMPT_VERSION_PATCH=0
LIBOPENMPT_VERSION_PATCH=2
LIBOPENMPT_VERSION_PREREL=
LIBOPENMPT_LTVER_CURRENT=4
LIBOPENMPT_LTVER_REVISION=0
LIBOPENMPT_LTVER_REVISION=2
LIBOPENMPT_LTVER_AGE=4

View file

@ -1269,6 +1269,8 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info)
m_Envelopes.push_back(dlsEnv);
rgn.uPercEnv = static_cast<uint32>(m_Envelopes.size());
pDlsEnv = &m_Envelopes[rgn.uPercEnv - 1];
if(globalZone.uPercEnv)
*pDlsEnv = m_Envelopes[globalZone.uPercEnv - 1];
}
// Region Default Values
@ -2271,10 +2273,10 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui
if(isDrum)
{
// Create a default envelope for drums
pIns->VolEnv.dwFlags.reset(ENV_SUSTAIN);
if(!pIns->VolEnv.dwFlags[ENV_ENABLED])
{
pIns->VolEnv.dwFlags.set(ENV_ENABLED);
pIns->VolEnv.dwFlags.reset(ENV_SUSTAIN);
pIns->VolEnv.resize(4);
pIns->VolEnv[0] = EnvelopeNode(0, ENVELOPE_MAX);
pIns->VolEnv[1] = EnvelopeNode(ScaleEnvelope(5, tempoScale), ENVELOPE_MAX);

View file

@ -361,7 +361,7 @@ struct DSmFileHeader
{
return !memcmp(magic, "DSm\x1A", 4)
&& version == 0x20
&& numChannels >= 1 && numChannels <= 32
&& numChannels >= 1 && numChannels <= 16
&& numSamples > 0
&& numOrders > 0
&& globalVol <= 100;

View file

@ -488,9 +488,9 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
m_dwLastSavedWithVersion = MPT_V("1.17.00.00");
} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && fileHeader.reserved == 0)
{
// ModPlug Tracker b3.3 - 1.09, instruments 557 bytes apart
// ModPlug Tracker b3.2 - 1.09, instruments 557 bytes apart
m_dwLastSavedWithVersion = MPT_V("1.09.00.00");
madeWithTracker = U_("ModPlug Tracker b3.3 - 1.09");
madeWithTracker = U_("ModPlug Tracker b3.2 - 1.09");
interpretModPlugMade = true;
} else if(fileHeader.cwtv == 0x0300 && fileHeader.cmwt == 0x0300 && fileHeader.reserved == 0 && fileHeader.ordnum == 256 && fileHeader.sep == 128 && fileHeader.pwd == 0)
{
@ -1192,11 +1192,33 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
&& fileHeader.msglength == 0 && fileHeader.msgoffset == 0 && fileHeader.reserved == 0)
{
madeWithTracker = U_("OpenSPC conversion");
} else if(fileHeader.cwtv == 0x0202 && fileHeader.cmwt == 0x0200 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.reserved == 0 && !patPos.empty() && !smpPos.empty() && patPos[0] != 0 && patPos[0] < smpPos[0])
{
// ModPlug Tracker 1.0 pre-alpha up to alpha 4, patterns located before instruments / samples
m_dwLastSavedWithVersion = MPT_V("1.00.00.A0");
madeWithTracker = U_("ModPlug Tracker 1.0 pre-alpha / alpha");
interpretModPlugMade = true;
} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.reserved == 0)
{
// ModPlug Tracker 1.00a5, instruments 560 bytes apart
m_dwLastSavedWithVersion = MPT_V("1.00.00.A5");
madeWithTracker = U_("ModPlug Tracker 1.00a5");
if(fileHeader.special & (ITFileHeader::embedPatternHighlights | ITFileHeader::embedEditHistory))
{
// ModPlug Tracker 1.0a6/b1/b2
// Instruments are 557 bytes apart in beta 2.3, in beta 1 still 560 bytes like in earlier versions
if(insPos.size() >= 2 && insPos[1] - insPos[0] == 557)
{
m_dwLastSavedWithVersion = MPT_V("1.00.00.B2");
madeWithTracker = U_("ModPlug Tracker 1.0b2");
} else
{
m_dwLastSavedWithVersion = MPT_V("1.00.00.B1");
madeWithTracker = U_("ModPlug Tracker 1.0 alpha / beta");
}
} else
{
// ModPlug Tracker 1.0a5, instruments 560 bytes apart
m_dwLastSavedWithVersion = MPT_V("1.00.00.A5");
madeWithTracker = U_("ModPlug Tracker 1.0a5");
}
interpretModPlugMade = true;
} else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !memcmp(&fileHeader.reserved, "CHBI", 4))
{
@ -2118,11 +2140,11 @@ std::pair<bool, bool> CSoundFile::LoadMixPlugins(FileReader &file)
else if(code[0] == 'F' && (code[1] == 'X' || MPT_ISDIGIT(1)) && MPT_ISDIGIT(2) && MPT_ISDIGIT(3))
#undef MPT_ISDIGIT
{
PLUGINDEX plug = (code[2] - '0') * 10 + (code[3] - '0'); //calculate plug-in number.
if(code[1] != 'X') plug += (code[1] - '0') * 100;
if(plug < MAX_MIXPLUGINS)
uint16 fxplug = (code[2] - '0') * 10 + (code[3] - '0'); //calculate plug-in number.
if(code[1] != 'X') fxplug += (code[1] - '0') * 100;
if(fxplug < MAX_MIXPLUGINS)
{
PLUGINDEX plug = static_cast<PLUGINDEX>(fxplug);
ReadMixPluginChunk(chunk, m_MixPlugins[plug]);
}
hasPluginChunks = true;

View file

@ -1302,6 +1302,7 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags)
}
PATTERNINDEX numPatterns = songHeader.numBlocks;
LimitMax(numPatterns, static_cast<PATTERNINDEX>(PATTERNINDEX_INVALID - basePattern));
Patterns.ResizeArray(basePattern + numPatterns);
for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
{

View file

@ -1415,7 +1415,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
if(!sampleChunk.chunk.IsValid())
continue;
SAMPLEINDEX sharedOggHeader = smp + sampleChunk.sharedHeader;
SAMPLEINDEX sharedOggHeader = (smp + sampleChunk.sharedHeader > 0) ? static_cast<SAMPLEINDEX>(smp + sampleChunk.sharedHeader) : smp;
// Which chunk are we going to read the header from?
// Note: Every Ogg stream has a unique serial number.
// stb_vorbis (currently) ignores this serial number so we can just stitch

View file

@ -786,6 +786,12 @@ static bool CheckMODMagic(const char magic[4], MODMagicResult &result)
// Hacked .DMF files from the game "Apocalypse Abyss"
result.numChannels = 4;
result.swapBytes = true;
} else if(IsMagic(magic, "WARD"))
{
// MUSIC*.DTA files from the DOS game Aleshar - The World Of Ice
result.madeWithTracker = UL_("Generic MOD-compatible Tracker");
result.isGenericMultiChannel = true;
result.numChannels = 8;
} else
{
return false;

View file

@ -1,7 +1,7 @@
/*
* Load_xmf.cpp
* ------------
* Purpose: Module loader for music files from the DOS game "Imperium Galactica"
* Purpose: Module loader for music files from the DOS game "Imperium Galactica" and various Astroidea demos
* Notes : This format has nothing to do with the XMF format by the MIDI foundation.
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
@ -33,7 +33,7 @@ struct XMFSampleHeader
uint8 flags;
uint16le sampleRate;
bool IsValid() const noexcept
bool IsValid(uint8 type) const noexcept
{
if(flags & ~(smp16Bit | smpEnableLoop | smpBidiLoop))
return false;
@ -42,13 +42,15 @@ struct XMFSampleHeader
if(dataStart.get() > dataEnd.get())
return false;
const uint32 length = dataEnd.get() - dataStart.get();
if(length > 0 && sampleRate < 100)
if(type != 2 && length > 0 && sampleRate < 100)
return false;
if(type == 2 && length > 0 && sampleRate >= 0x8000) // Any values != 0 are not really usable but when they turn negative, playback really goes haywire
return false;
if((flags & smp16Bit) && (length % 2u))
return false;
if((flags & smpEnableLoop) && !loopEnd.get())
return false;
if(loopEnd.get() != 0 && (loopEnd.get() > length || loopStart.get() >= loopEnd.get()))
if(loopEnd.get() != 0 && (loopEnd.get() >= length || loopStart.get() >= loopEnd.get()))
return false;
return true;
}
@ -58,12 +60,12 @@ struct XMFSampleHeader
return dataEnd.get() > dataStart.get();
}
void ConvertToMPT(ModSample &mptSmp) const
void ConvertToMPT(ModSample &mptSmp, uint8 type) const
{
mptSmp.Initialize(MOD_TYPE_MOD);
mptSmp.nLength = dataEnd.get() - dataStart.get();
mptSmp.nLoopStart = loopStart.get();
mptSmp.nLoopEnd = loopEnd.get();
mptSmp.nLoopStart = loopStart.get() + 1u;
mptSmp.nLoopEnd = loopEnd.get() + 1u;
mptSmp.uFlags.set(CHN_LOOP, flags & smpEnableLoop);
mptSmp.uFlags.set(CHN_PINGPONGLOOP, flags & smpBidiLoop);
if(flags & smp16Bit)
@ -72,7 +74,8 @@ struct XMFSampleHeader
mptSmp.nLength /= 2;
}
mptSmp.nVolume = defaultVolume;
mptSmp.nC5Speed = sampleRate;
if(type != 2)
mptSmp.nC5Speed = sampleRate;
mptSmp.FrequencyToTranspose();
}
};
@ -80,22 +83,30 @@ struct XMFSampleHeader
MPT_BINARY_STRUCT(XMFSampleHeader, 16)
static bool TranslateXMFEffect(ModCommand &m, uint8 command, uint8 param)
static bool TranslateXMFEffect(ModCommand &m, uint8 command, uint8 param, uint8 type)
{
if(command == 0x0B && param < 0xFF)
{
param++;
} else if(command == 0x10)
} else if(command == 0x10 || command == 0x11)
{
param = 0x80 | (command << 4) | (param & 0x0F);
command = 0x0E;
param = 0x80 | (param & 0x0F);
} else if(command > 0x10)
} else if(command == 0x12)
{
// The ULT to XMF converter uses this to translate ULT command 5 but the player does not handle this command. Thus we will simply ignore it.
command = param = 0;
} else if(command > 0x12)
{
return false;
}
CSoundFile::ConvertModCommand(m, command, param);
if(m.command == CMD_VOLUME)
if(type == 4 && m.command == CMD_VOLUME && (!(m.param & 0x03) || m.param == 0xFF))
m.param = static_cast<ModCommand::PARAM>((m.param + 3u) / 4u);
else if(m.command == CMD_VOLUME)
m.command = CMD_VOLUME8;
if(type != 4 && m.command == CMD_TEMPO && m.param == 0x20)
m.command = CMD_SPEED;
return true;
}
@ -104,7 +115,8 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXMF(MemoryFileReader file, co
{
if(!file.CanRead(1))
return ProbeWantMoreData;
if(file.ReadUint8() != 0x03)
uint8 type = file.ReadUint8();
if(type < 2 || type > 4)
return ProbeFailure;
constexpr size_t probeHeaders = std::min(size_t(256), (ProbeRecommendedSize - 1) / sizeof(XMFSampleHeader));
@ -113,7 +125,7 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXMF(MemoryFileReader file, co
XMFSampleHeader sampleHeader;
if(!file.ReadStruct(sampleHeader))
return ProbeWantMoreData;
if(!sampleHeader.IsValid())
if(!sampleHeader.IsValid(type))
return ProbeFailure;
}
@ -125,7 +137,11 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXMF(MemoryFileReader file, co
bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags)
{
file.Rewind();
if(file.ReadUint8() != 0x03)
uint8 type = file.ReadUint8();
// Type 2: Old UltraTracker finetune behaviour, automatic tone portamento
// Type 3: Normal finetune behaviour, automatic tone portamento (like in ULT)
// Type 4: Normal finetune behaviour, manual tone portamento (like in MOD)
if(type < 2 || type > 4)
return false;
if(!file.CanRead(256 * sizeof(XMFSampleHeader) + 256 + 3))
return false;
@ -135,7 +151,7 @@ bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags)
{
XMFSampleHeader sampleHeader;
file.ReadStruct(sampleHeader);
if(!sampleHeader.IsValid())
if(!sampleHeader.IsValid(type))
return false;
if(sampleHeader.HasSampleData())
numSamples = smp;
@ -147,15 +163,16 @@ bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags)
InitializeGlobals(MOD_TYPE_MOD);
m_SongFlags.set(SONG_IMPORTED);
m_SongFlags.reset(SONG_ISAMIGA);
m_nSamples = numSamples;
m_nSamplePreAmp = 192;
m_nSamplePreAmp = (type == 3) ? 192 : 48; // Imperium Galactica files are really quiet, no other XMFs appear to use type 3
file.Seek(1);
for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++)
{
XMFSampleHeader sampleHeader;
file.ReadStruct(sampleHeader);
sampleHeader.ConvertToMPT(Samples[smp]);
sampleHeader.ConvertToMPT(Samples[smp], type);
m_szNames[smp] = "";
}
@ -186,18 +203,16 @@ bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags)
continue;
}
ModCommand dummy;
for(ROWINDEX row = 0; row < 64; row++)
for(ModCommand &m : Patterns[pat])
{
for(ModCommand &m : Patterns[pat].GetRow(row))
{
const auto data = file.ReadArray<uint8, 6>();
if(data[0] > 0 && data[0] <= 77)
m.note = NOTE_MIN + 35 + data[0];
m.instr = data[1];
if(!TranslateXMFEffect(m, data[2], data[5]) || !TranslateXMFEffect(dummy, data[3], data[4]))
return false;
const auto data = file.ReadArray<uint8, 6>();
if(data[0] > 0 && data[0] <= 77)
m.note = NOTE_MIN + 35 + data[0];
m.instr = data[1];
if(!TranslateXMFEffect(m, data[2], data[5], type) || !TranslateXMFEffect(dummy, data[3], data[4], type))
return false;
if(dummy.command != CMD_NONE)
m.FillInTwoCommands(m.command, m.param, dummy.command, dummy.param);
}
}
}
@ -212,7 +227,7 @@ bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags)
}
}
m_modFormat.formatName = UL_("Imperium Galactica XMF");
m_modFormat.formatName = UL_("Astroidea XMF");
m_modFormat.type = UL_("xmf");
m_modFormat.madeWithTracker.clear();
m_modFormat.charset = mpt::Charset::CP437; // No strings in this format...

View file

@ -13,10 +13,10 @@
#include "Snd_defs.h"
class Opal;
OPENMPT_NAMESPACE_BEGIN
class Opal;
class OPL
{
public:

View file

@ -396,21 +396,20 @@ bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file,
std::string sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(tags));
if(rawData.size() / numChannels / (bitsPerSample / 8) > MAX_SAMPLE_LENGTH)
const size_t length = rawData.size() / numChannels / (bitsPerSample / 8);
if(length < 1 || length > MAX_SAMPLE_LENGTH)
{
return false;
}
SmpLength length = mpt::saturate_cast<SmpLength>(rawData.size() / numChannels / (bitsPerSample/8));
DestroySampleThreadsafe(sample);
if(!mo3Decode)
{
m_szNames[sample] = sampleName;
Samples[sample].Initialize();
Samples[sample].nC5Speed = samplesPerSecond;
m_szNames[sample] = sampleName;
}
Samples[sample].nLength = length;
Samples[sample].nLength = static_cast<SmpLength>(length);
Samples[sample].uFlags.set(CHN_16BIT, bitsPerSample >= 16);
Samples[sample].uFlags.set(CHN_STEREO, numChannels == 2);
Samples[sample].AllocateSample();
@ -423,24 +422,24 @@ bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file,
{
if(numChannels == 2)
{
CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(Samples[sample], rawData.data(), rawData.size());
CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24>>>(Samples[sample], rawData.data(), rawData.size());
} else
{
CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(Samples[sample], rawData.data(), rawData.size());
CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24>>>(Samples[sample], rawData.data(), rawData.size());
}
} else if(bitsPerSample == 32)
{
if(numChannels == 2)
{
CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(Samples[sample], rawData.data(), rawData.size());
CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32>>>(Samples[sample], rawData.data(), rawData.size());
} else
{
CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(Samples[sample], rawData.data(), rawData.size());
CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32>>>(Samples[sample], rawData.data(), rawData.size());
}
} else
{
// just copy
std::copy(rawData.data(), rawData.data() + rawData.size(), mpt::byte_cast<char*>(Samples[sample].sampleb()));
std::copy(rawData.begin(), rawData.end(), mpt::byte_cast<char *>(Samples[sample].sampleb()));
}
#undef MPT_MF_CHECKED

View file

@ -295,12 +295,14 @@ bool CSoundFile::ReadSampleFromSong(SAMPLEINDEX targetSample, const CSoundFile &
return false;
}
if(GetNumSamples() < targetSample)
m_nSamples = targetSample;
DestroySampleThreadsafe(targetSample);
const ModSample &sourceSmp = srcSong.GetSample(sourceSample);
ModSample &targetSmp = GetSample(targetSample);
if(GetNumSamples() < targetSample) m_nSamples = targetSample;
targetSmp = sourceSmp;
m_szNames[targetSample] = srcSong.m_szNames[sourceSample];

View file

@ -254,6 +254,19 @@ struct FileHistory
{
return loadDate != mpt::Date::AnyGregorian{};
}
bool operator==(const FileHistory &other) const noexcept
{
return std::tie(loadDate, openTime) == std::tie(other.loadDate, other.openTime);
}
bool operator!=(const FileHistory &other) const noexcept
{
return std::tie(loadDate, openTime) != std::tie(other.loadDate, other.openTime);
}
bool operator<(const FileHistory &other) const noexcept
{
return std::tie(loadDate, openTime) < std::tie(other.loadDate, other.openTime);
}
};

View file

@ -103,7 +103,7 @@ static constexpr ModFormatInfo modFormatInfo[] =
{ UL_("Graoumf Tracker 1 / 2"), "gt2"},
{ UL_("UltraTracker"), "ult" },
{ UL_("Mod's Grave"), "wow" },
{ UL_("Imperium Galactica"), "xmf" },
{ UL_("Astroidea XMF"), "xmf" },
// converted formats (no MODTYPE)
{ UL_("General Digital Music"), "gdm" },
{ UL_("Un4seen MO3"), "mo3" },

View file

@ -25,6 +25,8 @@
OPENMPT_NAMESPACE_BEGIN
//==================================================================================================
// Opal class.
//==================================================================================================
@ -1343,3 +1345,5 @@ void Opal::Operator::ComputeKeyScaleLevel() {
uint16_t i = (Chan->GetOctave() << 4) | (Chan->GetFreq() >> 6);
KeyScaleLevel = levtab[i] >> KeyScaleShift;
}
OPENMPT_NAMESPACE_END

View file

@ -66,7 +66,7 @@
#define MPT_ARCH_X86_CX8
#define MPT_ARCH_X86_CMOV
#define MPT_ARCH_X86_MMX
#define MPT_ARCH_X86_3DNOWPREFETCH
#define MPT_ARCH_X86_MMXEXT
#define MPT_ARCH_X86_FXSR
#define MPT_ARCH_X86_SSE
#define MPT_ARCH_X86_SSE2
@ -81,7 +81,7 @@
#define MPT_ARCH_X86_CX8
#define MPT_ARCH_X86_CMOV
#define MPT_ARCH_X86_MMX
#define MPT_ARCH_X86_3DNOWPREFETCH
#define MPT_ARCH_X86_MMXEXT
#define MPT_ARCH_X86_FXSR
#define MPT_ARCH_X86_SSE
#define MPT_ARCH_X86_SSE2
@ -95,7 +95,7 @@
#define MPT_ARCH_X86_CX8
#define MPT_ARCH_X86_CMOV
#define MPT_ARCH_X86_MMX
#define MPT_ARCH_X86_3DNOWPREFETCH
#define MPT_ARCH_X86_MMXEXT
#define MPT_ARCH_X86_FXSR
#define MPT_ARCH_X86_SSE
#elif MPT_MSVC_AT_LEAST(2008, 0)
@ -120,6 +120,7 @@
#endif
#endif
#if defined(__AVX__)
#define MPT_ARCH_X86_3DNOWPREFETCH
#ifndef MPT_ARCH_X86_XSAVE
#define MPT_ARCH_X86_XSAVE
#endif
@ -169,17 +170,22 @@
#define MPT_ARCH_X86_MMX
#endif
#ifdef __3dNOW__
#define MPT_ARCH_X86_MMXEXT
#define MPT_ARCH_X86_3DNOW
#endif
#ifdef __3dNOW_A__
#define MPT_ARCH_X86_MMXEXT
#define MPT_ARCH_X86_3DNOWEXT
#endif
#ifdef __PRFCHW__
#define MPT_ARCH_X86_3DNOWPREFETCH
#endif
#ifdef __FXSR__
#define MPT_ARCH_X86_FXSR
#endif
#ifdef __SSE__
#define MPT_ARCH_X86_3DNOWPREFETCH
#ifndef MPT_ARCH_X86_MMXEXT
#define MPT_ARCH_X86_MMXEXT
#endif
#define MPT_ARCH_X86_SSE
#ifndef MPT_ARCH_X86_CMOV
#define MPT_ARCH_X86_CMOV
@ -317,7 +323,7 @@ inline constexpr feature_flags intel586 = featureset::intel486DX | fea
inline constexpr feature_flags intel586_mmx = featureset::intel586 | feature::mmx;
inline constexpr feature_flags intel686 = featureset::intel586 | feature::cmov;
inline constexpr feature_flags intel686_mmx = featureset::intel686 | feature::mmx;
inline constexpr feature_flags intel686_sse = featureset::intel686_mmx | feature::fxsr | feature::sse | feature::x3dnowprefetch;
inline constexpr feature_flags intel686_sse = featureset::intel686_mmx | feature::mmxext | feature::fxsr | feature::sse;
inline constexpr feature_flags intel686_sse2 = featureset::intel686_sse | feature::sse2;
inline constexpr feature_flags intel786 = featureset::intel686_sse2;
inline constexpr feature_flags amd64 = featureset::intel686_sse2;
@ -328,8 +334,8 @@ inline constexpr feature_flags msvc_x86_2005 = featureset::intel486DX;
inline constexpr feature_flags msvc_x86_2008 = featureset::intel586;
inline constexpr feature_flags msvc_x86_sse = featureset::intel686_sse;
inline constexpr feature_flags msvc_x86_sse2 = featureset::intel686_sse2;
inline constexpr feature_flags msvc_x86_avx = featureset::intel686_sse2 | feature::xsave | feature::avx;
inline constexpr feature_flags msvc_x86_avx2 = featureset::intel686_sse2 | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1;
inline constexpr feature_flags msvc_x86_avx = featureset::intel686_sse2 | feature::x3dnowprefetch | feature::xsave | feature::avx;
inline constexpr feature_flags msvc_x86_avx2 = featureset::intel686_sse2 | feature::x3dnowprefetch | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1;
inline constexpr feature_flags msvc_amd64 = featureset::amd64;
inline constexpr feature_flags msvc_amd64_avx = featureset::amd64 | feature::xsave | feature::avx;
inline constexpr feature_flags msvc_amd64_avx2 = featureset::amd64 | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1;
@ -359,7 +365,7 @@ inline constexpr mode_flags msvc_x86_avx2 = mode::base | mode::xmm128sse | mod
inline constexpr mode_flags msvc_amd64 = mode::base | mode::xmm128sse;
inline constexpr mode_flags msvc_amd64_avx = mode::base | mode::xmm128sse | mode::ymm256avx;
inline constexpr mode_flags msvc_amd64_avx2 = mode::base | mode::xmm128sse | mode::ymm256avx;
} // namespace featureset
} // namespace modeset
// clang-format on
@ -1351,7 +1357,7 @@ public:
Features |= (StandardFeatureFlags.d & (1u << 15)) ? (feature::cmov) : feature::none;
Features |= (StandardFeatureFlags.d & (1u << 23)) ? (feature::mmx) : feature::none;
Features |= (StandardFeatureFlags.d & (1u << 24)) ? (feature::fxsr) : feature::none;
Features |= (StandardFeatureFlags.d & (1u << 25)) ? (feature::sse | feature::x3dnowprefetch) : feature::none;
Features |= (StandardFeatureFlags.d & (1u << 25)) ? (feature::sse | feature::mmxext) : feature::none;
Features |= (StandardFeatureFlags.d & (1u << 26)) ? (feature::sse2) : feature::none;
Features |= (StandardFeatureFlags.c & (1u << 0)) ? (feature::sse3) : feature::none;
Features |= (StandardFeatureFlags.c & (1u << 9)) ? (feature::ssse3) : feature::none;
@ -1644,7 +1650,7 @@ public:
Features |= (IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE_DOUBLE) != 0) ? (feature::cx8 | feature::intel486) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::mmx | feature::intel486) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::x3dnow) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse | feature::fxsr | feature::x3dnowprefetch | feature::cmov) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse | feature::mmxext | feature::fxsr | feature::cmov) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse2) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse3) : feature::none;
Features |= (IsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::ssse3) : feature::none;

View file

@ -13,6 +13,9 @@
#if MPT_CXX_BEFORE(20)
#include <array>
#endif // !C++20
#if defined(MPT_COMPILER_QUIRK_BROKEN_BITCAST)
#include <atomic>
#endif
#if MPT_CXX_AT_LEAST(20)
#include <bit>
#endif // C++20
@ -21,7 +24,7 @@
#endif // !C++23
#include <type_traits>
#if MPT_CXX_BEFORE(20) || MPT_LIBCXX_GNU_BEFORE(11) || MPT_LIBCXX_LLVM_BEFORE(14000)
#if MPT_CXX_BEFORE(20) || MPT_LIBCXX_GNU_BEFORE(11) || MPT_LIBCXX_LLVM_BEFORE(14000) || defined(MPT_COMPILER_QUIRK_BROKEN_BITCAST)
#include <cstring>
#endif // !C++20
@ -36,7 +39,19 @@ inline namespace MPT_INLINE_NS {
#if MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_GNU_BEFORE(11) && !MPT_LIBCXX_LLVM_BEFORE(14000)
#if defined(MPT_COMPILER_QUIRK_BROKEN_BITCAST)
// VS2022 17.6.0 ARM64 gets confused about alignment in std::bit_cast (or equivalent code),
// causing an ICE with LTCG turned on.
// We try to work-around this problem by placing signal fences as an optimization barrier around the (presumably) confused operation.
template <typename Tdst, typename Tsrc>
MPT_FORCEINLINE typename std::enable_if<(sizeof(Tdst) == sizeof(Tsrc)) && std::is_trivially_copyable<Tsrc>::value && std::is_trivially_copyable<Tdst>::value, Tdst>::type bit_cast(const Tsrc & src) noexcept {
Tdst dst{};
std::atomic_signal_fence(std::memory_order_seq_cst);
std::memcpy(&dst, &src, sizeof(Tdst));
std::atomic_signal_fence(std::memory_order_seq_cst);
return dst;
}
#elif MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_GNU_BEFORE(11) && !MPT_LIBCXX_LLVM_BEFORE(14000)
using std::bit_cast;
#else // !C++20
// C++2a compatible bit_cast.

View file

@ -50,7 +50,9 @@
#elif defined(_MSC_VER)
#define MPT_COMPILER_MSVC 1
#if (_MSC_VER >= 1935)
#if (_MSC_VER >= 1936)
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 6)
#elif (_MSC_VER >= 1935)
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 5)
#elif (_MSC_VER >= 1934)
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 4)

View file

@ -5,6 +5,7 @@
#include "mpt/base/detect_arch.hpp"
#include "mpt/base/detect_compiler.hpp"
#include "mpt/base/detect_libc.hpp"
#include "mpt/base/detect_libcxx.hpp"
@ -36,6 +37,15 @@
#if MPT_COMPILER_MSVC && MPT_MSVC_AT_LEAST(2022, 6) && MPT_ARCH_AARCH64
// VS2022 17.6.0 ARM64 gets confused about alignment in std::bit_cast (or equivalent code),
// causing an ICE.
// See <https://developercommunity.visualstudio.com/t/ICE-when-compiling-for-ARM64-due-to-alig/10367205>.
#define MPT_COMPILER_QUIRK_BROKEN_BITCAST
#endif
#if MPT_CXX_BEFORE(20) && MPT_COMPILER_MSVC
// Compiler has multiplication/division semantics when shifting signed integers.
// In C++20, this behaviour is required by the standard.
@ -249,7 +259,7 @@
#elif MPT_LIBCXX_GNU
#define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE_PARSE
#endif
#if MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2022, 6) || !MPT_COMPILER_MSVC)
#if MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2022, 7) || !MPT_COMPILER_MSVC)
// Causes massive memory leaks.
// See
// <https://developercommunity.visualstudio.com/t/stdchronoget-tzdb-list-memory-leak/1644641>
@ -258,6 +268,11 @@
#endif
#endif
#if MPT_MSVC_AT_LEAST(2022, 6) && MPT_MSVC_BEFORE(2022, 7)
// std::chrono triggers ICE in VS2022 17.6.0, see <https://developercommunity.visualstudio.com/t/INTERNAL-COMPILER-ERROR-when-compiling-s/10366948>.
#define MPT_LIBCXX_QUIRK_CHRONO_DATE_BROKEN_ZONED_TIME
#endif
#if MPT_LIBCXX_GNU_BEFORE(8)

View file

@ -7,6 +7,7 @@
#include "mpt/base/namespace.hpp"
#include <algorithm>
#include <limits>

View file

@ -17,6 +17,8 @@
#include <ostream>
#include <type_traits>
#include <cstddef>
namespace mpt {
@ -123,8 +125,19 @@ public:
}
inline mpt::byte_span ReadRawImpl(mpt::byte_span data) {
f.read(mpt::byte_cast<char *>(data.data()), data.size());
return data.first(mpt::saturate_cast<std::size_t>(f.gcount()));
std::size_t bytesToRead = data.size();
std::size_t bytesRead = 0;
while (bytesToRead > 0) {
std::streamsize bytesChunkToRead = mpt::saturate_cast<std::streamsize>(bytesToRead);
f.read(mpt::byte_cast<char *>(data.data()) + bytesRead, bytesChunkToRead);
std::streamsize bytesChunkRead = f.gcount();
bytesRead += static_cast<std::size_t>(bytesChunkRead);
bytesToRead -= static_cast<std::size_t>(bytesChunkRead);
if (bytesChunkRead != bytesChunkToRead) {
break;
}
}
return data.first(bytesRead);
}
inline bool IsEof() {
@ -210,7 +223,17 @@ public:
}
inline bool WriteRawImpl(mpt::const_byte_span data) {
f.write(mpt::byte_cast<const char *>(data.data()), data.size());
std::size_t bytesToWrite = data.size();
std::size_t bytesWritten = 0;
while (bytesToWrite > 0) {
std::streamsize bytesChunk = mpt::saturate_cast<std::streamsize>(bytesToWrite);
f.write(mpt::byte_cast<const char *>(data.data()) + bytesWritten, bytesChunk);
if (f.fail()) {
break;
}
bytesWritten += static_cast<std::size_t>(bytesChunk);
bytesToWrite -= static_cast<std::size_t>(bytesChunk);
}
return !f.fail();
}

View file

@ -70,8 +70,19 @@ private:
// inefficient istream implementations might invalidate their buffer when seeking, even when seeking to the current position
stream.seekg(static_cast<std::streamoff>(pos), std::ios::beg);
}
stream.read(mpt::byte_cast<char *>(dst.data()), dst.size());
return dst.first(static_cast<std::size_t>(stream.gcount()));
std::size_t bytesToRead = dst.size();
std::size_t bytesRead = 0;
while (bytesToRead > 0) {
std::streamsize bytesChunkToRead = mpt::saturate_cast<std::streamsize>(bytesToRead);
stream.read(mpt::byte_cast<char *>(dst.data()) + bytesRead, bytesChunkToRead);
std::streamsize bytesChunkRead = stream.gcount();
bytesRead += static_cast<std::size_t>(bytesChunkRead);
bytesToRead -= static_cast<std::size_t>(bytesChunkRead);
if (bytesChunkRead != bytesChunkToRead) {
break;
}
}
return dst.first(bytesRead);
}
};
@ -98,8 +109,19 @@ private:
}
mpt::byte_span InternalReadUnseekable(mpt::byte_span dst) const override {
stream.read(mpt::byte_cast<char *>(dst.data()), dst.size());
return dst.first(static_cast<std::size_t>(stream.gcount()));
std::size_t bytesToRead = dst.size();
std::size_t bytesRead = 0;
while (bytesToRead > 0) {
std::streamsize bytesChunkToRead = mpt::saturate_cast<std::streamsize>(bytesToRead);
stream.read(mpt::byte_cast<char *>(dst.data()) + bytesRead, bytesChunkToRead);
std::streamsize bytesChunkRead = stream.gcount();
bytesRead += static_cast<std::size_t>(bytesChunkRead);
bytesToRead -= static_cast<std::size_t>(bytesChunkRead);
if (bytesChunkRead != bytesChunkToRead) {
break;
}
}
return dst.first(bytesRead);
}
};