.IT format "Fine" Tone Portamento

Started by Danny-E 33, January 08, 2023, 21:13:44

Previous topic - Next topic

Danny-E 33

Hello.

I'm working on a program which creates .it modules in-memory for the sake of immediate playback.

Due to the requirements of the song data I'm working with, all songs must always be set to 1 tick per row.
Unfortunately, this makes Tone Portamento Gxx unusable, since it only applies to ticks 2+ of every row.

Exx and Fxx have a "fine" version, which *only* applies to the first tick of every row, which is exactly what I need except for Gxx.
Is this possible?

P.S.

I could consider using a speed setting of 2 ticks per row in order to "enable" Tone Portamento, and then double the openmpt::ext::interactive tempo_factor to compensate.

The problem with this is that it makes vibrato too uncooperative. The vibrato speed/rate is always too fast and not granular enough anymore.

Even if I switch from vibrato Hxy to Uxy to get "4 times the precision", that seems to only affect the depth, and not the speed.

Is there a way to get the "best of both worlds"? A "fine" Tone Portamento and a "fine" vibrato speed?

Thanks!

Saga Musix

Technically this isn't something the IT format supports - but as you are just generating files in memory, you could in theory take advantage of an old playback bug compatibility setting, because OpenMPT used to apply normal slides (including Gxx) on tick 1 if the speed was one tick per row. There are two ways to do this but both are not really optimal.

1) Generate an IT file that pretends it was made with OpenMPT 1.17 - 1.19, i.e. the cwtv value in the header should be set to 0x5119. I would not recommend this because it implies that any other playback bugs of those old versions are also emulated, which may result in less accurate pitch slides, among many other things.
2) Generate OpenMPT song extensions at the end of the file, in particular the ".FSM" chunk. In this chunk, bit 6 of the first byte (0x40) needs to be set to enable emulation of this particular playback quirk. The rest of the bits in this chunk should stay the same as with an IT file saved through the latest OpenMPT version (so it's best to just extract the value of this chunk from an existing file, toggle that one bit and then store the chunk contents somewhere in your code).

Both options aren't really optimal, so I would advise against using them if you can find another way. Generally using 2 ticks per row may be a better idea. Maybe you can resort to using pitch envelopes for vibrato if the settings don't need to be too flexible?
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

Danny-E 33

Oh, interesting! I will tinker with each of those and compare. Thanks for the suggestions!

Assuming I figure out a way to increase to 2 ticks per row and get vibrato to still sound good/the same, that will still require doubling the tempo_factor, which I've already had to double from 1.0 to 2.0, so this would mean doubling again from 2.0 to 4.0 (the max).

I would be a little nervous cause I would be out of wiggle-room and unable to increase the tempo factor again if any more similar issues come up in the future.

The original reason I had to double from 1.0 to 2.0 is because the allowed .it tempos of 32-255 just don't go high enough.

I have seen that there is a "hack" flag in OpenMPT for allowing tempos beyond that range -- and I assume I could figure out how to set that flag in memory myself -- but I'm unsure how to utilize tempos >255 given that I am still limited to the Txx command only accepting a 1-byte parameter.

Is there a "hack" to allow Txxxx or something similar?

(Is there another format other than .it that I should be considering that does all the same stuff plus more?)

Thanks!

Saga Musix

#3
You can write an initial tempo higher than 255 BPM again using the song extensions (using the "..TD" chunk). To do the same in patterns, you need to use the Parameter Extension command: https://wiki.openmpt.org/Manual:_Effect_Reference#Effect_Column_5
This is only documented for MPTM but you can just as well write it in IT files (as the same code is used for reading IT and MPTM files, and this feature was introduced long before MPTM existed). In IT pattern data, the corresponding byte to write for that effect would be 27.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

Danny-E 33

#4
Hmm, #xx sounds like exactly what I need but so far not having luck getting it to behave correctly.

The #xx example shows the extension values being spread out across multiple rows but I would need the new effective tempo to be applied immediately.

I have tried stacking multiple commands on the same channel in the same row, and also tried sharing between two channels:

pattern_data.push_back(CHANNEL + CH1); // 0x80 + 1
pattern_data.push_back(COMMAND);       // 8
pattern_data.push_back(TEMPO);         // 20
pattern_data.push_back(tempo % 256);   // tempo (lo)
pattern_data.push_back(CHANNEL + CH1); // 0x80 + 1 (I have also tried 0x80 + 2)
pattern_data.push_back(COMMAND);       // 8
pattern_data.push_back(EXTENSION);     // 27
pattern_data.push_back(tempo / 256);   // tempo (hi)

Obviously I can understand why an indefinite number of commands per channel per row is impractical for GUIs, but for streaming to libopenmpt is there any real issue chaining multiple commands together like this?

Also based on this sentence:
QuoteIf there is only one #xx command below the actual command (the limit for Bxx, Cxx, and Txx), xx is added to the parameter of the original command × 256.
I'm interpreting this to mean that I should put the lo byte of the tempo in the Txx command (ie, % 256) and the hi byte in the #xx command (ie, / 256), but my main confusion is; how to handle situations where the lo byte just happens to be <32? (I might have the endianness backwards, but still, then what if the hi byte happens to be <32?)
How do I prevent the Txx command from being interpreted as a T0x or a T1x command? This makes me think I am most likely really incorrectly interpreting the explanation of #xx.
(Is there a compatibility/options flag that I have to set before #xx becomes "recognized"?)

Also (sorry for all the questions), how does one determine that # is equal to 27?
A-Z are clearly 1-26 but I don't see any meaningful pattern with :, #, +, *.
(I may be interested in using +xx but I have no idea how to determine its ID other than trial and error, but I assume there's gotta be a better way.)

Danny-E 33

Quote from: Saga Musix on January 09, 2023, 09:49:14Maybe you can resort to using pitch envelopes for vibrato if the settings don't need to be too flexible?

Could you elaborate on this a bit? I don't see anything about specifying a pitch envelope in the effect reference wiki page (only mention of turning it on and off). If it makes a difference, I am using samples and not instruments.

Saga Musix

Quote from: Danny-E 33 on January 09, 2023, 22:53:49The #xx example shows the extension values being spread out across multiple rows but I would need the new effective tempo to be applied immediately.
The entire command is evaluated at once on the row which contains the Txx command, there is no delay.

Quote from: Danny-E 33 on January 09, 2023, 22:53:49I have tried stacking multiple commands on the same channel in the same row, and also tried sharing between two channels:
That won't work. While it may be possible to imagine IT pattern data as a stream that is executed one command after another, in practice this is not how it is stored in memory. What you see on the screen is exactly what is stored in memory, so two commands being placed in the same cell in-file will just overwrite each other.

QuoteObviously I can understand why an indefinite number of commands per channel per row is impractical for GUIs, but for streaming to libopenmpt is there any real issue chaining multiple commands together like this?
See above. The GUI is what mandates the internal data structures in this case, not the other way around.

Quote from: Danny-E 33 on January 09, 2023, 22:53:49I'm interpreting this to mean that I should put the lo byte of the tempo in the Txx command (ie, % 256) and the hi byte in the #xx command (ie, / 256)
I can try to reword the sentence but it literally means the opposite; the #xx command is added, the original tempo command is multiplied by 256...

Quote from: Danny-E 33 on January 09, 2023, 22:53:49but my main confusion is; how to handle situations where the lo byte just happens to be <32? (I might have the endianness backwards, but still, then what if the hi byte happens to be <32?)
...hence this is not possible. But anyway, all commands that can be extended with #xx are evaluated after the individual commands have been added up, so if there is a distinction between values (e.g. 0 = continue, < 32 = tempo slide, etc.) then this distinction is made on the computed value after summing up, not before.

Quote from: Danny-E 33 on January 09, 2023, 22:53:49(Is there a compatibility/options flag that I have to set before #xx becomes "recognized"?)
The command is always available.

Quote from: Danny-E 33 on January 09, 2023, 22:53:49Also (sorry for all the questions), how does one determine that # is equal to 27?
Only by reading the OpenMPT code, specially Load_s3m.cpp. ;)  (not the most intuitive of places, but as IT and S3M share the same basic command set, that's where these functions ended up, just like how XM command decoding can be found in Load_mod.cpp instead)

Quote from: Danny-E 33 on January 09, 2023, 22:53:49Could you elaborate on this a bit? I don't see anything about specifying a pitch envelope in the effect reference wiki page (only mention of turning it on and off). If it makes a difference, I am using samples and not instruments.
In sample mode this option won't be available. However, it just came to my mind that there is probably a better alternative anyway: Using the sample-specific auto-vibrato, you can get slower vibratos than with pattern commands. But just like with pitch envelopes, this is only useful of course if you only need to use one sample with one specific set of vibrato parameters and don't need to change them dynamically.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

Danny-E 33

Ahh, it didn't even cross my mind that libopenmpt might "peek ahead" to process #xx. Thanks for the clarification.
I added the STPM+.FSM chunks and flipped the tempo clamp bit. I'm able to get an appropriate range by using #xx instead of set_tempo_factor(2.0).

I don't think static vibrato parameters will work for my needs so I opted to set the "fine" tone portamento flag in the .FSM and left the ticks per row at 1, but I'll keep this in the back of my mind. Thanks again for the wisdom.

Saga Musix

I think you don't need to toggle the tempo clamping bit, as that should only be relevant for tempo slides (unless you were going to use slides of course...).
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

Danny-E 33

#xx worked fine without necessarily turning off the tempo clamp bit, but set_position_order_row() did not. Arbitrarily jumping around the song often resulted in playback which was too slow (I assume being clamped at 255).

Saga Musix

You're right, there's a bug that mistakenly applies the tempo limits not just to tempo slide commands but all tempo commands when changing the playback position. This will be fixed in the next release.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.

Saga Musix

For the record, the tempo clamping fix can be found in the libopenmpt updated released today.
» No support, bug reports, feature requests via private messages - they will not be answered. Use the forums and the issue tracker so that everyone can benefit from your post.