Feat: adding some basic music theory
This commit is contained in:
@@ -88,6 +88,7 @@ pub enum Op {
|
||||
Generate,
|
||||
GeomRange,
|
||||
Times,
|
||||
Chord(&'static [i64]),
|
||||
// MIDI
|
||||
MidiEmit,
|
||||
GetMidiCC,
|
||||
|
||||
129
crates/forth/src/theory/chords.rs
Normal file
129
crates/forth/src/theory/chords.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
pub struct Chord {
|
||||
pub name: &'static str,
|
||||
pub intervals: &'static [i64],
|
||||
}
|
||||
|
||||
pub static CHORDS: &[Chord] = &[
|
||||
// Triads
|
||||
Chord {
|
||||
name: "maj",
|
||||
intervals: &[0, 4, 7],
|
||||
},
|
||||
Chord {
|
||||
name: "m",
|
||||
intervals: &[0, 3, 7],
|
||||
},
|
||||
Chord {
|
||||
name: "dim",
|
||||
intervals: &[0, 3, 6],
|
||||
},
|
||||
Chord {
|
||||
name: "aug",
|
||||
intervals: &[0, 4, 8],
|
||||
},
|
||||
Chord {
|
||||
name: "sus2",
|
||||
intervals: &[0, 2, 7],
|
||||
},
|
||||
Chord {
|
||||
name: "sus4",
|
||||
intervals: &[0, 5, 7],
|
||||
},
|
||||
// Seventh chords
|
||||
Chord {
|
||||
name: "maj7",
|
||||
intervals: &[0, 4, 7, 11],
|
||||
},
|
||||
Chord {
|
||||
name: "min7",
|
||||
intervals: &[0, 3, 7, 10],
|
||||
},
|
||||
Chord {
|
||||
name: "dom7",
|
||||
intervals: &[0, 4, 7, 10],
|
||||
},
|
||||
Chord {
|
||||
name: "dim7",
|
||||
intervals: &[0, 3, 6, 9],
|
||||
},
|
||||
Chord {
|
||||
name: "m7b5",
|
||||
intervals: &[0, 3, 6, 10],
|
||||
},
|
||||
Chord {
|
||||
name: "minmaj7",
|
||||
intervals: &[0, 3, 7, 11],
|
||||
},
|
||||
Chord {
|
||||
name: "aug7",
|
||||
intervals: &[0, 4, 8, 10],
|
||||
},
|
||||
// Sixth chords
|
||||
Chord {
|
||||
name: "maj6",
|
||||
intervals: &[0, 4, 7, 9],
|
||||
},
|
||||
Chord {
|
||||
name: "min6",
|
||||
intervals: &[0, 3, 7, 9],
|
||||
},
|
||||
// Extended chords
|
||||
Chord {
|
||||
name: "dom9",
|
||||
intervals: &[0, 4, 7, 10, 14],
|
||||
},
|
||||
Chord {
|
||||
name: "maj9",
|
||||
intervals: &[0, 4, 7, 11, 14],
|
||||
},
|
||||
Chord {
|
||||
name: "min9",
|
||||
intervals: &[0, 3, 7, 10, 14],
|
||||
},
|
||||
Chord {
|
||||
name: "dom11",
|
||||
intervals: &[0, 4, 7, 10, 14, 17],
|
||||
},
|
||||
Chord {
|
||||
name: "min11",
|
||||
intervals: &[0, 3, 7, 10, 14, 17],
|
||||
},
|
||||
Chord {
|
||||
name: "dom13",
|
||||
intervals: &[0, 4, 7, 10, 14, 21],
|
||||
},
|
||||
// Add chords
|
||||
Chord {
|
||||
name: "add9",
|
||||
intervals: &[0, 4, 7, 14],
|
||||
},
|
||||
Chord {
|
||||
name: "add11",
|
||||
intervals: &[0, 4, 7, 17],
|
||||
},
|
||||
Chord {
|
||||
name: "madd9",
|
||||
intervals: &[0, 3, 7, 14],
|
||||
},
|
||||
// Altered dominants
|
||||
Chord {
|
||||
name: "dom7b9",
|
||||
intervals: &[0, 4, 7, 10, 13],
|
||||
},
|
||||
Chord {
|
||||
name: "dom7s9",
|
||||
intervals: &[0, 4, 7, 10, 15],
|
||||
},
|
||||
Chord {
|
||||
name: "dom7b5",
|
||||
intervals: &[0, 4, 6, 10],
|
||||
},
|
||||
Chord {
|
||||
name: "dom7s5",
|
||||
intervals: &[0, 4, 8, 10],
|
||||
},
|
||||
];
|
||||
|
||||
pub fn lookup(name: &str) -> Option<&'static [i64]> {
|
||||
CHORDS.iter().find(|c| c.name == name).map(|c| c.intervals)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod chords;
|
||||
mod scales;
|
||||
|
||||
pub use scales::lookup;
|
||||
|
||||
@@ -455,7 +455,11 @@ impl Forth {
|
||||
let a_f = a.as_float()?;
|
||||
let b_f = b.as_float()?;
|
||||
let (lo, hi) = if a_f <= b_f { (a_f, b_f) } else { (b_f, a_f) };
|
||||
let val = self.rng.lock().unwrap().gen_range(lo..hi);
|
||||
let val = if (hi - lo).abs() < f64::EPSILON {
|
||||
lo
|
||||
} else {
|
||||
self.rng.lock().unwrap().gen_range(lo..hi)
|
||||
};
|
||||
stack.push(Value::Float(val, None));
|
||||
}
|
||||
}
|
||||
@@ -629,6 +633,13 @@ impl Forth {
|
||||
stack.push(result);
|
||||
}
|
||||
|
||||
Op::Chord(intervals) => {
|
||||
let root = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
for &interval in *intervals {
|
||||
stack.push(Value::Int(root + interval, None));
|
||||
}
|
||||
}
|
||||
|
||||
Op::Oct => {
|
||||
let shift = stack.pop().ok_or("stack underflow")?;
|
||||
let note = stack.pop().ok_or("stack underflow")?;
|
||||
|
||||
@@ -830,6 +830,292 @@ pub const WORDS: &[Word] = &[
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
// Chords - Triads
|
||||
Word {
|
||||
name: "maj",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth)",
|
||||
desc: "Major triad",
|
||||
example: "c4 maj => 60 64 67",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "m",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth)",
|
||||
desc: "Minor triad",
|
||||
example: "c4 m => 60 63 67",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dim",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth)",
|
||||
desc: "Diminished triad",
|
||||
example: "c4 dim => 60 63 66",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "aug",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth)",
|
||||
desc: "Augmented triad",
|
||||
example: "c4 aug => 60 64 68",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "sus2",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root second fifth)",
|
||||
desc: "Suspended 2nd",
|
||||
example: "c4 sus2 => 60 62 67",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "sus4",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root fourth fifth)",
|
||||
desc: "Suspended 4th",
|
||||
example: "c4 sus4 => 60 65 67",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// Chords - Seventh
|
||||
Word {
|
||||
name: "maj7",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Major 7th",
|
||||
example: "c4 maj7 => 60 64 67 71",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "min7",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Minor 7th",
|
||||
example: "c4 min7 => 60 63 67 70",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dom7",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Dominant 7th",
|
||||
example: "c4 dom7 => 60 64 67 70",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dim7",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Diminished 7th",
|
||||
example: "c4 dim7 => 60 63 66 69",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "m7b5",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Half-diminished (min7b5)",
|
||||
example: "c4 m7b5 => 60 63 66 70",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "minmaj7",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Minor-major 7th",
|
||||
example: "c4 minmaj7 => 60 63 67 71",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "aug7",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh)",
|
||||
desc: "Augmented 7th",
|
||||
example: "c4 aug7 => 60 64 68 70",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// Chords - Sixth
|
||||
Word {
|
||||
name: "maj6",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth sixth)",
|
||||
desc: "Major 6th",
|
||||
example: "c4 maj6 => 60 64 67 69",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "min6",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth sixth)",
|
||||
desc: "Minor 6th",
|
||||
example: "c4 min6 => 60 63 67 69",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// Chords - Extended
|
||||
Word {
|
||||
name: "dom9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh ninth)",
|
||||
desc: "Dominant 9th",
|
||||
example: "c4 dom9 => 60 64 67 70 74",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "maj9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh ninth)",
|
||||
desc: "Major 9th",
|
||||
example: "c4 maj9 => 60 64 67 71 74",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "min9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh ninth)",
|
||||
desc: "Minor 9th",
|
||||
example: "c4 min9 => 60 63 67 70 74",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dom11",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh ninth eleventh)",
|
||||
desc: "Dominant 11th",
|
||||
example: "c4 dom11 => 60 64 67 70 74 77",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "min11",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh ninth eleventh)",
|
||||
desc: "Minor 11th",
|
||||
example: "c4 min11 => 60 63 67 70 74 77",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dom13",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh ninth thirteenth)",
|
||||
desc: "Dominant 13th",
|
||||
example: "c4 dom13 => 60 64 67 70 74 81",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// Chords - Add
|
||||
Word {
|
||||
name: "add9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth ninth)",
|
||||
desc: "Major add 9",
|
||||
example: "c4 add9 => 60 64 67 74",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "add11",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth eleventh)",
|
||||
desc: "Major add 11",
|
||||
example: "c4 add11 => 60 64 67 77",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "madd9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth ninth)",
|
||||
desc: "Minor add 9",
|
||||
example: "c4 madd9 => 60 63 67 74",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// Chords - Altered dominants
|
||||
Word {
|
||||
name: "dom7b9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh flatninth)",
|
||||
desc: "7th flat 9",
|
||||
example: "c4 dom7b9 => 60 64 67 70 73",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dom7s9",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third fifth seventh sharpninth)",
|
||||
desc: "7th sharp 9 (Hendrix chord)",
|
||||
example: "c4 dom7s9 => 60 64 67 70 75",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dom7b5",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third flatfifth seventh)",
|
||||
desc: "7th flat 5",
|
||||
example: "c4 dom7b5 => 60 64 66 70",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "dom7s5",
|
||||
aliases: &[],
|
||||
category: "Chord",
|
||||
stack: "(root -- root third sharpfifth seventh)",
|
||||
desc: "7th sharp 5",
|
||||
example: "c4 dom7s5 => 60 64 68 70",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// LFO
|
||||
Word {
|
||||
name: "ramp",
|
||||
@@ -2676,6 +2962,11 @@ pub(super) fn compile_word(
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(intervals) = theory::chords::lookup(name) {
|
||||
ops.push(Op::Chord(intervals));
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(word) = lookup_word(name) {
|
||||
match &word.compile {
|
||||
Simple => {
|
||||
|
||||
Reference in New Issue
Block a user