Author Topic: Preserving OPL instruments  (Read 9777 times)

saga

  • Posts: 2754
Preserving OPL instruments
« on: 23 Nov '19 - 14:49 »
While XMPlay/BASS don't support it, it would still be nice if the MO3 format could preserve OPL instruments in S3M and MPTM files. I think the only format change required would be to add a new sample format flag, and then store the instrument bytes as regular sample data. Also the encoder should obviously never try to use MP3 or Vorbis compression for such sample slots (although I assume that due to the low size of 12 bytes, it would always fall back to lossless sample data anway - this would mostly be a cosmetic change).

- For the S3M format, OPL instruments can be identified by sample type being set to 2, and the 12 instrument bytes are stored in the length, loop start and loop end fields of the sample header.
- For the MPTM format, OpenMPT already saves the instrument data as regular sample data and sets the sample length to 12, but sets the "cvt" value in the sample header to 0x40, which is a reserved value according to ITTECH.TXT. Note that the check for this flag should be an equal comparison (cvt == 0x40), not a bitwise AND, due to ModPlug's legacy ADPCM sample cvt type (0xFF). Any combination with other cvt flags is considered to be illegal.

As ScreamTracker can only handle either PCM or OPL instruments on a channel, the channel pan/type table would have to be adjusted in the UNMO3 tool as well: Channels carrying AdLib instruments should use channel types A1 through A9 (16...25) instead of L1....R8. Alternatively, the original channel configuration table of the S3M file could of course be preserved in a new chunk at the end of the music data. This would probably be less work to implement and it would in general allow for a more accurate restoration of the original S3M file, even if no OPL instruments are used.
« Last Edit: 23 Nov '19 - 15:40 by saga »

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #1 on: 22 May '20 - 16:37 »
I'm looking into this now. Better late than never :)

To avoid noises with existing MO3 players/decoders that aren't expecting OPL instruments, I'm thinking of putting the data in the sample headers, like S3M does. The length header would be set to 0, which means the sample doesn't get played normally (so no noises), and the OPL data would be put in the loop headers (normal+sustain). Does that sound OK, ie. OpenMPT isn't already using those headers with OPL instruments and the data is always 12 bytes?

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #2 on: 22 May '20 - 22:16 »
Currently the data is always 12 bytes so it would work, but there are plans to support OPL3 patches in addition to just OPL2 patches in the future at least for the MPTM format, which would require about double the space (registers of 4 operators rather than just two). Maybe to have the best of both worlds (freely definable length and no unknown sample decoding), a sample compression flag combination could be used that has not been used before? e.g. combining flags 0x1000 and 0x4000 could indicate OPL patches.

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #3 on: 25 May '20 - 16:02 »
The problem is the sample memory isn't 0-initialized in existing BASS/XMPlay/UNMO3, so using an unknown compression method would leave them playing random data/noise. I guess another way to do it would be to convert each byte of the data to 16-bit, so that it is at least very quiet when played. Not very elegant though. Any other ideas?

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #4 on: 25 May '20 - 16:15 »
How about this: The patch data is stored in the sample data, but it is prepended by a bunch (e.g. 4) of zero bytes and the sample loop is set to cover those zero bytes. A player that is not aware of OPL patches would just play the silenced bytes, and a player supporting OPL patches would load the patch data, ignoring the prepended zeros.

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #5 on: 25 May '20 - 17:38 »
Yes, that seems like a nicer idea. I'll look into it.

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #6 on: 29 May '20 - 16:38 »
I wasn't entirely happy with that idea either in the end, because it would be wasting CPU playing the silent loop, but I think I've got something that'll work. An OPL sample will have its length header set to 0 (so won't be played by existing software) and the compressed length header set the length of the OPL data, which is stored uncompressed (I guess it'll always be very small anyway?). The compression flags (bits 12-15) will be set to 1000, ie. flags&0xf000=0x8000. Here's an update for you to try:

   www.un4seen.com/stuff/mo3.exe
   www.un4seen.com/stuff/unmo3.exe

Will OPL3 data be distinguishable just by its length or will you need it to be indicated in some other way? If the latter, rather than adding another flag for that, I would prefer to add a byte to the start of the OPL data to identify the OPL version. Let me know if that's needed.

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #7 on: 29 May '20 - 18:45 »
Ah yes, in hindsight that's a very obvious solution. :) I like it. If/when OpenMPT adds support for OPL3 patches, they will definitely be identifiable by their length, and indeed they won't be much bigger than the current patches, so I don't think that the lack of compression will hurt. Since it's not PCM data, the existing delta prediction will probably not work very well for those patches, anyway. :)
I expect that the OPL3 data will be stored in a backwards-compatible way (i.e. the first bytes will still be a valid OPL 2 patch without the additional two operators), so I think that a version byte won't be necessary. If it proves to be necessary, I will have to somehow add it to the MPTM format as well, so it would probably just be part of the sample data itself.

I gave the new MO3 version a spin, and while S3Ms seem to work fine, something doesn't seem to be quite right yet for MPTM files and the patch bytes end up being garbled. Interestingly, unmo3.exe gives a different result from my adjusted MO3 decoder in OpenMPT, and both of them are incorrect. The problem can be reproduced using the example file provided above. Looking at the bytes at that location, it seems like some code from your previous idea of storing the patch data as 16-bit data might have been left in place, because every other byte appears to be 0.

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #8 on: 1 Jun '20 - 15:57 »
I gave the new MO3 version a spin, and while S3Ms seem to work fine, something doesn't seem to be quite right yet for MPTM files and the patch bytes end up being garbled.

Oops, here's an update that should fix that:

   www.un4seen.com/stuff/mo3.exe

Let me know if there is still any problem.

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #9 on: 1 Jun '20 - 18:49 »
Yup, it works fine now. Thanks a lot! I guess the only thing really missing now is the ST3 pan / channel type table; Using UNMO3 to convert an MO3 file back to S3M will prevent the AdLib instruments from being heard in ScreamTracker, because UNMO3 only writes channel types L1...L8 and R1...R8 to the channel type table.

I think the information from the channel type table could be stored in the second half of the channel pan table in the MO3 song header, since that table has 64 entries and S3M files can only have 32 channels. Alternatively (assuming that BASS/XMPlay don't apply it unconditionally), I suppose that the "channel volume" table in the MO3 song header could be re-used to store this information, as that table is only used in IT format.
If neither of this is possible, a new chunk could be added at the end of the music data.
« Last Edit: 1 Jun '20 - 20:13 by saga »

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #10 on: 2 Jun '20 - 16:36 »
I think the information from the channel type table could be stored in the second half of the channel pan table in the MO3 song header, since that table has 64 entries and S3M files can only have 32 channels.

That seems like a good idea. Here's an update for you to try:

   www.un4seen.com/stuff/mo3.exe
   www.un4seen.com/stuff/unmo3.exe

Btw, this UNMO3 update will also exclude the S3M pan table if only default panning is used. Let me know if you see any problem with that.

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #11 on: 2 Jun '20 - 18:51 »
This seems to be working fine now. :)
One last thought about the sample flags - You mentioned that the sample memory would remain uninitialized if the compression method is not recognized, but now that the sample length is set to 0, is this still case? If it isn't, I suppose a combination of the existing flags (e.g. 0x1000 | 0x4000) could be used instead. That way, the last remaining flag bit could be saved for some future expansion.

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #12 on: 2 Jun '20 - 19:15 »
Oh, and two more issues... :)

The original MPTM file in question: https://sagamusix.de/download/flourishing_magic/

I did two conversions, one with MP3 and one with Ogg Vorbis. There is one common issue: With this file, the contents of the "OMPT" chunk are not written back when using UNMO3, so there are no channel names and the file is recognized as an IT file rather than MPTM. This is not an issue with the MO3 file itself, since OpenMPT's MO3 decoder can read the information just fine.
Now, the second issue is arguably worse: When I load the Vorbis-compressed MO3 file into XMPlay, it crashes (it says the "Modules plugin" crashed, so I assume that is its internal decoder). OpenMPT itself also cannot decode the Vorbis samples at all. I used OggEnc v2.87 at quality 6 to create this file.

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #13 on: 3 Jun '20 - 17:29 »
One last thought about the sample flags - You mentioned that the sample memory would remain uninitialized if the compression method is not recognized, but now that the sample length is set to 0, is this still case? If it isn't, I suppose a combination of the existing flags (e.g. 0x1000 | 0x4000) could be used instead. That way, the last remaining flag bit could be saved for some future expansion.

Do you mean making the flag bit available for other compression options or for non-compression purposes? There are several other flag bits still unused, so probably no need to reclaim it for non-compression purposes. Regarding compression, the codec (MP3/OGG) is actually detected from the data by BASS/XMPlay/UNMO3 currently (for the last 10 years or so), so adding other codecs is unlikely to require extra flags. Note this does mean that 0x5000 would currently be treated as a header-sharing OGG sample because the OGG flag (0x2000) is ignored.

Oh, and two more issues... :)

The original MPTM file in question: https://sagamusix.de/download/flourishing_magic/

I did two conversions, one with MP3 and one with Ogg Vorbis. There is one common issue: With this file, the contents of the "OMPT" chunk are not written back when using UNMO3, so there are no channel names and the file is recognized as an IT file rather than MPTM. This is not an issue with the MO3 file itself, since OpenMPT's MO3 decoder can read the information just fine.
Now, the second issue is arguably worse: When I load the Vorbis-compressed MO3 file into XMPlay, it crashes (it says the "Modules plugin" crashed, so I assume that is its internal decoder). OpenMPT itself also cannot decode the Vorbis samples at all. I used OggEnc v2.87 at quality 6 to create this file.

Oops! These are both bugs that were introduced in the recent updates. Here's another update that should fix them:

   www.un4seen.com/stuff/mo3.exe
   www.un4seen.com/stuff/unmo3.exe

Btw, this MO3 update zeros the info (except text) of samples that are removed or have no data, for a little more size reduction. That shouldn't cause any problems, or could it?

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #14 on: 3 Jun '20 - 18:50 »
Quote
Do you mean making the flag bit available for other compression options or for non-compression purposes? There are several other flag bits still unused, so probably no need to reclaim it for non-compression purposes.
Ah, indeed, I overlooked that quite a few of the lower bits are currently unused. So my suggestion can be ignored.

Quote
Btw, this MO3 update zeros the info (except text) of samples that are removed or have no data, for a little more size reduction. That shouldn't cause any problems, or could it?
I think it might be dangerous but I cannot construct a valid example right now. I'm mostly thinking about executing a portamento or sample swap between two sample slots of which one has no sample data. Such empty sample slots seem to be optimized out currently. It's not a lot of data, so I would suggest to keep the default volume and middle-C frequency at their original values, to rule out any such quirks from being broken by this optimization. Any other data such as auto-vibrato, global volume or loop info should be safe to remove, though.

Oh, and one more slightly related issue: Could XMPlay's recently-introduced "Don't use built-in decoder on Adlib S3M files" setting be extended to MO3 / MPTM files? :)

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #15 on: 4 Jun '20 - 17:29 »
Quote
Btw, this MO3 update zeros the info (except text) of samples that are removed or have no data, for a little more size reduction. That shouldn't cause any problems, or could it?
I think it might be dangerous but I cannot construct a valid example right now. I'm mostly thinking about executing a portamento or sample swap between two sample slots of which one has no sample data. Such empty sample slots seem to be optimized out currently. It's not a lot of data, so I would suggest to keep the default volume and middle-C frequency at their original values, to rule out any such quirks from being broken by this optimization. Any other data such as auto-vibrato, global volume or loop info should be safe to remove, though.

OK, probably not worth the risk, so here's an update that puts all the info back:

   www.un4seen.com/stuff/mo3.exe

Oh, and one more slightly related issue: Could XMPlay's recently-introduced "Don't use built-in decoder on Adlib S3M files" setting be extended to MO3 / MPTM files? :)

Yep, here's an XMPlay update that detects OPL samples in MPTM and MO3 files. It also silences them, and silences unknown MO3 compression methods.

   www.un4seen.com/stuff/xmplay.exe

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: Preserving OPL instruments
« Reply #16 on: 4 Jun '20 - 18:13 »
OK, probably not worth the risk, so here's an update that puts all the info back:

Actually, here's another one that will only clear a sample's info if its data is being removed too (set to "remove"). It won't clear the info if the sample never had any data. That should be safe I think, as removing the data will affect playback anyway if the sample was used.

   www.un4seen.com/stuff/mo3.exe

saga

  • Posts: 2754
Re: Preserving OPL instruments
« Reply #17 on: 4 Jun '20 - 20:34 »
The new updates work fine. :) The format changes are now also documented, and the next OpenMPT / libopenmpt versions will support MO3 with OPL, too.