New Tool: Interpolate Between Patterns

Hello, I have made another tool, similar structure to the last one. A new hotkey that interpolates between two step modulation points, the current step and the next to occur, across patterns. I often set modulation to occur across several patterns and I hate using graphical automation. Now I can define my start and end values and tie between them.

As is with the last one, please point out where I went wrong and I will fix it.

rfgd.garbanzo.InterpolateBeyond_V1.xrnx (2.2 KB)

Interpolate Automation

Most recent version VVVV
rfgd.garbanzo.InterpolateBeyond_V1.75.xrnx (5.3 KB)

10 Likes

Thanks! Aways wanted this. I wonder why it isn’t native!?

Your math is off in your interpolate function.

--interpolator
local function interpolate(stepCounter, startValue, endValue, curStep)
    if startValue < endValue then
        return ((endValue) * (curStep / stepCounter)) + startValue
    else
        return (startValue) - ((curStep / stepCounter) * startValue)
    end
end

This will go larger than endValue and crash when writing until a sufficiently large byte value.

  • you are getting a normalized value from 0 to 1 with curStep / stepCounter which represents your progress from start to end
  • If you multiply the endValue (let’s say 200) with 1 and add the startValue (for example 100) you get 300, when it should’ve been between 100 and 200.
  • Your second case doesn’t even use the endValue which means it cannot be right.

Below is the common equation for linear interpolation (or lerp)
a + t * (b - a)

  • t is your time that goes form 0 to 1
  • a and b are the two end points, the neat thing is that their order doesn’t matter, the equation will work whether or not a is smaller than b

Try updating your function knowing this. :slight_smile:

Some other points

  • Your code never accounts for a possible difference in pattern length, if the interpolation would need to go through patterns with different lengths the tool will leave gaps (if the ‘bridge pattern’ is longer) or possibly crash (if it is shorter).

  • What if there is no end point to be found? Maybe the tool should alert the user or try interpolating to the currently set value on the parameter until the end of the project

  • While technically not wrong, I’d suggest trying to keep it simple when writing logic, for example your isLineEmpty function complicates things to a point it might be difficult to see what it does (especially if you come back to this a few weeks later)

  local isLineNotEmpty = true
  if deviceString ~= "00" then
    isLineNotEmpty = false
  end
  return isLineNotEmpty

Whenever you want to return a boolean (true or false value) based on some condition, you can just return the condition. These two blocks of code do the same thing, if the deviceString contains “00” it will return true otherwise false.

return deviceString == "00"

Hope it helps! Happy coding!

2 Likes

Thank you for the code review again. I really value the hints. As is clear, I don’t really know what I’m doing and I’m looking around in the dark. That said, I think I was able to implement everything you suggested.

  • lerp is now the right math and works better
  • logic for different pattern lengths
  • if there is no end point it will use the parameters current value and run it until the end
  • isLineNotEmpty is now cleaner, although that doesn’t matter for the end user, but it helps me learn

gif below shows:

  • correct values
  • running across different pattern lengths
  • to the end
  • previous functionality is the same, will run between two defined points.

rfgd.garbanzo.InterpolateBeyond_V1.1.xrnx (2.3 KB)
Interpolate Automation_2

4 Likes

Good job! And don’t worry, we are all looking around in the dark.

This tool seems rather complete for what it aims to do now, but if you ever wanted to upgrade it, consider making it so that you could execute the command from anywhere in-between two values.

As you are more likely to enter the end value later (and then you have to scroll back to the start value to do the interpolation), it would make sense to do it backwards as well, but then it would be ambiguous which way you wanted to interpolate if there was a similar parameter value in both directions, so I guess the general solution would be to make it so that it needs to be started from an empty line, it looks in both directions, and if it finds two parameter values with matching device on both ends, it does the interpolation in-between them.

3 Likes

How dare you give me a new idea to obsess over until I complete it as soon as possible. Haha. I will see if I can get that working. You have good ideas.

4 Likes

Update:
rfgd.garbanzo.InterpolateBeyond_V1.2.xrnx (2.9 KB)
Interpolate Automation_3

Changes:

  • Works no matter where you use the hotkey (unless there is literally no step modulation in the track)
  • If you use it between two points it will interpolate between them. goes across patterns of different sizes as well
  • If you use it ON a point, that point will be used as the start point and it will run to the next point down
  • If you use it on a blank line and there is no next point, it will run the modulation to the end of the track
  • If you use it on a blank line and there is no previous point, it will run the modulation to the beginning of the track

I think with this you can really fly with interpolating now. The only glitches that I anticipate are:

  • that it doesn’t run to the end if there are deleted/unused patterns in the track. I don’t know how to pull the count of used patterns out. Just delete unused patterns if you don’t need them or place a modulation point at the end
  • It doesn’t really know what to do with alias patterns. Neither do I. I’m sure I could make something clever and complicated that loops and it and then carries on where it left off. I don’t think its really in the spirit of the idea though. I just wanted to make something that interpolates from A to B, so Just be mindful of using it around aliases I guess.
1 Like

little bug if I press hot key on final parameters

Could you elaborate on what you used it on? maybe a screenshot of the point you used it on?

For automation we need to have 2 points. If I pressed on the last point I have this message.

Sorry for my English))

Nice!

There is a bit of a general problem with your method. Patterns in renoise live in renoise.song().patterns[] but they are not necessarily in order (or even used) inside your pattern sequence (which is shown in the pattern matrix on the left of renoise).

So your song may be like 0, 1, 2, 8, 9, 5 or any other ordering. By default renoise will try keeping them at least in order (if the sorting is enabled) but you can still have gaps.

You can get the indices this sequence has using renoise.song().sequencer.pattern_sequence this.

You can define a helper function to get the pattern based on the index inside the sequence instead of the index in the patterns list.

function pattern_from_sequence(index)
  local song = renoise.song()
  local seq = song.sequencer
  if index <= #seq.pattern_sequence then
    return song:pattern(seq.pattern_sequence[index])
  else
    return nil
  end
end

You can also get the currently selected index for this by song.selected_sequence_index.

If a pattern track is aliased the tool could treat it as the end of the song. You can see if it is using song:pattern(pattern_index):track(track_index).alias_pattern_index which will be zero if it is not aliased, otherwise the alias index.

If you feel like your main is getting a bit unwieldy, it can help if you split it up into parts that all do just one thing. For example have a function that gets a position (as a starting sequence index and a line number) and track/device target and returns a range of start and end positions where the interpolation should happen, then have another function that receives such a range with track/device and does the actual interpolation.

While technically you could write everything into one long function, doing the splitting can help a lot with debugging as you don’t have to keep all the context in your head to understand where you have some edge-case you didn’t cover.

I’m sorry, I can’t recreate this, is this with the latest version I posted this morning? You should only need one modulation point now. Could you share a screenshot or picture of the point and patterns you’re trying to use it on? When I use the hotkey on a single modulation point it runs to the end of the project.

1 Like

ScreenFlow

Apparently I have a talent for stumbling upon completely unexpected errors =)

1 Like

Oh I see now. I don’t normally use that base device in the effect column. I didn’t write the script to consider L, P, or W commands. I will be able to think of something to fix that, I will take a look tonight. Thanks.

Could you try doing the same thing on a modulation for a device, like a filter sweep?

I would never find these issues myself/if I never shared this because I tend to do the same thing over and over.

1 Like

we are quickly approaching the limit of my abilities for complexity. I will take a look and try to figure out the indexing of patterns without the sequencer order. Last night I started to break my functions out, but it is always a struggle for me. Lack of experience I guess.

Don’t worry, you’ve already achieved a lot and there is no rush.

1 Like

rfgd.garbanzo.InterpolateBeyond_V1.3.xrnx (3.0 KB)
should work for volume, panning, and width parameters now too.

3 Likes

ScreenFlow

everything seems to be working. but I was confused by the moment where the final point aligns automation for itself even if there are no values for automation. this can cause a problem if the final automation point is the beginning of the next pattern.

A couple of ‘rules’ it follows:

  • if the cursor is on a modulation point, that will be the first point, regardless of if there is modulation prior in the project. (first attempt in gif)
  • if the cursor is on a blank line, the first point will be the first modulation point above it finds and the second point will be the first modulation point below that it finds (second attempt in gif)
  • if no modulation point is found (either before or after) it will use the value currently set in the device itself as the destination modulation value

So, when you activate the hotkey the first time, it sends 124D to the end of the project because that’s also what the parameter was set to on the device too. I think after using a bit, the arbitrary rules I’ve set up will be clear and modulating will be very simple.

2 Likes

This is a really good tool. Honestly it’s really good software: just what it offers and no more. You should be proud!

Only thing I would further request is exponential and logarithmic. I thought I saw someone else request it above but I don’t see it. I’m not sure how hard that would be to implement but this deserves to be a native feature, with those additions. Thanks Garbanzo.

3 Likes