Add sliders to your touch screen projects -- free library

Was just gonna post about handle droppings and 1200 lines of code. Have created an array setup of 8 pages of 16 slider elements enabling ILI9431_t3_controls and 16 encoders to scroll thru the lot. The array covers every slider parameter and I found that altering per-slider colors triggered droppings when touch was used.

Thought to check your Git first, found and had a play with the new release so here's an edited post.

The compiler falls over with:-

error: 'class SliderV' has no member named 'changed'

From there, backed out and had a crack at the Multi-screen example and was greeted with:-

error: 'ScreenX' was not declared in this scope.

Runng on Win10, IDE 1.8.13 TD1.54B7. Pretty keen to get the new lib working so thanks in advance for guidance.
 
@matrixrat, fixed up the library, let me know if something doesn't work.

ScreenX issue was a typo SceenX was accidentially used
changed() was removed as I found a better way to managed telling the user a control changed, added changed() back to support previous examples and implementations
 
Got the Multi-Screen example working, encoder trails gone.

Have adjusted the foundations of my project to use the new library tho have the devil of finer detail namely getting the array system to present per (SliderElement.color ->colorData[stuff]) properly.

Have indexed Handle shape and size working and observed that when a new handleshape is assigned to a slider that the previous handle image does not seem to be getting erased from a buffer before the new one gets plonked on to of it, so if it was Round and you change it to Triangle, you get to see a a triangle stuck into a Round then if you move it a little PacMan is left behind if you get the drift. Only happens when slider inits are changed on the fly.

Otherwise, looking pretty darn good!
 
@matrixRat -- I never intended to change the handle shape after init but depending on your use case this may be easy to address. What are you truing to do? Are you trying to dynamically change the handle as the user slides the handle or change the handle not when the user is interacting with the slider?
 
@matrixRat -- I updated the setHandleSize() and setHandleShape() methods to redraw upon a change. The handle will only be redrawn after the draw method (that way we're not painting handles before the control is drawn.

you only need to get the latest (v5.3) .h and .cpp files and recompile, no new or removed methods.

example implementation using the graphic equalizer example

Code:
      if (sBand1.value > 3) {
        sBand2.setHandleShape(HANDLE_TRIANGLE_1);
        sBand2.setHandleSize(10);
      }
      else if (sBand1.value < -3) {
        sBand2.setHandleShape(HANDLE_TRIANGLE_2);
        sBand2.setHandleSize(10);
      }
      else  {
        sBand2.setHandleShape(HANDLE_TRIANGLE_3);
        sBand2.setHandleSize(8);
      }
 
Basically, playing around with MIDI stuff. Built a few controllers with pots, love 'em or otherwise, and then encoders, flying blind with no knob pointer... want something to remember and show where the knobs were set.

What started out as a quest for some visual feedback for 16 encoders and yeah I suppose, rings of leds or whatever, and this library showed up and got my learning muscle inspired.

The aim is to use this lib as a window into a larger matrix, say a set of arrays that hold the entire patch contents of a synth, pull in a patch and theoretically, the sliders dance, the encoders are all synced and then point at a block and use it, I guess you'd call it as a control surface - editor.

Most of my synth parameters are 0-127, some are like 0-5, or 0-17 or whatever so that's why the big array covers all the details, and already have encoder and slider limits, tick, snap etc working. Figure using colors and shapes related to particular groups or functions offers extra user feedback.

Um, yes the display is a little small, am eyeing off those 1280x400s. Geting the "first one working".

Snagged the latest, many thanks.
 
Got it working, not without a struggle. The latest lib tweak cleaned up loads of bits and pieces but did not evict the PacMan effect so played with Round of different sizes and discovered that if you assign say handle round size 10, ColorBack that a ring would remain after dropping a size 10 handle over a previous size 16 by assigning new SliderElement parameters to the same slider, so I figured the lib must be starting up with size 16 as a default so sniffed out line 56 in ILI9341_t3_Controls.h and changed it to #define SLIDER_HANDLE_SIZE 0

For a double check, rolled back to the previous lib. Ragged bits returned as did different behavior in response to either touch or external input so the latest tweak gets a big thumbs-up.

Am curious, will this lib run on a T4x as looking at the numbers it's inevitable that a stack collision will happen on the T3.2 when a per SliderElement MidiOutput class is added the way things are progressing.

Here is a stripped version of the code in a zip as has a few tabs, might be useful as a dev tool.
Uses a single encoder to scroll thru 10 Blocks and @Luni's EncoderTool to drive it.

Thanks again.
 

Attachments

  • DevKitRev3Stripped.zip
    8.5 KB · Views: 55
Playing around with a Horizontal slider and discovered that Snap doesn't seem to work and while setting up this example code found artefacts to do with handleShape(5) - only.


HorizSliderIssues.jpg

And the code:-
Code:
#include <ILI9341_t3.h>           // fast display driver lib
#include "UTouch.h"               // touchscreen lib
#include <ILI9341_t3_Controls.h>  // custom control define file
#include <font_Arial.h>
#define FONT Arial_16
//****************** Hardware details ****************************
#define TFT_DC     9              // DC pin on LCD
#define TFT_CS    10              // chip select pin on LCD
#define LCD_PIN   32              // lcd pin to control brightness
#define TOUCH_CLK 24
#define TOUCH_CS  25
#define TOUCH_DIN 26
#define TOUCH_DO  27
#define TOUCH_IRQ 28
#define Rotation   3
//#define USE_YELLOW_HEADERS
#define USE_BLACK_HEADERS

float VertVal = 2, HorizVal = 5;
int BtnX, BtnY;

char buf[22];
ILI9341_t3 Display = ILI9341_t3(TFT_CS, TFT_DC);
UTouch  Touch( TOUCH_CLK, TOUCH_CS, TOUCH_DIN, TOUCH_DO, TOUCH_IRQ);

//SliderH Red(&Display, left, top, width, bar color, back color, ball color);
SliderV Vert(&Display);
SliderH Horiz(&Display);

void setup() {
  Serial.begin(9600);
  pinMode(LCD_PIN, OUTPUT);
  Vert.init   (20,  20, 150, 0, 5, 1.0, 1.0, C_WHITE, C_BLACK, C_YELLOW);
  Horiz.init  (60, 200, 240, 0, 9, 1.0, 1.0, C_WHITE, C_BLACK, C_GREEN);
  Horiz.setHandleShape(5);
  Horiz.setHandleSize(16);
  Vert.setHandleShape(5);
  Vert.setHandleSize(16);
  Display.begin();
  Touch.InitTouch(PORTRAIT);
  Touch.setPrecision(PREC_EXTREME);
  Display.invertDisplay(false);
  Display.fillScreen(C_BLACK);
  analogWrite(LCD_PIN, 255);
  Display.setRotation(Rotation);
  Display.setTextSize(2);
  Display.setTextColor(C_WHITE, C_BLACK);
  Display.setFont(FONT);
  Horiz.draw(HorizVal);
  Vert.draw(VertVal);
  Display.setCursor(50, 20); Display.print((int)Vert.value);//
  Display.setCursor(200, 150); Display.print((int)Horiz.value); //
}


void loop() {
  if (Touch.dataAvailable()) {
    ProcessTouch();
    HorizVal =    Horiz.slide(BtnX, BtnY);
    VertVal =   Vert.slide(BtnX, BtnY);
    if (Vert.changed())
    {
      Display.fillRect (50, 20, 50, 50, C_BLACK);
      Display.setCursor(50, 20); Display.print((int)Vert.value);//
    }
    else if (Horiz.changed())
    {
      Display.fillRect (200, 150, 20, 20, C_BLACK);
      Display.setCursor(200, 150); Display.print((int)Horiz.value); //
    }
  }
}
//********************************************
void ProcessTouch() {
  Touch.read();
  BtnX = Touch.getX();
  BtnY = Touch.getY();

#if defined USE_YELLOW_HEADERS
  // tft with yellow headers
  BtnX  = map(BtnX, 240, 0, 320, 0);
  BtnY  = map(BtnY, 379, 0, 240, 0);
#endif

#if defined USE_BLACK_HEADERS
  // tft with black headers
  BtnX  = map(BtnX, 0, 240, 320, 0);
  BtnY  = map(BtnY, 0, 380, 240, 0);
#endif
}
 
a couple of very silly mistakes on my part, but fixed either grab the new .h and .cpp files. or I can indicate the lines to edit in these files.
 
Thank you again Kris. Here's the current action:

MidiBlock2.jpg

Horiz slider indicates that we're looking at Block 2 of 10. Now that individual item color selection is working, next is to play with how colors are addressed..
 
As far as color seletion goes, have built a HSV-based approach which provides 16 colors and 16 levels each of Saturation and Value which works well with the display. Colors are chosen with eg. Ox0FF gives color 0 (Red), Sat15,Value15. R,G and B output values are restricted to 4-bit as AFAICT, the display does not respond to any more than that.
Just back to it after some travels and am seeing a bag of compiler complaints wrt the new lib fix and I don't think my code is an issue as it works fine on the previous. So, looking at the Multi-screen example, here's the last few lines typical of what fills many screens of compiler output:

Code:
^C:\Users\Pat\Documents\Arduino\libraries\ILI9341_t3_controls\ILI9341_t3_Controls.cpp:781:159: error: 'uint16_t' was not declared in this scope void SliderV::init(uint16_t SliderX, uint16_t SliderY, uint16_t SliderH, float ScaleLow, float ScaleHi, float ScaleSize, float SnapSize,uint16_t SliderColor, uint16_t BackgroundColor, uint16_t HandleColor ) {                                                                                                                                                               ^C:\Users\Pat\Documents\Arduino\libraries\ILI9341_t3_controls\ILI9341_t3_Controls.cpp:781:185: error: 'uint16_t' was not declared in this scope void SliderV::init(uint16_t SliderX, uint16_t SliderY, uint16_t SliderH, float ScaleLow, float ScaleHi, float ScaleSize, float SnapSize,uint16_t SliderColor, uint16_t BackgroundColor, uint16_t HandleColor ) {                                                                                                                                                                                         ^Using library SPI at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\SPI Using library ILI9341_t3 at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\ILI9341_t3 Using library UTouch in folder: C:\Users\Pat\Documents\Arduino\libraries\UTouch (legacy)Using library ILI9341_t3_controls in folder: C:\Users\Pat\Documents\Arduino\libraries\ILI9341_t3_controls (legacy)Error compiling for board Teensy 3.5.

Thanks for your support, this Library is fun to play with.
 
Need to add */ at line 34 of ILI9341_t3_Controls.h to shut the compiler complaints up.

Been busy down the Touch rabbithole.

Utouch although has excellent oversampling gives spurious touch output that can randomly trigger nearby touch elements and happens more so with higher CPU speeds.

The Teensy XP-2046 touch lib lacks the oversampling of Utouch and although it works on T3.2 - T4.1, needs some love and digging through it's library noted a TODO by @Paul wrt oversampling. Hmmm, my project needs to use a T4x.

Looking More closely at Utouch discovered that at 24 Mhz and lower, NO spurious touch data is present.

Am using a Teensy LC @24 Mhz as a "Touch co-processor" configured to send via I2C EasyTransfer to the main board.

There are probably more elegant ways of getting decent touch data but my coding skills are probably of Grade School standard. Ordering more LC's, am sure the spare pins on the LC will be put to good use.
 
Thanks the issue was in the .cpp file.


I actually use both touch drivers depending on my display. Some of my TFT's share the SPI nicely hence the XP-2046 is my first choice, other displays I need dedicated SPI lines. I generally try to use large buttons and such for touch objects and may mask the issues you are referring to. Good tips though.
 
Oops, PEBCAK typo, sorry.

Just climbed out of the ILI_t3_Controls lib rabbithole with a pic speaking of 2k+ lines of code.

Msliders.jpg
The cursor colors were first separated from the handle color and then the transparent cursors were created as additional HandleShapes. Here's a take on using what's been added.

Code:
  sRow1_BlockSel.setHandleShape(10); //Transparent double triangle
  sRow1_BlockSel.setTickColor(Get565Wheel(0x2FF)); // My way  of relating 
// an onscreen number to a possible color without having to find it.
  sRow1_BlockSel.setCursorOutline(Get565Wheel(0x699));
  sRow1_BlockSel.setCursorFill   (Get565Wheel(0x699));

Thinking of adding a few more Handles like say an uppercase Y rotated 90Deg and setCursorOffset for Triangular cursors as well, then dig into why the bottom Tick is not visible after a dynamic init. Note that the rightmost sliders have the bottom tick as are called in void setup().

Not obvious here is a functional Midi output handler currently supporting CCs, NRPNs and several flavors of System Exclusive, yet to add output Port/ Cable handlers.

Adding .setDisableColor(s) as well as you need to think about how to use them when you get esoteric with color schemes. Interestingly, when a Slider is disabled, it still responds to external input. Am not thinking this is a problem, instead a useful feature in that a disabled Slider can be used as a Midi input value monitor and be configured to convert say a CC or NRPN message to Sysex or whatever.
 
Today's pic, everything works, no artefacts.

LockdownIV.jpg

Never figured where the bottom ticks went, just how to put them there.

Ditched the idea of a horizontal uppercase Y cursor for now at least and came up with the skinny triangle instead. Added setTriangleOffset which affects all triangle-based cursors. The rectangle just had to be created simply coz that's what many real hardware EQ's have.

Have also separated the Touch pickup area from HANDLESIZE so you can have a big cursor and avoid any ambiguity as it can be easy to move two adjacent sliders. A positive side-effect would likely be that this will filter out at least some spurious touch data although have not actually tested this yet.

As it stands, you can touch anywhere along the length of the slider and the cursor snaps to that location.
Would be great if you could pick up the cursor and not have it move unless you drag it if you get my drift.

Be delighted to hand up my efforts to be inserted into your library.
 
@KrisKasprzak -- Updating, >6k lines of working code now have full two-way Sysex comms with Roland JV-1080, mapped to two rows of 296 SliderElements. Time for some fresh dedicated hardware to free up the dev kit.

Am thinking of another block of 16 encoders and a second screen. Hardware wise, it looks a simple matter to connect another display up but am venturing into unchartered code waters here.

What needs to be done to get this lib working across two displays?
 
You shouldn’t need to do anything Different to get sliders to work on a second displaying. Just create a second display object and a second touch object, then pass your display object to the slider objects that need to show up on that screen and that should be good. If you get stuck I’ll see if I can work up some sample code
 
Got it! playing around with the Multi example have sliders on two screens.
Now for a general programming question wrt inits.
In the Multi example we have this bit:-
Code:
  // initialize sliders
  sBand1.init(BAND1, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand2.init(BAND2, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand3.init(BAND3, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand4.init(BAND4, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand5.init(BAND5, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand6.init(BAND6, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand7.init(BAND7, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
  sBand8.init(BAND8, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
How would I call inits numerically rather than by name so we might end up with something like:-
Code:
initBand(bandNumber,BAND1, TOP, HEIGHT, MINDB, MAXDB, TickSetting, SnapSetting, SLIDECOLOR, BackColor, HANDLECOLOR);
inside a loop instead of my amateurish repeated blocks of pretty much the same code/
 
Okay, never mind the exterior. Using @luni's shift register EncoderTool.

UM, a couple of years later...

Ran out of memory with a T3.2 so the messy rainbow breaks a T3.6 into it's place. The 8x8 button matrix is 4x Adafruit NeoTrellis. A T4.0 drives it and it sends Midi CC messages via serial Midi to the T3.6. Will probably replace it with a Launchpad Mini.

Row 1 is for utility functions, Get Patch, Get everything, send Patches whatever.
Row 2 selects which Perform (Multitimbral) Part we're looking at.
Rows 3 - 8 select which of 48 Blocks of up to sixteen Parameters we're looking at.

Top right of screen exits to a menu. The black 1 in the white rectangle tells us which of three Roland JV's we're looking at. 0 and 1 look at JV-1080's, 2 looks at a JV-2080.

Overview.jpg

The underlying Midi controller engine's data structure holds data for 2 x 384 control Elements, like every darn configurable Value, Address, CC numbers, Channel, sysex message type, handle size, tick color whatever. Why 384? Need to be mindful of ticking the Stack. Everything I need to load up a JV-2080 fits leaving a handful of Blocks for other stuff.

Current compile stats indicate 75% Ram, 88% makes the T3.6 do odd stuff, not crash but can crash the Synth.

Now, to make it speak Roland, yep more data structures, replicating the various patches and other data is added to list stuff like parameter value ranges, other bits and pieces to deal with "special case" messages and potentially the entire list of Element display attributes. Much is done globally, this thing will go nuts on a T4.1.

When all that stuff's organized, a bunch of Inits sets the whole mess up in Midi controller proper.
More data arrays exist to hold JV System foundations, a Temporary Patch, eight Perform parts and the 8 associated Patches and then multiply that to cover three separate Synths.

Menu.jpg
Green next to Part 1 indicates we're in Perform mode, Synth 2 looking at Block 16 when we exit. Pressing Mode toggles Synth mode and the green button turns red to indicate Patch mode.
JV1_P4_Blk_43.jpg
We're looking at Synth 1, Part 4, Block 43.
PatchCommonFX.jpg
Here we're looking at Synth 0, Patch Mode, Part 1 is selected.
This is the result of a JV "special case". Not all EFX parameters are used for a given EFX type.
PerfCommFX.jpg
Here we're looking at Synth 0, Perform Mode, Part1. EFX Parameter range and function can appear anywhere, therein lurks another database.
JV2080_perfPart.jpg
Here we're looking at Synth 2, Perform Mode, Part5, Block 10 shows we have the JV-2080 sussed.

The madness of supporting three synths struck about a week and a half ago. Currently wrestling with more arrays to track what most "special case" parameters were doing for each particular Patch and each particular Part across the three synths. so far so good, prob 20% completed. Otherwise, every flamin, knob works, and to cap it off, somebody had the good sense to build an index into the works, primarily to assist with "special cases" eg. where one parameter is spread across more than a single 0x0 - 0x7F. The end result once all the Roland stuff is instantiated, the mechanism exists for user - organized layouts. currently no user interface for that, just a hard-coded nudge to show that it works.

Have an auto-pull data from a given synth kind of mechanism working, mulling over auto-detect Synth type (JV_1080 or JV-2080 and what added resources like Expansion Rom packs a JV may have.

A few built-in quirks, Some blocks contain CC controller elements for Mod, Foot, Vol etc, one for each part. When a Temp Patch is sent, a snapshot of CC elements current values is sent as well.

Another relates to variable encoder resolution sort of tied to value range. Using 96 PPR encoders, Max resolution works well for 0-127 if it's for Level but for 0-127 for Filter Cutoff a lesser resolution feels best so inevitably wil ditch the lut and add an EncResolution parameter to to each Roland parameter. Darn excellent Synths, deserve decent knobs.
 
Last edited:
Now have support for Roland JV-1080, JV-2080, JV-1010, XP-30, XP-50 and XP-60.

Has been extensively tested on the first two, looking forward to trying it on a friend's XP-30.
 
Back
Top