What is Relanote?
Relanote is a pure functional, statically-typed programming language designed specifically for describing music. Unlike traditional notation or MIDI programming, Relanote uses relative intervals as its foundation, making transposition, modulation, and musical transformations natural and effortless.
Why Relative Intervals?
Traditional music notation and most programming approaches use absolute pitches (C4, D4, E4...). This creates problems:
- Transposition requires rewriting - Moving a melody up a step means changing every note
- Modal thinking is awkward - Scale degrees are fundamental to music theory but secondary in absolute systems
- Patterns are obscured - A "I-IV-V progression" looks different in every key
Relanote solves these by making intervals first-class:
; Define a scale
scale Major = { R, M2, M3, P4, P5, M6, M7 }
; This melody works in ANY key
let melody = | <1> <3> <5> <3> <1> |
; Transform with builtins
let transformed = melody |> transpose P5
transformedWhy Relative Rhythm?
Traditional notation ties rhythm to absolute values (quarter notes, eighth notes...). Relanote uses relative rhythm within blocks:
scale Major = { R, M2, M3, P4, P5, M6, M7 }
; 4 notes = each is 1/4 of the block duration
let fast = | <1> <3> <5> <3> |
; 2 notes = each is 1/2 of the block duration
let slow = | <1> <5> |
; Both blocks take the same total time!
fast ++ slowThis approach brings the same benefits as relative pitch:
- Tempo-independent patterns - Double tempo without rewriting
- Natural feel - Think in beats and subdivisions, not milliseconds
- Composability - Combine blocks of different densities seamlessly
Functional Approach
Relanote embraces functional programming principles:
Immutability
Values never change. Transformations create new values:
scale Major = { R, M2, M3, P4, P5, M6, M7 }
let original = | <1> <2> <3> |
let reversed = original |> reverse ; original unchangedFirst-Class Functions
Functions are values. Pass them around, compose them:
let transform = transpose M3 >> reverse >> repeat 2
melody |> transformPure Functions
No side effects. Same input always produces same output:
let doubled = melody |> map (\n -> n + P8)Static Typing
Relanote catches errors before you hear them:
scale Major = { R, M2, M3, P4, P5, M6, M7 }
; Type error: can't add a Scale to an Interval
let wrong = Major + P5 ; Compile error
; Correct: transpose the scale
let correct = Major |> transpose P5What Can You Build?
- Melodies using scale degrees and intervals
- Chord progressions with functional harmony
- Multi-part arrangements with parts and sections
- Algorithmic compositions using map, filter, and recursion
- MIDI files for DAW integration