PER|FORMER
eurorack-sequencer-firmware-styr
Mod

eurorack-sequencer-firmware-styr

Hype20/100

Styr is an independent firmware fork and modernization of Simon Kallweit’s Westlicht PER|FORMER Eurorack sequencer, with a modern build system, simulator, tests, documentation, and ongoing feature dev

eurorack-sequencer-firmware-styr is a mod for the Westlicht PER|FORMER, by @napolitano. Open source under MIT, 1 star on GitHub.

forWestlicht PER|FORMER·by@napolitano

Unclaimed. Is this yours? Sign in with GitHub as @napolitano to claim it.

Downloads
0
Star
1
Forks
0
Commits
30
Last commit
Get the source

No release files yet. Build from source.

MIT· napolitano/eurorack-sequencer-firmware-styr·ko-fi.com/southsignallab·downloads come from the creator’s GitHub releases

30
Commits
0
Releases
30 commits and 0 releases in the last year
Activity · last 12 months

Styr

CI Code license: MIT Documentation: CC BY-NC 4.0 Target: STM32F405RG Firmware build: PlatformIO Simulator build: CMake

Acknowledgement

Styr exists because Simon Kallweit created Westlicht PER|FORMER. The hardware concept, original firmware and the technical foundation this fork builds on are his work. I am genuinely grateful that he made PER|FORMER available as an open project and gave others something substantial to learn from and continue working with.

Styr is an independent continuation and modernization of that foundation. It is not an attempt to blur, replace or take ownership of Simon's authorship; keeping that provenance clear is part of the project itself.


Styr modernizes the build, simulator, tests, documentation and selected firmware functionality while retaining explicit provenance to the original PER|FORMER project.

Why Styr?

Styr comes from the Swedish verb styra: to steer, guide, direct, or control. Styr is its present-tense form — roughly, steers or controls. The word reaches further back into the Germanic languages: Old Norse stýra carried much the same meaning, with relatives still visible in English steer and German steuern.

That felt appropriate for a sequencer.

Styr provides timing, structure, modulation, probability, routing and generative tools, but it is not intended to make musical decisions for you. The direction remains yours. It is there to steer a performance rather than define it.

The name is also deliberately short and functional: four letters for a device whose job is to keep a fairly complex musical system under control.

[!IMPORTANT] Styr is an independent project. Westlicht and PER|FORMER identify the upstream hardware and firmware on which inherited parts of this repository are based; they are not Styr branding and are not presented as property of this project.

[!WARNING] Styr is under active development and is not yet presented as a drop-in production replacement for the original firmware. Read the firmware update guide before installing it on hardware.

Index

Project goals

Styr focuses on preserving a capable Eurorack sequencing platform while making continued development practical. The work is deliberately incremental:

  • keep working sequencer behavior stable unless a change is intentional and tested;
  • keep firmware and simulator on the same src/sequencer/ implementation;
  • provide reproducible PlatformIO and CMake build workflows;
  • retain the established flash layout and SD-card update path while the legacy bootloader remains in service;
  • improve automated testing and deterministic documentation tooling;
  • modernize dependencies and subsystems one at a time instead of replacing the whole platform at once;
  • keep inherited authorship, provenance and third-party licensing explicit.

Current status

AreaStatusNotes
Application firmwareActivePlatformIO build is part of CI.
SD-card update bundleActiveRecommended installation path for end users.
BootloaderCritical / gatedThe bootloader must link within 32 KiB; host tests, ABI checks and a hard CI size gate protect it.
Native simulatorActiveCMake-based; Windows UCRT64 and Linux workflows are maintained.
Product testsActivePlatformIO owns native bootloader, shared-core and sequencer/application tests; CI runs all 44 suites.
Manual screenshotsActiveDeterministic LCD captures generated from simulator state.
End-user manualIn progressScreen and feature documentation is being expanded incrementally.

[!NOTE] The bootloader is release-critical and no longer allowed to fail silently in CI. Its ARM build must fit within 32 KiB and pass the dedicated bootloader verification gates. See docs/testing/bootloader.md.

Changes from PER|FORMER

Styr keeps user-visible changes separate by type. The Fixed upstream bugs table contains only defects verified in the original Westlicht PER|FORMER v0.1.42 source. Styr-specific regressions are fixed as normal maintenance and are not attributed to upstream.

Fixed upstream bugs

AreaInherited issueWhat Styr does
External clockThe first real BPM measurement required a third edge because timestamp 0 also meant “no previous edge”.Uses explicit edge-valid state, so the second edge already gives a real tempo measurement.
External clockInitial slave BPM was strongly pulled toward zero by the startup filter.Locks the first valid period immediately, then applies tracking to later measurements.
External clockAlternating swing biased BPM because individual BPM values were smoothed instead of pulse periods.Estimates tempo in the period domain and tracks swing phase separately.
External clockAuto mode always used a 500 ms loss-of-clock timeout.Uses an acquisition window and a timeout derived from the measured pulse period.
External clockPhase recovery used unsigned time subtraction, so a future deadline could look massively overdue.Uses wrap-safe signed/modular deadline comparisons.
External clockSwing interpolation predicted the next interval from the interval that had just ended.Learns the short/long pair and predicts the opposite interval.
External clockSlave sub-tick deadlines were unsafe across the 32-bit microsecond rollover.Uses rollover-safe time comparisons.
External clockStop/Continue could retain pending interpolated ticks.Clears stale interpolation state before transport resumes.
External clockDisabling the active MIDI/USB clock source could leave the clock stuck running.Stops and releases the active slave source immediately.
Clock outputPulse width was derived from master BPM even while slaved.Derives pulse timing from the tempo source that is actually active.
SequenceSingle-step aligned PingPong could divide/modulo by zero.Treats a one-step range as a stable one-step sequence.
SequenceSingle-step Free PingPong could temporarily leave its only valid step.Keeps the playhead on the sole valid step.
Note trackRecording the first completed step could underflow its quantization window.Uses a bounded first-step recording window without unsigned wraparound.
Note trackA positive gate could quantize to zero ticks at the fastest routed divisor.Keeps every logically present gate at least one engine tick long.
Note trackRetrigger high pulses could quantize to zero ticks at small divisors.Limits realized retrigger density to timing that can actually be represented.
Curve trackFree mode could jump phase when its divisor changed.Keeps a local free-running phase and applies divisor changes without snapping to the transport grid.
Curve trackNext Pattern fill mixed current-pattern gate data with next-pattern curve data.Evaluates gate and curve from the same next-pattern step.
Curve trackNext Pattern fill used the current pattern's shape-variation probability.Uses the selected next-pattern step consistently for variation decisions.
Curve trackStep equality ignored gate and gate-probability data, so gate-only edits could appear unchanged.Compares the complete Curve step state.
Curve trackA present Curve gate could quantize to a zero-tick pulse at the fastest divisor.Keeps every present Curve gate at least one engine tick long.

Implemented upstream TODOs

Upstream TODO / gapWhat Styr does
Negative Note Gate Offset was explicitly left for future implementation.Adds signed microtiming with deterministic look-ahead where the next event is knowable, and safe boundary fallback where it is not.

Improvements

AreaWhat changed
External clock robustnessIsolated early/late pulses are distinguished from confirmed tempo changes, reducing reactions to double-triggers and single missing pulses.
Note microtimingFuture gate events are scheduled chronologically and generation-owned, so an old Gate-Off cannot cut short a newer pre-triggered gate.
Microtiming boundariesForward/Backward loop wraps can pre-trigger exactly; transport start, Reset Measure, linked tracks, pending pattern changes, dynamic Fill and non-deterministic modes use conservative boundary timing instead of guessing.
Simulator timingHost clock timers now account for the full requested simulated wait interval, including the first millisecond after enable/re-enable.
Build and verificationFirmware tests are owned by PlatformIO/Unity; simulator-only tests remain under CMake/CTest, with hard bootloader and repository-cleanliness gates.
Source documentationFirst-party APIs, state, constants and enums use structured US-English Doxygen documentation, enforced by a source-documentation quality gate and prepared for HTML/XML technical-reference generation.

New features

FeatureWhat it adds
LFO trackDedicated Free/Sync modulation track with eight waveforms, voltage range control, clipping and preview support.
Acid Bassline generatorDeterministic acid-style Note patterns with seed, root, length, density and legato controls plus preview/commit workflow.
Overview mini mapCompact indication of the active pattern segment in the overview.
Overview note labelsNote tracks can show note names directly in the overview.
Advanced SettingsAdds a dedicated system page for advanced configuration.

Quick start

Firmware

Install the pinned PlatformIO Core version:

python -m pip install -r toolchain/requirements-platformio.txt

Build the application:

pio run -e application

Build the SD-card update image:

pio run -e application -t sd-update

Flash through ST-Link:

pio run -e application -t upload

[!CAUTION] ST-Link is a development/service path, not the recommended end-user update method. The programming header connects directly to the MCU and has no protective interface. Follow the connection order and electrical warnings in README_FIRMWARE_UPDATE.md.

Simulator

The simulator executes the same sequencer implementation used by the hardware firmware.

On Windows with MSYS2 UCRT64:

cd src\simulator
C:\msys64\ucrt64\bin\cmake.exe --preset windows-ucrt64-debug
C:\msys64\ucrt64\bin\cmake.exe --build --preset windows-ucrt64-debug

Run from the repository root:

.\build\simulator\windows-ucrt64-debug\styr_simulator.exe

Host prerequisites and additional presets are documented in src/simulator/README.md.

Tests

PlatformIO is the canonical test runner for code that ships in the embedded product. Run the complete native product suite — bootloader, shared core and sequencer — from the repository root:

pio test -e test_product_native

The focused test_bootloader_native environment remains available for bootloader-only safety verification.

CMake/CTest is reserved for simulator-specific behavior. After configuring and building the simulator, run its host-only regression suite with:

cd src/simulator
ctest --preset release --output-on-failure

Test strategy, ownership rules and verification material belong under docs/testing/.

Manual screenshots

Generate the maintained LCD documentation screenshots on Windows:

cd src\simulator
cmake.exe --build --preset windows-ucrt64-debug --target manual-screenshots

The generator updates PNG assets only. It does not generate or overwrite the hand-maintained Markdown documentation.

See README_SCREENSHOTS.md for the capture model, scaling rules, validation and review workflow.

Documentation

The documentation is intentionally organized by audience and purpose, not by whichever source directory happens to implement a feature. The main entry point is docs/README.md.

Documentation index

NeedStart herePurpose
Use Styrdocs/manual/README.mdMaintained end-user manual, features, UI screens and controls.
Install/update firmwareREADME_FIRMWARE_UPDATE.mdSD-card update workflow and ST-Link service/development procedure.
Regenerate manual imagesREADME_SCREENSHOTS.mdDeterministic screenshot generation and validation.
Understand the architecturedocs/development/README.mdBuild, architecture, formats, sequencer internals and developer workflows.
Source/API documentation rulesdocs/development/documentation/README.mdUS-English Doxygen contract, technical-reference output and separation from end-user manual prose.
Understand persistent formatsdocs/development/formats/README.mdProject, settings and user-scale file formats.
Work on sequencer internalsdocs/development/sequencer/README.mdTrack models, layers and song internals.
Verify behaviordocs/testing/README.mdTest strategy and verification procedures.
Consult upstream historical docsdocs/legacy/performer/Original PER

Agent-assisted manual maintenance

Styr uses repository-scoped AI agents to help analyze, draft, review, and edit the end-user manual. The process is deliberately transparent and review-driven: agent-produced documentation is version-controlled like any other source change, is checked against the implementation, tests, and deterministic screenshots, and requires human review before it becomes part of a release. Release documentation is built from the reviewed repository sources; agents are not used to rewrite the manual at release time.

Documentation-agent work is maintainer-triggered. Public issues or comments are not treated as authorization to run an agent or modify the manual. An authorized sync issue is assigned once to the Styr Documentation Orchestrator, which delegates analysis, authoring, technical review, and final US-English editing to internal specialist agents inside the same task and Draft PR. Deterministic CI and human review remain mandatory. See docs/development/documentation/AGENT_WORKFLOW.md for the operational workflow and docs/development/documentation/README.md for the documentation architecture.

How the documentation is organized

docs/
├── manual/                 end-user documentation
│   ├── features/           feature-oriented guides
│   ├── screens/            one maintained Markdown page per relevant UI state
│   └── assets/             manual-owned images, including generated LCD captures
├── development/            implementation and contributor documentation
│   ├── architecture/       source ownership and system structure
│   ├── build/              embedded build workflows
│   ├── documentation/      documentation tooling internals
│   ├── fonts/              font conversion and editing toolchain
│   ├── formats/            persistent file formats
│   └── sequencer/          sequencer implementation details
├── testing/                test strategy and verification procedures
└── legacy/performer/       inherited upstream documentation kept unchanged where possible

The placement rules are:

  1. End-user behavior belongs in docs/manual/. A feature or screen should be understandable without reading implementation notes.
  2. Every relevant UI state can have its own Markdown document. Screenshot regeneration replaces only the corresponding PNG asset, never the Markdown source.
  3. Feature guides and screen references are complementary. Feature guides explain workflows and concepts; screen pages document concrete UI states and controls.
  4. Developer material belongs in docs/development/. Architecture, formats, source ownership and implementation details should not leak into the user manual unless needed to operate the module.
  5. Verification belongs in docs/testing/. Test policy and procedures stay separate from implementation design notes.
  6. Inherited PER|FORMER documents stay under docs/legacy/performer/. They remain historical/upstream references and retain their original provenance.
  7. Assets live with the documentation area that owns them. There is deliberately no generic docs/assets/ bucket; manual images live in docs/manual/assets/.
  8. Root-level operational READMEs are exceptional entry points. Firmware update and screenshot-generation procedures stay at repository root because they are frequently used directly from the GitHub landing page.

[!TIP] When adding a new feature, start with a feature README under docs/manual/features/, add dedicated screen references under docs/manual/screens/ for relevant UI states, and add deterministic screenshots to docs/manual/assets/ where they materially improve the explanation.

Repository layout

styr/
├── src/                    first-party source code
│   ├── sequencer/          main Styr sequencer implementation
│   ├── simulator/          desktop host + simulator-only CMake/CTest tests
│   ├── bootloader/         SD-card firmware updater
│   ├── hwconfig/           hardware configuration image
│   ├── tester/             hardware diagnostics firmware
│   ├── shared/             genuinely cross-target support code
│   └── tools/              host-side source utilities
├── assets/                 first-party build/runtime source assets
├── test/                   PlatformIO + Unity product tests
├── third_party/            imported source governed by upstream licenses
├── toolchain/              board, linker and build-system integration
├── docs/                   maintained documentation tree
├── .github/                CI, contribution, security and repository metadata
├── platformio.ini          embedded build entry point
└── LICENSES/               license texts and provenance support

[!IMPORTANT] Sequencer behavior belongs under src/sequencer/ even when it is exercised through the simulator. The simulator is a host for the real sequencer implementation, not a parallel firmware implementation.

Development principles

  • CLI-first and editor-independent build workflows are canonical.
  • VSCodium/VS Code configuration may provide convenience, but must not become a build requirement.
  • New behavior should receive focused regression coverage where practical.
  • Third-party code remains visibly separated under third_party/.
  • Documentation changes should preserve the distinction between inherited upstream facts, current Styr behavior and unresolved analysis.
  • Generated artifacts must not overwrite hand-maintained documentation sources.

Contributing and security

Repository policies live under .github/:

Licensing and provenance

Inherited PER|FORMER source remains MIT-licensed. The root LICENSE and LICENSES/MIT.txt, together with file-level authorship/SPDX headers, preserve the software licensing and attribution boundary. Third-party code retains its own upstream licenses.

New Styr-authored documentation is licensed separately under CC BY-NC 4.0; see docs/LICENSE. Inherited PER|FORMER documentation under docs/legacy/performer/ retains its upstream provenance and license.

From Munich with blue heart