The BLOCKS SDK
The LittleFoot Language

A description of the LittleFoot language

A description of the LittleFoot language is contained in the SDK source code at juce_blocks_basics/littlefoot/LittleFoot Language README.txt:

This is a brief description of the LittleFoot language syntax

Littlefoot basically looks like C, but has no pointers, and the only types are:

- int   (32-bit signed integer)
- float (32-bit float)
- bool

The top-level syntax of a program is a list of global variables and global functions. Order
of declaration isn't important, you can use functions and variables that are declared later
in the file without needing to pre-declare anything.

Comments are the same format as C/C++/java/etc

So for example:


    // global variables. These are initialised to 0 or false when the program is loaded, and
    // you can't currently provide any other initial values
    int foo, bar;

    int getTheNextNumber()
    {
        return addTwoNumbers (++foo, 2.0) * 3;
    }

    float addTwoNumbers (int x, float y)
    {
        return float (x) + y;
    }

The usual control-flow operators are provided, all with C++ style syntax:

    if/else
    for
    while
    do...while
    continue
    break
    return

(There isn't currently a switch statement though)

Arithmetic ops are the usual suspects, (with the standard operator precedence):

    +, -, *, /, %
    ||, &&, |, &, |, ~
    ++, --, +=, -=, *=, /=, %=, ^=, |=, &=, ^=
    ==, !=, <, >, <=, >=, !
    <<, >>, <<=, >>=
    Ternary operator (x ? y : z)

Local variables are declared in C++-style syntax:

    void foo()
    {
        int x = 123;
        float y = 12.0, z = 1.0e5;
        bool b = y > 20.0;
    }

Casts of primitive types are done with function-style syntax, e.g.

    int x = int (123.0);
    float f = float (getIntegerValue());

The program communicates with the host computer by using a shared area of memory
called the heap which the host can change. There are some built-in functions
available for the program to use to read from the heap:

    int getHeapByte (int byteIndex);                    // reads a single byte from the heap
    int getHeapInt (int byteIndex);                     // reads 4 bytes from the heap as an integer
    int getHeapBits (int startBitIndex, int numBits);   // reads a sequence of bits from the heap and returns it as an integer
    void setHeapByte (int byteIndex, int newValue);     // writes a single byte to the heap
    void setHeapInt (int byteIndex, int newValue);      // writes 4 bytes to the heap

Depending on the context, there will also be some built-in functions that the
program can use to do what it needs to do. Currently in the standard Pad BLOCK program,
you have the following functions available:

    int makeARGB (int alpha, int red, int green, int blue);         // combines a set of 8-bit ARGB values into a 32-bit colour
    int blendARGB (int baseColour, int overlaidColour);             // blends the overlaid ARGB colour onto the base one and returns the new colour
    void fillPixel (int rgb, int x, int y);                         // sets a LED colour on the display
    void fillRect (int rgb, int x, int y, int width, int height);   // fills a rectangle on the display

A BLOCKs program needs to provide a repaint() function which the block will call
at approximately 25Hz to draw the display. For example, here's a simple program that
draws a moving rectangle:

    int rectangleX;

    void repaint()
    {
        fillRect (0xff000044, 0, 0, 15, 15); // fill the display with dark blue
        fillRect (0xffffffff, rectangleX, 5, 4, 4); // draw a white rectangle

        rectangleX = (rectangleX + 1) % 15; // animate our position and make it wrap
    }

The host can also send simple event messages to the program, and to receive these you must
provide a function called "handleMessage", e.g.

    void handleMessage (int param1, int param2)
    {
        // do something with the two integer parameters that the app has sent...
    }

A LittleFoot example

The BitmapLEDProgram class is a simple example of a LittleFoot program.

juce_blocks_basics/visualisers/juce_BitmapLEDProgram.h

/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
{
void setLED (uint32 x, uint32 y, LEDColour);
private:
juce::String getLittleFootProgram() override;
};

juce_blocks_basics/visualisers/juce_BitmapLEDProgram.cpp

/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/*
The heap format for this program is just an array of 15x15 5:6:5 colours,
and the program just copies them onto the screen each frame.
*/
{
if (auto ledGrid = block.getLEDGrid())
{
auto w = (uint32) ledGrid->getNumColumns();
auto h = (uint32) ledGrid->getNumRows();
if (x < w && y < h)
{
auto bit = (x + y * w) * 16;
block.setDataBits (bit, 5, colour.getRed() >> 3);
block.setDataBits (bit + 5, 6, colour.getGreen() >> 2);
block.setDataBits (bit + 11, 5, colour.getBlue() >> 3);
}
}
else
{
}
}
juce::String BitmapLEDProgram::getLittleFootProgram()
{
String program (R"littlefoot(
#heapsize: 15 * 15 * 2
void repaint()
{
for (int y = 0; y < NUM_ROWS; ++y)
{
for (int x = 0; x < NUM_COLUMNS; ++x)
{
int bit = (x + y * NUM_COLUMNS) * 16;
fillPixel (makeARGB (255,
getHeapBits (bit, 5) << 3,
getHeapBits (bit + 5, 6) << 2,
getHeapBits (bit + 11, 5) << 3), x, y);
}
}
}
)littlefoot");
if (auto ledGrid = block.getLEDGrid())
return program.replace ("NUM_COLUMNS", juce::String (ledGrid->getNumColumns()))
.replace ("NUM_ROWS", juce::String (ledGrid->getNumRows()));
return {};
}

The repaint() method of the LittleFoot program is called at approximately 25 Hz, and each time it simply inspects the heap (the shared area of memory used to communicate between your application code and your LittleFoot program) and sets the LEDs based on the heap's content. To update the heap, and hence the LEDS, your application code calls BitmapLEDProgram::setLED.

A more advanced example can be found in the source code of the DrumPadGridProgram class or in the BlocksSynth example.