Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: Wavetable Synth with TFT ILI9341 Display, interpolating issues

  1. #1
    Junior Member
    Join Date
    Nov 2020
    Location
    Germany
    Posts
    14

    Wavetable Synth with TFT ILI9341 Display, interpolating issues

    Hello!

    Currently I am trying to build a step sequencer where I can draw four individual waves with the TFT ILI9341 Display and put them on any of the 16 steps. I was trying to interpolate between the points where the screen didn't record any values but for some reason, the screen behaves in an odd way.

    Click image for larger version. 

Name:	WhatsApp Image 2021-01-19 at 12.42.53.jpg 
Views:	13 
Size:	87.2 KB 
ID:	23346

    main.cpp:
    Code:
    #include <Arduino.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #include <Encoder.h>
    #include "Display.h"
    #include "Sequencer.h"
    
    Display display;
    Sequencer sequencer;
    
    int b1 = 0;
    int b2 = 0;
    int b3 = 0;
    int b4 = 0;
    
    void ADSR(float att, float dec, float sus, float rel)
    {
      // b1 = digitalRead(20);
      b2 = digitalRead(2);
      b3 = digitalRead(3);
      b4 = digitalRead(4);
    }
    
    void setup()
    {
      display.init();
    }
    
    void loop()
    {
      display.update();
      sequencer.update();
    }
    Display.h:
    Code:
    #ifndef Display_h
    #define Display_h
    #include <array>
    #include <SPI.h>
    #include <ILI9341_t3.h>
    #include <font_Arial.h>
    #include <XPT2046_Touchscreen.h>
    
    class Display
    {
    public:
      Display();
      // int getX();
      // int getY();
      void fillWaveArray();
      void clear();
      void init();
      void drawButtons();
      void start();
      void touchButton();
      int16_t *getArray();
      float loPass(float xInput, float xOutput);
      boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH);
      boolean isTouched();
      TS_Point getPoint();
      void update();
      void linearInterpolation(TS_Point pTS);
      boolean previousIsTouched;
     // float mapper(float x, float in_min, float in_max, float out_min, float out_max);
      int X_old;
      int X;
      int maximumX = 256;
      int minimumX = 0;
      int maximumY = 32767;
      int minimumY = -32767;
      void draw(TS_Point pTS);
      int _heightSquare = 20;
      int _widthSquare = 75;
      int _gap = 4;
      int _beyondDisplay = 400; // Value to use for the else statement of the getX / getY methods
      int _radiusOfRoundCorner = 3;
      int16_t initValue;
      int16_t wave1Values[257] = {initValue};
      int _x;
      int _y;
      boolean _touched;
    
    private:
      XPT2046_Touchscreen ts;
      ILI9341_t3 tft;
      int pointRadius = 2;
      char buttonNames[4][10] = { //First bracket indicates the amount of words
          "Clear",                // second bracket indicates the amount of maximal letters for one string
          "<----",
          "---->",
          "Waves"};
    };
    
    #endif
    Display.cpp:
    Code:
    #include "Display.h"
    
    // XPT2046_Touchscreen ts(CS_PIN); // Instanziierung eines ts Objekts der Klasse XPT2046_Touchscreen
    // ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
    #define TIRQ_PIN 2
    #define CS_PIN 8
    #define TFT_DC 9
    #define TFT_CS 10
    
    Display::Display() : ts(CS_PIN), tft(TFT_CS, TFT_DC)
    {
    }
    
    // Original raw minimum and maximum values:
    // X --> 340 bis 3900
    // Y --> 200 bis 3850
    
    boolean Display::isTouched()
    {
        return ts.touched();
    }
    
    TS_Point Display::getPoint()
    {
        int16_t xScaled{0};
        int16_t yScaled{0};
        TS_Point pUnscaled = ts.getPoint(); // point getter function
        if (map(pUnscaled.x, 340, 3900, maximumX, minimumX) < minimumX)
        {
            xScaled = minimumX;
        }
        else if (map(pUnscaled.x, 340, 3900, maximumX, minimumX) > maximumX)
        {
            xScaled = maximumX;
        }
        else
        {
            xScaled = map(pUnscaled.x, 340, 3900, maximumX, minimumX);
        }
    
        if (map(pUnscaled.y, 200, 3850, maximumY, minimumY) < minimumY)
        {
            yScaled = minimumY;
        }
    
        else if (map(pUnscaled.y, 200, 3850, maximumY, minimumY) > maximumY)
        {
            yScaled = maximumY;
        }
        else
        {
            yScaled = map(pUnscaled.y, 200, 3850, maximumY, minimumY);
        }
        TS_Point pScaled{xScaled, yScaled, 0};
        return pScaled;
    }
    
    int16_t *Display::getArray()
    {
        return wave1Values;
    }
    
    void Display::drawButtons()
    {
        for (int i{0}; i < 4; ++i)
        {
            tft.fillRoundRect(_gap + (_gap + _widthSquare) * i, 220, _widthSquare, _heightSquare, _radiusOfRoundCorner, CL(250, 0, 0));
            tft.setCursor(26 + ((_gap + _widthSquare) * i), 227);
            tft.print(buttonNames[i]);
        }
        tft.drawLine(0, 120, 320, 120, CL(255, 255, 255));
        tft.drawLine(0, 121, 320, 121, CL(255, 255, 255));
        tft.drawLine(0, 119, 320, 119, CL(255, 255, 255));
    }
    
    void Display::clear()
    {
        tft.fillScreen(ILI9341_BLACK);
        drawButtons();
    }
    
    void Display::start()
    {
        Serial.begin(38600);
        tft.begin();
        tft.setRotation(1);
        tft.fillScreen(ILI9341_BLACK);
        ts.begin();
        ts.setRotation(1);
        while (!Serial && (millis() <= 1000))
            ; // weiß nicht was das ist
    }
    
    boolean Display::pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
    {
        boolean ret = false;
        if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
        {
            ret = true;
        }
        return ret;
    }
    
    void Display::touchButton()
    {
        if (pointInRect(_x, _y, _gap, (240 - _heightSquare), (_widthSquare), (_heightSquare)))
        {
            tft.fillRoundRect(_gap, (240 - _heightSquare), _widthSquare, _heightSquare, _radiusOfRoundCorner, CL(250, 100, 0));
            clear();
            // clearArray();
        }
    }
    
    void Display::draw(TS_Point pTS)
    {
        wave1Values[pTS.x] = pTS.y;
     //   Serial.println(*getArray());
    
        for (int i{0}; i < 257; ++i)
        {
            tft.fillCircle(map(i, 0, 256, 0, 320), map(wave1Values[i], -32767, 32767, 0, 240), pointRadius, CL(255, 0, 0));
        }
    }
    
    /* float Display::mapper(float x, float in_min, float in_max, float out_min, float out_max)
    {
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    } */
    
    void Display::linearInterpolation(TS_Point pTS)
    {
        if (X_old <= pTS.x)
        {
            for (int i = X_old; i < pTS.x; ++i)
            {
                wave1Values[i] = map(i, X_old, pTS.x, wave1Values[X_old], wave1Values[pTS.x]);
            }
        }
        else
        {
            for (int i = pTS.x; i < X_old; ++i)
            {
                wave1Values[i] = map(i, X_old, pTS.x, wave1Values[X_old], wave1Values[pTS.x]);
            }
        }
        X_old = pTS.x;
    }
    
    void Display::init()
    {
        start();
        clear();
        drawButtons();
    }
    
    void Display::update()
    {
        if (isTouched())
        {
            TS_Point pTS = getPoint();
            if (previousIsTouched)
            {
                linearInterpolation(pTS);
            }
            touchButton();
            clear();
            draw(pTS);
        }
        previousIsTouched = isTouched();
    }

  2. #2
    Senior Member
    Join Date
    Jul 2020
    Posts
    682
    The logic doesn't look good in linearInterpolation... First you are not dealing with any edge cases, such as when X_old == pTS.x.
    Second you are overwriting wave1Values[Xold] the first time round the loop - you should only be updating the entries between
    the endpoints I think.

    Thirdly where does wave1Values[pTS.x] get initialized before linearInterpolation() is called? Can't figure this out.

    Normally Bressenham's would be used for this, and you'd pass in the two x,y pairs for the line segment endpoints and it would
    draw all the points as it goes.

  3. #3
    Junior Member
    Join Date
    Nov 2020
    Location
    Germany
    Posts
    14
    Hello Mark! Thank you for your reply! The problem was actually solved by initializing the wave1Values array at the beginning of the linearInterpolation function. If I understood you right, thats what you meant too..
    Before that, the wave1Values array was initialized in the Display::draw function.

    the new linearInterpolation function:
    Code:
    void Display::linearInterpolation(TS_Point pTS)
    {
        wave1Values[pTS.x] = pTS.y;
    
        if (X_old <= pTS.x)
        {
            for (int i = X_old; i < pTS.x; ++i)
            {
                wave1Values[i] = map(i, X_old, pTS.x, wave1Values[X_old], wave1Values[pTS.x]);
            }
        }
    
        else
        {
            for (int i = pTS.x; i < X_old; ++i)
            {
                wave1Values[i] = map(i, X_old, pTS.x, wave1Values[X_old], wave1Values[pTS.x]);
            }
        }
        X_old = pTS.x;
    }

  4. #4
    Senior Member
    Join Date
    Jul 2020
    Posts
    682
    I guess I was saying either use a standard Bressenham's or write something cleaner without the arbitrary mix of global variables and
    passed arguments. For me a nice clean interface would be a function you pass two points to and it draws a line on the screen.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •