vsariola / sointu

Fork of 4klang that can target 386, amd64 and WebAssembly. Tools run on Windows, Mac & Linux
MIT License
262 stars 17 forks source link

Sointu

Tests Binaries

A cross-architecture and cross-platform modular software synthesizer for small intros, forked from 4klang. Targetable architectures include 386, amd64, and WebAssembly; targetable platforms include Windows, Mac, Linux (and related) + browser.

User manual will be in the Wiki.

Installation

You can either 1) download the prebuilt release binaries from the releases; or 2) download the latest build from the master branch from the actions (find workflow "Binaries" and scroll down for .zip files containing the artifacts). Then just run one of the executables or, in the case of the VST plugins library files, copy them wherever you keep you VST2 plugins.

The pre 1.0 version tags are mostly for reference: no backwards compatibility will be guaranteed while upgrading to a newer version. Backwards compatibility will be attempted from 1.0 onwards.

Uninstallation: Sointu stores recovery data in OS-specific folders e.g. AppData/Roaming/Sointu on Windows. For clean uninstall, delete also this folder. See here where to find those folders on other platforms.

Summary

Sointu is work-in-progress. It is a fork and an evolution of 4klang, a modular software synthesizer intended to easily produce music for 4k intros — small executables with a maximum filesize of 4096 bytes containing realtime audio and visuals. Like 4klang, the sound is produced by a virtual machine that executes small bytecode to produce the audio; however, by now the internal virtual machine has been heavily rewritten and extended. It is actually extended so much that you will never fit all the features at the same time in a 4k intro, but a fairly capable synthesis engine can already be fitted in 600 bytes (386, compressed), with another few hundred bytes for the patch and pattern data.

Sointu consists of two core elements:

This is how the current prototype app looks like:

Screenshot of the tracker

Building

Various aspects of the project have different tool dependencies, which are listed below.

Sointu-track

This is the stand-alone version of the synth-tracker. Sointu-track uses the gioui for the GUI and oto for the audio, so the portability is currently limited by these.

Prerequisites

Running

go run cmd/sointu-track/main.go

Building an executable

go build -o sointu-track.exe cmd/sointu-track/main.go

On other platforms than Windows, replace -o sointu-track.exe with -o sointu-track.

If you want to use the x86 native virtual machine, add -tags=native to all the commands e.g.

go build -o sointu-track.exe -tags=native cmd/sointu-track/main.go

Sointu-vsti

This is the VST instrument plugin version of the tracker, compiled into a dynamically linked library and ran inside a VST host.

Prerequisites

Building

go build -buildmode=c-shared -tags=plugin -o sointu-vsti.dll .\cmd\sointu-vsti\

On other platforms than Windows, replace -o sointu-vsti.dll appropriately e.g. -o sointu-vsti.so; so far, the VST instrument has been built & tested on Windows and Linux.

Notice the -tags=plugin build tag definition. This is required by the vst2 library; otherwise, you will get a lot of build errors.

Add -tags=native,plugin to use the x86 native virtual machine instead of the virtual machine written in Go.

Sointu-compile

The command line interface to it is sointu-compile and the actual code resides in the compiler package, which is an ordinary go package with no other tool dependencies.

Running

go run cmd/sointu-compile/main.go

Building an executable

go build -o sointu-compile.exe cmd/sointu-compile/main.go

On other platforms than Windows, replace -o sointu-compile.exe with -o sointu-compile.

Usage

The compiler can then be used to compile a .yml song into .asm and .h files. For example:

sointu-compile -o . -arch=386 tests/test_chords.yml
nasm -f win32 test_chords.asm

WebAssembly example:

sointu-compile -o . -arch=wasm tests/test_chords.yml
wat2wasm --enable-bulk-memory test_chords.wat

If you are looking for an easy way to compile an executable from a Sointu song (e.g. for a executable music compo), take a look at NR4's Python-based tool for it.

Examples

The folder examples/code contains usage examples for Sointu with winmm and dsound playback under Windows and asound playback under Unix. Source code is available in C and x86 assembly (win32, elf32 and elf64 versions).

To build the examples, use ninja examples.

If you want to target smaller executable sizes, using a compressing linker like Crinkler on Windows is recommended.

The linux examples use ALSA and need libasound2-dev (or libasound2-dev:386) installed. The 386 version also needs pipewire-alsa:386 installed, which is not there by default.

Native virtual machine

The native bridge allows Go to call the sointu compiled x86 native virtual machine, through cgo, instead of using the Go written bytecode interpreter. It's likely slightly faster than the interpreter. Before you can actually run it, you need to build the bridge using CMake (thus, this will not work with go get).

Prerequisites

The last point is because the command line player and the tracker use cgo to interface with the synth core, which is compiled into a library. The cgo bridge resides in the package bridge.

Building

Assuming you are using ninja:

mkdir build
cd build
cmake .. -GNinja
ninja sointu

:warning: you must build the library inside a directory called 'build' at the root of the project. This is because the path where cgo looks for the library is hard coded to point to build/ in the go files.

Running ninja sointu only builds the static library that Go needs. This is a lot faster than building all the CTests.

You and now run all the Go tests, even the ones that test the native bridge. From the project root folder, run:

go test ./...

Play a song from the command line:

go run -tags=native cmd/sointu-play/main.go tests/test_chords.yml

:warning: Unlike the x86/amd64 VM compiled by Sointu, the Go written VM bytecode interpreter uses a software stack. Thus, unlike x87 FPU stack, it is not limited to 8 items. If you intent to compile the patch to x86/amd64 targets, make sure not to use too much stack. Keeping at most 5 signals in the stack is presumably fine (reserving 3 for the temporary variables of the opcodes). In future, the app should give warnings if the user is about to exceed the capabilities of a target platform.

:warning: If you are using Yasm instead of Nasm, and you are using MinGW: Yasm 1.3.0 (currently still the latest stable release) and GNU linker do not play nicely along, trashing the BSS layout. The linker had placed our synth object overlapping with DLL call addresses; very funny stuff to debug. See here and the fix here. Since Nasm is nowadays under BSD license, there is absolutely no reason to use Yasm. However, if you do, use a newer nightly build of Yasm that includes the fix.

Tests

There are regression tests that are built as executables, testing that they work the same way when you would link them in an intro.

Prerequisites

Building and running

Assuming you are using ninja:

mkdir build
cd build
cmake .. -GNinja
ninja
ninja test

Note that this builds 64-bit binaries on 64-bit Windows. To build 32-bit binaries on 64-bit Windows, replace in above:

cmake .. -DCMAKE_C_FLAGS="-m32" -DCMAKE_ASM_NASM_OBJECT_FORMAT="win32" -GNinja

Another example: on Visual Studio 2019 Community, just open the folder, choose either Debug or Release and either x86 or x64 build, and hit build all.

WebAssembly tests

These are automatically invoked by CTest if node and wat2wasm are found in the path.

New features since fork

Future goals

Long-shot ideas

Design philosophy

Background and history

4klang development was started in 2007 by Dominik Ries (gopher) and Paul Kraus (pOWL) of Alcatraz. The write-up will still be helpful for anyone looking to understand how 4klang and Sointu use the FPU stack to manipulate the signals. Since then, 4klang has been used in countless of scene productions and people use it even today.

However, 4klang seems not to be actively developed anymore and polyphonism was implemented only in a rather limited way (you could have exactly 2 voices per instrument if you enable it). Also, reading through the code, I spotted several avenues to squeeze away more bytes. These observations triggered project Sointu. That, and I just wanted to learn x86 assembly, and needed a real-world project to work on.

What's with the name

"Sointu" means a chord, in Finnish; a reference to the polyphonic capabilities of the synth. I assume we have all learned by now what "klang" means in German, so I thought it would fun to learn some Finnish for a change. And there's enough klangs already.

Prods using Sointu

Contributing

Pull requests / suggestions / issues welcome, through Github! Or just DM me on Discord (see contact information below).

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Veikko Sariola - pestis_bc on Demoscene discord - firstname.lastname@gmail.com

Project Link: https://github.com/vsariola/sointu

Credits

The original 4klang: Dominik Ries (gopher/Alcatraz) & Paul Kraus (pOWL/Alcatraz) :heart:

Sointu: Veikko Sariola (pestis/bC!), Apollo/bC!, NR4/Team210, PoroCYon, kendfss, anticore, qm210