Skip to content

robertmeta/swiftmac

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SwiftMac

SwiftMac logo

A fast, async Emacspeak speech server for macOS written in Swift.

Requirements: Apple Silicon Mac (M1, M2, M3, M4, or newer)

Quick Links

Installation

Homebrew (Recommended)

The easiest installation method for macOS users:

brew tap robertmeta/swiftmac
brew install swiftmac

Then configure Emacs:

(setenv "EMACSPEAK_DIR" "/path/to/.emacspeak")
(load-file "/opt/homebrew/share/emacs/site-lisp/swiftmac-voices.el")
(dtk-select-server "swiftmac")

For manual Emacspeak integration:

ln -sf /opt/homebrew/opt/swiftmac/libexec/swiftmac $EMACSPEAK_DIR/servers/
ln -sf /opt/homebrew/opt/swiftmac/libexec/log-swiftmac $EMACSPEAK_DIR/servers/
ln -sf /opt/homebrew/opt/swiftmac/libexec/cloud-swiftmac $EMACSPEAK_DIR/servers/
ln -sf /opt/homebrew/opt/swiftmac/libexec/ogg.framework $EMACSPEAK_DIR/servers/
ln -sf /opt/homebrew/opt/swiftmac/libexec/vorbis.framework $EMACSPEAK_DIR/servers/

Binary Release (swiftmac.tar.gz)

Download from GitHub releases.

Copy the extracted files to the $EMACSPEAK_DIR/servers and then add the swiftmac server to your emacs config, for more info see: Readme.emacspeak.org

From Source

See: Readme.emacspeak.org

Helper Scripts and Tools

SwiftMac includes several helper tools to make configuration easier.

Voice Configuration Tools

sample-voices.el - Interactive Voice Sampler

Interactive Emacs tool to sample and test all installed voices.

Load it in your Emacs config:

(load-file "/path/to/swiftmac/sample-voices.el")

Run M-x swiftmac-sample-voices to open an interactive buffer showing:

  • All voices grouped by quality (Premium/Enhanced/Compact)
  • Organized by locale (en_US, en_GB, etc.)

Keybindings:

  • RET or s - Sample the voice at point
  • x - Stop all speaking
  • g - Refresh the list
  • q - Quit

download-premium-voices.sh - Voice Installation Helper

Lists all available premium and enhanced voices with installation instructions.

./scripts/download-premium-voices.sh          # Show available voices
./scripts/download-premium-voices.sh verify   # Verify installed voices

To download voices:

  1. Open System Settings → Accessibility → Spoken Content
  2. Click the INFO BUTTON (ⓘ) next to ‘System Voice’
  3. Search for ‘premium’ or ‘enhanced’
  4. Download only the voices you’ll use (each is 50-300MB)

show-voices.swift - List All Voices

Quick script to list all available voices with quality levels:

swift scripts/show-voices.swift

Output includes language, identifier, name, and quality level (1=Compact, 2=Enhanced, 3=Premium).

Voice Configuration Examples

**Default Configuration (swiftmac-voices.el)**

The swiftmac-voices.el file is the standard voice configuration that ships with Emacspeak. It provides:

  • Default voice definitions
  • CSS voice mapping (for rich text rendering)
  • Integration with Emacspeak’s voice lock system

This file is automatically loaded when you select the swiftmac server.

**English (Premium + Enhanced)**

The repo includes examples/voices-config-english.el which uses:

  • Samantha (Enhanced) as main/default voice
  • Alex (Enhanced) for strings and quoted text
  • Premium voices for special emphasis
(load-file "/path/to/swiftmac/examples/voices-config-english.el")

**Polish**

The repo includes examples/voices-config-polish.el for Polish voices:

(load-file "/path/to/swiftmac/examples/voices-config-polish.el")

**Markdown Reading**

The examples/markdown-voices-config.el provides optimized voice settings for reading Markdown files.

**Custom Voice Configuration**

Example of defining your own voices:

(swiftmac-define-voice voice-bolden "[{voice en-US:Evan}] [[pitch 1]]")
(swiftmac-define-voice voice-animate "[{voice en-US:Ava (Premium)}] [[pitch 1]]")
(swiftmac-define-voice voice-lighten "[{voice en-AU:Matilda}] [[pitch 1.1]]")
(swiftmac-define-voice voice-smoothen "[{voice en-US:Zoe (Premium)}] [[pitch 0.8]]")

Audio Volume Control

Control volume levels for different audio types (values between 0.0 and 1.0):

(setenv "SWIFTMAC_TONE_VOLUME" "0.1")      ; Beeps and tones
(setenv "SWIFTMAC_SOUND_VOLUME" "0.1")     ; Sound effects
(setenv "SWIFTMAC_VOICE_VOLUME" "1.0")     ; Speech

Audio Device Tools

list-audio-devices.swift - Find Audio Device IDs

Lists all available audio output devices with their IDs and channel counts:

swift scripts/list-audio-devices.swift
# or
make list-devices

Example output:

[DEFAULT] DeviceID: 125 | "Audioengine D1" | Channels: 2
          DeviceID: 110 | "LG Ultra HD" | Channels: 2
          DeviceID: 89 | "MacBook Pro Speakers" | Channels: 2

Use these device IDs for multi-device routing configuration (see below).

Example Configuration Files

The examples/ directory contains several example configurations:

  • examples/init.el-example.el - Example Emacspeak initialization
  • examples/minimal-emacspeak-init.el - Minimal working Emacspeak config
  • examples/voices-config-english.el - English voice configuration (Samantha + Alex)
  • examples/voices-config-polish.el - Polish voice configuration
  • examples/markdown-voices-config.el - Voice configuration for reading Markdown files
  • examples/simple-device-test.el - Basic device routing test
  • examples/simple-device-switch.el - Example of switching audio devices
  • examples/device-test-with-stop.el - Device testing with stop commands

These are useful as starting points for your own configuration.

Testing and Development Files

If you’re developing or debugging SwiftMac:

**Shell Test Scripts:**

  • scripts/test-clean-emacspeak.sh - Test with clean Emacspeak environment
  • scripts/test-dual-mode.sh - Test dual-process mode
  • scripts/test-multi-device.sh - Test multi-device routing
  • scripts/test-multiple-instances.sh - Test multiple SwiftMac instances
  • scripts/test-proper-dual.sh - Test proper dual-mode setup

**Emacs Test Files:** The tests/ directory contains automated test files:

  • tests/test-audio-routing.el - Audio routing tests
  • tests/test-notifications.el - Notification routing tests
  • tests/test-runtime-device-switching.el - Runtime device switch tests
  • tests/test-simple-routing.el - Simple routing tests

Multi-Device and Channel Routing

SwiftMac supports routing different audio types to different physical devices AND channels. All four audio types can be independently configured:

  • Speech (main spoken output)
  • Notifications (auditory icons/beeps)
  • Tones (generated tones)
  • Sound effects (played audio files)

Finding Your Device IDs

Run this to list available audio output devices:

make list-devices

Example output:

[DEFAULT] DeviceID: 125 | "Audioengine D1" | Channels: 2
          DeviceID: 110 | "LG Ultra HD" | Channels: 2
          DeviceID: 89 | "MacBook Pro Speakers" | Channels: 2

Configuration Format

Set environment variables in your Emacs init file (BEFORE loading emacspeak):

(setenv "SWIFTMAC_<TYPE>_DEVICE_AND_CHANNEL" "<deviceID>:<channel>")

Where:

  • <TYPE>: SPEECH, NOTIFICATION, TONE, or SOUNDEFFECT
  • <deviceID>: Numeric ID from make list-devices (or 0 for system default)
  • <channel>: left, right, or both

Example Configurations

All Audio to One Device (Simple Setup)

; Everything to Audioengine D1, stereo
(setenv "SWIFTMAC_SPEECH_DEVICE_AND_CHANNEL" "125:both")
(setenv "SWIFTMAC_NOTIFICATION_DEVICE_AND_CHANNEL" "125:both")
(setenv "SWIFTMAC_TONE_DEVICE_AND_CHANNEL" "125:both")
(setenv "SWIFTMAC_SOUNDEFFECT_DEVICE_AND_CHANNEL" "125:both")

Separate Devices for Speech and Notifications

; Speech to headphones, notifications to monitor speakers
(setenv "SWIFTMAC_SPEECH_DEVICE_AND_CHANNEL" "125:both")  ; Audioengine D1
(setenv "SWIFTMAC_NOTIFICATION_DEVICE_AND_CHANNEL" "110:both")  ; LG Ultra HD
(setenv "SWIFTMAC_TONE_DEVICE_AND_CHANNEL" "125:both")
(setenv "SWIFTMAC_SOUNDEFFECT_DEVICE_AND_CHANNEL" "110:both")

; IMPORTANT: Enable notification server for multi-device routing
(setopt tts-notification-device "left")

Same Device, Different Channels

; Speech in both ears, notifications in left ear only
(setenv "SWIFTMAC_SPEECH_DEVICE_AND_CHANNEL" "125:both")
(setenv "SWIFTMAC_NOTIFICATION_DEVICE_AND_CHANNEL" "125:left")
(setenv "SWIFTMAC_TONE_DEVICE_AND_CHANNEL" "125:both")
(setenv "SWIFTMAC_SOUNDEFFECT_DEVICE_AND_CHANNEL" "125:left")

(setopt tts-notification-device "left")  ; Enable notification server

All Four Audio Types to Different Outputs

; Maximum separation for complex audio setups
(setenv "SWIFTMAC_SPEECH_DEVICE_AND_CHANNEL" "125:both")  ; Speech -> Audioengine D1
(setenv "SWIFTMAC_NOTIFICATION_DEVICE_AND_CHANNEL" "110:left")  ; Notifications -> LG left
(setenv "SWIFTMAC_TONE_DEVICE_AND_CHANNEL" "89:both")  ; Tones -> MacBook speakers
(setenv "SWIFTMAC_SOUNDEFFECT_DEVICE_AND_CHANNEL" "110:right")  ; Sounds -> LG right

(setopt tts-notification-device "left")  ; Enable notification server

Runtime Channel Commands

Change ONLY the channel (not device) on the fly:

  • tts_set_speech_channel {left|right|both}
  • tts_set_notification_channel {left|right|both}

Note: Runtime device switching (changing the physical device) is not yet supported. Restart Emacs to change devices.

How Multi-Device Routing Works

Emacspeak spawns two separate swiftmac processes:

  1. Speech process (main): Handles regular speech output
  2. Notification process: Handles auditory icons and notifications

The tts-notification-device setting triggers Emacspeak to spawn the second process with SWIFTMAC_AUDIO_TARGET set, which swiftmac detects as notification mode.

Each process reads its own device configuration from the environment variables, allowing speech and notifications to output to different physical devices.

For more details, see MULTI-DEVICE-SETUP.md.

Introduction

This is an emacspeak server written in swift intended to be as async as reasonable, fast and responsive.

Unless you are a developer or interested in becoming one, you probably want to use the version bundled with emacspeak, I keep that copy up to date with this one fairly consistently.

Development

Want to contribute or build from source? See Contributing.org for:

  • Development requirements (Xcode, Homebrew tools)
  • Build instructions and workflow
  • Make commands reference
  • Testing and debugging
  • Release process
  • Code style guidelines

Quick start for developers:

make debug        # Build debug version
make test-emacs   # Test with Emacspeak
make tidy         # Format code (required before commits)

Having Trouble?

It emits warnings and notes

I am aware of the current warnings, it is a goal to get it to build completely clean but tthat is not a priority right now, getting to v2 is the priority.

Double-Speaking

If you are hearing stuff twice, ensure that mac-ignore-accessibility is set and your emacs version supports it. If that doesn’t work, you can use the VoiceOver Utility that comes with MacOS to create an activity for Emacs.app to turn off voiceover while in the Emacs window. This only works if you are using a windowed version of Emacs (not terminal version).

Design

The server intends to provide primitives to support all the features used by emacspeak and swiftmac-voices.el.

Supported Commands

These are the commands sent via stdin and on thier own line.

  • a: queue audio icon
  • c: queue code
  • d: dispatch queue
  • l: instant letter
  • p: instant audio icon
  • q: queue speech
  • s: stop all (confirm with list)_
  • sh: queue silence
  • t: queue tone
  • tts_pause: instant pause speech engine (should stop?)
  • tts_reset: queue reset (to defaults?)
  • tts_resume: instant resume speech engine
  • tts_say: instant say no additional tweaking
  • tts_set_character_scale: queue char scale change
  • tts_set_punctuations: queue punct change
  • tts_set_speech_rate: queue rate change
  • tts_split_caps: queue split caps change
  • tts_sync_state: [decomp] queue multiple settings change
  • version: [decomp] say tts version

Not Implemented yet:

  • set_next_lang:
  • set_previous_lang:
  • set_lang
  • set_preferred_lang

Engine Specific:

  • tts_exit: instant exit
  • tts_set_pitch_multiplier: .5 to 2 pitch multiplier
  • tts_set_sound_volume: 0 to 1 (1 being 100% sound volume)
  • tts_set_tone_volume: 0 to 1 (1 being 100% tone volume)
  • tts_set_voice: queue voice change
  • tts_set_voice_volume: 0 to 1 (1 being 100% voice volume)

Broken:

  • tts_allcaps_beep: queue caps beep change, setting only works on typing input

Supported Embeddings

These are converted by the preprocessor into tts_ commands.

  • [*] - queue silence in place of this

Goals

  1. The server should be as dumb as possible.
  2. Major decisions should be configurable in lisp.
  3. System should be “usable by default” meaing: once it builds, it works.
  4. Server will depend on only clearly defined and checked at compile time things. No secret deps on command line tools.

About

A port of the emacspeak python server to swift

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •