Skip to content

shard520/circle-composer-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Circle Composer

View the site here.

Contents


Description

The Circle Composer is a rhythm sequencer, designed to allow beginners and experienced musicians to explore rhythm. Using a series of circles which display the main beats and subdivisions in a bar, users can toggle each circle to programme a rhythm, then play that rhythm against a sound marking the pulse beats. The rhythm can be shifted backwards or forwards by one circle at a time by using the shift buttons.


Docs

Documentation has been written using JSDoc and can be viewed here. This is updated with each build so will always contain documentation for everything on the main branch.


Design

The app has been refactored from the initial version and is inspired by this tutorial project, it uses MVC architecture with OOP, and a version of the publisher/subscriber pattern to handle UI events.


Dependencies

There are no main dependencies. Dev dependencies are just Parcel and JSDoc, along with the necessary packages added by Parcel.


Features

The core functionality of the app revolves around the way it uses the Web Audio API. Rather than using the default methods like play which are available when using new Audio(url), the audioObj is initialised with a url, then a reference to the Audio Context is passed as an argument to createAudio(ctx), this method asynchronously fetches the data, storing it in an array buffer before decoding it, and creating and storing a gain node. The play method can then be called with a time parameter which defaults to the current time. Instead of being promised based, this play method creates a buffer source node each time it is called which is ideal for the nature of the app playing short samples in quick succession, preventing errors related to uncaught promises or when trying to pause and reset the time before playing a single audio object.

Timing is handled by a scheduler function adapted from this artice. Instead of using setTimeout() or setInterval() to queue playback, the scheduler is called at an interval set with a config variable. Each time the scheduler is called, it checks to see if the next note is due. When a note is due, it queues it then updates the display and sets the time the next note is due. The combination of a short scheduler interval combined with a longer lookahead time allows for overlap which prevents timing issues which can arise when the callback in the native JS timers are delayed by other tasks on the main thread. This also allows seamless changes to the tempo and sequence to be made whilst the sequence is playing.

while (state.nextNoteTime < state.ctx.currentTime + SCHEDULER_LOOKAHEAD) {
  controlSequence(state.nextNoteTime);

  circlesView.updateCurrentDisplay(state.currentNote);

  controlSetNextNote();
}

License

Code is licensed under the MIT License

License: MIT