Schwung-Eloquence

This is the landing page for Schwung-Eloquence, a hack for replacing Flite with Eloquence (OpenEVV) in Schwung’s screen reader on the Ableton Move. Read on for installation instructions.

Why Does This Exist?

The Schwung screen reader offers two engines, eSpeak and Flite. Many people dislike both of these synthesizers or find them difficult to understand. Right now, adding alternative speech synthesis directly to Schwung would require maintaining a separate branch with separate updates, which is not ideal. Adding external TTS is on the roadmap, but is not possible at this time.

This project is a stopgap solution until Schwung supports external TTS. The install script replaces the Flite engine with a small proxy library that loads in its place and speaks through OpenEVV, a C port of IBM’s ETI-Eloquence. In practice, this means choosing Flite gets you Eloquence instead. ESpeak and Schwung are left unmodified.

Install

First, make sure you're running Schwung 1.5 or later. 1.5 was released on September 27th, only a few days before Schwung-Eloquence, and earlier Schwung releases had a bug that caused Move to crash when trying to change Flite's speed or pitch.

You need SSH access to your Move if you don’t have it already. Schwung’s installer should have set this up. From a terminal, ssh ableton@move.local, then run:

wget -qO- https://simonj.me/schwung-eloquence/install.sh | sh

Move restarts by itself when the install is finished. To restart it later yourself instead, end the command with | sh -s -- --no-restart.

After the restart, go to Global Settings (shift+hold step 2), choose Screen Reader, and set Engine to Flite. Your Flite should sound suspiciously Eloquence-like.

Security Notice

The Move’s wget does not check HTTPS certificates, so the one-liner trusts your network. If you’d rather perform a local install or your Move is not online, use a computer to download the installation script and installation files from the useful links section of this page, copy both to the Move, and run ./install.sh schwung-eloquence.tar.gz.

Files Added or Changed on your Move

Path Description
/data/UserData/eloquence/ the engine, your settings, the text fixes and any dictionaries in dict/, logs, licences, and a copy of the installer
/data/UserData/boot-targets/eloquence/ the “Schwung + Eloquence” boot target
/data/UserData/schwung/lib/libflite*.so.1 replaced; Schwung’s own are kept in eloquence/orig/
/data/UserData/boot-targets/default set to eloquence

Updating Schwung

Updating Schwung core would normally bring back Flite. To solve this, the installer makes “Schwung + Eloquence” the default boot target, which automatically puts Eloquence back after Schwung updates. You can change this back from the web manager or by uninstalling Schwung-Eloquence.

Uninstalling

SSH into your Move and run:

sh /data/UserData/eloquence/install.sh --uninstall

This puts Schwung’s own Flite back, removes the boot target, deletes everything in /data/UserData/eloquence, and restarts Move. That includes your settings and any dictionaries you added, so keep copies of those elsewhere.

Settings

/data/UserData/eloquence/eloquence.json is read when the screen reader first speaks after Move starts, so restart Move after changing it: over SSH, /data/UserData/schwung/restart-move.sh. The installer puts eloquence.example.json next to it, with every setting at its default; copy it to eloquence.json and change what you like. The example is replaced with the latest each time you install, but your eloquence.json is not. Every key is optional:

{
  "voice": 1,
  "wpm": 0,
  "pitch": 0,
  "inflection": -1,
  "phrase_prediction": 0,
  "log_text": 0
}

Text fixes

Eloquence mispronounces some things, and screen reader users have long fixed them with regular expressions. Rules go in /data/UserData/eloquence/dict/regexp.dic. The installer puts one there with the fixes from the Eloquence add-ons for NVDA (dates like “03 Marble”, “Mc” names, numbers like “1,000,500”), and replaces it with the latest each time you install, so keep your own changes elsewhere too. Changes are picked up the next time something is spoken, with no restart, and with no file there are simply no fixes.

The file has the shape of OpenEVV’s own dictionaries: one line per rule, consisting of a regular expression, a tab, and the replacement. Patterns use the same syntax as the Eloquence add-ons for NVDA, and (?i) at the start of one makes it ignore case:

\b(Mc)\s+([A-Z][a-z]|[A-Z][A-Z]+)	\1\2
(?i)\bmidi\b	MIDI

In a replacement, \1 or \g<1> is what the first group matched. A replacement can also contain Eloquence’s own annotations, such as `p300 for a 300 ms pause; backticks in what Schwung says are read as spaces, so only your rules can add them. Lines starting with # are comments. A rule that cannot be read is reported in eloquence.log with its line number.

Pronunciation dictionaries

The community’s IBMTTS dictionaries correct how Eloquence says thousands of words. They are not included, but any or all of the three US English ones can be added: copy ENUmain.dic, ENURoot.dic and ENUabbr.dic into /data/UserData/eloquence/dict/ with those exact names, and restart Move. They are read when the screen reader first speaks, and eloquence.log says how long each took.

ENURoot.dic has 69,000 entries, and during testing it took minutes to load, during which the screen reader is silent, and made every phrase several times slower afterwards. This appears to be a bug in OpenEVV. ENUmain.dic (whole words) and ENUabbr.dic (abbreviations) are small and cost nothing noticeable.

Contact

You can report bugs and make suggestions by:

  1. Sending me an e-mail
  2. Opening a GitHub issue

LLM Transparency

Some of this code was written or refined by Claude Opus 5.5, especially the proxy library. All code is thoroughly human-tested.