Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2.0.0-SNAPSHOT] Useful semantic headers and refactored track normalization #22

Merged
merged 52 commits into from
Oct 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
a764f7e
:recycle: :wrench: :microscope: :checkered_flag: Renamed lowest-beat …
slurmulon Sep 25, 2020
59e55b2
:scroll: :wrench: :sparkles: :checkered_flag: Made init symbol non-ca…
slurmulon Sep 25, 2020
ebdc796
:microscope: :recycle: :checkered_flag: Updated bach.ast-test suite t…
slurmulon Sep 25, 2020
f283106
:microscope: :recycle: :checkered_flag: Removed superfluous :init key…
slurmulon Sep 25, 2020
28d6e7a
:sparkles: Removed unused variable in bach.track/get-pulse-beat
slurmulon Sep 25, 2020
6def24f
:sparkles: Simplified scaled-pulse-beat slightly in bach.track/get-ms…
slurmulon Sep 25, 2020
a906e3e
:microscope: :recycle: :bug: :construction: Working through correctio…
slurmulon Sep 25, 2020
320dee7
:recycle: :microscope: :construction: Work towards refactoring ms-per…
slurmulon Sep 26, 2020
056732f
:bulb: :scroll: Great resource on music time calcs
slurmulon Sep 26, 2020
49f32f8
:art: :wrench: :construction: Introduced ms-per-unit header for easie…
slurmulon Sep 26, 2020
1497f2d
:sparkles: :recycle: Cleanup around bach.track/get-ms-per-beat refactor
slurmulon Sep 26, 2020
d0ba3f2
:microscope: :recycle: :construction: :ghost: Updated ms-per-beat and…
slurmulon Sep 26, 2020
bd1d712
:microscope: :sparkles: Removed pointless beat unit spec in bach.trac…
slurmulon Sep 26, 2020
be07920
:recycle: :sparkles: :checkered_flag: Broke out get-normalized-ms-per…
slurmulon Sep 26, 2020
293b073
:scroll: :sparkles: Improved clarity of docstring in get-pulse-beat
slurmulon Sep 26, 2020
58b2fcf
:scroll: :wrench: :checkered_flag: Differentiate between int and floa…
slurmulon Sep 29, 2020
cecb9e4
:recycle: :construction: Work towards adding more useful semantic hea…
slurmulon Sep 29, 2020
0a7de06
[2.0.0-SH] :vhs: :wrench: :recycle: Updated bach.cli to use renamed b…
slurmulon Sep 29, 2020
d5baa63
[2.0.0-SH] :recycle: :sparkles: :construction: Minor dev refactor cle…
slurmulon Sep 29, 2020
6821261
[2.0.0-SNAP] :recycle: :bug: :microscope: :checkered_flag: Created ba…
slurmulon Sep 29, 2020
0b6d5e2
[2.0.0-SNAP] :art: :scroll: Created bach.data/hiccup-to-vector method…
slurmulon Sep 29, 2020
bd32b02
[2.0.0-SNAP] :recycle: :wrench: :checkered_flag: Used bach.data/hiccu…
slurmulon Sep 29, 2020
5306ead
[2.0.0-SNAP] :wrench: :recycle: :microscope: :checkered_flag: Ensure …
slurmulon Sep 29, 2020
812163a
[2.0.0-SNAP] :recycle: :sparkles: Dev cleanup in bach.track
slurmulon Sep 30, 2020
c86fabb
[2.0.0-SNAP] :microscope: :sparkles: :construction: Cleaned up bach.t…
slurmulon Sep 30, 2020
4c5067e
[2.0.0-SNAP] :microscope: :bug: Updated/fixed bach.composition-test f…
slurmulon Sep 30, 2020
8511e04
[2.0.0-SNAP] :sparkles: Lint fixes
slurmulon Sep 30, 2020
18987b9
[2.0.0-SNAP] :scroll: :sparkles: Minor improvements to docstrings in …
slurmulon Sep 30, 2020
66f3398
[2.0.0-SNAP] :scroll: :sparkles: :construction: Updated examples, imp…
slurmulon Sep 30, 2020
e0f7459
[2.0.0-SNAP] :scroll: :sparkles: More clarity and interface consisten…
slurmulon Sep 30, 2020
9cf8331
[2.0.0-SNAP] :recycle: :wrench: :microscope: :checkered_flag: Renamed…
slurmulon Sep 30, 2020
1fee382
[2.0.0-SNAP] :scroll: :recycle: :sparkles: Improved clarity of more d…
slurmulon Sep 30, 2020
8284628
[2.0.0-SNAP] :scroll: :bug: Fixed typo in bach.track/normalize-durati…
slurmulon Sep 30, 2020
14bb4ef
[2.0.0-SNAP] :recycle: :scroll: :sparkles: Improved organization of m…
slurmulon Sep 30, 2020
d686e1f
[2.0.0-SNAP] :sparkles: Lint fixes in bach.track
slurmulon Sep 30, 2020
670e302
[2.0.0-SNAP] :scroll: :wrench: :recycle: :microscope: :checkered_flag…
slurmulon Sep 30, 2020
7130986
[2.0.0-SNAP] :grammar: :sparkles: Post-refactor cleanup in grammar (g…
slurmulon Sep 30, 2020
9c89c41
[2.0.0-SNAP] :scroll: :wrench: :sparkles: Improved examples for durat…
slurmulon Sep 30, 2020
3a72b32
[2.0.0-SNAP] :recycle: :bug: :checkered_flag: Ensured that value of n…
slurmulon Sep 30, 2020
336827c
:bulb: Useful reference links on music and rhythm calculations
slurmulon Sep 30, 2020
63631b0
[2.0.0-SNAP] :recycle: :wrench: :bug: :sparkles: Added beat-units-per…
slurmulon Oct 1, 2020
85c7293
[2.0.0-SNAP] :microscope: :scroll: :wrench: Added tests for allowed a…
slurmulon Oct 1, 2020
fade47b
[2.0.0-SNAP] :scroll: :bug: :checkered_flag: Corrected minor issue wi…
slurmulon Oct 1, 2020
b4572d1
[2.0.0-SNAP] :microscope: :performing_arts: :bug: Updated fixtures fo…
slurmulon Oct 1, 2020
7d4312c
[2.0.0-SNAP] :package: :wrench: Updated project version to 2.0.0-SNAP…
slurmulon Oct 1, 2020
5319806
[2.0.0-SNAP] :recycle: :sparkles: Post-refactor dev cleanp in bach.track
slurmulon Oct 1, 2020
7e947a8
[2.0.0-SNAP] :recycle: :scroll: :bug: Fixed minor typo in bach.track …
slurmulon Oct 1, 2020
094819f
[2.0.0-SNAP] :recycle: :scroll: :sparkles: Slightly improved readabil…
slurmulon Oct 1, 2020
f272346
[2.0.0-SNAP] :scroll: :sparkles: Cleaned up whitespace in grammar.bnf
slurmulon Oct 1, 2020
2178164
[2.0.0-SNAP] :microscope: Added more disallowed characters to bach.as…
slurmulon Oct 2, 2020
602b1c6
[2.0.0-SNAP] :art: :sparkles: Added beat-unit and pulse-beat alias me…
slurmulon Oct 2, 2020
742d3f3
[2.0.0-SNAP] :scroll: :bug: Fixed typo in Repl example code in README
slurmulon Oct 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions LEARNING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Learning & Help

## Music

- Time Calculations in Music: http://moz.ac.at/sem/lehre/lib/cdp/cdpr5/html/timechart.htm
- https://sites.uci.edu/camp2014/2014/05/19/its-about-time
- https://music.stackexchange.com/a/24141

## General
- http://xahlee.info/clojure/clojure_instaparse.html
- http://xahlee.info/clojure/clojure_instaparse_output_format.html
Expand Down
228 changes: 173 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
- [What](#what)
- [Goals](#goals)
- [Design](#design)
- [Example](#example)
- [Examples](#examples)
- [Install](#install)
- [Setup](#setup)
- [Testing](#testing)
Expand Down Expand Up @@ -48,19 +48,20 @@

`bach` is a semantic music notation designed to be both human and computer friendly.

Although its primary domain is music, `bach` enables the synchronization of rhythmic timelines with just about anything.

The project is pre-alpha and is not should **not** be considered stable for production use.

## Goals

- Native support for semantic music constructs such as chords and scales
- Easily support semantic music constructs such as chords and scales
- Seamless synchronization with associated data by minimizing the complexities around timing
- Allow for alternative real-time representations of music (e.g. visual instead of just audio)
- Seamless synchronization with associated audio data by minimizing the complexities around timing
- Easy to read for both humans and computers
- Easy to translate from sheet music
- Small learning curve
- Highly productive
- Trivial to interpret compiled output. Writing `bach` engines should be easy!
- Keeps your definitions DRY

## Design

Expand All @@ -70,22 +71,23 @@ This module, by itself, can only parse and compile plaintext `bach` data into [`

`bach.json` is a JSON micro-format that makes it trivial for `bach` engines to sequentially process a `bach` music track and synchronize it in real-time with audio.

## Example
## Examples

The following `bach` track represents the scale progression of a blues song:
For the sake of brevity, the examples found in this document all represent short and repeatable loops of music.

```
@Audio = 'http://api.madhax.io/track/q2IBRPmNq9/audio/mp3'
@Title = 'Jimi Style 12-Bar-Blues Backing Track in A'
@Instrument = 'guitar'
@Time = 4|4
### Intro

The following `bach` track represents a loopable scale progression for a blues song:

```bach
@Meter = 4|4
@Tempo = 42

:A = Scale('A3 minorpentatonic')
:D = Scale('D3 minorpentatonic')
:E = Scale('E3 minorpentatonic')

:Track = [
!Play [
1 -> :A
1 -> :D
2 -> :A
Expand All @@ -95,36 +97,141 @@ The following `bach` track represents the scale progression of a blues song:
1 -> :D
2 -> :A
]

!Play :Track
```

and is interpreted like so:

1. Scale `:A`, or `A3 minorpentatonic`, will be played for `1` measure, then
1. Scale `:D`, or `D3 minorpentatonic`, will be played for `1` measure, then
1. Scale `:A` will be played for `2` measures, then
1. ...
1. ... and so on

To find a list of every reserved construct supported by `bach` (such as `Note`, `Chord`, etc.), please refer to the ["Constructs"](https://github.com/slurmulon/bach#constructs) section.

### Basic

```bach
@Meter = 4|4
@Tempo = 44

:B = Chord('Bm')
:E = Chord('Em')
:F = Chord('F#m7')

!Play [
4 -> {
Scale('B minor')
:B
}
2 -> :E
2 -> :B
2 -> :F
2 -> :B
]
```

```bach
@Meter = 4|4
@Tempo = 169

!Play [
7/8 -> {
Scale('A aeolian')
Chord('F')
}
1 -> Chord('G')
2 + (1/8) -> Chord('Am')
]
```

```bach
@Meter = 4|4
@Tempo = 130

!Play [
3/8 -> {
Scale('G aeolian')
Chord('Gmin')
}
5/8 -> Chord('Eb')
3/8 -> Chord('Cmin7')
5/8 -> Chord('Bb')
]
```

### Advanced

#### Compound meters

```bach
@Meter = 12|8
@Tempo = 150

!Play [
12/8 -> {
Scale('A minor')
Chord('A')
}
12/8 -> Chord('A7')
12/8 -> Chord('D7')
12/8 -> Chord('D#7')

6/8 -> Chord('A')
6/8 -> Chord('F#m7')

6/8 -> Chord('Bm7')
6/8 -> Chord('E7')

6/8 -> Chord('A7')
6/8 -> Chord('D7')
]
```

To find a list of every construct supported by `bach` (such as `Note`, `Chord`, etc.), please refer to the ["Constructs"](https://github.com/slurmulon/bach#constructs) section.
#### Mixed meters

```bach
@Meter = 5|8
@Tempo = 150

!Play [
3/8 -> {
Scale('D dorian')
Chord('Dm9')
}
2/8 -> Chord('Am9')
]
```

```bach
@Meter = 3|4
@Tempo = 100

!Play [
6/4 -> {
Scale('C# phrygian')
Chord('C#m')
}
6/4 -> Chord('Dmaj7')
]
```

## Install

### Leinengen/Boot

`[bach "1.0.0-SNAPSHOT"]`
`[bach "2.0.0-SNAPSHOT"]`

### Gradle

`compile "bach:bach:1.0.0-SNAPSHOT"`
`compile "bach:bach:2.0.0-SNAPSHOT"`

### Maven

```
```xml
<dependency>
<groupId>bach</groupId>
<artifactId>bach</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>2.0.0-SNAPSHOT</version>
</dependency>
```

Expand Down Expand Up @@ -161,7 +268,7 @@ $ lein bin
Then you can execute the resulting binary like so:

```sh
$ target/default/bach-1.0.0-SNAPSHOT -i /path/to/track.bach compile
$ target/default/bach-2.0.0-SNAPSHOT -i /path/to/track.bach compile
```

The executable currently supports the following actions:
Expand All @@ -174,11 +281,22 @@ The executable currently supports the following actions:

```clojure
(ns my.namespace
(:require [bach.ast :refer [parse]]
[bach.track :refer [compile-track]]))
(:require [bach.track :refer [compose]]))

; Parses, optimizes and compiles bach data into an interpretable hash-map
(compose "!Play [1 -> Chord('A'), 1 -> Chord('C')]")
```

### Repl

```sh
$ lein repl
```

```clojure
(use 'bach.track :reload)

; parses and compiles raw bach data into an interpretable hash-map
(compile-track (parse "!Play [1 -> Chord('A'), 1 -> Chord('C')]"))
(compose "!Play [1 -> Chord('A'), 1 -> Chord('C')]")
```

## Documentation
Expand Down Expand Up @@ -215,40 +333,39 @@ The duration that a `Beat` is played for is specified using the tuple symbol, `-

#### Nesting

`Sets` or `Lists` defined in other `Sets` (i.e. nested `Sets`) may be defined without a duration.
Nesting functionality is limited by design, as it helps keep high-level interpretation as linear and simple as possible.

```
{
[
<duration> -> <element>
<duration> -> <element>
],
[
<duration> -> <element>
<duration> -> <element>
]
}
```
The rules are simple:

- `Lists` may contain `Sets`
- `Lists` may **not** contain other `Lists`
- `Sets` may **not** contain `Sets` or `Lists`

As a result, `Lists` **cannot** be nested in another `Collection` at _any_ level.

#### Durations

The value of a `Beat`'s `<duration>` can be:
The value of a `Beat`'s `<duration>` can be an integer, a fraction, or a mathematical expression composed of either.

```
1 = Whole note (or one entire measure in 4|4)
1 = Whole note (or one entire measure when `@Meter = 4|4`)
1/2 = Half note
1/4 = Quarter note
1/8 = Eighth note
1/16 = Sixteenth note
...

1/512 = Minimum duration
1024 = Maximum duration

2 + (1/2) = Two and a half whole notes
2 * (6/8) = Two and a half measures when `@Meter = 6|8`
```

To adhere with music theory, durations are strictly based on **common time** (`4|4`).
To adhere with music theory, durations are strictly based on **common time** (`@Meter = 4|4`).

This means that `1` always means 4 quarter notes, and only equates with a full measure when the number of beats in a measure is 4 (as in `4|4`, `3|4`, `5|4`, etc.).
This means that, in your definitions, `1` always means 4 quarter notes, and only equates with a full measure when the number of beats in a measure is 4 (as in `4|4`, `3|4`, `5|4`, etc.).

The examples in the remainder of this section assume common time, since this is the default when a `@Time` header is not provided.
The examples in the remainder of this section assume common time, since this is the default when a `@Meter` header is not provided.

##### Examples

Expand Down Expand Up @@ -289,7 +406,7 @@ is the same as:
This is usefeul for specifying more complicated rhythms, like those seen in jazz.

```
:Mutliple = [
:PartA = [
1/2 -> Chord('D2min7')
1+1/2 -> Chord('E2maj7')
1+1/2 -> Chord('C2maj7')
Expand Down Expand Up @@ -381,9 +498,9 @@ Optional header information, including the **tempo** and **time signature**, is
Headers outside of those defined in the [documentation](#headers-1) are allowed and can be interpreted freely by the end user, just like `X-` headers in HTTP. The value of custom headers can be of any [primitive type](#primitives).

```
@Title = 'My bach track'
@Time = 4|4
@Meter = 4|4
@Tempo = 90
@Title = 'My bach track'
@Tags = ['test', 'lullaby']
@Custom = 'so special'

Expand Down Expand Up @@ -427,8 +544,13 @@ Only one `!Play` definition is allowed per track file.

### Headers

- **`Tempo`** (integer, beats per minute)
- **`Time`** (meter, time signature. ex: `6|8`, `4|4`)
#### Reserved

- **`Tempo`** (number, beats per minute)
- **`Meter`** (meter, time signature. ex: `6|8`, `4|4`)

#### Useful

- `Key` (string, key signature)
- `Audio` (url)
- `Instrument` (string, arbitrary)
Expand All @@ -450,7 +572,7 @@ Only one `!Play` definition is allowed per track file.

- `'foo'` or `"bar"` = string
- `123` or `4.5` = number
- `#000000` = color
- `#000000` or `#fff` = color

## Related

Expand Down Expand Up @@ -480,10 +602,6 @@ Contributions are always welcome. Simply fork, make your changes and then create
- [ ] Expandable / destructured scales and chords (i.e. `[... 1/4 -> Scale('C2')]`)
- [ ] Application of collection variables (i.e. dereference and flatten value into surrounding list)
- [ ] Allow user to define sections of a track that should loop forever
- [ ] Allow track linking with Hypermedia
- [ ] Linkable sections with unique namespaces so that end users may bookmark and/or track progress, or specify areas to loop
- [X] Hide Chord or Scale (so it's only functionally relevant and not highlighted to the user)
- [x] Arbitrary classification of notes (i.e. `Note('C2', class: "blue")`)
- [x] Arbitrary classification of elements (i.e. `Note('C2', class: "blue")`)
- [x] Chord voicings/inversions (i.e. `Chord('C2maj7', inversion: 1)`)
- [x] Traids (root, 1st, 2nd)
- [ ] Sort out complexities around `Beats` in nested `List`s (i.e. should nested `Beats` / `Elements` be able to surpass their parents?)
2 changes: 1 addition & 1 deletion project.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(defproject bach "1.0.0-SNAPSHOT"
(defproject bach "2.0.0-SNAPSHOT"
:description "Semantic music notation"
:url "https://github.com/slurmulon/bach"
:license {:name "MIT"
Expand Down
Loading