Reactronica

React audio components for making music in the browser

Introduction

React treats UI as a function of state. This library aims to treat music as a function of state, rendering sound instead of UI. Reactronica can play complex musical sequences with web synths, samples and audio effects.

Your own UI components live side by side with Reactronica, sharing the same state and elegantly kept in sync.

Uses ToneJS under the hood. Inspired by React Music.

Warning: Highly experimental. APIs will change.

Demos

Digital Audio Workstation

Early prototype of a browser based Digital Audio Workstation. Inspired by Ableton Live, Cubase and Logic Pro, this experiment comes complete with multi-track sequencing, browser synths, drums and web audio effects.

https://reactronica.com/daw

Reactronica Digital Audio Workstation demo!

Music chord/scale toolbox

Improve your understanding of music theory with this chord, scale and progression finder.

https://music-toolbox.now.sh

Music chord, scale and progression tools!

Install

$ npm install --save reactronica tone

Note: Use React version >= 16.8 as Hooks are used internally.

Template

To get started quickly with Create React App and Reactronica, just run the command below:

$ npx create-react-app my-app --template reactronica

Examples

Drum Pads

Have a hit a tap out a beat.

import { Song, Track, Instrument } from 'reactronica';
// Simplified Drum Pads
const DrumPads = () => {
const [notes, setNotes] = React.useState(null);
return (
<>
<button
onMouseDown={() => setNotes([{ name: 'C3' }])}
onMouseUp={() => setNotes(null)}
>
Kick
</button>
{/* ...other pads */}
{/* Reactronica Components */}
<Song>
<Track>
<Instrument
type="sampler"
notes={notes}
samples={{
C3: '/drums/kick.wav',
D3: '/drums/snare.wav',
E3: '/drums/hat.wav',
}}
onLoad={() => {
// Runs when samples are loaded
}}
/>
</Track>
</Song>
</>
);
};

Piano Roll

Classic piano roll step sequencer. Try editing the notes and come up with different chords and melodies.



1
2
3
4
5
6
7
8
import { Song, Track, Instrument } from 'reactronica';
// Simplified Piano Roll
const PianoRollExample = () => {
const [isPlaying, setIsPlaying] = useState(false);
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [steps, setSteps] = useState([
['C3', 'E3', 'A3'],
null,
['C3', 'E3', 'G3', 'B3'],
null,
['C3', 'F3', 'A3'],
null,
['D3', 'G3', 'B3'],
null,
]);
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Play' : 'Stop'}
</button>
<PianoRoll
currentStepIndex={currentStepIndex}
onClick={(steps) => setSteps(steps)}
/>
{/* Reactronica Components */}
<Song isPlaying={isPlaying}>
<Track
steps={steps}
// Callback triggers on every step
onStepPlay={(stepNotes, index) => {
setCurrentStepIndex(index);
}}
>
<Instrument type="polySynth" />
</Track>
</Song>
</>
);
};

Ukulele Tablature

Interactive tablature for ukulele. Have a play and try changing the notes while the song is playing. Arrow keys should work as well.



import { Song, Track, Instrument } from 'reactronica';
const UkuleleTab = () => {
const [tab, setTab] = React.useState(defaultTab);
const [isPlaying, setIsPlaying] = React.useState(false);
const [currentIndex, setCurrentIndex] = React.useState(0);
const steps = tabToSteps(tab);
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Stop' : 'Play'}
</button>
<Tab
tab={tab}
currentIndex={currentIndex}
onUpdate={(newTab) => {
setTab(newTab);
}}
/>
{/* Reactronica Components */}
<Song isPlaying={isPlaying} bpm={90}>
<Track
steps={steps}
subdivision={'8n'}
onStepPlay={(_, i) => {
setCurrentIndex(i);
}}
>
<Instrument
type="sampler"
samples={{
C4: `/ukulele/uke_060.wav`,
'C#4': `/ukulele/uke_061.wav`,
// ... D4 - A#5 samples
B5: `/ukulele/uke_083.wav`,
C6: `/ukulele/uke_084.wav`,
}}
/>
</Track>
</Song>
</>
);
};

Usage

import React from 'react';
import { Song, Track, Instrument, Effect } from 'reactronica';
const Example = () => {
return (
// Top level component must be the Song, with Tracks nested inside
<Song bpm={90} isPlaying={true}>
<Track
// Array of several types
steps={[
// Note in string format
'C3',
// Object with note and duration
{ name: 'C3', duration: 0.5 },
{ name: 'D3', duration: 0.5 },
// Array of strings for chords
['C3', 'G3'],
null,
null,
// Array of objects for chords
[
{ name: 'C3', duration: 0.5 },
{ name: 'G3', duration: 0.5 },
],
null,
]}
volume={80}
pan={0}
// Callback for every tick
onStepPlay={(step, index) => {
doSomething(step, index);
}}
>
<Instrument type="polySynth" />
{/* Add effects chain here */}
<Effect type="feedbackDelay" />
<Effect type="distortion" />
</Track>
<Track>
<Instrument
type="sampler"
samples={{
C3: 'path/to/kick.mp3',
D3: 'path/to/snare.mp3',
E3: 'path/to/hihat.mp3',
}}
// Add some notes here to play
notes={[{ name: 'C3' }]}
/>
</Track>
</Song>
);
};

Documentation

Song

This component wraps around all Reactronica components, providing top level control of the audio.

  • bpm number - Speed or pace of the song. Short for beats per minute.
  • isPlaying boolean - Whether the song is playing or not. Defaults to false.
  • volume number - Volume of entire song
  • isMuted boolean - Mute the whole song

Track

Tracks make up the layers of audio within a Song. Each individual Track has independent volume, pan, steps and effects.

  • volume number - Volume of track
  • pan number - Panning of track
  • mute boolean - Mute track
  • solo boolean - Only play this track, or other solo'd tracks
  • steps StepType[] - An array of steps to play. Can be string or { name: string, duration: number, velocity: number }.
  • onStepPlay function - Callback that runs on every step.

Instrument

Should be wrapped by a Track and becomes its audio source.

Props

  • type amSynth | duoSynth | fmSynth | membraneSynth | metalSynth | monoSynth | pluckSynth | sampler | synth - Instrument type
  • notes NoteType[] - An array of notes ({ name: string, velocity: number }) to trigger Instrument, useful for auditioning sounds or live performance.
  • samples object - Only for sampler instrument type. eg. { C3: '/path/to/file1.wav', D3: '/path/to/file2.wav' }
  • polyphony number - Maximum number of notes played at the same time. Only for some synth types.
  • oscillator { type: 'triangle' | 'sine' | 'square' } - A repeating waveform shape. Only for some synth types.
  • envelope { attack: number, decay: number, sustain: number, release: number }
  • onLoad function - Only for sampler instrument type. Gets called after all samples load

Effect

Audio effects such as feedbackDelay, distortion and freeverb. Add as children of Track, with multiple Effects allowed.

Props

  • type autoFilter | autoPanner | autoWah | bitCrusher | distortion | feedbackDelay | freeverb | panVol | tremolo - Effect type
  • wet number - How much the effect is mixed with the original source. 1 = 100%, 0 = none.