Contents

Alternate Implementations

Here’s some more demo songs from other systems

The core ideas of bitrhythm are transferable to other languages as well. At most all you need is a music loop and samples to get started.

Here’s a demo by SunVox’s author ?

An example in C with raylib

brew install raylib
cc ray.c  `pkg-config --libs --cflags raylib` -o ray
#include "raylib.h"
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void setTimeout(int milliseconds)
{
    // If milliseconds is less or equal to 0
    // will be simple return from function without throw error
    if (milliseconds <= 0) {
        fprintf(stderr, "Count milliseconds for timeout is less or equal to 0\n");
        return;
    }

    // a current time of milliseconds
    int milliseconds_since = clock() * 1000 / CLOCKS_PER_SEC;

    // needed count milliseconds of return from this timeout
    int end = milliseconds_since + milliseconds;

    // wait while until needed time comes
    do {
        milliseconds_since = clock() * 1000 / CLOCKS_PER_SEC;
    } while (milliseconds_since <= end);
}


int main(void)
{

    InitAudioDevice();      // Initialize audio device

    Sound fxWav = LoadSound("Music/Kick01.wav");
    Sound fxWav2 = LoadSound("Music/Clap01.wav");

    int bpm;
    printf("Enter bpm: ");
    scanf("%d", &bpm);
    float time_per_beat = (60.0 / bpm) * 4;
    int delay = (time_per_beat * 1000) / 16;
    printf("%d\n", delay);

    while(1) {

        int i;
        for (i = 1; i <= 16; i++) {
            if ((i == 1) || (i == 5) || (i == 9) ||  (i == 13)) {
                PlaySound(fxWav);
            }
            if ((i == 5) ||  (i == 13)) {
                PlaySound(fxWav2);
            }
            setTimeout(delay);
        }
    }


    UnloadSound(fxWav);     // Unload sound data
    UnloadSound(fxWav2);     // Unload sound data

    CloseAudioDevice();     // Close audio device


    return 0;
}

Elementary

Elementary is a javascript runtime - https://github.com/nick-thompson/elementary.

The following is a basic incomplete example that makes use of the sample. Need to update it to the latest Elementary version to simplify tick logic.

const el = require('@nick-thompson/elementary');

const kick02 = './Music/Kick01.wav';
const hh02 = './Music/HH02.wav';
const clap01 = './Music/Clap01.wav';

let voices = {
  '60': {gain: 1.0, gate: 0.0, path: kick02, key: 'v1'},
  '61': {gain: 1.0, gate: 0.0, path: hh02, key: 'v2'},
  '62': {gain: 0.6, gate: 0.0, path: clap01, key: 'v3'},
};

function updateVoiceState(e) {
  if (e && e.hasOwnProperty('type') && e.type === 'noteOn') {
    if (voices.hasOwnProperty(e.noteNumber)) {
      voices[e.noteNumber].gate = 1.0;
    }
  }

  if (e && e.hasOwnProperty('type') && e.type === 'noteOff') {
    if (voices.hasOwnProperty(e.noteNumber)) {
      voices[e.noteNumber].gate = 0.0;
    }
  }
}

function samplerVoice(voice) {
  let gate = el.const({key: voice.key, value: voice.gate});
  return el.mul(voice.gain, el.sample({path: voice.path}, gate));
}

elementary.core.on('load', function() {
        let i = 0;
        let step = 0;
        function function2() {
            step = i % 16;
            console.log(step)
            if (i % 4 == 0) {
              updateVoiceState({type: 'noteOn', noteNumber: '60'});
            } else {
              updateVoiceState({type: 'noteOff', noteNumber: '60'});
            }

            if ((i !== 0) && (i % 8 == 0)) {
              updateVoiceState({type: 'noteOn', noteNumber: '62'});
            } else {
              updateVoiceState({type: 'noteOff', noteNumber: '62'});
            }

            let out = el.add(Object.keys(voices).map(function(n) {
                return samplerVoice(voices[n]);
            }));

            let filtered = el.lowpass(1800, 1.414, out);
            elementary.core.render(filtered, filtered);
            i++;
        }
        setInterval(function2, 60000 / 120.0 / 2);
});