194 lines
4.0 KiB
Rust
194 lines
4.0 KiB
Rust
use cagire::forth::Value;
|
|
|
|
use super::harness::{expect_error, expect_int, expect_stack};
|
|
|
|
fn ints(vals: &[i64]) -> Vec<Value> {
|
|
vals.iter().map(|&v| Value::Int(v, None)).collect()
|
|
}
|
|
|
|
// Inversions
|
|
|
|
#[test]
|
|
fn invert_major_triad() {
|
|
expect_stack("c4 maj inv", &ints(&[64, 67, 72]));
|
|
}
|
|
|
|
#[test]
|
|
fn invert_twice() {
|
|
expect_stack("c4 maj inv inv", &ints(&[67, 72, 76]));
|
|
}
|
|
|
|
#[test]
|
|
fn down_invert_major_triad() {
|
|
expect_stack("c4 maj dinv", &ints(&[55, 60, 64]));
|
|
}
|
|
|
|
#[test]
|
|
fn down_invert_min7() {
|
|
expect_stack("c4 min7 dinv", &ints(&[58, 60, 63, 67]));
|
|
}
|
|
|
|
#[test]
|
|
fn invert_min7() {
|
|
expect_stack("c4 min7 inv", &ints(&[63, 67, 70, 72]));
|
|
}
|
|
|
|
// Voicings
|
|
|
|
#[test]
|
|
fn drop2_maj7() {
|
|
// c4 maj7 = [60, 64, 67, 71], 2nd from top = 67, drop to 55
|
|
expect_stack("c4 maj7 drop2", &ints(&[55, 60, 64, 71]));
|
|
}
|
|
|
|
#[test]
|
|
fn drop3_maj7() {
|
|
// c4 maj7 = [60, 64, 67, 71], 3rd from top = 64, drop to 52
|
|
expect_stack("c4 maj7 drop3", &ints(&[52, 60, 67, 71]));
|
|
}
|
|
|
|
// Key
|
|
|
|
#[test]
|
|
fn key_sets_tonal_center() {
|
|
expect_int("g3 key! 0 major", 55);
|
|
}
|
|
|
|
#[test]
|
|
fn key_with_degree() {
|
|
// G3=55, degree 4 of major = semitone 7, so 55+7=62
|
|
expect_int("g3 key! 4 major", 62);
|
|
}
|
|
|
|
#[test]
|
|
fn key_default_is_c4() {
|
|
expect_int("0 major", 60);
|
|
}
|
|
|
|
#[test]
|
|
fn key_a3_minor() {
|
|
expect_int("a3 key! 0 minor", 57);
|
|
}
|
|
|
|
// Diatonic triads
|
|
|
|
#[test]
|
|
fn diatonic_triad_degree_0() {
|
|
// C major: degrees 0,2,4 = C,E,G = 60,64,67
|
|
expect_stack("0 major triad", &ints(&[60, 64, 67]));
|
|
}
|
|
|
|
#[test]
|
|
fn diatonic_triad_degree_1() {
|
|
// D minor: degrees 1,3,5 = D,F,A = 62,65,69
|
|
expect_stack("1 major triad", &ints(&[62, 65, 69]));
|
|
}
|
|
|
|
#[test]
|
|
fn diatonic_triad_degree_3() {
|
|
// F major: degrees 3,5,7(=0+12) = F,A,C = 65,69,72
|
|
expect_stack("3 major triad", &ints(&[65, 69, 72]));
|
|
}
|
|
|
|
#[test]
|
|
fn diatonic_triad_degree_4() {
|
|
// G major: degrees 4,6,8(=1+12) = G,B,D = 67,71,74
|
|
expect_stack("4 major triad", &ints(&[67, 71, 74]));
|
|
}
|
|
|
|
// Diatonic sevenths
|
|
|
|
#[test]
|
|
fn diatonic_seventh_degree_0() {
|
|
// C major7: degrees 0,2,4,6 = C,E,G,B = 60,64,67,71
|
|
expect_stack("0 major seventh", &ints(&[60, 64, 67, 71]));
|
|
}
|
|
|
|
#[test]
|
|
fn diatonic_seventh_degree_1() {
|
|
// D minor7: degrees 1,3,5,7(=0+12) = D,F,A,C = 62,65,69,72
|
|
expect_stack("1 major seventh", &ints(&[62, 65, 69, 72]));
|
|
}
|
|
|
|
#[test]
|
|
fn diatonic_seventh_degree_4() {
|
|
// G dom7: degrees 4,6,8(=1+12),10(=3+12) = G,B,D,F = 67,71,74,77
|
|
expect_stack("4 major seventh", &ints(&[67, 71, 74, 77]));
|
|
}
|
|
|
|
// Combined
|
|
|
|
#[test]
|
|
fn key_with_diatonic_triad() {
|
|
// G3=55 key, degree 0 major triad = G,B,D = 55,59,62
|
|
expect_stack("g3 key! 0 major triad", &ints(&[55, 59, 62]));
|
|
}
|
|
|
|
#[test]
|
|
fn key_with_triad_inv() {
|
|
// C4 key, degree 0 minor triad = C,Eb,G = 60,63,67, then inv = Eb,G,C+12 = 63,67,72
|
|
expect_stack("0 minor triad inv", &ints(&[63, 67, 72]));
|
|
}
|
|
|
|
#[test]
|
|
fn key_degree_4_triad_in_g() {
|
|
// G3=55, degree 4 of major = notes at degrees 4,6,8(=1+12)
|
|
// major pattern: [0,2,4,5,7,9,11]
|
|
// degree 4 -> semitone 7, degree 6 -> semitone 11, degree 8(=1+12) -> 12+2=14
|
|
// 55+7=62, 55+11=66, 55+14=69 -> D, F#, A
|
|
expect_stack("g3 key! 4 major triad", &ints(&[62, 66, 69]));
|
|
}
|
|
|
|
// Backwards compatibility
|
|
|
|
#[test]
|
|
fn scale_degree_still_works() {
|
|
expect_int("0 major", 60);
|
|
expect_int("7 major", 72);
|
|
}
|
|
|
|
#[test]
|
|
fn chords_still_work() {
|
|
expect_stack("c4 maj", &ints(&[60, 64, 67]));
|
|
expect_stack("c4 min7", &ints(&[60, 63, 67, 70]));
|
|
}
|
|
|
|
// Transpose
|
|
|
|
#[test]
|
|
fn transpose_major_triad() {
|
|
expect_stack("c4 maj 3 tp", &ints(&[63, 67, 70]));
|
|
}
|
|
|
|
#[test]
|
|
fn transpose_down() {
|
|
expect_stack("c4 maj -2 tp", &ints(&[58, 62, 65]));
|
|
}
|
|
|
|
#[test]
|
|
fn transpose_zero() {
|
|
expect_stack("c4 maj 0 tp", &ints(&[60, 64, 67]));
|
|
}
|
|
|
|
#[test]
|
|
fn transpose_single_note() {
|
|
expect_int("60 7 tp", 67);
|
|
}
|
|
|
|
#[test]
|
|
fn transpose_octave() {
|
|
expect_stack("c4 min7 12 tp", &ints(&[72, 75, 79, 82]));
|
|
}
|
|
|
|
// Error cases
|
|
|
|
#[test]
|
|
fn triad_without_scale_errors() {
|
|
expect_error("0 triad", "unknown word");
|
|
}
|
|
|
|
#[test]
|
|
fn seventh_without_scale_errors() {
|
|
expect_error("0 seventh", "unknown word");
|
|
}
|