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

Preset support for non .fxp format #131

Open
gudgud96 opened this issue Nov 4, 2022 · 6 comments
Open

Preset support for non .fxp format #131

gudgud96 opened this issue Nov 4, 2022 · 6 comments
Assignees
Labels
enhancement New feature or request

Comments

@gudgud96
Copy link

gudgud96 commented Nov 4, 2022

Hi @DBraun.

Thanks for this wonderful repo, it was truly a great tool for me to automate some workflows in my project!

I am recently working on using DawDreamer on Vital synthesizer. Overall for Vital most of the parts are compatible, only the preset loading part is not as .vital files are inherently JSON files instead of .fxp.

Reproducibility

The following code should run fine, including loading the synth, adding midi note, and setting parameters:

SAMPLE_RATE = 16000
BLOCK_SIZE = 512

engine = dawdreamer.RenderEngine(SAMPLE_RATE, BLOCK_SIZE)
SYNTH_PLUGIN = "C:/Program Files/VstPlugins/Vital.dll"

synth = engine.make_plugin_processor("vital_synth", SYNTH_PLUGIN)
assert synth.get_name() == "vital_synth"

synth.clear_midi()
synth.add_midi_note(72, 127, 0.01, 0.5) # (MIDI note, velocity, start, duration)
synth.set_parameters(20, 1)

However loading preset does not work as it is not compatible:

synth.load_preset("my_preset.vital")

I would like to ask if you would be open to the idea of supporting custom preset formats other than .fxp (such as .vital files). My idea might be to have some factory pattern on loadPreset, but I am not sure if this would be a feature of high demand.

@DBraun
Copy link
Owner

DBraun commented Nov 4, 2022

Thanks! I would like to do exactly what you've described, but I don't know how. I'm only able to interact with plugins via the VST API via JUCE, and there isn't a more general "load preset" function. There's only what I've already tried to implement (load_preset for ".fxp" files, and load_vst3_preset for ".vstpreset" files). The best solution so far, and it's still not great, is to use load_state and save_state in conjunction with open_editor. You would have to manually save a state for each of your .vital files. See test_plugin_editor in https://github.com/DBraun/DawDreamer/blob/feature/faust-signal-api/tests/test_plugins.py for some ideas.

@DBraun DBraun self-assigned this Nov 4, 2022
@DBraun DBraun added the enhancement New feature or request label Nov 4, 2022
@gudgud96
Copy link
Author

gudgud96 commented Nov 7, 2022

After studying I agree as you said, the open_editor approach might be our only best bet for now. Reason being the way how individual synth parses custom preset files + loading them into each of its own module states is highly customized, and almost impossible to be covered by DawDreamer on a case-by-case basis.

Take Vital as example, Vital supports dawdreamer's load_state and save_state due to open_editor support for manipulating states (see code). However the methods for loading the state into the synth after parsing the preset file (in Vital's context it's jsonToState) is a private function, so even we are able to parse JSON preset files, loading them into synth as a state is still not viable. Similar observation also happens for Dexed.

load/save_state should be helpful enough, but still we can't directly deal with custom preset files. A hacky way though, is to (1) parse preset file; (ii) warp it into memory block data; (iii) call setStateInformation (set_state underlying function). I personally think it's a dirty + "detour" solution, but might work. Love to hear what you think!

@DBraun
Copy link
Owner

DBraun commented Nov 7, 2022

If you're lucky, the preset file is actually human-readable, like json or xml, and you would be able to parse it with Python and then call set_parameter on each parameter. If you observe that for a specific plugin and can make a parser, I would welcome it as a contribution. We can fit it in somehow or put it in an examples folder.

Also, DawDreamer's PluginProcessor's load_state goes to here.

Maybe this means you can just call synth.load_state on a vital json filepath? Did you try that?

@GeoSpark
Copy link

I've tried this on Linux and Vitalium (the FOSS version of Vital), and I mostly get a segfault.

My first problem was that the plugin was running in a separate thread, and so calling

    import ctypes
    ctypes.CDLL('libX11.so').XInitThreads()

Was necessary before I initialized DawDreamer. Otherwise I got

[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:175: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.

After adding those lines I can open the UI with synth.open_editor() but as soon as I close the window I get the segfault.
Calling synth.load_state() with a Vitalium save file, opens and closes a window quickly, then I get the segfault again.
I totally understand that this could easily be a Vitalium/Vital issue, but if there are any thoughts as to why this might be happening, I'd love to hear them!

Strangely it did work once, and I managed to save a WAV file, but it's not worked since.

@DBraun
Copy link
Owner

DBraun commented Dec 19, 2022

@GeoSpark Thanks for the tip about libX11. That's something worth investigating.

Does synth.save_state("foo.json") with Vital/Vitalium result in the foo.json being human readable JSON?

If you got audio the first time, it's probably because save_state hadn't been called yet? But then subsequently you were trying load_state, which is where errors/crashes seem to be happening.

@DBraun
Copy link
Owner

DBraun commented Jun 4, 2023

For those subscribed here, we now have two examples for multiprocessing synthesizers:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants