Old 09-04-2016, 02:55 PM   #1
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default JSFX UI Library

Update 2018-02-22: New documentation, and a couple of API changes.
Update 2018-06-23: Experimental UI generator using slider definitions

I have completely rewritten the documentation, including example code and screenshots (web) or interactive demos (JSFX).

GitHub: https://github.com/geraintluff/jsfx-ui-lib

API docs on the web: https://geraintluff.github.io/jsfx-ui-lib/doc/html/

Stash: https://stash.reaper.fm/v/32955/ui-lib.zip - includes interactive demo / API docs as JSFX



-----------------------------

Update 2017-01-23:

New features: themes (default, plus black and grey), scroll-wheel support (dials/sliders)

I've started to write a getting-started guide. I would appreciate any feedback.


Original post:
Hi everyone,

I recently released a JSFX synth, and it was complex enough that I needed to build a basic framework for the UI.

I've split this UI framework out as a separate project, in case it's useful for anybody else.

GitHub: https://github.com/geraintluff/jsfx-ui-lib

Questions/bugs/etc. welcome.
Attached Images
File Type: png screen-waveform.png (16.8 KB, 581 views)
File Type: png control-screen-prompt.png (6.8 KB, 565 views)

Last edited by geraintluff; 06-27-2018 at 03:29 PM. Reason: Updated documentation
geraintluff is offline   Reply With Quote
Old 09-04-2016, 03:03 PM   #2
Smashed Transistors
Human being with feelings
 
Smashed Transistors's Avatar
 
Join Date: Jul 2014
Location: Là bas les huîtres (FR)
Posts: 424
Default

Wow, it looks great !!
I'm sort of very lazy when it comes to graphic interface for my synths.
Basically, i need what jsfx sliders offer (lists and sliders) in a more compact way so that i can layout all the controls in a logical/easy to understand way.
__________________
JSFX plugins and synths. See you here and there: SoundCloud, Youtube, Google Play...
Smashed Transistors is offline   Reply With Quote
Old 09-04-2016, 03:08 PM   #3
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

If all you want is sliders, I'm not sure it's "more compact" - although I do hope to add a rotating-dial control, that would be neater.

The viewport/layout engine might still be useful for you, depends on how complex you need things to be.
geraintluff is offline   Reply With Quote
Old 09-04-2016, 03:14 PM   #4
Smashed Transistors
Human being with feelings
 
Smashed Transistors's Avatar
 
Join Date: Jul 2014
Location: Là bas les huîtres (FR)
Posts: 424
Default

The idea is to have about 40 sliders and 20 option lists.
With the built in sliders, i can't go beyond ~30 sliders because there is no layout option, no multi column... people complain because they can't use my plugins on their laptops
__________________
JSFX plugins and synths. See you here and there: SoundCloud, Youtube, Google Play...
Smashed Transistors is offline   Reply With Quote
Old 09-04-2016, 04:41 PM   #5
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Ah - yes, it could help there. You could either lay out your controls in one page, but more compactly, or separate them out into different pages.

Would you be more interested in vertical sliders (only horizontal ones implemented right now!) or rotating dials?
geraintluff is offline   Reply With Quote
Old 09-04-2016, 11:03 PM   #6
Smashed Transistors
Human being with feelings
 
Smashed Transistors's Avatar
 
Join Date: Jul 2014
Location: Là bas les huîtres (FR)
Posts: 424
Default

I've implemented sort of compact sliders some time ago, but i'm quite lazy on this front. (see https://stash.reaper.fm/v/22090/TiaR_SHP_synth_00.zip)

I think that most of the time horizontal sliders will do it.

Vertical sliders would be great for Ze Cheesy Harmonic Synth which implements some early digital additive synthesis

BTW, it seems that you've implemented non linear curves for your sliders, that's really great.
__________________
JSFX plugins and synths. See you here and there: SoundCloud, Youtube, Google Play...
Smashed Transistors is offline   Reply With Quote
Old 09-05-2016, 01:39 AM   #7
reapercurious
Human being with feelings
 
reapercurious's Avatar
 
Join Date: Jul 2007
Posts: 1,890
Default

Quote:
Originally Posted by geraintluff View Post
Ah - yes, it could help there. You could either lay out your controls in one page, but more compactly, or separate them out into different pages.

Would you be more interested in vertical sliders (only horizontal ones implemented right now!) or rotating dials?
in my opinion it would be better than a knob or a slider to have a number entry box that is click+draggable.
reapercurious is offline   Reply With Quote
Old 09-05-2016, 07:57 AM   #8
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default Updated with dials and vertical sliders

OK - vertical sliders and two types of dial added. The dials work by clicking and dragging vertically on the dial (not doing something with rotations).

Attached is some example code you might use to pack lots of dials into a screen, and a screenshot of what it looks like.

Quote:
Originally Posted by reapercurious View Post
in my opinion it would be better than a knob or a slider to have a number entry box that is click+draggable.
Interesting - what would you use this for? That click+drag is how the dials work, so would a dial with text on it work for you, as in the example?
Attached Images
File Type: png demo-dials.png (8.1 KB, 593 views)
Attached Files
File Type: txt dial-demo.txt (1.5 KB, 497 views)
geraintluff is offline   Reply With Quote
Old 09-05-2016, 01:51 PM   #9
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,889
Default

Cool.
IXix is offline   Reply With Quote
Old 09-07-2016, 01:59 PM   #10
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Thanks for sharing !

I put a link on ReaTeam Teamplates repo README.

I think it would be cool if you put a link from your Readme to this thread.

Also, I see your libray have a page system,
could this allow to have a lot of JSFX sliders like exposed on this thread?
X-Raym is offline   Reply With Quote
Old 09-08-2016, 07:21 AM   #11
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Quote:
Originally Posted by X-Raym View Post
Also, I see your libray have a page system,
could this allow to have a lot of JSFX sliders like exposed on this thread?
EDIT - Whoah, I just realised you can have hidden sliders! This is awesome - state-saving works, automation works, the whole deal!

Yes, you can *absolutely* do that - here's some example code, with 20 hidden sliders, displayed as two pages with 10 sliders each:

Code:
desc:Multiple pages of sliders
// Sliders are hidden by starting with "-"
slider1:0<-1,1,0>-Slider 1
slider2:0<-1,1,0>-Slider 2
slider3:0<-1,1,0>-Slider 3
slider4:0<-1,1,0>-Slider 4
slider5:0<-1,1,0>-Slider 5
slider6:0<-1,1,0>-Slider 6
slider7:0<-1,1,0>-Slider 7
slider8:0<-1,1,0>-Slider 8
slider9:0<-1,1,0>-Slider 9
slider10:0<-1,1,0>-Slider 11
slider11:0<-1,1,0>-Slider 12
slider12:0<-1,1,0>-Slider 13
slider13:0<-1,1,0>-Slider 14
slider14:0<-1,1,0>-Slider 14
slider15:0<-1,1,0>-Slider 15
slider16:0<-1,1,0>-Slider 16
slider17:0<-1,1,0>-Slider 17
slider18:0<-1,1,0>-Slider 18
slider19:0<-1,1,0>-Slider 19
slider20:0<-1,1,0>-Slider 20

import ui-lib.jsfx-inc

@init

allocated_end = ui_setup(0);

@gfx

function my_labelled_slider(value, label) (
  ui_push_heighttext(-1); // Default height - text line plus padding
    ui_split_left(200);
      ui_align(1, 0.5); // Middle right
      ui_pad();
      ui_text(label);
    ui_pop();

    value = control_hslider(value, -1/*low*/, 1/*high*/, 0/*bias*/);
  ui_pop();
  value;
);

ui_start("screen1");

ui_screen() == "screen1" ? (
  control_navbar("Screen 1", "Screen 2", "screen2");

  ui_split_topratio(1/10);
    slider1 = my_labelled_slider(slider1, "Slider 1");
  ui_split_next();
    slider2 = my_labelled_slider(slider2, "Slider 2");
  ui_split_next();
    slider3 = my_labelled_slider(slider3, "Slider 3");
  ui_split_next();
    slider4 = my_labelled_slider(slider4, "Slider 4");
  ui_split_next();
    slider5 = my_labelled_slider(slider5, "Slider 5");
  ui_split_next();
    slider6 = my_labelled_slider(slider6, "Slider 6");
  ui_split_next();
    slider7 = my_labelled_slider(slider7, "Slider 7");
  ui_split_next();
    slider8 = my_labelled_slider(slider8, "Slider 8");
  ui_split_next();
    slider9 = my_labelled_slider(slider9, "Slider 9");
  ui_split_next();
    slider10 = my_labelled_slider(slider10, "Slider 10");
  ui_pop();
) : ui_screen() == "screen2" ? (
  control_navbar("Screen 2", -1, -1);

  ui_split_topratio(1/10);
    slider11 = my_labelled_slider(slider11, "Slider 11");
  ui_split_next();
    slider12 = my_labelled_slider(slider12, "Slider 12");
  ui_split_next();
    slider13 = my_labelled_slider(slider13, "Slider 13");
  ui_split_next();
    slider14 = my_labelled_slider(slider14, "Slider 14");
  ui_split_next();
    slider15 = my_labelled_slider(slider15, "Slider 15");
  ui_split_next();
    slider16 = my_labelled_slider(slider16, "Slider 16");
  ui_split_next();
    slider17 = my_labelled_slider(slider17, "Slider 17");
  ui_split_next();
    slider18 = my_labelled_slider(slider18, "Slider 18");
  ui_split_next();
    slider19 = my_labelled_slider(slider19, "Slider 19");
  ui_split_next();
    slider20 = my_labelled_slider(slider20, "Slider 20");
  ui_pop();
) : ui_system();
Screenshots attached.
Attached Images
File Type: png sliders-page-1.png (12.0 KB, 573 views)
File Type: png sliders-page-2.png (11.9 KB, 523 views)
File Type: jpg sliders-automation.jpg (60.0 KB, 512 views)

Last edited by geraintluff; 09-08-2016 at 08:43 AM. Reason: Whoah - hidden sliders!
geraintluff is offline   Reply With Quote
Old 10-20-2016, 05:53 AM   #12
rich_h
Human being with feelings
 
Join Date: May 2007
Posts: 93
Default

Just a note to say thanks for this! I've just used it to create control/edit panels for the Roland JU06, JP08, JX03 and TR8, which I shall upload to the stash later.

Just one observation - on the dials, if you let your finger linger on the mouse button, the value starts to drop quite rapidly even if you're not moving the mouse. This is only a minor issue for my purposes.
rich_h is offline   Reply With Quote
Old 10-24-2016, 09:48 AM   #13
rich_h
Human being with feelings
 
Join Date: May 2007
Posts: 93
Default

Ah, forget that stuff about the dial, it was down to the way I was forcing the values to integers. All sorted now
rich_h is offline   Reply With Quote
Old 10-24-2016, 12:04 PM   #14
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

@geraintluff
I missed your answer !

Thanks, and great stuff
X-Raym is offline   Reply With Quote
Old 01-23-2017, 08:50 AM   #15
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default Update, themes, features

OK, I've done a bit more work on this.

I've tried to write a short guide. Feedback would be appreciated - I have no idea if it makes sense to anybody but me.

Plus, two new themes! A black theme:



And a grey theme:

geraintluff is offline   Reply With Quote
Old 01-23-2017, 03:57 PM   #16
Ozman
Human being with feelings
 
Join Date: Feb 2015
Posts: 753
Default

Beautiful
Ozman is offline   Reply With Quote
Old 01-24-2017, 09:29 AM   #17
cyrilfb
Human being with feelings
 
cyrilfb's Avatar
 
Join Date: Apr 2012
Location: Denver, CO
Posts: 249
Default Wow

You are a very busy and talented person geraintluff!
Thanks for this library and for the ReaRack.
__________________
Cy Ball
Reaper + inspiration = music.
soundcloud.com/cyball or cyball.bandcamp.com/ or cyrilfb.com
cyrilfb is offline   Reply With Quote
Old 01-24-2017, 12:18 PM   #18
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,889
Default

Nice
IXix is offline   Reply With Quote
Old 02-23-2018, 02:47 AM   #19
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default Rewritten

OK, I have rewritten the documentation from scratch, including tons of example code and screenshots, and even an interactive JSFX demo (which doubles as API documentation).

Main page: https://github.com/geraintluff/jsfx-ui-lib

New API documentation: https://geraintluff.github.io/jsfx-ui-lib/doc/html/ - the shiny stuff is in the "rich controls" section.

Interactive JSFX demo / docs: https://stash.reaper.fm/v/32955/ui-lib.zip

I hope this might make it usable for more people.

Last edited by geraintluff; 02-23-2018 at 02:57 AM.
geraintluff is offline   Reply With Quote
Old 02-23-2018, 04:16 AM   #20
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,875
Default

Interactive JSFX tutorial, JSFX preprocessor, npm distribution, HTML help... Very good job, well done Thanks for sharing !

Small demo of the interactive JSFX (for those who want to see what it looks like)

X-Raym is offline   Reply With Quote
Old 04-01-2018, 06:51 AM   #21
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default Retina support

I've added Retina support (because I got a new monitor and all the JSFX suddenly looked a bit blocky).

You enable it by setting:

Code:
gfx_ext_retina = 1;
If all you're using is the built-in controls, that's all you need, and it should just work! It hides the difference for you, so even if your code uses exact pixel sizes (e.g. "ui_push_top(50)"), then it will still draw the same size on your screen.

If you are drawing your own UI components, using ui_left()/ui_height() etc. then you need a little bit extra, because the viewport functions like ui_left() will give their answer scaled down. This means that if you then draw to these positions using gfx_* functions, it won't be in the right place.

The simplest solution is: the function ui_retina() can either get the current pixel-scaling value, or set the pixel-scaling value. If you set the pixel-scaling value to 1, then it ui_left()/others will return the values you want, which match up to positions in the actual image buffer. (If you use any of the built-in elements at this point it will now draw them at the wrong size, though.)

Code:
ui_push()
    ui_retina(1); // Remove all pixel-scaling
    // You can now use ui_left() as actual pixel locations
    // However, it is your responsibility to draw things twice the size if needed 
    gfx_x = ui_left();
    gfx_y = ui_top();
    ...
ui_pop();
For example, these two lines are all it took to modify my Panalysis effect (which uses built-in controls but also has a custom graphics section): set gfx_ext_retina=1, and then call ui_retina(1) just before our custom drawing code.

It gets a bit fussier when dealing with the mouse though, but I hope to sort that out soon.

Here are a couple of effects rendered with Retina support: Humonica and Spectrum Matcher.

Last edited by geraintluff; 07-20-2018 at 04:04 AM.
geraintluff is offline   Reply With Quote
Old 06-23-2018, 01:10 AM   #22
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default UI Generator

Shared on another thread, but makes sense to post here as well.

I've made an experimental UI generator. The idea is that you put a few simple annotations next to the sliders, to tell it how to organise the controls into rows and groups.

Here are some annotations added to the built-in "Auto Wideness" effect:

Code:
// ui:row
// ui:group name=Envelope
slider1:-18<-60,0,1>-0% Wideness @ (dB)
slider2:-6<-30,24,1>-100% Wideness @ (dB)
slider3:1<0,50,1>-Attack (ms)
slider4:250<20,2000,10>-Release (ms)

// ui:row
// ui:group name=Width
slider5:0<0,50,1>-Min Width (%)
slider6:100<50,500,10>-Max Width (%)
slider7:0<0,2,1{Left+Right,Left,Right}>-0% Signal
slider8:0<0,1,1{No,Yes}>-Reverse Mode
// ui:group name=Output
slider14:0<0,100,1>-Current Wideness (%)

// ui:row
// ui:group name=Director
slider9:0<0,5,1{Left+Right,Left,Right,Sidechain Left+Right,Sidechain Left,Sidechain Right}>-Director
slider10:20<20,20000,10>-Director HP (Hz)
slider11:20000<20,20000,10>-Director LP (Hz)
slider12:0<0,1,1{No,Yes}>-Preview Director
It then generates a big mess of code to put in @gfx. The code above produces an interface that looks like this:



If you have lots of controls, there's a "compact" mode which could be good if you're trying to pack loads of sliders in:



The documentation included in the tool should explain how to use it. I'd be interested to hear about any difficulties you run into.
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-23-2018 at 12:58 PM.
geraintluff is offline   Reply With Quote
Old 06-23-2018, 02:35 AM   #23
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Seems great !

Could you post a feature list, e.g. what kind of controls can be generated and what options can be assigned to those (position, color, annotation, orientation, scale, ....) ?

Do you plan extensions such as "Level indicators" or similar ? (Checkboxes/Switches, and dropdown lists seem to be already in place ! )

Is there an easy way to combine such an automatically generated GUI with additional GUI elements such as graphics (e.g. I often do spectrum diagrams), or text ?
Thanks a lot !

-Michael

Last edited by mschnell; 06-23-2018 at 05:03 AM.
mschnell is offline   Reply With Quote
Old 06-23-2018, 02:35 AM   #24
IXix
Human being with feelings
 
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,889
Default

Quote:
Originally Posted by geraintluff View Post
Your kung-fu is strong!
IXix is offline   Reply With Quote
Old 06-23-2018, 03:47 AM   #25
sonicowl
Human being with feelings
 
sonicowl's Avatar
 
Join Date: Oct 2015
Posts: 739
Default

omg! yesss!!!!
sonicowl is offline   Reply With Quote
Old 06-23-2018, 11:53 AM   #26
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Quote:
Originally Posted by mschnell View Post
Could you post a feature list, e.g. what kind of controls can be generated and what options can be assigned to those (position, color, annotation, orientation, scale, ....) ?
I chose to make an opinionated tool that did as much as possible automatically. So it makes some choices for you (e.g. selecting which controls to use). This means you can get a useful UI working using just the "// ui:row" and "// ui:group" annotations.

The screenshots in my previous post are literally just what is produced using the annotations in the code above them (plus a single extra annotation for the compact version).

You can override certain things, and supported parameters are mentioned in the how-to guide. My next comment explains a bit more, and the initial code (which appears when you open the tool) demonstrates their use.

The layout is pretty fixed: controls are listed in order, and are separated into rows, each row is separated into groups, and everything is evenly spaced. You only really get to specify how it's split into rows/groups, not individually place each control.

It can't do different colours, although you can provide a custom overall theme using a simple bitmap template.

Quote:
Originally Posted by mschnell View Post
Do you plan extensions such as "Level indicators" or similar ? (Checkboxes/Switches, and dropdown lists seem to be already in place ! )
Possible - I mean, even in the example, the "Current Wideness" one is an output, and it draws as a dial (which is slightly inaccurate).

I don't want to get too specific, though - and also something like a level-meter might want to be a different shape to everything else, so can't be laid out in a basic grid. So yeah maybe, but at a certain point it might make more sense to use the generated code as a starting-point, and start wrestling with the layout code. :/ I'm not sure where the best balance is for that.

Quote:
Originally Posted by mschnell View Post
Is there an easy way to combine such an automatically generated GUI with additional GUI elements such as graphics (e.g. I often do spectrum diagrams), or text ?
Graphics: absolutely! The "how-to" section in the tool explains how to do this (see "Including existing graphics code"). Basically you wrap a function declaration around your existing @gfx block, add an annotation with the function name, and you're done - your custom graphics are displayed underneath the generated controls.

Text: not currently (assuming you mean "insert fixed text into certain points in the layout"). The only place custom text appears is group labels and control titles.
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-23-2018 at 01:05 PM.
geraintluff is offline   Reply With Quote
Old 06-23-2018, 12:13 PM   #27
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default Annotation/parameter reference

So, I put a bit of effort into writing the guide (included in the tool itself), and I think all of the annotations and parameters are covered in there. If something's not clear, I should change that guide.

However, here's a bit more detail as requested:

Controls

The controls are chosen based on the slider definition, and the options are:
  • switch - for a slider with two named options
  • up/down selector - for a slider with a handful of named options
  • an "edit" button which opens a popup full of radio-selectors - for a slider with many named options
  • plain dial - for a slider with no named options.

Annotations
  • "// ui:row" - starts a new row. No parameters.
  • "// ui:group" - starts a new group within a row. One parameter: name (optional)
  • "// ui:gfx" - configures custom graphics. Parameters are function, height, buffer (optional) and finish (optional) - see the "Including existing graphics code" section for details.
  • "// ui:layout" - configures overall layout. Parameters are compact (optional) and simple-bitmap (optional) - see "Compact layout" and "Custom Theme/Colours" sections.

Parameters

All parameters must be comma-separated.

Any comment line that doesn't start with one of those is assumed to be a set of control parameters, which are:
  • "title=" - for any control, it overrides the displayed title
  • "format=" - for dials, it's an sprintf-style format for display
  • "bias=" - for dials, changes how angle maps to value. 0 is linear, positive means more detail on the lower values, negative the opposite.
  • "inverted=" - for switches/selectors, 0 means in the order they are defined, 1 means reversed/flipped
  • "columns=" - for up/down selectors and popups. 0 forces it to be an up/down selector, positive integers make it a popup split into that number of columns

If your slider title ends with a single word in brackets (e.g. "Attack (ms)" ), that's taken to be a unit, and displayed alongside the value instead of in the title. This can be overridden by explicitly providing "format=" and "title=".
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-23-2018 at 01:07 PM.
geraintluff is offline   Reply With Quote
Old 06-23-2018, 01:09 PM   #28
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

This is great! (Range slider would be a nice addition )

Don't know how usable this would be, but gfx_getdropfile seems to work in JSFX too:


Code:
EEL: gfx_getdropfile(idx[,#str])

Enumerates any drag/dropped files. call gfx_dropfile(-1) to clear the list when finished. Returns 1 if idx is valid, 0 if idx is out of range.
spk77 is offline   Reply With Quote
Old 06-23-2018, 02:41 PM   #29
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,686
Default

Quote:
Originally Posted by geraintluff View Post
So, I put a bit of effort into writing the guide (included in the tool itself), and I think all of the annotations and parameters are covered in there. If something's not clear, I should change that guide.
Thanks a lot for this post !
I think such an overview is very helpful.
Thanks again,
-Michael
mschnell is offline   Reply With Quote
Old 06-27-2018, 12:57 PM   #30
tksense
Human being with feelings
 
Join Date: Apr 2010
Posts: 34
Default

Hi Geraint,

So far, I am able to import ui-lib, copy freemem @init, generate and paste @gfx code in the end, and hide JS sliders.

The GUI shows up, but the knob in the GUI would not respond to any click. Instead, moving the original JS slider will turn the GUI into a blank white screen with a message "Unknown screen: (65.000000)".

I suspect this can be solved by a "needs_slider_update" definition. However, I haven't figured out how to implement the function (in @init) yet.

Can you show us a before & after example in how to do this?

I am hoping it will work with sysex editors like below and with CCenv by Panu Aaltio and P.M. Crockett.

A generator like this for us less technical users is a godsend.

Thank you so much for sharing!

Pat


Code:
desc:V-Synth COSM1 DTVF

slider1:64<0,127,1>cutoff DTVF
slider2:64<0,127,1>Reso DTVF

////////////////////////////////////////////////////////////////////////////

in_pin:none
out_pin:none


import ui-lib.jsfx-inc

@init

freemem = 0;
freemem = ui_setup(freemem);


////////////////////////////////////////////////////////////////////////////

@slider
slider1 = floor(slider1);
Slider2 = floor(slider2);

////////////////////////////////////////////////////////////////////////////
@block

//COSM1 DTVF Cutoff

(slider1 != oldslider1) ?

(
msgbuf[0] = $x41;
msgbuf[1] = $x10;
msgbuf[2] = $x00;
msgbuf[3] = $x53;
msgbuf[4] = $x12;
msgbuf[5] = $x10;
msgbuf[6] = $x00;
msgbuf[7] = $x50;
msgbuf[8] = $x16;
msgbuf[9] = $x08;
msgbuf[10] = $x00;
msgbuf[11] = floor(slider1/16);
msgbuf[12] = floor(slider1 % $x10);
msgbuf[13] = floor(slider1);

 midisyx(0,msgbuf,14);
  oldslider1 = slider1;
);


//COSM1 DTVF Reso
(slider2 != oldslider2) ?
(
msgbuf[0] = $x41;
msgbuf[1] = $x10;
msgbuf[2] = $x00;
msgbuf[3] = $x53;
msgbuf[4] = $x12;
msgbuf[5] = $x10;
msgbuf[6] = $x00;
msgbuf[7] = $x50;
msgbuf[8] = $x06;
msgbuf[9] = $x08; 
msgbuf[10] = $x00;
msgbuf[11] = floor(slider2/16);
msgbuf[12] = floor(slider2 % $x10);
msgbuf[13] = floor(slider2);

 midisyx(0,msgbuf,14);
  oldslider2 = slider2;
);
tksense is offline   Reply With Quote
Old 06-27-2018, 03:14 PM   #31
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Quote:
Originally Posted by tksense View Post
So far, I am able to import ui-lib, copy freemem @init, generate and paste @gfx code in the end, and hide JS sliders.

The GUI shows up, but the knob in the GUI would not respond to any click. Instead, moving the original JS slider will turn the GUI into a blank white screen with a message "Unknown screen: (65.000000)".
So, the idea of "freemem" in my example is to make sure you don't have a clash, where two bits of code are trying to use the same section of memory buffer for different things.

However, in your code, you aren't initialising "msgbuf", so it has the default value 0 - which is the same section of memory that you're passing into ui_setup().

The fix is to initialise msgbuf, using freemem so it is guaranteed to come after the memory that the UI system's using:

Code:
@init

freemem = 0;
// Reserve some memory buffer for the UI
freemem = ui_setup(freemem);

// Reserve some memory buffer for msgbuf
msgbuf = freemem;
freemem += 14; // msgbuf has 14 items
Does that make sense?

With that fix, it draws two dials as intended.

Quote:
Originally Posted by tksense View Post
I suspect this can be solved by a "needs_slider_update" definition. However, I haven't figured out how to implement the function (in @init) yet.
You don't need this with the code you posted. Your @slider section is just doing rounding, but the dials produce rounded outputs anyway, just like the built-in sliders do.
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-28-2018 at 02:23 AM.
geraintluff is offline   Reply With Quote
Old 06-28-2018, 02:48 PM   #32
tksense
Human being with feelings
 
Join Date: Apr 2010
Posts: 34
Default

Great!

Now the only thing issue left with this sysex JS is how GUI's knobs do not speak automation to the DAW, whereas I'd have to still either grab the original JS sliders or go to "envelopes menu" to manually tick the checkbox to activate and use the slider in the track envelope lane.

Would this be an easy fix?

The next endeavor is to view all parameters in CCenv - this JS works along with another port-opening JS "CCenv input", which together enables Reaper to receive incoming CC and draw automation on the DAW at the same time.

The only issue is, of course, the 64 sliders. Is this one any more complicated? The below code returns all kinds of jitter like flashing knobs and sending CC117-127, but only when GUI is viewed (stops jitters when GUI is not on), is this related to "needs_slider_update"?

As I have no idea where to begin besides asking, so here's the code

Code:
desc:CCEnv
Author: Panu Aaltio and P.M. Crockett

options:gmem=ccEnv

slider1:0<0,127,1>-slider1 CC64
slider2:0<0,127,1>-slider2 CC65
slider3:0<0,127,1>-slider3 CC66
slider4:0<0,127,1>-slider4 CC67
slider5:0<0,127,1>-slider5 CC68
slider6:0<0,127,1>-slider6 CC69
slider7:0<0,127,1>-slider7 CC70
slider8:0<0,127,1>CC71
slider9:0<0,127,1>Amp Release CC72
slider10:0<0,127,1>Amp Attack CC73
slider11:0<0,127,1>Cutoff Frequency CC74
slider12:0<0,127,1>slider12 CC75
slider13:0<0,127,1>-slider13 CC76
slider14:0<0,127,1>-slider14 CC77
slider15:0<0,127,1>-slider15 CC78
slider16:0<0,127,1>-slider16 CC79
slider17:0<0,127,1>-slider17 CC80
slider18:0<0,127,1>-slider18 CC81
slider19:0<0,127,1>-slider19 CC82
slider20:0<0,127,1>-slider20 CC83
slider21:0<0,127,1>-slider21 CC84
slider22:0<0,127,1>-slider22 CC85
slider23:0<0,127,1>-slider23 CC86
slider24:0<0,127,1>-slider24 CC87
slider25:0<0,127,1>-slider25 CC88
slider26:0<0,127,1>-slider26 CC89
slider27:0<0,127,1>-slider27 CC90
slider28:0<0,127,1>-slider28 CC91
slider29:0<0,127,1>-slider29 CC92
slider30:0<0,127,1>-slider30 CC93
slider31:0<0,127,1>-slider31 CC94
slider32:0<0,127,1>-slider32 CC95
slider33:0<0,127,1>-slider33 CC96
slider34:0<0,127,1>-slider34 CC97
slider35:0<0,127,1>-slider35 CC98
slider36:0<0,127,1>-slider36 CC99
slider37:0<0,127,1>-slider37 CC100
slider38:0<0,127,1>-slider38 CC101
slider39:0<0,127,1>-slider39 CC102
slider40:0<0,127,1>-slider40 CC103
slider41:0<0,127,1>-slider41 CC104
slider42:0<0,127,1>-slider42 CC105
slider43:0<0,127,1>-slider43 CC106
slider44:0<0,127,1>-slider44 CC107
slider45:0<0,127,1>-slider45 CC108
slider46:0<0,127,1>-slider46 CC109
slider47:0<0,127,1>-slider47 CC110
slider48:0<0,127,1>-slider48 CC111
slider49:0<0,127,1>-slider49 CC112
slider50:0<0,127,1>-slider50 CC113
slider51:0<0,127,1>-slider51 CC114
slider52:0<0,127,1>-slider52 CC115
slider53:0<0,127,1>-slider53 CC116
slider54:0<0,127,1>-slider54 CC117
slider55:0<0,127,1>-slider55 CC118
slider56:0<0,127,1>-slider56 CC119
slider57:0<0,127,1>-slider57 CC120
slider58:0<0,127,1>-slider58 CC121
slider59:0<0,127,1>-slider59 CC122
slider60:0<0,127,1>-slider60 CC123
slider61:0<0,127,1>-slider61 CC124
slider62:0<0,127,1>-slider62 CC125
slider63:0<0,127,1>-slider63 CC126
slider64:0<0,127,1>-slider64 CC127

in_pin:none
out_pin:none

////////////////////////////////////////////////////////////////////////////

import ui-lib.jsfx-inc

@init

freemem = 0;
freemem = ui_setup(freemem);

////////////////////////////////////////////////////////////////////////////


//Set array memory locations
sentCc = 0;
previousCc = 128;
cooldown = 256;

i = 64;
loop(64,
  gmem[i] = -1;
  sentCc[i] = 0;
  previousCc[i] = -1;
  cooldown[i] = 0;
  i = i + 1;
);

COOLDOWN_TIMER = 64;

channel = 0;

@block
i = 64;
loop(64,
  gmem[i] > -1 ? (
    midisend(0, 11*16 + channel, i + gmem[i] * 256);
    
    slider(i - 63) = gmem[i];
    sentCc[i] = gmem[i];
    
    cooldown[i] = COOLDOWN_TIMER;
    
    slider_automate(slider(i - 63));
    previousCc[i] = gmem[i]; 
    gmem[i] = -1;
  );

  cooldown[i] > 0 ? (
    cooldown[i] = cooldown[i] - 1;
    
    // If still ignoring envelope data, make sure old envelope doesn't come through
    previousCc[i] > -1 && previousCc[i] != slider(i - 63) ? (
      slider(i - 63) = previousCc[i];
      slider_automate(slider(i - 63));
    ); 
  );

  sentCc[i] != slider(i - 63) ? (
    sentCc[i] = slider(i - 63);
    cooldown[i] == 0 ? (
      midisend(0, 11*16 + channel, i + sentCc[i] * 256);
    );
  );
  i = i + 1;
);
Frankly with this one, I'd be happy with a two-column view at 32 parameters each, just to view all parameters. I'm curious, can this be as simple as adding a few lines of code? This can be good for a quick fix sometimes.

Thanks for your help, I'm learning bit by bit, one step at a time!

Pat

Last edited by tksense; 06-28-2018 at 03:13 PM.
tksense is offline   Reply With Quote
Old 06-29-2018, 03:14 AM   #33
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Quote:
Originally Posted by tksense View Post
Now the only thing issue left with this sysex JS is how GUI's knobs do not speak automation to the DAW
Done - updated the UI generator to add automation support. It now updates "last touched" in the Param menu, and the controls can also be used to record automation ("write" and "latch" mode work fine, I'm still working on "touch").

Quote:
Originally Posted by tksense View Post
The next endeavor is to view all parameters in CCenv
[...]
The only issue is, of course, the 64 sliders. Is this one any more complicated? The below code returns all kinds of jitter like flashing knobs and sending CC117-127, but only when GUI is viewed (stops jitters when GUI is not on), is this related to "needs_slider_update"?
Nope - again, you have a clash with memory locations. It picks some memory locations in this code:

Code:
@init
//Set array memory locations
sentCc = 0;
previousCc = 128;
cooldown = 256;
So the first 384 slots of memory are used for the effect. This means when you call ui_setup(0), it will try and use the same memory for both.

Solution: pass an unused memory location to ui_setup(), such as 384:

Code:
@init

//Set array memory locations
sentCc = 0;
previousCc = 128;
cooldown = 256;

ui_setup(384);
Quote:
Originally Posted by tksense View Post
Frankly with this one, I'd be happy with a two-column view at 32 parameters each, just to view all parameters.
I tried it out, and I think it works nicely with 4 columns.

To do this (once you've made the above fix), just put a row annotation every four sliders. You also probably want the compact-mode annotation, like this:

Code:
//ui:layout compact=1

//ui:row
slider1:0<0,127,1>-slider1 CC64
slider2:0<0,127,1>-slider2 CC65
slider3:0<0,127,1>-slider3 CC66
slider4:0<0,127,1>-slider4 CC67
//ui:row
slider5:0<0,127,1>-slider5 CC68
slider6:0<0,127,1>-slider6 CC69
slider7:0<0,127,1>-slider7 CC70
slider8:0<0,127,1>-CC71
//ui:row
slider9:0<0,127,1>-Amp Release CC72
... etc.
This generates a big grid of dials.


I would like to be able to organise these dials better, using tabs or multiple pages/screens, and that's on my TODO list for the future.

Geraint
__________________
JSFX set | Bandcamp/SoundCloud/Spotify

Last edited by geraintluff; 06-29-2018 at 05:13 AM.
geraintluff is offline   Reply With Quote
Old 06-29-2018, 09:03 PM   #34
tksense
Human being with feelings
 
Join Date: Apr 2010
Posts: 34
Default

Geraint,

The GUI basically works now, I'm very happy already!

As for minor details, I am wondering if the GUI can display midi values 0-127 in a -63, 0 , +64 format?

A formula 0<-63,64,1> did not work because the incoming MIDI value 0 would be interpreted as a zero in the middle. So I will have to stick with a 64<0,127,1> in the JS.

As for the ON/OFF switch, is it possible to assign midi values other than 0, 1 by replacing a few lines or numbers inside the generated gfx code? For example, I'd like a switch to choose between value 16 and 48. Something like this in theory: 16<16,48,32{Off,on}>. Now I'd get around this by enumerating
"off,off,off...on" until the 49th integer. It works.

Just making gravy now. Thank you!

Pat

Last edited by tksense; 06-29-2018 at 09:14 PM.
tksense is offline   Reply With Quote
Old 07-18-2018, 06:56 PM   #35
tksense
Human being with feelings
 
Join Date: Apr 2010
Posts: 34
Default

I've spent some more time trying to optimise the GUI behavior.

-For non-incremental values, I've decided to name the options in the parameter as it would probably be too much hassle to alter the code. For example in the picture below, 0=norm, 64=Punch, 127=Snap.

-The Cyan GUI comes from Geraint's original preset "theme-cyan". I think it looks very nice!

-For Novation A-Station, I changed the theme and knob colors and gave it a white tick, starting from the GUI template provided by Geraint.

I'm very happy with this result. Thank you!

Pat
Attached Images
File Type: png Geraint_GUI.png (58.4 KB, 372 views)

Last edited by tksense; 07-19-2018 at 11:36 AM.
tksense is offline   Reply With Quote
Old 07-19-2018, 12:24 AM   #36
bezusheist
Human being with feelings
 
bezusheist's Avatar
 
Join Date: Nov 2010
Location: Mullet
Posts: 829
Default

Quote:
Originally Posted by tksense View Post
As for minor details, I am wondering if the GUI can display midi values 0-127 in a -63, 0 , +64 format?
Easy...just subtract 63 from the (0-127) value.
__________________
I like turtles
bezusheist is offline   Reply With Quote
Old 07-19-2018, 08:29 AM   #37
geraintluff
Human being with feelings
 
geraintluff's Avatar
 
Join Date: Nov 2009
Location: mostly inside my own head
Posts: 346
Default

Quote:
Originally Posted by tksense View Post
I am wondering if the GUI can display midi values 0-127 in a -63, 0 , +64 format?
Quote:
Originally Posted by bezusheist View Post
Easy...just subtract 63 from the (0-127) value.
Yep. There isn't a way to do this using the code generator, so this is the point where you have to make manual changes to the code.

If I understand correctly, you want to display values as -63-64, but leave the actual values as 0-127. There should be a line that looks a bit like this in your generated code:

Code:
gfx_ui_automate_slider(some_value, gfx_ui_layout_textnumber("Title", some_value, "%i"));
You'll need to subtract 63 from the value before the text is calculated. You also need to add +63 back on afterwards - this is because the user can right-click and enter exact new values (now in the -63-64 range), so you need to translate those back into 0-127:

Code:
gfx_ui_automate_slider(some_value, gfx_ui_layout_textnumber("Title", some_value - 63, "%i") + 63);
The auto-generator won't preserve this change, so you'll have to change it again if you regenerate.
__________________
JSFX set | Bandcamp/SoundCloud/Spotify
geraintluff is offline   Reply With Quote
Old 07-19-2018, 11:43 AM   #38
tksense
Human being with feelings
 
Join Date: Apr 2010
Posts: 34
Default

Awesome! It works now. Thank you!
tksense is offline   Reply With Quote
Old 08-03-2019, 09:42 AM   #39
jack461
Human being with feelings
 
jack461's Avatar
 
Join Date: Nov 2013
Location: France
Posts: 181
Default Some additions to the JSFX UI Library

Hi !

I have been working for some weeks with the very interesting UI library developed by Geraint Luff, and I found it provided many features I was looking for. Some of you may be interested in some additions I made to it.

Very shortly, these additions address the following goals :

- Check for the necessity of executing, or not, the graphic interface of the plugin. For me, this is useful to reduce CPU usage, since I work on installations using slow CPU cards.
- Provide a support for 24bit packed RGB colors ;
- Provide a control for native gfx menus.

1) Optimization of the execution of the graphic section

When you don't need real time display, you can choose to execute the graphic section only once every “n” frames, or every “n” seconds, or when the mouse is clicked inside the plugin window. Here are some examples :
Code:
// In the “@init” section, use a combination of :
ui_Xframe_period = 6; // execute every “6” graphic frames
ui_Xtime_period = 2.5; // execute every 2.5 seconds
ui_XFlags = ui_XonLMC | ui_XonKeyb; //   execute when left mouse button is clicked or released, or when a char is typed

// and anywhere in your code :

ui_GFXdoNow = 1; // to execute once the "@gfx" section as soon as possible

// Then, in the @gfx section, use :

must_do_gfx() ? (
     // do here the graphic stuff, like :

    control_start("main", "tron");
     …
);
2) Support of 24bit packed colors.

Actually of little use for now, except for the “menu” extension. It is expected to be more usable when new controls types are added.

3) Control of menus

A menu is defined by an array of values. This is an example of a 3 items menu
Code:
size_menu = nxtmem; nxtmem += 32; // array for the menu description
size_menu[ui_jmenu_typ] = ui_jmenu_typ_sel | ui_jmenu_opt_rndrect;
size_menu[ui_jmenu_itc] = 3; // item count
size_menu[ui_jmenu_res] = 0; // last item selected
size_menu[ui_jmenu_ticks] = 1; // first item is “ticked”
size_menu[ui_jmenu_disf] = 0; // no item is disabled
size_menu[ui_jmenu_title] = "Size"; // the title
size_menu[ui_jmenu_items+0] = "resizable"; // item 1
size_menu[ui_jmenu_items+1] = "fixed 1"; // item 2
size_menu[ui_jmenu_items+2] = "fixed 2"; // item 3

// You install the menu like any other graphic component, and control
// it with the “ui_menu_control” function :

      ui_split_toptext(-1); // This is for the menu bar...
          ui_split_leftratio(1/4); // up to 4 menus, 1 used...
              // This menu is associated with a slider : size_sel
              zz8 = ui_menu_control(size_menu, size_sel);
              (zz8 != 0) ? ( ...do something... );
          ui_pop();
      ui_pop();
There is actually 3 types of menus : “action” menus, which use no tick mark, “selection” menus, where just one item can have a mark, and “option” menus, where every item can be marked. Also, every item can be enabled or disabled.

Installing the extension

After deleting the ".txt" in the attached files, put the file “ui-lib-JJ.jsfx-inc” in the same directory as your plug-in, and include it after “ui-lib.jsfx-inc”. You need of course to have the original “ui-lib.jsfx-inc” file in this directory.

The file “chkui01.jsfx” is an example of use. You may want to add in the plug-in directory a subdirectory named “themes”, with the various “theme-xxx.png” provided by Geraint Luff as examples, or parts of its own plug-ins.

The documentation is mainly in the codes of the library and the provided example. Of course, all questions, requests and bug reports are welcomed...
Attached Files
File Type: txt ui-lib-JJ.jsfx-inc.txt (14.1 KB, 232 views)
File Type: txt chkui01.jsfx.txt (6.1 KB, 231 views)
jack461 is online now   Reply With Quote
Old 01-27-2020, 07:43 PM   #40
Bobo007
Human being with feelings
 
Join Date: Jan 2020
Posts: 1
Default Trouble getting knobs working 100%

This is so cool thanks for putting this together!

I used your Generator page to get some code back for the "8 to 1 stereo"

so... im not to sure atm if this would effect different jsfx differntly but..


Long story short my knobs are working but.. when i hit stop and then play again I have to touch one of the knobs to hear anything.

I tried putting the update slider bits in different sections of the code and changing their values but have no idea what i am doing.

Any chance you could help with this?


also i dont know if this s helpful at all ... but one variation (moving the update slider bits around in the code below) had it so i could set the knob/sliders and there was no funny business about having to touch a knob to hear something.... but i could not adjust the knobs/sliders in real time...i had to stop/play to hear the change


Code:
/*******************************************************************************
*  Copyright 2007 - 2011, Philip S. Considine                                  *
*  This program is free software: you can redistribute it and/or modify        *
*  it under the terms of the GNU General Public License as published by        *
*  the Free Software Foundation, either version 3 of the License, or           *
*  (at your option) any later version.                                         *
*                                                                              *
*  This program is distributed in the hope that it will be useful,             *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                *
*  GNU General Public License (http://www.gnu.org/licenses/)for more details.  *
*******************************************************************************/

desc:8x Stereo to 1x Stereo Mixer
//desc:8x Stereo to 1x Stereo Mixer [IXix]
desc:Drum Levels for DrumFX
import ui-lib.jsfx-inc
//tags: mixer gain
//author: IXix

slider1:0<-60,30,0.1>Sub
slider2:0<-60,30,0.1>Kick
slider3:0<-60,30,0.1>snare
slider4:0<-60,30,0.1>CL-HH
slider5:0<-60,30,0.1>OP-HH
slider6:0<-60,30,0.1>Level 11+12 RimShot)(dB)
slider7:0<-60,30,0.1>Level 13+14 (Rando1) (dB)
slider8:0<-60,30,0.1>Level 15+16 (Rando2) (dB)
slider9:0<-60,30,0.1>Level 17+18 (Rando3) (dB)









in_pin:input 1 L
in_pin:input 1 R
in_pin:input 2 L
in_pin:input 2 R
in_pin:input 3 L
in_pin:input 3 R
in_pin:input 4 L
in_pin:input 4 R
in_pin:input 5 L
in_pin:input 5 R
in_pin:input 6 L
in_pin:input 6 R
in_pin:input 7 L
in_pin:input 7 R
in_pin:input 8 L
in_pin:input 8 R
in_pin:input 9 L
in_pin:input 9 R
out_pin:output  L
out_pin:output  R
///////////////////////////////////////////////////////////////////////////////
@init
freemem = 0; // some empty section of the memory buffer
freemem = ui_setup(freemem); // returns the first index it's not using
gainMin = -60;
gainMax = 30;

///////////////////////////////////////////////////////////////////////////////
function slider_update_function() (
  needs_slider_update = 0;

  // previous @slider code
 // @slider
  slider1 = min(max(slider1, gainMin), gainMax);
  slider2 = min(max(slider2, gainMin), gainMax);
  slider3 = min(max(slider3, gainMin), gainMax);
  slider4 = min(max(slider4, gainMin), gainMax);
  slider5 = min(max(slider5, gainMin), gainMax);
  slider6 = min(max(slider6, gainMin), gainMax);
  slider7 = min(max(slider7, gainMin), gainMax);
  slider8 = min(max(slider8, gainMin), gainMax);
  slider9 = min(max(slider9, gainMin), gainMax);
  
  levelA = 2 ^ (slider1 / 6);
  levelB = 2 ^ (slider2 / 6);
  levelC = 2 ^ (slider3 / 6);
  levelD = 2 ^ (slider4 / 6);
  levelE = 2 ^ (slider5 / 6);
  levelF = 2 ^ (slider6 / 6);
  levelG = 2 ^ (slider7 / 6);
  levelH = 2 ^ (slider8 / 6);
  levelI = 2 ^ (slider9 / 6);
);
///////////////////////////////////////////////////////////////////////////////
@sample
// Do the left mix
spl0 =  (spl0 * levelA)  + 
    (spl2 * levelB) + 
    (spl4 * levelC) + 
    (spl6 * levelD) + 
    (spl8 * levelE) + 
    (spl10 * levelF)+ 
    (spl12 * levelG)+ 
    (spl14 * levelH)+
    (spl16 * levelI);

// Do the right mix
spl1 =   (spl1 * levelA)  + 
    (spl3 * levelB) + 
    (spl5 * levelC) + 
    (spl7 * levelD) + 
    (spl9 * levelE) + 
    (spl11 * levelF)+ 
    (spl13 * levelG)+ 
    (spl15 * levelH)+
    (spl17 * levelI);
    
    
    
@gfx 810 130

// AUTOGENERATED UI //
// generated from slider section: https://github.com/geraintluff/jsfx-ui-lib
function gfx_ui_automate_slider(slidervar*, new_value) (
  slidervar !== new_value ? (
    slidervar = new_value;
    slider_automate(slidervar);
  );
  new_value;
);

function gfx_ui_layout_textnumber(title, value, format) local(h) (
  h = max((ui_height() - 60)/2, ui_height()*0.2);
  ui_split_top(h);
    ui_text(title);
  ui_pop();
  ui_split_bottom(h);
    value = control_hidden_textnumber(value, value*1.00000001, format);
  ui_pop();
  value;
);

function gfx_ui_dial_rounded(slidervar*, low, high, bias, default, step) (
  slidervar != floor(slidervar._ui_gen_float/step + 0.5)*step ? slidervar._ui_gen_float = slidervar;
  slidervar._ui_gen_float = control_dial(slidervar._ui_gen_float, low, high, bias, default);
  gfx_ui_automate_slider(slidervar, floor(slidervar._ui_gen_float/step + 0.5)*step);
);

control_start("main", "default");

ui_screen() === "main" ? (
  ui_split_topratio(1/1); // single row
    ui_split_leftratio(9/9);
      // row 1, group 1
      ui_split_leftratio(1/9);
        gfx_ui_automate_slider(slider1, gfx_ui_layout_textnumber("Sub", slider1, "%.1f"));
        gfx_ui_dial_rounded(slider1, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider2, gfx_ui_layout_textnumber("Kick", slider2, "%.1f"));
        gfx_ui_dial_rounded(slider2, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider3, gfx_ui_layout_textnumber("snare", slider3, "%.1f"));
        gfx_ui_dial_rounded(slider3, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider4, gfx_ui_layout_textnumber("CL-HH", slider4, "%.1f"));
        gfx_ui_dial_rounded(slider4, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider5, gfx_ui_layout_textnumber("OP-HH", slider5, "%.1f"));
        gfx_ui_dial_rounded(slider5, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider6, gfx_ui_layout_textnumber("Level 11+12 RimShot)", slider6, "%.1f dB"));
        gfx_ui_dial_rounded(slider6, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider7, gfx_ui_layout_textnumber("Level 13+14 (Rando1)", slider7, "%.1f dB"));
        gfx_ui_dial_rounded(slider7, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider8, gfx_ui_layout_textnumber("Level 15+16 (Rando2)", slider8, "%.1f dB"));
        gfx_ui_dial_rounded(slider8, -60, 30, 0, 0, 0.1);
      ui_split_next();
        gfx_ui_automate_slider(slider9, gfx_ui_layout_textnumber("Level 17+18 (Rando3)", slider9, "%.1f dB"));
        gfx_ui_dial_rounded(slider9, -60, 30, 0, 0, 0.1);
      ui_pop();
    ui_pop();
  ui_pop();
) : control_system();



ui_interacted() ? needs_slider_update = 1;
// END OF AUTOGENERATED UI // 


@block
needs_slider_update ? slider_update_function();

Last edited by Bobo007; 01-27-2020 at 07:56 PM.
Bobo007 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 09:43 AM.


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