View Issue Details

IDProjectCategoryView StatusLast Update
0001145OpenMPTFile Format Supportpublic2018-09-22 06:36
ReporterSlender Assigned Tomanx  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product VersionOpenMPT 1.28.00.* (old testing) 
Target VersionOpenMPT 1.28.01.00 / libopenmpt 0.4.0 (upgrade first)Fixed in VersionOpenMPT 1.28.00.* (old testing) 
Summary0001145: MO3 no longer being treated as a container format
Description

It seems that when playing MO3 files, libopenmpt doesn't appear to be treating them as a container format anymore, resulting in the file format being listed as MO3 rather than the actual format the MO3 contains.

TagsNo tags attached.
Attached Files
Has the bug occurred in previous versions?
Tested code revision (in case you know it)r10826

Activities

manx

manx

2018-09-20 05:43

administrator   ~0003641

Why is that an issue in the first place?

MO3 had been treated (before libopenmpt 0.3) as a container format because we had been using the unmo3 library in earlier versions, which gives the impression of MO3 being a container format. However, it really actually isn't. It modifies all module file data and encodes in in its very own way. The process of unpacking a MO3 file is less like the process of unpacking a ZIP file (or any other container) and more like converting some module format back into some original module format from which it had been converted to MO3.

Regarding recent changes, in r10756 this actual reported module type (as opposed to container format) changed from mod/xm/s3m/it to mo3, which I think agree is wrong.

manx

manx

2018-09-20 06:04

administrator   ~0003642

Fixed in r10827.

Saga Musix

Saga Musix

2018-09-20 07:08

administrator   ~0003643

While I agree with the gist of the patch, setting the format type is semantically wrong. This is what should unambiguously tell the user (or program) what actual binary format the file is in, and that is without question "mo3" in this case. The same is done with other "super formats" like GDM. To keep things consistent with GDM, I would propose to change the format name to "MO3 v5 (converted from XM)".

manx

manx

2018-09-20 07:36

administrator   ~0003644

Well, the actual format on disk is (if set) always the container format.
Setting "type" to "mo3" provides no information whatsoever about what playback characteristics to expect from the given file.

I agree that GDM and MO3 should be handled consistently, however not setting any accessible field to literally "it" (or other respective original formats) is IMHO wrong and hides valuable information that was previously accessible. It might actually make sense to add another field precisely for these container-like converted formats. Something along the lines of "original_type" and "original_type_long"/"original_type_name", which more clearly and way easier to parse (as would be required when encoding it in text form in some other field) represent what is actually going on. In this case we can set "type" to "mo3" and can (and probably should) even avoid setting "container" to anything at all, because it really is a converted format and not a container format, in the strict sense. In the code, these formats are also handled differently than actual container formats, thus the change would make the code itself also more consistent. The changes required would also be rather minimal, with the most difficult thing being choosing the name of the field(s) exposed by libopenmpt.

manx

manx

2018-09-20 09:36

administrator   ~0003645

Last edited: 2018-09-20 11:13

Using separate fields solves also other issues. In case of weird situations like GDM in UMX, we can now properly represent the situation without hiding either the container or the converted-to format. Also, it allows us getting rid of MOD_CONTAINERTYPE_MO3 and MOD_CONTAINERTYPE_GDM completely. It also makes the container situation more consistent for libopenmpt, which exposes containers in its probing interface, previously leaving inconsistent results when probing without containers but later getting a MO3 file which says it is a container.

FWIW, OpenMPT itself already overrides the formatName field and shows the MOD_TYPE field instead for the 4 big formats. I do not think we want to change that. However I'm not sure what to do with MTM for MO3 and all the other formats for GDM. Currently, it would hide he original format (i.e. no change by this patch (when ignoring the intermediate state from the previous commit)).

All in all, IMO this patch is better in every aspect than any and all of the earlier behaviours.

I'm not sure if we should also split madeWithTracker.

originaltype-v2.patch (16,161 bytes)   
Index: libopenmpt/bindings/freebasic/libopenmpt.bi
===================================================================
--- libopenmpt/bindings/freebasic/libopenmpt.bi	(revision 10827)
+++ libopenmpt/bindings/freebasic/libopenmpt.bi	(working copy)
@@ -1037,7 +1037,9 @@
   \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)
-           - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+           - 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 to 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 to 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
Index: libopenmpt/dox/changelog.md
===================================================================
--- libopenmpt/dox/changelog.md	(revision 10827)
+++ libopenmpt/dox/changelog.md	(working copy)
@@ -26,6 +26,9 @@
         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 field `"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
Index: libopenmpt/libopenmpt.h
===================================================================
--- libopenmpt/libopenmpt.h	(revision 10827)
+++ libopenmpt/libopenmpt.h	(working copy)
@@ -1120,7 +1120,9 @@
  * \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)
- *          - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+ *          - 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 to 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 to 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
Index: libopenmpt/libopenmpt.hpp
===================================================================
--- libopenmpt/libopenmpt.hpp	(revision 10827)
+++ libopenmpt/libopenmpt.hpp	(working copy)
@@ -724,7 +724,9 @@
 	  \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)
-	           - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+	           - 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 to 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 to 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
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10827)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -1100,6 +1100,8 @@
 	{
 		"type",
 		"type_long",
+		"originaltype",
+		"originaltype_long",
 		"container",
 		"container_long",
 		"tracker",
@@ -1116,6 +1118,10 @@
 		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.type );
 	} else if ( key == std::string("type_long") ) {
 		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.formatName );
+	} else if ( key == std::string("originaltype") ) {
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.originalType );
+	} else if ( key == std::string("originaltype_long") ) {
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.originalFormatName );
 	} else if ( key == std::string("container") ) {
 		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() ) );
 	} else if ( key == std::string("container_long") ) {
Index: libopenmpt/xmp-openmpt.cpp
===================================================================
--- libopenmpt/xmp-openmpt.cpp	(revision 10827)
+++ libopenmpt/xmp-openmpt.cpp	(working copy)
@@ -1029,6 +1029,9 @@
 		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";
 	}
Index: openmpt123/openmpt123.cpp
===================================================================
--- openmpt123/openmpt123.cpp	(revision 10827)
+++ openmpt123/openmpt123.cpp	(working copy)
@@ -1542,6 +1542,9 @@
 			set_field( fields, "Container" ).ostream() << mod.get_metadata( "container" ) << " (" << mod.get_metadata( "container_long" ) << ")";
 		}
 		set_field( fields, "Type" ).ostream() << mod.get_metadata( "type" ) << " (" << mod.get_metadata( "type_long" ) << ")";
+		if ( !mod.get_metadata( "originaltype" ).empty() ) {
+			set_field( fields, "Orig. Type" ).ostream() << mod.get_metadata( "originaltype" ) << " (" << mod.get_metadata( "originaltype_long" ) << ")";
+		}
 		if ( ( mod.get_num_subsongs() > 1 ) && ( flags.subsong != -1 ) ) {
 			set_field( fields, "Subsong" ).ostream() << flags.subsong;
 		}
Index: soundlib/Load_gdm.cpp
===================================================================
--- soundlib/Load_gdm.cpp	(revision 10827)
+++ soundlib/Load_gdm.cpp	(working copy)
@@ -94,10 +94,23 @@
 {
 	MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
 };
-static const char gdmFormatOriginStr[][4] =
+static const MPT_UCHAR_TYPE gdmFormatOriginType[][4] =
 {
-	"???", "MOD", "MTM", "S3M", "669", "FAR", "ULT", "STM", "MED", "PSM"
+	MPT_ULITERAL(""), MPT_ULITERAL("mod"), MPT_ULITERAL("mtm"), MPT_ULITERAL("s3m"), MPT_ULITERAL("669"), MPT_ULITERAL("far"), MPT_ULITERAL("ult"), MPT_ULITERAL("stm"), MPT_ULITERAL("med"), MPT_ULITERAL("psm")
 };
+static const MPT_UCHAR_TYPE * const gdmFormatOriginFormat[] =
+{
+	MPT_ULITERAL(""),
+	MPT_ULITERAL("Generic MOD"),
+	MPT_ULITERAL("MultiTracker"),
+	MPT_ULITERAL("ScreamTracker 3"),
+	MPT_ULITERAL("Composer 669 / UNIS 669"),
+	MPT_ULITERAL("Farandole Composer"),
+	MPT_ULITERAL("UltraTracker"),
+	MPT_ULITERAL("ScreamTracker 2"),
+	MPT_ULITERAL("OctaMED"),
+	MPT_ULITERAL("Epic Megagames MASI")
+};
 
 
 static bool ValidateHeader(const GDMFileHeader &fileHeader)
@@ -153,9 +166,10 @@
 
 	m_modFormat.formatName = MPT_USTRING("General Digital Music");
 	m_modFormat.type = MPT_USTRING("gdm");
-	m_modFormat.madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2 (converted from %3)"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer, mpt::ToUnicode(mpt::CharsetASCII, gdmFormatOriginStr[fileHeader.originalFormat]));
+	m_modFormat.madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer);
+	m_modFormat.originalType = gdmFormatOriginType[fileHeader.originalFormat];
+	m_modFormat.originalFormatName = gdmFormatOriginFormat[fileHeader.originalFormat];
 	m_modFormat.charset = mpt::CharsetCP437;
-	m_ContainerType = MOD_CONTAINERTYPE_GDM;
 
 	// Song name
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songTitle);
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 10827)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2332,7 +2332,7 @@
 }
 
 
-void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMptMade)
+void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMptMade, bool isMO3)
 {
 	if(!file.ReadMagic("STPM"))	// 'MPTS'
 	{
@@ -2370,7 +2370,7 @@
 			case MagicBE("RPB."): ReadField(chunk, size, m_nDefaultRowsPerBeat); break;
 			case MagicBE("RPM."): ReadField(chunk, size, m_nDefaultRowsPerMeasure); break;
 				// FIXME: If there are only PC events on the last few channels in an MPTM MO3, they won't be imported!
-			case MagicBE("C..."): if(GetType() != MOD_TYPE_XM && m_ContainerType != MOD_CONTAINERTYPE_MO3) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); m_nChannels = Clamp(chn, m_nChannels, MAX_BASECHANNELS); } break;
+			case MagicBE("C..."): if(GetType() != MOD_TYPE_XM && !isMO3) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); m_nChannels = Clamp(chn, m_nChannels, MAX_BASECHANNELS); } break;
 			case MagicBE("TM.."): ReadFieldCast(chunk, size, m_nTempoMode); break;
 			case MagicBE("PMM."): ReadFieldCast(chunk, size, m_nMixLevels); break;
 			case MagicBE("CWV."): { uint32 ver = 0; ReadField(chunk, size, ver); m_dwCreatedWithVersion = Version(ver); break; }
Index: soundlib/Load_mo3.cpp
===================================================================
--- soundlib/Load_mo3.cpp	(revision 10827)
+++ soundlib/Load_mo3.cpp	(working copy)
@@ -800,34 +800,33 @@
 	m_nDefaultSpeed = fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6;
 	m_nDefaultTempo.Set(fileHeader.defaultTempo ? fileHeader.defaultTempo : 125, 0);
 
-	m_ContainerType = MOD_CONTAINERTYPE_MO3;
-	mpt::ustring formatType;
-	mpt::ustring formatName;
+	mpt::ustring originalFormatType;
+	mpt::ustring originalFormatName;
 	if(fileHeader.flags & MO3FileHeader::isIT)
 	{
 		SetType(MOD_TYPE_IT);
-		formatType = MPT_USTRING("it");
-		formatName = MPT_USTRING("Impulse Tracker");
+		originalFormatType = MPT_USTRING("it");
+		originalFormatName = MPT_USTRING("Impulse Tracker");
 	} else if(fileHeader.flags & MO3FileHeader::isS3M)
 	{
 		SetType(MOD_TYPE_S3M);
-		formatType = MPT_USTRING("s3m");
-		formatName = MPT_USTRING("ScreamTracker 3");
+		originalFormatType = MPT_USTRING("s3m");
+		originalFormatName = MPT_USTRING("ScreamTracker 3");
 	} else if(fileHeader.flags & MO3FileHeader::isMOD)
 	{
 		SetType(MOD_TYPE_MOD);
-		formatType = MPT_USTRING("mod");
-		formatName = MPT_USTRING("Generic MOD");
+		originalFormatType = MPT_USTRING("mod");
+		originalFormatName = MPT_USTRING("Generic MOD");
 	} else if(fileHeader.flags & MO3FileHeader::isMTM)
 	{
 		SetType(MOD_TYPE_MTM);
-		formatType = MPT_USTRING("mtm");
-		formatName = MPT_USTRING("MultiTracker");
+		originalFormatType = MPT_USTRING("mtm");
+		originalFormatName = MPT_USTRING("MultiTracker");
 	} else
 	{
 		SetType(MOD_TYPE_XM);
-		formatType = MPT_USTRING("xm");
-		formatName = MPT_USTRING("FastTracker 2");
+		originalFormatType = MPT_USTRING("xm");
+		originalFormatName = MPT_USTRING("FastTracker 2");
 	}
 
 	if(fileHeader.flags & MO3FileHeader::linearSlides)
@@ -1844,7 +1843,7 @@
 			}
 
 			LoadExtendedInstrumentProperties(chunk);
-			LoadExtendedSongProperties(chunk);
+			LoadExtendedSongProperties(chunk, nullptr, true);
 			if(cwtv > 0x0889 && cwtv <= 0x8FF)
 			{
 				m_nType = MOD_TYPE_MPT;
@@ -1872,8 +1871,10 @@
 	else
 		madeWithTracker = mpt::format(MPT_USTRING("MO3 v%1 (%2)"))(version, madeWithTracker);
 
-	m_modFormat.formatName = mpt::format(MPT_USTRING("%1 (MO3 v%2 packed)"))(formatName, version);
-	m_modFormat.type = std::move(formatType);
+	m_modFormat.formatName = mpt::format(MPT_USTRING("Un4seen MO3 v%1"))(version);
+	m_modFormat.type = MPT_USTRING("mo3");
+	m_modFormat.originalType = std::move(originalFormatType);
+	m_modFormat.originalFormatName = std::move(originalFormatName);
 	m_modFormat.madeWithTracker = std::move(madeWithTracker);
 	if(m_dwLastSavedWithVersion)
 		m_modFormat.charset = mpt::CharsetWindows1252;
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10827)
+++ soundlib/Snd_defs.h	(working copy)
@@ -105,8 +105,6 @@
 enum MODCONTAINERTYPE
 {
 	MOD_CONTAINERTYPE_NONE = 0x0,
-	MOD_CONTAINERTYPE_MO3  = 0x1,
-	MOD_CONTAINERTYPE_GDM  = 0x2,
 	MOD_CONTAINERTYPE_UMX  = 0x3,
 	MOD_CONTAINERTYPE_XPK  = 0x4,
 	MOD_CONTAINERTYPE_PP20 = 0x5,
Index: soundlib/Sndfile.h
===================================================================
--- soundlib/Sndfile.h	(revision 10827)
+++ soundlib/Sndfile.h	(working copy)
@@ -247,9 +247,11 @@
 
 struct ModFormatDetails
 {
-	mpt::ustring formatName;      // "FastTracker 2"
-	mpt::ustring type;            // "xm"
-	mpt::ustring madeWithTracker; // "OpenMPT 1.28.01.00"
+	mpt::ustring formatName;         // "FastTracker 2"
+	mpt::ustring type;               // "xm"
+	mpt::ustring madeWithTracker;    // "OpenMPT 1.28.01.00"
+	mpt::ustring originalFormatName; // "FastTracker 2" in the case of converted formats like MO3 or GDM
+	mpt::ustring originalType;       // "xm" in the case of converted formats like MO3 or GDM
 	mpt::Charset charset = mpt::CharsetUTF8;
 };
 
@@ -811,7 +813,7 @@
 	void SaveExtendedInstrumentProperties(INSTRUMENTINDEX nInstruments, std::ostream &f) const;
 	void SaveExtendedSongProperties(std::ostream &f) const;
 #endif // MODPLUG_NO_FILESAVE
-	void LoadExtendedSongProperties(FileReader &file, bool* pInterpretMptMade = nullptr);
+	void LoadExtendedSongProperties(FileReader &file, bool* pInterpretMptMade = nullptr, bool isMNO3 = false);
 	void LoadMPTMProperties(FileReader &file, uint16 cwtv);
 
 	mpt::ustring GetSchismTrackerVersion(uint16 cwtv);
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10827)
+++ soundlib/Tables.cpp	(working copy)
@@ -116,9 +116,7 @@
 static constexpr ModContainerInfo modContainerInfo[] =
 {
 	// Container formats
-	{ MOD_CONTAINERTYPE_GDM,   MPT_ULITERAL("General Digital Music"),    "gdm"   },
 	{ MOD_CONTAINERTYPE_UMX,   MPT_ULITERAL("Unreal Music"),             "umx"   },
-	{ MOD_CONTAINERTYPE_MO3,   MPT_ULITERAL("Un4seen MO3"),              "mo3"   },
 	{ MOD_CONTAINERTYPE_XPK,   MPT_ULITERAL("XPK packed"),               "xpk"   },
 	{ MOD_CONTAINERTYPE_PP20,  MPT_ULITERAL("PowerPack PP20"),           "ppm"   },
 	{ MOD_CONTAINERTYPE_MMCMP, MPT_ULITERAL("Music Module Compressor"),  "mmcmp" }
originaltype-v2.patch (16,161 bytes)   
Saga Musix

Saga Musix

2018-09-20 21:01

administrator   ~0003646

Having a second field would definitely be the best solution and semantically more correct.

manx

manx

2018-09-21 08:31

administrator   ~0003647

Changes:

  • Fix typo.
  • Restore mo3 and gdm into supported extensions list.
  • Change libopenmpt version.

Commit message:

[Mod] Store separate originalType and originalFormatName fields which in the case of MO3 and GDM store the original converted-from module format. Fixes &lt;https://bugs.openmpt.org/view.php?id=1145>.
[Mod] MO3: Partially revert r10827 and set type to mo3 again.
[Ref] Remove MOD_CONTAINERTYPE_GDM and MOD_CONTAINERTYPE_MO3.
[New] libopenmpt: Expose &quot;originaltype&quot; and &quot;originaltype_long&quot; metadata fields.
[New] openmpt123: Show new fields.
[New] xmp-openmpt: Show new fields.
[Mod] libopenmpt: Bump prerel version.
originaltype-v4.patch (17,689 bytes)   
Index: libopenmpt/bindings/freebasic/libopenmpt.bi
===================================================================
--- libopenmpt/bindings/freebasic/libopenmpt.bi	(revision 10828)
+++ libopenmpt/bindings/freebasic/libopenmpt.bi	(working copy)
@@ -1037,7 +1037,9 @@
   \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)
-           - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+           - 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
Index: libopenmpt/dox/changelog.md
===================================================================
--- libopenmpt/dox/changelog.md	(revision 10828)
+++ libopenmpt/dox/changelog.md	(working copy)
@@ -26,6 +26,9 @@
         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
Index: libopenmpt/libopenmpt.h
===================================================================
--- libopenmpt/libopenmpt.h	(revision 10828)
+++ libopenmpt/libopenmpt.h	(working copy)
@@ -1120,7 +1120,9 @@
  * \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)
- *          - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+ *          - 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
Index: libopenmpt/libopenmpt.hpp
===================================================================
--- libopenmpt/libopenmpt.hpp	(revision 10828)
+++ libopenmpt/libopenmpt.hpp	(working copy)
@@ -724,7 +724,9 @@
 	  \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)
-	           - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+	           - 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
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10828)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -1100,6 +1100,8 @@
 	{
 		"type",
 		"type_long",
+		"originaltype",
+		"originaltype_long",
 		"container",
 		"container_long",
 		"tracker",
@@ -1116,6 +1118,10 @@
 		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.type );
 	} else if ( key == std::string("type_long") ) {
 		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.formatName );
+	} else if ( key == std::string("originaltype") ) {
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.originalType );
+	} else if ( key == std::string("originaltype_long") ) {
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.originalFormatName );
 	} else if ( key == std::string("container") ) {
 		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() ) );
 	} else if ( key == std::string("container_long") ) {
Index: libopenmpt/libopenmpt_version.h
===================================================================
--- libopenmpt/libopenmpt_version.h	(revision 10828)
+++ libopenmpt/libopenmpt_version.h	(working copy)
@@ -21,7 +21,7 @@
 /*! \brief libopenmpt patch version number */
 #define OPENMPT_API_VERSION_PATCH 0
 /*! \brief libopenmpt pre-release tag */
-#define OPENMPT_API_VERSION_PREREL "-pre.7"
+#define OPENMPT_API_VERSION_PREREL "-pre.8"
 /*! \brief libopenmpt pre-release flag */
 #define OPENMPT_API_VERSION_IS_PREREL 1
 
Index: libopenmpt/libopenmpt_version.mk
===================================================================
--- libopenmpt/libopenmpt_version.mk	(revision 10828)
+++ libopenmpt/libopenmpt_version.mk	(working copy)
@@ -1,7 +1,7 @@
 LIBOPENMPT_VERSION_MAJOR=0
 LIBOPENMPT_VERSION_MINOR=4
 LIBOPENMPT_VERSION_PATCH=0
-LIBOPENMPT_VERSION_PREREL=-pre.7
+LIBOPENMPT_VERSION_PREREL=-pre.8
 
 LIBOPENMPT_LTVER_CURRENT=1
 LIBOPENMPT_LTVER_REVISION=0
Index: libopenmpt/xmp-openmpt.cpp
===================================================================
--- libopenmpt/xmp-openmpt.cpp	(revision 10828)
+++ libopenmpt/xmp-openmpt.cpp	(working copy)
@@ -1029,6 +1029,9 @@
 		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";
 	}
Index: openmpt123/openmpt123.cpp
===================================================================
--- openmpt123/openmpt123.cpp	(revision 10828)
+++ openmpt123/openmpt123.cpp	(working copy)
@@ -1542,6 +1542,9 @@
 			set_field( fields, "Container" ).ostream() << mod.get_metadata( "container" ) << " (" << mod.get_metadata( "container_long" ) << ")";
 		}
 		set_field( fields, "Type" ).ostream() << mod.get_metadata( "type" ) << " (" << mod.get_metadata( "type_long" ) << ")";
+		if ( !mod.get_metadata( "originaltype" ).empty() ) {
+			set_field( fields, "Orig. Type" ).ostream() << mod.get_metadata( "originaltype" ) << " (" << mod.get_metadata( "originaltype_long" ) << ")";
+		}
 		if ( ( mod.get_num_subsongs() > 1 ) && ( flags.subsong != -1 ) ) {
 			set_field( fields, "Subsong" ).ostream() << flags.subsong;
 		}
Index: soundlib/Load_gdm.cpp
===================================================================
--- soundlib/Load_gdm.cpp	(revision 10828)
+++ soundlib/Load_gdm.cpp	(working copy)
@@ -94,10 +94,23 @@
 {
 	MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
 };
-static const char gdmFormatOriginStr[][4] =
+static const MPT_UCHAR_TYPE gdmFormatOriginType[][4] =
 {
-	"???", "MOD", "MTM", "S3M", "669", "FAR", "ULT", "STM", "MED", "PSM"
+	MPT_ULITERAL(""), MPT_ULITERAL("mod"), MPT_ULITERAL("mtm"), MPT_ULITERAL("s3m"), MPT_ULITERAL("669"), MPT_ULITERAL("far"), MPT_ULITERAL("ult"), MPT_ULITERAL("stm"), MPT_ULITERAL("med"), MPT_ULITERAL("psm")
 };
+static const MPT_UCHAR_TYPE * const gdmFormatOriginFormat[] =
+{
+	MPT_ULITERAL(""),
+	MPT_ULITERAL("Generic MOD"),
+	MPT_ULITERAL("MultiTracker"),
+	MPT_ULITERAL("ScreamTracker 3"),
+	MPT_ULITERAL("Composer 669 / UNIS 669"),
+	MPT_ULITERAL("Farandole Composer"),
+	MPT_ULITERAL("UltraTracker"),
+	MPT_ULITERAL("ScreamTracker 2"),
+	MPT_ULITERAL("OctaMED"),
+	MPT_ULITERAL("Epic Megagames MASI")
+};
 
 
 static bool ValidateHeader(const GDMFileHeader &fileHeader)
@@ -153,9 +166,10 @@
 
 	m_modFormat.formatName = MPT_USTRING("General Digital Music");
 	m_modFormat.type = MPT_USTRING("gdm");
-	m_modFormat.madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2 (converted from %3)"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer, mpt::ToUnicode(mpt::CharsetASCII, gdmFormatOriginStr[fileHeader.originalFormat]));
+	m_modFormat.madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer);
+	m_modFormat.originalType = gdmFormatOriginType[fileHeader.originalFormat];
+	m_modFormat.originalFormatName = gdmFormatOriginFormat[fileHeader.originalFormat];
 	m_modFormat.charset = mpt::CharsetCP437;
-	m_ContainerType = MOD_CONTAINERTYPE_GDM;
 
 	// Song name
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songTitle);
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp	(revision 10828)
+++ soundlib/Load_it.cpp	(working copy)
@@ -2332,7 +2332,7 @@
 }
 
 
-void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMptMade)
+void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool *pInterpretMptMade, bool isMO3)
 {
 	if(!file.ReadMagic("STPM"))	// 'MPTS'
 	{
@@ -2370,7 +2370,7 @@
 			case MagicBE("RPB."): ReadField(chunk, size, m_nDefaultRowsPerBeat); break;
 			case MagicBE("RPM."): ReadField(chunk, size, m_nDefaultRowsPerMeasure); break;
 				// FIXME: If there are only PC events on the last few channels in an MPTM MO3, they won't be imported!
-			case MagicBE("C..."): if(GetType() != MOD_TYPE_XM && m_ContainerType != MOD_CONTAINERTYPE_MO3) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); m_nChannels = Clamp(chn, m_nChannels, MAX_BASECHANNELS); } break;
+			case MagicBE("C..."): if(GetType() != MOD_TYPE_XM && !isMO3) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); m_nChannels = Clamp(chn, m_nChannels, MAX_BASECHANNELS); } break;
 			case MagicBE("TM.."): ReadFieldCast(chunk, size, m_nTempoMode); break;
 			case MagicBE("PMM."): ReadFieldCast(chunk, size, m_nMixLevels); break;
 			case MagicBE("CWV."): { uint32 ver = 0; ReadField(chunk, size, ver); m_dwCreatedWithVersion = Version(ver); break; }
Index: soundlib/Load_mo3.cpp
===================================================================
--- soundlib/Load_mo3.cpp	(revision 10828)
+++ soundlib/Load_mo3.cpp	(working copy)
@@ -800,34 +800,33 @@
 	m_nDefaultSpeed = fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6;
 	m_nDefaultTempo.Set(fileHeader.defaultTempo ? fileHeader.defaultTempo : 125, 0);
 
-	m_ContainerType = MOD_CONTAINERTYPE_MO3;
-	mpt::ustring formatType;
-	mpt::ustring formatName;
+	mpt::ustring originalFormatType;
+	mpt::ustring originalFormatName;
 	if(fileHeader.flags & MO3FileHeader::isIT)
 	{
 		SetType(MOD_TYPE_IT);
-		formatType = MPT_USTRING("it");
-		formatName = MPT_USTRING("Impulse Tracker");
+		originalFormatType = MPT_USTRING("it");
+		originalFormatName = MPT_USTRING("Impulse Tracker");
 	} else if(fileHeader.flags & MO3FileHeader::isS3M)
 	{
 		SetType(MOD_TYPE_S3M);
-		formatType = MPT_USTRING("s3m");
-		formatName = MPT_USTRING("ScreamTracker 3");
+		originalFormatType = MPT_USTRING("s3m");
+		originalFormatName = MPT_USTRING("ScreamTracker 3");
 	} else if(fileHeader.flags & MO3FileHeader::isMOD)
 	{
 		SetType(MOD_TYPE_MOD);
-		formatType = MPT_USTRING("mod");
-		formatName = MPT_USTRING("Generic MOD");
+		originalFormatType = MPT_USTRING("mod");
+		originalFormatName = MPT_USTRING("Generic MOD");
 	} else if(fileHeader.flags & MO3FileHeader::isMTM)
 	{
 		SetType(MOD_TYPE_MTM);
-		formatType = MPT_USTRING("mtm");
-		formatName = MPT_USTRING("MultiTracker");
+		originalFormatType = MPT_USTRING("mtm");
+		originalFormatName = MPT_USTRING("MultiTracker");
 	} else
 	{
 		SetType(MOD_TYPE_XM);
-		formatType = MPT_USTRING("xm");
-		formatName = MPT_USTRING("FastTracker 2");
+		originalFormatType = MPT_USTRING("xm");
+		originalFormatName = MPT_USTRING("FastTracker 2");
 	}
 
 	if(fileHeader.flags & MO3FileHeader::linearSlides)
@@ -1844,7 +1843,7 @@
 			}
 
 			LoadExtendedInstrumentProperties(chunk);
-			LoadExtendedSongProperties(chunk);
+			LoadExtendedSongProperties(chunk, nullptr, true);
 			if(cwtv > 0x0889 && cwtv <= 0x8FF)
 			{
 				m_nType = MOD_TYPE_MPT;
@@ -1872,8 +1871,10 @@
 	else
 		madeWithTracker = mpt::format(MPT_USTRING("MO3 v%1 (%2)"))(version, madeWithTracker);
 
-	m_modFormat.formatName = mpt::format(MPT_USTRING("%1 (MO3 v%2 packed)"))(formatName, version);
-	m_modFormat.type = std::move(formatType);
+	m_modFormat.formatName = mpt::format(MPT_USTRING("Un4seen MO3 v%1"))(version);
+	m_modFormat.type = MPT_USTRING("mo3");
+	m_modFormat.originalType = std::move(originalFormatType);
+	m_modFormat.originalFormatName = std::move(originalFormatName);
 	m_modFormat.madeWithTracker = std::move(madeWithTracker);
 	if(m_dwLastSavedWithVersion)
 		m_modFormat.charset = mpt::CharsetWindows1252;
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10828)
+++ soundlib/Snd_defs.h	(working copy)
@@ -105,8 +105,6 @@
 enum MODCONTAINERTYPE
 {
 	MOD_CONTAINERTYPE_NONE = 0x0,
-	MOD_CONTAINERTYPE_MO3  = 0x1,
-	MOD_CONTAINERTYPE_GDM  = 0x2,
 	MOD_CONTAINERTYPE_UMX  = 0x3,
 	MOD_CONTAINERTYPE_XPK  = 0x4,
 	MOD_CONTAINERTYPE_PP20 = 0x5,
Index: soundlib/Sndfile.h
===================================================================
--- soundlib/Sndfile.h	(revision 10828)
+++ soundlib/Sndfile.h	(working copy)
@@ -247,9 +247,11 @@
 
 struct ModFormatDetails
 {
-	mpt::ustring formatName;      // "FastTracker 2"
-	mpt::ustring type;            // "xm"
-	mpt::ustring madeWithTracker; // "OpenMPT 1.28.01.00"
+	mpt::ustring formatName;         // "FastTracker 2"
+	mpt::ustring type;               // "xm"
+	mpt::ustring madeWithTracker;    // "OpenMPT 1.28.01.00"
+	mpt::ustring originalFormatName; // "FastTracker 2" in the case of converted formats like MO3 or GDM
+	mpt::ustring originalType;       // "xm" in the case of converted formats like MO3 or GDM
 	mpt::Charset charset = mpt::CharsetUTF8;
 };
 
@@ -811,7 +813,7 @@
 	void SaveExtendedInstrumentProperties(INSTRUMENTINDEX nInstruments, std::ostream &f) const;
 	void SaveExtendedSongProperties(std::ostream &f) const;
 #endif // MODPLUG_NO_FILESAVE
-	void LoadExtendedSongProperties(FileReader &file, bool* pInterpretMptMade = nullptr);
+	void LoadExtendedSongProperties(FileReader &file, bool* pInterpretMptMade = nullptr, bool isMNO3 = false);
 	void LoadMPTMProperties(FileReader &file, uint16 cwtv);
 
 	mpt::ustring GetSchismTrackerVersion(uint16 cwtv);
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10828)
+++ soundlib/Tables.cpp	(working copy)
@@ -94,6 +94,9 @@
 	{ MOD_TYPE_STP,  MPT_ULITERAL("Soundtracker Pro II"),        "stp" },
 	{ MOD_TYPE_ULT,  MPT_ULITERAL("UltraTracker"),               "ult" },
 	{ MOD_TYPE_MOD,  MPT_ULITERAL("Grave Composer"),             "wow" },
+	// converted formats (no MODTYPE)
+	{ MOD_TYPE_NONE, MPT_ULITERAL("General Digital Music"),      "gdm" },
+	{ MOD_TYPE_NONE, MPT_ULITERAL("Un4seen MO3"),                "mo3" },
 #ifndef NO_ARCHIVE_SUPPORT
 	// Compressed modules
 	{ MOD_TYPE_MOD,  MPT_ULITERAL("Compressed ProTracker"),      "mdz" },
@@ -116,9 +119,7 @@
 static constexpr ModContainerInfo modContainerInfo[] =
 {
 	// Container formats
-	{ MOD_CONTAINERTYPE_GDM,   MPT_ULITERAL("General Digital Music"),    "gdm"   },
 	{ MOD_CONTAINERTYPE_UMX,   MPT_ULITERAL("Unreal Music"),             "umx"   },
-	{ MOD_CONTAINERTYPE_MO3,   MPT_ULITERAL("Un4seen MO3"),              "mo3"   },
 	{ MOD_CONTAINERTYPE_XPK,   MPT_ULITERAL("XPK packed"),               "xpk"   },
 	{ MOD_CONTAINERTYPE_PP20,  MPT_ULITERAL("PowerPack PP20"),           "ppm"   },
 	{ MOD_CONTAINERTYPE_MMCMP, MPT_ULITERAL("Music Module Compressor"),  "mmcmp" }
originaltype-v4.patch (17,689 bytes)   
Saga Musix

Saga Musix

2018-09-21 20:34

administrator   ~0003648

The proposed patch looks fine to me. I'm not 100% happy how strings are duplicated but since it's just for two super formats, we can probably live with that.
I would propose to rename the new "isMO3" parameter to "ignoreChannelCount", and set it to true for both XM and MO3 to keep the logic more simple and consistent. In fact, now that I reviewed all callers, this must also be set to true for the ITP format. The fact that it is currently not done for ITP is a bug that could lead to crashes for malformed files.

Saga Musix

Saga Musix

2018-09-21 20:37

administrator   ~0003649

Last edited: 2018-09-21 20:50

I will apply the proposed change ahead of this patch as it has to be backported to 0.2 and 0.3 OpenMPT 1.27.
Edit: Done in r10838, r10839 (1.27/0.3) and r10840 (1.26/0.2). The latter has been done because ITP is enabled in libopenmpt fuzzer builds.

manx

manx

2018-09-22 06:32

administrator   ~0003650

I'm not 100% happy how strings are duplicated but since it's just for two super formats, we can probably live with that.

We could lookup the original format name strings in the table again, but I'm not sure if that's actually better, given that it only affects the two converted formats MO3 and GDM.

I'll leave the patch as is. This can always be changed later on top.

originaltype-v5.patch (15,518 bytes)   
Index: libopenmpt/bindings/freebasic/libopenmpt.bi
===================================================================
--- libopenmpt/bindings/freebasic/libopenmpt.bi	(revision 10844)
+++ libopenmpt/bindings/freebasic/libopenmpt.bi	(working copy)
@@ -1037,7 +1037,9 @@
   \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)
-           - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+           - 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
Index: libopenmpt/dox/changelog.md
===================================================================
--- libopenmpt/dox/changelog.md	(revision 10844)
+++ libopenmpt/dox/changelog.md	(working copy)
@@ -26,6 +26,9 @@
         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
Index: libopenmpt/libopenmpt.h
===================================================================
--- libopenmpt/libopenmpt.h	(revision 10844)
+++ libopenmpt/libopenmpt.h	(working copy)
@@ -1120,7 +1120,9 @@
  * \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)
- *          - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+ *          - 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
Index: libopenmpt/libopenmpt.hpp
===================================================================
--- libopenmpt/libopenmpt.hpp	(revision 10844)
+++ libopenmpt/libopenmpt.hpp	(working copy)
@@ -724,7 +724,9 @@
 	  \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)
-	           - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
+	           - 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
Index: libopenmpt/libopenmpt_impl.cpp
===================================================================
--- libopenmpt/libopenmpt_impl.cpp	(revision 10844)
+++ libopenmpt/libopenmpt_impl.cpp	(working copy)
@@ -1100,6 +1100,8 @@
 	{
 		"type",
 		"type_long",
+		"originaltype",
+		"originaltype_long",
 		"container",
 		"container_long",
 		"tracker",
@@ -1116,6 +1118,10 @@
 		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.type );
 	} else if ( key == std::string("type_long") ) {
 		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.formatName );
+	} else if ( key == std::string("originaltype") ) {
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.originalType );
+	} else if ( key == std::string("originaltype_long") ) {
+		return mpt::ToCharset(mpt::CharsetUTF8, m_sndFile->m_modFormat.originalFormatName );
 	} else if ( key == std::string("container") ) {
 		return mpt::ToCharset(mpt::CharsetUTF8, CSoundFile::ModContainerTypeToString( m_sndFile->GetContainerType() ) );
 	} else if ( key == std::string("container_long") ) {
Index: libopenmpt/libopenmpt_version.h
===================================================================
--- libopenmpt/libopenmpt_version.h	(revision 10844)
+++ libopenmpt/libopenmpt_version.h	(working copy)
@@ -21,7 +21,7 @@
 /*! \brief libopenmpt patch version number */
 #define OPENMPT_API_VERSION_PATCH 0
 /*! \brief libopenmpt pre-release tag */
-#define OPENMPT_API_VERSION_PREREL "-pre.7"
+#define OPENMPT_API_VERSION_PREREL "-pre.8"
 /*! \brief libopenmpt pre-release flag */
 #define OPENMPT_API_VERSION_IS_PREREL 1
 
Index: libopenmpt/libopenmpt_version.mk
===================================================================
--- libopenmpt/libopenmpt_version.mk	(revision 10844)
+++ libopenmpt/libopenmpt_version.mk	(working copy)
@@ -1,7 +1,7 @@
 LIBOPENMPT_VERSION_MAJOR=0
 LIBOPENMPT_VERSION_MINOR=4
 LIBOPENMPT_VERSION_PATCH=0
-LIBOPENMPT_VERSION_PREREL=-pre.7
+LIBOPENMPT_VERSION_PREREL=-pre.8
 
 LIBOPENMPT_LTVER_CURRENT=1
 LIBOPENMPT_LTVER_REVISION=0
Index: libopenmpt/xmp-openmpt.cpp
===================================================================
--- libopenmpt/xmp-openmpt.cpp	(revision 10844)
+++ libopenmpt/xmp-openmpt.cpp	(working copy)
@@ -1029,6 +1029,9 @@
 		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";
 	}
Index: openmpt123/openmpt123.cpp
===================================================================
--- openmpt123/openmpt123.cpp	(revision 10844)
+++ openmpt123/openmpt123.cpp	(working copy)
@@ -1542,6 +1542,9 @@
 			set_field( fields, "Container" ).ostream() << mod.get_metadata( "container" ) << " (" << mod.get_metadata( "container_long" ) << ")";
 		}
 		set_field( fields, "Type" ).ostream() << mod.get_metadata( "type" ) << " (" << mod.get_metadata( "type_long" ) << ")";
+		if ( !mod.get_metadata( "originaltype" ).empty() ) {
+			set_field( fields, "Orig. Type" ).ostream() << mod.get_metadata( "originaltype" ) << " (" << mod.get_metadata( "originaltype_long" ) << ")";
+		}
 		if ( ( mod.get_num_subsongs() > 1 ) && ( flags.subsong != -1 ) ) {
 			set_field( fields, "Subsong" ).ostream() << flags.subsong;
 		}
Index: soundlib/Load_gdm.cpp
===================================================================
--- soundlib/Load_gdm.cpp	(revision 10844)
+++ soundlib/Load_gdm.cpp	(working copy)
@@ -94,10 +94,23 @@
 {
 	MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
 };
-static const char gdmFormatOriginStr[][4] =
+static const MPT_UCHAR_TYPE gdmFormatOriginType[][4] =
 {
-	"???", "MOD", "MTM", "S3M", "669", "FAR", "ULT", "STM", "MED", "PSM"
+	MPT_ULITERAL(""), MPT_ULITERAL("mod"), MPT_ULITERAL("mtm"), MPT_ULITERAL("s3m"), MPT_ULITERAL("669"), MPT_ULITERAL("far"), MPT_ULITERAL("ult"), MPT_ULITERAL("stm"), MPT_ULITERAL("med"), MPT_ULITERAL("psm")
 };
+static const MPT_UCHAR_TYPE * const gdmFormatOriginFormat[] =
+{
+	MPT_ULITERAL(""),
+	MPT_ULITERAL("Generic MOD"),
+	MPT_ULITERAL("MultiTracker"),
+	MPT_ULITERAL("ScreamTracker 3"),
+	MPT_ULITERAL("Composer 669 / UNIS 669"),
+	MPT_ULITERAL("Farandole Composer"),
+	MPT_ULITERAL("UltraTracker"),
+	MPT_ULITERAL("ScreamTracker 2"),
+	MPT_ULITERAL("OctaMED"),
+	MPT_ULITERAL("Epic Megagames MASI")
+};
 
 
 static bool ValidateHeader(const GDMFileHeader &fileHeader)
@@ -153,9 +166,10 @@
 
 	m_modFormat.formatName = MPT_USTRING("General Digital Music");
 	m_modFormat.type = MPT_USTRING("gdm");
-	m_modFormat.madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2 (converted from %3)"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer, mpt::ToUnicode(mpt::CharsetASCII, gdmFormatOriginStr[fileHeader.originalFormat]));
+	m_modFormat.madeWithTracker = mpt::format(MPT_USTRING("BWSB 2GDM %1.%2"))(fileHeader.trackerMajorVer, fileHeader.formatMinorVer);
+	m_modFormat.originalType = gdmFormatOriginType[fileHeader.originalFormat];
+	m_modFormat.originalFormatName = gdmFormatOriginFormat[fileHeader.originalFormat];
 	m_modFormat.charset = mpt::CharsetCP437;
-	m_ContainerType = MOD_CONTAINERTYPE_GDM;
 
 	// Song name
 	mpt::String::Read<mpt::String::maybeNullTerminated>(m_songName, fileHeader.songTitle);
Index: soundlib/Load_mo3.cpp
===================================================================
--- soundlib/Load_mo3.cpp	(revision 10844)
+++ soundlib/Load_mo3.cpp	(working copy)
@@ -800,34 +800,33 @@
 	m_nDefaultSpeed = fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6;
 	m_nDefaultTempo.Set(fileHeader.defaultTempo ? fileHeader.defaultTempo : 125, 0);
 
-	m_ContainerType = MOD_CONTAINERTYPE_MO3;
-	mpt::ustring formatType;
-	mpt::ustring formatName;
+	mpt::ustring originalFormatType;
+	mpt::ustring originalFormatName;
 	if(fileHeader.flags & MO3FileHeader::isIT)
 	{
 		SetType(MOD_TYPE_IT);
-		formatType = MPT_USTRING("it");
-		formatName = MPT_USTRING("Impulse Tracker");
+		originalFormatType = MPT_USTRING("it");
+		originalFormatName = MPT_USTRING("Impulse Tracker");
 	} else if(fileHeader.flags & MO3FileHeader::isS3M)
 	{
 		SetType(MOD_TYPE_S3M);
-		formatType = MPT_USTRING("s3m");
-		formatName = MPT_USTRING("ScreamTracker 3");
+		originalFormatType = MPT_USTRING("s3m");
+		originalFormatName = MPT_USTRING("ScreamTracker 3");
 	} else if(fileHeader.flags & MO3FileHeader::isMOD)
 	{
 		SetType(MOD_TYPE_MOD);
-		formatType = MPT_USTRING("mod");
-		formatName = MPT_USTRING("Generic MOD");
+		originalFormatType = MPT_USTRING("mod");
+		originalFormatName = MPT_USTRING("Generic MOD");
 	} else if(fileHeader.flags & MO3FileHeader::isMTM)
 	{
 		SetType(MOD_TYPE_MTM);
-		formatType = MPT_USTRING("mtm");
-		formatName = MPT_USTRING("MultiTracker");
+		originalFormatType = MPT_USTRING("mtm");
+		originalFormatName = MPT_USTRING("MultiTracker");
 	} else
 	{
 		SetType(MOD_TYPE_XM);
-		formatType = MPT_USTRING("xm");
-		formatName = MPT_USTRING("FastTracker 2");
+		originalFormatType = MPT_USTRING("xm");
+		originalFormatName = MPT_USTRING("FastTracker 2");
 	}
 
 	if(fileHeader.flags & MO3FileHeader::linearSlides)
@@ -1872,8 +1871,10 @@
 	else
 		madeWithTracker = mpt::format(MPT_USTRING("MO3 v%1 (%2)"))(version, madeWithTracker);
 
-	m_modFormat.formatName = mpt::format(MPT_USTRING("%1 (MO3 v%2 packed)"))(formatName, version);
-	m_modFormat.type = std::move(formatType);
+	m_modFormat.formatName = mpt::format(MPT_USTRING("Un4seen MO3 v%1"))(version);
+	m_modFormat.type = MPT_USTRING("mo3");
+	m_modFormat.originalType = std::move(originalFormatType);
+	m_modFormat.originalFormatName = std::move(originalFormatName);
 	m_modFormat.madeWithTracker = std::move(madeWithTracker);
 	if(m_dwLastSavedWithVersion)
 		m_modFormat.charset = mpt::CharsetWindows1252;
Index: soundlib/Snd_defs.h
===================================================================
--- soundlib/Snd_defs.h	(revision 10844)
+++ soundlib/Snd_defs.h	(working copy)
@@ -105,8 +105,6 @@
 enum MODCONTAINERTYPE
 {
 	MOD_CONTAINERTYPE_NONE = 0x0,
-	MOD_CONTAINERTYPE_MO3  = 0x1,
-	MOD_CONTAINERTYPE_GDM  = 0x2,
 	MOD_CONTAINERTYPE_UMX  = 0x3,
 	MOD_CONTAINERTYPE_XPK  = 0x4,
 	MOD_CONTAINERTYPE_PP20 = 0x5,
Index: soundlib/Sndfile.h
===================================================================
--- soundlib/Sndfile.h	(revision 10844)
+++ soundlib/Sndfile.h	(working copy)
@@ -247,9 +247,11 @@
 
 struct ModFormatDetails
 {
-	mpt::ustring formatName;      // "FastTracker 2"
-	mpt::ustring type;            // "xm"
-	mpt::ustring madeWithTracker; // "OpenMPT 1.28.01.00"
+	mpt::ustring formatName;         // "FastTracker 2"
+	mpt::ustring type;               // "xm"
+	mpt::ustring madeWithTracker;    // "OpenMPT 1.28.01.00"
+	mpt::ustring originalFormatName; // "FastTracker 2" in the case of converted formats like MO3 or GDM
+	mpt::ustring originalType;       // "xm" in the case of converted formats like MO3 or GDM
 	mpt::Charset charset = mpt::CharsetUTF8;
 };
 
Index: soundlib/Tables.cpp
===================================================================
--- soundlib/Tables.cpp	(revision 10844)
+++ soundlib/Tables.cpp	(working copy)
@@ -94,6 +94,9 @@
 	{ MOD_TYPE_STP,  MPT_ULITERAL("Soundtracker Pro II"),        "stp" },
 	{ MOD_TYPE_ULT,  MPT_ULITERAL("UltraTracker"),               "ult" },
 	{ MOD_TYPE_MOD,  MPT_ULITERAL("Grave Composer"),             "wow" },
+	// converted formats (no MODTYPE)
+	{ MOD_TYPE_NONE, MPT_ULITERAL("General Digital Music"),      "gdm" },
+	{ MOD_TYPE_NONE, MPT_ULITERAL("Un4seen MO3"),                "mo3" },
 #ifndef NO_ARCHIVE_SUPPORT
 	// Compressed modules
 	{ MOD_TYPE_MOD,  MPT_ULITERAL("Compressed ProTracker"),      "mdz" },
@@ -116,9 +119,7 @@
 static constexpr ModContainerInfo modContainerInfo[] =
 {
 	// Container formats
-	{ MOD_CONTAINERTYPE_GDM,   MPT_ULITERAL("General Digital Music"),    "gdm"   },
 	{ MOD_CONTAINERTYPE_UMX,   MPT_ULITERAL("Unreal Music"),             "umx"   },
-	{ MOD_CONTAINERTYPE_MO3,   MPT_ULITERAL("Un4seen MO3"),              "mo3"   },
 	{ MOD_CONTAINERTYPE_XPK,   MPT_ULITERAL("XPK packed"),               "xpk"   },
 	{ MOD_CONTAINERTYPE_PP20,  MPT_ULITERAL("PowerPack PP20"),           "ppm"   },
 	{ MOD_CONTAINERTYPE_MMCMP, MPT_ULITERAL("Music Module Compressor"),  "mmcmp" }
originaltype-v5.patch (15,518 bytes)   
manx

manx

2018-09-22 06:36

administrator   ~0003651

Applied as r10847.

Issue History

Date Modified Username Field Change
2018-09-20 04:08 Slender New Issue
2018-09-20 05:43 manx Note Added: 0003641
2018-09-20 06:04 manx Assigned To => manx
2018-09-20 06:04 manx Status new => resolved
2018-09-20 06:04 manx Resolution open => fixed
2018-09-20 06:04 manx Fixed in Version => OpenMPT 1.28.00.* (old testing)
2018-09-20 06:04 manx Note Added: 0003642
2018-09-20 06:05 manx Product Version => OpenMPT 1.28.00.* (old testing)
2018-09-20 07:08 Saga Musix Note Added: 0003643
2018-09-20 07:36 manx Note Added: 0003644
2018-09-20 07:36 manx Status resolved => acknowledged
2018-09-20 07:56 manx Resolution fixed => open
2018-09-20 08:02 manx Target Version => OpenMPT 1.28.01.00 / libopenmpt 0.4.0 (upgrade first)
2018-09-20 08:03 manx Fixed in Version OpenMPT 1.28.00.* (old testing) =>
2018-09-20 09:36 manx File Added: originaltype-v2.patch
2018-09-20 09:36 manx Note Added: 0003645
2018-09-20 11:13 manx Note Edited: 0003645
2018-09-20 21:01 Saga Musix Note Added: 0003646
2018-09-21 08:31 manx File Added: originaltype-v4.patch
2018-09-21 08:31 manx Note Added: 0003647
2018-09-21 20:34 Saga Musix Note Added: 0003648
2018-09-21 20:37 Saga Musix Note Added: 0003649
2018-09-21 20:42 Saga Musix Note Edited: 0003649
2018-09-21 20:43 Saga Musix Note Edited: 0003649
2018-09-21 20:43 Saga Musix Note Edited: 0003649
2018-09-21 20:50 Saga Musix Note Edited: 0003649
2018-09-22 06:32 manx File Added: originaltype-v5.patch
2018-09-22 06:32 manx Note Added: 0003650
2018-09-22 06:36 manx Status acknowledged => resolved
2018-09-22 06:36 manx Resolution open => fixed
2018-09-22 06:36 manx Fixed in Version => OpenMPT 1.28.00.* (old testing)
2018-09-22 06:36 manx Note Added: 0003651