sezero / mikmod

Mikmod Sound System (mirror of git repo at https://sf.net/projects/mikmod/)
http://mikmod.sourceforge.net/
71 stars 22 forks source link

Several OctaMED effects are missing or broken. #19

Closed AliceLR closed 3 years ago

AliceLR commented 3 years ago

Sorry, here's another issue to organize my research on OctaMED-related bugs.

Aside from the missing effects I noted here I've found issues with several other effects and another set of missing OctaMED effects (this time, they were allegedly introduced in OctaMED 3).

Links to relevant documents:

My progress on this issue: https://github.com/sezero/mikmod/compare/master...AliceLR:fix-med-effects. Feedback re: any of this, but particularly how I added the new effects with regards to the UNI format definitely welcome.


Play note twice, delay note, play note three times (FF1, FF2, FF3)

FF1 uses: 90 MMD0, 154 MMD1 FF2 uses: 49 MMD0, 38 MMD1 FF3 uses: 19 MMD0, 43 MMD1

Despite the strange documentation in the OctaMED 2 effects document (which is probably why these were implemented the way they were), it's clarified in later documents that FF1 is equivalent to 1F03, FF2 is equivalent to 1F30, and FF3 is equivalent to 1F02 (i.e. all three commands assume a secondary tempo of 6). I've verified the following for various versions of OctaMED:

Cmd. OctaMED <=4.00 OctaMED 5.00 thru OctaMED SS 2 Demo
FF1 Only retriggers once, even at speeds >6 (i.e. NOT equivalent to 1F03). Same.
FF2 Is exactly equivalent to 1F30. Same.
FF3 Retriggers the first time at tick 2, then retriggers every tick (bug). Is exactly equivalent to 1F02.

This is easier to demonstrate with tests than with any modules I found. Each plays at speeds 6, 9, or 12: 1) two snare hits with no commands; 2) two snare hits, the second with FF1, then two snare hits, the second with 1F03; 3) two snare hits, the second with FF2, then two snare hits, the second with 1F30; 4) two snare hits, the second with FF3, then two snare hits, the second with 1F02.

ffcmds6.med.zip ffcmds9.med.zip ffcmds12.med.zip


Set pitch (FFD)

Total MMD0/MMD1 uses: 47.

This is supposed to immediately set the pitch of the current playing note to the new note without retriggering it. This required a new UNI effect (though all it does is stops the new note from playing...).

Example files Usage (tested w/ OctaMED 4) MikMod (master) MikMod (patch)
Reverb/halcyon.mmd0 used frequently for trills. works, but obvious. improved.
Reverb/serendipity.mmd0 guitar hammer-on/pull-off effect. works, but obvious. improved.
Dave Sullivan/funky fifth.mmd1 occasionally in melody. mostly works.
Ullrich/graviton.mmd1 used in the droning sound. not noticeable.

Portamento/Vibrato continue + volslide, Tremolo (0x05, 0x06, 0x07)

0x05 uses: 11 MMD0, 58 MMD1 0x06 uses: 15 MMD0, 152 MMD1 0x07 uses: 1 MMD0, 22 MMD1

These are apparently OctaMED 3 commands but I don't have the OctaMED 3 documentation; they're missing from the OctaMED 2 document but they're present in the OctaMED 4 document. These are ProTracker-compatible effects and are trivially implemented. Commands 0x06 and 0x07 don't exist in previous OctaMED versions so they should be safe. Command 0x05 was legacy vibrato prior to OctaMED 3, and all 11 MMD0s that use that command seem to have intended to use that.

All MMD0 modules using 0x05: Module 0x05 used as:
HJE/first strike.mmd0 Legacy vibrato.
Keith Tinman/hook - ingame 3.mmd0 Legacy vibrato. (starts in order 2 and noticeable if you're listening for testing.)
Keith Tinman/hook - ingame 4.mmd0 Legacy vibrato.
Keith Tinman/hook - ingame 7.mmd0 Legacy vibrato.
Keith Tinman/hook - title.mmd0 Legacy vibrato.
Keith Tinman/push-over - castle greek.mmd0 Legacy vibrato. (more obvious usage of 0x05 vibrato.)
Keith Tinman/push-over - dungeon.mmd0 Legacy vibrato.
Keith Tinman/push-over - greek.mmd0 Legacy vibrato.
Keith Tinman/push-over - japanese.mmd0 Legacy vibrato.
Keith Tinman/push-over - space.mmd0 Legacy vibrato.
SideWinder/planetsound.mmd0 Legacy vibrato. This is also the MMD0 track that uses 0x07—it appears to be a mistake that was intended as 0x04.
All MMD0 modules using 0x06: Module 0x06 used as:
- unknown/hafen.mmd0 Vibrato+Volslide
- unknown/herberge.mmd0 Vibrato+Volslide
- unknown/markt.mmd0 Vibrato+Volslide
- unknown/my voice.mmd0 Appears a few times but doesn't do anything...
- unknown/rathaus.mmd0 Vibrato+Volslide
- unknown/ultima vi - 4.mmd0 Vibrato+Volslide
- unknown/ultima vi - 6.mmd0 Vibrato+Volslide
- unknown/ultima vi - 7.mmd0 Vibrato+Volslide
Atheist/breathless.mmd0 Vibrato+Volslide
Barry Leitch/universal monsters - forest.mmd0 Vibrato+Volslide
Basehead/high velocity.mmd0 Vibrato+Volslide
Deus Ex Machina/goldrunner remix '93.mmd0 Appears a few times but doesn't do anything...
Jester/1990 - wahlkampfrede.snd.mmd0 Vibrato+Volslide
Mark Salud/bustin' up.mmd0 Vibrato+Volslide
Mem'o Ree/coop-Jazzcon/vision.mmd0 Vibrato+Volslide (occurs almost immediately, so it's a good test.)

So I put a version check on effect 0x05 and just let the other two translate to their ProTracker equivalents unconditionally. The implementation for the legacy vibrato was also wrong (the entire byte is the depth and the rate is fixed). I'm not sure the exact conversion to regular vibrato but I went with Rate=0xB, Depth=MIN(((old depth + 3) >> 2), 0xF) and it sounds close enough.

Portamento+volslide 0x05 example: orders 4/5 of balance.med. Tremolo example: the bass in john paul ii.med uses it, but it's subtle. Other examples use too many features MikMod doesn't support yet.


Finetune (0x15)

Total MMD1 uses: 33.

I had to make my own test case to really test this since nothing that uses it is particularly obvious about it. It's exactly the same as ProTracker finetune.

finetune.med.zip


Other fixes

sezero commented 3 years ago

Feedback re: any of this, but particularly how I added the new effects with regards to the UNI format definitely welcome.

UNI handling seems to be a mess. Trip down the memory lane:

mikmod-3.0.4: Removes the UNI loader

mikmod-3.1  : UNI_ITEFFECTZ inserted before UNI_ITEFFECTS0,
              UNI_ULTEFFECT9 added.

libmikmod-3.1.5 : UNI_MEDSPEED, UNI_MEDEFFECTF[1|2|3] added.
                  UNI loader is added back.

libmikmod-3.1.10: UNI_OKTARP added.

(Looks like it was a good thing that I gathered historic versions..)

So I'm not sure yet as to how UNI format handling should be done with your changes, considering it had not been handled before.

AliceLR commented 3 years ago

Good to know. FWIW the reasons I went with my current implementation is: 1) It looks like MikMod doesn't have MikCvt anymore (I might have missed it) so I'm not sure what would be able to produce a modern UNI file with these effects. 2) Having a cutoff for the UNI effects and adding new effects after it means there's more flexibility in reordering that part of the effects list and they can still get added to UNI later. 3) I found a post from 2002 implying that UNI was already pretty much unsupported by then...


Vibrato (0x04, MMD0 0x05, 0x14)

I updated MED vibrato and added support for the PT-compatible vibrato command. Since MED vibrato is supposed to have twice the depth of PT vibrato and it seems that MED vibrato also has 2-4x the rate of PT vibrato, I went ahead and added another UNI effect to allow the increased range. The depth conversion from old 5xx vibrato to 4xx vibrato actually seems to be around 8:1 but the 4:1 worked out because 4xx depth needed to be doubled. This is another one where the usage in actual files isn't that convincing so I made some test files.

vibrato5xx.med.zip (OctaMED 2.x test file with several patterns of roughly equivalent 5xx and 4xx) vibrato14xx.med.zip (OctaMED 4.x+ test file with several patterns of roughly equivalent 4xx and 14xx)

AliceLR commented 3 years ago

Just an update on this one since I've implemented a few more commands, particularly the ones that were causing the worst playback bugs (changing speed or getting stuck in loops).


Sample offset (0x19)

This one should be directly compatible with the .MOD offset effect.

Total MMD1s: 475.

Example files Usage (tested w/ OctaMED 4) MikMod (master) MikMod (patch)
Chris the Highlander/thend.mmd1 Timing misc. samples--obvious in drum pickup. Drums sound wrong; speed changes. works.
Essential Sound/another rave techno.mmd1 Timing misc. samples--obvious in bass. Bass sounds VERY wrong; speed changes. works.

Volume slide (0x0A and 0x0D)

I found a minor deviation from the way this is currently implemented in MikMod: in OctaMED, if both nibbles are set, a slide up is always performed. An example of this can be found in several orders near the end of alien breed ii.med, though MikMod can't play it due to broken commands 0x1A and 0x1B...


Fine volume slide (0x1A and 0x1B)

Total MMD1s: 224.

Implemented using the (now working) XM fine volslide effects. The first test fine volslides down 64 times then up 64 times, which I used to verify that these implementations work the same between MikMod and OctaMED. The second test uses a param of 0, which does nothing in OctaMED (and needs to be filtered out so it doesn't continue like the XM effects). Prior to patching these would immediately jump to order 1 and then interpret the 1A01s as regular volslides.

finevol.med.zip finevol0.med.zip

Example files Usage (tested w/ OctaMED 4) MikMod (master) MikMod (patch)
- unknown/alien breed ii.mmd1 Used at the start, other places. Gets stuck in order 1 Plays correctly now :D
Blair Zuppicich/roadkill - end.mmd1 Used near the start. Gets stuck in order 2 Doesn't get stuck anymore.

Note delay and retrigger (0x1F), FF1, FF2, FF3 revisited.

Total MMD1s that use 1Fx0 (x!=0): 84. Total MMD1s that use 1F0x (x!=0): 159. Total MMD1s that use 1Fxy (x,y!=0): 7.

This is only allowed on a line with a note and is ignored on lines without notes so fortunately there are fewer edge cases to worry about. This does need to work correctly with both params though. This fix allows the FF1/FF2/FF3 test files in the first post to actually play back correctly. Test file for various usage of this command:

1f.med.zip

Example files with obvious or frequent usage Used in
- unknown/funkee gitar.mmd1 Hi-hat, snare
Brooker/brooker3.mmd1 Various drums

I also gave FF1/FF2/FF3 another look because of #21 and I'm glad I did, because there are a couple of edge case quirks with FF1 and FF3. In OctaMED 4 and 5, these will retrigger on lines without notes (but not on tick 0), but from OctaMED 6.00d up they are ignored on lines without notes. By "lines without notes" I also mean lines with an instrument plus OctaMED's weird hold symbol. There are 5 MMD0s and 12 MMD1s that use these on a line with no notes. Since support for MMD2/MMD3s isn't a concern yet I just left a comment re: this and tweaked the FF3 implementation to not use E9x (so now .MED doesn't rely on E9x at all).

Two more test files for this specific edge case:

ffcmdsb6.med.zip ffcmdsb9.med.zip

Module Relies on these?
- unknown/argonaut.mmd0 Yes (seq. 9/block 5)
Dan Pyrik/trapped under ice.mmd0 Yes (seq. 33/block 27)
Daniel H. Dean/bloated skunk.mmd0 Yes (seq. 19/block 13)
Daniel H. Dean/eye socket wrench.mmd0 Probably (seq. 16/block 8)
Mark Salud/if in venus.mmd0 Yes (seq. 11/block 8)
Bobby Clark/asteroid trip 808.mmd1 Relies on rapidly strobing row highlighting :/
Bobby Clark/b.c.mmd1 No (seq. 12/block 11)
JaDe/deadline.mmd1 Yes (seq. 6/block 3)
Redd Kaa/astonishing.mmd1 Yes (seq. 28/block 0)
Redd Kaa/stormcaster.mmd1 Yes (seq. 23/block 12)
Redd Kaa/the big sellout.mmd1 Yes (seq. 56/block 29)
Sheffra/a different way.mmd1 No (seq. 30/block 28)
Sheffra/ad infinitum.mmd1 Yes(?) (seq. 64/block 47)
Sheffra/coop-Redd Kaa/synergy.mmd1 Probably (seq. 76/block 65)
Spoochy/denoman.mmd1 Probably (seq. 22/block 17)
The Raven/stage 2 act 2.mmd1 Yes (seq. 44/block 33)
Ullrich/snap d groove babe (from arne 2 wiebke).mmd1 No (seq. 18/block 5)
AliceLR commented 3 years ago

😱😱😱😱😱 http://www.hipooniosamigasite.org/amigadocs/files/LSD-DOCS-DISKS/LSD58/Octamedv5.Doc-Pt2

Note:  more  experimentative  users  may  discover that octaves 8 and 9 of a
normal  sample also appear to play two lower octaves.  These octaves should,
however, *NEVER* be used in songs (apart from with MIDI): believe it or not,
it  is  in  fact  a complete coincidence that they work!  ExtSamples are the
only "legal" way of using the two lower octaves.  In any case, octaves 8 and
9 are also one finetune step sharp :-)

childplay.med u got 2.med the chase.med

MikMod and libxmp play these notes at very high octaves. OpenMPT strips these notes out entirely. edit: 30 affected MMD1s and no affected MMD0s, though some of those might be MIDI (like "sweat" from the MMD1 unknown author dir).

This ridiculous format is never going to let me finish...

edit 2: Took a look at OpenMPT and it looks like it handles these in the instrument mapping due to it only affecting some cases (they only get stripped out in the tracker due to their octave being too high). Since it only affects some instruments and theoretically someday MikMod might have synth instruments, the fix for this probably needs to be implemented alongside the instrument transpose and IFF instrument fixes rather than by changing the notes.

AliceLR commented 3 years ago

Fine portamento (0x11 and 0x12)

Total MMD1s: 121.

Due to the expanded range these needed to be implemented with the XM implementations of the E1x and E2x effects (which already have the expanded range).

Test file: first pattern does fine portamento up from C-2 to approximately C#2, then the second pattern does fine portamento down from C#2 to approximately C-2. Prior to the fix they slide quite a bit further.

fineporta.med.zip

Example files Usage (tested w/ OctaMED 4) MikMod (previous patch)
- unknown/when she talks.mmd1 Guitar bends. Exaggerated bends...
Andy Soar/blood net - turn.mmd1 Slight detune for a "chorus" effect. Detunes too much.

Loop (0x16)

Total MMD1s: 156. Total MMD1s that use a param >0F: 5.

This is similar to PT looping but with an extended range. I did some testing to loop for any quirks that might be relevant.

Quirks:

Due to the way MikMod's loops currently work copying the behavior where the loop point carries between patterns would probably require a new variable in MODULE and some care to make sure infinite loops aren't possible. For now I just made it use the same loop implementation as E6x because it's not clear if anything even relies on that weird quirk. Adding a new variable would also help get rid of a hack to make the loop point global (instead of per-track).

Example files OctaMED 4 MikMod (previous patch) MikMod (loop fix)
Appi-Ukko/happovaiva.mmd1 1:27 1:02 1:13 (difference due to 0x1E)
Apollon/pilot i tyskland.mmd1 (>0F) ~65 minutes 1:43 Why can this command loop 256 times? :/
Brooker/(brooker) # 01.mmd1 3:06 3:00 3:06
Chris the Highlander/afraid.mmd1 1:50 1:27 1:50
Essential Sound/unnamed.mmd1 (>0F) 1:42 0:10 1:42
Muskote/accapela.mmd1 1:05 0:42 1:05
Muskote/afrika.mmd1 2:00 0:34 2:00
Phia/terrene.mmd1 3:39 3:19 3:39

Cut note (0x18)

Total MMD1s: 48. Total MMD1s that use a param >0F: 0.

Should be pretty much the same as .MOD cut note ECx but with a larger range. Like .MOD note cut, values >= speed do nothing and it's supposed to be implemented by just setting volume to 0.

18.med.zip

Example files Usage (tested w/ OctaMED 4)
- unknown/no second prize.mmd1 Used in various parts.
Blockhead/childplay.mmd1 Used briefly near the end.
Redd Kaa/coop-Necrofthonia/numb.mmd1 Used on pretty much every row in pattern 1.
Tripper/los weirdos.mmd1 Used frequently and overtly in the second half to truncate notes shortly after they begin.

Pattern break (0x1D)

Total MMD1s: 12.

Exactly the same as .MOD Dxx as far as I can tell. Not used by many tracks since OctaMED has F00 and variable-length patterns but when it is it's usually to control repeating.

Example files Usage (tested w/ OctaMED 4)
- unknown/fifteen k.mmd1 Uses 1D02 at the end to loop to an earlier block without triggering the first notes of the target block.
- unknown/loop#.mmd1 (there are 5 of these) Uses 1D01 to indefinitely loop a single row.
Brooker/(brooker) # 11.mmd1 Uses 1D20 to indefinitely loop the last half block.
Don Howard/myth.mmd1 Uses 1D02 at the end to loop to the first block without triggering the first notes of the target block.

Pattern delay (0x1E)

Total MMD1s: 126. Total MMD1s that use a param >0F: 81.

The same as .MOD pattern delay, but with a larger range.

Example files OctaMED 4 MikMod (previous patch) MikMod (pattern delay fix)
- unknown/no second prize.mmd1 2:34 2:33 2:34
Appi-Ukko/happovaiva.mmd1 (0xFF!) 1:27 1:12 1:27
Blockhead/childplay.mmd1 1:48 1:46 1:48

Portamento (0x01 and 0x02)

In OctaMED, these commands do not have effect memory: 100 and 200 are completely ignored, just like 1100 and 1200. I just added checks to the MED loader to remove instances of 100 and 200, but these effects should not provide effect memory for ST/NT/PT .MODs either (FT and MPT not clear; a research project for some other time probably better suited to issue #21). Found in one of the test files below (monstrous.med). xmp has this bug too.

porta00.med.zip


Tracks that use several of these effects.

Example files Uses OctaMED 4 xmp MikMod (master) MikMod (patch)
- unknown/alcoholic score.mmd1 14 18 19 1B 1F0x 4:49 4:49'8 Gets stuck in a loop at order 1. 4:49, sounds correct.
- unknown/amiga skank.mmd1 07 19 1E>0F 3:10 3:08'7 Speed drops to 22 at order 9. 3:10, sounds correct.
- unknown/monstrous.mmd1 11 14 16 18 19 1B 1F0x 6:49 6:49'8 Tempo drops to 3 at order 5. 6:49, portamento bug at order 44/45 (fixed).
- unknown/overkill.mmd1 11 19 1B 1Fx0 1F0x 1:27 1:27'1 Speed drops to 16 at order 3. 1:27, sounds correct.
Ache/coop-NRG/one step, a head.mmd1 11 14 16 19 1E 1Fx0 3:39 3:30'7[1] Speed drops to 16 at order 14. 3:31[1], sounds correct.
Clawz/canal green.mmd1 11 14 16 18 19 1B 1E 4:20 4:13'4[2] Speed drops to 18 at order 3. 4:20, sounds correct.
Eivind Segrov/nighttrain.mmd1 05 06 07 11 14 18 19 1D 1Fx0 4:47 4:47'3 5:14[3], minor bugs. 5:14[3], sounds correct.

[1]: This track uses 900 at the very end, which sets the speed to 32 in most Amiga OctaMED versions (where the 9xx command behaves as speed=param & 0x1F, 0->32). Soundstudio 2 and up ignores 900 and allows 9xx to set the speed higher than 32. Right now libxmp and OpenMPT ignore this and MikMod maps this to the initial speed (???), which is a behavior that survived my tempo/speed fix patch because I didn't question it as much as I should have. It might be worth allowing these unusual ranges for MMD0s, MMD1s, and MMD2s at the very least at some point, but for now I'm just making MikMod ignore it to be consistent with the handling of values >32. [2]: I think this difference might be due to a time tracking bug in libxmp... despite playing correctly(?) it counts ~19 seconds when it reaches the pattern delay at the end of the first two orders, vs. ~29 seconds in OctaMED and MikMod. [3]: MikMod plays a hidden sequence after a pattern jump; the main sequence ends at the correct time.

That should be all of the effects that need fixing/implementation right now unless I missed something else that's broken(!). Commands that can't be added right now or don't matter yet are 0x08 (set hold/decay, which isn't implemented), 0x0E (synth jump, but synths aren't implemented), and a handful of Soundstudio effects (only relevant to MMD3 mix mode).

edit: I forgot about FF8 and FF9, which turn the low-pass filter off and on (respectively). Not sure if they're even applicable but I'll check. There's also FFA and FFB, which send "hold pedal on" and "hold pedal off" for MIDI instruments, as well as some other MIDI alternate behaviors for other commands (MIDI isn't implemented either and I don't know if they even should be).