- C 48.3%
- C++ 46.1%
- Python 1.8%
- Makefile 1.4%
- HTML 0.9%
- Other 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| apis | ||
| cae | ||
| conf | ||
| debian | ||
| docs | ||
| helpers | ||
| icons | ||
| importers | ||
| ios | ||
| lib | ||
| LICENSES | ||
| rdadmin | ||
| rdairplay | ||
| rdalsa | ||
| rdcartslots | ||
| rdcastmanager | ||
| rdcatch | ||
| rdcatchd | ||
| rdhpi | ||
| rdlibrary | ||
| rdlogedit | ||
| rdlogin | ||
| rdlogmanager | ||
| rdmonitor | ||
| rdpadd | ||
| rdpadengined | ||
| rdpanel | ||
| rdrepld | ||
| rdrssd | ||
| rdselect | ||
| rdservice | ||
| rdvairplayd | ||
| ripcd | ||
| scripts | ||
| systemd | ||
| tests | ||
| tools | ||
| utils | ||
| versions | ||
| web | ||
| xdg | ||
| .gitignore | ||
| acinclude.m4 | ||
| AUTHORS | ||
| autogen.sh | ||
| BACKLOG.md | ||
| build_debs.sh.in | ||
| ChangeLog | ||
| CHANGELOG.md | ||
| ChangeLog.upstream-v4 | ||
| CODINGSTYLE | ||
| configure.ac | ||
| configure_build.sh | ||
| get_distro.pl | ||
| get_target.sh | ||
| INSTALL-WINDOWS | ||
| INSTALL.md | ||
| KNOWN_ISSUES.md | ||
| lindon-install.sh | ||
| Makefile.am | ||
| NEWS | ||
| README | ||
| README.md | ||
| rivendell.ism | ||
| rivendell.pro | ||
| rivendell.spec.in | ||
| ROADMAP.md | ||
| UPGRADING | ||
lindon
A private, trimmed fork of Rivolution (itself a Qt6 fork of Rivendell), maintained for use at some local radio stations, both fm and dab+ transmitted.
Not a public project — kept private intentionally. This README exists for our own future reference as much as anything else.
What this is
Rivolution's Qt6 migration is the part worth having: vanilla Rivendell v4 still depends on Qt5 components (notably QtWebKit) that have aged out of current distributions, making it awkward to package on a current Ubuntu. Rivolution solves that.
What we didn't want was everything Rivolution built on top of that
migration — a web dashboard, a self-healing PipeWire patchbay,
Icecast/Stereo Tool/Tailscale baked into the packaged stack, and (the
one that actually broke things) a segue back-timing feature that
doesn't compose correctly with voice tracking. lindon is Rivolution
with those parts removed or reverted, plus a couple of packaging bugs
fixed that we ran into ourselves.
How this differs from upstream Rivolution
-
rivapi(the Go dashboard) removed entirely — never built by the autotools chain to begin with; its systemd/sudoers hooks are stripped frompostinst/rules.srctoo. No web UI, no dashboard auth, no associatedsudogrant for the service account. -
PipeWire is user-scope, not system-scope — this deployment always runs with desktop autologin (
rdairplayin the desktop autostart), so a separate system-scope PipeWire instance (and its linger/tmpfiles workarounds) is unnecessary complexity.rivendell.servicebinds touser@<uid>.serviceinstead. -
icecast2andstereo-tool.servicedropped from the packaged stack — neither is installed or managed bylindon. Stereo Tool runs locally and gets patched into PipeWire by hand. -
tailscaledremoved fromrivolution-stack.target. -
Segue back-timing (upstream spec
docs/specs/0002-segue- backtiming.md) fully reverted, including its follow-on "second bug" fix. Upstream's own spec explicitly reasoned that voice tracking wouldn't interact with this feature — that reasoning turned out to be wrong on two separate counts:- Voice-tracked transitions save
SEGUE_GAIN=0as their normal, incidental value (full volume, no duck) — the exact same field this feature gates on — so every voice-tracked segue triggered it regardless of operator intent, playing out to the element's natural end with no audible transition instead of blending. - The follow-on fix for a related regression (
Finished()/FinishEvent()skipping the next element's start whenever anything else was still running, assuming it would be re-triggered later) silently stalled the log whenever the next line was a marker or an empty voice-track slot with no audio of its own to generate that re-trigger — the log would just sit there indefinitely, indistinguishable from a Stop.
Both reverted; confirmed via diff that the affected functions are now byte-identical to vanilla Rivendell 4.5.0. Reported upstream weeks ago, no response as of this writing.
- Voice-tracked transitions save
-
libmad0/libtwolame0added toDepends:— both are loaded viadlopen()at runtime rather than linked, so their absence doesn't show up vialddand wasn't caught by upstream's own packaging; without them, MP3/MPEG import silently fails. -
Renamed from
rivolutiontolindonat the package level (Conflicts:/Replaces:against every oldrivolution-*package for a cleanaptupgrade). Internal paths went the other way —/usr/share/rivolution/, our own systemd units (rivolution-stack.target,rivolution.conf) — reverted back to plainrivendellnaming, since there's no benefit to a third naming scheme once the package itself already sayslindon, and it keeps the diff surface smaller if anything here is ever worth pulling back upstream. Two things this surfaced, worth knowing if you're doing the same kind of rename elsewhere:postinst's fresh-install-vs-upgrade branch keyed only on$OLD_VERSION(set by dpkg for a same-name package upgrade). dpkg leaves that empty for aReplaces:-triggered rename, even with a fully working install already in place — the very firstrivolution→lindoninstall would otherwise have hit the fresh-install branch and dropped the production database (drop database if exists ...). Now also checks for a pre-existing/etc/rivendell.d/rd-default.confbefore deciding.- A
PYPAD_INSTANCES.SCRIPT_PATHvalue written before the rename doesn't update itself — it's just a string frozen in the database at creation time, unaffected by anything the newly installed package changes. Existing PyPAD instances need their script path corrected by hand after an upgrade; new ones created afterward pick up the right path automatically (RDAdmin's file picker defaults intoRD_PYPAD_SCRIPT_DIR, compiled from the current package). rivolution.confunderrivendell.service.d/isn't a dpkg-tracked conffile (justcp'd in bypostinst, same asrivendell.confthat replaces it) — dpkg has no reason to remove it on upgrade, so it's left sitting alongside the newrivendell.confunless removed by hand.
-
New: "Make Next & Wait max" grace-time mode, a fourth option alongside vanilla's Start Immediately / Make Next / Wait up to (
rdairplay,rdlogedit, andrdlogmanager's clock/event editor). Reserves the "next" slot immediately like Make Next (so the log doesn't fall through to whatever else happens to be next in a busy/segue-chained clock — e.g. a news slot skipping straight to the wrong interstitial instead of joining the current segue chain), but still enforces a bounded timeout like Wait up to, so an overrunning predecessor can't push a hard-timed element (news, legally-timed IDs) past its deadline. Encoded asGRACE_TIME <= -2(timeout_ms = -GRACE_TIME - 2); no database schema change. Three bugs found so far, all worth remembering:RDLogPlay::transTimerData():makeNext()callsSetTransTimer()internally, which can silently reassign the memberplay_trans_lineto whatever the next upcoming hard-time line is. Reading that member again afterward (instead of the function's own pre-captured localtrans_line, which exists for exactly this reason and is already used elsewhere in the function) armed the grace timer for the wrong log line — the symptom was a hard-timed element several lines away getting force-started instead of the one actually configured, skipping everything in between.- Two separate, unrelated display bugs made a correctly-saved
value look wrong without actually being wrong:
EventWidget::load()(rdlogmanager) lost thegrace= event_event->graceTime()assignment when itsswitchwas restructured to add the new branch, so re-opening any Hard-Time event always showed "Start Immediately" regardless of what was saved.RDEventLine::propertiesText()didn't know about the newGRACE_TIME <= -2range and ran it through the oldWait up toformatting path, whereQTime::addMSecs()wraps a sufficiently negative value around a 24-hour clock — a 2:00 timeout rendered as a nonsensical "57:59" in the RDLogManager event list. - A race between
RDLogPlay::Stopped()andgraceTimerData(): when the grace line was started by a normal segue from its predecessor, the predecessor'sStopped()could arrive before the grace line's ownPlaying()had stopped the grace timer (short segue, cued load latency). The timer then woke and calledStartEvent()for the already-running line a second time, stopping both decks and stalling the log until the next hard time (observed: 4:18 dead air in production).Stopped()now cancels the timer if the grace line is no longer Scheduled/Paused, andgraceTimerData()ignores such a line.
-
New: per-station LUFS-based loudness normalization, alongside the existing peak-based normalization (RDAdmin Host dialog switch). Ports the approach already used in the external M3U-import tooling (StereoTool) into core Rivendell itself, so stations not using that M3U-import workflow also benefit. Touches
rdaudioconvertand every import path: dropbox/feed/replicator, RDCatch (download/recording/ upload), CD ripper, and therdimportCLI. NewSTATIONS.LOUDNESS_NORMALIZATIONcolumn (schema 379 -> 380).- Fixed
RDCartDialog::loadFileData()(the "Load from File" quick-import in RDCartSlots) using a hardcoded dBFS-appropriate value (-11) that became far too loud once reinterpreted as a LUFS target on stations with LUFS normalization enabled; now picks -23 (LUFS) or -11 (dBFS) based on the station's setting.
- Fixed
-
New: number-key playback toggle for RDCartSlots (RDAdmin Edit CartSlots dialog switch, per station). Digit keys 1-8 toggle play/stop on the corresponding slot, independent of which widget has focus, as long as the RDCartSlots window itself is the active window. Slots in Breakaway mode ignore the key. A green border is drawn around the window while it's focused and the feature is enabled, so it's visible when the shortcut is live. New
STATIONS.CARTSLOT_KEY_PLAYBACKcolumn (schema 380 -> 381). -
lindon-install.sh— a setup wrapper (not part of upstream) that creates therdoperator account, configures desktop autologin (preferring X11 over Wayland), installs the built.debs, walks through NFS export/mount plus database pointer setup for standalone/server/client roles, and lets you pick the audio sample rate (44.1kHz fixed, 48kHz fixed, or auto-detect) viaConfigureSampleRate.
Installation
Grab the .deb files and lindon-install.sh from this repo's
Releases page, put them in the same directory, then:
sudo ./lindon-install.sh
The operator account is always named rd — see the comments in
lindon-install.sh for why, and what to do if you need something
else.
Upgrading an existing rivolution install
Don't run lindon-install.sh for this — it's a first-run wrapper
(account creation, autologin setup, NFS export/mount, database
pointer setup) that a working install has already been through.
Install the packages directly instead:
sudo apt install lindon_*.deb lindon-*.deb
Conflicts:/Replaces: handles removing the old rivolution-*
packages as part of the same transaction — review apt's summary
before confirming, it should show the matching set of rivolution-*
packages being removed. Back up the database first regardless
(mysqldump --all-databases > backup.sql) — see the PYPAD_INSTANCES
and rivolution.conf notes above for what still needs manual cleanup
after an upgrade.
Remotes / staying current
This repo tracks anjeleno/rivolution as its upstream remote:
git remote add upstream https://github.com/anjeleno/rivolution.git
git fetch upstream
git log --oneline main..upstream/main
Pulling upstream changes in isn't automatic or guaranteed to be conflict-free — Rivolution's own Qt6 migration touched a large fraction of the codebase, so a given upstream fix may or may not apply cleanly depending on whether it lands in code that migration also touched.
Not our own bug reports
Where a problem traces back to vanilla Rivendell itself rather than
anything Rivolution- or lindon-specific, that's tracked separately —
this repo's commit history is specifically about the delta from
Rivolution, not a general Rivendell bug tracker.