Touch Shield Piano

  • This project uses a 2.8" TFT Touch Screen for input and output (background display) and a standard simple speaker for audio output
  • It must be used with Arduino IDE ver. 1.0.1 -- the TFT library it depends upon does NOT compile correctly under version 1.0.3; other versions are untested.
  • This sketch requires the Adafruit TFT/Touchscreen libraries available from https://github.com/adafruit/Touch-Screen-Library

Hardware Required

 1 x Arduino Uno or Arduino Mega
 1 x Seeeduino Touch Shield, ver. 1.0 (2.8" TFT)
 1 x 8-Ohm Speaker

The Sketch

 // Adapted from the Adafruit Paint application included with the TFT/Touchscreen library package to demonstrate both TFT and Touch Screen
 // Code modified to draw a piano style keyboard and assign proper pitches to those keys so that they play the correct note when touched
 // It is recommended to use a PDA type stylus for added touch precision with this sketch, as the piano keys are pretty small
 // *** BE SURE TO SET THE "speaker" PIN VALUE CORRECTLY FOR YOUR ARDUINO BOARD ***
 // Ver. 1.0 - Clay Furman   20 DEC 2012

 #include <stdint.h>
 #include <TouchScreen.h>
 #include <TFT.h>

 const int speaker=19; //Pin to which the speaker is connected -- use 19 (this is the A5 pin, as a digital output) for Uno or 53 for Mega

 //Define frequencies for each of the possible notes
 #define NOTE_F3  175
 #define NOTE_FS3 185
 #define NOTE_G3  196
 #define NOTE_GS3 208
 #define NOTE_A3  220
 #define NOTE_AS3 233
 #define NOTE_B3  247
 #define NOTE_C4  262
 #define NOTE_CS4 277
 #define NOTE_D4  294
 #define NOTE_DS4 311
 #define NOTE_E4  330
 #define NOTE_F4  349
 #define NOTE_FS4 370
 #define NOTE_G4  392
 #define NOTE_GS4 415
 #define NOTE_A4  440
 #define NOTE_AS4 466
 #define NOTE_B4  494
 #define NOTE_C5  523
 #define NOTE_CS5 554
 #define NOTE_D5  587
 #define NOTE_DS5 622
 #define NOTE_E5  659
 #define NOTE_F5  698
 #define NOTE_FS5 740
 #define NOTE_G5  784
 #define NOTE_GS5 831
 #define NOTE_A5  880
 #define NOTE_AS5 932
 #define NOTE_B5  988
 #define NOTE_C6  1047
 #define NOTE_CS6 1109
 #define NOTE_D6  1175

 //Measured ADC values for (0,0) and (210-1,320-1)
 //TS_MINX corresponds to ADC value when X = 0
 //TS_MINY corresponds to ADC value when Y = 0
 //TS_MAXX corresponds to ADC value when X = 240 -1
 //TS_MAXY corresponds to ADC value when Y = 320 -1

 static unsigned int TS_MINX, TS_MAXX, TS_MINY, TS_MAXY;

 //Touch Screen Co-ordinate mapping register
 static unsigned int MapX1, MapX2, MapY1, MapY2;

 /* Usage: TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); 
   Where, XP = X plus, YP = Y plus, XM = X minus and YM = Y minus */
 //init TouchScreen port pins. This would be reinitialized in setup() based on the hardware detected.
 TouchScreen ts = TouchScreen(17, A2, A1, 14, 300); 

 int color = BLUE;  //Default Paint brush color
 int duration=250; //Default value for the tone duration
 int wait=300; //Default time to wait between notes

 void setup()
 {
    Tft.init();  //init TFT library
    initTouchScreenParameters(); // initializes Touch Screen parameters based on the detected TFT Touch Shield hardware

   // Serial.begin(9600); //debug

    //Draw the white keys on the keyboard
    for (int i=0; i<21; i++) {
    Tft.fillRectangle(0,i*16,240,15,WHITE);
    }
    //Draw the black keys on the keyboard
    Tft.fillRectangle(0,11,140,11,BLACK);
    Tft.fillRectangle(0,43,140,11,BLACK);
    Tft.fillRectangle(0,59,140,11,BLACK);
    Tft.fillRectangle(0,75,140,11,BLACK);
    Tft.fillRectangle(0,107,140,11,BLACK);
    Tft.fillRectangle(0,123,140,11,BLACK);
    Tft.fillRectangle(0,155,140,11,BLACK);
    Tft.fillRectangle(0,171,140,11,BLACK);
    Tft.fillRectangle(0,187,140,11,BLACK);
    Tft.fillRectangle(0,219,140,11,BLACK);
    Tft.fillRectangle(0,235,140,11,BLACK);
    Tft.fillRectangle(0,267,140,11,BLACK);
    Tft.fillRectangle(0,283,140,11,BLACK);
    Tft.fillRectangle(0,299,140,11,BLACK);

 }

 void loop()
 {

   // Serial.println(Tft.IC_CODE,HEX); //debug

    // a point object holds x y and z coordinates.
    Point p = ts.getPoint();

    // we have some minimum pressure we consider 'valid'
    // pressure of 0 means no pressing!

    if (p.z > ts.pressureThreshhold) {

    //map the ADC value read to into pixel co-ordinates

    p.x = map(p.x, TS_MINX, TS_MAXX, MapX1, MapX2);
    p.y = map(p.y, TS_MINY, TS_MAXY, MapY1, MapY2);

        // Determine if the key played is in the potential sharp side or not
        if(p.x < 140)
        {
            Tft.fillCircle(p.x,p.y,2,color);
            //Key might be a sharp -- split Y axis into black and white keys
            if (p.y>=0 && p.y<=10) tone(speaker,NOTE_D6, duration);
            if (p.y>=11 && p.y<=21) tone(speaker,NOTE_CS6, duration);
            if (p.y>=22 && p.y<=31) tone(speaker,NOTE_C6, duration);
            if (p.y>=33 && p.y<=42) tone(speaker,NOTE_B5, duration);
            if (p.y>=43 && p.y<=53) tone(speaker,NOTE_AS5, duration);
            if (p.y>=54 && p.y<=58) tone(speaker,NOTE_A5, duration);
            if (p.y>=59 && p.y<=69) tone(speaker,NOTE_GS5, duration);
            if (p.y>=70 && p.y<=74) tone(speaker,NOTE_G5, duration);
            if (p.y>=75 && p.y<=85) tone(speaker,NOTE_FS5, duration);
            if (p.y>=86 && p.y<=95) tone(speaker,NOTE_F5, duration);
            if (p.y>=97 && p.y<=106) tone(speaker,NOTE_E5, duration);
            if (p.y>=107 && p.y<=117) tone(speaker,NOTE_DS5, duration);
            if (p.y>=118 && p.y<=122) tone(speaker,NOTE_D5, duration);
            if (p.y>=123 && p.y<=133) tone(speaker,NOTE_CS5, duration);
            if (p.y>=134 && p.y<=143) tone(speaker,NOTE_C5, duration);
            if (p.y>=145 && p.y<=154) tone(speaker,NOTE_B4, duration);
            if (p.y>=155 && p.y<=165) tone(speaker,NOTE_AS4, duration);
            if (p.y>=166 && p.y<=170) tone(speaker,NOTE_A4, duration);
            if (p.y>=171 && p.y<=181) tone(speaker,NOTE_GS4, duration);
            if (p.y>=182 && p.y<=186) tone(speaker,NOTE_G4, duration);
            if (p.y>=187 && p.y<=197) tone(speaker,NOTE_FS4, duration);
            if (p.y>=198 && p.y<=207) tone(speaker,NOTE_F4, duration);
            if (p.y>=209 && p.y<=218) tone(speaker,NOTE_E4, duration);
            if (p.y>=219 && p.y<=229) tone(speaker,NOTE_DS4, duration);
            if (p.y>=230 && p.y<=234) tone(speaker,NOTE_D4, duration);
            if (p.y>=235 && p.y<=245) tone(speaker,NOTE_CS4, duration);
            if (p.y>=246 && p.y<=255) tone(speaker,NOTE_C4, duration);
            if (p.y>=257 && p.y<=266) tone(speaker,NOTE_B3, duration);
            if (p.y>=267 && p.y<=277) tone(speaker,NOTE_AS3, duration);
            if (p.y>=278 && p.y<=282) tone(speaker,NOTE_A3, duration);
            if (p.y>=283 && p.y<=293) tone(speaker,NOTE_GS3, duration);
            if (p.y>=294 && p.y<=298) tone(speaker,NOTE_G3, duration);
            if (p.y>=299 && p.y<=309) tone(speaker,NOTE_FS3, duration);
            if (p.y>=310 && p.y<=319) tone(speaker,NOTE_F3, duration);

        }
        else
        {
            //Key is too far along X axis to be sharp -- split Y axis into white keys only
            Tft.fillCircle(p.x,p.y,2,color);
            if (p.y>=0 && p.y<=15) tone(speaker,NOTE_D6, duration);
            if (p.y>=17 && p.y<=31) tone(speaker,NOTE_C6, duration);
            if (p.y>=33 && p.y<=47) tone(speaker,NOTE_B5, duration);
            if (p.y>=49 && p.y<=63) tone(speaker,NOTE_A5, duration);
            if (p.y>=65 && p.y<=79) tone(speaker,NOTE_G5, duration);
            if (p.y>=81 && p.y<=95) tone(speaker,NOTE_F5, duration);
            if (p.y>=97 && p.y<=111) tone(speaker,NOTE_E5, duration);
            if (p.y>=113 && p.y<=127) tone(speaker,NOTE_D5, duration);
            if (p.y>=129 && p.y<=143) tone(speaker,NOTE_C5, duration);
            if (p.y>=145 && p.y<=159) tone(speaker,NOTE_B4, duration);
            if (p.y>=161 && p.y<=175) tone(speaker,NOTE_A4, duration);
            if (p.y>=177 && p.y<=191) tone(speaker,NOTE_G4, duration);
            if (p.y>=193 && p.y<=207) tone(speaker,NOTE_F4, duration);
            if (p.y>=209 && p.y<=223) tone(speaker,NOTE_E4, duration);
            if (p.y>=225 && p.y<=239) tone(speaker,NOTE_D4, duration);
            if (p.y>=241 && p.y<=255) tone(speaker,NOTE_C4, duration);
            if (p.y>=257 && p.y<=271) tone(speaker,NOTE_B3, duration);
            if (p.y>=273 && p.y<=287) tone(speaker,NOTE_A3, duration);
            if (p.y>=289 && p.y<=303) tone(speaker,NOTE_G3, duration);
            if (p.y>=305 && p.y<=319) tone(speaker,NOTE_F3, duration);  

        }
        //Wait for the tone to play -- you can adjust the scalar to make the gap between tones more pronounced -- and then kill the tone output to prepare for the next cycle
        wait=duration*1;
        delay(wait);
        noTone(speaker);

    }

 }

 void initTouchScreenParameters()
 {
    //This function initializes Touch Screen parameters based on the detected TFT Touch Schield hardware

    if(Tft.IC_CODE == 0x5408) //SPFD5408A TFT driver based Touchscreen hardware detected
    {
 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
        ts = TouchScreen(54, A1, A2, 57, 300); //init  TouchScreen port pins
 #else 
        ts = TouchScreen(14, A1, A2, 17, 300); //init TouchScreen port pins
 #endif
        //Touchscreen parameters for this hardware
        TS_MINX = 120;
        TS_MAXX = 910;
        TS_MINY = 120;
        TS_MAXY = 950;

        MapX1 = 239;
        MapX2 = 0;
        MapY1 = 0;
        MapY2 = 319;
    }
    else //ST7781R TFT driver based Touchscreen hardware detected
    {
 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
        ts = TouchScreen(57, A2, A1, 54, 300); //init TouchScreen port pins
 #else 
        ts = TouchScreen(17, A2, A1, 14, 300); //init TouchScreen port pins
 #endif 

        //Touchscreen parameters for this hardware
        TS_MINX = 140;
        TS_MAXX = 900;
        TS_MINY = 120;
        TS_MAXY = 940;

        MapX1 = 239;
        MapX2 = 0;
        MapY1 = 319;
        MapY2 = 0;
    }
 }

Use

  • To play the piano, simply touch the "keys" displayed on the screen -- a PDA stylus is recommended because the keys are pretty small.

Enjoy! cfurman

Share