clojure-school-of-music/src/music.clj

60 lines
2.1 KiB
Clojure

(ns music)
;; an octave is an int, e.g. 4
;; a pitch class is a keyword from :Abb to G##
;; a pitch is a [pitch class, octave] vector, e.g. [:C 4] is middle C
;; a duration is a rational number, e.g. 1/8
;; a note has a duration, optionally a pitch, and optionally any other necessary keys (e.g. loudness)
;; {:duration 1/8 :pitch [:A# 3]} is a note. {:duration 1/4} is a note (really, a rest)
;; [:= noteA noteB] represents noteA played simultaneously with noteB
;; [:+ noteA noteB] represents noteA played followed by noteB
;; [:modify noteA control] annotates noteA with the control map
;; control maps have keys like ::tempo, ::transpose, ::instrument, ::phrase, ::player, ::keysig
;; primitives
(def note1 {:duration 1/4, :pitch [:Eb 4]})
(def note2 {:duration 1/4, :pitch [:G 4]})
(def note3 {:duration 1/8, :pitch [:F 4]})
(def rest1 {:duration 1/8})
[:= note1 note2] ;; note1 simultaneous with note2
[:+ note1 note3] ;; note1 followed by note3
[:+ [:= note1 note2] note3] ;; note1 simultaneous with note2, followed by note3
[:modify note1 {::tempo 120}] ;; note1 modified to have tempo 120
[:modify [:= note1 note2] {::tempo 120 ::instrument "Dope Organ"}] ;; note1 simultaneous with note2 modified with tempo and instrument
;; can be nested to arbitrary complexity
(def song
[:= [:+ {:duration 1/4, :pitch [:D 3]}
{:duration 1/4, :pitch [:E 3]}
{:duration 1/4, :pitch [:F 3]}]
[:+ {:duration 1/4, :pitch [:F 3]}
{:duration 1/4, :pitch [:G 3]}
{:duration 1/4, :pitch [:A 3]}]])
(defn note [duration pitch]
{:duration duration, :pitch pitch})
(defn rest [duration]
{:duration duration})
(defn tempo [tempo music]
[:modify music {::tempo tempo}])
(defn transpose [abs-pitch music]
[:modify music {::transpose abs-pitch}])
(defn instrument [instrument music]
[:modify music {::instrument instrument}])
(defn phrase [phrase-attributes music]
[:modify music {::phrase phrase-attributes}])
(defn player [player-name music]
[:modify music {::player player-name}])
(defn keysig [pitch mode music]
[:modify music {::keysig [pitch mode]}])