mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-03 00:58:26 -04:00
Update README.md
This commit is contained in:
parent
e6feed1e26
commit
358db1ca46
301
README.md
301
README.md
@ -7,24 +7,33 @@ A cross-platform modular software synthesizer for small intros, forked from
|
|||||||
Summary
|
Summary
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Sointu is work-in-progress. It is a fork and an evolution of [4klang](
|
Sointu is work-in-progress. It is a fork and an evolution of
|
||||||
https://github.com/hzdgopher/4klang), a modular software synthesizer intended
|
[4klang](https://github.com/hzdgopher/4klang), a modular software synthesizer
|
||||||
to easily produce music for 4k intros-small executables with a maximum
|
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
|
filesize of 4096 bytes containing realtime audio and visuals. Like 4klang, the
|
||||||
sound is produced by a virtual machine that executes small bytecode to
|
sound is produced by a virtual machine that executes small bytecode to produce
|
||||||
produce the audio; however, by now the internal virtual machine has been
|
the audio; however, by now the internal virtual machine has been heavily
|
||||||
heavily rewritten and extended to make the code more maintainable, possibly
|
rewritten and extended. It is actually extended so much that you will never fit
|
||||||
even saving some bytes in the process.
|
all the features at the same time in a 4k intro, but a fairly capable synthesis
|
||||||
|
engine can already be fitted in 600 bytes (compressed), with another few hundred
|
||||||
|
bytes for the patch and pattern data.
|
||||||
|
|
||||||
|
Sointu consists of two core elements:
|
||||||
|
- A cross-platform synth-tracker app for composing music, written in
|
||||||
|
[go](https://golang.org/). The app is not working yet, but a prototype is
|
||||||
|
existing. The app exports (will export) the projects .yml files.
|
||||||
|
- A compiler, likewise written in go, which can be invoked from the command line
|
||||||
|
to compile these .yml files into .asm code. The resulting single file .asm can
|
||||||
|
be then compiled by [nasm](https://www.nasm.us/) or
|
||||||
|
[yasm](https://yasm.tortall.net).
|
||||||
|
|
||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Requires [CMake](https://cmake.org), [nasm](https://www.nasm.us/) or
|
Requires [go](https://golang.org/), [CMake](https://cmake.org),
|
||||||
[yasm](https://yasm.tortall.net), and your favorite c-compiler & build tool.
|
[nasm](https://www.nasm.us/) or [yasm](https://yasm.tortall.net), and your
|
||||||
Results have been obtained using Visual Studio 2019, gcc&make on linux,
|
favorite c-compiler & build tool. Results have been obtained using Visual Studio
|
||||||
MinGW&mingw32-make, and ninja&AppleClang.
|
2019, gcc&make on linux, MinGW&mingw32-make, and ninja&AppleClang.
|
||||||
|
|
||||||
Additionally, building the tracker requires [go](https://golang.org/).
|
|
||||||
|
|
||||||
### Example: building and running CTests using MinGW32
|
### Example: building and running CTests using MinGW32
|
||||||
|
|
||||||
@ -54,96 +63,122 @@ cd ..
|
|||||||
go test ./...
|
go test ./...
|
||||||
```
|
```
|
||||||
|
|
||||||
Running `mingw32-make sointu` only builds the static library that go needs. This is a lot
|
Running `mingw32-make sointu` only builds the static library that go needs. This
|
||||||
faster than building all the CTests.
|
is a lot faster than building all the CTests.
|
||||||
|
|
||||||
If you plan to build the Sointu library for using it from the Go side, you
|
If you plan to build the Sointu library for using it from the Go side, you
|
||||||
*must* build in the build/ directory, as bridge.go assumes the library can be
|
*must* build in the build/ directory, as bridge.go assumes the library can be
|
||||||
found from build/.
|
found from build/.
|
||||||
|
|
||||||
> :warning: **If you are using MinGW and Yasm**: Yasm 1.3.0 (currently still the latest
|
> :warning: At the moment, you must have gcc (e.g. mingw32 on Windows) to build
|
||||||
stable release) and GNU linker do not play nicely along, trashing the BSS layout.
|
the project. This is because cgo (the bridge to call c from go) requires gcc
|
||||||
See [here](https://tortall.lighthouseapp.com/projects/78676/tickets/274-bss-problem-with-windows-win64)
|
compiler, and the rest of the project uses the go code to automatically build
|
||||||
and the fix [here](https://github.com/yasm/yasm/commit/1910e914792399137dec0b047c59965207245df5).
|
the .asm from the .yml test cases. A solution that drops the need for CMake and
|
||||||
|
gcc is in the works; it likely involves dropping precompiled binaries for the
|
||||||
|
most popular platforms in the repository, which should also allow `go get` the
|
||||||
|
project. Regardless, it is possible to build the test cases using Visual Studio,
|
||||||
|
after building the library using mingw32. Luckily, the prebuilt binaries will be
|
||||||
|
only few tens of KB; this is a 4k synth project after all.
|
||||||
|
|
||||||
|
> :warning: **If you are using MinGW and Yasm**: Yasm 1.3.0 (currently still the
|
||||||
|
latest stable release) and GNU linker do not play nicely along, trashing the BSS
|
||||||
|
layout. See
|
||||||
|
[here](https://tortall.lighthouseapp.com/projects/78676/tickets/274-bss-problem-with-windows-win64)
|
||||||
|
and the fix
|
||||||
|
[here](https://github.com/yasm/yasm/commit/1910e914792399137dec0b047c59965207245df5).
|
||||||
Use a newer nightly build of yasm that includes the fix. The linker had placed
|
Use a newer nightly build of yasm that includes the fix. The linker had placed
|
||||||
our synth object overlapping with DLL call addresses; very funny stuff to debug.
|
our synth object overlapping with DLL call addresses; very funny stuff to debug.
|
||||||
|
|
||||||
New features since fork
|
New features since fork
|
||||||
-----------------------
|
-----------------------
|
||||||
- **Per instrument polyphonism**. An instrument has the possibility to
|
- **Compiler**. Written in go. The input is a .yml file and the output is an
|
||||||
have any number of voices, meaning in practice that multiple voices can
|
.asm. It works by inputting the song data to the excellent go
|
||||||
reuse the same opcodes. Done, see [here](tests/test_polyphony.asm) for an
|
`text/template` package, effectively working as a preprocessor. This allows
|
||||||
example and [here](src/opcodes/flowcontrol_footer.inc) for the implementation. The
|
quite powerful combination: we can handcraft the assembly code to keep the
|
||||||
maximum total number of voices will be 32: you can have 32 monophonic
|
entropy as low as possible, yet we can call arbitrary go functions as
|
||||||
instruments or any combination of polyphonic instruments adding up to 32.
|
"macros".
|
||||||
- **Any number of voices per track**. For example, a polyphonic instrument of
|
- **Tracker**. Written in go. A prototype exists.
|
||||||
3 voices can be triggered by 3 parallel tracks, to produce chords. But one
|
- **Supports 32 and 64 bit builds**. The 64-bit version is done with minimal
|
||||||
track can also trigger 3 voices, for example when using arpeggio. A track
|
changes to get it work, using template macros to change the lines between
|
||||||
can even trigger 2 voices of different instruments, alternating between
|
32-bit and 64-bit modes. Mostly, it's as easy as writing {{.AX}} instead of
|
||||||
these two; maybe useful for example as an easy way to alternate between an
|
eax; the macro {{.AX}} compiles to eax in 32-bit and rax in 64-bit.
|
||||||
open and a closed hihat.
|
- **Supports Windows, Linux and MacOS**. On all three 64-bit platforms, all
|
||||||
|
tests are passing. Additionally, all tests are passing on windows 32.
|
||||||
|
- **New units**. For example: bit-crusher, gain, inverse gain, clip, modulate
|
||||||
|
bpm (proper triplets!), compressor (can be used for side-chaining).
|
||||||
|
- **Per instrument polyphonism**. An instrument has the possibility to have
|
||||||
|
any number of voices, meaning in practice that multiple voices can reuse the
|
||||||
|
same opcodes. So, you can have a single instrument with three voices, and
|
||||||
|
three tracks that use this instrument, to make chords. See
|
||||||
|
[here](tests/test_chords.asm) for an example and [here](templates/patch.yml)
|
||||||
|
for the implementation. The maximum total number of voices will be 32: you
|
||||||
|
can have 32 monophonic instruments or any combination of polyphonic
|
||||||
|
instruments adding up to 32.
|
||||||
|
- **Any number of voices per track**. A single track can trigger more than one
|
||||||
|
voice. At every note, a new voice from the assigned voices is triggered and
|
||||||
|
the previous released. Combined with the previous, you can have a single
|
||||||
|
track trigger 3 voices and all these three voices use the same instrument,
|
||||||
|
useful to do polyphonic arpeggios (see [here](tests/test_polyphony.yml)).
|
||||||
|
Not only that, a track can even trigger voices of different instruments,
|
||||||
|
alternating between these two; maybe useful for example as an easy way to
|
||||||
|
alternate between an open and a closed hihat.
|
||||||
- **Easily extensible**. Instead of %ifdef hell, the primary extension
|
- **Easily extensible**. Instead of %ifdef hell, the primary extension
|
||||||
mechanism will be through new opcodes for the virtual machine. Only the
|
mechanism will be through new opcodes for the virtual machine. Only the
|
||||||
opcodes actually used in a song are compiled into the virtual machine. The
|
opcodes actually used in a song are compiled into the virtual machine. The
|
||||||
goal is to try to write the code so that if two similar opcodes are used,
|
goal is to try to write the code so that if two similar opcodes are used,
|
||||||
the common code in both is reused by moving it to a function.
|
the common code in both is reused by moving it to a function. Macro and
|
||||||
- **Take the macro languge to its logical conclusion**: it should probably be
|
linker magic ensure that also helper functions are only compiled in if they
|
||||||
called an internal domain specific language, hosted within the .asm preprocessor,
|
are actually used.
|
||||||
implemented using loads of macro definitions. Only the patch definition is needed;
|
- **Songs are YAML files**. These markup files are simple data files,
|
||||||
all the %define USE_SOMETHING will be defined automatically by the macros. Only
|
describing the tracks, patterns and patch structure (see
|
||||||
the opcodes needed are compiled into the program. Done, see for example
|
[here](tests/test_oscillat_trisaw.yml) for an example). The sointu-cli
|
||||||
[this test](tests/test_oscillat_trisaw.asm)! This has the nice implication that,
|
compiler then reads these files and compiles them into .asm code. This has
|
||||||
in future, there will be no need for binary format to save patches: the .asm
|
the nice implication that, in future, there will be no need for a binary
|
||||||
is easy enough to be imported into / exported from the GUI. Being a text
|
format to save patches, nor should you need to commit .o or .asm to repo:
|
||||||
format, the .asm based patch definitions play nicely with source control.
|
just put the .yml in the repo and automate the .yml -> .asm -> .o steps
|
||||||
|
using sointu-cli & nasm.
|
||||||
- **Harmonized support for stereo signals**. Every opcode supports a stereo
|
- **Harmonized support for stereo signals**. Every opcode supports a stereo
|
||||||
variant: the stereo bit is hidden in the least significant bit of the
|
variant: the stereo bit is hidden in the least significant bit of the
|
||||||
command stream and passed in carry to the opcode. This has several nice
|
command stream and passed in carry to the opcode. This has several nice
|
||||||
advantages: 1) the opcodes that don't need any parameters do not need an
|
advantages: 1) the opcodes that don't need any parameters do not need an
|
||||||
entire byte in the value stream to define whether it is stereo; 2) stereo
|
entire byte in the value stream to define whether it is stereo; 2) stereo
|
||||||
variants of opcodes can be implemented rather efficiently; in many cases,
|
variants of opcodes can be implemented rather efficiently; in some cases,
|
||||||
the extra cost of stereo variant is only 7 bytes, of which 4 are zeros, so
|
the extra cost of stereo variant is only 5 bytes (uncompressed). 3) Since
|
||||||
should compress quite nicely. 3) Since stereo opcodes usually follow stereo
|
stereo opcodes usually follow stereo opcodes (and mono opcodes follow mono
|
||||||
opcodes (and mono opcodes follow mono opcodes), the stereo bits of the
|
opcodes), the stereo bits of the command bytes will be highly correlated and
|
||||||
command bytes will be highly correlated and if crinkler or any other
|
if crinkler or any other modeling compressor is doing its job, that should
|
||||||
modeling compressor is doing its job, that should make them highly
|
make them highly predictable i.e. highly compressably.
|
||||||
predictable i.e. highly compressably. Done.
|
|
||||||
- **Test-driven development**. Given that 4klang was already a mature project,
|
- **Test-driven development**. Given that 4klang was already a mature project,
|
||||||
the first thing actually implemented was a set of regression tests to avoid
|
the first thing actually implemented was a set of regression tests to avoid
|
||||||
breaking everything beyond any hope of repair. Done, using CTest.
|
breaking everything beyond any hope of repair. Done, using go test (runs the
|
||||||
- **New units**. Bit-crusher, gain, inverse gain, clip, modulate bpm
|
.yml regression tests through the library) and CTest (compiles each .yml
|
||||||
(proper triplets!), compressor (can be used for side-chaining)... As
|
into executable and ensures that when run like this, the test case produces
|
||||||
always, if you don't use them, they won't be compiled into the code.
|
identical output). The tests are also ran in the cloud using github actions.
|
||||||
- **Arbitrary signal routing**. SEND (used to be called FST) opcode normally
|
- **Arbitrary signal routing**. SEND (used to be called FST in 4klang) opcode
|
||||||
sends the signal as a modulation to another opcode. But with the new
|
normally sends the signal as a modulation to another opcode. But with the
|
||||||
RECEIVE opcode, you just receive the plain signal there. So you can connect
|
new RECEIVE opcode, you just receive the plain signal there. So you can
|
||||||
signals in an arbitrary way. Actually, 4klang could already do this but in
|
connect signals in an arbitrary way. Actually, 4klang could already do this
|
||||||
a very awkward way: it had FLD (load value) opcode that could be modulated;
|
but in a very awkward way: it had FLD (load value) opcode that could be
|
||||||
FLD 0 with modulation basically achieved what RECEIVE does, except that
|
modulated; FLD 0 with modulation basically achieved what RECEIVE does,
|
||||||
RECEIVE can also handle stereo signals. Additionally, we have OUTAUX, AUX
|
except that RECEIVE can also handle stereo signals. Additionally, we have
|
||||||
and IN opcodes, which route the signals through global main or aux ports,
|
OUTAUX, AUX and IN opcodes, which route the signals through global main or
|
||||||
more closer to how 4klang does. But this time we have 8 mono ports / 4
|
aux ports, more closer to how 4klang does. But this time we have 8 mono
|
||||||
stereo ports, so even this method of routing is unlikely to run out of ports
|
ports / 4 stereo ports, so even this method of routing is unlikely to run
|
||||||
in small intros.
|
out of ports in small intros.
|
||||||
- **Pattern length does not have to be a power of 2**.
|
- **Pattern length does not have to be a power of 2**.
|
||||||
- **Sample-based oscillators, with samples imported from gm.dls**. Reading
|
- **Sample-based oscillators, with samples imported from gm.dls**. Reading
|
||||||
gm.dls is obviously Windows only, but the sample mechanism can be used also
|
gm.dls is obviously Windows only, but the sample mechanism can be used also
|
||||||
without it, in case you are working on a 64k and have some kilobytes to
|
without it, in case you are working on a 64k and have some kilobytes to
|
||||||
spare. See [this example](tests/test_oscillat_sample.asm), and this Python
|
spare. See [this example](tests/test_oscillat_sample.yml), and this Python
|
||||||
[script](scripts/parse_gmdls.py) parses the gm.dls file and dumps the
|
[script](scripts/parse_gmdls.py) parses the gm.dls file and dumps the sample
|
||||||
sample offsets from it.
|
offsets from it.
|
||||||
- **Unison oscillators**. Multiple copies of the oscillator running sligthly
|
- **Unison oscillators**. Multiple copies of the oscillator running slightly
|
||||||
detuned and added up to together. Great for trance leads (supersaw). Unison
|
detuned and added up to together. Great for trance leads (supersaw). Unison
|
||||||
of up to 4, or 8 if you make stereo unison oscillator and add up both left
|
of up to 4, or 8 if you make stereo unison oscillator and add up both left
|
||||||
and right channels. See [this example](tests/test_oscillat_unison.asm).
|
and right channels. See [this example](tests/test_oscillat_unison.yml).
|
||||||
- **Supports 32 and 64 bit builds**. The 64-bit version is done with minimal
|
|
||||||
changes to get it work, mainly for the future prospect of running the MIDI
|
|
||||||
instrument in 64-bit mode. All tests are passing so it seems to work.
|
|
||||||
- **Supports Windows, Linux and MacOS**. On all three 64-bit platforms,
|
|
||||||
all tests are passing. Additionally, all tests are passing on windows 32.
|
|
||||||
- **Compiling as a library**. The API is very rudimentary, a single function
|
- **Compiling as a library**. The API is very rudimentary, a single function
|
||||||
render, and between calls, the user is responsible for manipulating
|
render, and between calls, the user is responsible for manipulating the
|
||||||
the synth state in a similar way as the actual player does (e.g. triggering/
|
synth state in a similar way as the actual player does (e.g. triggering/
|
||||||
releasing voices etc.)
|
releasing voices etc.)
|
||||||
- **Calling Sointu as a library from Go language**. The Go API is slighty more
|
- **Calling Sointu as a library from Go language**. The Go API is slighty more
|
||||||
sane than the low-level library API, offering more Go-like experience.
|
sane than the low-level library API, offering more Go-like experience.
|
||||||
@ -151,25 +186,44 @@ New features since fork
|
|||||||
Future goals
|
Future goals
|
||||||
------------
|
------------
|
||||||
|
|
||||||
- **Find a more general solution for skipping opcodes / early outs**. It's
|
- **Find a more general solution for skipping opcodes / early outs**. It might
|
||||||
probably a new opcode "skip" that skips from the opcode to the next out in
|
be a new opcode "skip" that skips from the opcode to the next out in case
|
||||||
case the signal entering skip and the signal leaving out are both close to
|
the signal entering skip and the signal leaving out are both close to zero.
|
||||||
zero.
|
Need to investigate the best way to implement this.
|
||||||
- **Even more opcodes**. Maybe an equalizer? DC-offset removal?
|
- **Even more opcodes**. Some potentially useful additions could be:
|
||||||
- **Browser-based GUI and MIDI instrument**. Modern browsers support WebMIDI,
|
- Equalizer / more flexible filters
|
||||||
WebAudio and, most importantly, they are cross-platform and come installed
|
- Very slow filters (~ DC-offset removal). Can be implemented using a single
|
||||||
on pretty much any computer. The only thing needed is to be able to
|
bit flag in the existing filter
|
||||||
communicate with the platform specific synth; for this, the best
|
- Arbitrary envelopes; for easier automation.
|
||||||
option seems to be to run the synth inside a tiny websocket server that
|
- **MIDI support for the tracker**.
|
||||||
receives messages from browser and streams the audio to the browser.
|
- **Reintroduce the sync mechanism**. 4klang could export the envelopes of all
|
||||||
The feasibility of the approach is proven (localhost websocket calls
|
instruments at a 256 times lower frequency, with the purpose of using them
|
||||||
have 1 ms range of latency), but nothing more is done yet.
|
as sync data. This feature was removed at some point, but should be
|
||||||
|
reintroduced at some point. Need to investigate the best way to implement
|
||||||
|
this; maybe a "sync" opcode that save the current signal from the stack? Or
|
||||||
|
reusing sends/outs and having special sync output ports, allowing easily
|
||||||
|
combining multiple signals into one sync. Oh, and we probably should dump
|
||||||
|
the whole thing also as a texture to the shader; to fly through the song, in
|
||||||
|
a very literal way.
|
||||||
|
|
||||||
Nice-to-have ideas
|
Crazy ideas
|
||||||
------------------
|
-----------
|
||||||
|
- **Using Sointu as a sync-tracker**. Similar to [GNU
|
||||||
- **Tracker**. If the list of primary goals is ever exhausted, a browser-based
|
Rocket](https://github.com/yupferris/gnurocket), but (ab)using the tracker
|
||||||
tracker would be nice to take advantage of all the features.
|
we already have for music. We could define a generic RPC protocol for Sointu
|
||||||
|
tracker send current sync values and time; one could then write a debug
|
||||||
|
version of a 4k intro that merely loads the shader and listens to the RPC
|
||||||
|
messages, and then draws the shader with those as the uniforms. Then, during
|
||||||
|
the actual 4k intro, just render song, get sync data from Sointu and send as
|
||||||
|
uniforms to shader. A track with two voices, triggering an instrument with a
|
||||||
|
single envelope and a slow filter can even be used as a cheap smooth
|
||||||
|
interpolation mechanism.
|
||||||
|
- **Support WASM targets with the compiler**. It should not be impossible to
|
||||||
|
reimplement the x86 core with WAT equivalent. It would be nice to make it
|
||||||
|
work (almost) exactly like the x86 version, so one could just track the song
|
||||||
|
with Sointu tools and export the song to WAT using sointu-cli.
|
||||||
|
- **Hack deeper into audio sources from the OS**. Speech synthesis, I'm eyeing
|
||||||
|
at you.
|
||||||
|
|
||||||
Anti-goals
|
Anti-goals
|
||||||
----------
|
----------
|
||||||
@ -182,17 +236,20 @@ Anti-goals
|
|||||||
VSTi2... There is [JUCE](https://juce.com/), but it is again a mammoth and
|
VSTi2... There is [JUCE](https://juce.com/), but it is again a mammoth and
|
||||||
requires apparently pretty deep integration in build system in the form of
|
requires apparently pretty deep integration in build system in the form of
|
||||||
Projucer. If someone comes up with a light-weight way and easily
|
Projucer. If someone comes up with a light-weight way and easily
|
||||||
maintainable way to make the project into DAW plugin, I may reconsider.
|
maintainable way to make the project into DAW plugin, I may reconsider. For
|
||||||
|
now, if you really must, we aim to support MIDI.
|
||||||
|
|
||||||
Design philosophy
|
Design philosophy
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
- Try to avoid %ifdef hell as much as possible. If needed, try to include all
|
- Make sure the assembly code is readable after compiling: it should have
|
||||||
code toggled by a define in one block.
|
liberally comments *in the outputted .asm file*. This allows humans to study
|
||||||
|
the outputted code and figure out more easily if there's still way to
|
||||||
|
squueze out instructions from the code.
|
||||||
- Instead of prematurely adding %ifdef toggles to optimize away unused
|
- Instead of prematurely adding %ifdef toggles to optimize away unused
|
||||||
features, start with the most advanced featureset and see if you can
|
features, start with the most advanced featureset and see if you can
|
||||||
implement it in a generalized way. For example, all the modulations are
|
implement it in a generalized way. For example, all the modulations are now
|
||||||
now added into the values when they are converted from integers, in a
|
added into the values when they are converted from integers, in a
|
||||||
standardized way. This got rid of most of the %ifdefs in 4klang. Also, with
|
standardized way. This got rid of most of the %ifdefs in 4klang. Also, with
|
||||||
no %ifdefs cluttering the view, many opportunities to shave away
|
no %ifdefs cluttering the view, many opportunities to shave away
|
||||||
instructions became apparent. Also, by making the most advanced synth
|
instructions became apparent. Also, by making the most advanced synth
|
||||||
@ -201,34 +258,48 @@ Design philosophy
|
|||||||
becomes untolerable.
|
becomes untolerable.
|
||||||
- Benchmark optimizations. Compression results are sometimes slightly
|
- Benchmark optimizations. Compression results are sometimes slightly
|
||||||
nonintuitive so alternative implementations should always be benchmarked
|
nonintuitive so alternative implementations should always be benchmarked
|
||||||
e.g. by compiling and linking a real-world song with [Leviathan](https://github.com/armak/Leviathan-2.0)
|
e.g. by compiling and linking a real-world song with
|
||||||
and observing how the optimizations
|
[Leviathan](https://github.com/armak/Leviathan-2.0) and observing how the
|
||||||
affect the byte size.
|
optimizations affect the byte size.
|
||||||
|
|
||||||
Background and history
|
Background and history
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
[4klang](https://github.com/hzdgopher/4klang) development was started in 2007
|
[4klang](https://github.com/hzdgopher/4klang) development was started in 2007 by
|
||||||
by Dominik Ries (gopher) and Paul Kraus (pOWL) of Alcatraz. The [write-up](
|
Dominik Ries (gopher) and Paul Kraus (pOWL) of Alcatraz. The
|
||||||
http://zine.bitfellas.org/article.php?zine=14&id=35) will still be helpful for
|
[write-up](http://zine.bitfellas.org/article.php?zine=14&id=35) will still be
|
||||||
anyone looking to understand how 4klang and Sointu use the FPU stack to
|
helpful for anyone looking to understand how 4klang and Sointu use the FPU stack
|
||||||
manipulate the signals. Since then, 4klang has been used in countless of scene
|
to manipulate the signals. Since then, 4klang has been used in countless of
|
||||||
productions and people use it even today.
|
scene productions and people use it even today.
|
||||||
|
|
||||||
However, 4klang is pretty deep in the [%ifdef hell](https://www.cqse.eu/en/blog/living-in-the-ifdef-hell/),
|
However, 4klang is not actively developed anymore and the polyphonism was never
|
||||||
and the polyphonism was never implemented in a very well engineered way (you
|
implemented in a very well engineered way (you can have exactly 2 voices per
|
||||||
can have exactly 2 voices per instrument if you enable it). Also, reading
|
instrument if you enable it). Also, reading through the code, I spotted several
|
||||||
through the code, I spotted several avenues to squeeze away more bytes. These
|
avenues to squeeze away more bytes. These observations triggered project Sointu.
|
||||||
observations triggered project Sointu. That, and I just wanted to learn x86
|
That, and I just wanted to learn x86 assembly, and needed a real-world project
|
||||||
assembly, and needed a real-world project to work on.
|
to work on.
|
||||||
|
|
||||||
|
What's with the name
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
"Sointu" means a chord, in Finnish; a reference to the polyphonic capabilities
|
||||||
|
of the synth. Also, 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](https://www.pouet.net/prod.php?which=53398)
|
||||||
|
[enough](https://www.pouet.net/prod.php?which=75814)
|
||||||
|
[klangs](https://www.pouet.net/prod.php?which=85351) already.
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
-------
|
-------
|
||||||
|
|
||||||
The original 4klang was developed by Dominik Ries ([gopher](https://github.com/hzdgopher/4klang)) and Paul Kraus
|
The original 4klang was developed by Dominik Ries
|
||||||
(pOWL) of Alcatraz.
|
([gopher](https://github.com/hzdgopher/4klang)) and Paul Kraus (pOWL) of
|
||||||
|
Alcatraz. :heart:
|
||||||
|
|
||||||
Sointu was initiated by Veikko Sariola (pestis/bC!).
|
Sointu was initiated by Veikko Sariola (pestis/bC!).
|
||||||
|
|
||||||
|
Apollo/bC! put the project on the path to Go, and wrote the prototype of the
|
||||||
|
tracker GUI.
|
||||||
|
|
||||||
PoroCYon's [4klang fork](https://github.com/PoroCYon/4klang) inspired the macros
|
PoroCYon's [4klang fork](https://github.com/PoroCYon/4klang) inspired the macros
|
||||||
to better support cross-platform asm.
|
to better support cross-platform asm.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user