DBraun / DawDreamer

Digital Audio Workstation with Python; VST instruments/effects, parameter automation, FAUST, JAX, Warp Markers, and JUCE processors
GNU General Public License v3.0
893 stars 65 forks source link

Some parameters don't get updated on dexed-0.9.6-win #149

Closed pcmbs closed 1 year ago

pcmbs commented 1 year ago

Hi, first of all thanks @DBraun for your great work on the library!

I am trying to change parameters 0 to 154 of dexed (dexed-0.9.6-win) using .set_parameter() to load presets (from a numpy array).

However, even though all parameters seem to be internally changed (by calling get_parameter() for each individual parameter or using get_parameters_description()), I notice that some parameters are actually not changed when I check the GUI (using open_editor()) or by listening to the rendered sounds. More precisely, parameters with indexes 10 to 99 (included) are not actually modified (see dexed_non_updated_parameters.log).

Do you know what could be the cause or if there is a possible workaround?

I checked the repo's issues and discussions but could not find people already mentioning that (and even seems to work for #63), which makes me think that I might be doing something wrong.

Here is the code for reproducibility (requires changing PIANO3_params.log .log extension to .npy):

import dawdreamer as daw 
import numpy as np
import os
from scipy.io import wavfile

SAMPLE_RATE = 44100
BUFFER_SIZE = 128 # Parameters will undergo automation at this buffer/block size.
PPQN = 960 # Pulses per quarter note (MIDI sequencer's timing resolution).
PATH_SYNTH = "C:\Program Files\VSTs\VST3\Dexed.vst3"  # extensions: .dll, .vst3, .vst, .component
PATH_PRESET = os.path.abspath('')

engine = daw.RenderEngine(SAMPLE_RATE, BUFFER_SIZE)

# Make a processor and give it the unique name "my_synth", which we use later.
synth = engine.make_plugin_processor("Dexed", PATH_SYNTH)
assert synth.get_name() == "Dexed"

# load parameters from PIANO 3 (SynprezFM_01 cartrigdge)
with open(os.path.join(PATH_PRESET,"PIANO3_params.npy"), "rb") as f: # load the preset parameters (ndarray)
    preset = np.load(f)

for i in range(len(preset)): synth.set_parameter(i, preset[i]) # set all parameters from ndarray entries

for i in range(len(preset)): # check if correctly assigned
    assert synth.get_parameter(i) == preset[i]  

# open UI for visual comparison: we can see that although all parameters were correctly 
# assigned (for loop in line 25) approx. half of the parameters were not updated 
# (e.g., all params from operator 1 to 3)
synth.open_editor() 

# Generate a MIDI note, specifying a start time and duration, both in seconds
synth.add_midi_note(69, 127, 0, 2)  # (MIDI note, velocity, start, duration)

# Generate DAG of processes
graph = [ (synth, []),]  # synth takes no inputs, so we give an empty list.

engine.load_graph(graph) #load a DAG of processors
engine.render(5) # Render 5 seconds of audio.

output = engine.get_audio() 

# rendering the audio results in a mix between the initial preset and PIANO3 preset
wavfile.write(os.path.join(PATH_PRESET,"PIANO3.wav"), SAMPLE_RATE, output.T) 

Thanks in advance!

pcmbs commented 1 year ago

I just tested on dexed-0.9.4-win (VST2, .dll) and it works fine as mentioned in the Plugin Compatibility page, looking forward to play around with it! Maybe you could add that DawDreamer it is not yet compatible with the .vst3 there?

DBraun commented 1 year ago

Ok I can check this out more at some point, but my first thought is that changing a parameter doesn't guarantee that it will affect the audio. FM synthesizers such as Dexed have various routings of several oscillators, and it's possible that a configuration doesn't use all of the parameters of a given oscillator. The parameter numbers may have also changed from 0.9.4 to 0.9.6, but all that is speculation. Just something to keep in mind if you test more plugins.

pcmbs commented 1 year ago

I actually generated the log file to guarantee that it is in fact not coming from what you are mentioning.

I basically set the current iterated parameter to be equal to 1.0 - round(synth.get_parameter(i)) such that parameters are either set to 1 (if param<= 0.5) or to 0 (if param > 0.5) depending on their initial value
and visually checked on the GUI using .open_editor() at each of the 155 iterations if the value actually changed. Non modified parameters were then written into the log file.

Moreover, I tested the exact same code on dexed 0.9.4 and it works fine, so I guess it has to do with dexed 0.9.6 (it would be good to know if someone else encountered the same problem on windows)

DBraun commented 1 year ago

I tried your script with the latest July 12, 2022 Dexed build (https://github.com/asb2m10/dexed/releases/tag/NIGHTLY) and didn't have any issues. Unfortunately, I'm noticing a similar problem with Serum 1.363b. If I load a preset, use set_parameter on a few parameters, and open_editor, then I see the changes in the GUI, but the audio isn't what I expect.

DBraun commented 1 year ago

Actually the Serum issue is my fault for having a MIDI note longer than my record duration, so the MIDI off message never happened. This caused an issue on later renders. There will be extra protection for this in the next DawDreamer release.

Closing because the next build of Dexed will address the issue you reported.