https://github.com/zserge/1bitr
Minimalistic text-based 1-bit music tracker
https://github.com/zserge/1bitr
Last synced: about 1 year ago
JSON representation
Minimalistic text-based 1-bit music tracker
- Host: GitHub
- URL: https://github.com/zserge/1bitr
- Owner: zserge
- Created: 2021-03-05T10:39:14.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2021-05-23T11:48:21.000Z (about 5 years ago)
- Last Synced: 2025-03-18T08:21:29.139Z (about 1 year ago)
- Language: C
- Size: 21.5 KB
- Stars: 73
- Watchers: 6
- Forks: 7
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 1bitr
1bitr ("One Bitter" or "The Bitter One") is a minimalistic text-based music tracker. It only supports 1-bit audio playback and encourages users to write their own sound routines (engines), as well as the music itself.
## Text file format
A code snippet is worth a thousand words:
```
; 0
; Fifth Symphony (ta-da-da dah...)
G-4 60
G-4
G-4
D#4 e0
```
You can play it as `./1bitr < examples/fifth`.
1bitr reads music line by line from `stdin`, parses it and passes each parsed row to the sound engine, which plays it. There are no patterns, no looping, no samples. Only notes and effects.
Line comments start with a `;`. Comments are ignored. Blank line are skipped as well. First line comment is a special one, see below about the engines.
Other lines must contain musical data that the sound engine can interpret and play.
Each line is a row of numerical values (up to 256 columns are supported, but most likely you will never use more than 16). Numerical values are writted in hexadecimal format (without `0x` prefix). Also, notes can be written as `C-3` or `A#4` and they are converted into numbers by parser. Values starting with a dash are interpreted as zeros (i.e. `--` is zero and `---` is zero and `00` is also zero).
## Playback
There are no loops or patterns beacause one can easily simulate them:
```
# Put each part into a separate file and concatenate them
$ cat INTRO P1 P2 P1 P3 | ./1bitr
# Play part of the file from line 10 to line 20
$ tail -n +20 MELODY | head -n 10 | ./1bitr
# Play random notes (shuffle music file)
$ cat MUSIC | sort -R | ./1bitr
```
If the stdout is not a terminal, `1bitr` write WAV data into the stdout (instead of playing it). This allows you to save music or to pass it further to other apps:
```
$ ./1bitr < MUSIC > music.bin
$ ./1bitr < MUSIC | aplay
```
Raw PCM data generated by `1bitr` can be converted to WAV
using `SoX`:
```
$ sox -t raw -e unsigned-integer -c 1 -r 44100 -b 8 music.bin music.wav
```
## Engines
You are the master of your music. If you are into programming, please try writing your own 1-bit sound routine, it's likely to be fun! Please, make a PR to share it with the others.
Sound routine is a function that takes a row of up to 256 integers and a special `out` function, that set audio output to 0 or non-zero level.
Here's a sound routine that always plays noise and ignores all music data:
```c
void noise(int *row, void (*out)(unsigned char)) {
out(rand() % 2);
}
```
And here's the Sound Engine Zero, it can only play 1 square wave of the given frequency with 50% duty cycle:
```c
static void zero(int *row, void (*out)(unsigned char)) {
int counter = row[0];
unsigned char value = 0;
for (int timer = 0; timer < 5000; timer++) {
if (--counter == 0) {
value = !value;
counter = row[0];
}
out(value);
}
}
```
If you have added a new engine - choose a single-byte identifier for it (it can be a letter or a digit), and adjust `set_engine` function to switch to your engine. For example, for our engine "zero" would like to use identifier "Z":
```c
static void set_engine(char c) {
switch (c) {
...
case 'Z': engine = zero; break;
...
}
}
```
Now you can write music for your engine. Either make the first line of your music file to be `; Z` or pass it via CLI switch:
```
$ cat << EOF | ./1bitr
; Z
C-4
G-4
EOF
or
$ (echo "C-4"; echo "G-4") | ./1bitr -Z
```
## Default sound engines
Out of the box there are two sound engines: Zero and One. Engine Zero is mostly boring and useless, first column is note value, second is tempo.
Engine One is a bit more advanced. It can support 2 PWM channels, and click drums. The columns are:
```
; Note1 Note2 Drums FX
C-4 C-5 03 15
--- D-5 00 00
```
Notes are obvious. Drums are short click samples, values from 1 to 5 are allowed.
Effects are also rather simple. High nibble is effect ID, low nibble is effect value.
* 1x - set channel 1 duty cycle to X. 1f - 50%, 10 - 0%.
* 2x - same for channel 2.
* 3x - swipe frequency up at speex X.
* 4x - swipe frequency down at speed X.
* fx - set tempo to X.
Both sound engines are provided mosly as references to let you build your own.
## License
Code is distributed under MIT license. PRs are welcome! If you have written any interesting (or buzzing and noisy) music - feel free to share it using the issue tracker or twitter with #1bitr hashtag!