Skip to content
Yummi

[ INTERNALS ]

How it is built

Yummi fits in five dependencies and none of them is heavy. The most unusual thing it does — capturing the audio of a single process — is done in plain ctypes, because the API has no Python library.

Layers

Only ui/ knows Tkinter and only audio/ knows PortAudio. That is why everything else runs in the tests with no sound card and no screen.

  • yummi/audio/devices.pyfinding and choosing devices
  • yummi/audio/loader.pydecoding, resampling, normalising
  • yummi/audio/player.pyplayback across outputs and the live bridge
  • yummi/audio/loopback.pyper-process capture (WASAPI process loopback)
  • yummi/tts/synthesis engines, automatic fallback and cache
  • yummi/ui/the Tkinter window and the black-and-white theme
  • yummi/library.pythe clip library
  • yummi/files.pyscanning the audio folder
  • yummi/config.pypreferences in JSON
  • yummi/hotkeys.pyglobal shortcuts (written, switched off)

The five dependencies

numpy

the maths over the samples

sounddevice

the bridge to sound cards, through PortAudio

soundfile

decodes MP3 and friends straight from memory, via libsndfile

edge-tts

Microsoft's neural voices

gTTS

the backup, when the first one doesn't answer

ffmpeg, pydub and scipy were left behind in version 3. pydub had stopped working on Python 3.13, when the audioop module left the standard library.

Per-window capture

ActivateAudioInterfaceAsync
AUDIOCLIENT_ACTIVATION_TYPE_PROCESS_LOOPBACK
PROCESS_LOOPBACK_MODE_INCLUDE_TARGET_PROCESS_TREE

Windows exposes a process's audio through ActivateAudioInterfaceAsync, with process loopback parameters. It is a C and COM API with no Python binding: the interfaces are called through ctypes, by each method's position in the function table, and the object that receives the asynchronous result is built by hand in Python. Outside Windows the module imports fine and only the capture declines, with a message.

The choice is saved by executable name, not by process id: closing and reopening Brave does not lose the setting.

Where the files live

Nothing is written inside the repository. Preferences, clips and cache live in the user folder:

Deleting that folder returns the program to a freshly installed state, without uninstalling anything.

%APPDATA%\Yummi\
├── config.json      saídas, voz, pasta de áudios, origem da ponte
├── clipes/          a biblioteca + biblioteca.json
└── cache/           as falas já sintetizadas

Tests

157 tests run on four Python versions on every push, with ruff in the same step. The ones that need a sound card are skipped on the server, and the interface is tested against a fake Tk root.

157

pytest

4

3.10 → 3.13

MIT

licence

See the repository