stretto 0.6.1

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 (77) hide show
  1. data/CHANGELOG.markdown +0 -0
  2. data/README.markdown +67 -0
  3. data/Rakefile +9 -0
  4. data/lib/stretto.rb +14 -0
  5. data/lib/stretto/grammar/channel_pressure_grammar.treetop +9 -0
  6. data/lib/stretto/grammar/chord_grammar.treetop +60 -0
  7. data/lib/stretto/grammar/controller_change_grammar.treetop +9 -0
  8. data/lib/stretto/grammar/duration_grammar.treetop +60 -0
  9. data/lib/stretto/grammar/grammar_helper.rb +6 -0
  10. data/lib/stretto/grammar/harmonic_chord_grammar.treetop +15 -0
  11. data/lib/stretto/grammar/harmony_grammar.treetop +15 -0
  12. data/lib/stretto/grammar/instrument_grammar.treetop +9 -0
  13. data/lib/stretto/grammar/key_signature_grammar.treetop +10 -0
  14. data/lib/stretto/grammar/layer_change_grammar.treetop +9 -0
  15. data/lib/stretto/grammar/measure_grammar.treetop +7 -0
  16. data/lib/stretto/grammar/note_grammar.treetop +32 -0
  17. data/lib/stretto/grammar/pitch_bend_grammar.treetop +7 -0
  18. data/lib/stretto/grammar/polyphonic_pressure_grammar.treetop +9 -0
  19. data/lib/stretto/grammar/rest_grammar.treetop +9 -0
  20. data/lib/stretto/grammar/stretto_grammar.treetop +62 -0
  21. data/lib/stretto/grammar/tempo_grammar.treetop +9 -0
  22. data/lib/stretto/grammar/timing_grammar.treetop +9 -0
  23. data/lib/stretto/grammar/tokens/attack_decay_token.rb +42 -0
  24. data/lib/stretto/grammar/tokens/chord_token.rb +67 -0
  25. data/lib/stretto/grammar/tokens/controller_change_token.rb +26 -0
  26. data/lib/stretto/grammar/tokens/duration_token.rb +55 -0
  27. data/lib/stretto/grammar/tokens/harmonic_chord_token.rb +25 -0
  28. data/lib/stretto/grammar/tokens/harmony_with_melody_token.rb +66 -0
  29. data/lib/stretto/grammar/tokens/hash_token.rb +15 -0
  30. data/lib/stretto/grammar/tokens/key_signature_token.rb +30 -0
  31. data/lib/stretto/grammar/tokens/measure_token.rb +21 -0
  32. data/lib/stretto/grammar/tokens/modifier_token.rb +99 -0
  33. data/lib/stretto/grammar/tokens/note_string_token.rb +106 -0
  34. data/lib/stretto/grammar/tokens/note_token.rb +25 -0
  35. data/lib/stretto/grammar/tokens/pattern_token.rb +26 -0
  36. data/lib/stretto/grammar/tokens/polyphonic_pressure_token.rb +28 -0
  37. data/lib/stretto/grammar/tokens/rest_token.rb +21 -0
  38. data/lib/stretto/grammar/tokens/value_token.rb +28 -0
  39. data/lib/stretto/grammar/tokens/variable_definition_token.rb +30 -0
  40. data/lib/stretto/grammar/value_grammar.treetop +45 -0
  41. data/lib/stretto/grammar/variable_grammar.treetop +10 -0
  42. data/lib/stretto/grammar/voice_change_grammar.treetop +9 -0
  43. data/lib/stretto/music_elements/channel_pressure.rb +44 -0
  44. data/lib/stretto/music_elements/chord.rb +194 -0
  45. data/lib/stretto/music_elements/controller_change.rb +49 -0
  46. data/lib/stretto/music_elements/harmonic_chord.rb +56 -0
  47. data/lib/stretto/music_elements/harmony.rb +37 -0
  48. data/lib/stretto/music_elements/instrument.rb +57 -0
  49. data/lib/stretto/music_elements/key_signature.rb +110 -0
  50. data/lib/stretto/music_elements/layer.rb +22 -0
  51. data/lib/stretto/music_elements/layer_change.rb +39 -0
  52. data/lib/stretto/music_elements/measure.rb +38 -0
  53. data/lib/stretto/music_elements/melody.rb +72 -0
  54. data/lib/stretto/music_elements/modifiers/attack_decay.rb +55 -0
  55. data/lib/stretto/music_elements/modifiers/chord_intervals.rb +44 -0
  56. data/lib/stretto/music_elements/modifiers/duration.rb +180 -0
  57. data/lib/stretto/music_elements/modifiers/value.rb +172 -0
  58. data/lib/stretto/music_elements/modifiers/variables.rb +365 -0
  59. data/lib/stretto/music_elements/music_element.rb +88 -0
  60. data/lib/stretto/music_elements/note.rb +282 -0
  61. data/lib/stretto/music_elements/pattern.rb +100 -0
  62. data/lib/stretto/music_elements/pitch_bend.rb +46 -0
  63. data/lib/stretto/music_elements/polyphonic_pressure.rb +62 -0
  64. data/lib/stretto/music_elements/rest.rb +26 -0
  65. data/lib/stretto/music_elements/tempo.rb +42 -0
  66. data/lib/stretto/music_elements/timing.rb +33 -0
  67. data/lib/stretto/music_elements/variable.rb +49 -0
  68. data/lib/stretto/music_elements/voice.rb +49 -0
  69. data/lib/stretto/music_elements/voice_change.rb +39 -0
  70. data/lib/stretto/parsers/exceptions.rb +11 -0
  71. data/lib/stretto/parsers/parser.rb +89 -0
  72. data/lib/stretto/renderers/midiator/player.rb +200 -0
  73. data/lib/stretto/util/jfugue_format_parser.rb +20 -0
  74. data/lib/stretto/util/node.rb +5 -0
  75. data/lib/stretto/util/utils.rb +41 -0
  76. data/lib/stretto/version.rb +3 -0
  77. metadata +203 -0
@@ -0,0 +1,9 @@
1
+ grammar TempoGrammar
2
+
3
+ include ValueGrammar
4
+
5
+ rule tempo
6
+ kind:'T' __value:variable_or_integer <Stretto::Tokens::TempoToken>
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ grammar TimingGrammar
2
+
3
+ include ValueGrammar
4
+
5
+ rule timing
6
+ kind:'@' __value:variable_or_integer <Stretto::Tokens::TimingToken>
7
+ end
8
+
9
+ end
@@ -0,0 +1,42 @@
1
+ module Stretto
2
+ module Tokens
3
+
4
+ # Token result from parsing attack and decay syntax
5
+ #
6
+ # @example "a100d[VAR]"
7
+ class AttackDecayToken < Treetop::Runtime::SyntaxNode
8
+
9
+ # @return [NumericToken, VariableToken, nil]
10
+ def attack
11
+ _attack.value.wrap if _attack and _attack.text_value.present?
12
+ end
13
+
14
+ # @return [NumericToken, VariableToken, nil]
15
+ def decay
16
+ _decay.value.wrap if _decay and _decay.text_value.present?
17
+ end
18
+
19
+ end
20
+
21
+
22
+ # Include this module to access functionality of attack and decay tokens
23
+ #
24
+ # @see #attack
25
+ # @see #decay
26
+ module WithAttackDecayToken
27
+
28
+ # @return [Value, nil] The attack value wrapped by a Value object, or nil
29
+ def attack
30
+ attack = attack_and_decay.attack
31
+ Stretto::Value.new(attack)
32
+ end
33
+
34
+ # @return [Value, nil] The decay value wrapped by a Value object, or nil
35
+ def decay
36
+ decay = attack_and_decay.decay
37
+ Stretto::Value.new(decay)
38
+ end
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,67 @@
1
+ require File.join(File.dirname(__FILE__), 'duration_token')
2
+ require File.join(File.dirname(__FILE__), 'note_string_token')
3
+ require File.join(File.dirname(__FILE__), 'attack_decay_token')
4
+ require File.join(File.dirname(__FILE__), '../../music_elements/chord')
5
+
6
+ module Stretto
7
+ module Tokens
8
+
9
+ # Parses a named chord
10
+ #
11
+ # @example: "C5#maj"
12
+ class ChordToken < HashToken
13
+
14
+ include WithDurationToken
15
+ include WithNoteStringToken
16
+ include WithAttackDecayToken
17
+
18
+ # @return [MusicElements::Chord] The constructed Chord element
19
+ def to_stretto(pattern = nil)
20
+ Stretto::MusicElements::Chord.new(self, pattern)
21
+ end
22
+
23
+ # Returns a base note hash, which can be seen as a token returned by the
24
+ # parsed note
25
+ def base_note
26
+ {
27
+ :text_value => note_string.text_value,
28
+ :key => key,
29
+ :pitch => pitch,
30
+ :accidental => accidental,
31
+ :octave => octave,
32
+ :attack => attack,
33
+ :decay => decay,
34
+ :duration => duration
35
+ }
36
+ end
37
+
38
+ # @return [NoteStringToken]
39
+ def note_string
40
+ __note_string
41
+ end
42
+
43
+ # @return A string containing the named chord
44
+ # @example "sus4"
45
+ def named_chord
46
+ __named_chord.text_value
47
+ end
48
+
49
+ # If inversions are present, return a hash containing the pivot note
50
+ # (e.g. "^C") or the number of inversions (e.g. 5)
51
+ def inversions
52
+ if __chord_inversions and __chord_inversions.text_value.present?
53
+ { :inversions => __chord_inversions.inversions,
54
+ :pivot_note => __chord_inversions.pivot_note }
55
+ end
56
+ end
57
+
58
+ # Don't precalculate values. Added for harmonic chords to be able to be
59
+ # constructed from a chord token.
60
+ # @private
61
+ def notes
62
+ nil
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), '../../music_elements/controller_change')
2
+
3
+ module Stretto
4
+ module Tokens
5
+
6
+ # Token result from parsing a controller change
7
+ class ControllerChangeToken < HashToken
8
+
9
+ # @return [MusicElements::ControllerChange]
10
+ def to_stretto(pattern)
11
+ Stretto::MusicElements::ControllerChange.new(self, pattern)
12
+ end
13
+
14
+ # @return [Value]
15
+ def controller
16
+ Value.new(__controller.wrap)
17
+ end
18
+
19
+ # @return [Value]
20
+ def value
21
+ Value.new(__value.wrap)
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,55 @@
1
+ module Stretto
2
+ module Tokens
3
+
4
+ # Token result from parsing a duration
5
+ #
6
+ # @example "wh", "q*3:4", "/2.5"
7
+ class DurationToken < Treetop::Runtime::SyntaxNode
8
+
9
+ # @return [true, false] if the duration starts a tie (e.g., "w-")
10
+ def start_of_tie?
11
+ _start_of_tie.text_value.present? if _start_of_tie
12
+ end
13
+
14
+ # @return [true, false] if the duration ends a tie (e.g., "-w")
15
+ def end_of_tie?
16
+ _end_of_tie.text_value.present? if _end_of_tie
17
+ end
18
+
19
+ # @return [Hash, nil] A hash containing both the numerator and denominator, if present
20
+ # @example { :numerator => 2, :denominator => 3 }
21
+ def tuplet
22
+ if duration_string.tuplet
23
+ {:numerator => duration_string.tuplet.numerator,
24
+ :denominator => duration_string.tuplet.denominator}
25
+ end
26
+ end
27
+
28
+ # @return [String] The duration expressed as characters
29
+ # @example "h", "wq"
30
+ def duration_character
31
+ duration_string.duration_character
32
+ end
33
+
34
+ # @return [Value, nil] A value wrapping the value of the duration, if present
35
+ def value
36
+ Stretto::Value.new(duration_string.value.wrap) if duration_string.value
37
+ end
38
+
39
+ # @return [String] Returns a string with the number of dots in the duration
40
+ # @example 2 (for string Cmajh..
41
+ def dots
42
+ duration_string.dots
43
+ end
44
+
45
+ end
46
+
47
+ # Include this module to obtain functionality for duration token
48
+ module WithDurationToken
49
+ def duration
50
+ __duration if __duration and __duration.text_value.present?
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__), '/../../music_elements/harmonic_chord')
2
+
3
+ module Stretto
4
+ module Tokens
5
+
6
+ # Token result from parsing a duration
7
+ #
8
+ # @example "C+D+E"
9
+ class HarmonicChordToken < HashToken
10
+
11
+ # @return [MusicElements::HarmonicChord] The constructed HarmonicChord element
12
+ def to_stretto(pattern = nil)
13
+ @pattern = pattern
14
+ Stretto::MusicElements::HarmonicChord.new(self, pattern)
15
+ end
16
+
17
+ # @return [Array<MusicElement>] The notes that form this chord
18
+ def notes
19
+ [_first_element.to_stretto(@pattern)] +
20
+ _other_elements.elements.map{|element| element._element.to_stretto(@pattern)}
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ require File.join(File.dirname(__FILE__), '../../music_elements/harmony')
2
+ require File.join(File.dirname(__FILE__), '../../music_elements/melody')
3
+
4
+ module Stretto
5
+ module Tokens
6
+
7
+ # Token result from parsing a harmony
8
+ #
9
+ # @example "Cmajh+Dh_+Ew"
10
+ class HarmonyWithMelodyToken < HashToken
11
+
12
+
13
+ # @return [MusicElements::Harmony, MusicElements::Melody] Returns the constructed
14
+ # Harmony or Melody object. It is a Harmony when there is more than one element
15
+ # (e.g. "A+B_C")
16
+ def to_stretto(pattern = nil)
17
+ @pattern = pattern
18
+ music_elements = harmony_elements(pattern)
19
+ if music_elements.size == 1 and music_elements.first.kind_of?(Stretto::MusicElements::Melody)
20
+ music_elements.first
21
+ else
22
+ Stretto::MusicElements::Harmony.new(self, pattern)
23
+ end
24
+ end
25
+
26
+ # @return [Array(MusicElements::MusicElement)] AN array of the music elements that form the harmony
27
+ def music_elements
28
+ @music_elements ||= harmony_elements(@pattern)
29
+ end
30
+
31
+ private
32
+
33
+ # Builds the Melody objects or the single elements that form a harmony
34
+ #-
35
+ # TODO: This can be refactored, even return the melodies directly from the token
36
+ def harmony_elements(pattern)
37
+ elements = [_first_element.to_stretto]
38
+ original_strings = [_first_element.text_value]
39
+ _other_elements.elements.each do |e|
40
+ element = e._element.to_stretto
41
+ case e._sep.text_value
42
+ when '_'
43
+ elements << [elements.pop] unless elements.last.kind_of?(Array)
44
+ elements.last << element
45
+ original_strings[-1] += element.original_string
46
+ when '+'
47
+ elements << element
48
+ original_strings << element.original_string
49
+ end
50
+ end
51
+ elements.zip(original_strings).map do |element, string|
52
+ if element.kind_of?(Array)
53
+ Stretto::MusicElements::Melody.new(
54
+ { :original_string => string,
55
+ :elements => element },
56
+ pattern
57
+ )
58
+ else
59
+ element
60
+ end
61
+ end
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
1
+ module Stretto
2
+ module Tokens
3
+
4
+ # Subclass of a parser token that overrides the #[] method to act like a Hash
5
+ class HashToken < Treetop::Runtime::SyntaxNode
6
+
7
+ # Quack like a hash. This is to make the individual element constructor accept either a hash
8
+ # or a token
9
+ def [](key)
10
+ send(key)
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), '../../music_elements/key_signature')
2
+
3
+ module Stretto
4
+ module Tokens
5
+
6
+ # Token result from parsing a key signature
7
+ #
8
+ # @example "KGmaj"
9
+ class KeySignatureToken < HashToken
10
+
11
+ # @return [MusicElements::KeySignature] The constructed token
12
+ def to_stretto(pattern = nil)
13
+ Stretto::MusicElements::KeySignature.new(self, pattern)
14
+ end
15
+
16
+ # @return A string with the key
17
+ # @example "C#"
18
+ def key
19
+ __note_key.text_value
20
+ end
21
+
22
+ # @return ['maj', 'min'] The scale of the key signature
23
+ def scale
24
+ __scale.text_value
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__), '../../music_elements/measure')
2
+
3
+ module Stretto
4
+ module Tokens
5
+
6
+ # Token result from parsing a measure
7
+ #
8
+ #-
9
+ # Right now, the only supported measure is "|"
10
+ # TODO: Add support for other measures? (Repeat signs, codas, etc.)
11
+ class MeasureToken < HashToken
12
+
13
+ # @return [MusicElements::Measure] The constructed Measure element
14
+ def to_stretto(pattern = nil)
15
+ Stretto::MusicElements::Measure.new(self, pattern)
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,99 @@
1
+ require File.join(File.dirname(__FILE__), '../../music_elements/modifiers/value')
2
+ require File.join(File.dirname(__FILE__), '../../music_elements/instrument')
3
+ require File.join(File.dirname(__FILE__), '../../music_elements/voice_change')
4
+ require File.join(File.dirname(__FILE__), '../../music_elements/layer_change')
5
+ require File.join(File.dirname(__FILE__), '../../music_elements/tempo')
6
+ require File.join(File.dirname(__FILE__), '../../music_elements/pitch_bend')
7
+ require File.join(File.dirname(__FILE__), '../../music_elements/channel_pressure')
8
+ require File.join(File.dirname(__FILE__), '../../music_elements/timing')
9
+
10
+ module Stretto
11
+ module Tokens
12
+
13
+ # Token result from parsing a modifier token.
14
+ # This encloses all elements that are constructed by a single character and a value.
15
+ # Refer to individual class to see the MusicElement generated from this token
16
+ #
17
+ # @example "I40". "T[ALLEGRO]", "@2000"
18
+ class ModifierToken < HashToken
19
+
20
+ # Returns an element of class KLASS
21
+ # @abstract
22
+ # @return [MusicElements::MusicElement]
23
+ # @see ModifierToken::KLASS
24
+ def to_stretto(pattern = nil)
25
+ self.class::KLASS.new(self, pattern)
26
+ end
27
+
28
+ # @return [Value] A Value object wrapping the value of the modifier
29
+ def value
30
+ Value.new(__value.wrap)
31
+ end
32
+
33
+ end
34
+
35
+ # Token result from parsing an instrument
36
+ #
37
+ # @example "I[FLUTE]"
38
+ class InstrumentToken < ModifierToken
39
+
40
+ # @private
41
+ KLASS = Stretto::MusicElements::Instrument
42
+ end
43
+
44
+ # Token result from parsing a voice
45
+ #
46
+ # @example "V10"
47
+ class VoiceChangeToken < ModifierToken
48
+
49
+ # @private
50
+ KLASS = Stretto::MusicElements::VoiceChange
51
+ end
52
+
53
+ # Token result from parsing a layer
54
+ #
55
+ # @example "L5"
56
+ class LayerChangeToken < ModifierToken
57
+
58
+ # @private
59
+ KLASS = Stretto::MusicElements::LayerChange
60
+ end
61
+
62
+ # Token result from parsing a tempo
63
+ #
64
+ # @example "T200", "T[ALLEGRO]"
65
+ class TempoToken < ModifierToken
66
+
67
+ # @private
68
+ KLASS = Stretto::MusicElements::Tempo
69
+ end
70
+
71
+ # Token result from parsing a pitch bend
72
+ #
73
+ # @example "&9001"
74
+ class PitchBendToken < ModifierToken
75
+
76
+ # @private
77
+ KLASS = Stretto::MusicElements::PitchBend
78
+ end
79
+
80
+ # Token result from parsing a channel pressure
81
+ #
82
+ # @example "+80"
83
+ class ChannelPressureToken < ModifierToken
84
+
85
+ # @private
86
+ KLASS = Stretto::MusicElements::ChannelPressure
87
+ end
88
+
89
+ # Token result from parsing a timing indication
90
+ #
91
+ # @example "@2000"
92
+ class TimingToken < ModifierToken
93
+
94
+ # @private
95
+ KLASS = Stretto::MusicElements::Timing
96
+ end
97
+
98
+ end
99
+ end