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
860 stars 67 forks source link

Need to be able configure bus channels in/out for VST Plugins #46

Closed DBraun closed 2 years ago

DBraun commented 2 years ago

It would make a lot of sense for a Faust or VST processor to be able to output more than one stereo pair. I should test ambisonics-related plugins such as http://research.spa.aalto.fi/projects/sparta_vsts/plugins.html and https://leomccormack.github.io/sparta-site/

DBraun commented 2 years ago

Good work-in-progress here https://github.com/DBraun/DawDreamer/tree/feature/multichannel

DBraun commented 2 years ago

The multichannel branch is merged into main because it works well for Faust but I still want to test these ambisonics plugins more.

piotr-czarnecki commented 2 years ago

hi, I am very interested in this topic, I succesfully installed dawdreamer on linux as docker. I also installed IEM ambisonic plugins (https://plugins.iem.at/) and plugins are succesfully loaded under dawdreamer, I can print their parameters. The problem is

  1. how to setup correct number of input/output. Is there any sample code for this, or docs?
  2. how to set parameters of the plugin

regards!

DBraun commented 2 years ago

@piotr-czarnecki Great! There are two relevant methods right now https://dirt.design/DawDreamer/_generate/dawdreamer.ProcessorBase.html get_num_input_channels() and get_num_output_channels()

Those methods work all on processors including PluginProcessors.

Next you can set parameters on a PluginProcessor (https://dirt.design/DawDreamer/_generate/dawdreamer.PluginProcessor.html) with set_automation(index: int, data: np.array) or set_parameter(index: int, value: float)

You can refer to the tests: https://github.com/DBraun/DawDreamer/blob/13cf58a8ee4413e553b057722f2c6b9e0b884951/tests/test_plugins.py#L153

The reason I haven't closed this issue is because it's still a bit incomplete. We need a way to configure the bus layout, rather than just using the default. I need to use these methods better https://docs.juce.com/master/classAudioProcessor.html

piotr-czarnecki commented 2 years ago

thank you for so fast reply! I have problem with set_parameter(index: int, value: float). The problem is because my vst plugin should get string value rather than float.

in particular my code looks like:

import dawdreamer as daw

SAMPLE_RATE = 44100
BUFFER_SIZE = 128 # Parameters will undergo automation at this block size. It can be as small as 1 sample.
AMBI_PLUGIN = "/root/.vst3/IEM/StereoEncoder.vst3"  # plugin.

engine = daw.RenderEngine(SAMPLE_RATE, BUFFER_SIZE)
engine.set_bpm(120.)  # default is 120.
DURATION = 30 # How many seconds we want to render.

plugin = engine.make_plugin_processor("my_plugin", AMBI_PLUGIN)

print(plugin.set_parameter(0, 1000))
print(plugin.get_parameter_name(0))
print(plugin.get_parameter(0))
print(plugin.get_parameter_text(0))

and ouput is:

True
Ambisonics Order
1000.0
Auto

'Ambisonics Order' as well as 'Auto' are actually correct values, but it is incorrect to set this parameter to actually float. The correct values for that parameter are 'Auto', '1st', '2nd', '3rd', '4th', '5th', '6th', '7th' - those are strings. So I think that there should be a way to set string kind parameters.

Additionally I think there is some problem with 'get_num_output_channels()', for that plugin it returns 2. The problem is that It is never 2, it can only be one of: 1, 4, 9, 16, 25, 36, 49, 64.

DBraun commented 2 years ago

My understanding is that a menu of strings such as "Auto", "1st" and so on is actually broken into the [0-1] range. So "Auto" might be used when the number is between 0 and 1./N, the next from 1./N and 2/N and so on. So the numbers you pass to set_parameter should be between 0 and 1, not as large as 1000.

However, there's a bug I need to fix.

https://github.com/DBraun/DawDreamer/blob/13cf58a8ee4413e553b057722f2c6b9e0b884951/Source/PluginProcessor.cpp#L331

This line is missing setParameter(pair.first, pair.second);

The consequence is that if you update with set_parameter() and then check with either get_plugin_parameters_description, get_parameter, or get_parameter_text you won't see the update. It works in terms of automation and rendering, but it's confusing to the user. I will try to fix that soon (at least this week).

If get_num_output_channels() is 2, then that might just be the default. We need to use functions such as canApplyBusesLayout https://docs.juce.com/master/classAudioProcessor.html#a7e36934d17a82a4264552f7fda1b8889

DBraun commented 2 years ago

0.6.3 now has open_editor(), load_state(filepath: str), save_state(filepath: str), set_bus(inputs: int, outputs: int) for Plugin Processor. I also tested IEMPlugins https://github.com/DBraun/DawDreamer/blob/9d286e1171b7f4c89558e5bdb9337649d2803f53/tests/test_plugins.py#L413

piotr-czarnecki commented 2 years ago

David, at first, thank you very much for your effort in this topic!

I have succesfully tested 0.6.3 and confirm that under Windows, IEM plugin works perfectly!!! In particular, I have tested MultiEncoder with two different waves, each assigned to different direction, and rendering 6-th order ambisonic (49 channels). I have than listening under Reaper (https://www.reaper.fm) - result is well.

However found some issue.

  1. Under Windows, IEM plugins in VST3 version actually does not load, only VST2 works (the error is: 'RuntimeError: Unable to load plugin.'). I am not an expert in this, I read on JUCE forum (https://forum.juce.com/t/the-removal-of-juce-s-embedded-vst2-sdk/29994) that VST2 actually are deprecated. Is DawDreamer tested with other plugins in VST3 format? if so maybe something bad is with IEM plugins, however if there are problems with other VST3 plugins maybe it is worth to investigate thsi issue.

  2. Under Ubuntu, exactly same python code unfortunately does not work. The only difference is that I use VST3 instead of VST2. It is not easy to build VST2 version of IEM plugins as VST2 SDK is required (is available on older version of JUCE, so I did not tested this yet). VST3 version however are loadable (there is no issue similar to Windows, plugin loads and it is possible to get output from 'ambisonics_encoder.get_plugin_parameters_description()'), however rendered output is incorrect. The output actually contains proper number of channels, but only first two channels are non zero, all the other channels are just zeros. I think that it is worth to be fixed as I think it is easy to be reproduced. Could you check it? Do you have idea why this may happen?

my code for Windows as well as for Ubuntu is as follows:

plugin_path = "D:\iem\VST3\IEM\MultiEncoder.vst3" # only works with VST2 with path "D:\iem\VST2\IEM\MultiEncoder.dll"

DURATION = 50.
SAMPLE_RATE = 44100

engine = daw.RenderEngine(SAMPLE_RATE, 128)
ambisonics_encoder = engine.make_plugin_processor("ambisonics_encoder", plugin_path)
ambisonics_encoder.record = True

AMBISONICS_ORDER = 6
num_inputs = 2
num_outputs = (AMBISONICS_ORDER+1)**2  # this is a fixed equation
ambisonics_encoder.set_parameter(7, 0.375) # 7 is azimuth of the first sound, 0.375 relates to -45 degrees where zero is in front. 
ambisonics_encoder.set_parameter(12, 0.625) # 12 is azimuth of the second sound, 0.625 relates to 45 degrees
ambisonics_encoder.set_bus(num_inputs, num_outputs)

data, rate = librosa.load("1.wav", duration=DURATION+.1, mono=False, sr=SAMPLE_RATE)
data2, rate2 = librosa.load("2.wav", duration=DURATION+.1, mono=False, sr=SAMPLE_RATE)

data = data.mean(axis=0, keepdims=True)
data2 = data2.mean(axis=0, keepdims=True)
playback_data = np.stack((data.reshape(data.shape[1]), data2.reshape(data2.shape[1])))

graph = [
        (engine.make_playback_processor("playback", playback_data), []),
        (ambisonics_encoder, ["playback"])
]

engine.load_graph(graph)
engine.render(DURATION)

audio = ambisonics_encoder.get_audio()
file_path = f'test_plugin_encoder_2sources-vst3.wav'
wavfile.write(file_path, SAMPLE_RATE, audio.transpose())

Many thanks for great job!

DBraun commented 2 years ago

You can download the VST2 library from archive.org I forget the link though. It's also in prior commits of JUCE: https://github.com/juce-framework/JUCE/tree/cf4f12a452611e46d29e4549ce69adac345706b7

Let's migrate the discussion to https://github.com/DBraun/DawDreamer/issues/86