All Projects → evashort → chords

evashort / chords

Licence: MIT license
Text-based chord progression editor

Programming Languages

elm
856 projects
javascript
184084 projects - #8 most used programming language
HTML
75241 projects

Projects that are alternatives of or similar to chords

Tonal
A functional music theory library for Javascript
Stars: ✭ 2,156 (+8524%)
Mutual labels:  music-theory, chords, chord-progression
Comet
Web Synthesis on steroids
Stars: ✭ 18 (-28%)
Mutual labels:  web-audio, web-audio-api
ember-audio
An Ember addon that makes working with the Web Audio API super EZ.
Stars: ✭ 33 (+32%)
Mutual labels:  web-audio, web-audio-api
react-redux-webaudio
An event manager for the Web Audio API, integrated with react-redux.
Stars: ✭ 23 (-8%)
Mutual labels:  web-audio, web-audio-api
MusicTheory
Music Theory Library for Java and Android apps
Stars: ✭ 24 (-4%)
Mutual labels:  music-theory, chords
react-orchestra
A declarative toolbox to build interactive musical instruments on web and mobile.
Stars: ✭ 72 (+188%)
Mutual labels:  music-composition, music-theory
AudioMasher
Generative Audio Playground
Stars: ✭ 50 (+100%)
Mutual labels:  web-audio, web-audio-api
mahler.c
Western music theory library in C99
Stars: ✭ 13 (-48%)
Mutual labels:  music-theory, chords
ziffers
Numbered musical notation for composing algorithmic and generative melodies
Stars: ✭ 53 (+112%)
Mutual labels:  music-composition, music-theory
chords
A Kotlin multi-platform view library for displaying stringed instrument chord diagrams
Stars: ✭ 25 (+0%)
Mutual labels:  music-composition, chords
cycle-audio-graph
Audio graph driver for Cycle.js based on virtual-audio-graph
Stars: ✭ 19 (-24%)
Mutual labels:  web-audio, web-audio-api
blackswan-js
A library for expressive music composition in JavaScript.
Stars: ✭ 38 (+52%)
Mutual labels:  music-composition, web-audio
musyn
Write music together, in real time.
Stars: ✭ 20 (-20%)
Mutual labels:  music-composition, music-theory
NegativeHarmonizer
A python tool to invert the tonality (a.k.a negative harmony) of midi notation
Stars: ✭ 23 (-8%)
Mutual labels:  music-composition, music-theory
arpeggio
A chord naming app for guitar written in React.
Stars: ✭ 49 (+96%)
Mutual labels:  music-theory, chords
Javascriptmusic
Live coding music and synthesis in Javascript / AssemblyScript (WebAssembly)
Stars: ✭ 193 (+672%)
Mutual labels:  music-composition
gensound
Pythonic audio processing and generation framework
Stars: ✭ 69 (+176%)
Mutual labels:  music-composition
Handel
a small procedural programming language for writting songs in browser
Stars: ✭ 185 (+640%)
Mutual labels:  music-composition
Scalacollider
A Scala sound synthesis library based on SuperCollider. Mirror of https://git.iem.at/sciss/ScalaCollider
Stars: ✭ 174 (+596%)
Mutual labels:  music-composition
extendable-media-recorder
An extendable drop-in replacement for the native MediaRecorder.
Stars: ✭ 123 (+392%)
Mutual labels:  web-audio

Chords

Text-based chord progression editor

Type chord names in a textbox to create a sequence of play buttons that you can use like an instrument.

Try it in your browser: https://evashort.com/chords/

chordsite.slack.com is the Slack channel for discussing this project.

Follow this link for a Slack invite.

Current features

  • Chords in textbox are colored to match play buttons
  • Play chords as arpeggio, strum pattern, continuous pad, or basic strum
  • Queue up a second chord to play in the next measure
  • Select a key signature to transpose the entire chord progression
  • Save progressions in URL to bookmark or share them
  • Adjustable tempo
  • Playable circle of 5ths
  • 7th, 9th, and 13th chords
  • Table showing all chords in key
  • View recently played chords to capture improvised sequences
  • On-screen piano keyboard that displays the most recently played chord
  • Search for chords by selecting piano keys
  • Option to save settings in local storage
  • Tutorial for new users

Planned features

  • Option to input chords as roman numerals
  • Tap to set tempo
  • Syntax to set duration of each chord
  • Chord duration saved in "Recently played" view
  • Export progression as MIDI
  • Buttons to play entire line of progression
  • View different Greek modes in chord table
  • 7th chords displayed within circle of 5ths, with show/hide option

Possible features

  • More arpeggio styles
  • Mobile-friendly interface
  • Suggestions for next chord in progression
  • Support for selected slash chords
  • Show chords on musical staff
  • Show guitar chord diagrams
  • Somehow indicate which notes are in the current key signature
  • Allow focusing chords using arrow keys

Color choices

The chord colors basically follow this scheme:

  • blue = tonic
  • red = dominant
  • green = subdominant

Chords are arranged in rainbow order as you move up the major scale by thirds. This way, triads that share two notes have neighboring colors.

Major and minor 7ths are colored by mixing the two triads they contain.

Diminished triads and chords that contain them are dark with white text.

The colors were chosen to be maximally saturated and close to the same lightness in the CIELAB color space. Since the red-green axis is missing for most people with color vision deficiency, the lightness varies to compensate, with green being lightest and red being darkest. The lightness was chosen to contrast with the text as required by WCAG 2.0.

Build steps

  1. Install Elm from http://elm-lang.org/

  2. From the project folder, run elm make src/Main.elm --output main.js

  3. Run elm reactor

  4. Go to the URL shown, most likely http://localhost:8000

  5. Click on index.html

IDE setup

  1. Install VS Code from https://code.visualstudio.com/

  2. Within VS Code, install the elm extension

  3. Install Node.js from https://nodejs.org/en/

  4. Use npm to install elm-live: https://github.com/architectcodes/elm-live

In .vscode/tasks.json, there is a build command to start elm-live from within VS Code. To run it, click Run Build Task... in the Tasks menu. You only have to do this once at the beginning of each session. Once elm-live is running, it will recompile the project every time you save a file. Your changes should appear immediately at the URL displayed by elm-live, most likely http://localhost:8000/

Implementation details

On the JS side, I use the Web Audio API to create a new chain of audio nodes for each note that is played. A sawtooth oscillator feeds into a gain node and then a lowpass filter, both of which decrease over time. There is a loop that disconnects the filter nodes so they can be garbage-collected.

On the Elm side, when you click a chord play button, I generate a list of AudioChange objects, such as AddNote { t : Float, f : Float } or MuteAllNotes. Then I encode them with a custom JSON encoder and send them through a port to JS. So the entire arpeggio is sent to the Web Audio API as soon as you click the button. In order for Elm to schedule the notes at the right time, I had to write a native module called AudioTime to access the audio clock.

Elm also sets "alarms", which are times when the UI needs to be updated. The loop in audio.js notifies Elm when an alarm has passed.

In order to programmatically replace text in the textarea without erasing the undo history, we secretly create a new textarea for every replacement. If the textarea receives a ctrl+z key press and the text doesn't change within 5ms, we assume that the user is trying to undo the programmatic change and we restore the old textarea. Same goes for redo. In Chrome and Edge, pressing ctrl+z can also affect the hidden textareas so we have to detect and counteract that. This is all handled on the JS side in theater.js, with an Elm interface in Theater.elm.

Design principles

Keep it flat flat flat

Refactor code when it becomes hard to manage, not when it becomes repetitive. Refactoring for the sake of code re-use tends to introduce extra abstraction layers which can hide opportunities for more meaningful refactors. The same is true of refactors that attempt to increase encapsulation.

Simple is better than pure

It's usually a bad idea to write extra code that smooths over an ugly hack for the sake of "correctness". Expect new features to introduce rough edges to the code base. If you let ugly code sit for a while, you'll often find a better solution while working on a different feature.

Always be open to removing features

The most important refactors start by questioning the utility of a feature you always thought was essential. This project was essentially dead for two months because the code got too complicated to maintain. I was able to bring it back by removing the ability to invert chords, a feature that had been baked into the design from the beginning.

Accept no glitches

As users, we don't always notice how much mental energy we spend compensating for interfaces that are slightly unpredictable. We develop a lot of unconscious behaviors like double-checking that a certain element has focus. This program is meant to act like an extension of the user's brain as they reason about chords, so it's very important to fix any glitches that might sap their mental energy.

The UI should be normal

Use standard controls like checkboxes, buttons, and drop-down menus. Don't style them with custom CSS. Yes, I know broke this rule by making fancy Mac-inspired radio buttons. Each UI element should have an explicit text description that's always visible so users know what it does at a glance. Don't hide things to save space unless absolutely necessary.

Strong opinions loosely held

Keep the UI simple by not overwhelming the user with choices. This means having an opinion about everything. If a user wants something to be customizable, see if you can accommodate their use case by changing your opinion instead.

Variable names

Prefer single-word variable names that refer to concrete objects in the real world. Use a thesaurus to spark your creativity but forego the long words. Take advantage of metaphors to name multiple related variables. For example, a 1D list containing multiple rows of data separated with a delimiter is called a train, and each row of data is called a car.

Fail loudly

It's not always practical to rely on Elm's guarantee of no runtime errors. For example, you might let y = modBy 12 x and then assume that y < 12. Or you add an item to a list and then assume that the list is not empty. Make these assumptions explicit by calling Debug.todo if they fail and printing some useful information.

Code style

I don't have strong opinions about code style and formatting; I'm just doing what works for me. I'd like to start using elm-format but I'm afraid it will ruin the commit history.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].