• Stars
    star
    153
  • Rank 243,368 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Browser based music making application driving modular synths, samplers and effects using a tracker interface. Supports MIDI controllers and provides both local and Dropbox project storage.

efflux

MadeWithVueJs.com shield

What is it ?

Efflux is an application that allows users to create music inside their browser. Efflux is a tracker and follows conventions familiar to those who have used anything from Ultimate Soundtracker to Renoise. All sounds are oscillator (or wave table) based and can be routed through an effects signal path, making Efflux a modular synthesis environment, where the synths are driven by the tracker.

Feature list

  • Create custom waveforms for multiple synth instruments
  • Load and manipulate audio files into samples
  • Record samples on the fly using your device microphone / inputs
  • Tons of keyboard shortcuts to provide nice and easy arranging using cutting, copying and cloning of (sub)patterns
  • State history that allows undo / redo of your actions
  • Save songs locally to continue working on them later or export / import them between devices
  • Save your favourite instrument presets to be reused
  • Attach a MIDI controller and record them live during playback (Google Chrome only)
  • Use the Tiny Player to play back Efflux songs embedded in your website or in demos.

Sounds cool, but I don't want to build from source, I just want to tinker with this!!

Of course, this was made to allow for instant composition, so let's cut the chatter! You can use the application right now from your web browser by visiting this link.

The Issue Tracker is your point of contact

Bug reports, feature requests, questions and discussions are welcome on the GitHub Issue Tracker, please do not send e-mails through the development website. However, please search before posting to avoid duplicates, and limit to one issue per post.

Please vote on feature requests by using the Thumbs Up/Down reaction on the first post.

Project outline

All source code can be found in the ./src-folder. Efflux is written using Vue, with the audio engine fully written in TypeScript.

  • ./src/ contains all source code with main.js and efflux-application.vue being the application entry points
  • ./src/assets contains all used fonts and images
  • ./src/model contains factories and utilities to create and serialize an Efflux song (see "Efflux song model" below)
  • ./src/services contains a variety of services used to integrate hardware interaction within the application
  • ./src/workers contains all Workers (which will be inlined into the compiled output and loaded as Blobs)
  • ./src/utils contains utilities for common operations or to orchestrate batch changes

Additional folders:

  • ./design contains SVG icons that are combined into a webfont (currently done manually through Fontello)
  • ./fixtures can be filled with separate JSON files containing Song and Instrument data, these will be concatenated into a single file that can be requested via Ajax on the first application start to provide demo content (see fixtures-loader.js)

Application actors

The Vuex store is defined in ./src/store/ and its submodules in the ./src/store/modules/-folder. Each part of the application has its own module, these are:

  • editor-module used to keep track of user interactions when editing patterns
  • history-module used to keep track of song mutation history to provide undo/redo functionality
  • instrument-module provides a store to save, load and edit instruments presets
  • midi-module used to link MIDI hardware to the application (currently Google Chrome only)
  • selection-module used to keep track of selections made in the pattern editor
  • settings-module used to maintain persistent configurations
  • song-module provides a store to save, load and edit songs

Efflux song model

The model of an Efflux song consists of the following actors (created via their respective factories):

  • Song
  • Patterns
  • Events
  • Instruments
  • Modules

A song contains a list of EffluxPatterns. A Pattern contains a list of channels (one for each available track) and a descriptor for the amount of steps the pattern contains (e.g. 16, 32, 64, etc.).

Each channel inside a pattern contains EffluxAudioEvents. These describe an action that should happen at a given step within a patterns channel. These can be note on/note off instructions or module parameter automations, or both. Each event references an Instrument that it will operate on (as not all events within a single pattern channel necessarily reference the same instrument to allow for more complex compositions).

As hinted above, a song also has Instruments. There are an equal amount of instruments available as there are tracks (the pattern channels). By default each channel references its own instruments. As the instruments in Efflux are synthesizers, each Instrument has a list of InstrumentOscillators which can be individually tuned and configured for playback.

Instruments also reference InstrumentModules. Each of these modules is basically an effects processor. Each instrument can have its output routed through multiple processors before its output is mixed into the master channel (by the AudioService).

All model types are generated through their respected FACTORIES. The factory should be able to create a new instance of the model type, as well as be able to assemble an instance from a serialized version. SERIALIZERS are separate files (to minimize file size of the Tiny player that should only be able to assemble (deserialize) serialized songs).

Efflux song model and Vuex

In Vuex, the song is stored inside its own Vuex store module "song-module.js". The editors bind directly to this reactive model, but for audio playback, an additional Object structure (e.g. EffluxAudioEvent.seq) is used. This separates the data aspect (maintained by the Vuex store mutations) from the audio rendering.

The history module provides custom methods for saving and restoring individual actions for specific sections of a song. While Vuex makes it easy to simply save an entire song upon each mutation, this will consume a lot (!) of memory fast. Which brings us to:

State history

Mutations can be registered in state history (Vuex history-module.js) in order to provide undo and redo of operations. In order to prevent storing a lot of changes of the same property (for instance when dragging a slider), the storage of a new state is deferred through a queue. This is why history states are enqueued by propertyName:

When enqueuing a new state while there is an existing one enqueued for the same property name, the first state is updated so its redo will match that of the newest state, the undo remaining unchanged. The second state will not be added to the queue.

It is good to understand that the undo/redo for an action should be considered separate from the Vue component that is triggering the transaction, the reason being that the component can be unmounted at the moment the history state is changed (and the component is no longer active).

That's why undo/redo handlers should either work on variables in a local scope, or on the Vuex store when mutating store properties. When relying on store state and getters, be sure to cache their values in the local scope to avoid conflicts (for instance in below example we cache selectedInstrument as it is used by the undo/redo methods to update a specific instrument. selectedInstrument can change during the application lifetime before the undo/redo handler fires which would otherwise lead to the wrong instrument being updated.

update( propertyName: string, newValue: any ): void {
    // cache the existing values of the property value we are about to mutate...
    const existingValue = this.getterForExistingValue;
    // ...and the instrument index that is used to identify the instrument containing the property
    const instrumentIndex = this.selectedInstrument;
    const store: Store<EffluxState> = this.$store;
    // define the method that will mutate the existing value to given newValue
    const commit = (): void => store.commit( "updateInstrument", { instrumentIndex, prop: propertyName, value: newValue });
    // and perform the mutation directly
    commit();
    // now define and enqueue undo/redo handlers to reverse and redo the commit mutation for given propertyName
    enqueueState( propertyName, {
        undo(): void {
            store.commit( "updateInstrument", { instrumentIndex, prop: propertyName, value: existingValue });
        },
        redo(): void {
            commit();
        },
    });
}

Audio rendering

The synthesizer itself renders its output by use of the Web Audio API's OscillatorNodes and PeriodicWave. All of this logic is determined by noteOn and noteOff events (similar to the MIDI spec) that is handled by the AudioService. The routing of audio paths, connecting of nodes and effect modules, recording, etc. is handled by the same service, see the ./services/audio/-folder.

When in doubt of how the audio output relates to the visual interface, remember that the Vuex song model defines what it should sound like (as in: defines the properties of the instruments) while the AudioService takes care of the actual sound rendering, outside of Vue.

Wiki

For more in-depth topics, you can consult the Wiki on GitHub.

Build instructions

You will need Node.js in order to run the build scripts and resolve the dependencies.

To build Efflux, first resolve all dependencies using NPM:

npm install

Generate the combined fixtures JSON files by running the following command (note: this only needs to be executed once or when new files are added / modified in the fixtures folder)

npm run fixtures

After which a development mode can be started (which conveniently opens your browser and points it to the correct location at http://localhost:5173) using the following NPM command:

npm run dev

A minified and transpiled production build can be created using the following command:

npm run build

After which the build output is available in the ./dist/-folder.

Unit testing

Unit tests are run via Jest. You can run the tests by using:

npm run test

Unit tests go in the ./tests-folder. The file name for a unit test should equal the file it is testing, but contain the .spec-suffix, e.g. functions.js will have a test file functions.spec.js.

Roadmap

Efflux is considered complete, though every now and then new features are added.

Future considerations for the code are migrating the Vue 2 code to Vue 3. To facilitate this, first the Vuex modules must be migrated to Pinia. There is no rush as Vue 2 is more than performant enough.

More Repositories

1

MWEngine

Audio engine and DSP library for Android, written in C++ providing low latency performance within a musical context, while providing a Java/Kotlin API. Supports both OpenSL and AAudio.
C++
252
star
2

molecular-music-generator

Application that generates musical compositions from algorithmically generated patterns, based on work by Duncan Lockerby.
Java
93
star
3

bitmappery

Browser based non-destructive photo editor with layering, masking, customizable brushes and cloud storage integration for all your web based working.
TypeScript
92
star
4

fogpad

A VST reverb effect in which the reflections can be frozen, filtered, pitch shifted and ultimately disintegrated.
C++
79
star
5

regrader

VST delay plugin where the repeats degrade in resolution
C++
75
star
6

VSTSID

VST plugin version of the WebSID Commodore 64 synthesizer
C++
61
star
7

kosm

Kosm for Android source code
Java
33
star
8

transformant

VST plugin that acts as a multi channel formant filter
C++
29
star
9

homecorrupter

VST plugin that reduces sampling rate, bit depth and playback speed on-the-fly
C++
26
star
10

darvaza

Darvaza is a multichannel audio gate with a twist : whenever the gate closes on your input signal, you get a perversion of your source spat back at you.
C++
22
star
11

vst-plugin-boilerplate

Basic template to build cross platform VST plugins using the Steinberg SDK, ready to start implementing your custom DSP.
C++
20
star
12

zCanvas

JavaScript library for interacting with HTML5 Canvas drawables as if they were separate animatable, interactive objects, mobile friendly and excellent as a lightweight game rendering engine.
JavaScript
19
star
13

rechoir

VST delay plugin where the repeats are pitch shifted in time to harmonize with the input signal
C++
16
star
14

zMIDI

Small JavaScript library providing an easy interface to work with Web MIDI, translating messages to notes.
JavaScript
16
star
15

tuning-spork

Browser based guitar scale and chord visualizer with multiple string and custom tuning support
Vue
15
star
16

molecular-music-generator-web

Web application that generates musical compositions from algorithmically generated patterns, based on work by Duncan Lockerby.
TypeScript
15
star
17

slocum-tracker

JavaScript based tracker application that exports compositions into assembly code for Paul Slocums Sequencer Kit for Atari 2600
JavaScript
10
star
18

zThreader

JavaScript "threading" library for maintaining application responsiveness during heavy operations!
TypeScript
5
star
19

nodejs-aws-lambda-boilerplate

Boilerplate code necessary to create a Node.js based AWS Lambda service which can also run on a local server
JavaScript
4
star
20

rts

An isometric real time strategy game that runs in your browser
TypeScript
4
star
21

weltkriegsimulator

Vertical scrolling shoot 'em up in the browser, using the zCanvas rendering lib. This is intended as a "bullet hell" game and is aimed more to showcase how to use zCanvas for game development.
JavaScript
2
star
22

js-image-processors

Experimental photo processing algorithms in JavaScript
JavaScript
1
star
23

web-app-boilerplate

Boilerplate configuration to create a web application using ES2018 (Babel), SASS, ready to use test framework and bundled by Webpack
JavaScript
1
star
24

soundcloud-iframe-analytics

Easily tracks visitor interaction on embedded SoundCloud content in Google Analytics
JavaScript
1
star
25

drunk-dragon-vs-the-drag-queens

Browser based adventure game set within a generative world in which drag queens are on the run from the Drunk Dragon during an endless escape from daylight (!)
JavaScript
1
star
26

igorski-as3-lib

ActionScript3 library of generic and not-so generic functions and classes
ActionScript
1
star