Old 08-25-2018, 06:13 AM   #1
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default OSC value feedback

I'm experimenting with OSC control of Reaper and an important part is the feedback from Reaper. For the most part this goes far beyond anything possible with the Mackie MCU or HUI protocols but I ran into something where something is missing that I took for granted. It concerns effect paramater feedback, especially strings.
For example the delay time of UAD Cooper Time Cube plugin is not sent as a string value (e.g. "375 ms") but as a string representation of a float:
Code:
/fxparam/10/name		String  = : RateB
/fxparam/10/value/str		String  = : 0.5200
/fxparam/10/value		Float   = : 0.52
The correct string value should be available from the plugin as both Logic and Cubase send it to a MCU. When in sync mode the timing devisor is shown in the controller.

Is there something I'm missing? Is this something I can solve myself?

In other cases there are real string values available:
Code:
/fxparam/1/name		String  = : Program
/fxparam/1/value/str		String  = : LgHall B
/fxparam/1/value		Float   = : 0.25
...
/fxparam/22/value/str		String  = : 15 kHz
/fxparam/22/value		Float   = : 0.17
...
What is different about delay times (I checked several delay type plugins) that these are displayed as a float?
Gerrit is offline   Reply With Quote
Old 08-25-2018, 10:39 AM   #2
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Why do you think Reaper would know that string ? (OK, you did say "Logic and Cubase" )

AFAIK, VST parameters usually are float values 0...1 (similar as usually done with OSC.)

You can see all available VST parameters in the Window Reaper surrounds the VST GUI with. Here Param -> FX Parameter List -> any of the submenus.

-Michael
mschnell is offline   Reply With Quote
Old 08-25-2018, 10:57 AM   #3
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
Why do you think Reaper would know that string ? (OK, you did say "Logic and Cubase" )

AFAIK, VST parameters usually are float values 0...1 (similar as usually done with OSC.)

You can see all available VST parameters in the Window Reaper surrounds the VST GUI with. Here Param -> FX Parameter List -> any of the submenus.

-Michael
Because sometimes Reaper sends values as strings:
Code:
/fxparam/5/name		String  = : Ch1LoFreq
/fxparam/5/value/str		String  = : 150 Hz
/fxparam/5/value		Float   = : 0.50
Moving the plugin knob with the mouse:
Code:
/fxparam/5/value/str		String  = : 100 Hz
/fxparam/5/value		Float   = : 0.40
Receiving OSC Bundle...
/track/7/fx/1/fxparam/5/value		Float   = : 0.30
/fxparam/5/value/str		String  = : 68 Hz
/fxparam/5/value		Float   = : 0.30
Receiving OSC Bundle...
/track/7/fx/1/fxparam/5/value		Float   = : 0.20
/fxparam/5/value/str		String  = : 47 Hz
/fxparam/5/value		Float   = : 0.20
Receiving OSC Bundle...
/track/7/fx/1/fxparam/5/value		Float   = : 0.10
/fxparam/5/value/str		String  = : 33 Hz
/fxparam/5/value		Float   = : 0.10
Receiving OSC Bundle...
/track/7/fx/1/fxparam/5/value		Float   = : 0.00
/fxparam/5/value/str		String  = : 22 Hz
/fxparam/5/value		Float   = : 0.00
The filter frequency is sent as a string perfect for display below a knob. Where do these strings come from?
Gerrit is offline   Reply With Quote
Old 08-25-2018, 11:13 AM   #4
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

I noticed that in parameter view there are two display types:
parameterview.png
A dropdown box and a slider. It seems that the dropdowns are sent as strings. Where is it determined what type a parameter should be?
Gerrit is offline   Reply With Quote
Old 08-25-2018, 11:30 AM   #5
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

I did not see a dropdown type parameter, yet.

Anyway, I suppose the VST decides which type of parameter view is to be used.

-Michael
mschnell is offline   Reply With Quote
Old 08-25-2018, 12:15 PM   #6
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
I did not see a dropdown type parameter, yet.

Anyway, I suppose the VST decides which type of parameter view is to be used.

-Michael
It has to be something in Reaper because the same plugin offers strings in Logic
As an example, here's the paramater view for the UAD EP-34 tape echo plugin in Reaper:
ep34-reaper.png
The same plugin in Logic as parameter view:
ep34-logic.png
In Logic the delay time is available in ms and several other parameters are also available in more readable values as strings. It's the same plugin. The same strings should be available to Reaper for use.
Gerrit is offline   Reply With Quote
Old 08-25-2018, 01:34 PM   #7
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

I suppose from some VST interface specification Logic guesses or knows that it should add a time unit to the display of the parameter.

I don't suppose that for such a typical numeric parameter the VST interface passes a string.

This should be decidable by taking a look at the VST (2 or 3) specification.

-Michael

Last edited by mschnell; 08-28-2018 at 07:52 AM.
mschnell is offline   Reply With Quote
Old 08-28-2018, 12:34 AM   #8
azslow3
Human being with feelings
 
Join Date: Nov 2017
Location: Heidelberg, Germany
Posts: 797
Default

Quote:
Originally Posted by Gerrit View Post
In Logic the delay time is available in ms and several other parameters are also available in more readable values as strings. It's the same plugin. The same strings should be available to Reaper for use.
In general, VST itself defines the labels. So check that you really work with exactly the same plug-in, I mean VST2/VST3 and the version. Many plug-ins are traditionally buggy in that part.
azslow3 is offline   Reply With Quote
Old 08-28-2018, 01:59 AM   #9
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by azslow3 View Post
In general, VST itself defines the labels. So check that you really work with exactly the same plug-in, I mean VST2/VST3 and the version. Many plug-ins are traditionally buggy in that part.
It's definitely Reaper that is at fault here. And it's not just because Cubase also shows the correct string values:
ep34-cubase.png

Relevant quotes from the VST3 specification:
Code:
The controller must support the conversion to a string for any exported parameter. 
The conversion method Steinberg::Vst::IEditController::getParamStringByValue
must provide a result for any possible normalized parameter value. 

Parameter values are always transmitted in a normalized representation [0.0, 1.0].
So there should always be a string representation available:

Code:
Although values are transmitted in a normalized format, the host
needs to know some details of the parameter's displayed GUI representation.
When editing automation data for example, the host must know the nature
of a parameter expressed in its 'step count'
(see Steinberg::Vst::ParameterInfo::stepCount). 

Step count semantics :
0 : A continuous parameter. Any normalized value has an exact mapping (0 = there are no steps between the values)
1 : A discrete parameter with 2 states like [on/off] [yes/no] etc. (1 = there is one step between these states)
2 : A discrete parameter with 3 states [0,1,2] or [3,5,7] (2 = there are two steps between these states)
3 : etc...
So it seems that Reaper does not send the string (but the normalised value) if the stepcount of the parameter is 0.

The vst3 parameter properties:
Code:
ParamID id
unique identifier of this parameter (named tag too)

String128 title
parameter title (e.g. "Volume")

String128 shortTitle
parameter shortTitle (e.g. "Vol")

String128 units
parameter unit (e.g. "dB")

int32 stepCount
number of discrete steps (0: continuous, 1: toggle, discrete value otherwise (corresponding to max - min, for example: 127 for a min = 0 and a max = 127) - see vst3parameterIntro)

ParamValue defaultNormalizedValue
default normalized value 0,1

UnitID unitId
id of unit this parameter belongs to (see VST 3 Units)

int32 flags
ParameterFlags (see below)
The unit (dB,Hz) is available as a property. Here's an example of a eq plugin parameter view showing the units are retrieved:
RedEqParamter.png
So Reaper can retrieve the unit for the parameter. Notice that value is displayed in normalised format thus making the combination of value and unit invalid.
For this plugin the normalised representation is sent in the string:
Code:
/fxparam/1/value/str		String  = : 0.1440
/fxparam/1/value		Float   = : 0.14
In case of the ReaDelay the correct values are shown in the parameter view:
ReDelay.png
and the string value is sent over OSC but without the unit:
Code:
/fxparam/4/value/str		String  = : 220.0
/fxparam/4/value		Float   = : 0.02
The ReaEQ does send the string value with the unit appended:
Code:
/fxparam/1/value/str		String  = : 619.3Hz
/fxparam/1/value		Float   = : 0.40
/fxeq/loshelf/freq/str		String  = : 619.3Hz
/fxeq/loshelf/freq		Float   = : 0.40
But if the plugin is selected for editing by the controller and Reaper sends the settings of the plugin the unit is missing:
Code:
Receiving OSC Bundle...
/fx/name		String  = : ReaEQ (Cockos)
/fx/number/str		String  = : 4
/fxparam/1/name		String  = : Freq-Low Shelf
/fxparam/1/value/str		String  = : 623.3
/fxparam/1/value		Float   = : 0.40
/fxparam/2/name		String  = : Gain-Low Shelf
/fxparam/2/value/str		String  = : -1.6
/fxparam/2/value		Float   = : 0.41
/fxparam/3/name		String  = : Q-Low Shelf
/fxparam/3/value/str		String  = : 2.12
/fxparam/3/value		Float   = : 0.53
Just to make this clear, the problems is with parameters with stepcount=0 (continuous), parameters that have a number of discrete steps are displayed and sent correctly. For example the frequency setting of the Manley Massive Passive is stepped, this is shown in the parameter view as a dropdown list:
massivepassive.png
And the values sent are the string values with the unit appended:
Code:
/fxparam/5/value/str		String  = : 68 Hz
/fxparam/5/value		Float   = : 0.30
At the very least the way continuous parameters are handled is inconsistent but I consider this a bug as it seriously diminishes the value of the feedback and in the case of the RedEq the information displayed in the parameter view is just wrong (all frequencies range from 0 to 1 Hz).
The way it is now OSC is of limited value for plugin control feedback whereas it would be pretty much perfect if the string values with the unit appended would be sent.
Gerrit is offline   Reply With Quote
Old 08-28-2018, 07:57 AM   #10
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

OK, so any host should be able to display these parameters including a decent unit, and converted to a decent range. And it might be counted as a shortcoming, if it does not do so.

But that does not imply anything about how they are transferred via OSC.

On the contrary,the usual way to transfer data via OSC is normalized to a real 0...1, i.e. using the raw normalizes value of the VST parameter is perfectly correct.

-Michael
mschnell is offline   Reply With Quote
Old 08-28-2018, 08:17 AM   #11
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
OK, so any host should be able to display these parameters including a decent unit, and converted to a decent range. And it might be counted as a shortcoming, if it does not do so.

But that does not imply anything about how they are transferred via OSC.

On the contrary,the usual way to transfer data via OSC is normalized to a real 0...1, i.e. using the raw normalizes value of the VST parameter is perfectly correct.

-Michael
Again, here's what the ReaEQ is ending over OSC:
Code:
Receiving OSC Bundle...
/fxparam/1/value/str		String  = : 703.3Hz
/fxparam/1/value		Float   = : 0.42
/fxeq/loshelf/freq/str		String  = : 703.3Hz
/fxeq/loshelf/freq		Float   = : 0.42
This is how it should be. The normalised value is sent as a float in /fxparam/1/value. /fxparam/1/value/str contains the string value that is intended for presentation on a display. It does not make any sense at all to send the normalised value as a string. Not only would that be redundant but the normalised value has no meaning to the user.
Why are the parameters of other plugins not handled like this?
Gerrit is offline   Reply With Quote
Old 08-28-2018, 02:21 PM   #12
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Quote:
Originally Posted by Gerrit View Post
Again, here's what the ReaEQ is sending over OSC:
I don't understand. ReaEQ does not feature an OSC interface at all.

But I suppose I do understand that Reaper sends ReaEQ parameters in a very different way than it does with certain parameters of certain other plugins.

Wild guess: Maybe the OSC definition file Reaper reads provides some additional information for ReaEQ ?

In fact it does:

Code:
Default.ReaperOSC: 


FX_EQ_BYPASS b/fxeq/bypass b/track/@/fxeq/bypass
FX_EQ_OPEN_UI b/fxeq/openui b/track/@/fxeq/openui

FX_EQ_PRESET s/fxeq/preset s/track/@/fxeq/preset
FX_EQ_PREV_PRESET s/fxeq/preset- s/track/@/fxeq/preset-
FX_EQ_NEXT_PRESET s/fxeq/preset+ s/track/@/fxeq/preset+

FX_EQ_MASTER_GAIN n/fxeq/gain n/track/@/fxeq/gain 
FX_EQ_MASTER_GAIN f/fxeq/gain/db f/track/@/fxeq/gain/db s/fxeq/gain/str
FX_EQ_WETDRY n/fxeq/wetdry n/track/@/fxeq/wetdry
FX_EQ_WETDRY s/fxeq/wetdry/str s/track/@/fxeq/wetdry/str

FX_EQ_HIPASS_NAME s/fxeq/hipass/str
FX_EQ_HIPASS_FREQ n/fxeq/hipass/freq n/track/@/fxeq/hipass/freq
FX_EQ_HIPASS_FREQ f/fxeq/hipass/freq/hz f/track/@/fxeq/hipass/freq/hz
FX_EQ_HIPASS_FREQ s/fxeq/hipass/freq/str s/track/@/fxeq/hipass/freq/str
FX_EQ_HIPASS_Q n/fxeq/hipass/q n/track/@/fxeq/hipass/q
FX_EQ_HIPASS_Q f/fxeq/hipass/q/oct f/track/@/fxeq/hipass/q/oct
FX_EQ_HIPASS_Q s/fxeq/hipass/q/str s/track/@/fxeq/hipass/q/str

FX_EQ_LOSHELF_NAME s/fxeq/lopass/str
FX_EQ_LOSHELF_FREQ n/fxeq/loshelf/freq n/track/@/fxeq/loshelf/freq
FX_EQ_LOSHELF_FREQ f/fxeq/loshelf/freq/hz f/track/@/fxeq/loshelf/freq/hz
FX_EQ_LOSHELF_FREQ s/fxeq/loshelf/freq/str s/track/@/fxeq/loshelf/freq/str
FX_EQ_LOSHELF_GAIN n/fxeq/loshelf/gain n/track/@/fxeq/loshelf/gain
FX_EQ_LOSHELF_GAIN f/fxeq/loshelf/gain/db f/track/@/fxeq/loshelf/gain/db
FX_EQ_LOSHELF_GAIN s/fxeq/loshelf/gain/str s/track/@/fxeq/loshelf/gain/str
FX_EQ_LOSHELF_Q n/fxeq/loshelf/q n/track/@/fxeq/loshelf/q
FX_EQ_LOSHELF_Q f/fxeq/loshelf/q/oct f/track/@/fxeq/loshelf/q/oct
FX_EQ_LOSHELF_Q s/fxeq/loshelf/q/str s/track/@/fxeq/loshelf/q/str

FX_EQ_BAND_NAME s/fxeq/band/str
FX_EQ_BAND_FREQ n/fxeq/band/@/freq n/track/@/fxeq/band/@/freq
FX_EQ_BAND_FREQ f/fxeq/band/@/freq/hz f/track/@/fxeq/band/@/freq/hz
FX_EQ_BAND_FREQ s/fxeq/band/@/freq/str s/track/@/fxeq/band/@/freq/str
FX_EQ_BAND_GAIN n/fxeq/band/@/gain n/track/@/fxeq/band/@/gain
FX_EQ_BAND_GAIN f/fxeq/band/@/gain/db f/track/@/fxeq/band/@/gain/db
FX_EQ_BAND_GAIN s/fxeq/band/@/gain/str s/track/@/fxeq/band/@/gain/str
FX_EQ_BAND_Q n/fxeq/band/@/q n/track/@/fxeq/band/@/q
FX_EQ_BAND_Q f/fxeq/band/@/q/oct f/track/@/fxeq/band/@/q/oct
FX_EQ_BAND_Q s/fxeq/band/@/q/str s/track/@/fxeq/band/@/q/str

FX_EQ_NOTCH_NAME s/fxeq/notch/str
FX_EQ_NOTCH_FREQ n/fxeq/notch/freq n/track/@/fxeq/notch/freq
FX_EQ_NOTCH_FREQ f/fxeq/notch/freq/hz f/track/@/fxeq/notch/freq/hz
FX_EQ_NOTCH_FREQ s/fxeq/notch/freq/str s/track/@/fxeq/notch/freq/str
FX_EQ_NOTCH_GAIN n/fxeq/notch/gain n/track/@/fxeq/notch/gain
FX_EQ_NOTCH_GAIN f/fxeq/notch/gain/db f/track/@/fxeq/notch/gain/db
FX_EQ_NOTCH_GAIN s/fxeq/notch/gain/str s/track/@/fxeq/notch/gain/str
FX_EQ_NOTCH_Q n/fxeq/notch/q n/track/@/fxeq/notch/q
FX_EQ_NOTCH_Q f/fxeq/notch/q/oct f/track/@/fxeq/notch/q/oct
FX_EQ_NOTCH_Q s/fxeq/notch/q/str s/track/@/fxeq/notch/q/str

FX_EQ_HISHELF_NAME s/fxeq/hishelf/str
FX_EQ_HISHELF_FREQ n/fxeq/hishelf/freq n/track/@/fxeq/hishelf/freq
FX_EQ_HISHELF_FREQ f/fxeq/hishelf/freq/hz f/track/@/fxeq/hishelf/freq/hz
FX_EQ_HISHELF_FREQ s/fxeq/hishelf/freq/str s/track/@/fxeq/hishelf/freq/str
FX_EQ_HISHELF_GAIN n/fxeq/hishelf/gain n/track/@/fxeq/hishelf/gain
FX_EQ_HISHELF_GAIN f/fxeq/hishelf/gain/sb f/track/@/fxeq/hishelf/gain/db
FX_EQ_HISHELF_GAIN s/fxeq/hishelf/gain/str s/track/@/fxeq/hishelf/gain/str
FX_EQ_HISHELF_Q n/fxeq/hishelf/q n/track/@/fxeq/hishelf/q
FX_EQ_HISHELF_Q f/fxeq/hishelf/q/oct f/track/@/fxeq/hishelf/q/oct
FX_EQ_HISHELF_Q s/fxeq/hishelf/q/str s/track/@/fxeq/hishelf/q/str

FX_EQ_LOPASS_NAME s/fxeq/loshelf/str
FX_EQ_LOPASS_FREQ n/fxeq/lopass/freq n/track/@/fxeq/lopass/freq
FX_EQ_LOPASS_FREQ f/fxeq/lopass/freq/hz f/track/@/fxeq/lopass/freq/hz
FX_EQ_LOPASS_FREQ s/fxeq/lopass/freq/str s/track/@/fxeq/lopass/freq/str
FX_EQ_LOPASS_Q n/fxeq/lopass/q n/track/@/fxeq/lopass/q
FX_EQ_LOPASS_Q f/fxeq/lopass/q/oct f/track/@/fxeq/lopass/q/oct
FX_EQ_LOPASS_Q s/fxeq/lopass/q/str s/track/@/fxeq/lopass/q/str
Hence I suppose you could enhance that file for having Reaper handle your plugins in the way you want it to. (Don't ask me about the format of that file .. )

-Michael

Last edited by mschnell; 08-28-2018 at 02:32 PM.
mschnell is offline   Reply With Quote
Old 08-30-2018, 06:17 AM   #13
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Did this help ?

-Michael
mschnell is offline   Reply With Quote
Old 08-30-2018, 09:42 AM   #14
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
Did this help ?

-Michael
Thank you for trying to help but alas, this didn't provide a solution.

Here are two examples that demonstrate the issue:

In the case of the Pultec EQ plugin everything is fine.
Screenshot of the parameter view: PultecEQ.png
There are just a few parameters and they are all presented as dropdown lists.
When then plugin is selected, either in Reaper with the OSC controller, the following is sent by Reaper:
Code:
Receiving OSC Bundle...
/fx/name			String  = : Pultec HLF-3C
/fx/number/str			String  = : 1
/fx/preset			String  = : DI-Underwater
/fx/openui			Float   = : 1.00
/fxparam/1/name			String  = : Low Cut
/fxparam/1/value/str		String  = : Off
/fxparam/1/value		Float   = : 0.00
/fxparam/2/name			String  = : High Cut
/fxparam/2/value/str		String  = : 1.5 KCS
/fxparam/3/name			String  = : Enable
/fxparam/3/value/str		String  = : In
/fxparam/3/value		Float   = : 1.00
/fxparam/4/name			String  = : Bypass
/fxparam/4/value/str		String  = : normal
/fxparam/4/value		Float   = : 0.00
/fxparam/5/name			String  = : Wet
/fxparam/5/value/str		String  = : 100
/fxparam/5/value		Float   = : 1.00
Perfect! All I need to know about the plugin and the settings. BTW. the name is the alias name I entered for this plugin, excellent.

The EP-34 tape delay contains sliders in the parameter view: EP-34.png
The value displayed next to the slider is the normalised value. This should be the formatted string value which includes the unit.
On selection the following is sent:
Code:
Receiving OSC Bundle...
/fx/name			String  = : EP-34 Tape Echo
/fx/number/str			String  = : 2
/fx/preset			String  = : Setzer Slapback
/fx/openui			Float   = : 0.00
/fxparam/1/name			String  = : Delay
/fxparam/1/value/str		String  = : 0.5000
/fxparam/1/value		Float   = : 0.50
/fxparam/2/name			String  = : Repeats
/fxparam/2/value/str		String  = : 0.0000
/fxparam/3/name			String  = : Echo Vol
/fxparam/3/value/str		String  = : 0.6156
/fxparam/3/value		Float   = : 0.62
/fxparam/4/name			String  = : Rec Vol
/fxparam/4/value/str		String  = : 0.0816
/fxparam/4/value		Float   = : 0.08
/fxparam/5/name			String  = : Treble
/fxparam/5/value/str		String  = : 0.5000
/fxparam/5/value		Float   = : 0.50
/fxparam/6/name			String  = : Bass
/fxparam/6/value/str		String  = : 0.5000
/fxparam/6/value		Float   = : 0.50
/fxparam/7/name			String  = : Pan
/fxparam/7/value/str		String  = : 0.9250
/fxparam/7/value		Float   = : 0.92
/fxparam/8/name			String  = : Input
/fxparam/8/value/str		String  = : HI
/fxparam/8/value		Float   = : 1.00
Receiving OSC Bundle...
/fxparam/9/name			String  = : Tension
/fxparam/9/value/str		String  = : LO
/fxparam/10/name		String  = : Send
/fxparam/10/value/str		String  = : ON
/fxparam/10/value		Float   = : 1.00
/fxparam/11/name		String  = : TempSync
/fxparam/11/value/str		String  = : ON
/fxparam/11/value		Float   = : 1.00
/fxparam/12/name		String  = : WetSolo
/fxparam/12/value/str		String  = : OFF
/fxparam/13/name		String  = : Power
/fxparam/13/value/str		String  = : ON
/fxparam/13/value		Float   = : 1.00
/fxparam/14/name		String  = : Bypass
/fxparam/14/value/str		String  = : normal
/fxparam/15/name		String  = : Wet
/fxparam/15/value/str		String  = : 100
/fxparam/15/value		Float   = : 1.00
In all cases where the parameter is displayed as a slider in the parameter view the OSC string value contains the normalised value in stead of the formatted string representation. All parameters that are displayed as dropdown lists in the parameter view correctly contain the formatted string in the OSC string.
It would be great if someone from the Reaper developer team could comment on this. It seems to me that the required change is relatively simple and it would make OSC perfect for creating advanced (extensive feedback) plugin controllers.

Here's a link to the thread about my OSC test setup on the PJRC Teensy forum: OSC digital audio workstation controller (Reaper)

The sketch has changed somewhat, here's the version I used for these examples:
Code:
// OSC  test code

#include <Bounce.h>
#include <Encoder.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <OSCBundle.h>

// ***** BUTTONS *****
#define BUTTON_ONE_PIN 20
#define BUTTON_TWO_PIN 21

int             debounceTime=5;
Bounce          buttonOne = Bounce(BUTTON_ONE_PIN,debounceTime);
Bounce          buttonTwo = Bounce(BUTTON_TWO_PIN,debounceTime);
elapsedMicros   sinceButtonCheck;                                   // timer for button check
unsigned int    buttonCheckInterval=1000;                           // interval in microseconds for checking buttons
// ***** END BUTTONS *****

// ***** ENCODERS *****
Encoder encoderOne(18,19);
Encoder encoderTwo(22,23);
long    currentEncoderOneValue=0;
long    currentEncoderTwoValue=0;
// ***** END  ENCODERS *****

#define NUM_OF_PARAMETERS 16    // number of effect/instrument parameters in parameter bank

// you can find this written on the board of some Arduino Ethernets or shields; I couldn't find it but it does not matter :-)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 

//ports
const unsigned int serverPort  = 8000;     // Reaper Out port
const unsigned int destPort    = 9000;     // Reaper IN port

//Create UDP message object
EthernetUDP Udp;

//the Teensy's IP
IPAddress ip(192, 168, 178, 177);
//destination IP
IPAddress outIp(192,168,178,38);

void setup(){
  Serial.begin(115200); 
  Serial.println("OSC test");

  pinMode(BUTTON_ONE_PIN, INPUT_PULLUP);
  pinMode(BUTTON_TWO_PIN, INPUT_PULLUP);
  //setup ethernet part
  Ethernet.begin(mac,ip);
  Udp.begin(serverPort);
}

void loop(){
  //process received messages
  //OSCMsgReceive();
  //OSCBundleReceive();
  OSCReceive();
  // check elapsedMicros and millis timers
  if (sinceButtonCheck >=buttonCheckInterval) {
    sinceButtonCheck = sinceButtonCheck - buttonCheckInterval;
    handleButtons();
    handleEncoders();
  }  
}

void OSCReceive(){
  int size;
  if( (size = Udp.parsePacket())>0) {
    byte udpData[size];
    for (int i=0;i<size;i++) udpData[i]=Udp.read();
    // if data begins with # it is a bundle
    if (udpData[0]==35){
      OSCBundle   bundleIN;
      bundleIN.fill(udpData,size);
      if(!bundleIN.hasError()) {
        Serial.println("Receiving OSC Bundle...");
        bundleIN.route("/track", showMessage);
        bundleIN.route("/fx", showMessage);
        bundleIN.route("/fxparam", showMessage);
        bundleIN.route("/fxeq", showMessage);
        bundleIN.route("/fxinstparam", showMessage);
      }
    }
    // if data begins with / it is a message
    else if (udpData[0]==47){
      OSCMessage  msgIN;
      msgIN.fill(udpData,size);
      if(!msgIN.hasError()){
        Serial.println("Receiving OSC Message...");
        msgIN.route("/track",showMessage);
        msgIN.route("/fx",showMessage);
        msgIN.route("/fxparam",showMessage);
        msgIN.route("/fxeq",showMessage);
        msgIN.route("/fxinstparam",showMessage);
        //msgIN.route("/beat",showMessage);
      }
    }
  }
}

void showMessage(OSCMessage &msg, int addrOffset){
  char adresStr[48];    
  msg.getAddress(adresStr);
  Serial.print(adresStr);
  Serial.print("\t\t");
  if (msg.isInt(0)){        
    Serial.print("Int     = : ");
    Serial.println(msg.getInt(0));
  } 
  else if(msg.isFloat(0)){       
    Serial.print("Float   = : ");
    Serial.println(msg.getFloat(0));
  } 
  else if(msg.isBoolean(0)){       
    Serial.print("Boolean = : ");
    Serial.println(msg.isBoolean(0));
  }
  else if(msg.isString(0)){   
    char str[48]    ;
    msg.getString(0,str,48);
    Serial.print("String  = : ");
    Serial.println(str);
  }
}

void displayFxParameter(OSCMessage &msg, int addrOffset ){
  //iterate through all the analog pins
  for(int i = 0; i < NUM_OF_PARAMETERS; i++){
    //match against the index number strings
    int indexMatched = msg.match(numToOSCAddress(i), addrOffset);
    if (indexMatched){
      
    }
  }
}

//converts (parameter, track) index to an osc address
char * numToOSCAddress( int index){
    static char s[10];
    int i = 9;
  
    s[i--]= '\0';
  do
    {
    s[i] = "0123456789"[index % 10];
                --i;
                index /= 10;
    }
    while(index && i);
    s[i] = '/';
    return &s[i];
}

void handleButtons(){
  if (buttonOne.update()) {
    if (buttonOne.fallingEdge()) {
     Serial.println("Button One pushed");
       
     OSCMessage msgOUT("/device/fx/-");
     msgOUT.add(1.0);
    Udp.beginPacket(outIp, destPort);
    msgOUT.send(Udp); // send the bytes
    Udp.endPacket(); // mark the end of the OSC Packet
    msgOUT.empty(); // free space occupied by message
    }
  }
  if (buttonTwo.update()) {
    if (buttonTwo.fallingEdge()) {
     Serial.println("Button Two pushed");
     OSCMessage msgOUT("/device/fx/+");
     msgOUT.add(1.0);
    Udp.beginPacket(outIp, destPort);
    msgOUT.send(Udp); // send the bytes
    Udp.endPacket(); // mark the end of the OSC Packet
    msgOUT.empty(); // free space occupied by message
    }
  }
}

void handleEncoders(){
  // long for new encoder value
  long newEncoderValue = 0;
  // Encoder One
  newEncoderValue=encoderOne.read();
  if (newEncoderValue!=currentEncoderOneValue){
    currentEncoderOneValue=newEncoderValue;
    Serial.println(currentEncoderOneValue);
  }
  // Encoder Two
  newEncoderValue=encoderTwo.read();
  if (newEncoderValue!=currentEncoderTwoValue){
    currentEncoderTwoValue=newEncoderValue;
    Serial.println(currentEncoderTwoValue);
  }
}
Gerrit is offline   Reply With Quote
Old 08-30-2018, 02:24 PM   #15
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Did you try to modify or do a ReaperOSC file to allow Reaper do deal with the parameters of that plugin(s) in the way you want it to ?

-Michael
mschnell is offline   Reply With Quote
Old 08-30-2018, 03:05 PM   #16
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
Did you try to modify or do a ReaperOSC file to allow Reaper do deal with the parameters of that plugin(s) in the way you want it to ?

-Michael
I added this (conform the example in the default definition):
Code:
FX_PARAM_VALUE f/fxparam/@/value/raw  f/fx/@/fxparam/@/value/raw
to get the raw value but it doesn't do anything. I expected this because the default OSC configuration should contain all possible OSC paths and datatypes as it is all the documentation there is. There's nothing to add, you can only leave out stuff you don't need and change the controller properties (track count and such).
Anyway, this is besides the point. The OSC string should contain a formatted representation (including the unit) of the plugin parameter value irrespective of wether the parameter is discrete or continuous. No changes or additions to any configuration should be needed for this.
Gerrit is offline   Reply With Quote
Old 08-30-2018, 09:31 PM   #17
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

I understand that the file tells Reaper how to handle a dedicated (VST- parameter -) value (according to a kind of parameter specification such as FX_EQ_BYPASS -> binary, FX_EQ_NOTCH_NAME -> string or FX_EQ_MASTER_GAIN -> continuous).

In some way such identification needs to come from the plugin. how else should Reaper know that a parameter it really is e.g. a " FX_EQ_MASTER_GAIN " ?

Hence if you want to use some new VST with some new parameter identification (whatever this is) same would need to be notified in the ReaperOSC to allow Reaper to use it in the dedicated way.

But I never did any work in that area, and especially I don't have any idea how the said parameter identification options are transferred from the plugin to the host.

Maybe you want to ask in the "developers" subforum.

-Michael

Last edited by mschnell; 08-30-2018 at 10:01 PM.
mschnell is offline   Reply With Quote
Old 08-30-2018, 11:56 PM   #18
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
I understand that the file tells Reaper how to handle a dedicated (VST- parameter -) value (according to a kind of parameter specification such as FX_EQ_BYPASS -> binary, FX_EQ_NOTCH_NAME -> string or FX_EQ_MASTER_GAIN -> continuous).

In some way such identification needs to come from the plugin. how else should Reaper know that a parameter it really is e.g. a " FX_EQ_MASTER_GAIN " ?

Hence if you want to use some new VST with some new parameter identification (whatever this is) same would need to be notified in the ReaperOSC to allow Reaper to use it in the dedicated way.

But I never did any work in that area, and especially I don't have any idea how the said parameter identification options are transferred from the plugin to the host.

Maybe you want to ask in the "developers" subforum.

-Michael
The ReaEQ is a special case for which Reaper provides detailed OSC control and feedback, parameters are explicitly named in the OSC adres.
The generic plugin handling is completely covered by this part:
Code:
FX_NAME s/fx/name s/fx/@/name s/track/@/fx/@/name
FX_NUMBER s/fx/number/str s/fx/@/number/str s/track/@/fx/@/number/str
FX_BYPASS b/fx/bypass b/fx/@/bypass b/track/@/fx/@/bypass 
FX_OPEN_UI b/fx/openui b/fx/@/openui b/track/@/fx/@/openui

FX_PRESET s/fx/preset s/fx/@/preset s/track/@/fx/@/preset
FX_PREV_PRESET t/fx/preset- t/fx/@/preset- t/track/@/fx/@/preset-
FX_NEXT_PRESET t/fx/preset+ t/fx/@/preset+ t/track/@/fx/@/preset+

FX_PARAM_NAME s/fxparam/@/name s/fx/@/fxparam/@/name
FX_WETDRY n/fx/wetdry n/fx/@/wetdry n/track/@/fx/@/wetdry
FX_WETDRY s/fx/wetdry/str s/fx/@/wetdry/str s/track/@/fx/@/wetdry/str
FX_PARAM_VALUE n/fxparam/@/value n/fx/@/fxparam/@/value
FX_PARAM_VALUE s/fxparam/@/value/str s/fx/@/fxparam/@/value/str
Based on the DEVICE_FX_PARAM_COUNT setting Reaper will send the specified number of plugin parameters, 16 in my case. The parameters are not explicitly identified but indexed. So if you don't know the index number you cannot directly adres a specific parameter but because Reaper also sends the name indexed the name can be displayed next to the knob/slider on the controller so the user knows which knob will change a certain parameter. Using this approach the controller doesn't have to have any knowledge of the plugin (parameter OSC adres) thus providing universal plugin support.

Your suggestion to put is on the developer subforum seems like a good idea. Now that I've investigated the matter in more detail I can present the issue more clearly with a couple of examples.
Gerrit is offline   Reply With Quote
Old 08-31-2018, 05:59 AM   #19
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Quote:
Originally Posted by Gerrit View Post
The ReaEQ is a special case for which Reaper provides detailed OSC control and feedback, parameters are explicitly named in the OSC adres.
Obviously.

But OTOH, why should Reaper detect ReaEQ and handle same differently from any other effect in a hard coded way ?

To me it seems more likely that it would be possible to do dedicated section in the *.ReaperOSC file to detect and handle other (3rd party) plugins.

But as said all this is just guessing from a programmer's POV, but not driven by any experience. You would need to ask some expert to decide.

-Michael

Last edited by mschnell; 08-31-2018 at 01:17 PM.
mschnell is offline   Reply With Quote
Old 08-31-2018, 07:12 AM   #20
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by mschnell View Post
Obviously.

But OTOH, why should Reaper detect ReaEQ and handle same differently from any other effect in a hard coded way ?

To me it seems more likely that it would be possible to do dedicated section in the *.ReaperOSC file to detect and handle other (3rd party) plugins.

But as said all this is just guessing from a programmer's POV, but no9t driven by any experience. You would need to ask some expert to decide.

-Michael
Indeed, there's not really a compelling argument for handling the ReaEQ any different from all other plugins. I guess the reasoning is that an EQ is an integral part of a mixing desk and that's why it has specialised OSC paths for the parameters. The problem is that once this is actually used someone will say that the really nice big desks all have a gate and compressor per channel, where does it end?
IMO there's no need for any specialised OSC messages. I'd much rather have access to all the parameter info exposed by the plugin through a generic message. For example an OSC message like this:

Code:
/fx/@/getparameterinfo
That would call for each plugin parameter:
Code:
virtual tresult getParameterInfo ( int32 paramIndex, ParameterInfo & info )		

Gets for a given index the parameter information.
and return all available info for all parameters. The plugin and each parameter all have unique 32bit ids, it would be great if these could be returned. With these ids it's possible to control any plugin in the same detailed manner that is now only available for the ReaEQ.
The method example is from the VST3 specification, I don't know the other plugin specs but it seems reasonable to assume that other specs (i.e. AU) have similar methods.
The cherry on top would be sending metering data from a plugin over OSC just like VU meter data. I don't actually know if this is exposed by a plugin but each parameter has a readonly flag which I would expect to be used for things like meters. Controllers like the Softube Console 1 have meters on the control surface and support multiple plugins. Getting, for example, gain reduction meter data from a plugin over OSC would be absolutely fabulous. The controller would send an OSC message containing plugin and parameter id to tell Reaper that a specific parameter is a meter so Reaper can treat it as such.
Just a little dreaming on a Friday afternoon
Gerrit is offline   Reply With Quote
Old 09-01-2018, 01:03 PM   #21
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

FWIW:

-> https://www.reaper.fm/sdk/osc/osc.php :

Pattern Config Files

To use an OSC device for more than basic action shortcuts and FX parameter learn, you will need to configure either REAPER or the device to define the OSC messages that will be used for communication.

The pattern config file (.ReaperOSC) is how REAPER defines the OSC messages it understands. In order to use REAPER with any OSC device, you can either create a custom pattern config file so that REAPER sends and receives messages the OSC device understands, or configure the OSC device to send and receive messages that REAPER understands, or both.

To open the default pattern config file folder, select "open config directory" under "pattern config" in the OSC control surface settings dialog. The best way to create a new pattern config is to make a copy of the included Default.ReaperOSC file, rename the copy, and change the patterns defined in the file. Please see the extensive comments in Default.ReaperOSC for more detail about how messages are formed, and what the messages mean.

Further Exploration

For more help on OSC in REAPER, to report bugs, to request additional functionality, to share pattern config files, or just to discuss the possibilities, please use the REAPER User Forum."
mschnell is offline   Reply With Quote
Old 09-02-2018, 01:26 AM   #22
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

see -> https://forum.cockos.com/showthread....7635&page=2#50 ff
-Michael
mschnell is offline   Reply With Quote
Old 09-03-2018, 01:51 AM   #23
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

As I'm developing my own Teensy based controller I can use the OSC messages as they are defined in the default config. No changes of any kind are required for operation. However, it does make sense to comment out OSC messages you'll never use but it's not necessary.
I've gotten to the point where the initial Reaper track data dump is parsed and stored in structs like this one.
Code:
// struct containing Reaper track info & data
struct track{
  char        name[NAME_LENGTH];              // track name
  int         number;                         // track number
  char        volumeStr[VALUE_LENGTH];        // volume string    
  float       volume;                         // normalised volume
  char        panStr[VALUE_LENGTH];           // panning string    
  float       pan;                            // normalised panning
  bool        rec;                            // record arm
  bool        mute;                           // track mute
  bool        solo;                           // track solo
  bool        monitor;                        // track monitor
  TrackSend   send[NUM_OF_SENDS];             // track sends
  TrackInsert insert[NUM_OF_INSERTS];         // track effects/instrument plugins
};
typedef struct track Track;
A function displays the content on the serial monitor.
Selected track data:
Code:
SELECTED TRACK PARAMETERS
	Name		SEM
	Number		1
	Volume		-8.42dB
	Pan		C
	Record		1
	Mute		0
	Solo		0
	Monitor		0

	Send 1		Lexicon		-38.6dB		center
	Send 2		AMS		-26.1dB		center
	Send 3		Send 3		-inf dB		center
	Send 4		Send 4		-inf dB		center
	Send 5		Send 5		-inf dB		center
	Send 6		Send 6		-inf dB		center
	Send 7		Send 7		-inf dB		center
	Send 8		Send 8		-inf dB		center

	Insert 1	1	Oberheim SEM V (Arturia)
	Insert 2	0	ReaDelay (Cockos)
	Insert 3	1	Red 2 EQ
	Insert 4	1	ReaEQ (Cockos)
	Insert 5	0	
	Insert 6	0	
	Insert 7	0	
	Insert 8	0
The string representations are shown, the normalised values are present but not shown here to reduce clutter.

Parameters of the selected plugin/instrument:
Code:
SELECTED INSERT PARAMETERS
	Master Volume		0.8160
	Master Tune		        0.5000
	VCO1 Freq (fine)		0.5000
	VCO1 Freq (coarse)	0.0000
	VCO1 PW		       0.5000
	VCO1 Modulation Amount		0.4080
	VCO2 Freq (fine)		0.5000
	VCO2 Freq (coarse)	0.0000
	VCO2 PW		0.5000
	VCO2 Modulation Amount		0.5000
	VCO Hard Sync		off
	ENV1 Attack		0.0000
	ENV1 Decay		0.1000
	ENV1 Sustain		1.0000
	ENV2 Attack		0.0000
	ENV2 Decay		0.0000
Again we see the issue that this thread is about: The string does not contain the formatted string but the normalised value except for the parameter 'VCO Hard Sync' where the string is actually a formatted string.


Overview of the tracks (number, volume, pan, track name, 1st plugin name, 1st send name):
Code:
TRACK OVERVIEW
	1	-8.42dB		C	SEM		Oberheim SEM V (Arturia)		Lexicon
	2	0.00dB		C	Marshall		Big Muff		Lexicon
	3	0.00dB		C	Clean Guitar		ReaTuner		EMT Plate
	4	0.00dB		C	Synth		Pultec HLF-3C		Lexicon
	5	0.00dB		C	Lexicon		Lexicon 224		Send 1
	6	0.00dB		C	EMT Plate		EMT 140		Send 1
	7	0.00dB		C	AMS		AMS RMX16		Send 1
	8	-inf dB		C	Track 8				Send 1
	9	-inf dB		C	Track 9				Send 1
	10	-inf dB		C	Track 10				Send 1
	11	-inf dB		C	Track 11				Send 1
	12	-inf dB		C	Track 12				Send 1
	13	-inf dB		C	Track 13				Send 1
	14	-inf dB		C	Track 14				Send 1
	15	-inf dB		C	Track 15				Send 1
	16	-inf dB		C	Track 16				Send 1
Just the first send and plugin are shown here, the purpose is to check if the parsing went OK. Now that I've got the basics covered I can start testing the behaviour (what is sent when).
Gerrit is offline   Reply With Quote
Old 06-17-2019, 02:04 AM   #24
netphreak
Human being with feelings
 
Join Date: Apr 2019
Posts: 98
Default

Gerrit - thank you for sharing!

While trying to run this on an Arduino Uno, I noticed a few things that may help others trying to do the same:

There's a missing reference to the library "elapsedMillis" - download and add #include <elapsedMillis.h>.

#include <Bounce.h> should be replaced with #include <Bounce2.h>, keyword Bounce.h not working in recent release.
netphreak is offline   Reply With Quote
Old 06-17-2019, 02:07 AM   #25
netphreak
Human being with feelings
 
Join Date: Apr 2019
Posts: 98
Default

Any idea why sending /action/41743 to Reaper is not giving any output by your script?
netphreak is offline   Reply With Quote
Old 06-17-2019, 05:23 AM   #26
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by netphreak View Post
Any idea why sending /action/41743 to Reaper is not giving any output by your script?
I don't understand the question, what did you expect to happen?
This is an older thread, new developments are covered in this thread: Teensy based OSC controller for Reaper
I've nearly finished turning my MIDI controller into an OSC controller, when I'm done I will publish it on the Teensy forum and on this forum.
Gerrit is offline   Reply With Quote
Old 06-17-2019, 12:16 PM   #27
netphreak
Human being with feelings
 
Join Date: Apr 2019
Posts: 98
Default

When sending /action/41743 I expected that Reaper "Control surface: refresh all surfaces". When listening with OSC_Data_Monitor (Windows software on my computer) I can see Reaper resend all information. But when listening with Arduino, nothing is detected...
netphreak is offline   Reply With Quote
Old 06-17-2019, 12:50 PM   #28
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by netphreak View Post
When sending /action/41743 I expected that Reaper "Control surface: refresh all surfaces". When listening with OSC_Data_Monitor (Windows software on my computer) I can see Reaper resend all information. But when listening with Arduino, nothing is detected...
You said you use an Arduino Uno, how is it connected (ethernet,usb)? Do you monitor all incoming messages on the serial port?

With my Teensy 3.6 setup it works just fine, all the track and insert info is sent when the action is sent to Reaper. Very important during development, every time the code is uploaded the action is triggered on reboot and the controller receives all the track and insert info.
Gerrit is offline   Reply With Quote
Old 06-17-2019, 04:33 PM   #29
netphreak
Human being with feelings
 
Join Date: Apr 2019
Posts: 98
Default

Yes, I monitor all ports with SLIPSerial during debugging. Arduino Uno and W5500 ethernet. Ordered an Teensy 3.5. Could be because W5500 use ethernet2.h, unfortunately...
netphreak is offline   Reply With Quote
Old 01-19-2020, 11:25 AM   #30
dtsmarin
Human being with feelings
 
Join Date: Dec 2017
Posts: 21
Default

I'm having trouble with receiving the value/str when I have a "fixed" OSC address in Open Stage Control.

I need a widget that always points to track 1, fx 1, parameter, 1

fxparam/value and fxparam/name work great but I can't read the /str it only works as a 0 to 1 value.

Is it a Reaper limitation or am I doing something wrong in OSC?
dtsmarin is offline   Reply With Quote
Old 01-20-2020, 01:39 AM   #31
Gerrit
Human being with feelings
 
Join Date: Aug 2018
Location: Maastricht
Posts: 92
Default

Quote:
Originally Posted by dtsmarin View Post
I'm having trouble with receiving the value/str when I have a "fixed" OSC address in Open Stage Control.

I need a widget that always points to track 1, fx 1, parameter, 1

fxparam/value and fxparam/name work great but I can't read the /str it only works as a 0 to 1 value.

Is it a Reaper limitation or am I doing something wrong in OSC?
The problems is with Reaper, it occurs with parameters that have continuous values. It's not specifically related to OSC because the same thing happens if you put such a parameter in the track controls.
Gerrit is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:41 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.