Interactive Control and Scripting Language: ueForth

Interactive Control and Scripting Language for libDaisy: ueForth

  • Perhaps this is interesting or inspiring for somebody?

Wouldn’t it be nice to be able to peek into Daisy while it is running or set some more parameters, than you have potentiometers?
The idea is to integrate a scripting language and remote terminal access into the running Daisy Seed with libDaisy.

Why Forth?
Perhaps you might ask, why anyone might bother about this weird language in 2024?
The reason is, that Forth is the simplest in a row of interactive languages Forth-Lua-Micropython. This simplicity gives you speed and makes the memory footprint small. Forth had it’s peak of popularity for PCs in about 1985, when PCs had perhaps 256kB or less of RAM. This is, why it’s very well suited for microcontrollers like Daisy.

For ESP32 a speed comparison of these languages in a simple Fibonacci test is:
Micropython:Lua:Esp32Forth:Compiled_C = 1 : 3 : 48 : 145

The price for the speed and compactness is some inconveniance for the programmer. So to set a variable, instead of “varname= 5;” you have to type "5 varname ! ".
On the other side, Forth is very powerful. Anything you can write in any other programming language, you can also do in Forth. Additionally you can design new language elements. The ueForth choosen here gives you an operating system with multitasking, a compiler and console access. For example Simple Forth (murphywong.net) can give you some overview to the Forth language.

Selection of a Forth System
There are several Forth Systems for microcontrollers available, which can be combined with CPP programs in controllers. I had a look into some of these:

YAFFA-ARM by Stuart Wood is a basic system, which I have used for several years. It is more on the secure side than on the speed side. sdwood68 (Stuart Wood) · GitHub

ceForth by C.H. Ting is a simple basic system, which has the benefit, that it’s internals are described very well: ceForth/ceForth_33.pdf at master · pahihu/ceForth · GitHub

Atlast Forth by John Walker is meant as a scripting language and was developed at Autodesk. It is more complete as the previous ones and has a very fine manual. Atlast (fourmilab.ch)

µeForth or ESP32forth by Bradley D. Nelson is from 2021 and both the fastest and the completest of the row here. ESP32forth It brings multitasking, floating point math and local variables.
µeForth is derived somewhat from Tings eForth, so eForth Overview (exemark.com) is good reading here!
ueForth is made to be fast! So it simply does, what you ask it to be done. No checks.

About Readability of Forth
Forth has gained a bad reputation of bad readability in it’s early days. In my opinion there have been mainly two reasons for this:

  1. In 1980 Forthers had to squeeze their code into screens of 15 lines by 64 columns. No room for comments. Short names. This is no more necessary today. (Well, it was then, when in Commodore Basic it was a good idea to omit blanks between commands to gain power….)
  2. The handling of several local variables on the stack (ROT, DUP, TUCK,-ROT), where they are hidden without names, can make code quite obscure. So named local variables have been incorporated into the Forth standard in 1994. Unfortunately a bit late. And unfortunately there are many Forthers, who are proud, that they don’t need Locals for themselves, still producing code, which is harder to read for others….

For Daisy
So in my selection I put some emphasis on locals, speed and on multitasking. The idea is to be open to try to do at least some control in Forth. For example the VCO of a tremolo can be done as a Forth task. But perhaps even some sound processing is possible within Forth. The example included shows this possibility.

If you have a look at the code, you will see, that I pruned away lots of features of ESP32forth. So as I don’t have an SD card connected to the system, I have instead implemented the old-style Block file system on QSPI flash, but with 4096 bytes per block, because in QSPI flash that is the minimal size, which can be erased at a time. (A Block file system is very very much simpler than a system with FAT but still gives you most possibilities.)

Words for Daisy
Marker \ will type “Marker”
MS-TICKS ( – milliseconds )
US-TICKS ( – µseconds )
SetLed ( 0/1 – )
getBlock ( bufferAddr blocknumber – ) \ read from flash
putBlock ( bufferAddr blocknumber – ) \ write to flash
REBOOT
daisyControls ( – addr ) \ get the array address, probably floats
daisyAudio ( – addr ) \ get the address of an Audio Buffer, probably floats.
audioXt ( – addrXT ) usage: ’ myword audioXT !
Set a word to be executed by audioCallback, 0 for nothing.
callDaisy ( – ) execute the routine calledByForth();

1 LIST will list Block Number 1
10 LOAD will evaluate Block number 10

To load new text into block number 2:
2 LIST WIPE set block number 2 and wipe it
GETTEXT samples all Terminal Input until ESQ or € into the blockbuffer, up to 4096 chars.
UPDATE FLUSH will write the blockbuffer back to the block.

Example oscUefC.cpp and audioTest.fth
This example provides 3 oscillators:
1. An Audio Oscillator by libDaisy
2. A slow oscillator by Forth to modulate the first.
3. A second Audio oscillator by Forth

The makefile is “APP_TYPE = BOOT_SRAM” (so the bootloader is necessary) and needs about 120kB of program memory.
Attach a Terminal to the Daisy builtin USB Port connection. I use “Teraterm” on Windows. audioTest.fth will have to be send to the Forth system to activate 2nd and 3rd oscillators.
The example is a modified version of the osc example.
A global buffer daisyControls allows Forth to control frequency and amplitude via Forth. Also to read cpuload.

There are some words like MUTE1 to directly affect something via the Terminal.
’ fmodulate audioXT will attach the Forth routine FMODULATE to the audiocallback to do some frequency modulation.

While the example’s 3 oscillators are running, the terminal console is still accessible. Allowing to set parameters or even to compile new stuff…
osc2UefC.zip (1.8 MB)

Example is provided as is!

Perhaps I should add, that the Forth console also allows Forth to be used als a communication protocol between a computer and Daisy Seed over a serial line.

Comments, Ideas?

Have Fun!
Christof

3 Likes

Does this mean using a USB to serial cable or can you just connect the host USB port to the Daisy USB and it just works?

Your Forth program apparently requires Daisy bootloader.

Seems to work. I first used Forth in about 1982 on a VIC-20. I’m not convinced of its usefulness for Daisy, but it’s cool just seeing it run.

Forth is an awesome and fast, but the reverse Polish notation is just killing it for me.

Yes, I meant the USB connection. Teraterm will switch to “disconnected” during a new flash and then automaticly back to connected, when Daisy is running.

1 Like

How convenient, thank you.

Ah, yes, I should have mentioned, that the bootloader is needed.

About usefulness, I will have to see myself. I always thought, that the strength of an interactive language is during software development. You can try out things very quickly. It is an experimenters language. Forth had it’s debut controlling and evaluating experiments on radio telescopes. Forthers have always said, that development time is several times reduced in comparison to normal compiler language. I think, that this is true for me too…

Also a scripting language should be a good means, if a sound shall change over time or depending from ???.
I want to integrate rot-encoder and the oled display into Forth in the near future.

Some vague idea is, that it should be possible and probably not too difficult to write a compiler for the Plug Data scripts language in Forth.

Which “scripts language” do you mean here? :thinking:

1 Like

Hi, I meant, what is saved as *.pd.
(((I have seen, that Plugdata supports Lua, but not for Heavy/Daisy and not to be used for Soundprocessing.)))

I don’t think this makes any sense. You want to implement a Puredata compiler in Forth? o.O

What’s wrong with the Heavy Compiler? :smiley:

[edit: maybe I’m reading your words in the wrong order. you want to have a Forth scripting object that is compatible both inside Puredata and inside Heavy?]

Hi,
There is one weakness in the Plugdata system with Heavy and Daisy. While in Plugdata and Pure Data on the Pc you can influence sound very dynamicly, the compile cycle with Heavy is rather slow, which makes changes a bit exausting for me. While Forth would be much faster there, the sound processing in Forth is about 4 times slower than direct cpp. Not too bad, I think.

Expr~ is missing in Heavy.

In Heavy there is also a lack of support for parameter sets, rot encoder, display. I now got the flash block file, encoder and display working. So these things are feasable.

At the moment I am working primarily towards controlling parameters of a setup, which is compiled from PD by Heavy.