├── Factory Scripts ├── MusicGen.littlefootModes │ ├── A min.mode │ ├── C Maj.mode │ ├── E min.mode │ ├── F Maj.mode │ └── G Maj.mode ├── Seaboard.littlefootModes │ ├── Piano.mode │ ├── MPE.mode │ ├── Multi Channel.mode │ └── Single Channel.mode ├── Note Grid.littlefootModes │ ├── MPE.mode │ ├── Multi Channel.mode │ └── Single Channel.mode ├── Drum Block.littlefootModes │ ├── 2x2 MPE Mode.mode │ ├── 3x3 MPE Mode.mode │ ├── 4x4 MPE Mode.mode │ ├── 2x2 Multi Channel Mode.mode │ ├── 3x3 Multi Channel Mode.mode │ ├── 4x4 Multi Channel Mode.mode │ ├── 2x2 Single Channel Mode.mode │ ├── 3x3 Single Channel Mode.mode │ └── 4x4 Single Channel Mode.mode ├── BLOCKSvaders.littlefoot ├── BreakBLOCKS.littlefoot ├── RISE Controller.littlefoot ├── Fader Block.littlefoot ├── XYZ Pad.littlefoot ├── Mixer Block.littlefoot ├── MusicGen.littlefoot ├── Control Grid.littlefoot └── Drum Block.littlefoot ├── Example Scripts ├── PressureMap.littlefoot ├── BuzzyBee.littlefoot ├── SonOfPong.littlefoot ├── DynamicParameters.littlefoot ├── ColourPressureMap.littlefoot ├── Mario.littlefoot ├── Pacman.littlefoot ├── TicTacToe.littlefoot └── MusicGen.littlefoot └── LICENSE.txt /Factory Scripts/MusicGen.littlefootModes/A min.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Factory Scripts/MusicGen.littlefootModes/C Maj.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Factory Scripts/MusicGen.littlefootModes/E min.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Factory Scripts/MusicGen.littlefootModes/F Maj.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Factory Scripts/MusicGen.littlefootModes/G Maj.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example Scripts/PressureMap.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | */ 5 | 6 | void touchStart (int index, float x, float y, float z, float vz) 7 | { 8 | addPressurePoint (0xffffff, x, y, z * 100.0); 9 | } 10 | 11 | void touchMove (int index, float x, float y, float z, float vz) 12 | { 13 | addPressurePoint (0xffffff, x, y, z * 20.0); 14 | } 15 | 16 | void repaint() 17 | { 18 | clearDisplay(); 19 | drawPressureMap(); 20 | fadePressureMap(); 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This software is distributed under the terms of the Creative Commons 2 | Public Domain Dedication [CC0]: 3 | 4 | To the extent possible under law, ROLI Ltd 5 | has waived all copyright, and related or neighboring rights, 6 | to this work. 7 | 8 | In no way are the patent or trademark rights of any person affected 9 | by CC0, nor are the rights that other persons may have in the work 10 | or in how the work is used, such as publicity or privacy rights. 11 | 12 | ROLI Ltd. makes no warranties about the work, and disclaims 13 | liability for all uses of the work, to the fullest extent permitted 14 | by applicable law. 15 | 16 | When using or citing the work, you should not imply endorsement by 17 | ROLI Ltd. 18 | -------------------------------------------------------------------------------- /Example Scripts/BuzzyBee.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | */ 8 | 9 | int x; 10 | int y; 11 | 12 | int xDir; 13 | int yDir; 14 | 15 | void repaint() 16 | { 17 | clearDisplay(); 18 | 19 | fillRect (beeColour, x, y, 2, 2); 20 | 21 | if (xDir == 0) 22 | { 23 | x += 1; 24 | if (x >= 13) 25 | { 26 | xDir = 1; 27 | } 28 | } 29 | else 30 | { 31 | if (x <= 1) 32 | { 33 | xDir = 0; 34 | } 35 | x -= 1; 36 | } 37 | 38 | if (yDir == 0) 39 | { 40 | y += 1; 41 | if (y >= 7) 42 | { 43 | yDir = 1; 44 | } 45 | } 46 | else if (yDir == 1) 47 | { 48 | if (y <= 1) 49 | { 50 | yDir = 2; 51 | y = 7; 52 | } 53 | else 54 | { 55 | y -= 1; 56 | } 57 | } 58 | else if (yDir == 2) 59 | { 60 | y += 1; 61 | if (y >= 13) 62 | { 63 | yDir = 3; 64 | } 65 | } 66 | else if (yDir == 3) 67 | { 68 | if (y <= 1) 69 | { 70 | yDir = 0; 71 | } 72 | y -= 1; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Example Scripts/SonOfPong.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | */ 5 | 6 | int ballX, ballY; 7 | bool ballXVec, ballYVec; 8 | bool hasStarted; 9 | 10 | int paddleL, paddleR; 11 | 12 | void repaint() 13 | { 14 | fillRect (0x000000, 0, 0, 15, 15); 15 | 16 | if (! hasStarted) 17 | { 18 | ballX = 7; 19 | ballY = 7; 20 | 21 | ballXVec = true; 22 | ballYVec = false; 23 | hasStarted = true; 24 | 25 | paddleL = 7; 26 | paddleR = 7; 27 | } 28 | 29 | if (ballXVec) 30 | { 31 | ballX += 1; 32 | if (ballX >= 13) 33 | { 34 | ballX = 13; 35 | ballXVec = false; 36 | } 37 | } 38 | else 39 | { 40 | if (ballX <= 2) 41 | { 42 | ballX = 2; 43 | ballXVec = true; 44 | } 45 | ballX -= 1; 46 | } 47 | 48 | if (ballYVec) 49 | { 50 | ballY += 1; 51 | if (ballY >= 15) 52 | { 53 | ballY = 15; 54 | ballYVec = false; 55 | } 56 | } 57 | else 58 | { 59 | if (ballY <= 1) 60 | { 61 | ballYVec = true; 62 | } 63 | ballY -= 1; 64 | } 65 | 66 | fillRect (0xFFFF00, ballX, ballY, 1, 1); 67 | 68 | fillRect (0xFFFF00, 0, paddleL - 2, 1, 5); 69 | fillRect (0xFFFF00, 14, paddleR - 2, 1, 5); 70 | } 71 | -------------------------------------------------------------------------------- /Factory Scripts/Seaboard.littlefootModes/Piano.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Factory Scripts/Seaboard.littlefootModes/MPE.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Factory Scripts/Seaboard.littlefootModes/Multi Channel.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Factory Scripts/Seaboard.littlefootModes/Single Channel.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example Scripts/DynamicParameters.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | */ 21 | 22 | void repaint() 23 | { 24 | clearDisplay(); 25 | 26 | if (draw) 27 | fillRect (makeARGB (int (alpha), red, green, blue), xPos, yPos, width, height); 28 | } 29 | -------------------------------------------------------------------------------- /Factory Scripts/Note Grid.littlefootModes/MPE.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Factory Scripts/Note Grid.littlefootModes/Multi Channel.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Factory Scripts/Note Grid.littlefootModes/Single Channel.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Example Scripts/ColourPressureMap.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | */ 12 | 13 | int getPressureColour (int index) 14 | { 15 | int col = pressureColour3; 16 | 17 | if (index == 1) 18 | { 19 | col = pressureColour0; 20 | } 21 | else if (index == 2) 22 | { 23 | col = pressureColour1; 24 | } 25 | else if (index == 3) 26 | { 27 | col = pressureColour2; 28 | } 29 | 30 | return col; 31 | } 32 | 33 | void touchStart (int index, float x, float y, float z, float vz) 34 | { 35 | addPressurePoint (getPressureColour (index), x, y, z * float (scaling)); 36 | } 37 | 38 | void touchMove (int index, float x, float y, float z, float vz) 39 | { 40 | addPressurePoint (getPressureColour (index), x, y, z * float (scaling)); 41 | } 42 | 43 | void repaint() 44 | { 45 | clearDisplay(); 46 | drawPressureMap(); 47 | fadePressureMap(); 48 | } 49 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/2x2 MPE Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/3x3 MPE Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/4x4 MPE Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/2x2 Multi Channel Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/3x3 Multi Channel Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/4x4 Multi Channel Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/2x2 Single Channel Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/3x3 Single Channel Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefootModes/4x4 Single Channel Mode.mode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Example Scripts/Mario.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | */ 5 | 6 | void repaint() 7 | { 8 | clearDisplay(); 9 | 10 | // Hands fill 11 | fillRect (makeARGB (255, 239, 193, 49), 2, 9, 12, 3); 12 | 13 | // Left foot 14 | fillRect (makeARGB (255, 64, 40, 3), 2, 14, 4, 1); 15 | fillRect (makeARGB (255, 64, 40, 3), 3, 13, 3, 1); 16 | 17 | // Right foot 18 | fillRect (makeARGB (255, 64, 40, 3), 10, 14, 4, 1); 19 | fillRect (makeARGB (255, 64, 40, 3), 10, 13, 3, 1); 20 | 21 | // Dungarees 22 | fillRect (makeARGB (255, 7, 0, 250), 4, 12, 3, 1); 23 | fillRect (makeARGB (255, 7, 0, 250), 9, 12, 3, 1); 24 | fillRect (makeARGB (255, 7, 0, 250), 4, 11, 8, 1); 25 | fillRect (makeARGB (255, 7, 0, 250), 5, 10, 6, 1); 26 | fillRect (makeARGB (255, 7, 0, 250), 5, 9, 1, 1); 27 | fillRect (makeARGB (255, 7, 0, 250), 7, 9, 2, 1); 28 | fillRect (makeARGB (255, 7, 0, 250), 10, 9, 1, 1); 29 | fillRect (makeARGB (255, 7, 0, 250), 6, 8, 4, 1); 30 | fillRect (makeARGB (255, 7, 0, 250), 6, 7, 1, 1); 31 | fillRect (makeARGB (255, 7, 0, 250), 9, 7, 1, 1); 32 | fillRect (makeARGB (255, 7, 0, 250), 6, 6, 1, 1); 33 | fillRect (makeARGB (255, 7, 0, 250), 9, 6, 1, 1); 34 | 35 | // Buttons 36 | fillRect (makeARGB (255, 251, 242, 57), 6, 9, 1, 1); 37 | fillRect (makeARGB (255, 251, 242, 57), 9, 9, 1, 1); 38 | 39 | // Shirt 40 | fillRect (makeARGB (255, 203, 34, 41), 7, 6, 2, 2); 41 | fillRect (makeARGB (255, 203, 34, 41), 4, 6, 2, 3); 42 | fillRect (makeARGB (255, 203, 34, 41), 10, 6, 2, 3); 43 | fillRect (makeARGB (255, 203, 34, 41), 3, 7, 1, 2); 44 | fillRect (makeARGB (255, 203, 34, 41), 2, 8, 1, 1); 45 | fillRect (makeARGB (255, 203, 34, 41), 4, 9, 1, 1); 46 | fillRect (makeARGB (255, 203, 34, 41), 12, 7, 1, 2); 47 | fillRect (makeARGB (255, 203, 34, 41), 13, 8, 1, 1); 48 | fillRect (makeARGB (255, 203, 34, 41), 11, 9, 1, 1); 49 | 50 | // Head 51 | fillRect (makeARGB (255, 239, 193, 49), 5, 1, 6, 5); 52 | fillRect (makeARGB (255, 239, 193, 49), 4, 1, 1, 3); 53 | fillRect (makeARGB (255, 239, 193, 49), 11, 2, 2, 2); 54 | fillRect (makeARGB (255, 239, 193, 49), 13, 3, 1, 1); 55 | 56 | // Moustache 57 | fillRect (makeARGB (255, 12, 12, 12), 9, 4, 4, 1); 58 | fillRect (makeARGB (255, 12, 12, 12), 10, 3, 1, 1); 59 | 60 | // Eyes 61 | fillRect (makeARGB (255, 12, 12, 12), 9, 1, 1, 2); 62 | 63 | // Hat 64 | fillRect (makeARGB (255, 203, 34, 41), 4, 0, 9, 1); 65 | 66 | // Hair 67 | fillRect (makeARGB (255, 64, 40, 3), 4, 2, 1, 2); 68 | fillRect (makeARGB (255, 64, 40, 3), 5, 4, 1, 1); 69 | fillRect (makeARGB (255, 64, 40, 3), 5, 1, 3, 1); 70 | fillRect (makeARGB (255, 64, 40, 3), 6, 1, 1, 3); 71 | fillRect (makeARGB (255, 64, 40, 3), 7, 3, 1, 1); 72 | } 73 | -------------------------------------------------------------------------------- /Example Scripts/Pacman.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | */ 5 | 6 | float position; 7 | float speed; 8 | 9 | int mouthWidth; 10 | float mouthSpeed; 11 | float mouthHeight; 12 | float mouthMaxHeight; 13 | 14 | bool msPacman; 15 | int pacmanSize; 16 | 17 | void initialise() 18 | { 19 | position = -14.0; 20 | speed = 0.3; 21 | 22 | mouthWidth = 9; 23 | mouthSpeed = 2.0; 24 | mouthHeight = 7.0; 25 | mouthMaxHeight = 12.0; 26 | 27 | msPacman = false; 28 | 29 | pacmanSize = 14; 30 | } 31 | 32 | void repaint() 33 | { 34 | clearDisplay(); 35 | 36 | int pos = int (position); 37 | 38 | paintFood (pos, 1); 39 | paintPacmanAt (pos, 1); 40 | paintPacmanMouthAt (pos, 1); 41 | 42 | if (msPacman) 43 | paintAccessories (pos, 1); 44 | 45 | update(); 46 | } 47 | 48 | void paintPacmanAt (int x, int y) 49 | { 50 | int colour = makeARGB (255, 255, 255, 0); 51 | 52 | fillRect (colour, x + 4, y, 5, 1); 53 | fillRect (colour, x + 2, y + 1, 9, 1); 54 | fillRect (colour, x + 1, y + 2, 11, 1); 55 | fillRect (colour, x + 1, y + 3, 11, 1); 56 | fillRect (colour, x + 0, y + 4, 13, 1); 57 | fillRect (colour, x + 0, y + 5, 13, 1); 58 | fillRect (colour, x + 0, y + 6, 13, 1); 59 | fillRect (colour, x + 0, y + 7, 13, 1); 60 | fillRect (colour, x + 0, y + 8, 13, 1); 61 | fillRect (colour, x + 1, y + 9, 11, 1); 62 | fillRect (colour, x + 1, y + 10, 11, 1); 63 | fillRect (colour, x + 2, y + 11, 9, 1); 64 | fillRect (colour, x + 4, y + 12, 5, 1); 65 | } 66 | 67 | void paintPacmanMouthAt (int x, int y) 68 | { 69 | int colour = makeARGB (255, 0, 0, 0); 70 | 71 | int cx = x + 4; 72 | int cy = y + 6; 73 | 74 | for (int i = 0; i < mouthWidth; ++i) 75 | { 76 | int h = getMouthHeight (i, mouthHeight); 77 | fillRect (colour, cx + i, cy - h / 2, 1, h); 78 | } 79 | } 80 | 81 | void paintAccessories (int x, int y) 82 | { 83 | int red = makeARGB (255, 255, 0, 0); 84 | fillRect (red, x + 0, y + 4, 2, 2); 85 | fillRect (red, x + 2, y + 2, 2, 2); 86 | fillRect (red, x + 4, y + 0, 2, 2); 87 | fillRect (red, x - 1, y + 1, 3, 4); 88 | fillRect (red, x + 1, y + 1, 2, 2); 89 | fillRect (red, x + 1, y - 1, 4, 2); 90 | 91 | int aqua = makeARGB (255, 51, 153, 255); 92 | fillRect (aqua, x + 2, y, 2, 2); 93 | fillRect (aqua, x, y + 2, 2, 2); 94 | 95 | int black = makeARGB (255, 0, 0, 0); 96 | fillRect (black, x + 4, y + 4, 2, 1); 97 | fillRect (black, x + 3, y + 5, 1, 1); 98 | 99 | for (int i = mouthWidth - 3; i < mouthWidth; ++i) 100 | { 101 | int cx = x + 3; 102 | int cy = y + 6; 103 | int h = getMouthHeight (i, mouthHeight); 104 | int halfHeight = int (h / 2.0); 105 | 106 | fillRect (red, cx + i, cy - halfHeight, 1, 1); 107 | fillRect (red, cx + i, cy + halfHeight, 1, 1); 108 | } 109 | } 110 | 111 | void paintFood (int x, int y) 112 | { 113 | int colour = makeARGB (255, 0, 0, 255); 114 | 115 | int cy = y + 6; 116 | 117 | int spacing = 2; 118 | 119 | for (int i = 0; i < 14; i += spacing) 120 | { 121 | if (i > x + (pacmanSize / 2) - 1) 122 | fillPixel (colour, i, cy); 123 | } 124 | } 125 | 126 | int getMouthHeight (int x, float h) 127 | { 128 | return int (x / 8.0 * h); 129 | } 130 | 131 | void update() 132 | { 133 | position += speed; 134 | 135 | if (position > 14) 136 | position = 0 - pacmanSize; 137 | 138 | mouthHeight += mouthSpeed; 139 | 140 | if (mouthHeight > mouthMaxHeight || mouthHeight < 0) 141 | { 142 | mouthSpeed *= -1.0; 143 | } 144 | } 145 | 146 | void touchMove (int index, float x, float y, float z, float vz) 147 | { 148 | speed = 0.3 + z * 2.0; 149 | } 150 | 151 | void touchEnd (int index, float x, float y, float z, float vz) 152 | { 153 | speed = 0.3; 154 | } 155 | 156 | void handleButtonDown (int index) 157 | { 158 | msPacman = ! msPacman; 159 | } 160 | -------------------------------------------------------------------------------- /Example Scripts/TicTacToe.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | */ 5 | 6 | int tl, t, tr; 7 | int ml, m, mr; 8 | int bl, b, br; 9 | 10 | int currentTurn; 11 | 12 | int winner; 13 | 14 | void initialise() 15 | { 16 | tl = 0; 17 | t = 0; 18 | tr = 0; 19 | ml = 0; 20 | m = 0; 21 | mr = 0; 22 | bl = 0; 23 | b = 0; 24 | br = 0; 25 | 26 | currentTurn = 1; 27 | winner = 0; 28 | } 29 | 30 | void repaint() 31 | { 32 | clearDisplay(); 33 | 34 | if (winner == 0) 35 | { 36 | drawGrid(); 37 | drawSigns(); 38 | } 39 | else 40 | { 41 | drawWinner(); 42 | } 43 | } 44 | 45 | void drawWinner() 46 | { 47 | if (winner == 1) 48 | { 49 | int xColour = makeARGB (255, 0, 255, 0); 50 | fillRect (xColour, 0, 0, 15, 15); 51 | } 52 | else if (winner == 2) 53 | { 54 | int oColour = makeARGB (255, 0, 0, 255); 55 | fillRect (oColour, 0, 0, 15, 15); 56 | } 57 | } 58 | 59 | void drawGrid() 60 | { 61 | int white = makeARGB (255, 200, 200, 200); 62 | 63 | if (tl == 0) drawRect (white, 0, 0, 5, 5); 64 | if (t == 0) drawRect (white, 5, 0, 5, 5); 65 | if (tr == 0) drawRect (white, 10, 0, 5, 5); 66 | if (ml == 0) drawRect (white, 0, 5, 5, 5); 67 | if (m == 0) drawRect (white, 5, 5, 5, 5); 68 | if (mr == 0) drawRect (white, 10, 5, 5, 5); 69 | if (bl == 0) drawRect (white, 0, 10, 5, 5); 70 | if (b == 0) drawRect (white, 5, 10, 5, 5); 71 | if (br == 0) drawRect (white, 10, 10, 5, 5); 72 | } 73 | 74 | void drawRect (int colour, int x, int y, int w, int h) 75 | { 76 | fillRect (colour, x, y, 1, h); 77 | fillRect (colour, x, y, w, 1); 78 | 79 | fillRect (colour, x + w - 1, y, 1, h); 80 | fillRect (colour, x, y + h - 1, w, 1); 81 | } 82 | 83 | void drawSigns() 84 | { 85 | evaluate (tl, 0, 0); 86 | evaluate (t , 5, 0); 87 | evaluate (tr, 10, 0); 88 | 89 | evaluate (ml, 0, 5); 90 | evaluate (m, 5, 5); 91 | evaluate (mr, 10, 5); 92 | 93 | evaluate (bl, 0, 10); 94 | evaluate (b, 5, 10); 95 | evaluate (br, 10, 10); 96 | } 97 | 98 | void evaluate (int value, int x, int y) 99 | { 100 | if (value == 1) 101 | drawX (x, y); 102 | else if (value == 2) 103 | drawO (x, y); 104 | } 105 | 106 | void drawX (int x, int y) 107 | { 108 | int xColour = makeARGB (255, 0, 255, 0); 109 | 110 | fillRect (xColour, x, y, 1, 1); 111 | fillRect (xColour, x + 1, y + 1, 1, 1); 112 | fillRect (xColour, x + 2, y + 2, 1, 1); 113 | fillRect (xColour, x + 3, y + 3, 1, 1); 114 | fillRect (xColour, x + 4, y + 4, 1, 1); 115 | 116 | fillRect (xColour, x + 4, y, 1, 1); 117 | fillRect (xColour, x + 3, y + 1, 1, 1); 118 | fillRect (xColour, x + 2, y + 2, 1, 1); 119 | fillRect (xColour, x + 1, y + 3, 1, 1); 120 | fillRect (xColour, x, y + 4, 1, 1); 121 | } 122 | 123 | void drawO (int x, int y) 124 | { 125 | int oColour = makeARGB (255, 0, 0, 255); 126 | 127 | fillRect (oColour, x, y, 5, 1); 128 | fillRect (oColour, x, y + 4, 5, 1); 129 | fillRect (oColour, x, y, 1, 5); 130 | fillRect (oColour, x + 4, y, 1, 5); 131 | } 132 | 133 | void touchStart (int index, float x, float y, float z, float vz) 134 | { 135 | int xPos = int (x * 7); 136 | int yPos = int (y * 7); 137 | 138 | int index = getIndex (xPos, yPos); 139 | 140 | if (setValueForIndex (index, currentTurn)) 141 | { 142 | currentTurn = currentTurn == 1 ? 2 : 1; 143 | } 144 | 145 | if (xHasWon()) winner = 1; 146 | else if (oHasWon()) winner = 2; 147 | } 148 | 149 | int getIndex (int x, int y) 150 | { 151 | int xInd = x / 5; 152 | int yInd = y / 5; 153 | 154 | return yInd * 3 + xInd; 155 | } 156 | 157 | bool setValueForIndex (int index, int value) 158 | { 159 | if (index == 0) { tl = tl == 0 ? value : tl; return true; } 160 | if (index == 1) { t = t == 0 ? value : t ; return true; } 161 | if (index == 2) { tr = tr == 0 ? value : tr; return true; } 162 | if (index == 3) { ml = ml == 0 ? value : ml; return true; } 163 | if (index == 4) { m = m == 0 ? value : m ; return true; } 164 | if (index == 5) { mr = mr == 0 ? value : mr; return true; } 165 | if (index == 6) { bl = bl == 0 ? value : bl; return true; } 166 | if (index == 7) { b = b == 0 ? value : b ; return true; } 167 | if (index == 8) { br = br == 0 ? value : br; return true; } 168 | 169 | return false; 170 | } 171 | 172 | bool xHasWon() { return hasWon (1); } 173 | bool oHasWon() { return hasWon (2); } 174 | 175 | bool hasWon (int player) 176 | { 177 | return (tl == player && t == player && tr == player) 178 | || (ml == player && m == player && mr == player) 179 | || (bl == player && b == player && br == player) 180 | 181 | || (tl == player && ml == player && bl == player) 182 | || (t == player && m == player && b == player) 183 | || (tr == player && mr == player && br == player) 184 | 185 | || (tl == player && m == player && br == player) 186 | || (tr == player && m == player && bl == player); 187 | } 188 | 189 | void handleButtonDown (int index) 190 | { 191 | initialise(); 192 | } 193 | -------------------------------------------------------------------------------- /Factory Scripts/BLOCKSvaders.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | 5 | int gameState_Over; 6 | int gameState_Play; 7 | int gameState_Prepare; 8 | int gameState; 9 | 10 | int score; 11 | int highScore; 12 | 13 | float playerX; 14 | float playerY; 15 | float targetPlayerX; 16 | float playerSpeedX; 17 | 18 | float enemyX; 19 | float enemyY; 20 | float enemySpeedY; 21 | 22 | float enemySpeedIncreasePerKill; 23 | 24 | float bulletX; 25 | float bulletY; 26 | float bulletSpeedY; 27 | 28 | float explosionX; 29 | float explosionY; 30 | float explosionWidth; 31 | float explosionGrowPerFrame; 32 | float explosionMax; 33 | 34 | int gameOverMsec; 35 | int gameStartMsec; 36 | 37 | int msecPerCountdownTick; 38 | int numCountdownTicks; 39 | 40 | int randomSeed; 41 | 42 | /////////////////////////// 43 | // Initialisation 44 | 45 | void initialise() 46 | { 47 | // game state enum 48 | gameState_Over = 0; 49 | gameState_Prepare = 1; 50 | gameState_Play = 2; 51 | 52 | gameState = gameState_Over; 53 | 54 | enemySpeedIncreasePerKill = 0.03; 55 | 56 | bulletSpeedY = 0.5; 57 | 58 | highScore = 0; 59 | 60 | explosionGrowPerFrame = 0.6; 61 | explosionMax = 5.0; 62 | 63 | gameOverMsec = -9999; 64 | 65 | msecPerCountdownTick = 500; 66 | numCountdownTicks = 3; 67 | 68 | for (int i = 0; i < 32; ++i) 69 | setLocalConfigActiveState (i, false, false); 70 | } 71 | 72 | /////////////////////////// 73 | // Utilities 74 | 75 | float getRandom01() 76 | { 77 | while(true) 78 | { 79 | randomSeed = 214013 * randomSeed + 2531011; 80 | int rndInt = (randomSeed >> 16) & 0x7fff; 81 | float f01 = float(rndInt) / 32768.0; 82 | if (f01 >= 0.0 && f01 < 1.0) 83 | return f01; 84 | } 85 | return 0.0; 86 | } 87 | 88 | float getRandomInRange(float start, float rangeExclusive) 89 | { 90 | float rnd = getRandom01(); 91 | return start + (rangeExclusive - 0.0001) * rnd; 92 | } 93 | 94 | /////////////////////////// 95 | // Game Logic 96 | 97 | void startGame() 98 | { 99 | randomSeed = getMillisecondCounter(); 100 | 101 | gameState = gameState_Play; 102 | 103 | playerX = 8.0; 104 | playerY = 12.0; 105 | targetPlayerX = 8.0; 106 | playerSpeedX = 0.3; 107 | 108 | enemySpeedY = 0.1; 109 | 110 | bulletX = -99.0; 111 | score = 0; 112 | 113 | explosionX = -1.0; 114 | explosionY = -1.0; 115 | explosionWidth = 0.0; 116 | 117 | spawnEnemy(); 118 | } 119 | 120 | void setPlayerTarget02(float x02) 121 | { 122 | targetPlayerX = float(x02) / 2.0 * 15.0; 123 | } 124 | 125 | void spawnEnemy() 126 | { 127 | enemyY = 0.0; 128 | enemyX = getRandomInRange(1.0, 13.0); 129 | } 130 | 131 | void spawnBullet() 132 | { 133 | bulletX = playerX; 134 | bulletY = playerY - 1.0; 135 | } 136 | 137 | void updatePlayer() 138 | { 139 | playerX = playerX + (targetPlayerX - playerX) * playerSpeedX; 140 | } 141 | 142 | void updateEnemy() 143 | { 144 | enemyY += enemySpeedY; 145 | } 146 | 147 | void updateBullet() 148 | { 149 | bulletY -= bulletSpeedY; 150 | if (bulletY < 0) 151 | bulletX = -1; 152 | } 153 | 154 | void updateExplosion() 155 | { 156 | if (explosionX >= 0.0) 157 | { 158 | explosionWidth += explosionGrowPerFrame; 159 | if (explosionWidth > explosionMax) 160 | { 161 | explosionX = -1.0; 162 | } 163 | } 164 | } 165 | 166 | void destroyEnemy() 167 | { 168 | bulletX = -99.0; 169 | bulletY = -1; 170 | explosionX = enemyX; 171 | explosionY = enemyY; 172 | explosionWidth = 1.0; 173 | 174 | enemySpeedY += enemySpeedIncreasePerKill; 175 | score++; 176 | } 177 | 178 | void detectCollisions() 179 | { 180 | if (bulletX >= 0) 181 | { 182 | int ydist = abs(int(bulletY)- int(enemyY)); 183 | if (ydist < 3) 184 | { 185 | int dist = abs(int(bulletX) - int(enemyX)); 186 | if (dist < 3) 187 | { 188 | destroyEnemy(); 189 | spawnEnemy(); 190 | } 191 | } 192 | } 193 | } 194 | 195 | void detectGameOver() 196 | { 197 | if (enemyY > 13) 198 | { 199 | gameState = gameState_Over; 200 | if (score > highScore) 201 | { 202 | highScore = score; 203 | gameOverMsec = getMillisecondCounter(); 204 | } 205 | } 206 | } 207 | 208 | void updatePrepare() 209 | { 210 | int msecSinceStart = getMillisecondCounter() - gameStartMsec; 211 | if (msecSinceStart > numCountdownTicks * msecPerCountdownTick) 212 | { 213 | startGame(); 214 | } 215 | } 216 | 217 | void updateGame() 218 | { 219 | updatePlayer(); 220 | updateEnemy(); 221 | updateBullet(); 222 | updateExplosion(); 223 | 224 | detectCollisions(); 225 | detectGameOver(); 226 | } 227 | 228 | /////////////////////////// 229 | // Input detection 230 | 231 | void touchStart(int index, float touchX02, float touchY, float touchZ, float touchScale) 232 | { 233 | if (gameState == gameState_Over) 234 | { 235 | if (getMillisecondCounter() - gameOverMsec > 1000) 236 | { 237 | gameStartMsec = getMillisecondCounter(); 238 | gameState = gameState_Prepare; 239 | } 240 | } 241 | else if (gameState == gameState_Play) 242 | { 243 | setPlayerTarget02(touchX02); 244 | } 245 | } 246 | 247 | void touchMove(int index, float touchX02, float touchY, float touchZ, float touchScale) 248 | { 249 | setPlayerTarget02(touchX02); 250 | } 251 | 252 | void touchEnd(int index, float touchX02, float touchY, float touchZ, float touchScale) 253 | { 254 | if (gameState == gameState_Play) 255 | { 256 | spawnBullet(); 257 | } 258 | } 259 | 260 | /////////////////////////// 261 | // Drawing 262 | 263 | void drawBullet() 264 | { 265 | if (bulletX >= 0.0) 266 | fillRect(0xffffffff, int(bulletX) - 1, int(bulletY), 3, 3); 267 | } 268 | 269 | void drawPlayer() 270 | { 271 | int col = 0xff0000ff; 272 | int px = int(playerX); 273 | int py = int(playerY); 274 | fillPixel (col, px + 0, py + 0); 275 | fillPixel (col, px - 1, py + 1); 276 | fillPixel (col, px + 0, py + 1); 277 | fillPixel (col, px + 1, py + 1); 278 | fillPixel (col, px - 1, py + 2); 279 | fillPixel (col, px + 1, py + 2); 280 | } 281 | 282 | void drawEnemy() 283 | { 284 | int col = 0xffff0000; 285 | int px = int(enemyX); 286 | int py = int(enemyY); 287 | fillPixel (col, px + 0, py + 2); 288 | fillPixel (col, px - 1, py + 1); 289 | fillPixel (col, px + 0, py + 1); 290 | fillPixel (col, px + 1, py + 1); 291 | fillPixel (col, px - 1, py + 0); 292 | fillPixel (col, px + 1, py + 0); 293 | } 294 | 295 | void drawExplosion() 296 | { 297 | if (explosionX >= 0.0) 298 | { 299 | blendRect(0x80ffffff, int(explosionX + explosionWidth) + 1, int(explosionY), 2, 1); 300 | blendRect(0x80ffffff, int(explosionX - explosionWidth) - 1, int(explosionY), 2, 1); 301 | } 302 | } 303 | 304 | void repaintPlay() 305 | { 306 | blendRect(0x30000000, 0, 0, 15, 15); 307 | drawPlayer(); 308 | drawEnemy(); 309 | drawBullet(); 310 | drawExplosion(); 311 | } 312 | 313 | void repaintGameOver() 314 | { 315 | fillRect(0xff00ff00, 0, 0, 15, 15); 316 | fillRect(0xff000000, 1, 1, 13, 13); 317 | drawNumber(score, 0xffffffff, 2, 2); 318 | drawNumber(highScore, 0xffffffff, 2, 8); 319 | } 320 | 321 | void repaintPrepare() 322 | { 323 | fillRect(0xff000000, 0, 0, 15, 15); 324 | int msecSinceStart = getMillisecondCounter() - gameStartMsec; 325 | int counterDigit = (numCountdownTicks * msecPerCountdownTick - msecSinceStart) / msecPerCountdownTick + 1; 326 | drawNumber(counterDigit, 0xffffffff, 5, 5); 327 | } 328 | 329 | void repaint() 330 | { 331 | if (gameState == gameState_Play) 332 | { 333 | updateGame(); 334 | repaintPlay(); 335 | } 336 | else if (gameState == gameState_Prepare) 337 | { 338 | repaintPrepare(); 339 | updatePrepare(); 340 | } 341 | else 342 | { 343 | repaintGameOver(); 344 | } 345 | } 346 | 347 | /* 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | */ -------------------------------------------------------------------------------- /Factory Scripts/BreakBLOCKS.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | */ 11 | 12 | int paddlePos; 13 | int paddleWidth; 14 | bool down; 15 | int seed; 16 | int ballXVec; 17 | int ballYVec; 18 | int ballX; 19 | int ballY; 20 | int advanceCount; 21 | 22 | bool gameIsOver; 23 | bool gameIsPaused; 24 | int gameOverCoverIndex; 25 | int gameOverCoverCount; 26 | int gameStartMsec; 27 | 28 | #heapsize: 1 29 | 30 | void resetState() 31 | { 32 | gameIsPaused = true; 33 | gameIsOver = false; 34 | 35 | paddleWidth = 4; 36 | paddlePos = 7; 37 | seed = 5; 38 | 39 | ballX = 7; 40 | ballY = 10; 41 | ballYVec = -1; 42 | if (getRandomInt (255) > 127) 43 | { 44 | ballXVec = 1; 45 | } 46 | else 47 | { 48 | ballXVec = -1; 49 | } 50 | 51 | int seedColour = makeARGB (255, getRandomInt (255), getRandomInt (255), getRandomInt (255)); 52 | for (int i = 0; i < 20; ++i) 53 | { 54 | int r = (((seedColour >> 16) & 0xFF) + getRandomInt (255)) % 255; 55 | int g = (((seedColour >> 8) & 0xFF) + getRandomInt (255)) % 255; 56 | int b = (((seedColour) & 0xFF) + getRandomInt (255)) % 255; 57 | 58 | seedColour = makeARGB (255, b, r, g); // Yep, lets really mess things up 59 | setBrickCol (i, seedColour); 60 | setBrick (i, true); 61 | } 62 | } 63 | 64 | void initialise() 65 | { 66 | resetState(); 67 | startNewGame(); 68 | for (int i = 0; i < 32; ++i) 69 | setLocalConfigActiveState (i, false, false); 70 | } 71 | 72 | void handleTouch (int index, float x, float y, float z, float vz) 73 | { 74 | if (! gameIsOver) 75 | { 76 | paddlePos = int ((x * 0.5) * 15.0); 77 | paddlePos = clamp (paddleWidth / 2, 15 - (paddleWidth / 2), paddlePos); 78 | } 79 | } 80 | 81 | void touchStart (int index, float x, float y, float z, float vz) 82 | { 83 | handleTouch (index, x, y, z, vz); 84 | } 85 | 86 | void touchMove (int index, float x, float y, float z, float vz) 87 | { 88 | handleTouch (index, x, y, z, vz); 89 | } 90 | 91 | void touchEnd (int index, float x, float y, float z, float vz) 92 | { 93 | handleTouch (index, x, y, z, vz); 94 | } 95 | 96 | int getBrickX (int brickIndex) 97 | { 98 | return (brickIndex / 4) * 3; 99 | } 100 | 101 | int getBrickRight (int brickIndex) 102 | { 103 | return getBrickX (brickIndex) + 3; 104 | } 105 | 106 | int getBrickY (int brickIndex) 107 | { 108 | return (brickIndex % 4) * 2; 109 | } 110 | 111 | int getBrickBottom (int brickIndex) 112 | { 113 | return getBrickY (brickIndex) + 2; 114 | } 115 | 116 | void handleButtonDown (int index) 117 | { 118 | initialise(); 119 | } 120 | 121 | void paintComponents() 122 | { 123 | if (! gameIsPaused) 124 | { 125 | clearDisplay(); 126 | for (int i = 0; i < 20; ++i) 127 | { 128 | if (getBrick (i)) 129 | { 130 | fillRect (getBrickCol (i), getBrickX (i), getBrickY (i), 3, 2); 131 | } 132 | } 133 | fillRect (0xFF0000, paddlePos - (paddleWidth / 2), 14, paddleWidth, 1); 134 | fillRect (0x00FF00, ballX, ballY, 1, 1); 135 | } 136 | 137 | if (! gameIsOver && gameIsPaused) 138 | { 139 | clearDisplay(); 140 | int msecSinceStart = getMillisecondCounter() - gameStartMsec; 141 | int counterDigit = max (0, (3 * 500 - msecSinceStart) / 500 + 1); 142 | if (counterDigit == 0) 143 | { 144 | resetState(); 145 | gameIsPaused = false; 146 | gameIsOver = false; 147 | } 148 | else 149 | { 150 | drawNumber(counterDigit, 0xffffffff, 5, 8); 151 | } 152 | } 153 | } 154 | 155 | void advance() 156 | { 157 | if (gameIsPaused) 158 | { 159 | return; 160 | } 161 | 162 | if (++advanceCount % 2 != 0) 163 | { 164 | return; 165 | } 166 | 167 | ballY += ballYVec; 168 | ballX += ballXVec; 169 | 170 | if (ballX < 0) 171 | { 172 | ballX = 0; 173 | ballXVec = -ballXVec; 174 | } 175 | else if (ballX > 14) 176 | { 177 | ballX = 14; 178 | ballXVec = -ballXVec; 179 | } 180 | 181 | if (ballY < 0) 182 | { 183 | ballY = 0; 184 | ballYVec = -ballYVec; 185 | } 186 | else if (ballY >= 14) 187 | { 188 | if (ballX >= paddlePos - (paddleWidth / 2) && ballX < paddlePos + (paddleWidth / 2)) 189 | { 190 | ballYVec = -ballYVec; 191 | } 192 | else 193 | { 194 | triggerGameOver(); 195 | return; 196 | } 197 | } 198 | 199 | bool hitOne = false; 200 | for (int i = 19; i >= 0; --i) 201 | { 202 | if (! hitOne && 203 | getBrick (i) && 204 | ballY <= getBrickBottom (i) && 205 | ballX >= getBrickX (i) && 206 | ballX < getBrickRight (i)) 207 | { 208 | ballYVec = 1; 209 | setBrick (i, false); 210 | paintComponents(); 211 | hitOne = true; 212 | } 213 | } 214 | 215 | bool foundABrick = false; 216 | for (int i = 0; i < 20; ++i) 217 | { 218 | if (getBrick (i)) 219 | { 220 | foundABrick = true; 221 | break; 222 | } 223 | } 224 | 225 | if (! foundABrick) 226 | { 227 | triggerGameOver(); 228 | } 229 | } 230 | 231 | void triggerGameOver() 232 | { 233 | gameIsOver = true; 234 | gameOverCoverIndex = 0; 235 | gameOverCoverCount = 2; 236 | gameIsPaused = true; 237 | } 238 | 239 | void startNewGame() 240 | { 241 | gameStartMsec = getMillisecondCounter(); 242 | gameIsOver = false; 243 | } 244 | 245 | void showGameOver() 246 | { 247 | fillRect (0x000000, 0, 0, 15, gameOverCoverIndex); 248 | if (--gameOverCoverCount < 0) 249 | { 250 | gameOverCoverCount = 2; 251 | if (++gameOverCoverIndex == 15) 252 | { 253 | gameOverCoverIndex = 15; 254 | startNewGame(); 255 | } 256 | } 257 | } 258 | 259 | void repaint() 260 | { 261 | paintComponents(); 262 | if (! gameIsOver) 263 | advance(); 264 | else 265 | showGameOver(); 266 | } 267 | 268 | /* 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | */ 345 | -------------------------------------------------------------------------------- /Factory Scripts/RISE Controller.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | */ 28 | 29 | int view; 30 | const int faderView = 0; 31 | const int xyPadView = 1; 32 | 33 | int slider0; 34 | int slider1; 35 | int slider2; 36 | 37 | void initialise() 38 | { 39 | view = faderView; 40 | 41 | slider0 = slider1 = slider2 = 64; 42 | 43 | for (int i = 0; i < 32; ++i) 44 | setLocalConfigActiveState (i, false, false); 45 | } 46 | 47 | int mapTouchToRange (float v, float max) 48 | { 49 | return int (map (v, 7.0 / 100.0, 193.0 / 100.0, 0.0, max)); 50 | } 51 | 52 | void handleTouchFader (int index, float x, float y, float z, float vz) 53 | { 54 | int xPixel = mapTouchToRange (x, 14.0); 55 | int yValue = 127 - mapTouchToRange (y, 127.0); 56 | 57 | if (xPixel < 5) 58 | { 59 | slider0 = yValue; 60 | sendCC ((channel - 1), s0CC, slider0); 61 | } 62 | if (xPixel >= 5 && xPixel < 10) 63 | { 64 | slider1 = yValue; 65 | sendCC ((channel - 1), s1CC, slider1); 66 | } 67 | if (xPixel >= 10) 68 | { 69 | slider2 = yValue; 70 | sendCC ((channel - 1), s2CC, slider2); 71 | } 72 | } 73 | 74 | int mapTouchToRange (float v, float inMin, float inMax, float outMax) 75 | { 76 | return int (map (v, inMin / 100.0, inMax / 100.0, 0.0, outMax)); 77 | } 78 | 79 | void outputCC (float v, int cc, float inMin, float inMax, bool invert) 80 | { 81 | int value = mapTouchToRange (v, inMin, inMax, 127.0); 82 | if (invert) 83 | value = 127 - value; 84 | 85 | sendCC ((channel - 1), cc, value); 86 | } 87 | 88 | void handleTouchXYPad (int index, float x, float y, float z, float vz) 89 | { 90 | 91 | addPressurePoint (xyzColour, x, y, z * 20.0); 92 | 93 | if (send == 0 || send == 1) outputCC (x, xCC, 7.0, 193.0, false); 94 | if (send == 0 || send == 2) outputCC (y, yCC, 7.0, 193.0, true); 95 | } 96 | 97 | void handleTouch (int index, float x, float y, float z, float vz) 98 | { 99 | if (view == faderView) 100 | handleTouchFader (index, x, y, z, vz); 101 | 102 | if (view == xyPadView) 103 | handleTouchXYPad (index, x, y, z, vz); 104 | } 105 | 106 | void touchStart (int index, float x, float y, float z, float vz) 107 | { 108 | handleTouch (index, x, y, z, vz); 109 | } 110 | 111 | void touchMove (int index, float x, float y, float z, float vz) 112 | { 113 | handleTouch (index, x, y, z, vz); 114 | } 115 | 116 | void touchEnd (int index, float x, float y, float z, float vz) 117 | { 118 | handleTouch (index, x, y, z, vz); 119 | } 120 | 121 | void handleButtonDown (int index) 122 | { 123 | if (view == faderView) 124 | view = xyPadView; 125 | else 126 | view = faderView; 127 | } 128 | 129 | void repaint() 130 | { 131 | clearDisplay(); 132 | 133 | if (view == faderView) 134 | paintFaderView(); 135 | 136 | if (view == xyPadView) 137 | paintXYPadView(); 138 | } 139 | 140 | void paintFaderView() 141 | { 142 | int slider0DrawableHeight = int (map (float (slider0), 0.0, 127.0, 1.0, 15.0)); 143 | int slider1DrawableHeight = int (map (float (slider1), 0.0, 127.0, 1.0, 15.0)); 144 | int slider2DrawableHeight = int (map (float (slider2), 0.0, 127.0, 1.0, 15.0)); 145 | 146 | fillRect (s0Colour, 0, 15 - slider0DrawableHeight, 4, slider0DrawableHeight); 147 | fillRect (s1Colour, 5, 15 - slider1DrawableHeight, 4, slider1DrawableHeight); 148 | fillRect (s2Colour, 10, 15 - slider2DrawableHeight, 4, slider2DrawableHeight); 149 | } 150 | 151 | void paintXYPadView() 152 | { 153 | fillRect (xyzBackColour, 0, 0, 15, 15); 154 | drawPressureMap(); 155 | fadePressureMap(); 156 | } 157 | 158 | /* 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | */ -------------------------------------------------------------------------------- /Factory Scripts/Fader Block.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | */ 22 | 23 | int bank; 24 | int clusterSize; 25 | bool bankButtonEnabled; 26 | int clusterUpdateStage; 27 | int sliderChangeMessage; 28 | 29 | int getFirstSliderIndexForBank () 30 | { 31 | return bank * 4; 32 | } 33 | 34 | int sliderIndexForX (float x) 35 | { 36 | float x01 = x * 0.5; 37 | 38 | // Each slider has an area of 3px + 1px gap. We want the gaps to be dead zones.. 39 | int ledZone = int (x01 * 15); 40 | 41 | if (ledZone <= 3) return 0; 42 | if (ledZone >= 4 && ledZone <= 7) return 1; 43 | if (ledZone >= 8 && ledZone <= 11) return 2; 44 | if (ledZone >= 12 && ledZone <= 15) return 3; 45 | 46 | return -1; 47 | } 48 | 49 | bool sliderIsInBank (int sliderIndex) 50 | { 51 | int bankStart = getFirstSliderIndexForBank(); 52 | int bankEnd = bankStart + 4; 53 | return (sliderIndex >= bankStart && sliderIndex < bankEnd); 54 | } 55 | 56 | int getSliderMaxValueForClusterSize (int theClusterSize) 57 | { 58 | if (theClusterSize == 1) 59 | return 13; 60 | 61 | return 15; 62 | } 63 | 64 | int getSliderMaxValue() 65 | { 66 | return getSliderMaxValueForClusterSize (clusterSize); 67 | } 68 | 69 | float getSliderMinValue() 70 | { 71 | if (clusterSize == 1) 72 | { 73 | return 2.0; 74 | } 75 | 76 | return 0.0; 77 | } 78 | 79 | float getSliderValue01ForTouchAtY (float y) 80 | { 81 | float sliderMax = 14.0; 82 | float sliderMin = getSliderMinValue(); 83 | float sliderRange = sliderMax - sliderMin; 84 | 85 | float closestLED = clamp (sliderMin, sliderMax, float (y * 14)); 86 | float value01 = ((closestLED - sliderMin) / sliderRange); 87 | return 1.0 - value01; 88 | } 89 | 90 | int convertSliderValue01ToRange (float slider01, int sliderMin, int sliderMax, int hardMax) 91 | { 92 | return clamp (0x00, hardMax, sliderMin + int (slider01 * float (sliderMax - sliderMin))); 93 | } 94 | 95 | int convertSliderValue01ToOutputRange (int sliderIndex, float slider01) 96 | { 97 | return convertSliderValue01ToRange (slider01, getSliderMin (sliderIndex), getSliderMax (sliderIndex), 0x7F); 98 | } 99 | 100 | void doTouch (int index, float x, float y, float z, float vz) 101 | { 102 | int sliderIndex = sliderIndexForX(x) + getFirstSliderIndexForBank(); 103 | if (sliderIndex >= 0) 104 | { 105 | int currentValue = getSlider (sliderIndex); 106 | float slider01 = getSliderValue01ForTouchAtY (y * 0.5); 107 | int midiValue = convertSliderValue01ToOutputRange (sliderIndex, slider01); 108 | int newValue = convertSliderValue01ToRange (slider01, 1, getSliderMaxValue(), getSliderMaxValue()); 109 | 110 | setSlider (sliderIndex, newValue); 111 | 112 | if (clusterSize != 1 && currentValue != newValue) 113 | { 114 | sendSliderValueMessage (sliderIndex, newValue); 115 | } 116 | 117 | sendMIDI (0xB0 | (midiChannel - 1), getCc (sliderIndex), midiValue); 118 | } 119 | } 120 | 121 | void touchStart (int index, float x, float y, float z, float vz) 122 | { 123 | doTouch (index, x, y, z, vz); 124 | } 125 | 126 | void touchMove (int index, float x, float y, float z, float vz) 127 | { 128 | doTouch (index, x, y, z, vz); 129 | } 130 | 131 | void handleButtonDown (int index) 132 | { 133 | if (bankButtonEnabled) 134 | { 135 | bank = (bank + 1) % 4; 136 | } 137 | } 138 | 139 | void paintBankIndicator() 140 | { 141 | if (clusterSize == 1) 142 | { 143 | fillRect (makeARGB (255, 255, 0, 0), getFirstSliderIndexForBank(), 0, 3, 1); 144 | } 145 | } 146 | 147 | void paintSliders() 148 | { 149 | int bankStart = getFirstSliderIndexForBank(); 150 | for (int slider = 0; slider < 4; ++slider) 151 | { 152 | int sliderIndex = slider + bankStart; 153 | int sliderValue = getSlider (sliderIndex); 154 | int sliderColour = getColour (sliderIndex); 155 | fillRect (sliderColour, slider * 4, 15 - sliderValue, 3, sliderValue); 156 | } 157 | } 158 | 159 | void repaint() 160 | { 161 | clearDisplay(); 162 | paintBankIndicator(); 163 | paintSliders(); 164 | updateClustering(); 165 | } 166 | 167 | 168 | void zeroSliders() 169 | { 170 | for (int i = 0; i < 16; ++i) 171 | setSlider (i, 1); 172 | } 173 | 174 | void initialise() 175 | { 176 | sliderChangeMessage = 0x7F2E; 177 | 178 | clusterUpdateStage = -1; 179 | zeroSliders(); 180 | updateClusterPosition(); 181 | notifyOtherBlocksInClusterOfSliderValues(); 182 | 183 | for (int i = 0; i < 32; ++i) 184 | setLocalConfigActiveState (i, false, false); 185 | } 186 | 187 | void updateClusterPosition() 188 | { 189 | clusterSize = getClusterWidth(); 190 | 191 | if (clusterSize == 1) 192 | { 193 | bank = 0; 194 | bankButtonEnabled = true; 195 | } 196 | else 197 | { 198 | bank = getClusterXpos(); 199 | bankButtonEnabled = false; 200 | } 201 | } 202 | 203 | void updateClustering() 204 | { 205 | int newClusterSize = getClusterWidth(); 206 | if (clusterSize != newClusterSize) 207 | { 208 | if (newClusterSize == 1) 209 | rescaleSliders (false); 210 | else if (newClusterSize > 1 && clusterSize == 1) 211 | rescaleSliders (true); 212 | 213 | updateClusterPosition(); 214 | notifyOtherBlocksInClusterOfSliderValues(); 215 | } 216 | } 217 | 218 | void notifyOtherBlocksInClusterOfSliderValues() 219 | { 220 | if (isMasterInCurrentCluster() && clusterSize != 1) 221 | { 222 | int ourID = getBlockIDForIndex (0); 223 | for (int clusterIndex = 0; clusterIndex < getNumBlocksInCurrentCluster(); ++clusterIndex) 224 | { 225 | int id = getBlockIdForBlockInCluster (clusterIndex); 226 | 227 | if (id == ourID) 228 | continue; 229 | 230 | for (int slider = 0; slider < 16; ++slider) 231 | sendMessageToBlock (id, sliderChangeMessage, slider, getSlider (slider)); 232 | } 233 | } 234 | } 235 | 236 | void handleMessage (int data0, int data1, int data2) 237 | { 238 | if (data0 == sliderChangeMessage) 239 | setSlider (data1, data2); 240 | } 241 | 242 | void sendSliderValueMessage (int slider, int value) 243 | { 244 | int ourID = getBlockIDForIndex (0); 245 | for (int clusterIndex = 0; clusterIndex < getNumBlocksInCurrentCluster(); ++clusterIndex) 246 | { 247 | int id = getBlockIdForBlockInCluster (clusterIndex); 248 | 249 | if (id == ourID) 250 | continue; 251 | 252 | sendMessageToBlock (id, sliderChangeMessage, slider, value); 253 | } 254 | } 255 | 256 | void rescaleSliders (bool isNowClustering) 257 | { 258 | float nonClusterMax = float (getSliderMaxValueForClusterSize (1)); 259 | float clusterMax = float (getSliderMaxValueForClusterSize (4)); 260 | 261 | if (isNowClustering) 262 | { 263 | for (int slider = 0; slider < 16; ++slider) 264 | setSlider (slider, int ((float (getSlider (slider)) / nonClusterMax) * clusterMax)); 265 | } 266 | else 267 | { 268 | for (int slider = 0; slider < 16; ++slider) 269 | setSlider (slider, int ((float (getSlider (slider)) / clusterMax) * nonClusterMax)); 270 | } 271 | } 272 | 273 | 274 | /* 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | */ -------------------------------------------------------------------------------- /Factory Scripts/XYZ Pad.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | */ 16 | 17 | void initialise() 18 | { 19 | for (int i = 0; i < 32; ++i) 20 | setLocalConfigActiveState (i, false, false); 21 | } 22 | 23 | int mapTouchToRange (float v, float inMin, float inMax, float outMax) 24 | { 25 | return int (map (v, inMin / 100.0, inMax / 100.0, 0.0, outMax)); 26 | } 27 | 28 | void outputCC (float v, int cc, float inMin, float inMax, bool invert) 29 | { 30 | int value = mapTouchToRange (v, inMin, inMax, 127.0); 31 | if (invert) 32 | value = 127 - value; 33 | 34 | sendCC ((channel - 1), cc, value); 35 | } 36 | 37 | void handleTouch (int index, float x, float y, float z, float scale) 38 | { 39 | if (index == 1) 40 | { 41 | addPressurePoint (colour, x, y, z * scale); 42 | 43 | if (send == 0 || send == 1) outputCC (x, xCC, 7.0, 193.0, false); 44 | if (send == 0 || send == 2) outputCC (y, yCC, 7.0, 193.0, true); 45 | if (send == 0 || send == 3) outputCC (z, zCC, 0.0, 100.0, false); 46 | } 47 | } 48 | 49 | void touchStart (int index, float x, float y, float z, float vz) 50 | { 51 | handleTouch (index, x, y, z, 75.0); 52 | } 53 | 54 | void touchMove (int index, float x, float y, float z, float vz) 55 | { 56 | handleTouch (index, x, y, z, 20.0); 57 | } 58 | 59 | void repaint() 60 | { 61 | fillRect (backgroundColour, 0, 0, 15, 15); 62 | drawPressureMap(); 63 | fadePressureMap(); 64 | } 65 | 66 | /* 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | */ 297 | -------------------------------------------------------------------------------- /Example Scripts/MusicGen.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | */ 10 | 11 | int green; 12 | int red; 13 | int blue; 14 | int yellow; 15 | int count; 16 | 17 | float bullet1x; 18 | float bullet1y; 19 | float bullet2x; 20 | float bullet2y; 21 | float bullet3x; 22 | float bullet3y; 23 | float bullet4x; 24 | float bullet4y; 25 | float bullet5x; 26 | float bullet5y; 27 | 28 | int bullet1d; 29 | int bullet2d; 30 | int bullet3d; 31 | int bullet4d; 32 | int bullet5d; 33 | 34 | int blob1x; 35 | int blob1y; 36 | int blob2x; 37 | int blob2y; 38 | int blob3x; 39 | int blob3y; 40 | int blob4x; 41 | int blob4y; 42 | int blob5x; 43 | int blob5y; 44 | 45 | int blob1d; 46 | int blob2d; 47 | int blob3d; 48 | int blob4d; 49 | int blob5d; 50 | 51 | int lastNote1; 52 | int lastNote2; 53 | int lastNote3; 54 | int lastNote4; 55 | int lastNote5; 56 | 57 | void initialise() 58 | { 59 | clearDisplay(); 60 | 61 | sendCC (0, 120, 127); 62 | 63 | blob1x = -99; 64 | blob2x = -99; 65 | blob3x = -99; 66 | blob4x = -99; 67 | blob5x = -99; 68 | 69 | blob1y = -99; 70 | blob2y = -99; 71 | blob3y = -99; 72 | blob4y = -99; 73 | blob5y = -99; 74 | 75 | blob1d = 3; 76 | blob2d = 3; 77 | blob3d = 3; 78 | blob4d = 3; 79 | blob5d = 3; 80 | 81 | bullet1x = -99; 82 | bullet2x = -99; 83 | bullet3x = -99; 84 | bullet4x = -99; 85 | bullet5x = -99; 86 | 87 | bullet1y = -99; 88 | bullet2y = -99; 89 | bullet3y = -99; 90 | bullet4y = -99; 91 | bullet5y = -99; 92 | 93 | green = 0x2200FF00; 94 | red = 0x22FF0000; 95 | blue = 0x220000FF; 96 | yellow = 0x22FFFF00; 97 | 98 | count = 0; 99 | } 100 | 101 | // Detect touches 102 | void touchStart (int touchIndex, float x, float y, float z, float vz) 103 | { 104 | int intX = int (x * 7); 105 | int intY = int (y * 7); 106 | 107 | int touch = touchBlob (intX, intY); 108 | 109 | if (touch >= 1) 110 | { 111 | changeBlob (touch); 112 | } 113 | else if (count < 5) 114 | { 115 | if (z < 0.05) 116 | { 117 | assignBlob (intX, intY, count, 0); 118 | } 119 | else if (z < 0.2) 120 | { 121 | assignBlob (intX, intY, count, 1); 122 | } 123 | else if (z < 0.5) 124 | { 125 | assignBlob (intX, intY, count, 2); 126 | } 127 | else 128 | { 129 | assignBlob (intX, intY, count, 3); 130 | } 131 | 132 | ++count; 133 | } 134 | } 135 | 136 | //Detect if touch is on a Blob 137 | int touchBlob (int x, int y) 138 | { 139 | int touch = 0; 140 | 141 | if (x >= (blob1x - 1) && x <= (blob1x + 1) && y >= (blob1y - 1) && y <= (blob1y + 1)) 142 | { 143 | touch = 1; 144 | } 145 | else if (x >= (blob2x - 1) && x <= (blob2x + 1) && y >= (blob2y - 1) && y <= (blob2y + 1)) 146 | { 147 | touch = 2; 148 | } 149 | else if (x >= (blob3x - 1) && x <= (blob3x + 1) && y >= (blob3y - 1) && y <= (blob3y + 1)) 150 | { 151 | touch = 3; 152 | } 153 | else if (x >= (blob4x - 1) && x <= (blob4x + 1) && y >= (blob4y - 1) && y <= (blob4y + 1)) 154 | { 155 | touch = 4; 156 | } 157 | else if (x >= (blob5x - 1) && x <= (blob5x + 1) && y >= (blob5y - 1) && y <= (blob5y + 1)) 158 | { 159 | touch = 5; 160 | } 161 | 162 | return touch; 163 | } 164 | 165 | void changeBlob (int blob) 166 | { 167 | if (blob == 1) 168 | { 169 | if (blob1d < 3) 170 | { 171 | ++blob1d; 172 | } 173 | else 174 | { 175 | blob1d = 0; 176 | } 177 | } 178 | else if (blob == 2) 179 | { 180 | if (blob2d < 3) 181 | { 182 | ++blob2d; 183 | } 184 | else 185 | { 186 | blob2d = 0; 187 | } 188 | } 189 | else if (blob == 3) 190 | { 191 | if (blob3d < 3) 192 | { 193 | ++blob3d; 194 | } 195 | else 196 | { 197 | blob3d = 0; 198 | } 199 | } 200 | else if (blob == 4) 201 | { 202 | if (blob4d < 3) 203 | { 204 | ++blob4d; 205 | } 206 | else 207 | { 208 | blob4d = 0; 209 | } 210 | } 211 | else if (blob == 5) 212 | { 213 | if (blob5d < 3) 214 | { 215 | ++blob5d; 216 | } 217 | else 218 | { 219 | blob5d = 0; 220 | } 221 | } 222 | } 223 | 224 | // Blob Creation and Assignment! 225 | void paintBlob (int x, int y, int type) 226 | { 227 | if (type == 0) 228 | { 229 | fillRect (green, x, y - 1, 1, 2); 230 | blendRect (green, x - 1, y, 3, 1); 231 | } 232 | else if (type == 1) 233 | { 234 | fillRect (red, x, y, 2, 1); 235 | blendRect (red, x, y - 1, 1, 3); 236 | } 237 | else if (type == 2) 238 | { 239 | fillRect (blue, x, y, 1, 2); 240 | blendRect (blue, x - 1, y, 3, 1); 241 | } 242 | else if (type == 3) 243 | { 244 | fillRect (yellow, x - 1, y, 2, 1); 245 | blendRect (yellow, x, y - 1, 1, 3); 246 | } 247 | } 248 | 249 | void assignBlob (int x, int y, int index, int type) 250 | { 251 | if (index == 0) 252 | { 253 | blob1x = x; 254 | blob1y = y; 255 | blob1d = type; 256 | spawnBullet1(); 257 | } 258 | else if (index == 1) 259 | { 260 | blob2x = x; 261 | blob2y = y; 262 | blob2d = type; 263 | spawnBullet2(); 264 | } 265 | else if (index == 2) 266 | { 267 | blob3x = x; 268 | blob3y = y; 269 | blob3d = type; 270 | spawnBullet3(); 271 | } 272 | else if (index == 3) 273 | { 274 | blob4x = x; 275 | blob4y = y; 276 | blob4d = type; 277 | spawnBullet4(); 278 | } 279 | else if (index == 4) 280 | { 281 | blob5x = x; 282 | blob5y = y; 283 | blob5d = type; 284 | spawnBullet5(); 285 | } 286 | } 287 | 288 | // Make Bullets! 289 | void spawnBullet1() 290 | { 291 | bullet1x = blob1x; 292 | bullet1y = blob1y; 293 | bullet1d = blob1d; 294 | } 295 | 296 | void spawnBullet2() 297 | { 298 | bullet2x = blob2x; 299 | bullet2y = blob2y; 300 | bullet2d = blob2d; 301 | } 302 | 303 | void spawnBullet3() 304 | { 305 | bullet3x = blob3x; 306 | bullet3y = blob3y; 307 | bullet3d = blob3d; 308 | } 309 | 310 | void spawnBullet4() 311 | { 312 | bullet4x = blob4x; 313 | bullet4y = blob4y; 314 | bullet4d = blob4d; 315 | } 316 | 317 | void spawnBullet5() 318 | { 319 | bullet5x = blob5x; 320 | bullet5y = blob5y; 321 | bullet5d = blob5d; 322 | } 323 | 324 | void drawBullet (float x, float y, int d) 325 | { 326 | fillPixel (0xFF222222, int (x), int (y)); 327 | 328 | if (d == 0) 329 | { 330 | fillPixel (0xFFFFFF, int (x), int (y - 1)); 331 | } 332 | else if (d == 1) 333 | { 334 | fillPixel (0xFFFFFF, int (x + 1), int (y)); 335 | } 336 | else if (d == 2) 337 | { 338 | fillPixel (0xFFFFFF, int (x), int (y + 1)); 339 | } 340 | else 341 | { 342 | fillPixel (0xFFFFFF, int (x - 1), int (y)); 343 | } 344 | } 345 | 346 | void updateBullet1() 347 | { 348 | if (blob1d == 0) 349 | { 350 | bullet1y -= speed; 351 | } 352 | else if (blob1d == 1) 353 | { 354 | bullet1x += speed; 355 | } 356 | else if (blob1d == 2) 357 | { 358 | bullet1y += speed; 359 | } 360 | else if (blob1d == 3) 361 | { 362 | bullet1x -= speed; 363 | } 364 | } 365 | 366 | void updateBullet2() 367 | { 368 | if (blob2d == 0) 369 | { 370 | bullet2y -= speed; 371 | } 372 | else if (blob2d == 1) 373 | { 374 | bullet2x += speed; 375 | } 376 | else if (blob2d == 2) 377 | { 378 | bullet2y += speed; 379 | } 380 | else if (blob2d == 3) 381 | { 382 | bullet2x -= speed; 383 | } 384 | } 385 | 386 | void updateBullet3() 387 | { 388 | if (blob3d == 0) 389 | { 390 | bullet3y -= speed; 391 | } 392 | else if (blob3d == 1) 393 | { 394 | bullet3x += speed; 395 | } 396 | else if (blob3d == 2) 397 | { 398 | bullet3y += speed; 399 | } 400 | else if (blob3d == 3) 401 | { 402 | bullet3x -= speed; 403 | } 404 | } 405 | 406 | void updateBullet4() 407 | { 408 | if (blob4d == 0) 409 | { 410 | bullet4y -= speed; 411 | } 412 | else if (blob4d == 1) 413 | { 414 | bullet4x += speed; 415 | } 416 | else if (blob4d == 2) 417 | { 418 | bullet4y += speed; 419 | } 420 | else if (blob4d == 3) 421 | { 422 | bullet4x -= speed; 423 | } 424 | } 425 | 426 | void updateBullet5() 427 | { 428 | if (blob5d == 0) 429 | { 430 | bullet5y -= speed; 431 | } 432 | else if (blob5d == 1) 433 | { 434 | bullet5x += speed; 435 | } 436 | else if (blob5d == 2) 437 | { 438 | bullet5y += speed; 439 | } 440 | else if (blob5d == 3) 441 | { 442 | bullet5x -= speed; 443 | } 444 | } 445 | 446 | void detectBullet() 447 | { 448 | //Bullet1 449 | if (bullet1x > 15) 450 | { 451 | spawnBullet1(); 452 | midiNote (0, 0); 453 | } 454 | else if (bullet1x < 0 && bullet1x > -90) 455 | { 456 | spawnBullet1(); 457 | midiNote (0, 1); 458 | } 459 | else if (bullet1y > 15) 460 | { 461 | spawnBullet1(); 462 | midiNote (0, 2); 463 | } 464 | else if (bullet1y < 0 && bullet1y > -90) 465 | { 466 | spawnBullet1(); 467 | midiNote (0, 3); 468 | } 469 | 470 | //Bullet2 471 | if (bullet2x > 15) 472 | { 473 | spawnBullet2(); 474 | midiNote (1, 0); 475 | } 476 | else if (bullet2x < 0 && bullet2x > -90) 477 | { 478 | spawnBullet2(); 479 | midiNote (1, 1); 480 | } 481 | else if (bullet2y > 15) 482 | { 483 | spawnBullet2(); 484 | midiNote (1, 2); 485 | } 486 | else if (bullet2y < 0 && bullet2y > -90) 487 | { 488 | spawnBullet2(); 489 | midiNote (1, 3); 490 | } 491 | 492 | //Bullet3 493 | if (bullet3x > 15) 494 | { 495 | spawnBullet3(); 496 | midiNote (2, 0); 497 | } 498 | else if (bullet3x < 0 && bullet3x > -90) 499 | { 500 | spawnBullet3(); 501 | midiNote (2, 1); 502 | } 503 | else if (bullet3y > 15) 504 | { 505 | spawnBullet3(); 506 | midiNote (2, 2); 507 | } 508 | else if (bullet3y < 0 && bullet3y > -90) 509 | { 510 | spawnBullet3(); 511 | midiNote (2, 3); 512 | } 513 | 514 | //Bullet4 515 | if (bullet4x > 15) 516 | { 517 | spawnBullet4(); 518 | midiNote (3, 0); 519 | } 520 | else if (bullet4x < 0 && bullet4x > -90) 521 | { 522 | spawnBullet4(); 523 | midiNote (3, 1); 524 | } 525 | else if (bullet4y > 15) 526 | { 527 | spawnBullet4(); 528 | midiNote (3, 2); 529 | } 530 | else if (bullet4y < 0 && bullet4y > -90) 531 | { 532 | spawnBullet4(); 533 | midiNote (3, 3); 534 | } 535 | 536 | //Bullet5 537 | if (bullet5x > 15) 538 | { 539 | spawnBullet5(); 540 | midiNote (4, 0); 541 | } 542 | else if (bullet5x < 0 && bullet5x > -90) 543 | { 544 | spawnBullet5(); 545 | midiNote (4, 1); 546 | } 547 | else if (bullet5y > 15) 548 | { 549 | spawnBullet5(); 550 | midiNote (4, 2); 551 | } 552 | else if (bullet5y < 0 && bullet5y > -90) 553 | { 554 | spawnBullet5(); 555 | midiNote (4, 3); 556 | } 557 | } 558 | 559 | //MIDI FUN! 560 | void midiNote(int note1, int note2) 561 | { 562 | note2 *= 12; 563 | int note = rootNote; 564 | 565 | if (note1 == 0) 566 | { 567 | note += note2; 568 | note1 (note); 569 | } 570 | else if (note1 == 1) 571 | { 572 | if (chord == 0) 573 | { 574 | note += 4; 575 | } 576 | else 577 | { 578 | note += 3; 579 | } 580 | note += note2; 581 | note2 (note); 582 | } 583 | else if (note1 == 2) 584 | { 585 | note += 7; 586 | note += note2; 587 | note3 (note); 588 | } 589 | else if (note1 == 3) 590 | { 591 | if (chord == 0) 592 | { 593 | note += 11; 594 | } 595 | else 596 | { 597 | note += 10; 598 | } 599 | note += note2; 600 | note4 (note); 601 | } 602 | else if (note1 == 4) 603 | { 604 | note += 14; 605 | note += note2; 606 | note5 (note); 607 | } 608 | } 609 | 610 | void note1 (int note) 611 | { 612 | sendNoteOff (0, lastNote1, 80); 613 | sendNoteOn (0, note, 80); 614 | lastNote1 = note; 615 | } 616 | void note2 (int note) 617 | { 618 | sendNoteOff (0, lastNote2, 80); 619 | sendNoteOn (0, note, 80); 620 | lastNote2 = note; 621 | } 622 | void note3 (int note) 623 | { 624 | sendNoteOff (0, lastNote3, 80); 625 | sendNoteOn (0, note, 80); 626 | lastNote3 = note; 627 | } 628 | void note4 (int note) 629 | { 630 | sendNoteOff (0, lastNote4, 80); 631 | sendNoteOn (0, note, 80); 632 | lastNote4 = note; 633 | } 634 | void note5 (int note) 635 | { 636 | sendNoteOff (0, lastNote5, 80); 637 | sendNoteOn (0, note, 80); 638 | lastNote5 = note; 639 | } 640 | 641 | void handleButtonDown (int index) 642 | { 643 | initialise(); 644 | } 645 | 646 | void repaint() 647 | { 648 | clearDisplay(); 649 | 650 | //Draw 5 Blobs 651 | paintBlob (blob1x, blob1y, blob1d); 652 | paintBlob (blob2x, blob2y, blob2d); 653 | paintBlob (blob3x, blob3y, blob3d); 654 | paintBlob (blob4x, blob4y, blob4d); 655 | paintBlob (blob5x, blob5y, blob5d); 656 | 657 | //Draw 5 Bullets 658 | drawBullet (bullet1x, bullet1y, blob1d); 659 | drawBullet (bullet2x, bullet2y, blob2d); 660 | drawBullet (bullet3x, bullet3y, blob3d); 661 | drawBullet (bullet4x, bullet4y, blob4d); 662 | drawBullet (bullet5x, bullet5y, blob5d); 663 | 664 | //Update Bullet 665 | updateBullet1(); 666 | updateBullet2(); 667 | updateBullet3(); 668 | updateBullet4(); 669 | updateBullet5(); 670 | 671 | //Detect Collision 672 | detectBullet(); 673 | } 674 | -------------------------------------------------------------------------------- /Factory Scripts/Mixer Block.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | */ 27 | 28 | // PC Note - We arent using the heap. Without this statement we end up using too much of the heap... 29 | #heapsize: 1 30 | 31 | const int touchTypeNone = 0; 32 | const int touchTypeSlider = 1; 33 | const int touchTypeButton = 2; 34 | 35 | //============================================================================== 36 | void initialise() 37 | { 38 | for (int i = 0; i < 4; ++i) 39 | setSlider (i, 1); 40 | 41 | for (int i = 0; i < 32; ++i) 42 | setLocalConfigActiveState (i, false, false); 43 | } 44 | 45 | //============================================================================== 46 | int channelIndexForX (float x) 47 | { 48 | float x01 = x * 0.5; 49 | 50 | // Each slider has an area of 3px + 1px gap. We want the gaps to be dead zones.. 51 | int ledZone = int (x01 * 15); 52 | 53 | if (ledZone <= 3) return 0; 54 | if (ledZone >= 4 && ledZone <= 7) return 1; 55 | if (ledZone >= 8 && ledZone <= 11) return 2; 56 | return 3; 57 | } 58 | 59 | //============================================================================== 60 | float getSliderValue01ForTouchAtY (float y) 61 | { 62 | float sliderMax = 14.0; 63 | float sliderMin = 4.0; 64 | float sliderRange = sliderMax - sliderMin; 65 | 66 | float closestLED = clamp (sliderMin, sliderMax, float (y * 14)); 67 | float value01 = ((closestLED - sliderMin) / sliderRange); 68 | return 1.0 - value01; 69 | } 70 | 71 | //============================================================================== 72 | int convertSliderValue01ToRange (float slider01, int sliderMin, int sliderMax, int hardMax) 73 | { 74 | return clamp (0x00, hardMax, sliderMin + int (slider01 * float (sliderMax - sliderMin))); 75 | } 76 | 77 | //============================================================================== 78 | int convertSliderValue01ToOutputRange (int sliderIndex, float slider01) 79 | { 80 | return convertSliderValue01ToRange (slider01, getSliderMin (sliderIndex), getSliderMax (sliderIndex), 0x7F); 81 | } 82 | 83 | //============================================================================== 84 | void doTouchSlider (int index, float x, float y, float z, float vz) 85 | { 86 | int sliderIndex = channelIndexForX (x); 87 | int currentValue = getSlider (sliderIndex); 88 | float slider01 = getSliderValue01ForTouchAtY (y * 0.5); 89 | int midiValue = convertSliderValue01ToOutputRange (sliderIndex, slider01); 90 | int newValue = convertSliderValue01ToRange (slider01, 1, 11, 11); 91 | 92 | setSlider (sliderIndex, newValue); 93 | sendMIDI (0xB0 | (midiChannel - 1), getSliderCC (sliderIndex), midiValue); 94 | } 95 | 96 | //============================================================================== 97 | void doTouchButtonDown (int in, float x, float y, float z, float vz) 98 | { 99 | int buttonIndex = channelIndexForX (x); 100 | int buttonCC = getButtonCC (buttonIndex); 101 | int behaviour = getBehaviour (buttonIndex); 102 | 103 | if (behaviour == 0) // Toggle 104 | { 105 | setButton (buttonIndex, 255 - getButton (buttonIndex)); 106 | sendCC (midiChannel - 1, buttonCC, getButton (buttonIndex) / 2); 107 | } 108 | else if (behaviour == 1) // Gate 109 | { 110 | setButton (buttonIndex, 255); 111 | sendCC (midiChannel - 1, buttonCC, 0x7F); 112 | } 113 | else if (behaviour == 2) // trigger 114 | { 115 | setButton (buttonIndex, 255); 116 | sendCC (midiChannel - 1, buttonCC, 0x7F); 117 | } 118 | } 119 | 120 | //============================================================================== 121 | void doTouchButtonUp (int index, float x, float y, float z, float vz) 122 | { 123 | int buttonIndex = channelIndexForX (x); 124 | if (getBehaviour (buttonIndex) == 1) 125 | { 126 | setButton (buttonIndex, 0); 127 | sendCC (midiChannel - 1, getButtonCC (buttonIndex), 0x00); 128 | } 129 | } 130 | 131 | //============================================================================== 132 | bool isTouchingButton (float y) 133 | { 134 | return (int (y * 0.5 * 15.0) <= 2); 135 | } 136 | 137 | //============================================================================== 138 | bool isValidTouchIndex (int index) 139 | { 140 | return ((index - 1) < 16); 141 | } 142 | 143 | //============================================================================== 144 | void touchStart (int index, float x, float y, float z, float vz) 145 | { 146 | if (! isValidTouchIndex (index)) 147 | { 148 | return; 149 | } 150 | 151 | if (isTouchingButton (y)) 152 | { 153 | doTouchButtonDown (index, x, y, z, vz); 154 | setTouchType ((index - 1), touchTypeButton); 155 | } 156 | else 157 | { 158 | doTouchSlider (index, x, y, z, vz); 159 | setTouchType ((index - 1), touchTypeSlider); 160 | } 161 | } 162 | 163 | //============================================================================== 164 | void touchMove (int index, float x, float y, float z, float vz) 165 | { 166 | if (! isValidTouchIndex (index)) 167 | { 168 | return; 169 | } 170 | 171 | if (! isTouchingButton (y)) 172 | { 173 | doTouchSlider (index, x, y, z, vz); 174 | } 175 | } 176 | 177 | //============================================================================== 178 | void touchEnd (int index, float x, float y, float z, float vz) 179 | { 180 | if (! isValidTouchIndex (index)) 181 | { 182 | return; 183 | } 184 | 185 | int touchType = getTouchType ((index - 1)); 186 | if (touchType == touchTypeButton) 187 | { 188 | doTouchButtonUp (index, x, y, z, vz); 189 | } 190 | else 191 | { 192 | doTouchSlider (index, x, y, z, vz); 193 | } 194 | 195 | setTouchType ((index - 1), touchTypeNone); 196 | } 197 | 198 | //============================================================================== 199 | void repaint() 200 | { 201 | fillRect (0x000000, 0, 0, 15, 15); 202 | 203 | for (int channel = 0; channel < 4; ++channel) 204 | { 205 | int buttonValue = getButton (channel); 206 | int behaviour = getBehaviour (channel); 207 | 208 | if (buttonValue > 0) 209 | { 210 | if (behaviour == 2) 211 | { 212 | buttonValue -= 31; 213 | if (buttonValue < 0) 214 | { 215 | buttonValue = 0; 216 | } 217 | setButton (channel, buttonValue); 218 | sendCC (midiChannel - 1, getButtonCC (channel), buttonValue / 2); 219 | blendRect (makeARGB (buttonValue, (buttonColour >> 16) & 0xFF, (buttonColour >> 8) & 0xFF, (buttonColour) & 0xFF), channel * 4, 0, 3, 3); 220 | } 221 | else 222 | { 223 | fillRect (buttonColour, channel * 4, 0, 3, 3); 224 | } 225 | } 226 | 227 | int sliderValue = getSlider (channel); 228 | fillRect (sliderColour, channel * 4, 15 - sliderValue, 3, sliderValue); 229 | } 230 | } 231 | 232 | /* 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | */ -------------------------------------------------------------------------------- /Factory Scripts/MusicGen.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | */ 12 | 13 | 14 | //============================================================================== 15 | int green; 16 | int red; 17 | int blue; 18 | int yellow; 19 | int count; 20 | 21 | int clock; 22 | 23 | float bullet1x; 24 | float bullet1y; 25 | float bullet2x; 26 | float bullet2y; 27 | float bullet3x; 28 | float bullet3y; 29 | float bullet4x; 30 | float bullet4y; 31 | float bullet5x; 32 | float bullet5y; 33 | 34 | int bullet1d; 35 | int bullet2d; 36 | int bullet3d; 37 | int bullet4d; 38 | int bullet5d; 39 | 40 | int blob1x; 41 | int blob1y; 42 | int blob2x; 43 | int blob2y; 44 | int blob3x; 45 | int blob3y; 46 | int blob4x; 47 | int blob4y; 48 | int blob5x; 49 | int blob5y; 50 | 51 | int blob1d; 52 | int blob2d; 53 | int blob3d; 54 | int blob4d; 55 | int blob5d; 56 | 57 | int lastNote1; 58 | int lastNote2; 59 | int lastNote3; 60 | int lastNote4; 61 | int lastNote5; 62 | 63 | void initialise() 64 | { 65 | clearDisplay(); 66 | 67 | sendCC (0, 120, 127); 68 | 69 | blob1x = -99; 70 | blob2x = -99; 71 | blob3x = -99; 72 | blob4x = -99; 73 | blob5x = -99; 74 | 75 | blob1d = 3; 76 | blob2d = 3; 77 | blob3d = 3; 78 | blob4d = 3; 79 | blob5d = 3; 80 | 81 | bullet1x = -99; 82 | bullet2x = -99; 83 | bullet3x = -99; 84 | bullet4x = -99; 85 | bullet5x = -99; 86 | 87 | bullet1x = -99; 88 | bullet2x = -99; 89 | bullet3x = -99; 90 | bullet4x = -99; 91 | bullet5x = -99; 92 | 93 | bullet1y = -99; 94 | bullet2y = -99; 95 | bullet3y = -99; 96 | bullet4y = -99; 97 | bullet5y = -99; 98 | 99 | green = 0x2200FF00; 100 | red = 0x22FF0000; 101 | blue = 0x220000FF; 102 | yellow = 0x22FFFF00; 103 | count = 0; 104 | for (int i = 0; i < 32; ++i) 105 | setLocalConfigActiveState (i, false, false); 106 | } 107 | 108 | // Detect touches 109 | 110 | void touchStart (int touchIndex, float x, float y, float z, float vz) 111 | { 112 | int intX = int (x*7); 113 | int intY = int (y*7); 114 | 115 | int touch = touchBlob (intX, intY); 116 | 117 | log(touch); 118 | 119 | if (touch >= 1) 120 | { 121 | changeBlob(touch); 122 | log(123); 123 | } 124 | else if (count < 5) 125 | { 126 | if (z < 0.05) 127 | { 128 | assignBlob (intX, intY, count, 0); 129 | } 130 | else if (z < 0.2) 131 | { 132 | assignBlob (intX, intY, count, 1); 133 | } 134 | else if (z < 0.5) 135 | { 136 | assignBlob (intX, intY, count, 2); 137 | } 138 | else 139 | { 140 | assignBlob (intX, intY, count, 3); 141 | } 142 | count ++; 143 | } 144 | } 145 | 146 | //Detect if touch is on a Blob 147 | int touchBlob (int x, int y) 148 | { 149 | int touch; 150 | 151 | if (x >= (blob1x-1) && x <= (blob1x+1) && y >= (blob1y-1) && y <= (blob1y+1)) 152 | { 153 | touch = 1; 154 | } 155 | else if (x >= (blob2x-1) && x <= (blob2x+1) && y >= (blob2y-1) && y <= (blob2y+1)) 156 | { 157 | touch = 2; 158 | } 159 | else if (x >= (blob3x-1) && x <= (blob3x+1) && y >= (blob3y-1) && y <= (blob3y+1)) 160 | { 161 | touch = 3; 162 | } 163 | else if (x >= (blob4x-1) && x <= (blob4x+1) && y >= (blob4y-1) && y <= (blob4y+1)) 164 | { 165 | touch = 4; 166 | } 167 | else if (x >= (blob5x-1) && x <= (blob5x+1) && y >= (blob5y-1) && y <= (blob5y+1)) 168 | { 169 | touch = 5; 170 | } 171 | else 172 | { 173 | touch = 0; 174 | } 175 | return touch; 176 | } 177 | 178 | void changeBlob(int blob){ 179 | if (blob == 1) 180 | { 181 | if (blob1d < 3){ 182 | blob1d++; 183 | } 184 | else{ 185 | blob1d = 0; 186 | } 187 | } 188 | else if (blob == 2) 189 | { 190 | if (blob2d < 3){ 191 | blob2d++; 192 | } 193 | else{ 194 | blob2d = 0; 195 | } 196 | } 197 | else if (blob == 3) 198 | { 199 | if (blob3d < 3){ 200 | blob3d++; 201 | } 202 | else{ 203 | blob3d = 0; 204 | } 205 | } 206 | else if (blob == 4) 207 | { 208 | if (blob4d < 3){ 209 | blob4d++; 210 | } 211 | else{ 212 | blob4d = 0; 213 | } 214 | } 215 | else if (blob == 5) 216 | { 217 | if (blob5d < 3){ 218 | blob5d++; 219 | } 220 | else{ 221 | blob5d = 0; 222 | } 223 | } 224 | } 225 | 226 | // Blob Creation and Assignment! 227 | 228 | void paintBlob (int x, int y, int type) 229 | { 230 | if (type == 0) 231 | { 232 | fillRect(green, x, y-1, 1, 2); 233 | blendRect(green, x-1, y, 3, 1); 234 | } 235 | else if (type == 1) 236 | { 237 | fillRect(red, x, y, 2, 1); 238 | blendRect(red, x, y-1, 1, 3); 239 | } 240 | else if (type == 2) 241 | { 242 | fillRect(blue, x, y, 1, 2); 243 | blendRect(blue, x-1, y, 3, 1); 244 | } 245 | else if (type == 3) 246 | { 247 | fillRect(yellow, x-1, y, 2, 1); 248 | blendRect(yellow, x, y-1, 1, 3); 249 | } 250 | } 251 | 252 | 253 | void assignBlob (int x, int y, int index, int type) 254 | { 255 | if (index == 0) 256 | { 257 | blob1x = x; 258 | blob1y = y; 259 | blob1d = type; 260 | spawnBullet1(); 261 | } 262 | else if (index == 1) 263 | { 264 | blob2x = x; 265 | blob2y = y; 266 | blob2d = type; 267 | spawnBullet2(); 268 | } 269 | else if (index == 2) 270 | { 271 | blob3x = x; 272 | blob3y = y; 273 | blob3d = type; 274 | spawnBullet3(); 275 | } 276 | else if (index == 3) 277 | { 278 | blob4x = x; 279 | blob4y = y; 280 | blob4d = type; 281 | spawnBullet4(); 282 | } 283 | else if (index == 4) 284 | { 285 | blob5x = x; 286 | blob5y = y; 287 | blob5d = type; 288 | spawnBullet5(); 289 | } 290 | } 291 | 292 | // Make Bullets! 293 | 294 | void spawnBullet1() 295 | { 296 | bullet1x = blob1x; 297 | bullet1y = blob1y; 298 | bullet1d = blob1d; 299 | } 300 | 301 | void spawnBullet2() 302 | { 303 | bullet2x = blob2x; 304 | bullet2y = blob2y; 305 | bullet2d = blob2d; 306 | } 307 | 308 | void spawnBullet3() 309 | { 310 | bullet3x = blob3x; 311 | bullet3y = blob3y; 312 | bullet3d = blob3d; 313 | } 314 | 315 | void spawnBullet4() 316 | { 317 | bullet4x = blob4x; 318 | bullet4y = blob4y; 319 | bullet4d = blob4d; 320 | } 321 | 322 | void spawnBullet5() 323 | { 324 | bullet5x = blob5x; 325 | bullet5y = blob5y; 326 | bullet5d = blob5d; 327 | } 328 | 329 | 330 | void drawBullet (float x, float y, int d) 331 | { 332 | fillPixel(0xFF222222, int(x), int(y)); 333 | 334 | if (d == 0) 335 | { 336 | fillPixel(0xFFFFFF, int(x), int(y-1)); 337 | } 338 | else if (d == 1) 339 | { 340 | fillPixel(0xFFFFFF, int(x+1), int(y)); 341 | } 342 | else if (d == 2) 343 | { 344 | fillPixel(0xFFFFFF, int(x), int(y+1)); 345 | } 346 | else 347 | { 348 | fillPixel(0xFFFFFF, int(x-1), int(y)); 349 | } 350 | } 351 | 352 | void updateBullet1() 353 | { 354 | if (blob1d == 0) 355 | { 356 | bullet1y = bullet1y - speed; 357 | } 358 | else if (blob1d == 1) 359 | { 360 | bullet1x = bullet1x + speed; 361 | } 362 | else if (blob1d == 2) 363 | { 364 | bullet1y = bullet1y + speed; 365 | } 366 | else if (blob1d == 3) 367 | { 368 | bullet1x = bullet1x - speed; 369 | } 370 | } 371 | 372 | void updateBullet2() 373 | { 374 | if (blob2d == 0) 375 | { 376 | bullet2y = bullet2y - speed; 377 | } 378 | else if (blob2d == 1) 379 | { 380 | bullet2x = bullet2x + speed; 381 | } 382 | else if (blob2d == 2) 383 | { 384 | bullet2y = bullet2y + speed; 385 | } 386 | else if (blob2d == 3) 387 | { 388 | bullet2x = bullet2x - speed; 389 | } 390 | } 391 | 392 | void updateBullet3() 393 | { 394 | if (blob3d == 0) 395 | { 396 | bullet3y = bullet3y - speed; 397 | } 398 | else if (blob3d == 1) 399 | { 400 | bullet3x = bullet3x + speed; 401 | } 402 | else if (blob3d == 2) 403 | { 404 | bullet3y = bullet3y + speed; 405 | } 406 | else if (blob3d == 3) 407 | { 408 | bullet3x = bullet3x - speed; 409 | } 410 | } 411 | 412 | void updateBullet4() 413 | { 414 | if (blob4d == 0) 415 | { 416 | bullet4y = bullet4y - speed; 417 | } 418 | else if (blob4d == 1) 419 | { 420 | bullet4x = bullet4x + speed; 421 | } 422 | else if (blob4d == 2) 423 | { 424 | bullet4y = bullet4y + speed; 425 | } 426 | else if (blob4d == 3) 427 | { 428 | bullet4x = bullet4x - speed; 429 | } 430 | } 431 | 432 | void updateBullet5() 433 | { 434 | if (blob5d == 0) 435 | { 436 | bullet5y = bullet5y - speed; 437 | } 438 | else if (blob5d == 1) 439 | { 440 | bullet5x = bullet5x + speed; 441 | } 442 | else if (blob5d == 2) 443 | { 444 | bullet5y = bullet5y + speed; 445 | } 446 | else if (blob5d == 3) 447 | { 448 | bullet5x = bullet5x - speed; 449 | } 450 | } 451 | 452 | void detectBullet() 453 | { 454 | //Bullet1 455 | if (bullet1x > 15) 456 | { 457 | spawnBullet1(); 458 | midiNote(0, 0); 459 | } 460 | else if (bullet1x < 0 && bullet1x > -90) 461 | { 462 | spawnBullet1(); 463 | midiNote(0, 1); 464 | } 465 | else if (bullet1y > 15) 466 | { 467 | spawnBullet1(); 468 | midiNote(0, 2); 469 | } 470 | else if (bullet1y < 0 && bullet1y > -90) 471 | { 472 | spawnBullet1(); 473 | midiNote(0, 3); 474 | } 475 | 476 | //Bullet2 477 | if (bullet2x > 15) 478 | { 479 | spawnBullet2(); 480 | midiNote(1, 0); 481 | } 482 | else if (bullet2x < 0 && bullet2x > -90) 483 | { 484 | spawnBullet2(); 485 | midiNote(1, 1); 486 | } 487 | else if (bullet2y > 15) 488 | { 489 | spawnBullet2(); 490 | midiNote(1, 2); 491 | } 492 | else if (bullet2y < 0 && bullet2y > -90) 493 | { 494 | spawnBullet2(); 495 | midiNote(1, 3); 496 | } 497 | 498 | //Bullet3 499 | if (bullet3x > 15) 500 | { 501 | spawnBullet3(); 502 | midiNote(2, 0); 503 | } 504 | else if (bullet3x < 0 && bullet3x > -90) 505 | { 506 | spawnBullet3(); 507 | midiNote(2, 1); 508 | } 509 | else if (bullet3y > 15) 510 | { 511 | spawnBullet3(); 512 | midiNote(2, 2); 513 | } 514 | else if (bullet3y < 0 && bullet3y > -90) 515 | { 516 | spawnBullet3(); 517 | midiNote(2, 3); 518 | } 519 | 520 | //Bullet4 521 | if (bullet4x > 15) 522 | { 523 | spawnBullet4(); 524 | midiNote(3, 0); 525 | } 526 | else if (bullet4x < 0 && bullet4x > -90) 527 | { 528 | spawnBullet4(); 529 | midiNote(3, 1); 530 | } 531 | else if (bullet4y > 15) 532 | { 533 | spawnBullet4(); 534 | midiNote(3, 2); 535 | } 536 | else if (bullet4y < 0 && bullet4y > -90) 537 | { 538 | spawnBullet4(); 539 | midiNote(3, 3); 540 | } 541 | 542 | //Bullet5 543 | if (bullet5x > 15) 544 | { 545 | spawnBullet5(); 546 | midiNote(4, 0); 547 | } 548 | else if (bullet5x < 0 && bullet5x > -90) 549 | { 550 | spawnBullet5(); 551 | midiNote(4, 1); 552 | } 553 | else if (bullet5y > 15) 554 | { 555 | spawnBullet5(); 556 | midiNote(4, 2); 557 | } 558 | else if (bullet5y < 0 && bullet5y > -90) 559 | { 560 | spawnBullet5(); 561 | midiNote(4, 3); 562 | } 563 | } 564 | 565 | //MIDI FUN! 566 | 567 | void midiNote(int note1, int note2) 568 | { 569 | note2 = note2 * 12; 570 | int note = rootNote; 571 | 572 | if (note1 == 0) 573 | { 574 | note = note + note2; 575 | note1(note); 576 | } 577 | else if (note1 == 1) 578 | { 579 | if (chord == 0) 580 | { 581 | note = note + 4; 582 | } 583 | else 584 | { 585 | note = note + 3; 586 | } 587 | note = note + note2; 588 | note2(note); 589 | } 590 | else if (note1 == 2) 591 | { 592 | note = note + 7; 593 | note = note + note2; 594 | note3(note); 595 | } 596 | else if (note1 == 3) 597 | { 598 | if (chord == 0) 599 | { 600 | note = note + 11; 601 | } 602 | else 603 | { 604 | note = note + 10; 605 | } 606 | note = note + note2; 607 | note4(note); 608 | } 609 | else if (note1 == 4) 610 | { 611 | note = note + 14; 612 | note = note + note2; 613 | note5(note); 614 | } 615 | } 616 | 617 | void note1(int note) 618 | { 619 | sendNoteOff (0, lastNote1, 80); 620 | sendNoteOn (0, note, 80); 621 | lastNote1 = note; 622 | } 623 | void note2(int note) 624 | { 625 | sendNoteOff (0, lastNote2, 80); 626 | sendNoteOn (0, note, 80); 627 | lastNote2 = note; 628 | } 629 | void note3(int note) 630 | { 631 | sendNoteOff (0, lastNote3, 80); 632 | sendNoteOn (0, note, 80); 633 | lastNote3 = note; 634 | } 635 | void note4(int note) 636 | { 637 | sendNoteOff (0, lastNote4, 80); 638 | sendNoteOn (0, note, 80); 639 | lastNote4 = note; 640 | } 641 | void note5(int note) 642 | { 643 | sendNoteOff (0, lastNote5, 80); 644 | sendNoteOn (0, note, 80); 645 | lastNote5 = note; 646 | } 647 | 648 | void handleButtonDown (int index) 649 | { 650 | initialise(); 651 | } 652 | 653 | void repaint() 654 | { 655 | clearDisplay(); 656 | 657 | //Draw 5 Blobs 658 | paintBlob(blob1x, blob1y, blob1d); 659 | paintBlob(blob2x, blob2y, blob2d); 660 | paintBlob(blob3x, blob3y, blob3d); 661 | paintBlob(blob4x, blob4y, blob4d); 662 | paintBlob(blob5x, blob5y, blob5d); 663 | 664 | //Draw 5 Bullets 665 | drawBullet(bullet1x, bullet1y, blob1d); 666 | drawBullet(bullet2x, bullet2y, blob2d); 667 | drawBullet(bullet3x, bullet3y, blob3d); 668 | drawBullet(bullet4x, bullet4y, blob4d); 669 | drawBullet(bullet5x, bullet5y, blob5d); 670 | 671 | //Update Bullet 672 | updateBullet1(); 673 | updateBullet2(); 674 | updateBullet3(); 675 | updateBullet4(); 676 | updateBullet5(); 677 | 678 | //Detect Collision 679 | detectBullet(); 680 | } 681 | 682 | /* 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | */ 709 | -------------------------------------------------------------------------------- /Factory Scripts/Control Grid.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | */ 28 | 29 | #heapsize: 381 30 | 31 | /* 32 | * Heap layout is as follows: 33 | * bytes 0 - 16 touch to touch pads 34 | * byte 32+ 35 | * Index 0 4 bytes note off delta 36 | * Index 1 4 bytes start time 37 | * Index 2 4 bytes velocity 38 | * 39 | */ 40 | 41 | int padWidth; 42 | int padSpacing; 43 | int gridSize; 44 | int numPads; // Num pads in the grid, so a gridSize=4 would set this to 16 45 | int activePads; 46 | int dimFactor; 47 | int dimDelay; 48 | int dimDelta; 49 | 50 | const int behaviourNoteOnOff = 0; 51 | const int behaviourCC = 1; 52 | const int actionToggle = 0; 53 | const int actionGate = 1; 54 | const int actionTrigger = 2; 55 | 56 | void setPadActive (int padIndex, bool shouldBeActive) 57 | { 58 | activePads = shouldBeActive ? (activePads | (1 << padIndex)) : (activePads & ~(1 << padIndex)); 59 | } 60 | 61 | bool isPadActive (int padIndex) 62 | { 63 | return activePads & (1 << padIndex); 64 | } 65 | 66 | bool isAnyPadActive() 67 | { 68 | return activePads; 69 | } 70 | 71 | void setPadForTouch (int touchIndex, int padIndex) 72 | { 73 | setHeapByte (touchIndex, padIndex); 74 | } 75 | 76 | int getPadForTouch (int touchIndex) 77 | { 78 | return getHeapByte (touchIndex); 79 | } 80 | 81 | int getTrailColour (int padColour) 82 | { 83 | if (gridSize == 1) 84 | { 85 | // Note - With a grid size of 1, we dont see the pad dim at note on (and hence its next to impossible to see the touch) 86 | // With this, we draw a white heat trail over the top of the pad, giving a clear touch indication 87 | // There is the potential that the heat trail being white might clash with the chosen colour, 88 | // But given that its white, i figure we will normally still be able to see it, and it avoids having 89 | return 0xFFFFFF; 90 | } 91 | 92 | if (padColour == 0xff000000) 93 | { 94 | return 0xffaaaaaa; 95 | } 96 | 97 | return blendARGB (0x88ffffff, padColour); 98 | } 99 | 100 | void onStateChanged() 101 | { 102 | gridSize = gridOption + 1; 103 | numPads = gridSize * gridSize; 104 | padWidth = 15 / gridSize; 105 | padSpacing = gridSize > 1 ? (15 - gridSize * padWidth) / (gridSize - 1) : 0; 106 | padWidth += padSpacing; 107 | } 108 | 109 | void initialise() 110 | { 111 | onStateChanged(); 112 | activePads = 0; 113 | dimFactor = 0; 114 | dimDelta = 0; 115 | dimDelay = 12; 116 | 117 | for (int i = 0; i < 32; ++i) 118 | setLocalConfigActiveState (i, false, false); 119 | } 120 | 121 | void updateDimFactor() 122 | { 123 | if (isAnyPadActive() || dimDelta) 124 | { 125 | if (dimFactor < 180) 126 | { 127 | dimDelta = 60; 128 | } 129 | else 130 | { 131 | dimDelta = 0; 132 | } 133 | 134 | dimFactor += dimDelta; 135 | dimDelay = 8; 136 | } 137 | else 138 | { 139 | if (--dimDelay <= 0) 140 | { 141 | dimFactor -= 24; 142 | 143 | if (dimFactor < 0) 144 | { 145 | dimFactor = 0; 146 | } 147 | } 148 | } 149 | } 150 | 151 | void drawPads() 152 | { 153 | int padIndex = 0; 154 | for (int padY = 0; padY < gridSize; ++padY) 155 | { 156 | for (int padX = 0; padX < gridSize; ++padX) 157 | { 158 | int padColour = getPadColour (padIndex); 159 | int overlayColour = isPadActive (padIndex) ? 0x33ffffff : (dimFactor << 24); 160 | 161 | fillRect (blendARGB (padColour, overlayColour), 162 | padX * padWidth, (gridSize - padY - 1) * padWidth, 163 | padWidth - padSpacing, padWidth - padSpacing); 164 | 165 | 166 | ++padIndex; 167 | } 168 | } 169 | } 170 | 171 | void sendNoteOffForPad (int padIndex, int velocity) 172 | { 173 | sendNoteOff ((channel - 1), getNote (padIndex), velocity); 174 | setPadActive (padIndex, false); 175 | } 176 | 177 | void sendNoteOnForPad (int padIndex, int velocity) 178 | { 179 | sendNoteOn ((channel - 1), getNote (padIndex), velocity); 180 | setPadActive (padIndex, true); 181 | } 182 | 183 | void sendCCForPad (int padIndex, int ccValue, bool changePadActiveStatus) 184 | { 185 | sendCC ((channel - 1), getCC (padIndex), ccValue); 186 | if (changePadActiveStatus) 187 | { 188 | setPadActive (padIndex, ccValue == 127); 189 | } 190 | } 191 | 192 | int getVelocityForVz (float vz) 193 | { 194 | return clamp (1, 127, int (vz * 127.0)); 195 | } 196 | 197 | int getPressureForZ (float z) 198 | { 199 | return int ((z * z) * 127.0); 200 | } 201 | 202 | void handleNoteOnOffTouchStart (int padIndex, int action, int velocity, bool pressure) 203 | { 204 | if (action == actionToggle) 205 | { 206 | if (isPadActive (padIndex)) 207 | { 208 | sendNoteOffForPad (padIndex, velocity); 209 | } 210 | else 211 | { 212 | sendNoteOnForPad (padIndex, velocity); 213 | } 214 | } 215 | else if (action == actionGate) 216 | { 217 | sendNoteOnForPad (padIndex, velocity); 218 | } 219 | else if (action == actionTrigger) 220 | { 221 | sendNoteOnForPad (padIndex, velocity); 222 | setPadOffDeltaTime (padIndex, noteOffTime, velocity); 223 | } 224 | } 225 | 226 | void sendPressure (int padIndex, int pressure) 227 | { 228 | if (getBehaviour (padIndex) == behaviourNoteOnOff) 229 | { 230 | if (wantsPolyPressure) 231 | { 232 | sendMIDI (0xa0 | (channel - 1), getNote (padIndex), pressure); 233 | } 234 | else 235 | { 236 | sendMIDI (0xd0 | (channel - 1), pressure); 237 | } 238 | } 239 | else 240 | { 241 | sendCCForPad (padIndex, pressure, false); 242 | } 243 | } 244 | 245 | void handleCCTouchStart (int padIndex, int action, int velocity, bool pressure) 246 | { 247 | if (! pressure) 248 | { 249 | if (action == actionToggle) 250 | { 251 | if (isPadActive (padIndex)) 252 | { 253 | sendCCForPad (padIndex, 0, true); 254 | } 255 | else 256 | { 257 | sendCCForPad (padIndex, 127, true); 258 | } 259 | } 260 | else if (action == actionGate) 261 | { 262 | sendCCForPad (padIndex, 127, true); 263 | } 264 | else if (action == actionTrigger) 265 | { 266 | sendCCForPad (padIndex, 127, true); 267 | setPadOffDeltaTime (padIndex, noteOffTime, 0); 268 | } 269 | } 270 | } 271 | 272 | void touchStart (int touchIndex, float x, float y, float z, float vz) 273 | { 274 | int row = gridSize - (int (y * (0.95 / 2.0) * float (gridSize))) - 1; 275 | int col = int (x * (0.95 / 2.0) * float (gridSize)); 276 | int padIndex = (gridSize * row) + col; 277 | 278 | int action = getAction (padIndex); 279 | int velocity = getVelocityForVz (vz); 280 | bool pressure = getPressure (padIndex); 281 | 282 | if (getBehaviour (padIndex) == behaviourNoteOnOff) 283 | { 284 | handleNoteOnOffTouchStart (padIndex, action, velocity, pressure); 285 | } 286 | else 287 | { 288 | handleCCTouchStart (padIndex, action, velocity, pressure); 289 | } 290 | 291 | if (pressure) 292 | { 293 | sendPressure (padIndex, getPressureForZ (z)); 294 | } 295 | 296 | addPressurePoint (getTrailColour (getPadColour (padIndex)), x, y, z * 10.0); 297 | setPadForTouch (touchIndex, padIndex); 298 | } 299 | 300 | void touchMove (int touchIndex, float x, float y, float z, float vz) 301 | { 302 | int padIndex = getPadForTouch (touchIndex); 303 | if (padIndex == 0xff) 304 | { 305 | return; // touch was not started. 306 | } 307 | 308 | if (getPressure (padIndex)) 309 | { 310 | sendPressure (padIndex, getPressureForZ (z)); 311 | } 312 | 313 | addPressurePoint (getTrailColour (getPadColour (padIndex)), x, y, z * 10.0); 314 | } 315 | 316 | void touchEnd (int touchIndex, float x, float y, float z, float vz) 317 | { 318 | int padIndex = getPadForTouch (touchIndex); 319 | 320 | if (padIndex == 0xff) 321 | { 322 | return; // touch was not started. 323 | } 324 | 325 | if (getPressure (padIndex)) 326 | { 327 | sendPressure (padIndex, getPressureForZ (z)); 328 | } 329 | 330 | int behaviour = getBehaviour (padIndex); 331 | int action = getAction (padIndex); 332 | if (behaviour == behaviourNoteOnOff) 333 | { 334 | if (action == actionGate) 335 | { 336 | sendNoteOffForPad (padIndex, getVelocityForVz (vz)); 337 | } 338 | } 339 | else 340 | { 341 | if (action == actionGate && ! getPressure (padIndex)) 342 | { 343 | sendCCForPad (padIndex, 0, true); 344 | } 345 | } 346 | 347 | setPadForTouch (touchIndex, 0xff); 348 | } 349 | 350 | void setPadOffDeltaTime (int padIndex, int delta, int velocity) 351 | { 352 | int basePadAddress = 32 + (padIndex * 12); 353 | 354 | setHeapInt (basePadAddress, delta); 355 | setHeapInt (basePadAddress + 4, getMillisecondCounter()); 356 | setHeapInt (basePadAddress + 8, velocity); 357 | } 358 | 359 | void updateNoteOffTime() 360 | { 361 | int currentTime = getMillisecondCounter(); 362 | for (int padIndex = 0; padIndex < numPads; ++padIndex) 363 | { 364 | int padAddress = 32 + (padIndex * 12); 365 | int padTime = getHeapInt (padAddress); 366 | if (padTime > 0) 367 | { 368 | int padStartTime = getHeapInt (padAddress + 4); 369 | if (currentTime - padStartTime >= padTime) 370 | { 371 | int velocity = getHeapInt (padAddress + 8); 372 | if (getBehaviour (padIndex) == 0) 373 | { 374 | sendNoteOffForPad (padIndex, velocity); 375 | } 376 | else 377 | { 378 | sendCCForPad (padIndex, velocity, false); 379 | } 380 | setPadOffDeltaTime (padIndex, 0, 0); 381 | } 382 | } 383 | } 384 | } 385 | 386 | void repaint() 387 | { 388 | clearDisplay(); 389 | updateDimFactor(); 390 | drawPads(); 391 | updateNoteOffTime(); 392 | drawPressureMap(); 393 | fadePressureMap(); 394 | } 395 | 396 | 397 | /* 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | */ -------------------------------------------------------------------------------- /Factory Scripts/Drum Block.littlefoot: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 73 | 74 | 89 | 90 | */ 91 | 92 | #heapsize: 381 93 | 94 | //============================================================================== 95 | /* 96 | Heap layout: 97 | 98 | === 25 x Pad === 99 | 100 | 0 4 byte x 25 colours 101 | 100 1 byte x 25 note numbers 102 | 103 | === 24 x Touch === 104 | 105 | 125 1 byte x 24 corresponding pad index (0xff if none) 106 | 149 4 byte x 24 initial x positions (for relative pitchbend) 107 | 245 4 byte x 24 initial y positions (for relative y axis) 108 | 341 1 byte x 24 MIDI channel assigned 109 | 110 | === 16 x Channel === 111 | 112 | 365 1 byte x 16 touch to track for this channel (depends on tracking mode) 113 | */ 114 | //============================================================================== 115 | 116 | int padWidth, padSpacing; 117 | int dimFactor, dimDelay, dimDelta; 118 | int channelLastAssigned; 119 | int activePads; 120 | int clusterWidth; 121 | int clusterHeight; 122 | 123 | //============================================================================== 124 | void checkAndUpdateCluster() 125 | { 126 | int w = getClusterWidth(); 127 | int h = getClusterHeight(); 128 | 129 | if (clusterWidth != w || clusterHeight != h) 130 | { 131 | updateCluster(); 132 | } 133 | } 134 | 135 | //============================================================================== 136 | void updateCluster() 137 | { 138 | clusterWidth = getClusterWidth(); 139 | clusterHeight = getClusterHeight(); 140 | 141 | if (clusterWidth == 1 && clusterHeight == 1) 142 | return; 143 | 144 | int x = getClusterXpos() % 4; 145 | int y = getClusterYpos() % 4; 146 | 147 | int numPadsInGrid = (gridSize * gridSize); 148 | 149 | if (clusterWidth == 2 && clusterHeight == 1) 150 | baseNote += (x * numPadsInGrid); 151 | else if (clusterWidth == 1 && clusterHeight == 2) 152 | baseNote += (y * numPadsInGrid); 153 | else 154 | baseNote += ((x * clusterWidth) + y) * numPadsInGrid; 155 | 156 | baseNote = min (baseNote, 127 - numPadsInGrid); 157 | } 158 | 159 | //============================================================================== 160 | int Pad_getColour (int padIndex) 161 | { 162 | if (padIndex == 0) return padColour1; 163 | if (padIndex == 1) return padColour2; 164 | if (padIndex == 2) return padColour3; 165 | if (padIndex == 3) return padColour4; 166 | if (padIndex == 4) return padColour5; 167 | if (padIndex == 5) return padColour6; 168 | if (padIndex == 6) return padColour7; 169 | if (padIndex == 7) return padColour8; 170 | if (padIndex == 8) return padColour9; 171 | if (padIndex == 9) return padColour10; 172 | if (padIndex == 10) return padColour11; 173 | if (padIndex == 11) return padColour12; 174 | if (padIndex == 12) return padColour13; 175 | if (padIndex == 13) return padColour14; 176 | if (padIndex == 14) return padColour15; 177 | if (padIndex == 15) return padColour16; 178 | 179 | return 0xffffffff; 180 | } 181 | 182 | void Pad_setNote (int padIndex, int note) 183 | { 184 | setHeapByte (padIndex + 100, note); 185 | } 186 | 187 | int Pad_getNote (int padIndex) 188 | { 189 | return baseNote + padIndex; 190 | } 191 | 192 | void Pad_setActive (int padIndex, bool shouldBeActive) 193 | { 194 | activePads = shouldBeActive ? (activePads | (1 << padIndex)) 195 | : (activePads & ~(1 << padIndex)); 196 | } 197 | 198 | bool Pad_isActive (int padIndex) 199 | { 200 | return activePads & (1 << padIndex); 201 | } 202 | 203 | bool isAnyPadActive() 204 | { 205 | return activePads; 206 | } 207 | 208 | //============================================================================== 209 | void Touch_setPad (int touchIndex, int padIndex) 210 | { 211 | setHeapByte (touchIndex + 125, padIndex); 212 | } 213 | 214 | int Touch_getPad (int touchIndex) 215 | { 216 | return getHeapByte (touchIndex + 125); 217 | } 218 | 219 | // Note: littlefoot doesn't have set/getHeapFloat yet, so we store initial x/y 220 | // positions as ints, scaled up by a factor of 1e6. 221 | void Touch_setInitialX (int touchIndex, float initialX) 222 | { 223 | setHeapInt ((touchIndex * 4) + 149, int (initialX * 1e6)); 224 | } 225 | 226 | float Touch_getInitialX (int touchIndex) 227 | { 228 | return float (getHeapInt ((touchIndex * 4) + 149)) / 1e6; 229 | } 230 | 231 | void Touch_setInitialY (int touchIndex, float initialY) 232 | { 233 | setHeapInt ((touchIndex * 4) + 245, int (initialY * 1e6)); 234 | } 235 | 236 | float Touch_getInitialY (int touchIndex) 237 | { 238 | return float (getHeapInt ((touchIndex * 4) + 245)) / 1e6; 239 | } 240 | 241 | void Touch_setChannel (int touchIndex, int channel) 242 | { 243 | setHeapByte (touchIndex + 341, channel); 244 | } 245 | 246 | int Touch_getChannel (int touchIndex) 247 | { 248 | return getHeapByte (touchIndex + 341); 249 | } 250 | 251 | //============================================================================== 252 | void Channel_setTrackedTouch (int channel, int touchIndex) 253 | { 254 | setHeapByte (channel + 365, touchIndex); 255 | } 256 | 257 | int Channel_getTrackedTouch (int channel) 258 | { 259 | return getHeapByte (channel + 365); 260 | } 261 | 262 | //============================================================================== 263 | int getTouchedPad (float x, float y) 264 | { 265 | // Pad positions are inverted in y - i.e. 0 is bottom left, not top left. 266 | int row = gridSize - (int (y * (0.95 / 2.0) * float (gridSize))) - 1; 267 | int col = int (x * (0.95 / 2.0) * float (gridSize)); 268 | 269 | return (gridSize * row) + col; 270 | } 271 | 272 | //============================================================================== 273 | int getTrailColour (int padColour) 274 | { 275 | if (gridSize == 1) 276 | { 277 | // Note - With a grid size of 1, we dont see the pad dim at note on (and hence its next to impossible to see the touch) 278 | // With this, we draw a white heat trail over the top of the pad, giving a clear touch indication 279 | // There is the potential that the heat trail being white might clash with the chosen colour, 280 | // But given that its white, i figure we will normally still be able to see it, and it avoids having 281 | return 0xFFFFFF; 282 | } 283 | 284 | if (padColour == 0xff000000) 285 | return 0xffaaaaaa; 286 | 287 | return blendARGB (0x88ffffff, padColour); 288 | } 289 | 290 | //============================================================================== 291 | void updateDimFactor() 292 | { 293 | if (isAnyPadActive() || dimDelta) 294 | { 295 | if (dimFactor < 180) 296 | dimDelta = 60; 297 | else 298 | dimDelta = 0; 299 | 300 | dimFactor += dimDelta; 301 | dimDelay = 8; 302 | } 303 | else 304 | { 305 | if (--dimDelay <= 0) 306 | { 307 | dimFactor -= 24; 308 | 309 | if (dimFactor < 0) 310 | dimFactor = 0; 311 | } 312 | } 313 | } 314 | 315 | //============================================================================== 316 | void drawPad (int x, int y, int colour, int bottomRightCornerDarkeningAmount) 317 | { 318 | int dark = blendARGB (colour, bottomRightCornerDarkeningAmount << 24); 319 | int mid = blendARGB (colour, (bottomRightCornerDarkeningAmount / 2) << 24); 320 | 321 | int w = padWidth - padSpacing; 322 | blendGradientRect (colour, mid, dark, mid, x * padWidth, y * padWidth, w, w); 323 | } 324 | 325 | void drawPads() 326 | { 327 | int padIndex = 0; 328 | 329 | for (int padY = 0; padY < gridSize; ++padY) 330 | { 331 | for (int padX = 0; padX < gridSize; ++padX) 332 | { 333 | int overlayColour = Pad_isActive (padIndex) ? 0x33ffffff : (dimFactor << 24); 334 | 335 | drawPad (padX, gridSize - padY - 1, blendARGB (Pad_getColour (padIndex), overlayColour), 0xcc); 336 | 337 | ++padIndex; 338 | } 339 | } 340 | } 341 | 342 | //============================================================================== 343 | void initialisePads() 344 | { 345 | for (int padIndex = 0; padIndex < 25; ++padIndex) 346 | { 347 | // note numbers: 348 | Pad_setNote (padIndex, baseNote + padIndex); 349 | } 350 | 351 | activePads = 0; 352 | } 353 | 354 | void initialiseTouches() 355 | { 356 | for (int touchIndex = 0; touchIndex < 24; ++touchIndex) 357 | { 358 | Touch_setPad (touchIndex, 0xff); 359 | Touch_setChannel (touchIndex, 0xff); 360 | } 361 | } 362 | 363 | void initialiseChannels() 364 | { 365 | for (int channel = 0; channel < 16; ++channel) 366 | { 367 | Channel_setTrackedTouch (channel, 0xff); 368 | 369 | // Send note-offs for all channels & notes to avoid stuck notes 370 | // when modifying dynamic variables from the sidepanel. 371 | sendMIDI (0xb0 | channel, 120, 0); // All sound off msg 372 | sendMIDI (0xb0 | channel, 123, 0); // All notes off msg 373 | } 374 | } 375 | 376 | void initialise() 377 | { 378 | updateCluster(); 379 | 380 | padWidth = 15 / gridSize; 381 | padSpacing = gridSize > 1 ? (15 - gridSize * padWidth) / (gridSize - 1) : 0; 382 | padWidth += padSpacing; 383 | 384 | dimFactor = 0; 385 | dimDelta = 0; 386 | dimDelay = 12; 387 | 388 | initialisePads(); 389 | initialiseTouches(); 390 | initialiseChannels(); 391 | 392 | useMPEDuplicateFilter (true); 393 | setChannelRange (midiMode == 0, channelFirst, channelLast); 394 | for (int i = 0; i < 32; ++i) 395 | setLocalConfigActiveState (i, false, false); 396 | } 397 | 398 | //============================================================================== 399 | void repaint() 400 | { 401 | clearDisplay(); 402 | updateDimFactor(); 403 | 404 | if (isConnectedToHost()) 405 | drawPads(); 406 | 407 | // Overlay heatmap 408 | drawPressureMap(); 409 | fadePressureMap(); 410 | 411 | checkAndUpdateCluster(); 412 | } 413 | 414 | //============================================================================== 415 | int getPitchwheelValue (int touchIndex, float x) 416 | { 417 | if (! shouldSendPitchBend) 418 | return 8192; 419 | 420 | float blockWidthUnits = 2.0; 421 | float initialX = Touch_getInitialX (touchIndex); 422 | float deltaX = (x - initialX) * (blockWidthUnits + 0.1); // Adjust width by 0.1 as edges are hard to reach 423 | 424 | if (abs (deltaX) > 1.0) 425 | { 426 | // Initially the note centre is at centre of the finger strike, 427 | // but after a significant slide is performed, we want to use the 428 | // actual pad centres to avoid confusion about pad boundaries. 429 | float divisor = 1.0 / float (gridSize); 430 | 431 | initialX = ((mod (Touch_getPad (touchIndex), gridSize) * divisor) + (divisor * 0.5)) * blockWidthUnits; 432 | deltaX = (x - initialX) * (blockWidthUnits + 0.1); // recompute with new initialX 433 | } 434 | int pitchWheel = getPitchWheelFromDeltaX (deltaX); 435 | return pitchWheel; 436 | } 437 | 438 | //============================================================================== 439 | int getPitchWheelFromDeltaX (float deltaX) 440 | { 441 | // Wheel range is front 0 - 1, where 0.5 is linear. We dont want it to go fully to zero tho, because that disabled the curve 442 | float wheelRange = ((pitchBendCurve * 0.85) + 0.15); 443 | float center = 8192.0; 444 | float range = 8192.0 * wheelRange; 445 | float minRange = center - range; 446 | float maxRange = center + range; 447 | float pitchwheel = map (deltaX, -2.0, 2.0, minRange, maxRange); 448 | return clamp (0, 16383, int (pitchwheel)); 449 | } 450 | 451 | //============================================================================== 452 | int getYAxisValue (int touchIndex, float y) 453 | { 454 | float initialY = Touch_getInitialY (touchIndex); 455 | 456 | if (y >= initialY) 457 | y = map (y, initialY, 2.0, 0.0, -1.0); 458 | else 459 | y = map (y, 0.0, initialY, 1.0, 0.0); 460 | 461 | y = 0.5 + (0.5 * applyCurve (y)); 462 | 463 | return clamp (0, 127, int (y * 127)); 464 | } 465 | 466 | float applyCurve (float y) 467 | { 468 | float absY = slideCoef < 0 ? 1.0 - abs (y) : abs(y); 469 | float absCoef = abs (slideCoef); 470 | 471 | if (absCoef < 0.01) 472 | return y; 473 | 474 | float ky = (16.0 * absCoef / (1.0 + absCoef)) * absY; 475 | float curved = (absY + ky) / (1 + ky); 476 | 477 | if (slideCoef < 0) 478 | curved = 1 - curved; 479 | 480 | if (y < 0) 481 | curved = -curved; 482 | 483 | return curved; 484 | } 485 | 486 | //============================================================================== 487 | bool shouldTrackNewTouch (int channel, int touchIndex, int note) 488 | { 489 | if (trackingMode == 0) 490 | return true; // track last note on channel: new note always overrides old one! 491 | 492 | int previouslyTrackedTouch = Channel_getTrackedTouch (channel); 493 | 494 | if (previouslyTrackedTouch == 0xff) 495 | return true; // channel is free and can track this touch 496 | 497 | int previouslyTrackedNote = Pad_getNote (Touch_getPad (previouslyTrackedTouch)); 498 | 499 | if ((trackingMode == 1 && note > previouslyTrackedNote) || (trackingMode == 2 && note < previouslyTrackedNote)) 500 | return true; // new note is higher/lower than previous note, and we should track highest/lowest note 501 | 502 | return false; 503 | } 504 | 505 | //============================================================================== 506 | void touchStart (int touchIndex, float x, float y, float z, float vz) 507 | { 508 | int padIndex = getTouchedPad (x, y); 509 | int note = Pad_getNote (padIndex); 510 | int colour = Pad_getColour (padIndex); 511 | int channel = assignChannel (note); 512 | int velocity = fixedStrikeOn ? fixedStrikeValue : clamp (1, 127, int (vz * 127.0)); 513 | int pressure = clamp (0, 127, int (z * 127.0)); 514 | 515 | if (pressType == 0) // channel pressure 516 | sendMIDI (0xd0 | channel, pressure); 517 | 518 | else // poly aftertouch 519 | sendMIDI (0xa0 | channel, note, pressure); 520 | 521 | sendPitchBend (channel, 8192); 522 | sendMIDI (0xb0 | channel, slideCc, 64); // initial Y in relative mode 523 | sendNoteOn (channel, note, velocity); 524 | 525 | addPressurePoint (getTrailColour (colour), x, y, z * 10.0); 526 | 527 | Pad_setActive (padIndex, true); 528 | 529 | Touch_setPad (touchIndex, padIndex); 530 | Touch_setInitialX (touchIndex, x); 531 | Touch_setInitialY (touchIndex, y); 532 | Touch_setChannel (touchIndex, channel); 533 | 534 | if (shouldTrackNewTouch (channel, touchIndex, note)) 535 | Channel_setTrackedTouch (channel, touchIndex); 536 | } 537 | 538 | void touchMove (int touchIndex, float x, float y, float z, float vz) 539 | { 540 | int padIndex = Touch_getPad (touchIndex); 541 | int channel = Touch_getChannel (touchIndex); 542 | 543 | if (padIndex == 0xff) 544 | return; // touch was not started. 545 | 546 | if (Channel_getTrackedTouch (channel) != touchIndex) 547 | return; // these are not the touch messages you're looking for... 548 | 549 | int pressure = clamp (0, 127, int (z * 127.0)); 550 | 551 | if (pressType == 0) // channel pressure 552 | sendMIDI (0xd0 | channel, pressure); 553 | 554 | else // poly aftertouch 555 | sendMIDI (0xa0 | channel, Pad_getNote (padIndex), pressure); 556 | 557 | sendMIDI (0xb0 | channel, slideCc, getYAxisValue (touchIndex, y)); 558 | 559 | sendPitchBend (channel, getPitchwheelValue (touchIndex, x)); 560 | 561 | int colour = Pad_getColour (padIndex); 562 | addPressurePoint (getTrailColour (colour), x, y, z * 10.0); 563 | } 564 | 565 | void touchEnd (int touchIndex, float x, float y, float z, float vz) 566 | { 567 | int padIndex = Touch_getPad (touchIndex); 568 | int channel = Touch_getChannel (touchIndex); 569 | 570 | if (padIndex == 0xff) 571 | return; // touch was not started. 572 | 573 | int note = Pad_getNote (padIndex); 574 | int velocity = clamp (0, 127, int (vz * 127.0)); 575 | 576 | sendNoteOff (channel, note, velocity); 577 | 578 | Pad_setActive (padIndex, false); 579 | 580 | Touch_setPad (touchIndex, 0xff); 581 | Touch_setChannel (touchIndex, 0xff); 582 | 583 | Channel_setTrackedTouch (channel, 0xff); 584 | 585 | deassignChannel (note, channel); 586 | } 587 | 588 | 589 | /* 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | */ --------------------------------------------------------------------------------