musicality 0.11.1 → 0.12.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.
Files changed (124) hide show
  1. checksums.yaml +5 -5
  2. data/.coveralls.yml +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +4 -0
  5. data/ChangeLog.md +11 -0
  6. data/README.md +3 -0
  7. data/Rakefile +11 -3
  8. data/lib/musicality/composition/model/rhythm.rb +33 -0
  9. data/lib/musicality/composition/model/rhythm_class.rb +30 -0
  10. data/lib/musicality/composition/sequencing/drum_machine/drum_kit.rb +18 -0
  11. data/lib/musicality/composition/sequencing/drum_machine/drum_machine.rb +59 -0
  12. data/lib/musicality/composition/sequencing/drum_machine/drum_parts.rb +21 -0
  13. data/lib/musicality/composition/sequencing/drum_machine/drum_pattern.rb +66 -0
  14. data/lib/musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns.rb +146 -0
  15. data/lib/musicality/composition/sequencing/note_array.rb +33 -0
  16. data/lib/musicality/composition/sequencing/note_fifo.rb +73 -0
  17. data/lib/musicality/composition/sequencing/sequenceable.rb +9 -0
  18. data/lib/musicality/composition/sequencing/sequencer.rb +35 -0
  19. data/lib/musicality/errors.rb +2 -2
  20. data/lib/musicality/notation/model/dynamics.rb +2 -2
  21. data/lib/musicality/notation/model/key.rb +42 -91
  22. data/lib/musicality/notation/model/keys.rb +35 -34
  23. data/lib/musicality/notation/model/note.rb +31 -9
  24. data/lib/musicality/notation/model/pitch.rb +2 -2
  25. data/lib/musicality/notation/parsing/convenience_methods.rb +23 -12
  26. data/lib/musicality/notation/parsing/duration_parsing.rb +3 -3
  27. data/lib/musicality/notation/parsing/key_parsing.rb +150 -0
  28. data/lib/musicality/notation/parsing/key_parsing.treetop +37 -0
  29. data/lib/musicality/notation/parsing/meter_parsing.rb +3 -3
  30. data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +3 -1
  31. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +1 -0
  32. data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +1 -1
  33. data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +4 -1
  34. data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +1 -1
  35. data/lib/musicality/notation/parsing/parseable.rb +13 -17
  36. data/lib/musicality/notation/parsing/pitch_parsing.rb +7 -0
  37. data/lib/musicality/notation/parsing/segment_parsing.rb +3 -0
  38. data/lib/musicality/performance/conversion/note_sequence_extractor.rb +82 -134
  39. data/lib/musicality/performance/model/note_sequence.rb +22 -3
  40. data/lib/musicality/performance/supercollider/performer.rb +2 -2
  41. data/lib/musicality/performance/supercollider/sc_drum_kits.rb +29 -0
  42. data/lib/musicality/performance/supercollider/synthdefs/bass.rb +211 -0
  43. data/lib/musicality/performance/supercollider/synthdefs/claps.rb +80 -0
  44. data/lib/musicality/performance/supercollider/synthdefs/cymbals.rb +57 -0
  45. data/lib/musicality/performance/supercollider/synthdefs/hihats.rb +67 -0
  46. data/lib/musicality/performance/supercollider/synthdefs/kicks.rb +158 -0
  47. data/lib/musicality/performance/supercollider/synthdefs/mario.rb +49 -0
  48. data/lib/musicality/performance/supercollider/{synthdefs.rb → synthdefs/other.rb} +0 -767
  49. data/lib/musicality/performance/supercollider/synthdefs/pianos.rb +46 -0
  50. data/lib/musicality/performance/supercollider/synthdefs/snares.rb +169 -0
  51. data/lib/musicality/performance/supercollider/synthdefs/toms.rb +25 -0
  52. data/lib/musicality/performance/supercollider/synthdefs/volume.rb +20 -0
  53. data/lib/musicality/pitch_class.rb +1 -1
  54. data/lib/musicality/pitch_classes.rb +3 -5
  55. data/lib/musicality/version.rb +1 -1
  56. data/lib/musicality.rb +25 -1
  57. data/musicality.gemspec +3 -2
  58. data/spec/composition/convenience_methods_spec.rb +8 -8
  59. data/spec/composition/generation/random_rhythm_generator_spec.rb +5 -5
  60. data/spec/composition/model/pitch_class_spec.rb +22 -16
  61. data/spec/composition/model/pitch_classes_spec.rb +5 -5
  62. data/spec/composition/model/rhythm_class_spec.rb +42 -0
  63. data/spec/composition/model/rhythm_spec.rb +43 -0
  64. data/spec/composition/model/scale_class_spec.rb +26 -26
  65. data/spec/composition/model/scale_spec.rb +38 -38
  66. data/spec/composition/sequencing/drum_machine/drum_machine_spec.rb +67 -0
  67. data/spec/composition/sequencing/drum_machine/drum_pattern_spec.rb +58 -0
  68. data/spec/composition/sequencing/note_array_spec.rb +94 -0
  69. data/spec/composition/sequencing/note_fifo_spec.rb +183 -0
  70. data/spec/composition/sequencing/sequencer_spec.rb +76 -0
  71. data/spec/composition/util/adding_sequence_spec.rb +33 -33
  72. data/spec/composition/util/compound_sequence_spec.rb +6 -6
  73. data/spec/composition/util/note_generation_spec.rb +34 -34
  74. data/spec/composition/util/probabilities_spec.rb +7 -7
  75. data/spec/composition/util/random_sampler_spec.rb +3 -3
  76. data/spec/composition/util/repeating_sequence_spec.rb +28 -28
  77. data/spec/musicality_spec.rb +1 -1
  78. data/spec/notation/conversion/change_conversion_spec.rb +87 -87
  79. data/spec/notation/conversion/note_time_converter_spec.rb +22 -22
  80. data/spec/notation/conversion/score_conversion_spec.rb +1 -1
  81. data/spec/notation/conversion/score_converter_spec.rb +31 -31
  82. data/spec/notation/conversion/tempo_conversion_spec.rb +11 -11
  83. data/spec/notation/model/change_spec.rb +80 -80
  84. data/spec/notation/model/key_spec.rb +135 -69
  85. data/spec/notation/model/link_spec.rb +27 -27
  86. data/spec/notation/model/meter_spec.rb +28 -28
  87. data/spec/notation/model/note_spec.rb +68 -47
  88. data/spec/notation/model/part_spec.rb +19 -19
  89. data/spec/notation/model/pitch_spec.rb +69 -68
  90. data/spec/notation/model/score_spec.rb +50 -47
  91. data/spec/notation/parsing/articulation_parsing_spec.rb +4 -4
  92. data/spec/notation/parsing/convenience_methods_spec.rb +49 -10
  93. data/spec/notation/parsing/duration_nodes_spec.rb +13 -13
  94. data/spec/notation/parsing/duration_parsing_spec.rb +10 -10
  95. data/spec/notation/parsing/key_parsing_spec.rb +19 -0
  96. data/spec/notation/parsing/link_nodes_spec.rb +7 -7
  97. data/spec/notation/parsing/link_parsing_spec.rb +4 -4
  98. data/spec/notation/parsing/meter_parsing_spec.rb +5 -5
  99. data/spec/notation/parsing/note_node_spec.rb +19 -19
  100. data/spec/notation/parsing/note_parsing_spec.rb +4 -4
  101. data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +8 -8
  102. data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +2 -2
  103. data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +1 -1
  104. data/spec/notation/parsing/numbers/positive_float_spec.rb +8 -8
  105. data/spec/notation/parsing/numbers/positive_integer_spec.rb +6 -6
  106. data/spec/notation/parsing/numbers/positive_rational_spec.rb +6 -6
  107. data/spec/notation/parsing/pitch_node_spec.rb +7 -7
  108. data/spec/notation/parsing/pitch_parsing_spec.rb +2 -2
  109. data/spec/notation/parsing/segment_parsing_spec.rb +3 -3
  110. data/spec/notation/util/function_spec.rb +15 -15
  111. data/spec/notation/util/transition_spec.rb +12 -12
  112. data/spec/notation/util/value_computer_spec.rb +35 -36
  113. data/spec/performance/conversion/glissando_converter_spec.rb +24 -24
  114. data/spec/performance/conversion/note_sequence_extractor_spec.rb +39 -39
  115. data/spec/performance/conversion/portamento_converter_spec.rb +23 -23
  116. data/spec/performance/midi/midi_util_spec.rb +41 -41
  117. data/spec/performance/midi/part_sequencer_spec.rb +10 -10
  118. data/spec/performance/midi/score_sequencer_spec.rb +15 -15
  119. data/spec/performance/midi/score_sequencing_spec.rb +2 -2
  120. data/spec/performance/util/optimization_spec.rb +9 -9
  121. data/spec/printing/note_engraving_spec.rb +16 -16
  122. data/spec/printing/score_engraver_spec.rb +5 -5
  123. data/spec/spec_helper.rb +5 -0
  124. metadata +85 -30
@@ -2,27 +2,28 @@ module Musicality
2
2
 
3
3
  class Key
4
4
  include Packable
5
-
5
+
6
6
  FLAT = :flat
7
7
  SHARP = :sharp
8
- ACCIDENTAL_TYPES = [FLAT, SHARP]
9
-
8
+ NONE = :none
9
+ ACCIDENTAL_TYPES = [FLAT, SHARP, NONE]
10
+
10
11
  MAJOR = :major
11
12
  MINOR = :minor
12
13
  TRIAD_TYPES = [MAJOR, MINOR]
13
-
14
- TONICS = {
14
+
15
+ TONIC_PCS = {
15
16
  MAJOR => {
16
17
  FLAT => [PitchClasses::F, PitchClasses::Bb, PitchClasses::Eb,
17
- PitchClasses::Ab, PitchClasses::Db, PitchClasses::Gb, PitchClasses::Cb],
18
+ PitchClasses::Ab, PitchClasses::Db, PitchClasses::Gb],
18
19
  SHARP => [PitchClasses::G,PitchClasses::D,PitchClasses::A,
19
- PitchClasses::E,PitchClasses::B,PitchClasses::Fs,PitchClasses::Cs]
20
+ PitchClasses::E,PitchClasses::B]
20
21
  },
21
22
  MINOR => {
22
23
  FLAT => [PitchClasses::D,PitchClasses::G,PitchClasses::C,
23
- PitchClasses::F,PitchClasses::Bb,PitchClasses::Eb,PitchClasses::Ab],
24
+ PitchClasses::F,PitchClasses::Bb,PitchClasses::Eb],
24
25
  SHARP => [PitchClasses::E,PitchClasses::B,PitchClasses::Fs,
25
- PitchClasses::Cs,PitchClasses::Gs,PitchClasses::Ds,PitchClasses::As]
26
+ PitchClasses::Cs,PitchClasses::Gs]
26
27
  }
27
28
  }
28
29
 
@@ -33,105 +34,55 @@ class Key
33
34
  PitchClasses::Ds,PitchClasses::As,PitchClasses::Es,PitchClasses::Bs]
34
35
  }
35
36
 
36
- attr_reader :tonic_pc, :triad, :accidental_pref
37
-
38
- def initialize tonic_pc, triad: MAJOR, accidental_pref: FLAT
39
- self.tonic_pc = tonic_pc
40
- self.triad = triad
41
- self.accidental_pref = accidental_pref
42
- end
43
-
44
- def self.major_flat tonic_pc
45
- Key.new(tonic_pc, triad: MAJOR, accidental_pref: FLAT)
46
- end
47
-
48
- def self.major_sharp tonic_pc
49
- Key.new(tonic_pc, triad: MAJOR, accidental_pref: SHARP)
50
- end
51
-
52
- def self.minor_flat tonic_pc
53
- Key.new(tonic_pc, triad: MINOR, accidental_pref: FLAT)
54
- end
55
-
56
- def self.minor_sharp tonic_pc
57
- Key.new(tonic_pc, triad: MINOR, accidental_pref: SHARP)
58
- end
59
-
60
- def major?; @triad == MAJOR; end
61
- def minor?; @triad == MINOR; end
62
-
63
- def flat?; accidental_type == FLAT; end
64
- def sharp?; accidental_type == SHARP; end
65
-
66
- def accidental_free?
67
- (major? && @tonic_pc == PitchClasses::C) || (minor? && @tonic_pc == PitchClasses::A)
68
- end
37
+ attr_reader :tonic_pc, :triad_type, :accidentals, :accidental_type
69
38
 
70
- def triad= triad
71
- if triad != @triad
72
- unless TRIAD_TYPES.include? triad
73
- raise ArgumentError, "Triad type #{triad} is not supported"
39
+ def initialize tonic_pc, triad_type: MAJOR
40
+ raise ArgumentError, "Unknown triad type #{triad_type}" unless TRIAD_TYPES.include?(triad_type)
41
+ @triad_type = triad_type
42
+ @tonic_pc = PitchClass.from_i(tonic_pc)
43
+
44
+ if (@triad_type == MAJOR && @tonic_pc == PitchClasses::C) ||
45
+ (@triad_type == MINOR && @tonic_pc == PitchClasses::A)
46
+ @accidentals = []
47
+ @accidental_type = NONE
48
+ else
49
+ if TONIC_PCS[@triad_type][FLAT].include?(@tonic_pc)
50
+ @accidental_type = FLAT
51
+ elsif TONIC_PCS[@triad_type][SHARP].include?(@tonic_pc)
52
+ @accidental_type = SHARP
53
+ else
54
+ raise ArgumentError, "unknown tonic PC #{@tonic_pc}"
74
55
  end
75
- @triad = triad
76
- reset_accidentals
56
+ i = TONIC_PCS[@triad_type][@accidental_type].index(@tonic_pc)
57
+ @accidentals = ACCIDENTALS[@accidental_type][0..i]
77
58
  end
78
59
  end
79
60
 
80
- def accidental_pref= accidental_pref
81
- if accidental_pref != @accidental_pref
82
- unless ACCIDENTAL_TYPES.include? accidental_pref
83
- raise ArgumentError, "Accidental type #{accidental_pref} is not supported"
84
- end
85
- @accidental_pref = accidental_pref
86
- reset_accidentals
87
- end
61
+ def self.major tonic_pc
62
+ Key.new(tonic_pc, triad_type: MAJOR)
88
63
  end
89
64
 
90
- def tonic_pc= tonic_pc
91
- if tonic_pc != @tonic_pc
92
- @tonic_pc = PitchClass.from_i(tonic_pc)
93
- reset_accidentals
94
- end
65
+ def self.minor tonic_pc
66
+ Key.new(tonic_pc, triad_type: MINOR)
95
67
  end
96
-
68
+
69
+ def major?; @triad_type == MAJOR; end
70
+ def minor?; @triad_type == MINOR; end
71
+
72
+ def flat?; @accidental_type == FLAT; end
73
+ def sharp?; @accidental_type == SHARP; end
74
+
97
75
  def ==(other)
98
- return @tonic_pc == other.tonic_pc && @triad == other.triad &&
99
- @accidental_pref == other.accidental_pref
76
+ return @tonic_pc == other.tonic_pc && @triad_type == other.triad_type
100
77
  end
101
78
 
102
79
  def clone
103
80
  Marshal.load(Marshal.dump(self))
104
81
  end
105
-
106
- def accidentals
107
- unless @accidentals
108
- @accidentals = []
109
- unless accidental_free?
110
- acc_type = accidental_type
111
- idx = TONICS[@triad][acc_type].index(@tonic_pc)
112
- @accidentals = ACCIDENTALS[acc_type].take(idx+1)
113
- end
114
- end
115
- return @accidentals
116
- end
117
-
118
- def accidental_type
119
- if accidental_free? || TONICS[@triad][@accidental_pref].include?(@tonic_pc)
120
- @accidental_pref
121
- else
122
- (@accidental_pref == FLAT) ? SHARP : FLAT
123
- end
124
- end
125
82
 
126
83
  def transpose interval
127
- new_key = self.clone
128
- new_key.tonic_pc += interval
129
- return new_key
84
+ Key.new(PitchClass.from_i(@tonic_pc+interval), @triad_type)
130
85
  end
131
-
132
- private
133
-
134
- def reset_accidentals; @accidentals = nil; end
135
86
  end
136
87
 
137
88
  end
@@ -1,37 +1,38 @@
1
1
  module Musicality
2
2
  module Keys
3
- C_MAJOR = Key.major_sharp(PitchClasses::C)
4
- G_MAJOR = Key.major_sharp(PitchClasses::G)
5
- D_MAJOR = Key.major_sharp(PitchClasses::D)
6
- A_MAJOR = Key.major_sharp(PitchClasses::A)
7
- E_MAJOR = Key.major_sharp(PitchClasses::E)
8
- B_MAJOR = Key.major_sharp(PitchClasses::B)
9
- F_SHARP_MAJOR = Key.major_sharp(PitchClasses::Fs)
10
- C_SHARP_MAJOR = Key.major_sharp(PitchClasses::Cs)
11
-
12
- F_MAJOR = Key.major_flat(PitchClasses::F)
13
- B_FLAT_MAJOR = Key.major_flat(PitchClasses::Bb)
14
- E_FLAT_MAJOR = Key.major_flat(PitchClasses::Eb)
15
- A_FLAT_MAJOR = Key.major_flat(PitchClasses::Ab)
16
- D_FLAT_MAJOR = Key.major_flat(PitchClasses::Db)
17
- G_FLAT_MAJOR = Key.major_flat(PitchClasses::Gb)
18
- C_FLAT_MAJOR = Key.major_flat(PitchClasses::Cb)
19
-
20
- A_MINOR = Key.minor_sharp(PitchClasses::A)
21
- E_MINOR = Key.minor_sharp(PitchClasses::E)
22
- B_MINOR = Key.minor_sharp(PitchClasses::B)
23
- F_SHARP_MINOR = Key.minor_sharp(PitchClasses::Fs)
24
- C_SHARP_MINOR = Key.minor_sharp(PitchClasses::Cs)
25
- G_SHARP_MINOR = Key.minor_sharp(PitchClasses::Gs)
26
- D_SHARP_MINOR = Key.minor_sharp(PitchClasses::Ds)
27
- A_SHARP_MINOR = Key.minor_sharp(PitchClasses::As)
28
-
29
- D_MINOR = Key.minor_flat(PitchClasses::D)
30
- G_MINOR = Key.minor_flat(PitchClasses::G)
31
- C_MINOR = Key.minor_flat(PitchClasses::C)
32
- F_MINOR = Key.minor_flat(PitchClasses::F)
33
- B_FLAT_MINOR = Key.minor_flat(PitchClasses::Bb)
34
- E_FLAT_MINOR = Key.minor_flat(PitchClasses::Eb)
35
- A_FLAT_MINOR = Key.minor_flat(PitchClasses::Ab)
3
+ C_MAJOR = Key.major(PitchClasses::C)
4
+
5
+ # Major keys with sharps
6
+ G_MAJOR = Key.major(PitchClasses::G)
7
+ D_MAJOR = Key.major(PitchClasses::D)
8
+ A_MAJOR = Key.major(PitchClasses::A)
9
+ E_MAJOR = Key.major(PitchClasses::E)
10
+ B_MAJOR = Key.major(PitchClasses::B)
11
+
12
+ # Major keys with flats
13
+ F_MAJOR = Key.major(PitchClasses::F)
14
+ Bb_MAJOR = Key.major(PitchClasses::Bb)
15
+ Eb_MAJOR = Key.major(PitchClasses::Eb)
16
+ Ab_MAJOR = Key.major(PitchClasses::Ab)
17
+ Db_MAJOR = Key.major(PitchClasses::Db)
18
+ Gb_MAJOR = Key.major(PitchClasses::Gb)
19
+
20
+ A_MINOR = Key.minor(PitchClasses::A)
21
+
22
+ # Minor keys with sharps
23
+ E_MINOR = Key.minor(PitchClasses::E)
24
+ B_MINOR = Key.minor(PitchClasses::B)
25
+ Fs_MINOR = Key.minor(PitchClasses::Fs)
26
+ Cs_MINOR = Key.minor(PitchClasses::Cs)
27
+ Gs_MINOR = Key.minor(PitchClasses::Gs)
28
+
29
+ # Minor keys with flats
30
+ D_MINOR = Key.minor(PitchClasses::D)
31
+ G_MINOR = Key.minor(PitchClasses::G)
32
+ C_MINOR = Key.minor(PitchClasses::C)
33
+ F_MINOR = Key.minor(PitchClasses::F)
34
+ Bb_MINOR = Key.minor(PitchClasses::Bb)
35
+ Eb_MINOR = Key.minor(PitchClasses::Eb)
36
+ end
37
+
36
38
  end
37
- end
@@ -5,10 +5,10 @@ require 'set'
5
5
  class Note
6
6
  include Packable
7
7
  include Validatable
8
-
8
+
9
9
  attr_reader :pitches, :links, :duration, :marks
10
10
  attr_accessor :articulation
11
-
11
+
12
12
  def initialize duration, pitches = [], links: {}, articulation: Articulations::NORMAL, marks: []
13
13
  self.duration = duration
14
14
  if !pitches.is_a? Enumerable
@@ -19,18 +19,24 @@ class Note
19
19
  @articulation = articulation
20
20
  @marks = marks
21
21
  end
22
-
22
+
23
23
  def check_methods
24
- [ :check_pitches ]
24
+ [ :check_duration, :check_pitches ]
25
+ end
26
+
27
+ def check_duration
28
+ if duration <= 0
29
+ raise RangeError, "Duration is non-positive: #{duration}"
30
+ end
25
31
  end
26
-
32
+
27
33
  def check_pitches
28
34
  non_pitches = @pitches.select {|p| !p.is_a?(Pitch) }
29
35
  if non_pitches.any?
30
36
  raise TypeError, "Found non-pitches: #{non_pitches}"
31
37
  end
32
38
  end
33
-
39
+
34
40
  def == other
35
41
  return (@duration == other.duration) &&
36
42
  (self.pitches == other.pitches) &&
@@ -38,7 +44,7 @@ class Note
38
44
  (@articulation == other.articulation) &&
39
45
  (@marks == marks)
40
46
  end
41
-
47
+
42
48
  def clone
43
49
  Marshal.load(Marshal.dump(self))
44
50
  end
@@ -55,10 +61,26 @@ class Note
55
61
  return new_note
56
62
  end
57
63
 
64
+ def tie_to pitches
65
+ new_note = self.clone
66
+ if pitches.is_a? Pitch
67
+ pitches = [pitches]
68
+ end
69
+
70
+ pitches.each do |pitch|
71
+ new_note.links[pitch] = Link::Tie.new
72
+ end
73
+ return new_note
74
+ end
75
+
76
+ def mark_accented!
77
+ @articulation = Articulations::ACCENT
78
+ end
79
+
58
80
  def transpose diff
59
81
  self.clone.transpose! diff
60
82
  end
61
-
83
+
62
84
  def transpose! diff
63
85
  @pitches = @pitches.map {|pitch| pitch.transpose(diff) }
64
86
  @links = Hash[ @links.map do |k,v|
@@ -106,7 +128,7 @@ class Note
106
128
  Note.new(dur, pitches, articulation: articulation, links: links, marks: marks)
107
129
  end
108
130
  end
109
-
131
+
110
132
  {
111
133
  :sixteenth => Rational(1,16),
112
134
  :dotted_sixteenth => Rational(3,32),
@@ -13,9 +13,9 @@ module Musicality
13
13
  # @author James Tunnell
14
14
  #
15
15
  # @!attribute [r] octave
16
- # @return [Fixnum] The pitch octave.
16
+ # @return [Integer] The pitch octave.
17
17
  # @!attribute [r] semitone
18
- # @return [Fixnum] The pitch semitone.
18
+ # @return [Integer] The pitch semitone.
19
19
  #
20
20
  class Pitch
21
21
  include Comparable
@@ -5,13 +5,19 @@ module Musicality
5
5
  CONVERSION_METHOD = :to_r
6
6
  include Parseable
7
7
  end
8
-
8
+
9
9
  class Pitch
10
10
  PARSER = Parsing::PitchParser.new
11
11
  CONVERSION_METHOD = :to_pitch
12
12
  include Parseable
13
13
  end
14
-
14
+
15
+ class Key
16
+ PARSER = Parsing::KeyParser.new
17
+ CONVERSION_METHOD = :to_key
18
+ include Parseable
19
+ end
20
+
15
21
  class Note
16
22
  PARSER = Parsing::NoteParser.new
17
23
  CONVERSION_METHOD = :to_note
@@ -23,7 +29,7 @@ module Musicality
23
29
  CONVERSION_METHOD = :to_meter
24
30
  include Parseable
25
31
  end
26
-
32
+
27
33
  class Segment
28
34
  PARSER = Parsing::SegmentParser.new
29
35
  CONVERSION_METHOD = :to_range
@@ -37,38 +43,43 @@ class String
37
43
  end
38
44
  alias :to_dur :to_duration
39
45
  alias :to_d :to_duration
40
-
46
+
41
47
  def to_durations pattern=" "
42
48
  Musicality::Duration.split_parse(self, pattern)
43
49
  end
44
50
  alias :to_durs :to_durations
45
51
  alias :to_ds :to_durations
46
-
47
- def to_pitch
52
+
53
+ def to_pitch
48
54
  Musicality::Pitch.parse(self)
49
55
  end
50
56
  alias :to_p :to_pitch
51
-
57
+
52
58
  def to_pitches pattern=" "
53
59
  Musicality::Pitch.split_parse(self, pattern)
54
60
  end
55
61
  alias :to_ps :to_pitches
56
-
62
+
63
+ def to_key
64
+ Musicality::Key.parse(self)
65
+ end
66
+ alias :to_k :to_key
67
+
57
68
  def to_note
58
69
  Musicality::Note.parse(self)
59
70
  end
60
71
  alias :to_n :to_note
61
-
72
+
62
73
  def to_notes pattern=" "
63
74
  Musicality::Note.split_parse(self, pattern)
64
75
  end
65
76
  alias :to_ns :to_notes
66
-
77
+
67
78
  def to_meter
68
79
  Musicality::Meter.parse(self)
69
80
  end
70
-
81
+
71
82
  def to_segment
72
83
  Musicality::Segment.parse(self)
73
84
  end
74
- end
85
+ end
@@ -80,7 +80,7 @@ module Duration
80
80
  r2 = true
81
81
  @index += match_len
82
82
  else
83
- terminal_parse_failure("/")
83
+ terminal_parse_failure('"/"')
84
84
  r2 = nil
85
85
  end
86
86
  s0 << r2
@@ -128,7 +128,7 @@ module Duration
128
128
  r3 = true
129
129
  @index += match_len
130
130
  else
131
- terminal_parse_failure("/")
131
+ terminal_parse_failure('"/"')
132
132
  r3 = nil
133
133
  end
134
134
  if r3
@@ -173,7 +173,7 @@ module Duration
173
173
  r1 = true
174
174
  @index += match_len
175
175
  else
176
- terminal_parse_failure("/")
176
+ terminal_parse_failure('"/"')
177
177
  r1 = nil
178
178
  end
179
179
  s0 << r1
@@ -0,0 +1,150 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+
4
+ module Musicality
5
+ module Parsing
6
+
7
+ module Key
8
+ include Treetop::Runtime
9
+
10
+ def root
11
+ @root ||= :key
12
+ end
13
+
14
+ include Pitch
15
+
16
+ module Key0
17
+ def pitch_letter
18
+ elements[0]
19
+ end
20
+
21
+ def mod
22
+ elements[1]
23
+ end
24
+
25
+ def major_minor
26
+ elements[2]
27
+ end
28
+ end
29
+
30
+ module Key1
31
+ def to_key
32
+ sem = pitch_letter.to_semitone
33
+ modval = 0
34
+ if !mod.empty?
35
+ modval = case mod.text_value
36
+ when "#" then 1
37
+ when "b" then -1
38
+ end
39
+ end
40
+
41
+ triad_type = if major_minor.text_value.include?("maj")
42
+ Musicality::Key::MAJOR
43
+ else
44
+ Musicality::Key::MINOR
45
+ end
46
+
47
+ return Musicality::Key.new(sem + modval, triad_type: triad_type)
48
+ end
49
+ end
50
+
51
+ def _nt_key
52
+ start_index = index
53
+ if node_cache[:key].has_key?(index)
54
+ cached = node_cache[:key][index]
55
+ if cached
56
+ node_cache[:key][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
57
+ @index = cached.interval.end
58
+ end
59
+ return cached
60
+ end
61
+
62
+ i0, s0 = index, []
63
+ r1 = _nt_pitch_letter
64
+ s0 << r1
65
+ if r1
66
+ if has_terminal?(@regexps[gr = '\A[#b]'] ||= Regexp.new(gr), :regexp, index)
67
+ r3 = true
68
+ @index += 1
69
+ else
70
+ terminal_parse_failure('[#b]')
71
+ r3 = nil
72
+ end
73
+ if r3
74
+ r2 = r3
75
+ else
76
+ r2 = instantiate_node(SyntaxNode,input, index...index)
77
+ end
78
+ s0 << r2
79
+ if r2
80
+ r4 = _nt_major_minor
81
+ s0 << r4
82
+ end
83
+ end
84
+ if s0.last
85
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
86
+ r0.extend(Key0)
87
+ r0.extend(Key1)
88
+ else
89
+ @index = i0
90
+ r0 = nil
91
+ end
92
+
93
+ node_cache[:key][start_index] = r0
94
+
95
+ r0
96
+ end
97
+
98
+ def _nt_major_minor
99
+ start_index = index
100
+ if node_cache[:major_minor].has_key?(index)
101
+ cached = node_cache[:major_minor][index]
102
+ if cached
103
+ node_cache[:major_minor][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
104
+ @index = cached.interval.end
105
+ end
106
+ return cached
107
+ end
108
+
109
+ i0 = index
110
+ if (match_len = has_terminal?("maj", false, index))
111
+ r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
112
+ @index += match_len
113
+ else
114
+ terminal_parse_failure('"maj"')
115
+ r1 = nil
116
+ end
117
+ if r1
118
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
119
+ r0 = r1
120
+ else
121
+ if (match_len = has_terminal?("min", false, index))
122
+ r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
123
+ @index += match_len
124
+ else
125
+ terminal_parse_failure('"min"')
126
+ r2 = nil
127
+ end
128
+ if r2
129
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
130
+ r0 = r2
131
+ else
132
+ @index = i0
133
+ r0 = nil
134
+ end
135
+ end
136
+
137
+ node_cache[:major_minor][start_index] = r0
138
+
139
+ r0
140
+ end
141
+
142
+ end
143
+
144
+ class KeyParser < Treetop::Runtime::CompiledParser
145
+ include Key
146
+ end
147
+
148
+
149
+ end
150
+ end
@@ -0,0 +1,37 @@
1
+ module Musicality
2
+ module Parsing
3
+
4
+ grammar Key
5
+ include Pitch
6
+
7
+ rule key
8
+ pitch_letter mod:[#b]? major_minor {
9
+ def to_key
10
+ sem = pitch_letter.to_semitone
11
+ modval = 0
12
+ if !mod.empty?
13
+ modval = case mod.text_value
14
+ when "#" then 1
15
+ when "b" then -1
16
+ end
17
+ end
18
+
19
+ triad_type = if major_minor.text_value.include?("maj")
20
+ Musicality::Key::MAJOR
21
+ else
22
+ Musicality::Key::MINOR
23
+ end
24
+
25
+ return Musicality::Key.new(sem + modval, triad_type: triad_type)
26
+ end
27
+ }
28
+ end
29
+
30
+ rule major_minor
31
+ "maj" / "min"
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -80,7 +80,7 @@ module Meter
80
80
  r2 = true
81
81
  @index += match_len
82
82
  else
83
- terminal_parse_failure("/")
83
+ terminal_parse_failure('"/"')
84
84
  r2 = nil
85
85
  end
86
86
  s0 << r2
@@ -142,7 +142,7 @@ module Meter
142
142
  r2 = true
143
143
  @index += match_len
144
144
  else
145
- terminal_parse_failure("*")
145
+ terminal_parse_failure('"*"')
146
146
  r2 = nil
147
147
  end
148
148
  s0 << r2
@@ -154,7 +154,7 @@ module Meter
154
154
  r4 = true
155
155
  @index += match_len
156
156
  else
157
- terminal_parse_failure("/")
157
+ terminal_parse_failure('"/"')
158
158
  r4 = nil
159
159
  end
160
160
  s0 << r4
@@ -36,12 +36,14 @@ module NonnegativeFloat
36
36
  r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
37
37
  r0 = r1
38
38
  r0.extend(NonnegativeFloat0)
39
+ r0.extend(NonnegativeFloat0)
39
40
  else
40
41
  r2 = _nt_float2
41
42
  if r2
42
43
  r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
43
44
  r0 = r2
44
45
  r0.extend(NonnegativeFloat0)
46
+ r0.extend(NonnegativeFloat0)
45
47
  else
46
48
  @index = i0
47
49
  r0 = nil
@@ -222,7 +224,7 @@ module NonnegativeFloat
222
224
  r1 = true
223
225
  @index += match_len
224
226
  else
225
- terminal_parse_failure("e")
227
+ terminal_parse_failure('"e"')
226
228
  r1 = nil
227
229
  end
228
230
  s0 << r1