PDA

View Full Version : call from host -> render track? :P


onqel
11-19-2009, 01:51 PM
Hi

Are there a way for my plugin to know when the host is rendering the project to file ? I have some settings (oversampling, etc) that I would like to change on render..

I've tried searching but couldn't find anything..

- John

Tale
05-05-2010, 09:22 AM
I would also like to know this, although I think I already know that "no" is the answer...

The problem is, I've created a seperate thread to recalculate wave tables. This works great in realtime, but the wave tables don't get recalculated at all when rendering offline. What I would like is a simple flag that tells me that we're rendering offline, so I know I can recalculate the wave tables in the audio thread and not is a seperate thread. However, I don't think there is such a simple flag, or is there?

So what other options are there? Implement the effOffline* opcodes?

Xenakios
05-05-2010, 11:32 AM
So what other options are there? Implement the effOffline* opcodes?

That most definitely isn't going to do anything good, it would need support from the host side. However, Steinberg's Wavelab is the only host around that has (had?) support for those.

There is however for example this :

enum VstProcessLevels
{
//-------------------------------------------------------------------------------------------------------
kVstProcessLevelUnknown = 0, ///< not supported by Host
kVstProcessLevelUser, ///< 1: currently in user thread (GUI)
kVstProcessLevelRealtime, ///< 2: currently in audio thread (where process is called)
kVstProcessLevelPrefetch, ///< 3: currently in 'sequencer' thread (MIDI, timer etc)
kVstProcessLevelOffline ///< 4: currently offline processing and thus in user thread
//-------------------------------------------------------------------------------------------------------
};


So, the plugin can ask the host about the current situation with regards to threads.

Xenakios
05-05-2010, 11:36 AM
Hi

Are there a way for my plugin to know when the host is rendering the project to file ? I have some settings (oversampling, etc) that I would like to change on render..

I've tried searching but couldn't find anything..

- John

Are you by the way sure that is a very good idea? Why not let the user decide on his own if he wants the plugin to run in a "extra quality mode" and thus suffer higher CPU/RAM/latency etc? I'd personally find it rather annoying if a plugin decided to render a noticeably different sound when rendering a DAW project, compared to playing it back in real time. Then on the other hand, if the change in sound quality is so subtle it won't easily be even noticed by the user, why bother with it at all?

Tale
05-05-2010, 12:33 PM
That most definitely isn't going to do anything good, it would need support from the host side. However, Steinberg's Wavelab is the only host around that has (had?) support for those.
Ok, thanks!

There is however for example this :

enum VstProcessLevels
{
//-------------------------------------------------------------------------------------------------------
kVstProcessLevelUnknown = 0, ///< not supported by Host
kVstProcessLevelUser, ///< 1: currently in user thread (GUI)
kVstProcessLevelRealtime, ///< 2: currently in audio thread (where process is called)
kVstProcessLevelPrefetch, ///< 3: currently in 'sequencer' thread (MIDI, timer etc)
kVstProcessLevelOffline ///< 4: currently offline processing and thus in user thread
//-------------------------------------------------------------------------------------------------------
};


So, the plugin can ask the host about the current situation with regards to threads.
I've already tried that, but REAPER seems to only return kVstProcessLevelUser and kVstProcessLevelRealtime.

--

Does anyone know how the REAPER option "Inform plug-ins of offline rendering state" actually informs a VST of the rendering state?

Soundbytes
05-05-2010, 02:49 PM
The problem is, I've created a separate thread to recalculate wave tables. This works great in real time, but the wave tables don't get recalculated at all when rendering offline. (...)

Ouch! In what situation does this happen? Can you give a description how to reproduce the error? I am asking because I also use a separate thread to load sample content and would like to make sure this does not happen to me as well.
BTW: in which function do you start your table calculation thread? How does the plugin behave when audio is rendered before the wave table is in place?
Does it then block the audio thread or does it just put out silence?
(or does it just read from the uninitialized table?)

Andreas

Tale
05-05-2010, 03:36 PM
Ouch! In what situation does this happen? Can you give a description how to reproduce the error? I am asking because I also use a separate thread to load sample content and would like to make sure this does not happen to me as well.
I just hold a couple of notes for a while, and meanwhile I retune a note. When I do this live it takes about 250 ms to recalculate the wave tables, but when I render at Full-speed Offline it takes about 6 seconds. (The main audio thread could probably do it in less than 20 ms, but that would interrupt the audio stream.)

If you change wave tables on the fly e.g. because of an automated parameter, then this will probably also happen to your plug-in.

BTW: in which function do you start your table calculation thread?
I create the thread in OnParamChange(), and I control it from ProcessDoubleReplacing().

How does the plugin behave when audio is rendered before the wave table is in place?
No audio is rendered before the wave tables are completely available, because when the sample rate is initialized or changes, I recalculate the wave tables in Reset(), thus in the main audio thread.

Does it then block the audio thread or does it just put out silence?
(or does it just read from the uninitialized table?)
I recalculate the wave tables one at the time. When I recalculate a wave table, I do this is a temporary buffer, so the original wave table can still be used. When a recalculated wave table is ready, the main audio thread copies it from the temporary buffer to the wave table. Even before the new wave table is in place, I already play the old wave table using the new tuning (which is why nobody but me will probably ever notice).

Soundbytes
05-05-2010, 04:17 PM
Thanks for the description. To me it looks like the issue you are describing is related to thread priority management. It seems like the offline render process has a higher priority which in turn means that the recalculation thread gets less CPU cycles.

Andreas

Tale
05-06-2010, 12:18 AM
I guess I could try to raise the thread's priority, but that would only lessen the problem. So I would rather not use the seperate thread (or perhaps wait for it) when rendering offline, because that way the wave tables get recalculated immediately.

cc_
05-06-2010, 05:35 AM
Thanks for explaining this! I've known vaguely that there was a problem somewhere in rendering, but I never quite worked out what it was before...

Anyway, in REAPER's VST preferences there is a box to "Inform plug-ins of offline rendering state", have you tried with that on?

Also I did a search of the VST mailing list, I found this (in 2006):


if (getCurrentProcessLevel() == 4)
// the host renders to disk
else
// the host is processing realtime

Please note that Cubase SX returns 0 in process(...) or processReplacing(...) when it is *not* rendering to disk.

The docs say that a host *should* return 2 but SX doesn't.


And this from Didier Dambrin in 2007:


well, in FL we do report the 'offline processing' (thread) when the project is being rendered. I don't know how many plugins check this, but I think Halion uses it to know when it's rendering.

However we only do when the user enabled it, because of the ambiguity of the "4: currently offline processing and thus in user thread" line.

Indeed, we're offline processing, but we're NOT in the user thread, so it's too risky to do it by default.

Tale
05-06-2010, 06:11 AM
Thanks a lot for the info.

I have tried the "Inform plug-ins of offline rendering state" before, but I couldn't find how it informs a VST of the rendering state. I have also tried getCurrentProcessLevel(), but that didn't seem to ever return 4. However, reading the info from the VST mailing list, it would seem that getCurrentProcessLevel() is the way to go. I will try it again.

Tale
05-06-2010, 07:24 AM
Yay! Thanks to Xenakios' and cc_'s info I have "solved the puzzle". :D

Both REAPER and FL Studio set the process level to 4 (kVstProcessLevelOffline) when rendering offline. When playing or rendering online REAPER sets it to 2 (kVstProcessLevelRealtime) and FL Studio to 0 (kVstProcessLevelUnknown?). So if you want to do things differently while rendering, simply check if the process level is 4:

int processLevel = GetHostCallback()(&mAEffect, audioMasterGetCurrentProcessLevel, 0, 0, 0, 0.0f);

if (processLevel == kVstProcessLevelOffline)
{
// Offline rendering
}
else
{
// Realtime processing
}

Soundbytes
05-07-2010, 07:45 AM
So if you want to do things differently while rendering, simply check if the process level is 4: (...)


I have to say to me this does not look like a solution to the problem but rather like an invitation for further trouble. What if another host sets the process level to 3? Maybe you are just recalculating the wave tables a bit too often.
I understand that your aim is to save CPU resources while at the same delivering highest audio quality. On the other hand how would your Oscillator behave if lets say pitch is lfo modulated ? From what I understand so far when continuous pitch modulation is applied you interpolate anyway plus the wave table is recalculated all the time. Does not look to me like any CPU resources are saved then. Instead You do a lot of table recalculations that will hardly be of any real use.
Why not then just stick with interpolation in the first place?

Andreas

Tale
05-07-2010, 09:01 AM
I have to say that does not look like a solutionn to the problem but rather like an invitation for further trouble. What if another host sets the process level to 3? Maybe you are just recalculating the wave tables a bit too often.
I understand that your aim is to save CPU ressources while at the same delivering highes audio quality. On the other hand how would your Oscillator behave if lets say pitch is lfo modulated ? From what I understand so far when continous pitch modulation is applied you interpolate anyway plus the wave table is recalculated all the time. Does not look to me like any CPU resources are saved then. Instead You do a lot of table recalculations that will hardly be of any real use.
Why not then stick with interpolation in the first place?
My aim is to deliver the highest quality possible. I use the seperate thread only to prevent pops and clicks in the real-time audio stream, not necessarily to save CPU resources.

Actually I would like to calculate only when the project first loads, so that the wave tables are optimal for the initial tuning chosen for that specific project. I don't really care about changing tunings mid-project, so interpolation would be fine here.

The problem is that some hosts will first set the default tuning (and sample rate), and after that set the tuning for the project. In that case I would like to calculate the wave tables only for the 2nd tuning setting, but how would my plug-in know to wait for this 2nd tuning setting?

Same problem, different angle: While you're tuning in real-time there would be no need to recalculate the wave tables. But once you're done tuning the wave tables should be recalculated. How would my plug-in know you're done tuning?

Thank you for feedback BTW. The bottom line: I guess you are right, and I need to come up with something that gives me a better balance between quality and performance.

cc_
05-07-2010, 09:10 AM
In general though I think there is a need to know whether you are rendering or not.

For instance, if you are streaming samples from disk you will have a seperate disk reading thread, in the rare event that the disk read is not ready in the normal case you do not want to hold up the audio thread and ruin someone's recording.

But in the rendering case the disk read will usually not be ready, and you always want to wait for it to complete.

Tale
05-11-2010, 02:36 AM
[Off topic] BTW, here what I think I'll do: I will only recalculate wave tables when tuning hasn't changed for 100 ms. That way I will have no (unnecessary) recalculations when a sine wave LFO is automating the tuning. When retuning real-time by hand there will be a 100 ms delay before starting to recalculate, which is no big deal. I will also add parameter to disable recaclulating altogether, for the rare case where you automate the tuning using e.g. a very slow square wave LFO.

For rendering I still think it's alright to check for process level 4. If the host does not provide process levels, then the worst that can happen is that the wave tables don't get recalculated. Such a host may well have other rendering options (e.g. real-time bouncing) that will allow the recalculating thread to do its job.

onqel
04-24-2013, 02:26 PM
I'm revisiting this one again..
I implemented the check for kVstProcessLevelOffline in the Reset() procedure, but it seems like Reaper (on OSX at least) informs the plugin that is has the kVstProcessLevelOffline state on it's first reset-call.. (the first time you load your plugin..) when you hit play it returns to realtime render state and stays there until you do a offline-render..
Should I just do the check in the process-thread instead if this "bug" is a standard on all hosts ?