Giter Club home page Giter Club logo

alda's Introduction

alda logo

Installation | Docs | Changelog | Contributing

Join us on Slack!

Alda is a text-based programming language for music composition. It allows you to compose and play back music using only your text editor and the command line.

piano:
  o3
  g8 a b > c d e f+ g | a b > c d e f+ g4
  g8 f+ e d c < b a g | f+ e d c < b a g4
  << g1/>g/>g/b/>d/g

For more examples, see these example scores.

The language's design equally favors aesthetics, flexibility and ease of use.

(Why compose music this way instead of in a graphical sheet music notation program? See this blog post for a brief history and rationale.)

Features

  • Easy to understand, markup-like syntax.
  • Designed for musicians who don't know how to program, as well as programmers who don't know how to music.
  • A score is a text file that can be played using the alda command-line tool.
  • Interactive REPL lets you enter Alda code and hear the results in real time.
  • Supports writing music programmatically (for algorithmic composition, live coding, etc.)
  • Create MIDI music using any of the instruments in the General MIDI Sound Set

Planned

If you'd like to help, come on in -- the water's fine!

Installation

See the official website for instructions to install the latest release of Alda.

Demo

For an overview of available commands and options:

alda --help

To play a file containing Alda code:

alda play --file examples/bach_cello_suite_no_1.alda

To play arbitrary code at the command line:

alda play --code "piano: c6 d12 e6 g12~4"

To start an interactive Alda REPL session:

alda repl

Documentation

Alda's documentation can be found here.

Contributing

We'd love your help -- Pull Requests welcome!

For a top-level overview of things we're talking about and working on, check out the Alda GitHub Project board.

For more details on how you can contribute to Alda, see CONTRIBUTING.md.

Another way you can contribute is by sponsoring Dave in the future development of Alda.

Support, Discussion, Camaraderie

Slack: Joining the Alda Slack group is quick and painless. Come say hi!

Reddit: Subscribe to the /r/alda subreddit, where you can discuss all things Alda and share your Alda scores!

License

Copyright © 2012-2024 Dave Yarwood et al

Distributed under the Eclipse Public License version 2.0.

alda's People

Contributors

0atman avatar 1of12 avatar bbqbaron avatar benoid avatar crisptrutski avatar daveyarwood avatar elydpg avatar feldoh avatar fraglegs avatar freginold avatar ginglis13 avatar hemaolle avatar jeluard avatar jgerman avatar jgkamat avatar jtbeckha avatar kristories avatar kylewilk567 avatar micha avatar mrko777 avatar n-makim avatar nvitucci avatar percy16jackson avatar pomax avatar pulkitsharma07 avatar scowluga avatar tbuc avatar ulysseszh avatar waffle-iron avatar wmwragg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

alda's Issues

Plugin system

Why not have one piece of software that can serve as the Great Tree that supports all of these existing worlds?

I love the idea of Alda and I love this especially.

I understand this project is still very much a WIP, but a random sampling of issues has me wondering to what extent the syntax will support these "existing worlds".

The README says this:

Alda is designed in a way that equally favors aesthetics, flexibility and ease of use, with (eventual) support for the text-based creation of all manner of music: classical, popular, chiptune, electroacoustic, and more!

I'm a heavy Lilypond user, and while I acknowledge that its syntax can be a little arcane, it would be amazing if I could a) import my existing scores into Alda, and b) use the Lilypond syntax I've already learned to compose new scores.

Of course, not everyone will prefer Lilypond. Hence language modes. Perhaps Alda could support an optional language directive (defaulting to the Alda syntax when not specified) at the beginning of the source code (or specified as a flag on the CLI)?

Alda could use a better logo

You can see our current logo here: https://github.com/alda-lang

It's something I hacked together in GIMP late one night because I was tired of looking at the default org logo generated by GitHub.

What I would love, though, is for someone with better graphic design skills than I to come up with something more pleasing to the eye.

I'm thinking something that doesn't have the word "alda" on it. Maybe some kind of stylized "A"? The name Alda comes from the Quenya word for "tree," so something tree-related might be cool, but that's not a requirement.

Long comment syntax

#{ Long comments } don't quite work correctly -- they will always terminate prematurely at the first instance of #{ or } after the beginning of the comment -- which means nested comments don't work, nor will commenting out any block of code that includes } ({ ... } is a planned syntax for advanced rhythms, so this is something that could very well happen)

Need to tweak the way I've defined long comments in the grammar... for reference, see how long comments are handled in Instaparse examples.

Another thing to consider: is there a smarter and/or better-looking syntax for long comments than #{ this }? I'm not totally happy with #{ this }, in part because it reminds me of Ruby string interpolation instead of a long comment. For inspiration, this is how other languages handle comment syntax.

moar docs

So far we just have information about Alda the language (how the syntax works, etc.) in the wiki.

To add:

  • alda.lisp
  • alda.repl
  • alda.now
  • a landing page with links to the above topics

EDIT 9/24: Also, we should move everything definitive in the wiki to markdown files in a doc/ folder in the root of the project. (Planning documents can stay in the wiki)

Feature request: Set the key

It would be nice to be able to set the key (either by name or as a series of flatted/sharped notes) as an attribute and global attribute. I don't know Clojure well enough to quickly set up a pull request for this, but if I find time I might try my hand at it. In the meantime, I put this out there for anyone else working on it.

Clean up / refactor code

Notes:

  • I got pretty far implementing alda.lisp with the idea that attributes are stored in top-level dynamic vars like *octave*, *volume*, etc. I wrote an entire macro, defattribute, around this idea, and I even wrote things like *global-attributes* and *current-offset* using defattribute. But then, once I got to the point where I was ready to implement part, I realized that it would be much easier to implement if attributes were stored separately for each instrument. I've successfully adjusted everything so that this is working, and storing attributes on a per-instrument basis totally makes more sense. But, as a consequence of having initially written all the code with a different goal in mind, there are some things that seem messy. There are probably a bunch of things that could be refactored or generally cleaned up.
  • When converting to this new way of handling attributes, the system I ended up using was essentially, rename event functions like note to e.g. note*, and add an instrument parameter to said function; then, write a short function with the original name (e.g. note) which iterates through all the instruments in *current-instruments* and calls the asterix-version on each instrument. My initial thought was that it might be useful to have a standalone function available to do the thing on one particular instrument, but by the time I was done rewriting, I ended up only having used the asterix-versions within the bodies of the regular functions. So, could probably refactor this by writing a macro/fn that models this abstraction and then use it within each regular function and scrap the asterix-versions.
  • The get-attribute pattern that I ended up using seems messy. Before this rewrite, I was able to get the values I needed directly from dynamic vars, at any point, and the values would always be up-to-date. Now, instead of e.g. *volume*, you have to do something like (-> (*instruments* "piano") :volume). A more elegant solution might be to have defattribute also define a helper function with multiple arity that will either A) get an up-to-date value for a specific instrument, or B) if no argument is provided, uses the first instrument (usually the only one) it finds it *current-instruments*. Then we can get the same kind of brevity as before, we'll just be calling a function like (tempo°) or (tempo° "harmonica") instead of referring to a value stored in *tempo*. (ended up generating getter methods named like ($tempo))
  • I wrote some pretty awkward-looking macros for chord and voices - they could probably be simplified or made more elegant somehow. I may have under-used syntax quoted forms.
  • I've made use of pre-conditions in some places, and also done manual type-checking that looks particularly messy in the note* function. This could be refactored using core.match / defun. I also wonder if there are other places where pattern matching could help clean things up.

(MIDI) Slurs not quite working like they should

I assumed that setting (quant 100) would blend the notes together so that it sounds like one note, but in practice, if the 2 notes are the same pitch, then the second note fails to play at all. D'oh!! Setting (quant 99) sounds OK, but you can still definitely hear the space between the notes, and the slower the tempo, the more noticeable it is.

Of note, (quant 100) is fine for slurring together two notes of different pitches -- the problem is just for "slurs" between 2 of the same note, which really shouldn't be happening anyway, since by definition that would be a tie. So, what we should do is write in some logic that converts two slurred notes that are the same (e.g. c2~c4) into just one note with the sum of their durations (e.g. c2~4).

(Note: this might only be an issue in MIDI -- but, the fix I'm proposing should also be an improvement for non-MIDI music)

Implement advanced rhythms

Cram

I came up with this idea for representing advanced rhythms. I call it "cram" because you're basically cramming a bunch of notes inside of a set duration and dividing them up either evenly or according to a weight distribution.

(EDIT 9/7/15: @crisptrutski has a much better idea -- see comments below)
Desired syntax:

{ d+ c+ < b }2 

The above is one way to represent a quarter note triplet -- it's 3 notes crammed into the space of a half note. By default, each note inside the braces is equal in length.

Notes inside of "cram brackets" use a slightly different syntax than usual, in that you don't specify exact note durations like eighth, quarter, etc. Instead, you can (optionally) specify how much weight each crammed note gets, by adding *'s to the notes you want to be relatively longer than the others. This can get rather complicated, but here is an simple example:

{ c* d }4

The "c" has one *, and the "d" has none, and they are crammed into the space of a quarter note (4). By default, a note has no , which corresponds to a ratio of 1:1 (i.e. all notes are equal in length). With each * that you add, the first number of the ratio increases by one. So what this means is that in the example above, the "c" note (c) has a length ratio of 2:1, whereas the "d" note (d) is just 1:1 (technically 1:2, compared to the "c" note). Because the "c" note is twice as long as the "d" note, and the two notes are crammed into the space of a quarter note, the result is two "swung" eighths, or in other words, an eighth note triplet where the "c" occupies the first two notes, and the "d" occupies the third.

Perhaps an easier way to think about adding *'s to notes within cram brackets, is that with each * you add, it's like adding another note into the crammed group, only instead of a new note, you're repeating the note you *'d, and then tying them together.

It should be possible to include rests and chords inside of cram brackets, too.

Second/millisecond durations

Come up with some syntax for overriding the beat/tempo model and letting users define exact durations of notes in seconds and milliseconds. Could be as simple as c60s (a C lasting 60 seconds), d+500ms (a D# lasting 500 milliseconds), etc.

*Lispification intensifies*

Started on this in the moar-lisp branch. What we have happening on the master branch is only half lispified -- instaparse emits Hiccup, which is then manipulated as Hiccup data and then transformed into Clojure code. We can do one better by having instaparse immediately transform the Hiccup into Clojure code (this is working ✅ ), which can then be evaluated (this needs work ❌ ).

I'm having trouble writing a top-level macro (alda-score) that reorganizes the body of the Clojure code, which is a series of instrument calls, with an optional global-attributes form in the first position. The result should be a score form with a variable number of consolidated parts as args. alda-score's job is to assign parts to each of the instrument calls and consolidate repeated instrument calls into part forms, each containing the instrument name and instance number and all of the music-data for that instance consolidated into the one part. This is mostly working at this point, except that an internal function update-data returned by instrument-call is receiving two arguments for some reason. I also just realized that comp is not the right thing to use in order to apply each instrument-call in sequence to the working data (comp will do them in reverse order).

When I was debugging this yesterday with @micha, he brought up the idea of leveraging the power of vars (possibly within a Boot pod) to hold the working data when doing the work that alda-score needs to do. This might help to simplify the process of part consolidation, or at least make the code cleaner. I'm sure it is possible to get things working the way I'm currently doing it, but the way I'm approaching the problem might be overly complicated in light of the options I have available.

Another thought I had is that part consolidation doesn't necessarily need to happen. I could take Alda's algorithm for assigning a part (which is currently part of the update-data function returned by each instrument-call and make it a standalone function, which can then be called by the part function. So the syntax of parts would go from e.g. (part "violin" 1 (music-data ...)) to (part "violin" (music-data ...)) and the part function would figure out that it's instance 1, given the working data stored in some var that was initialized by the score function and modified by any preceding parts.

While we're at it, it would probably make sense to give each instrument its own unique ID (perhaps the instrument name and a random number) instead of representing an instance as a map of the instrument name to a number. The ID can be stored in a var, corresponding to an Instance record. There needs to be a way to find any existing instance records of a certain instrument (e.g. piano), so the part can know whether to append to an existing instance's music data or create a new instance.

Implement durations & timestamps

Pt. 1: Durations

Currently, a duration like 2.~4~8 (a dotted half note tied to a quarter note tied to an eighth note) parses as [:duration "2" "." "~" "4" "~" "8"] -- it just lists out the components of the duration.

  • Write a function which converts this to an actual number of beats, in the form of a decimal, e.g. 2.~4~8 => 3 beats + 1 beats + 0.5 beat = 3.5 beats
  • Write a function which takes a number of beats and a tempo and returns the actual duration in milliseconds.

Pt. 2: Timestamps

Once we are able to convert the duration of an event (e.g. a note) to milliseconds, we should be able to iterate through a sequence of musical events and assign timestamps to everything, where the timestamp of the first thing that happens is 0 milliseconds, and every subsequent event is given a timestamp equal to the timestamp of the event before it + the duration of the event before it.

NOTE: Chords, voices and markers are going to be special cases, but we'll cross that bridge when we get to it. I have the algorithm worked out in my head.

Maintaining GitHub streak on the road, Day 2

Offset

Alda places notes chronologically by assigning each note an offset. There are two types of offset: absolute and relative. Absolute offset expresses the number of ms from the beginning of the score. Relative offset expresses the number of ms after a marker.

Markers can be placed and referenced at any point during a score, and in any instrument part. e.g. %chorus will place a marker called "chorus" at the current offset, and then using @Chorus at any point will set the current offset to that of the "chorus" marker.

Chords

A chord is a collection of notes which all start at the same offset, i.e. they all start at the exact same time. In Alda, a chord is expressed as notes with slashes in between them: c/e/g

It's acceptable to have octave changes in between the notes of a chord, which allows for chords spanning multiple octaves: c/g/>c/e/g

The notes in a chord can all be different lengths, in which case, the next note event after the chord will happen after the shortest note in the chord. This makes it easy to have chords with shifting tones, e.g.: c1~1/>c/<e4 f g f e1 (also, note that, just like with sequential notes, each note duration becomes the default for all notes that follow - both C notes in this chord are 2 whole notes long).

Alda also allows you to use rests in a chord. Because the next note event after a chord will start after the shortest note/rest in the chord, this can be useful for writing melodies entwined with chords, e.g. c1/e/g/r4 b e g

Make note-length an accessible attribute

Currently in Alda syntax, the only way to change an instrument's default note duration is to write a note/rest with that duration. It would be nice to be able to explicitly set note length as an attribute change, i.e. (note-length 1~2..)

Pretty-print parser output

Currently when you do, e.g., boot parse --lisp -f test/examples/hello_world.alda, you get the output verbatim -- we should pretty-print it instead.

(I tried using pprint initially, but it didn't work, I think due to a bug with Boot... it's been a while though, possibly fixed now)

Rewrite voices

voices is currently a one-off thing, implemented as a macro that properly handles *current-offset*, shifting it back at the beginning of each voice, for each voice in the voice group. This works fine for one-off evaluation of voices, but not so well for the Alda REPL, which needs to allow for starting a voice group, then starting a voice, then adding some stuff to the voice, then starting a new voice, then adding some stuff to that voice, then finally ending the voice group once you use V0: or start a new instrument part -- all on separate lines entered into the REPL.

To do this, we can add top-level vars describing the state of the voices... maybe *current-voice*, which is nil when not in a voice group, or a voice number. Will probably also need to store the initial instrument snapshot(s) (which will include the initial offset) at the start of the voice group. Basically, we need to split out the current implementation of voices into discrete steps, which can be followed at their own pace during an Alda REPL session.

Maintaining GitHub streak on the road, Day 3

Voices

Voices provide a way to subdivide an instrument into its own separate parts, which play simultaneously. This can be useful for polyphonic instruments, that is, instruments that can play more than one note at a time, e.g. guitar, piano.

Example

V1: c d e f g1
V2: e f g a b1
V3: g a b > c d1

V0: c e g > c2.

Each voice is its own sequence of note events. The first note/rest in each voice starts at the same time, like the notes in a chord. Whereas a chord bumps forward the current offset by the shortest note duration in the chord, after a group of voices, the current offset is that of the longest voice in the group. V0: signals the end of a voice grouping and a return to using a single voice.

Write docs

TODO: document how Alda's syntax works, for the benefit of end users and contributors alike

MIDI volume / velocity

Need to implement volume of MIDI notes. The volume values are already coming through via the parser, the values just aren't being used for anything yet. Currently every note has a hard-coded velocity of 127.

TODO: use the volume of notes as the MIDI note velocity in alda.sound.midi/play-note!

I think volume changes (e.g. (volume: 90)) should change the velocity of MIDI notes. Actual MIDI volume changes are a less common thing, more for setting a track's overall volume relative to the other tracks. In Alda, this should be a separate attribute called something like track-volume.

(ref: MIDI volume vs. velocity)

It looks like volume can be set (per-channel) like this.

Maintaining GitHub streak on the road, Day 4

Scores/Parts

The top level of a piece of music written in Alda is the score. A score consists of any number of instrument parts, each of which have their own note events, which occur simultaneously.

Alda is designed to be flexible about how a score is organized. For the same piece of music, a composer can choose to write each instrument part's notes from beginning to end before moving on to the next instrument part (something like ex. 1), or alternate between the instrument parts, organizing the score by section rather than by part (ex. 2).

Ex. 1

trumpet: 
o4 c d e f g a b > c d e f g a b > c

trombone:
o3 e f g a b > c d e f g a b > c d e

Ex. 2

trumpet: o4 c d e f g a b > c
trombone: o3 e f g a b > c d e

trumpet: d e f g a b > c
trombone: f g a b > c d e

Under the hood, Alda processes a score sequentially, keeping track of information about each instrument, including the instrument's volume, tempo, duration, offset, and octave. The nice thing about this is that, when switching to another instrument and then switching back, you don't have to worry about changing the volume, tempo, octave, etc. back to what they were when you were last using the instrument - Alda keeps track of that for you.

Instrument groups

It's possible in Alda to use the same note events for multiple instruments at once by grouping them, e.g.:

trumpet/trombone: c d e f g f e d c

Keep in mind that Alda is still keeping track of each instrument's volume, tempo, octave, offset, etc. separately, which means it is up to the composer to ensure that the instruments are playing in sync, if that's what the composer wants. In ex. 3, the trumpet plays some repeated D notes at the start of the score, then an ascending D minor scale; the trombone also plays the D minor scale, however it starts at the beginning of the score, so it beats the trumpet to the punch. Ex. 4 shows a way to remedy this situation, in cases where the really want both instruments playing in unison. Ex. 5 shows another way to achieve the same effect using markers.

Ex. 3

trumpet: d d d d d d d d

# not in sync, trombone starts earlier
trumpet/trombone: d e f g a b- c d

Ex. 4

trumpet: d d d d d d d d
trombone: r1~1 # (rest for 8 beats) 

# in sync 
trumpet/trombone: d e f g a b- c d

Ex. 5

trumpet: 
d d d d d d d d %scaleTime

trumpet/trombone: 
@scaleTime d e f g a b- c d

Alda chooses not to force instrument parts to sync up when used as a group so that composers have the freedom to experiment with multiple instruments playing the same notes in different ways. For example, you can give the instruments different tempos and/or note durations and have them play the same notes:

Ex. 6

violin: (tempo 100)
viola: (tempo 112)
cello: (tempo 124)

violin/viola/cello: e f g e f g e f g e f g e f g

Maintaining GitHub streak on the road

Did a ton of work on Alda during flights from Portland -> Chicago -> RDU. No public Internet here at Chicago O'Hare, apparently. Will commit once I get home :)

CLI support for execution via existing process

Seems like the easiest solution to start-up latency is to support sending commands "server daemon" - which could just be the most recently launched repl. Perhaps flags like --existing or --port <number> could be added to any of the CLI commands.

It would also be nice if these arguments could be passively activated by a dotfile or environment variables.

Requires #43 I guess

Lispify Alda

Major props to Alan for bringing this up. I really like this idea.

At this point, we have a working parser that emits Hiccup. Instead of processing Hiccup programmatically, we should transform it into Clojure code and then eval it.

e.g., chord nodes become calls to the "chord" function with note arguments, each one a call to the "note" function with pitch and duration arguments, etc.

The purpose of the top level function, "score," can be to create audio data from its arguments, then the main program can decide what to do with that audio data (play it and discard it, output it to a file, etc.)

Implement attributes

I'm not sure yet how to go about doing this -- it depends on how they need to be supplied when we get to the "generating sound" part. I think Overtone might require that each note has its own a volume, panning, etc. attribute, so if that's the case, we could assign each and every note its own values for those attributes, by iterating through the sequence of musical events and keeping track of the "current" value of each attribute and changing it whenever an attribute change is encountered.

Attributes ending in exclamation points are global attributes -- anytime one is encountered (in any instrument's part), it alters the value of that attribute for all instruments, at that timestamp.

Turn off logging by default

Timbre logs a bunch of stuff at the DEBUG level, which is all visible out of the box when you clone this repo and start to play around with Alda. I put a little blurb in the README about how to turn this off, but it would be nice if it were off by default. I'm sure there is a way to do this with Timbre, just need to look for it.

Implement repeats, variables & modules

(None of these are yet defined in the grammar or implemented in the parser behavior.)

EDIT 9/30/15: See below for updated syntax ideas.

Repeats

Self-explanatory. e.g. c1(~1)x7 should expand to c1~1~1~1~1~1~1~1 at compile time.

Variables

Variables should work like they do in Lilypond. Any piece of code can be enclosed in brackets and defined as a variable, then called in the code any number of times, at any point in time.

Desired syntax:

# Defining a variable: 
riffA = [f8 f g+ a > c c d c <]
riffB = [b-8 b- > c+ d f f g f <]
riffC = [> c8 c d+ e g g a g < ]
riffD = [f8 f g+ a > c c d < b > | c c < b- b- a a g g]

# calling a variable
$riffA # expands to "f8 f g+ a > c c d c <"

# using variables + repeats
($riffA)x4 
($riffB)x2  ($riffA)x2
$riffC $riffB $riffD

# bonus: conglomerate variables into other variables!
rockinRiff = 
  [ ($riffA)x4 
    ($riffB)x2  ($riffA)x2
    $riffC $riffB $riffD    ] 

guitar/saxophone: 
    ($rockinRiff) x9999999

Modules

Take the variable concept and apply it to entire files.

For example, each instrument's part could be written in a separate file in the same directory as a main file, then in the main file (say, "score.alda"), you could write something like:

&clarinet.alda
&trombone.alda
&tuba.alda
&banjo.alda
&piano.alda
&drums.alda

and each of these statements would be replaced by the contents of each file at compile time.

This would be especially cool in that you could define custom instruments (e.g. custom synth instruments) as standalone files and then load them in as modules in any piece of music in which you'd like to use them.

NOTE: Modules might be a little tricky to implement and preserve line numbers for error reporting. Ideally we'd be able to report the line/column number and name of the file where the error occurred.

Website issues

One of the chord examples is:

o4 c1/e/g/>c4 < b a g | < g+1/b/>e

However, wouldn't this cause the lower C note to be a quarter note instead of a whole note?

git clone [email protected]:alda-lang/alda.git gives me an error

This:

Warning: Permanently added the RSA host key for IP address '192.30.252.129' to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.

I'm using Fedora 22 64 bits, with Boot installed doing
mv boot.sh boot && chmod a+x boot && sudo mv boot /usr/local/bin && boot -h

"this will take a few minutes" message when downloading FluidR3

It takes at least a few minutes to download the 125 MB FluidR3 soundfont (packaged as an optional Maven dependency). We already warn users in the README that this will take a while the first time they run Alda, but it would be better if we also print something out to the console like "Downloading FluidR3 MIDI soundfont. This will take a few minutes." Otherwise, users might wonder if the Maven download is stalling (when in fact, it just takes longer than the majority of Maven dependencies)

Implement pitches & octaves

Octaves

Octave numbers in Alda correspond (as they do in most other music programming languages) are based on scientific pitch notation.

Alda's syntax works like MML (and unlike standard musical notation) in that the octave of a note is not written as a part of the note, but as something that the parser keeps track of as it iterates through the notes in order of execution. The octave of a given note depends on the "current octave" at that chronological point in the score. If no initial octave is specified, default to octave 4 (the octave containing both middle C and A440). Each instrument keeps track of its own octave separately, and starts at octave 4 if no other octave is specified.

An octave change can be a specific octave number, octave down (<) or octave up (>). When a specific number is encountered, switch to that octave. When an octave down or up is encountered, decrement or increment the current octave.

Pitches

Pitches currently parse as strings like a, c+, f++, etc. The letter can have any number of pluses or minuses after it, and each one either augments or diminishes the pitch -- that is, it raises or lowers it by a half-step.

Overtone handles letter-name/MIDI/Hz conversion for musical notes really well, so we should employ the same techniques. Of note, we eventually want to allow using specific frequencies in Hz (via an alternate syntax), not just 12-tone equal temperament. So, in preparation for that, we should take care that our functions that handle pitches (such as augment and diminish) can handle any pitch in Hz, not just those belonging to equal temperament.

  • Write a function that iterates through a sequence of musical events and assigns exact pitches, in Hz, to each note. It should keep track of the octave as it goes along, adjusting the octave each time an octave change is encountered.

NOTE: We might need to validate that each pitch is within an acceptable range of Hz, in order to ensure that any note can be represented in MIDI format. We probably shouldn't allow negative Hz as that would involve time travel. Not sure about the upper limit, maybe nothing higher than 12543.9 (the highest MIDI note, G9). See this chart, and also note that C-1 or MIDI note 0 = about 8 Hz (they left MIDI notes 0-11 out of the chart because they're so low humans can't hear them, but I say we include these frequencies in Alda so at least mice and birds can enjoy them).

`boot play` task fails silently when given invalid code

$ boot play --code "PORKCHOP SANDWICHES"

$ boot parse --lisp --code "PORKCHOP SANDWICHES"
Parse error at line 1, column 10:
PORKCHOP SANDWICHES
         ^
Expected one of:
":"
"|"
"#"
"#{"
#"\s"
"\""
"/"

I took for granted that an instaparse failure does not throw an exception, it returns an instaparse failure object. The boot play task should check whether the result of parsing the score is an instaparse failure and log an error before exiting.

Improve/update command line argument parsing

I wrote the command-line parsing aspects in alda.core and alda.sound-generator in September 2013 using clojure.tools.cli 0.2.4. The state of command line argument parsing in Clojure has improved since then -- we should update the clojure.tools.cli dependency version and use the latest & greatest methods of parsing command line arguments.

Specifically, the function clojure.tools.cli/cli (which I used) is now deprecated and has been superseded by clojure.tools.cli/parse-opts.

Reference:
https://github.com/clojure/tools.cli

Desired syntax at this point:
https://github.com/daveyarwood/alda/wiki/Command-line-syntax

Java version problem on OS X

When I run alda repl, I get:

Exception in thread "main" java.lang.UnsupportedClassVersionError: boot/App : Unsupported major.minor version 51.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:637) at java.lang.ClassLoader.defineClass(ClassLoader.java:621) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) at java.net.URLClassLoader.access$000(URLClassLoader.java:58) at java.net.URLClassLoader$1.run(URLClassLoader.java:197) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

java -versionreports:
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-466.1-11M4716)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-466.1, mixed mode)

And in Preferences > Java > Update it says: "Java 8, update 60."

Error on Windows

C:\Users\*****\alda>boot alda play --file=test.alda
             clojure.lang.ExceptionInfo: java.lang.IllegalArgumentException: No such task (alda)
    data: {:file
           "C:\\Users\\*****\\AppData\\Local\\Temp\\boot.user5660940546126207748.clj",
           :line 7}
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: No such task (alda)
     java.lang.IllegalArgumentException: No such task (alda)
          boot.core/construct-tasks  core.clj:  672
                                ...
                 clojure.core/apply  core.clj:  630
                  boot.core/boot/fn  core.clj:  706
clojure.core/binding-conveyor-fn/fn  core.clj: 1916
                                ...

Apply default BOOT_JVM_OPTIONS (will fix heap space issues for some users)

Here's what I get when I run alda on OS X 10.10.5:

~|⇒ alda repl
2015-Sep-06 13:34:32 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.attribute...
2015-Sep-06 13:34:32 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.offset...
2015-Sep-06 13:34:32 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.global-attribute...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.marker...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.event...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.pitch...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.duration...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.model.instrument...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.attributes...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.events.note...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.events.rest...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.events.chord...
2015-Sep-06 13:34:33 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.events.voice...
2015-Sep-06 13:34:34 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.instruments.midi...
2015-Sep-06 13:34:35 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.score.part...
2015-Sep-06 13:34:35 -0700 UnknownHost DEBUG [alda.lisp] - Loading alda.lisp.score...

 █████╗ ██╗     ██████╗  █████╗
██╔══██╗██║     ██╔══██╗██╔══██╗
███████║██║     ██║  ██║███████║
██╔══██║██║     ██║  ██║██╔══██║
██║  ██║███████╗██████╔╝██║  ██║
╚═╝  ╚═╝╚══════╝╚═════╝ ╚═╝  ╚═╝

            v0.4.4
         repl session

Loading MIDI synth... 2015-Sep-06 13:34:36 -0700 UnknownHost DEBUG [alda.sound.midi] - Loading MIDI synth...
2015-Sep-06 13:34:36 -0700 UnknownHost DEBUG [alda.sound.midi] - Loading MIDI soundfont...
clojure.lang.ExceptionInfo: Java heap space
    data: {:file
           "/var/folders/_g/vjftnz6s2q36lcsmxzw3ypl80000gn/T/boot.user4692146052994996114.clj",
           :line 11}
java.lang.OutOfMemoryError: Java heap space
     com.sun.media.sound.SF2Soundbank.readSdtaChunk                 SF2Soundbank.java: 177
     com.sun.media.sound.SF2Soundbank.readSoundbank                 SF2Soundbank.java: 132
            com.sun.media.sound.SF2Soundbank.<init>                 SF2Soundbank.java: 113
com.sun.media.sound.SF2SoundbankReader.getSoundbank           SF2SoundbankReader.java:  58
           javax.sound.midi.MidiSystem.getSoundbank                   MidiSystem.java: 530
                                                ...
               midi.soundfont/load-all-instruments!                     soundfont.clj:  13
                   alda.sound.midi/open-midi-synth!                          midi.clj:  65
                             alda.sound/eval7701/fn                         sound.clj:  23
                                                ...
                                 alda.sound/set-up!                         sound.clj:  33
                                                ...
                              alda.repl/start-repl!                          repl.clj:  91
                               alda.cli/eval8100/fn                           cli.clj:  66
                                                ...
                                  alda.cli/delegate                           cli.clj:  91
                                     alda.cli/-main                           cli.clj: 105
                                                ...
                                 clojure.core/apply                          core.clj: 624
                                    boot.user/-main  boot.user4692146052994996114.clj:   9
                                                ...

Maintaining GitHub streak on the road, Day 1

Notes

Alda's syntax for notes is heavily inspired by MML.

Components

Octave

Western music theory divides pitches into repeating groups of 12 notes, e.g. (ascending) c c# d d# e f f# g g# a a# b (next octave) c c# d, etc. The combination of the letter pitch (e.g. C#) and the octave determines the frequency of the note in Hz. Octave is expressed as a number, typically between 1 and 7, corresponding to scientific notation. For example, middle C and A440 are both in octave 4, which is the default octave in Alda. Just like in MML, the octave is set separately from the notes themselves - i.e. it's not "attached to" or "part of" the note, rather, each note looks at the current octave in order to determine its pitch.

You can set the octave two ways:

o5 sets the octave to octave 5. Any integer can follow o.

< decreases current octave by 1. > increases current octave by 1.

Duration

Duration in Alda (as in MML) is expressed in note lengths from standard music notation, in number form. 4 is a quarter note, 2 is a half note, 1 is a whole note, etc.

Any number of dots can be added to a note duration, which has the same effect as in standard music notation - it essentially adds half of the note duration to the total duration of the note.

e.g.
2 = half note, 2 beats
2. = dotted half note, 3 beats (2 + 1)
2.. = double-dotted half note, 3-1/2 beats (2 + 1 + 1/2)

Note durations can also be added together using the tie syntax, . 44 = two quarter notes tied together, 2 beats total.

A special feature of Alda is that you can use non-standard numbers as note durations. For example, 6 is a note that lasts 1/6 of a measure in 4/4 time (in standard notation, there is no such thing as a "sixth note," but this note length would be expressed as one note in a quarter note triplet; in Alda, a "6th note" doesn't necessarily need to be part of a triplet, however, which raises interesting rhythmic possibilities).

Alda keeps track of both the current octave and the current default note duration as notes are processed sequentially in a score. Each time a note duration is specified, that duration becomes the new default note duration. Each note that follows, when no note duration is specified, will have the default note duration. At the beginning of each instrument part, the default octave is 4 and the default note duration is 4 (i.e. a quarter note, 1 beat).

Letter pitch

A note in Alda is expressed as a letter from a-g, any number of accidentals (optional), and a note duration (also optional).

Flats and sharps will decrease/increase the pitch by one half step, e.g. C + 1/2 step = C#. Flats and sharps are expressed in Alda as - and +, and you can have multiple sharps or multiple flats, or even combine them, if you'd like. e.g. c++ = C double-sharp = D.

Example

The following is a 1-octave B major scale, ascending and descending, starting in octave 4:

o4 b4 > c+8 d+ e f+ g+ a+ b4
a+ g+ f+ e d+ c+ < b2.

Rests

Rests work exactly like notes, except it's just the letter r (with an optional duration following the same rules as notes). When Alda encounters a rest, it waits for the duration of the rest before placing the next note. (Under the hood, it's just bumping forward the current offset.)

Refine and document Alda installation/usage on Windows

A large handful of people have noted experiencing problems installing and running Alda in a Windows environment. #47 is a good example of an error that at least 2 other people have noted running into.

Open questions:

  • Is it possible to run a standalone executable Boot script in Windows?

    The alda executable does start with #!/usr/bin/env boot. On OS X, I am able to run alda globally by making this file executable and copying it a directory in my $PATH. I am also able to run it by running boot ~/Code/alda/bin/alda. I can reproduce the "No such task (alda)" issue by cd-ing into ~/Code/alda/bin and trying to run boot alda, probably because Boot can't know if alda is supposed to be a task or a file. Clarifying that it's a file by running boot ./alda fixes it.

  • Can a Windows user simply copy the alda executable script into a directory in their path and be able to run alda from any directory?

    Subquestion: Does a file need to be a .exe in order to be added to the path?

  • Why doesn't running boot D:\path\to\alda (with boot.exe on the user's path) work?

    ... Does it work?

Would greatly appreciate any insight from Windows power users, or better yet, Windows users familiar with running Boot. I am a Windows n00b.

Write unit tests

Write tests for individual musical events and other features.

e.g., c4 should parse as [:note [:pitch "c"] [:duration "4"]]

What would be really cool is if we wrote generative tests using clojure.test.check -- define generators for notes, chords, etc. and test their general properties.

We could also use more examples of input files for testing purposes -- small excerpts from different pieces of music, or little original compositions.

alda broke my computer

first I saw this:

fiatjaf@mises ~ $ alda repl

boot: script file not found: build.boot
Perhaps /usr/local/bin/alda should have the .boot extension?

Usage: boot :strap
       boot [arg ...]
       boot <scriptfile.boot> [arg ...]

Create a minimal boot script: `boot :strap > build.boot`

then I ran boot :strap > build.boot and alda repl again.

the screen went black.

Implement quantization

In MML, you can "quantize" notes, which sets the actual length of the note regardless of the placement. This is effectively just setting the amount of space between notes. MML's formula is a little obtuse IMHO. I think a more intuitive way would be to take a value 0-100 and use that as the percentage of the note that is heard, i.e. 100% is slurred notes (no space between notes), 0% is a rest for the duration of the note. 90% is probably a good default.

TODO: come up with a syntax* and add it to the grammar, write a test alda score that uses quantization.

*Should probably just let it be an attribute called "quant," for use during attribute changes. This seems clearer than copying MML's q<number> syntax.

Add logging

It will probably be helpful for testing/debugging purposes to add logging for each event, attribute change, etc.

Smart buffering

Due to timing issues with queuing up the notes, we have to pass in a "lead-time" argument (1000 ms is the default, 3000 ms seems to work alright for longer scores). What would be ideal is if Alda determined dynamically how long to wait before starting the score, so all the user has to worry about is supplying Alda with a score to play.

With MIDI at least, there is also some guesswork in figuring out how long to wait before returning -- this is necessary because otherwise the MIDI synthesizer closes immediately after queuing up the notes. So I've written some code that figures out how long the score is and then waits for that amount of time plus 5000 ms. This seems to work OK, although it's slightly annoying if all you want to hear is one note, for example. What would be ideal is if the player exits once the score is done, plus ~1 second. (That's actually what I did initially, but it ended up needing a little extra buffer time to cover load time + the "lead-time" buffer to queue up the notes.) I wonder if there is some way we can have the player queue up an "OK, I'm done event" at the end to trigger the player to return?

How to run this on Windows

I just installed boot as suggested on Windows, not sure what else do I need to run this on Windows.

image

Any suggestions?

Thanks,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.