A music composition library for Clojure and Clojurescript.

Related tags

leipzig
Overview

Leipzig

Build Status

A composition library for Clojure and Clojurescript by @ctford.

Use

Include it as a dependency in your project.clj, along with Overtone:

[overtone "0.9.1"]
[leipzig "0.10.0"]

Leiningen template

There is a Leiningen template that creates a simple Leipzig project, ready to run.

Get started

Leipzig models music as a sequence of notes, each of which is a map. They are ordered by :time:

[{:time 0
  :pitch 67
  :duration 2
  :part :melody}
 {:time 2
  :pitch 71
  :duration 2
  :part :melody}]

When using Leipzig, it's helpful to keep this model of notes in mind. Leipzig's functions are convenient ways of manipulating this basic structure, but there's nothing to stop you from building your own.

You can create a melody with the phrase function. Here's a simple melody:

(require '[leipzig.melody :refer [all bpm is phrase tempo then times where with]])

(def melody
         ; Row,  row,  row   your  boat
  (phrase [3/3   3/3   2/3   1/3   3/3]
          [  0     0     0     1     2]))

The first argument to phrase is a sequence of durations. The second is a sequence of pitches. phrase builds a sequence of notes which we can transform with sequence functions, either from Leipzig or ones from Clojure's core libraries.

To play a melody, first define an arrangement. play-note is a multimethod that dispatches on the :part key of each note, so you can easily define an instrument responsible for playing notes of each part. Then, put the sequence of notes into a particular key and tempo and pass them along to play:

(require '[overtone.live :as overtone]
         '[leipzig.live :as live]
         '[leipzig.scale :as scale])

(overtone/definst beep [freq 440 dur 1.0]
  (-> freq
      overtone/saw
      (* (overtone/env-gen (overtone/perc 0.05 dur) :action overtone/FREE))))

(defmethod live/play-note :default [{midi :pitch seconds :duration}]
  (-> midi overtone/midi->hz (beep seconds)))

(->>
  melody
  (tempo (bpm 90))
  (where :pitch (comp scale/C scale/major))
  live/play)

There's nothing magic about where. It just applies a function to a particular key of each note, like update-in for sequences.

Let's define two other parts to go with the original melody:

(def reply "The second bar of the melody."
         ; Gent -ly  down the stream
  (phrase [2/3  1/3  2/3  1/3  6/3]
          [  2    1    2    3    4]))

(def bass "A bass part to accompany the melody."
  (->> (phrase [1  1 2]
               [0 -3 0])
       (all :part :bass)))

(defmethod live/play-note :bass [{midi :pitch}]
  ; Halving the frequency drops the note an octave.
  (-> midi overtone/midi->hz (/ 2) (beep 0.5)))

You can then put multiple series of notes together:

(->>
  bass
  (then (with bass melody))
  (then (with bass melody reply))
  (then (times 2 bass))
  (tempo (bpm 90))
  (where :pitch (comp scale/C scale/major))
  live/play)

Namespaces

Leipzig features a number of namespaces, each containing functions pertaining to a particular area of composition.

leipzig.melody

This namespace contains the core functions for creating and manipulating melodies. In particular:

  • phrase creates a melody from a sequence of durations and a sequence of pitches.
  • where applies a function to a specified key of each note in a melody.

For example:

(->> (phrase [3/3 3/3 2/3 1/3 3/3] [0 0 0 1 2])
     (where :time inc))

leipzig.live

Here are functions to send your melodies to Overtone:

  • play-note is a multimethod that dispatches on the :part a note has.
  • play plays the notes.
  • jam loops the notes, reloading the var each time.
  • stop stops all running melodies.

For example:

(defmethod live/play-note :melody [{midi :pitch}]
  (some-> midi overtone/midi->hz beep))

(def boring-scale
  (->> (phrase (repeat 1) (range 8))
       (all :part :melody)
       (where :pitch (comp C major))))

(jam (var boring-scale))
; Edits to boring-scale will be played each time we go back round the loop.

leipzig.scale

This namespace contains functions for placing melodies within musical scales. In particular:

  • major and minor are functions that place a pitch within a relative scale.
  • A, B, C etc are functions that take a relative pitch, and place it in a specific absolute key.

For example:

(->> (phrase (repeat 1) (range 8))
     (where :pitch (comp C major)))

leipzig.chord

The phrase function accepts chords as well as simple pitches. This namespace provides simple ways to manipulate them:

  • triad is the tonic, which can be manipulated to form other chords.
  • root scales the chord up to the specified root.
  • inversion inverts the chord, leaving the root where it is.

For example, a fourth chord, then the second inversion of the fifth:

(phrase
  [4 4]
  [(-> triad (root 3))
   (-> triad (inversion 2) (root 4))])

leipzig.temperament

This namespace translates midi pitches into frequencies. Overtone's midi->hz will usually do just fine, but if you want to experiment with more exotic temperaments, there are plenty here.

In particular:

  • equal is equivalent to midi->hz and translates frequencies into pitches like a piano is tuned.
  • just uses pure ratios, and more closely models how singers interpret intervals into frequencies.

For example:

(->> (phrase (repeat 1) (range 8))
     (where :pitch (comp just C major)))

Advanced use

In addition to simple pitches, phrase can take maps representing chords or nils:

(require '[leipzig.chord :as chord])

(def chords "Off-beat chords."
  (->> (phrase (repeat 1/2)
               [nil chord/triad
                nil (-> chord/seventh (chord/root 4) (chord/inversion 1) (dissoc :v))
                nil chord/triad
                nil chord/triad])
       (all :part :chords)))

The maps generate a note for each value in the map - the keys are used only to enable chord-transforming functions such as root and inversion.

The nils generate notes without pitches, representing rests. This is convenient, because it allows melodies to have a duration extending beyond their last audible note. However, the play-note implementations and where invocations must be prepared to handle this, e.g. by using when and where's variation wherever:

(require '[leipzig.melody :refer [wherever]]
         '[leipzig.scale :refer [lower]])

(defmethod live/play-note :chords [{midi :pitch}]
  (when midi (-> midi overtone/midi->hz beep)))

(->>
  (times 2 chords)
  (wherever :pitch, :pitch lower)
  (with (->> melody (then reply)))
  (tempo (bpm 90))
  (where :pitch (comp scale/C scale/major))
  live/play)

Clojurescript

Leipzig supports Clojurescript for all of its namespaces save leipzig.live. The live namespace depends directly on Overtone, so it cannot be used in the browser. However the rest of Leipzig can be used so long as an alternative synthesis engine is present like the Web Audio API. Klangmeister is a good example of this.

Examples

See Row, row, row your boat or whelmed for examples.

In Leipzig from scratch, I demonstrate how to create a piece from lein new onwards.

Leipzig came out of a talk I gave called Functional Composition, where I explain basic music theory using Overtone and Clojure.

API

API documentation, generated by Codox.

Design

Leipzig is designed to play nicely with Clojure's standard sequence functions. Therefore, Leipzig's functions for transforming notes all take the sequence as a final argument so that they can be threaded with the ->> macro:

(->>
  (phrase (repeat 1) (cycle [0 2 4]))
  (take 24)
  (filter #(-> % :time even?)))

These sequence functions all exhibit "closure" i.e. their result is the same shape as their input. That allows them to be used and combined very flexibly. where for example, can raise the pitch, set the part or put the notes into a particular tempo:

(->> notes (where :pitch inc))
(->> notes (where :time (bpm 90)))

Leipzig aims to be a library rather than a framework or environment. It uses simple Clojure datastructures and strives to be as open as possible. A new timing scheme, tuning or tempo can be mixed with Leipzig's other functions just as easily as the ones that come with the library.

Testing

To run the unit tests without having to start Overtone's Supercollider server:

lein midje leipzig.test.*

Issues

As pointed out by @clojens, leipzig.live imports overtone.live, which implicitly boots an internal Supercollider server and can cause problems for folks using 64 bit Windows.

Issues
  • [Feature Request] Velocity support

    [Feature Request] Velocity support

    Velocity is also an important part of music. It would be great if notes were represented like this:

    {:time 0
    :pitch 67
    :velocity 127
    :duration 2
    :part :melody}
    
    opened by kureta 9
  • how to implement retrograde?

    how to implement retrograde?

    I'm not sure if this is an issue or just my misunderstanding. I'm trying to implement a "retrograde" function that will reverse a melody. I think I should be able to do something along the lines of (->> the-phrase crab (simple the-phrase-length)), but that doesn't quite work. I hope you can set me straight here.

    Consider a simple example of a whole note followed by two half notes:

    > ((lc/simple (- 2 0.5)) (lc/crab (lm/phrase [1 0.5 0.5] [4 5 6])))
    ({:pitch 4, :duration 1, :time 1.5} 
     {:pitch 5, :duration 0.5, :time 0.5} 
     {:pitch 6, :duration 0.5, :time 0.0})
    

    That almost works. Note 6 & 5 start at 0 and 0.5, but Note 4 is at time 1.5? Shouldn't it be at time 1?

    I drew this out and it finally made sense to me. I think there is a missing step

    ;;  -2  -1   0   1   2
    ;; --|-+-|-+-|-+-|-+-|
    ;;           AaaaBbCc = start with whole note + 2 half-notes
    ;;    cCbBaaaA        = crab?  no...we don't play notes backwards
    ;;     CcBb  Aaaa     = actual crab result when notes actual durations
    ;;   CcBbAaaa         = a missing step: offset-each-by-duration
    ;;           CcBbAaaa = (simple 2) puts melody in proper location
    

    Do you agree there's an issue? Or is this just a misunderstanding on my part?

    Thanks in advance...

    --Roger

    opened by rogerallen 8
  • Full stop

    Full stop

    Was playing around with leipzig again this evening and found myself wanting a "full stop" helper.

    I noticed I can capture the play future and stop it like this:

    (def player (->> drums (times 4) play))
    (future-cancel player)
    

    But I get the feeling something like

    (leipzig.live/stop)
    

    that canceled all play futures could be handy if you happen to kick off a somewhat long sequence.

    opened by matschaffer 5
  • Support CLJS

    Support CLJS

    Leipzig's dependence on Overtone is very slim - at and now. If we provide equivalents for CLJS, then Leipzig should be able to support music in the browser, using web audio instead of Overtone synths.

    opened by ctford 5
  • Fix several typos in README.md

    Fix several typos in README.md

    opened by ethancrawford 2
  • [question] Stringed instruments?

    [question] Stringed instruments?

    Hi there, I am really digging this library but I am having a bit of a hard time using it with stringed instruments. I tried to write an example based on the overtone stringed synth examples here but it is not clear to me how I could express the chords in a more elegant way. Any ideas or suggestions?

    opened by baskeboler 2
  • README example needs another couple of imports

    README example needs another couple of imports

    I needed to add all and tempo to the list of imports from leipzig.melody when running the example code.

    opened by dfannius 1
  • Add `tempo` to `require` form in README.md example

    Add `tempo` to `require` form in README.md example

    tempo is used later in the example code. Add it to the require so that copy-pasting code from the README works.

    opened by bjackman 1
  • Is clojure /  clojurescript dep really needed?

    Is clojure / clojurescript dep really needed?

    When using Leipzig, I'm noticing that deps are rather old and include both Clojure and Clojurescript. Maybe they both could be a :provided dependency, so you don't get them when consuming the library?

    opened by l3nz 0
  • [question] syncing leipzig compositions with quil visuals

    [question] syncing leipzig compositions with quil visuals

    hello, I have been making some music with leipzig and I'm loving the library, but I would like to sync some live visuals to my music with quil. Is there a way to do this with leipzig?

    opened by nihilazo 4
  • Allow to pass note play scheduling function

    Allow to pass note play scheduling function

    The current implementation of leipzig/live uses overtone/at to schedule playing a note, but this works only with OSC events. In my use case I want to schedule MIDI out events which uses Java MIDI API. I'm doing some research about the best options, for now I'm using overtone.at-at/at-at with fixed thread pool.

    So in this PR I only make possible to pass own play-fn function to both leipzig.live/play and jam

    opened by pjagielski 1
  • Windows 64bit and overtone.live

    Windows 64bit and overtone.live

    Hi,

    Just to inform you, something I faced a bit earlier when trying to setup Overtone in LightTable on Windows (8) 64bit. Normally I run a ArchLinux setup in virtualbox guest on this machine but due to a cracking sound, I had to switch back to the host Win. The problem I faced was java.lang.NoClassDefFoundError: Could not initialize class com.sun.jna.NativeLong exceptions thrown and the solution was found in https://groups.google.com/forum/#!topic/overtone/orbm9ZEtZaE group.

    Basically what it boils down to, from what I understand, is that overtone.live can't be used/called in Windows 64bit. It is not just limited to LightTable, lein repl throws the same. Falling back to overtone.core and then using (boot-external-server) everything run smoothly though and, from what I read, seems to be the prefered method of dealing with this issue.

    Perhaps something to take into account for leipzig as I noticed you made use of it in leipzig.live and mention it in the how-to of the README file.

    opened by clojens 6
Owner
Chris Ford
Chris Ford
A beautiful cross platform Desktop Player for Google Play Music

Google Play Music™ Desktop Player Windows: MacOS / Linux: Run "Google Play Music" as a standalone desktop app. Never again will you have to hunt throu

Samuel Attard 8.5k Sep 12, 2021
Typographic Beat-Oriented Notation for music

tbon Typographic Beat-Oriented Notation for music Tbon aims to be the fastest way to enter pitches, rhythms, meter and dynamic levels from a computer

null 11 Jan 23, 2020
Music typeset with the Lilypond system

Intro (from long ago) This repo contains sheet music typeset with the Lilypond typesetter. The music chosen is in favour of cello music (mostly chambe

Enthusiastic about  the Cello 95 Sep 15, 2021
网易云音乐第三方

ieaseMusic Elegant NeteaseMusic desktop app, Rock with NeteaseMusic ?? Built by Electron, React, MobX, JSS API 由 Binaryify/NeteaseCloudMusicApi 提供。 Pr

null 8.6k Sep 22, 2021
A music programming language for musicians. :notes:

Installation | Docs | Changelog | Contributing composers chatting Alda is a text-based programming language for music composition. It allows you to co

Alda 4.7k Sep 15, 2021
OpenSheetMusicDisplay renders sheet music in MusicXML format in your web browser based on VexFlow. OSMD is brought to you by PhonicScore.com.

OpenSheetMusicDisplay (OSMD) A MusicXML renderer for the Browser opensheetmusicdisplay.org About OSMD • Demo • Key Features • Limitations • How to Use

Open Sheet Music Display 800 Sep 15, 2021
A language for music notation

Lydown is a language and compiler for creating music scores, parts and snippets. The lydown code is compiled to lilypond code and then compiled to PDF

Sharon Rosner 21 Apr 8, 2021
🎵 Music notation engraving library for MEI with MusicXML and Humdrum support and various toolkits (JavaScript, Python)

Verovio is a fast, portable and lightweight library for engraving Music Encoding Initiative (MEI) digital scores into SVG images. Verovio also contain

RISM Digital Center 426 Sep 22, 2021
A Music programming language. Translates source code into MIDI. Includes a player. Supports MIDI-Karaoke. Includes a MIDI analyzer.

Get Started | Features | Screenshots | Programming | CLI | Contribute | License Midica is an interpreter for a Music Programming Language. It translat

Jan Trukenmüller 47 Sep 17, 2021
Music player for deepin desktop environment.

deepin-music Deepin music is a local music player with beautiful design and simple functions developed by Deepin Technology. Dependencies Build depend

Wuhan Deepin Technology Co.,Ltd. 155 Sep 16, 2021
music library manager and MusicBrainz tagger

beets Beets is the media library management system for obsessive music geeks. The purpose of beets is to get your music collection right once and for

beetbox 10.4k Sep 15, 2021
Mopidy is an extensible music server written in Python

Mopidy Mopidy is an extensible music server written in Python. Mopidy plays music from local disk, Spotify, SoundCloud, Google Play Music, and more. Y

Mopidy 7.2k Sep 17, 2021
Frescobaldi LilyPond Editor

README for Frescobaldi Homepage: http://www.frescobaldi.org/ Main author: Wilbert Berendsen Frescobaldi is a LilyPond sheet music text editor. It aims

Frescobaldi 501 Sep 21, 2021
web based music sheet viewer (go, pdfjs) as a single binary

Digital Music Stand A simple cross-platform browser-based pdfjs-based viewer to display and search music sheets. A single binary including all assets.

Patrick Wieschollek 21 Aug 27, 2021
Streaming music player that finds free music for you

Desktop music player focused on streaming from free sources Links Official website Mastodon Twitter Support channel (Matrix): #nuclear:matrix.org Disc

null 6.8k Sep 17, 2021
The git repository of the advanced drum machine

Hydrogen drum machine Hydrogen is an advanced drum machine for GNU/Linux, Mac and Windows. It's main goal is to bring professional yet simple and intu

Hydrogen 702 Sep 15, 2021
MuseScore is an open source and free music notation software. For support, contribution, bug reports, visit MuseScore.org. Fork and make pull requests!

Music notation and composition software MuseScore is an open source and free music notation software. For support, contribution, and bug reports visit

MuseScore 6.3k Sep 24, 2021
Lilypond music preprocessor

Ripple - DRY for Lilypond Ripple is a small program that helps you generate scores and parts without repeating yourself, performing complex includes o

Sharon Rosner 21 Mar 24, 2020
Music player and music library manager for Linux, Windows, and macOS

Quod Libet: an audio library, manager & player Quod Libet is a cross-platform audio / music management program. It provides many ways to view your loc

Quod Libet 1k Sep 16, 2021