Mod Archive Forums

Music Production => Players => Topic started by: DZ-Jay on December 27, 2023, 16:49:02

Title: Understanding effects processing
Post by: DZ-Jay on December 27, 2023, 16:49:02
Hello,

I'm a retro-game developer for the old Mattel Intellivision, and I maintain a music player software library that plays tracks in a bastardized version of XM format.

I'm currently working on adding support for some (most?) FT2 effects and I need some help understanding how they should work.

Most docs suggest that when a new note is read, the note is played on the first tick, and the effect start playing on the subsequent ticks.  This sounds reasonable.  However, I would like to know how does this affect the behaviour of effects such as "note delay," "pattern delay," "jump to order," and other such effects that affect the music player's behaviour and not just the note waveform/amplitude.

For "pattern delay," do we really wait until the second tick to start counting down?  And what happens during the delay -- do we play the new note, or do we continue stretching what is already playing on the channel (i.e., the previous note)?

For "note delay," what plays while we are delaying the note?  Do we continue playing the previous note, or do we start playing the first one and just stretch it during the delay period without advancing the player state?  (I can't imagine it would just be silence ...)

For "jump to order," do we jump immediately upon reading the note/effect, or do we play the note and jump when it finishes?  (Same for "pattern loop" and "pattern break": do we break/loop immediately when signaled, on second tick, or when the note plays out?)

I apologize if these questions seem silly, but my target platform is severely constrained in resources (it's a games console from 1980!), and I wish to understand how to implement the effects in the most efficient and optimized way.

Thanks in advance!
    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on December 28, 2023, 08:54:29
Greetz :-)
I have good experience with XM and I can help you with my intel
Some corrections from others will be appreciated if any are needed

Pattern delay pauses the playback by the number of rows you specify. For example if you set pattern delay by 8 rows, the module will stop advancing for 8 rows equivalent of time (if you take ticks per row in mind) and continue afterwards. Note that all note playback and/or effects will persist while it's delayed.

Note delay makes the note play not on the first tick of the row, but later, depends on how many ticks are you delaying it. Make sure that it's not above the ticks per row value for your tracker. If for example your TPR is 4 and you set delay by 5, the note will simply not play when delaying, the previous note keeps playing without any stetching of sorts

Jump to order jumps the order after on the last tick of the row. Same works pattern break and pattern loop and also break to row.

Hope this helps :-)
Title: Re: Understanding effects processing
Post by: DZ-Jay on December 28, 2023, 19:10:34
Hi, Looper,

Thank you for responding, it helps a lot.  It is similar to what I've noticed by experimenting with MilkyTracker.

Let me see how far I get with this implementation ...

    Thanks again!
   -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on December 28, 2023, 19:15:37
Glad to help :-)
If there are any further questions, ask away
Title: Re: Understanding effects processing
Post by: DZ-Jay on December 29, 2023, 14:08:24
Hi again,

I have a question regarding the "Portamento To Note" effect.  I'm not quite clear on how it differs from the "Portamento Up/Down" effect.

From what I read on FT2's and MilkyTracker's docs, it appears that the main difference is that the regular portamento applies to the new note, while the "portamento to note" bends the pitch of the current note towards the new.

In my mind, this means that in the following example ("Portamento Up"):
Code: [Select]
  C-4 .1 .. ...
  E-4 .1 .. 103

the note E-4 is played, and starts bending upwards, while in the following ("Portamento To Note"):
Code: [Select]
  C-4 .1 .. ...
  E-4 .1 .. 304

the note E-4 is not played, but C-4 starts bending towards E-4.  I suppose this means that once E-4 is reached (if it gets there), the pitch stops bending and the E-4 note continues.

Is this correct?

     -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on December 29, 2023, 16:22:44
Hi again.
The note portamento works a little bit differently than portamento up or down effect. You've got the setup part correct, where you have to put that effect on the row where the note is present, so that it will start shifting pitch to that note. One important thing however is the speed. You have to also add 30x commands afterwards to keep pitching until it reaches your target note. You can also aet the speed to a high value, so it reaches the note in just one row, but generally, if you're going for a gradual portamento to a note, you need to do it like so:

Code: [Select]
C-5 01 v64 ---
D#6 01 v64 308
--- -- --- 308
--- -- --- 308
--- -- --- 308

And so on until it reaches the d#6 note
Title: Re: Understanding effects processing
Post by: DZ-Jay on December 29, 2023, 16:41:27
Hi again.
The note portamento works a little bit differently than portamento up or down effect. You've got the setup part correct, where you have to put that effect on the row where the note is present, so that it will start shifting pitch to that note. One important thing however is the speed. You have to also add 30x commands afterwards to keep pitching until it reaches your target note. You can also aet the speed to a high value, so it reaches the note in just one row, but generally, if you're going for a gradual portamento to a note, you need to do it like so:

Code: [Select]
C-5 01 v64 ---
D#6 01 v64 308
--- -- -- 308
--- -- -- 308
--- -- -- 308

And so on until it reaches the d#6 note

Thank you for responding.  I understand now, so the effect is applied only to the specific row on which it was set.  I believe this is the same for all (most?) other effects as well, right?

One other question on the note portamento:  What happens if it overshoots?  I mean, if I continue setting 3xx and the pitch reaches D#6 earlier?  Does it saturate at new note and stop pitching?  Or will it start pitching in the opposite direction to bend towards the note again?

I guess I'm still trying to grasp the key differences of the "port up/down" and "note port," to figure out how to implement them.

From a functional perspective, it seems that a key difference is that for regular portamento you tell it whether you want to bend up or down, along with the speed; while in note portamento you give it only the speed and the player pitches up or down depending on the relative direction of the note deltas.

What I am trying to determine now is if I need to also have the player keep track of how close it gets to the target note in order to stop when it reaches it; to start pitching in the opposite direction if it "misses" the target note; or if it is up to the musician to enter sensible speeds that "sound right."

Thanks again,

     -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on December 29, 2023, 17:45:55
Yes. you are correct. Basically ALL commands in the tracker are only applied to the specific row. Note commands, instrument commands, volume commands, effect commands, you specifically tell the song how to manage its playback.

On note portamento, when it reaches the target note in pitching, it simply stops shifting and keeps the note you were trying to pitch to. It will start to change only when you put a different note under that effect and it will start pitching to that specific new note afterwards. It won't shift backwards or any sort of action like that. (Vibrato would be more handy for you in this case hehe)

Yes. You are also correct in your 4th statement

It is up to musician whether the note reached it's point or not. XM does not revert changes if it overshoots or some sorts... Scratch that, Tracker cannot overshoot the target note when tone portamento is used. It can only undershoot it and even then it's the fault of the composer, who didn't calculate the number of rows required to reach the target note on a certain speed.

Hope this helps
Title: Re: Understanding effects processing
Post by: DZ-Jay on December 29, 2023, 18:02:12
Hope this helps

Yes, it helps greatly!  Thank you so much for the help.

    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on December 29, 2023, 18:56:58

Yes, it helps greatly!  Thank you so much for the help.

    -dZ.

I'm really glad it did, because I feel like my wording was a little twisted maybe :-)
Good luck with your progress and don't hesitate to ask about anything

Cheers
-Looper
Title: Re: Understanding effects processing
Post by: DZ-Jay on December 30, 2023, 15:09:48
Hello,

Sorry for the bother, but I have yet another question on the "note portamento" effect, which may apply to other effects as well.

The docs I've read suggest that effects are applied on the second tick after they are read.  To me, this means that when a new row is read, the note will be played on the first tick, and the effect after that.

Except that "note portamento" does not seem to honour this.

Based on my understanding (and the hardware limitations on the platform), the algorithm I've followed for my player goes something like this:

On every tick ...

It appears that "note portamento" (and I think a few other effects as well), are processed before the new note is applied.

I have not had a chance to take a look at the source code of MilkyTracker or any other tracker, so I do not really know how these things are implemented there; but I have some severe physical constraints on my platform that force me to compromise certain aspects.

I thought that the "skip effect on first tick" was a very reasonable side-effect of a functional optimization: We either read/decode row event data or we process effects; which avoids incurring the processing cost of both on the same tick.

However, it appears that this is not really the case -- at least not all the time -- so now that feature appears arbitrary to me. :(

I think the same thing applies to the "Note Delay" effect:  I can't delay the note if I already played it on the first tick, before processing the delay effect.

Obviously I am way off in my understanding.

My apologies if this sounds confusing -- perhaps I should describe my technical design, choices, and compromises.

    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on December 31, 2023, 01:01:42
Hmm. Sorry, but it indeed sounds confusing to me. I really don't know a solution to your problem..
Title: Re: Understanding effects processing
Post by: DZ-Jay on December 31, 2023, 16:10:33
No worries, I was mostly rambling.  My apologies for that.

I guess my primary question can be boiled down to this:  when "note portamento" is read, does it start bending the pitch of the old (current) note on the second tick, or on the first tick?

Likewise for the "note delay": does the first tick count as part of the delay, or should the counter start on the second tick?

    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 02, 2024, 12:57:25
No worries, I was mostly rambling.  My apologies for that.

I guess my primary question can be boiled down to this:  when "note portamento" is read, does it start bending the pitch of the old (current) note on the second tick, or on the first tick?

Likewise for the "note delay": does the first tick count as part of the delay, or should the counter start on the second tick?

    -dZ.

It all starts on the first tick
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 03, 2024, 00:14:44
Thanks.  I have figured out my algorithm now.  I'm confident I can implement the effects.  :)

    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 03, 2024, 01:08:44
Interested to see progress from you!
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 03, 2024, 17:08:21
Interested to see progress from you!

Thanks for the interest.  I'll post a WAV or MP3 file as soon as I have something to show.

Right now, I have just completed the initial infrastructure changes to my music player that will allow it to support effects -- not a trivial thing for a tracker driving an AY-8914 on a 50 year old CPU with severe RAM limitations. :)

I will start implementing what look to be the easiest ones this week -- arpeggio, portamento up/down, volume slide, and tremolo -- so stay tuned!

    -dZ.


P.S., You may want to temper your expectations ... The Intellivision hardware is not powerful enough to play PCM samples, so all instruments are square waves with software envelopes.
Title: Re: Understanding effects processing
Post by: m0d on January 03, 2024, 17:54:55
50 years! Bloody heck! :O
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 03, 2024, 18:08:32
50 years! Bloody heck! :O

I know!  Sounds crazy when I say it that way, but the truth is that the Intellivision is a games console released in 1980.  It has a CP-1610 processor -- one of the very firsts 16-bit microprocessors -- running at 1MHz, designed sometime in the 1970s!!! :O

The console has an on-board AY-8914 sound processor (a very early one!), and offers an expansion module that adds an extra sound chip.  Each AY has 3 square wave voices and a single noise generator which can be mixed with any of the voices.

That's it.  No filters.  No selectable waveforms.  No ring modulator.  All modulation is done in software, old school.

My goal is to make the Intellivision sing glorious chip-tunes like the best of the crop. :)

     -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 07, 2024, 23:37:49
HAPPY NEW YEAR!!!

I have some good news to share about my progress ...  I have managed to implement the first three effects:

I have tested and debugged these first effects and they appear to work as expected.
Attached are three wave files generated from the emulator.  I created a simple one-track pattern for each to test the data encoding, the music player, and the effect processing.

For reference, below are the test patterns I used:
Arpeggio:
Code: [Select]
; 0xx: Arpeggio
00 C-4 -1 F 037
01 --- -- - 037
02 --- -- - 037
03 --- -- - 037
04 --- -- - 037
05 --- -- - 037
06 --- -- - 037
07 --- -- - 037
08 --- -- - 037
09 --- -- - 037
10 --- -- - 037
11 --- -- - 037
12 --- -- - 037
13 --- -- - 037
14 --- -- - 037
15 --- -- - 037

16 D-4 -- F 037
17 --- -- - 037
18 --- -- - 037
19 --- -- - 037
20 --- -- - 037
21 --- -- - 037
22 --- -- - 037
23 --- -- - 037
24 E-4 -- - 037
25 --- -- - 037
26 --- -- - 037
27 --- -- - 037
28 F-4 -- - 037
29 --- -- - 037
30 --- -- - 037
31 --- -- - 037

Portamento (Up/Down)
Code: [Select]
; 1xy: Portamento Up
; 2xy: portamento Down
00 C-4 -2 F 208
01 --- -- - 208
02 --- -- - 208
03 --- -- - 208
04 --- -- - 208
05 --- -- - 208
06 --- -- - 208
07 --- -- - 208
08 --- -- - 208
09 --- -- - 208
10 --- -- - 208
11 --- -- - 208
12 --- -- 0 ---
13 --- -- - ---
14 --- -- - ---
15 --- -- - ---

16 C-3 -- F 108
17 --- -- - 108
18 --- -- - 108
19 --- -- - 108
20 --- -- - 108
21 --- -- - 108
22 --- -- - 108
23 --- -- - 108
24 --- -- - 108
25 --- -- - 108
26 --- -- - 108
27 --- -- - 108
28 --- -- 0 ---
29 --- -- - ---
30 --- -- - ---
31 --- -- - ---

Portamento To Note
Code: [Select]
; 3xx: Portamento To Note
00 C-4 -2 F ---
01 E-4 -2 F 304
02 --- -- - 304
03 --- -- - 310
04 --- -- - ---
05 --- -- - ---
06 --- -- - ---
07 --- -- - ---
08 E-4 -1 - ---
09 --- -- - ---
10 --- -- - ---
11 --- -- - ---
12 --- -- - ---
13 --- -- - ---
14 --- -- - ---
15 --- -- - ---

16 E-4 -2 F ---
17 C-4 -2 F 304
18 --- -- - 304
19 --- -- - 310
20 --- -- - ---
21 --- -- - ---
22 --- -- - ---
23 --- -- - ---
24 C-4 -1 - ---
25 --- -- - ---
26 --- -- - ---
27 --- -- - ---
28 --- -- - ---
29 --- -- - ---
30 --- -- - ---
31 --- -- - ---

I am quite happy with the results and this success gives me confidence to proceed with the rest of the effects.

I have yet to implement "effects memory," but I suppose it shouldn't be a big deal.

Anyway, I just wanted to share some progress.  This is a major milestone in my project, for it included re-factoring and enhancing the music tracker, expanding the encoding structure, and implementing the effects.  :)

Thank you to looper231 for your patience.

     Cheers!
     dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 11:09:13
Great stuff! Keep it up, brother!  :)

Code: [Select]
Thank you to looper231 for your patienceHehehe, thank you for your great effort too :) <3
Title: Re: Understanding effects processing
Post by: m0d on January 08, 2024, 13:02:23
I’ve got nothing to add other than to congratulate, bravo that is awesome DZ-Jay
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 13:05:25
BTW, Dz, You can try to port Pink's chiptunes as a benchmark for your work. He has a lot of great chips out there. You can also take a look at AHX uploads, since they are SID-like tunes but made on Amiga.

Good luck with your project!
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 13:20:44
BTW, Dz, You can try to port Pink's chiptunes as a benchmark for your work. He has a lot of great chips out there. You can also take a look at AHX uploads, since they are SID-like tunes but made on Amiga.

Good luck with your project!

Hello,

Thanks for the support and encouragement.  Once I get a few effects more, I'll try porting some tunes.

I don't really compose music myself, but I like tracking.  I sort of treat it as "remixing" like back in my DJ days.

BTW, where do I find Pink's chiptunes?

     -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 13:24:58
https://modarchive.org/index.php?request=view_artist_modules&query=85716&page=2#mods

A good chunk of them is AHX. rest are MODs with chiptune samples in them
The difference here is that in AHX is not sample based
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 14:29:20
https://modarchive.org/index.php?request=view_artist_modules&query=85716&page=2#mods

A good chunk of them is AHX. rest are MODs with chiptune samples in them
The difference here is that in AHX is not sample based

Thanks for that.  It seems MilkiTracker does not open AHX.

Sorry for the bother, I'm sort of new to the scene -- can you recommend an AHX tracker for Mac?

    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 14:34:15
Sorry for the bother, I'm sort of new to the scene -- can you recommend an AHX tracker for Mac?
    -dZ.
http://www.hivelytracker.co.uk/downl.php
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 15:53:36
I have another question on effect functionality.  (Please let me know if you recommend I start a new topic for each individual question.)

For "volume slide," is the note volume itself altered or is it only modulated while the effect is given?

Here is an example.  Suppose I set a note with a volume slide downwards by one unit (the amplitude range on my sound chip is from 0-F).  The volume is decrement on each tick, only row #2.  Does the note continue at its regular volume, or does it stay at the last level modulated in row #1?

Code: [Select]
00 C-4 -1 F A01
01 --- -- - A01
02 --- -- - ---   <-- what happens to volume here?
03 --- -- - ---
04 --- -- - ---
05 --- -- - ---
06 --- -- - ---
07 --- -- - ---
08 --- -- - ---
09 --- -- - ---
10 --- -- - ---
11 --- -- - ---
12 --- -- - ---
13 --- -- - ---
14 --- -- - ---
15 --- -- - ---

   -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 16:08:58
Hi again. The note volume stays to whatever it is sled to after. The effect itself slides the volume of the note played and not the sample itself. Keep in mind that "Volume slide" is not only an effect command but also a volume command. What do I mean? In XM and other later tracker formats you can do like so:

Code: [Select]
c-5 18 v64 ---
--- -- c01 ---
--- -- c01 ---
--- -- c01 ---
--- -- c01 ---

"c01" here is a volume command, which tells the note to slide volume. In this case, slide upwards. to slide it down, you use dXX command. This is useful for many different cases, like for example if you want to keep portamento while you're sliding volume.

Also keep in mind that there is an effect like "Kxx" which is a VolSide+Vibrato and "Lxx" which is VolSlide+NotePorta

It's ultimately up to a composer on how to use the tools.

Also, you can keep it in one thread. It's okay :)

Hope this helps
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 16:26:02
Hi again. The note volume stays to whatever it is sled to after. The effect itself slides the volume of the note played and not the sample itself.

Hmm ... I think I understand.  In my case, I don't have samples -- just software instruments.  I suppose that for this, your comment above means that the base volume of the instrument (modulated by its envelope) is not affected, but the note in the channel is.

Is that right?

Keep in mind that "Volume slide" is not only an effect command but also a volume command. What do I mean? In XM and other later tracker formats you can do like so:

Yeah, I've seen that before.  My current data structure supports a single byte for the volume, so it has no way to encode those.  Therefore, I'm sort of ignoring them for the time-being. :)

Also keep in mind that there is an effect like "Kxx" which is a VolSide+Vibrato and "Lxx" which is VolSlide+NotePorta

Hmm ... I've seen those as "6xx" (Vibrato + Volume Slide) and "5xx" (Portamento To Note + Volume Slide), but I suppose it's the same thing.

Also, you can keep it in one thread. It's okay :)

Will do. :)

Hope this helps

Thank you, it does.

   -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 16:33:40
I suppose that for this, your comment above means that the base volume of the instrument (modulated by its envelope) is not affected, but the note in the channel is.

Is that right?
   -dZ.

Correct. the base volume of the instrument/sample isn't affected by the commands, but are instead affected on the channel where its played on. Let's just say, that whatever happens on the pattern sheet stays within that pattern sheet :-)
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 17:01:15
Correct. the base volume of the instrument/sample isn't affected by the commands, but are instead affected on the channel where its played on. Let's just say, that whatever happens on the pattern sheet stays within that pattern sheet :-)

That makes sense, and I just observed that same behaviour in MilkyTracker.

I may be able to replicate that behaviour for volume, but unfortunately not for pitch-bending. :(

Call it a technical limitation of the way it was originally implemented.  It means that the moment you stop a portamento effect, the note will go back to its base pitch.  I don't see a way around it at the moment without re-writing the entire thing.  :'(

     -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 17:09:33
Call it a technical limitation of the way it was originally implemented.  It means that the moment you stop a portamento effect, the note will go back to its base pitch.  I don't see a way around it at the moment without re-writing the entire thing.  :'(

This might help:
The way portamento and vibrato works in a tracker is by changing the speed of the sample played. so to tone down the note's pitch, the sample is gradually slowed down.

I should have also mentioned, but pitches in trackers work same way any sampler does in a DAW. You tune it to a specific note and then each note corresponds to a certain speed stretch of the sample.

It doesn't work that way on non-sample based trackers of course, but if you're aiming to port XM, you should keep that in mind, maybe that helps you solving the question
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 17:46:02
Call it a technical limitation of the way it was originally implemented.  It means that the moment you stop a portamento effect, the note will go back to its base pitch.  I don't see a way around it at the moment without re-writing the entire thing.  :'(

This might help:
The way portamento and vibrato works in a tracker is by changing the speed of the sample played. so to tone down the note's pitch, the sample is gradually slowed down.

I should have also mentioned, but pitches in trackers work same way any sampler does in a DAW. You tune it to a specific note and then each note corresponds to a certain speed stretch of the sample.

It doesn't work that way on non-sample based trackers of course, but if you're aiming to port XM, you should keep that in mind, maybe that helps you solving the question

Thanks.  The problem I have is that my tracker was never intended to replicate XM.  The individual who originally developed it, based it on XM -- but stripped it to its minimum in order to fit within the platform constraints and be super fast and compact to include in our games.

I have since carried on the mantle of maintaining it, and now I'm sort of stretching its capabilities by adding support for (some) XM effects.  However, I don't think I will ever be able to achieve parity -- the Intellivision is really a rather limited platform, and my tracker has carried on certain original design choices that limit its flexibility.

For instance, consider that the tracker runs on a three step cycle:

Step #2 is very simplistic:  For each channel, it keeps track of the current note, instrument, and volume.  It has a counter that it uses to advance the state of envelope (and now effects).

On every tick it does the following:

As you can see, it is sort of "stateless":  the period and volume are re-computed on every tick based on the current note and instrument -- and the channel counter is used to know how much to modulate by as it progresses.

I've added a new stage between #2 and #3 to apply effects.  Once the instrument synthesizer computes the period and volume for the current tick, an active effect will further modulate them.

It works, but the downside is that the moment the effect stops modulating, the instrument synthesizer will compute the pitch and volume as normal, so the note will sound exactly as it would at that point in the pattern, had the effect not being applied.

Obviously this is not compatible with XM and other trackers.  But re-engineering that is akin to starting the tracker from scratch, which seems a lot more daunting than what I'm actually doing. :(

I hope this makes sense.  Anway, sorry for the long post.

    -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 18:30:48
Er ... I just took a long hot shower (what I tend to do to think and ponder) and had an epiphany -- I think I may be able to fix my pitch bending behaviour.   :o

Stay tuned!

    -dZ.
Title: Re: Understanding effects processing
Post by: looper231 on January 08, 2024, 18:34:06
He's onto something. Shower thoughts always win
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 21:07:04
Got something ...   :D

I made a quick and dirty test with the following pattern.  See the attached output from the emulator.

Code: [Select]
00 C-4 -3 F 210
01 --- -- - 200
02 --- -- - 208
03 --- -- - 200
04 --- -- - 204
05 --- -- - 200
06 --- -- - ---
07 --- -- - ---
08 --- -- - ---
09 --- -- - ---
10 --- -- - ---
11 --- -- - ---
12 --- -- - ---
13 --- -- - ---
14 --- -- - ---
15 --- -- - ---

16 C-3 -- F 110
17 --- -- - 100
18 --- -- - 108
19 --- -- - 100
20 --- -- - 104
21 --- -- - 100
22 --- -- - ---
23 --- -- - ---
24 --- -- - ---
25 --- -- - ---
26 --- -- - ---
27 --- -- - ---
28 --- -- - ---
29 --- -- - ---
30 --- -- - ---
31 --- -- - ---

I am now tracking the pitch delta separately and applying it the the note period for as long as the note lasts.  Portamento increments or decrements this value, depending on the case.

When the effect stops (rows #06 and #22), the delta continues being applied to the note.  On a new note, the delta is reset.

I suppose I can also use this same state variable for the "Set Fine-Tune" effect (E5x) later on.

     -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 08, 2024, 22:29:13
I have another question:  For vibrato effect, what does the "y" parameter represent?  Is it just a period or is it an index into some table of offsets?

I know that the speed is how much to advance the position in the waveform on each tick (like I do with volume envelopes), but I'm not sure I know what to do with the depth parameter.

    -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 09, 2024, 13:30:39
I have another question:  For vibrato effect, what does the "y" parameter represent?  Is it just a period or is it an index into some table of offsets?

I found some information here:
https://forum.openmpt.org/index.php?topic=6835.0

Quote
The pattern effect (4xy) has a resolution of 1/8th of a semitone in linear slides mode, so at the maximum depth (15) it spans approximately +/-2 semitones.

Seems reasonable.  Now I have to figure out how to modulate that with the various waveforms.  My tracker uses a static triangle waveform for instrument auto-vibrato (a simple linear ramp up and down dividing the peak amplitude by powers of 2), so I can't re-use that one.

I suppose I could limit my implementation to a single waveform.  If so, which would you recommend?  Triangle is linear and straightforward, but sine is the XM default ... Any suggestions?

     -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 20, 2024, 16:16:41
Just a minor update -- I'm still working on this project, I just ran out of Christmas vacation days so I have mostly the week-ends to work on it.

I had a rather major set-back due to the way I implemented the pitch bending effects -- when the effect runs out, the original tone was being reset, which is not correct.  It wasn't really a bug, more like a design flaw.  This was particularly bad in the Note Portamento:  if the effect ran out before reaching the new note, the period would be reset to the new note anyway!

In any case -- I came up with a different approach, and now I am happy to say that I have finally slay that dragon for good!  Portamento Up/Down and Note Portamento behave correctly.  :D

Now, on to Vibrato.  It's going to be tricky because my target CPU (GI CP-1610) does not have instructions for multiplication or division -- heck, it doesn't even have a logical OR instruction! -- so scaling amplitudes and tone periods is expensive.

Nevertheless, I think I see a way out ... stay tuned!

     -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on January 21, 2024, 18:24:22
Quick update:  Vibrato is done! (That was quick!  :o)

Attached is a test sample extracted from the emulator.  It uses the following pattern -- a single note played for 32 rows, with a flat sustain instrument envelope, just to let the vibrato play out:
Code: [Select]
00 C-4 -3 F 444 ; Speed: 4; Depth: 1/4
01 --- -- - 400
02 --- -- - 400
03 --- -- - 400
04 --- -- - 400
05 --- -- - 400
06 --- -- - 400
07 --- -- - 400
08 --- -- - 480 ; Speed: 8
09 --- -- - 400
10 --- -- - 400
11 --- -- - 400
12 --- -- - 400
13 --- -- - 400
14 --- -- - 400
15 --- -- - 400

16 --- -- - 408 ; Depth: 1/2
17 --- -- - 400
18 --- -- - 400
19 --- -- - 400
20 --- -- - 400
21 --- -- - 400
22 --- -- - 400
23 --- -- - 400
24 --- -- - 40F ; Depth: full
25 --- -- - 400
26 --- -- - 400
27 --- -- - 400
28 --- -- - 400
29 --- -- - 400
30 --- -- - 400
31 --- -- - 400

I've adapted the effect to conform to the platform capabilities.  It simulates an LFO with a sine waveform plotted over 64 points, with a maximum amplitude of +/- 2 semitones:
Code: [Select]
      0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
30 0F :.............#####.............:...............:...............
29 0E :...........##..:..##...........:...............:...............
28 0D :..........#....:....#..........:...............:...............
27 0C :........##.....:.....##........:...............:...............
26 0B :.......#.......:.......#.......:...............:...............
25 0A :......#........:........#......:...............:...............
24 09 :...............:...............:...............:...............
23 08 :.....#.........:.........#.....:...............:...............
22 07 :....#..........:..........#....:...............:...............
21 06 :...#...........:...........#...:...............:...............
20 05 :...............:...............:...............:...............
19 04 :..#............:............#..:...............:...............
18 03 :.#.............:.............#.:...............:...............
17 02 :...............:...............:...............:...............
16 01 :#..............:..............#:...............:...............
15 00 #---------------+---------------#-------------------------------
14 01 :...............:...............:#..............:..............#
13 02 :...............:...............:...............:...............
12 03 :...............:...............:.#.............:.............#.
11 04 :...............:...............:..#............:............#..
10 05 :...............:...............:...............:...............
09 06 :...............:...............:...#...........:...........#...
08 07 :...............:...............:....#..........:..........#....
07 08 :...............:...............:.....#.........:.........#.....
06 09 :...............:...............:...............:...............
05 0A :...............:...............:......#........:........#......
04 0B :...............:...............:.......#.......:.......#.......
03 0C :...............:...............:........##.....:.....##........
02 0D :...............:...............:..........#....:....#..........
01 0E :...............:...............:...........##..:..##...........
00 0F :...............:...............:.............#####.............

The speed parameter is obviously how many points in the graph to advance on each tick, and the depth parameter scales the amplitude at each point in 1/16th increments.  So, a depth of $4 will be 4/16th of the amplitude at the current point in the graph, and a depth of $F will be 16/16th, or the full amplitude.

The only thing I am not really sure about is the maximum amplitude of the LFO.  I have it right now to be the distance between the previous and the next semitone of the active note -- or +/- 2 semitones.  I think this is how it should be.

Any feedback is appreciated! :)

     -dZ.
Title: Re: Understanding effects processing
Post by: DZ-Jay on March 17, 2024, 17:23:16
Progress, you ask?  Why, yes.  We have some.  :)

I fixed a bug* in which "tick-zero of a row" was confused with "first tick of a note," which caused the tick-zero handling to only be executed when a new note is started.  DOH!

(* The "bug" existed in my head as well, since I wrote the code to work that way because that is how I understood it.  Imagine my shock and surprise when I finally figured out that it was all wrong.)

We now have the following effects supported:

That's a pretty nice roster.

All these effects have been tested and work as expected -- well, at least the way I understood them to work, based on my research, reference documents, and the feedback from this forum.

I'm quite happy with the results.  I feel now that I have a rather solid framework that handles ticks and effects correctly, so adding new effects should go smoother in the future -- I mean, what could possibly go wrong?  ;D  (Said the guy that has had to re-write his tracker engine multiple times to fix design flaws ...)

Anyway, my next step is to implement a few more of the low-hanging fruit effects, such as  Set Song Speed (Fxx), Tremor (Txx), etc., and see how it goes.

Stay tuned! (Har! Har! see what I did there?)

     -dZ.


UPDATE: Added Gxx effect.
Title: Re: Understanding effects processing
Post by: looper231 on March 18, 2024, 02:10:59
Keep up the development  ;)
Title: Re: Understanding effects processing
Post by: DZ-Jay on April 06, 2024, 14:28:07
Another week, another progress report.

After going off on a tangent foolishly attempting to optimize effects processing, I hit a rather nasty brick wall.  I ended up reverting most of those changes and going back to the way I had it working.

Plus ça change ...

Anyway, I added a few more effects:  The tracker now has dynamic song speed (Fxx) and pattern delay (EEx), among other new tricks.

Below is the latest list of effects and their status:
Code: [Select]
--------------------------------                ------
Standard Effects                                Status
--------------------------------                ------
$00: 0   Arpeggio                               Done
$01: 1   Portamento Up                          Done
$02: 2   Portamento Down                        Done
$03: 3   Portamento To Note                     Done
$04: 4   Vibrato                                Done
$05: 5   Portamento To Note + Volume Slide      Done
$06: 6   Vibrato + Volume Slide                 Done
$07: 7   Tremolo                                Done
$08: 8   ---                                   
$09: 9   ---                                   
$0A: A   Volume Slide                           Done
$0B: B   Jump To Order                         
$0C: C   Set Note Volume                       
$0D: D   Pattern Break                         
$0E: E   E Sub-Commands (Dispatcher)            Done
$0F: F   Set Song Speed                         Done
$10: G   Set Global Volume                      Done (Controls volume attenuation only.)
$11: H   Global Volume Slide                    Done (Controls volume attenuation only.)
$12: I   ---                                   
$13: J   ---                                   
$14: K   ---                                   
$15: L   Set Envelope Position                 
$16: M   ---                                   
$17: N   ---                                   
$18: O   ---                                   
$19: P   ---                                   
$1A: Q   ---                                   
$1B: R   Re-trigger Note + Volume Slide         
$1C: S   ---                                   
$1D: T   Tremor                                 
$1E: U   ---                                   
$1F: V   ---                                   
$20: W   ---                                   
$21: X   X Sub-Commands                         
$22: Y   ---                                   
$23: Z   ---                                   
                                               
--------------------------------                ------
Standard Effects                                Status
--------------------------------                ------
$00: E0  ---                                   
$01: E1  Fine Portamento Up                     Done
$02: E2  Fine Portamento Down                   Done
$03: E3  ---                                   
$04: E4  Set Vibrato Waveform                   
$05: E5  ---                                   
$06: E6  Pattern Loop                           
$07: E7  Set Tremolo Waveform                   
$08: E8  ---                                   
$09: E9  Re-trigger Note                       
$0A: EA  Fine Volume Slide Up                   Done
$0B: EB  Fine Volume Slide Down                 Done
$0C: EC  Note Cut                               
$0D: ED  Note Delay                             
$0E: EE  Pattern Delay                          Done
$0F: EF  ---                                   
                                               
--------------------------------                ------
"X" Extended Sub-Command Effects               
--------------------------------                ------
$00: X0  ---                                   
$01: X1  Extra Fine Portamento Up               
$02: X2  Extra Fine Portamento Down             

Aiming for Note Delay (EDx) next and a few of the other "global" control commands like Pattern Loop (E6x), Pattern Break (Dxx), Jump To Order (Bxx), etc.

Here's hoping for a smooth ride!

   -dZ.


P.S. One of these days I will have to start tracking a song for real to make sure it all works ... Someday ...