Genesis Digital Audio Workstation
Genesis is a cross-platform digital audio workstation with ambitious goals: peer-to-peer multiplayer editing, complete plugin safety, and a built-in community which shares plugins, projects, and samples.
Genesis aims to make music creation collaborative, global, free, and open source.
Core Library (libgenesis)
- Load and save any format audio file.
- Multi-threaded audio pipeline working.
- MIDI Keyboard support.
- Basic synthesizer plugin. YouTube Demo
- Basic delay plugin.
- Resampling and channel remapping plugin.
delay.c- default recording device connected to a delay effect connected to default playback device.
synth.c- default midi keyboard connected to a synth connected to default playback device.
list_devices.c- list available audio and midi devices and watch for when devices are added or removed.
list_supported_formats.c- list available audio import and export formats.
normalize_audio.c- open an audio file, normalize it, and export it as a new file.
- Display recording and playback devices in a tree view.
- Browse sample files in a tree widget and hear file previews.
- Drag audio clips into the track editor.
libgenesis is programmed in a tiny subset of C++:
- No STL.
- No exceptions or run-time type information.
- Pass pointers instead of references.
- No linking against libstdc++.
- All fields and methods in structs and classes are
- Avoid constructor initialization lists.
Building and Running
mkdir build cd build cmake .. make ./genesis
Running the Tests
Generate Test Coverage Report
sudo apt-get install lcov make coverage # view `coverage/index.html` in a browser
When you build, you have 2 choices:
Debug: slower, but contains useful information for reporting and fixing bugs. This is the default configuration.
Release: generates optimized code, but if the software crashes or misbehaves, it is difficult to troubleshoot.
To build in
mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release make ./genesis
- playback: sometimes doesn't activate all the audio clip segments
- assertion failure / memory corruption when multithreading on?
- rendering multiple jobs freezes with multithreading on
- UI spacing on render jobs is weirdo
- ability to update audio graph without stopping pipeline
- make a playback selection
- sequencer / piano roll
- make sure recording works and is stable
- drag samples directly to track editor
- audio clip segment: display waveform
- audio clip segment: drag to move
- right click to delete audio clip segments
- drag audio clip: display clip even while drag ongoing
- quantization when dragging (hold alt to disable)
- resample node needed for audio clip nodes
- undo/redo crash
Real-time Safety and Multithreading
Most operating systems do not attempt to make any real-time guarantees. This means that various operations do not guarantee a maximum bound on how long it might take. For example, when you allocate memory, it might be very quick, or the kernel might have to do some memory defragmentation and cache invalidation to make room for your new segment of memory. Writing to a hard drive might cause it to have to warm up and start spinning.
This can be a disaster if one of these non-bounded operations is in the audio rendering pipeline, especially if the latency is low. The buffer of audio going to the sound card might empty before it gets filled up, causing a nasty audio glitch sound known as a "buffer underrun".
In general, all syscalls are suspect when it comes to real-time guarantees. The careful audio programmer will avoid them all.
libgenesis meets this criteria with one exception. libgenesis takes advantage of hardware concurrency by using one worker thread per CPU core to render audio. It carefully uses a lock-free queue data structure to avoid making syscalls, but when there is not enough work to do and some threads are sitting idly by, those threads need to suspend execution until there is work to do.
So if there is more work to be done than worker threads, no syscalls are made.
However, if a worker thread has nothing to do and needs to suspend execution,
it makes a
FUTEX_WAIT syscall, and then is woken up by another worker thread
libgenesis follows semver. Major version is bumped when API or ABI compatibility is broken. Minor version is bumped when new features are added. Patch version is bumped only for bug fixes. Until 1.0.0 is released no effort is made toward backward compatibility whatsoever.
Genesis Audio Studio has an independent version from libgenesis. Major version is bumped when a project file will no longer generate the same output audio as the previous version. Minor version is bumped when new features are added. Patch version is bumped only for bug fixes. Until 1.0.0 is released no effort is made toward project files being backward compatible to previous versions.
Positions in the audio project are in floating point whole notes. This is to take into account the fact that the tempo and time signature could change at any point in the audio project. You can convert from whole notes to frames by calling a utility function which takes into account tempo and time signature changes.
Project File Format
The first 16 bytes of every Genesis project file are:
ca2f 5ef5 00d8 ef0b 8074 18d0 e40b 7a4f
This uniquely identifies the file as a Genesis project file. The default file
After this contains an ordered list of transactions. A transaction is a set of edits. There are 2 types of edits: put and delete.
A put contains a key and a value, each of which is a variable number of bytes. A delete contains only a key, which is a variable number of bytes.
A transaction looks like this:
Offset | Description -------+------------ 0 | uint32be crc32 of this transaction, everything excluding this field 4 | uint32be length of transaction in bytes including this and crc32 8 | uint32be number of put edits in this transaction 12 | uint32be number of delete edits in this transaction 16 | the put edits in this transaction - | the delete edits in this transaction
A put edit looks like:
Offset | Description -------+------------ 0 | uint32be key length in bytes 4 | uint32be value length in bytes 8 | key bytes - | value bytes
A delete edit looks like:
Offset | Description -------+------------ 0 | uint32be key length in bytes 4 | key bytes
That's it. To read the file, apply the transactions in order. To update a file, append a transaction. Periodically "garbage collect" by creating a new project file with a single transaction with all the data, and then atomically rename the new project file over the old one.
Genesis is licensed with the General Public License. A full copy of the license text is included in the LICENSE file, but here's a non-normative summary:
As a user you have access to the source code, and if you are willing to compile from source yourself, you can get the software for free.
As a company you may use the source code in your software as long as you publish your software's source code under a free software license.