stretto 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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