underscoreio/compose

Name: compose

Owner: Underscore

Description: Compositional music composition using Scala, SuperCollider, and Web Audio.

Created: 2015-01-26 15:54:41.0

Updated: 2018-04-05 21:55:30.0

Pushed: 2017-08-08 18:12:48.0

Homepage:

Size: 1547

Language: Scala

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

Compose

A compositional music composition library.

Copyright 2015-2016 Dave Gurnell. Licensed Apache 2.

Build Status Coverage status Maven Central Join the chat at https://gitter.im/underscoreio/scala

Overview

Compose is a library for writing songs using functional programming. It is split into a number of subprojects:

You can read more about Compose on the Underscore blog.

Compose is cross-built for the JVM and ScalaJS. The JVM player uses ScalaCollider and Supercollider to play songs using a synthesizer (a sine wave by default). The ScalaJS player uses the web audio API to play songs using samples.

Running a Quick Demo

On the JVM:

  1. Install SuperCollider 3.7+

  2. Set the environment variable SC_HOME to point to Content/Resources inside your SuperCollider directory:

    rt SC_HOME=/path/to/SuperCollider.app/Content/Resources
    
  3. Run sbt demoJVM/run

In Javascript:

  1. Compile the JS version with sbt demoJS/fastOptJS
  2. .

Using Compose as a Library

If you're working on the JVM, you can add Compose to your SBT build as follows:

aryDependencies ++= Seq(
o.underscore" %% "compose-core"     % "<<VERSION>>",
o.underscore" %% "compose-player"   % "<<VERSION>>",
o.underscore" %% "compose-examples" % "<<VERSION>>"

If you're working in ScalaJS, use the following settings instead:

aryDependencies ++= Seq(
o.underscore" %%% "compose-core"     % "<<VERSION>>",
o.underscore" %%% "compose-player"   % "<<VERSION>>",
o.underscore" %%% "compose-examples" % "<<VERSION>>"

Once you've added Compose to your build, you can write songs as follows:

rt compose.core._

song =
te(Pitch.C3, Duration.Quarter) ~
te(Pitch.E3, Duration.Quarter) ~
te(Pitch.G3, Duration.Quarter) ~
te(Pitch.G3, Duration.Whole)

There are numerous shortcuts and conversions to make this code easier to write. Check out the examples for inspiration.

You can play your song on the JVM as follows:

rt compose.player._
rt scala.concurrent.Await
rt scala.concurrent.ExecutionContext.Implicits.global
rt scala.concurrent.duration.{ Duration => Dur }

reate a player:
aColliderPlayer.withPlayer(4) { player: ScalaColliderPlayer =>

 Start the song playing:
l playing: Future[ScalaColliderPlayer.State] =
player.play(song, Tempo(180))

 Wait for the song to finish:
ait.result(playing, Dur.Inf)


On ScalaJS, the code looks like the following:

rt compose.player._
rt scala.concurrent.Await
rt scala.concurrent.duration.{ Duration => Dur }
rt scalajs.concurrent.JSExecutionContext.Implicits.queue

reate a player:
player: WebAudioPlayer = new WebAudioPlayer()

tart the song playing:
playing: Future[WebAudioPlayer.State] =
ayer.play(song, Tempo(180))

ait for the song to finish:
t.result(playing, Dur.Inf)

That's all. If you have any questions, please ask on Gitter. Happy composing!

Sample Credits

The samples in the samples directory are sourced from the following places:


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.