Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lfo display optimization #7895

Open
blancoberg opened this issue Dec 3, 2024 · 7 comments
Open

lfo display optimization #7895

blancoberg opened this issue Dec 3, 2024 · 7 comments
Labels
Bug Report Item submitted using the Bug Report template Code Refactoring General code refactoring and cleanup issues like names, unused variables, warnings, fixme Performance UI Issues related to UI look&feel

Comments

@blancoberg
Copy link
Contributor

Bug Description:
The lfo display is in need of some optimizations as all interactions with it is very laggy. It also causes lag to the rest of the UI. One example being the overlays, which starts to lag when you drag them over the bounds of the lfo display.

A first step to remedy this could be to add image caching to the waveform drawing. That way the waveform only needs to be drawn once each time a parameter is changed. This should solve the lag with the overlays atleast.

Reproduction Steps:
Steps to reproduce the behavior:

  1. Open formula code editor
  2. drag the window around the top of the ui and there is no lag.
  3. drag the window over the bounds of the lfo display and will lag significantly.

or

  1. Choose formula
  2. Drag the sliders so the waveform updates
  3. lag

Expected Behavior:
No lag :)

@blancoberg blancoberg added the Bug Report Item submitted using the Bug Report template label Dec 3, 2024
@nuoun
Copy link
Contributor

nuoun commented Dec 3, 2024

So it's calling Formula's process() function thousands of times to update the display when leaving the LFO area with the mouse even when nothing changed. Seems to me it can just not do that.

Can test this by running Surge from the terminal to see stdout with this Formula script:

function init(state)
    print("init")
    state.count = 0
    return state
end

function process(state)
    state.output = state.phase * 2 - 1
    print(state.count)
    state.count = state.count + 1

    return state
end

@mkruselj mkruselj added Code Refactoring General code refactoring and cleanup issues like names, unused variables, warnings, fixme UI Issues related to UI look&feel Performance labels Dec 3, 2024
@baconpaul baconpaul added this to the Surge XT 1.4.0 milestone Dec 4, 2024
@baconpaul
Copy link
Collaborator

@blancoberg does merging #7901 mean we can close this?

@blancoberg
Copy link
Contributor Author

@baconpaul I was thinking we can take a look at the actual drawing call for the waveform as well. I don't know if anything can be done there but it could atleast be worth a try

@baconpaul
Copy link
Collaborator

yeah ok in the waveform case i did quite a bit of work on it when we ported to juce - mostly involving path downsampling and range adjustment. but always good to look!

@blancoberg
Copy link
Contributor Author

blancoberg commented Dec 7, 2024

@baconpaul here is an idea; add a setBlockRate() to LFOModulationSource, and use that to lower the resolution of the lfo display.
right now it has to process over 8000 samples for a display that is a 10th of that width in pixels. In theory we could lower that to 1000 by setting the blocksize to 256 and still have enough samples to draw each pixel on the screen.

One downside to this approach is that this assumes the code in the formula takes blocksize into account, otherwise the output will be off. But at the same time, that could be a positive thing, as it will tell you if you have done something wrong.
( this only happens if you don't rely on state.phase that is. so in most cases this would still work)

@baconpaul
Copy link
Collaborator

Is block size a variable or a constexpr? I worry about the compute cost of taking it out of the compiler optimization path in the audio thread.

But that said you have the exact right idea run formulas at 10X rate and down sample - I wonder if just running the ui version at rate + 2 and the. Use every 8 samples would work

@blancoberg
Copy link
Contributor Author

blancoberg commented Dec 7, 2024

its a const as far as I know.
block_size is only checked once in process_block():

frate = (double)BLOCK_SIZE_OS * storage->dsamplerate_os_inv *
        pow(2.0, localcopy[rate].f);

The only different would be something like this:

frate = customBlockSize ? customBlockSizeValue : (double)BLOCK_SIZE_OS * storage->dsamplerate_os_inv *
        pow(2.0, localcopy[rate].f);

OR maybe we can set a pointer to a function so there is no need for a if statement at all. the pointer is set by default to a function that returns the BLOCK_SIZE, and switched to another function when a custom block size is set. Kind of how its done for the interpolations methods in wavetable osc

That way it shouldnt affect the lfos performance when not running them as displays

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Report Item submitted using the Bug Report template Code Refactoring General code refactoring and cleanup issues like names, unused variables, warnings, fixme Performance UI Issues related to UI look&feel
Projects
None yet
Development

No branches or pull requests

4 participants