head_music 11.2.0 → 11.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/head_music/content/cantus_firmus/example.rb +58 -0
- data/lib/head_music/content/cantus_firmus/examples.yml +115 -0
- data/lib/head_music/content/cantus_firmus/source.rb +58 -0
- data/lib/head_music/content/cantus_firmus/sources.yml +28 -0
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +2 -1
- metadata +6 -3
- data/lib/head_music/content/cantus_firmus_examples.rb +0 -58
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d8882c692b8b956f3856e601c37ce271c86b513064071d69b8e6965d67d8514
|
|
4
|
+
data.tar.gz: 9c14060294dfc59bb6abc768f5090edec67bdb65ef3c8e4ad6c7079b4fec93df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0803c09f157ec3331c3e3921c5fb9d3ec2873b7655a54f2d4dc518613d4059f470eaf17900c1f2f28fbd274fe15e4a53d7603c65f2b6dacd550dc596b57c872
|
|
7
|
+
data.tar.gz: f98d4b7e8fdfdae06ca3e116ebf19793151abaeeb5c3535708181abcb3b8d9deae965262da7f69fab6ca6e29065832f253532b186dfa0bfc0e98d8c4a80f2e90
|
data/Gemfile.lock
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module HeadMusic
|
|
2
|
+
module Content
|
|
3
|
+
module CantusFirmus
|
|
4
|
+
# Sample cantus firmus examples from various pedagogical sources.
|
|
5
|
+
# These are traditional melodies used for teaching counterpoint.
|
|
6
|
+
class Example
|
|
7
|
+
EXAMPLES_DATA = YAML.load_file(File.expand_path("examples.yml", __dir__)).freeze
|
|
8
|
+
|
|
9
|
+
attr_reader :source, :tonal_center, :mode, :pitches
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
def all
|
|
13
|
+
@all ||= EXAMPLES_DATA["cantus_firmus_examples"].map do |data|
|
|
14
|
+
new(data: data)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def by_source(source_identifier)
|
|
19
|
+
source = Source.get(source_identifier)
|
|
20
|
+
return [] unless source
|
|
21
|
+
|
|
22
|
+
all.select { |example| example.source == source }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def sources
|
|
26
|
+
all.map(&:source).uniq
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def by_mode(mode_name)
|
|
30
|
+
normalized_mode = mode_name.to_s.downcase
|
|
31
|
+
all.select { |example| example.mode.to_s.downcase == normalized_mode }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def by_tonal_center(tonal_center_name)
|
|
35
|
+
all.select { |example| example.tonal_center.to_s == tonal_center_name.to_s }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(data:)
|
|
40
|
+
@source = Source.get(data["source"])
|
|
41
|
+
@tonal_center = data["tonal_center"]
|
|
42
|
+
@mode = data["mode"]&.to_sym
|
|
43
|
+
@pitches = data["pitches"] || []
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def length
|
|
47
|
+
pitches.length
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
"#{tonal_center} #{mode} (#{source})"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private_class_method :new
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
cantus_firmus_examples:
|
|
2
|
+
- source: "Fux"
|
|
3
|
+
tonal_center: D
|
|
4
|
+
mode: dorian
|
|
5
|
+
pitches: ["D", "F", "E", "D", "G", "F", "A", "G", "F", "E", "D"]
|
|
6
|
+
|
|
7
|
+
- source: "Fux"
|
|
8
|
+
tonal_center: E
|
|
9
|
+
mode: phrygian
|
|
10
|
+
pitches: ["E", "C", "D", "C", "A3", "A", "G", "E", "F", "E"]
|
|
11
|
+
|
|
12
|
+
- source: "Fux"
|
|
13
|
+
tonal_center: F
|
|
14
|
+
mode: lydian
|
|
15
|
+
pitches: ["F", "G", "A", "F", "D", "E", "F", "C5", "A", "F", "G", "F"]
|
|
16
|
+
|
|
17
|
+
- source: "Fux"
|
|
18
|
+
tonal_center: G
|
|
19
|
+
mode: mixolydian
|
|
20
|
+
pitches: ["G3", "C", "B3", "G3", "C", "E", "D", "G", "E", "C", "D", "B3", "A3", "G3"]
|
|
21
|
+
|
|
22
|
+
- source: "Fux"
|
|
23
|
+
tonal_center: A
|
|
24
|
+
mode: aeolian
|
|
25
|
+
pitches: ["A3", "C", "B3", "D", "C", "E", "F", "E", "D", "C", "B3", "A3"]
|
|
26
|
+
|
|
27
|
+
- source: "Fux"
|
|
28
|
+
tonal_center: C
|
|
29
|
+
mode: ionian
|
|
30
|
+
pitches: ["C", "E", "F", "G", "E", "A", "G", "E", "F", "E", "D", "C"]
|
|
31
|
+
|
|
32
|
+
- source: "Fux"
|
|
33
|
+
tonal_center: C
|
|
34
|
+
mode: ionian
|
|
35
|
+
pitches: ["C", "E", "F", "E", "G", "F", "E", "D", "C"]
|
|
36
|
+
|
|
37
|
+
- source: "Clendinning & Marvin"
|
|
38
|
+
tonal_center: F
|
|
39
|
+
mode: ionian
|
|
40
|
+
pitches: ["F3", "G3", "A3", "F3", "D3", "E3", "F3", "C4", "A3", "F3", "G3", "F3"]
|
|
41
|
+
|
|
42
|
+
- source: "Clendinning & Marvin"
|
|
43
|
+
tonal_center: D
|
|
44
|
+
mode: aeolian
|
|
45
|
+
pitches: ["D3", "A3", "G3", "F3", "E3", "D3", "F3", "E3", "D3"]
|
|
46
|
+
|
|
47
|
+
- source: "Clendinning & Marvin"
|
|
48
|
+
tonal_center: C
|
|
49
|
+
mode: ionian
|
|
50
|
+
pitches: ["C", "D", "F", "E", "F", "G", "A", "G", "E", "D", "C"]
|
|
51
|
+
|
|
52
|
+
- source: "Clendinning & Marvin"
|
|
53
|
+
tonal_center: C
|
|
54
|
+
mode: ionian
|
|
55
|
+
pitches: ["C3", "E3", "F3", "G3", "E3", "A3", "G3", "E3", "F3", "E3", "D3", "C3"]
|
|
56
|
+
|
|
57
|
+
- source: "Davis & Lybbert"
|
|
58
|
+
tonal_center: C
|
|
59
|
+
mode: ionian
|
|
60
|
+
pitches: ["C3", "E3", "D3", "G3", "A3", "G3", "E3", "F3", "D3", "C3"]
|
|
61
|
+
|
|
62
|
+
- source: "Davis & Lybbert"
|
|
63
|
+
tonal_center: C
|
|
64
|
+
mode: ionian
|
|
65
|
+
pitches: ["C3", "D3", "E3", "G3", "A3", "F3", "E3", "D3", "C3"]
|
|
66
|
+
|
|
67
|
+
- source: "Davis & Lybbert"
|
|
68
|
+
tonal_center: G
|
|
69
|
+
mode: ionian
|
|
70
|
+
pitches: ["G3", "F#3", "G3", "E3", "D3", "B2", "C3", "D3", "B2", "A2", "G2"]
|
|
71
|
+
|
|
72
|
+
- source: "Davis & Lybbert"
|
|
73
|
+
tonal_center: G
|
|
74
|
+
mode: ionian
|
|
75
|
+
pitches: ["G2", "B2", "C3", "D3", "E3", "D3", "B2", "C3", "A2", "G2"]
|
|
76
|
+
|
|
77
|
+
- source: "Davis & Lybbert"
|
|
78
|
+
tonal_center: F
|
|
79
|
+
mode: ionian
|
|
80
|
+
pitches: ["F3", "D3", "C3", "F3", "G3", "A3", "E3", "D3", "G3", "F3"]
|
|
81
|
+
|
|
82
|
+
- source: "Davis & Lybbert"
|
|
83
|
+
tonal_center: A
|
|
84
|
+
mode: aeolian
|
|
85
|
+
pitches: ["A2", "E3", "C3", "D3", "B2", "G2", "A2", "C3", "B2", "A2"]
|
|
86
|
+
|
|
87
|
+
- source: "Davis & Lybbert"
|
|
88
|
+
tonal_center: A
|
|
89
|
+
mode: aeolian
|
|
90
|
+
pitches: ["A2", "B2", "C3", "D3", "E3", "F3", "E3", "C3", "B2", "A2"]
|
|
91
|
+
|
|
92
|
+
- source: "Davis & Lybbert"
|
|
93
|
+
tonal_center: E
|
|
94
|
+
mode: aeolian
|
|
95
|
+
pitches: ["E3", "A3", "B3", "G3", "C4", "A3", "B3", "G3", "F#3", "E3"]
|
|
96
|
+
|
|
97
|
+
- source: "Davis & Lybbert"
|
|
98
|
+
tonal_center: E
|
|
99
|
+
mode: aeolian
|
|
100
|
+
pitches: ["E3", "D3", "C3", "B2", "G2", "A2", "B2", "E3", "G3", "F#3", "E3"]
|
|
101
|
+
|
|
102
|
+
- source: "Davis & Lybbert"
|
|
103
|
+
tonal_center: D
|
|
104
|
+
mode: aeolian
|
|
105
|
+
pitches: ["D3", "F3", "E3", "G3", "F3", "D3", "A3", "G3", "F3", "E3", "D3"]
|
|
106
|
+
|
|
107
|
+
- source: "Schoenberg"
|
|
108
|
+
tonal_center: Eb
|
|
109
|
+
mode: ionian
|
|
110
|
+
pitches: ["Eb", "D", "G3", "Ab3", "C", "Ab3", "F3", "Eb3"]
|
|
111
|
+
|
|
112
|
+
- source: "Schoenberg"
|
|
113
|
+
tonal_center: A
|
|
114
|
+
mode: ionian
|
|
115
|
+
pitches: ["A3", "C#4", "B3", "F#3", "A3", "F#3", "G#3", "A3"]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module HeadMusic
|
|
2
|
+
module Content
|
|
3
|
+
module CantusFirmus
|
|
4
|
+
# A pedagogical source of cantus firmus examples.
|
|
5
|
+
# Sources include books and treatises on counterpoint.
|
|
6
|
+
class Source
|
|
7
|
+
SOURCES_DATA = YAML.load_file(File.expand_path("sources.yml", __dir__)).freeze
|
|
8
|
+
|
|
9
|
+
attr_reader :key, :publication_name, :publication_edition, :author_names, :notes
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
def all
|
|
13
|
+
@all ||= SOURCES_DATA["cantus_firmus_sources"].map do |key, data|
|
|
14
|
+
new(key: key, data: data)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get(identifier)
|
|
19
|
+
return identifier if identifier.is_a?(self)
|
|
20
|
+
|
|
21
|
+
normalized_key = normalize_key(identifier)
|
|
22
|
+
all.find { |source| source.key == normalized_key }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def keys
|
|
26
|
+
all.map(&:key)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# Normalize various source name formats to the YAML key format
|
|
32
|
+
# e.g., "Fux" -> "fux", "Clendinning & Marvin" -> "clendinning_and_marvin"
|
|
33
|
+
def normalize_key(identifier)
|
|
34
|
+
identifier.to_s
|
|
35
|
+
.downcase
|
|
36
|
+
.gsub(/\s*&\s*/, "_and_")
|
|
37
|
+
.gsub(/\s+/, "_")
|
|
38
|
+
.to_sym
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def initialize(key:, data:)
|
|
43
|
+
@key = key.to_sym
|
|
44
|
+
@publication_name = data["publication_name"]
|
|
45
|
+
@publication_edition = data["publication_edition"]
|
|
46
|
+
@author_names = data["author_names"] || []
|
|
47
|
+
@notes = data["notes"]&.strip
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
publication_name
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private_class_method :new
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
cantus_firmus_sources:
|
|
2
|
+
fux:
|
|
3
|
+
publication_name: Gradus ad Parnassum
|
|
4
|
+
author_names:
|
|
5
|
+
- Johann Joseph Fux
|
|
6
|
+
notes: >
|
|
7
|
+
A foundational text on counterpoint by Johann Joseph Fux, first published in 1725.
|
|
8
|
+
clendinning_and_marvin:
|
|
9
|
+
publication_name: The Musician's Guide to Theory and Analysis
|
|
10
|
+
publication_edition: 3rd
|
|
11
|
+
author_names:
|
|
12
|
+
- Jane Piper Clendinning
|
|
13
|
+
- Elizabeth West Marvin
|
|
14
|
+
notes: >
|
|
15
|
+
A contemporary guide to music theory and analysis, widely used in music education.
|
|
16
|
+
davis_and_lybbert:
|
|
17
|
+
publication_name: The Essentials of Counterpoint
|
|
18
|
+
author_names:
|
|
19
|
+
- Ferdinand Davis
|
|
20
|
+
- Donald Lybbert
|
|
21
|
+
notes: >
|
|
22
|
+
A comprehensive text on counterpoint techniques and practices.
|
|
23
|
+
schoenberg:
|
|
24
|
+
publication_name: Preliminary Exercises in Counterpoint
|
|
25
|
+
author_names:
|
|
26
|
+
- Arnold Schoenberg
|
|
27
|
+
notes: >
|
|
28
|
+
A set of exercises by Arnold Schoenberg designed to teach the fundamentals of counterpoint.
|
data/lib/head_music/version.rb
CHANGED
data/lib/head_music.rb
CHANGED
|
@@ -110,7 +110,8 @@ require "head_music/instruments/score_order"
|
|
|
110
110
|
|
|
111
111
|
# content
|
|
112
112
|
require "head_music/content/bar"
|
|
113
|
-
require "head_music/content/
|
|
113
|
+
require "head_music/content/cantus_firmus/source"
|
|
114
|
+
require "head_music/content/cantus_firmus/example"
|
|
114
115
|
require "head_music/content/composition"
|
|
115
116
|
require "head_music/content/note"
|
|
116
117
|
require "head_music/content/placement"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: head_music
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 11.
|
|
4
|
+
version: 11.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob Head
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -181,7 +181,10 @@ files:
|
|
|
181
181
|
- lib/head_music/analysis/pitch_collection.rb
|
|
182
182
|
- lib/head_music/analysis/sonority.rb
|
|
183
183
|
- lib/head_music/content/bar.rb
|
|
184
|
-
- lib/head_music/content/
|
|
184
|
+
- lib/head_music/content/cantus_firmus/example.rb
|
|
185
|
+
- lib/head_music/content/cantus_firmus/examples.yml
|
|
186
|
+
- lib/head_music/content/cantus_firmus/source.rb
|
|
187
|
+
- lib/head_music/content/cantus_firmus/sources.yml
|
|
185
188
|
- lib/head_music/content/composition.rb
|
|
186
189
|
- lib/head_music/content/note.rb
|
|
187
190
|
- lib/head_music/content/placement.rb
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
module HeadMusic
|
|
2
|
-
module Content
|
|
3
|
-
# Sample cantus firmus examples from various pedagogical sources.
|
|
4
|
-
# These are traditional melodies used for teaching counterpoint.
|
|
5
|
-
module CantusFirmusExamples
|
|
6
|
-
FUX = [
|
|
7
|
-
{source: "Fux", tonality: "D dorian", pitches: %w[D F E D G F A G F E D]},
|
|
8
|
-
{source: "Fux", tonality: "E phrygian", pitches: %w[E C D C A3 A G E F E]},
|
|
9
|
-
{source: "Fux", tonality: "F lydian", pitches: %w[F G A F D E F C5 A F G F]},
|
|
10
|
-
{source: "Fux", tonality: "G mixolydian", pitches: %w[G3 C B3 G3 C E D G E C D B3 A3 G3]},
|
|
11
|
-
{source: "Fux", tonality: "A aeolian", pitches: %w[A3 C B3 D C E F E D C B3 A3]},
|
|
12
|
-
{source: "Fux", tonality: "C ionian", pitches: %w[C E F G E A G E F E D C]},
|
|
13
|
-
{source: "Fux", tonality: "C ionian", pitches: %w[C E F E G F E D C]}
|
|
14
|
-
].freeze
|
|
15
|
-
|
|
16
|
-
CLENDINNING = [
|
|
17
|
-
{source: "Clendinning", name: "F major", tonality: "F major", pitches: %w[F3 G3 A3 F3 D3 E3 F3 C4 A3 F3 G3 F3]},
|
|
18
|
-
{source: "Clendinning", name: "D minor", tonality: "D minor", pitches: %w[D3 A3 G3 F3 E3 D3 F3 E3 D3]},
|
|
19
|
-
{source: "Clendinning", name: "C major (treble)", tonality: "C major", pitches: %w[C D F E F G A G E D C]},
|
|
20
|
-
{source: "Clendinning", name: "C major (bass)", tonality: "C major", pitches: %w[C3 E3 F3 G3 E3 A3 G3 E3 F3 E3 D3 C3]}
|
|
21
|
-
].freeze
|
|
22
|
-
|
|
23
|
-
DAVIS_AND_LYBBERT = [
|
|
24
|
-
{source: "Davis & Lybbert", name: "CF 1 in C major", tonality: "C major", pitches: %w[C3 E3 D3 G3 A3 G3 E3 F3 D3 C3]},
|
|
25
|
-
{source: "Davis & Lybbert", name: "CF 2 in C major", tonality: "C major", pitches: %w[C3 D3 E3 G3 A3 F3 E3 D3 C3]},
|
|
26
|
-
{source: "Davis & Lybbert", name: "CF 3 in G major", tonality: "G major", pitches: %w[G3 F#3 G3 E3 D3 B2 C3 D3 B2 A2 G2]},
|
|
27
|
-
{source: "Davis & Lybbert", name: "CF 4 in G major", tonality: "G major", pitches: %w[G2 B2 C3 D3 E3 D3 B2 C3 A2 G2]},
|
|
28
|
-
{source: "Davis & Lybbert", name: "CF 5 in F major", tonality: "F major", pitches: %w[F3 D3 C3 F3 G3 A3 E3 D3 G3 F3]},
|
|
29
|
-
{source: "Davis & Lybbert", name: "CF 6 in A minor", tonality: "A minor", pitches: %w[A2 E3 C3 D3 B2 G2 A2 C3 B2 A2]},
|
|
30
|
-
{source: "Davis & Lybbert", name: "CF 7 in A minor", tonality: "A minor", pitches: %w[A2 B2 C3 D3 E3 F3 E3 C3 B2 A2]},
|
|
31
|
-
{source: "Davis & Lybbert", name: "CF 8 in E minor", tonality: "E minor", pitches: %w[E3 A3 B3 G3 C4 A3 B3 G3 F#3 E3]},
|
|
32
|
-
{source: "Davis & Lybbert", name: "CF 9 in E minor", tonality: "E minor", pitches: %w[E3 D3 C3 B2 G2 A2 B2 E3 G3 F#3 E3]},
|
|
33
|
-
{source: "Davis & Lybbert", name: "CF 10 in D minor", tonality: "D minor", pitches: %w[D3 F3 E3 G3 F3 D3 A3 G3 F3 E3 D3]}
|
|
34
|
-
].freeze
|
|
35
|
-
|
|
36
|
-
SCHOENBERG = [
|
|
37
|
-
{source: "Schoenberg", tonality: "Eb major", pitches: %w[Eb D G3 Ab3 C Ab3 F3 Eb3]},
|
|
38
|
-
{source: "Schoenberg", tonality: "A major", pitches: %w[A3 C#4 B3 F#3 A3 F#3 G#3 A3]}
|
|
39
|
-
].freeze
|
|
40
|
-
|
|
41
|
-
EXAMPLES = (FUX + CLENDINNING + DAVIS_AND_LYBBERT + SCHOENBERG).freeze
|
|
42
|
-
|
|
43
|
-
class << self
|
|
44
|
-
def all
|
|
45
|
-
EXAMPLES
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def by_source(source)
|
|
49
|
-
EXAMPLES.select { |ex| ex[:source] == source }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def sources
|
|
53
|
-
EXAMPLES.map { |ex| ex[:source] }.uniq
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|