jazz_model 0.1.0 → 0.2.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +187 -0
  4. data/db/schema.rb +83 -0
  5. data/lib/jazz_model/base.rb +13 -6
  6. data/lib/jazz_model/chord.rb +50 -70
  7. data/lib/jazz_model/chord_collection.rb +21 -45
  8. data/lib/jazz_model/chord_quality.rb +5 -6
  9. data/lib/jazz_model/chord_scale.rb +13 -13
  10. data/lib/jazz_model/chord_symbol.rb +14 -12
  11. data/lib/jazz_model/chord_symbol_collection.rb +3 -10
  12. data/lib/jazz_model/chord_tone.rb +20 -21
  13. data/lib/jazz_model/definition.rb +18 -18
  14. data/lib/jazz_model/definitions/default.rb +316 -321
  15. data/lib/jazz_model/definitions/keys.rb +36 -36
  16. data/lib/jazz_model/definitions.rb +3 -0
  17. data/lib/jazz_model/key.rb +22 -25
  18. data/lib/jazz_model/key_context.rb +31 -22
  19. data/lib/jazz_model/mode.rb +30 -35
  20. data/lib/jazz_model/mode_context.rb +22 -26
  21. data/lib/jazz_model/mode_sequence.rb +13 -12
  22. data/lib/jazz_model/notes_collection.rb +64 -71
  23. data/lib/jazz_model/scale.rb +63 -85
  24. data/lib/jazz_model/scale_tone.rb +14 -15
  25. data/lib/jazz_model/tone.rb +47 -48
  26. data/lib/jazz_model/tone_sequence.rb +56 -58
  27. data/lib/jazz_model/version.rb +2 -2
  28. data/lib/jazz_model/voicing.rb +6 -7
  29. data/lib/jazz_model/voicing_tone.rb +5 -6
  30. data/lib/jazz_model.rb +7 -10
  31. metadata +104 -141
  32. data/CHANGELOG.rdoc +0 -14
  33. data/Gemfile +0 -4
  34. data/README.rdoc +0 -186
  35. data/Rakefile +0 -14
  36. data/lib/jazz_model/note_sequence.rb +0 -15
  37. data/spec/chord_collection_spec.rb +0 -21
  38. data/spec/chord_quality_spec.rb +0 -27
  39. data/spec/chord_scale_spec.rb +0 -7
  40. data/spec/chord_spec.rb +0 -29
  41. data/spec/chord_symbol_spec.rb +0 -6
  42. data/spec/chord_tone_spec.rb +0 -6
  43. data/spec/definition_spec.rb +0 -35
  44. data/spec/key_context_spec.rb +0 -27
  45. data/spec/key_spec.rb +0 -15
  46. data/spec/mode_spec.rb +0 -9
  47. data/spec/notes_collection_spec.rb +0 -25
  48. data/spec/scale_spec.rb +0 -42
  49. data/spec/scale_tone_spec.rb +0 -6
  50. data/spec/spec_helper.rb +0 -12
  51. data/spec/tone_sequence_spec.rb +0 -17
  52. data/spec/tone_spec.rb +0 -4
  53. data/spec/voicing_spec.rb +0 -6
  54. data/spec/voicing_tone_spec.rb +0 -6
@@ -1,136 +1,114 @@
1
1
  module JazzModel
2
2
  # A scale is an ordered collection of tones.
3
- #
3
+ #
4
4
  # == Creating a Scale
5
- #
5
+ #
6
6
  # Scale objects should be created by indexing the +Scale+ class directly:
7
- #
7
+ #
8
8
  # Scale['Major']
9
- #
10
- # An alternative method of resolving a chord is to use the +resolve+ method,
9
+ #
10
+ # An alternative method of resolving a chord is to use the +resolve+ method,
11
11
  # though this is likely to become deprecated in the future when chord progression
12
12
  # support/representation is added:
13
13
  #
14
14
  # Scale.resolve(name)
15
15
  #
16
16
  # == Associations
17
- #
17
+ #
18
18
  # * +modes+ - Associated modes.
19
- # * +main_mode+ - Associated mode with a mode index of 1 (first mode). This sometimes
19
+ # * +main_mode+ - Associated mode with a mode index of 1 (first mode). This sometimes
20
20
  # the only defined mode such as for the whole tone scale.
21
21
  # * +tones+ - A collection of +ScaleTone+s.
22
22
  # * +notes+ - An array of notes (delegated through +tones+)
23
23
  # * +chords+ - A collection of associated chords with the first mode of this scale.
24
- #
24
+ #
25
25
  # == Modes
26
- #
27
- # Each scale can have one or many modes, which really define the relationship to chords.
26
+ #
27
+ # Each scale can have one or many modes, which really define the relationship to chords.
28
28
  # Modes are accessible like so (all methods are equal):
29
- #
29
+ #
30
30
  # Scale['Major']['Dorian']
31
31
  # Scale['Major'][2]
32
32
  # Scale['Major'].modes['Dorian']
33
33
  # Scale['Major'].modes[2]
34
- #
34
+ #
35
35
  # == Examples
36
- #
36
+ #
37
37
  # === Listing Tones in Scales
38
- #
38
+ #
39
39
  # Scale['Major'].notes
40
40
  # # => ["C", "D", "E", "F", "G", "A", "B"]
41
- #
41
+ #
42
42
  # Scale['Major'].in_key_of('Eb').notes
43
43
  # Scale['Eb Major'].notes # Same as above
44
44
  # # => ["Eb", "F", "G", "Ab", "Bb", "C", "D"]
45
- #
45
+ #
46
46
  # === Correctly Interpets Theoretical Keys (not just pitches)
47
- #
47
+ #
48
48
  # Scale['Gb Major'].notes
49
49
  # # => ["Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F"]
50
50
  # # Note the use of Cb which is theoretically correct over enharmonic B.
51
- #
51
+ #
52
52
  # Also correctly interpet tones off of enharmonic base keys:
53
- #
53
+ #
54
54
  # Scale['Gb Major'].notes
55
55
  # # => ["Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F"]
56
56
  # Scale['F# Major'].notes
57
57
  # # => ["F#", "G#", "A#", "B", "C#", "D#", "E#"]
58
- #
58
+ #
59
59
  # === Listing Tones within the context of a mode
60
- #
60
+ #
61
61
  # Scale['Major'].modes['Dorian']
62
62
  # Scale['Major']['Dorian'] # Same as above
63
63
  # # => ["D", "E", "F", "G", "A", "B", "C"]
64
- #
64
+ #
65
65
  # Scale['Melodic Minor'].modes['Super Locrian'].notes
66
66
  # # => ["B", "C", "D", "Eb", "F", "G", "A"] # aka. Altered Scale or Dim. Whole Tone
67
- #
67
+ #
68
68
  # == Listing Related Chords
69
- #
69
+ #
70
70
  # Scale['Major'].chords.symbols
71
71
  # # => ['maj7', 'maj6', '6/9']
72
72
  # Scale['Major']['Dorian'].chords.symbols
73
73
  # # => ['min7', 'min6']
74
- #
74
+ #
75
75
  class Scale < JazzModel::Base
76
- include KeyContext
77
- include ModeContext
78
-
79
- has_many :modes, :extend => ModeSequence, :dependent => :destroy
80
- has_many :tones, :class_name => 'ScaleTone', :extend => ToneSequence, :dependent => :destroy
81
-
82
- delegate :notes, :to => :tones
83
- delegate :chords, :to => :main_mode
84
-
85
- class << self
86
- def resolve(symbol)
87
- in_key = nil
88
-
89
- return nil if symbol.nil?
90
- symbol = symbol.dup
91
-
92
- Key.all.each do |k|
93
- if symbol.starts_with?(k.name)
94
- in_key = k
95
- symbol.gsub!(/^#{k.name}/, '').strip!
96
- break
97
- end
98
- end
99
-
100
- scale = Scale.find_by_name(symbol)
101
-
102
- # Perhaps the matched key was really part of the name of the chord, try that:
103
- if scale.nil? && !in_key.nil?
104
- symbol = in_key.name + symbol
105
- scale = Scale.all.detect {|s| s.name == symbol}
106
- end
107
-
108
- # If still not found, must be invalid:
109
- return nil if scale.nil?
110
-
111
- scale.key = in_key
112
- scale
113
- end
114
- alias_method :[], :resolve
115
- end
116
-
117
- def [](name)
118
- name.is_a?(String) ? self.modes.find_by_name(name) : self.modes.find_by_mode(name)
119
- end
120
-
121
- def main_mode
122
- self[1]
123
- end
124
-
125
- def symmetric?
126
- !self.symmetry_index.nil?
127
- end
128
-
129
-
130
- def to_xml(options = {})
131
- super(options.merge(:skip_types => true))
132
- end
133
-
134
- end
76
+ include KeyContext
77
+ include ModeContext
135
78
 
136
- end
79
+ has_many :modes, extend: ModeSequence, dependent: :destroy
80
+ has_many :tones, class_name: "ScaleTone", extend: ToneSequence, dependent: :destroy
81
+
82
+ delegate :notes, to: :tones
83
+ delegate :chords, to: :main_mode
84
+
85
+ class << self
86
+ # Resolves a scale name, optionally prefixed with a key (such as
87
+ # "Eb Major"), into a scale.
88
+ def resolve(symbol)
89
+ return nil if symbol.nil?
90
+
91
+ KeyContext.each_split(symbol) do |in_key, rest|
92
+ scale = find_by_name(rest) or next
93
+ scale.key = in_key
94
+ return scale
95
+ end
96
+ nil
97
+ end
98
+ alias_method :[], :resolve
99
+ end
100
+
101
+ # Finds a mode of this scale by name or number, passing along key context.
102
+ def [](name)
103
+ modes[name]
104
+ end
105
+
106
+ def main_mode
107
+ self[1]
108
+ end
109
+
110
+ def symmetric?
111
+ !symmetry_index.nil?
112
+ end
113
+ end
114
+ end
@@ -1,24 +1,23 @@
1
1
  module JazzModel
2
- # Represents one tone in a scale.
3
- #
2
+ # Represents one tone in a scale.
3
+ #
4
4
  # == Attributes
5
- #
6
- # * +tone+ - A tone index from 0-11 representing the relative position of the
5
+ #
6
+ # * +tone+ - A tone index from 0-11 representing the relative position of the
7
7
  # tone within the chromatic scale.
8
- #
9
- # * +letter_index+ - A 0-6 value representing the relative letter position, which
8
+ #
9
+ # * +letter_index+ - A 0-6 value representing the relative letter position, which
10
10
  # helps to disambiguate theoretic values such as Eb and D#. See +Key+.
11
- #
11
+ #
12
12
  # == Key Context
13
- #
13
+ #
14
14
  # +key+ is delgated to chord to access the scale's key context.
15
15
  #
16
16
  class ScaleTone < Tone
17
- belongs_to :scale
18
-
19
- acts_as_list :scope => :scale
20
-
21
- delegate :key, :to => :scale
22
-
17
+ belongs_to :scale
18
+
19
+ acts_as_list scope: :scale
20
+
21
+ delegate :key, to: :scale
23
22
  end
24
- end
23
+ end
@@ -1,51 +1,50 @@
1
1
  module JazzModel
2
- # Abstract base class for the concept of a tone.
3
- # Eventually will be expanded with common functionality for
4
- # all tone objects.
5
- #
2
+ # Abstract base class for the concept of a tone.
3
+ # Eventually will be expanded with common functionality for
4
+ # all tone objects.
5
+ #
6
6
  class Tone < JazzModel::Base
7
- self.abstract_class = true
8
-
9
- # Defines constants representing intervals
10
- module Interval
11
- ROOT = 0
12
- MINOR_2ND = 1
13
- MAJOR_2ND = 2
14
- AUGMENTED_2ND = 3
15
- MINOR_3RD = 3
16
- MAJOR_3RD = 4
17
- PERFECT_4TH = 5
18
- AUGMENTED_4TH = 6
19
- DIMINISHED_5TH = 6
20
- TRITONE = 6
21
- PERFECT_5TH = 7
22
- AUGMENTED_5TH = 8
23
- MINOR_6TH = 8
24
- MAJOR_6TH = 9
25
- DIMINISHED_7TH = 9
26
- MINOR_7TH = 10
27
- DOMINANT_7TH = 10
28
- MAJOR_7TH = 11
29
- OCTAVE = 12
30
- end
31
-
32
- # Defines constants representing letter intervals
33
- module LetterInterval
34
- FIRST = 0
35
- SECOND = 1
36
- THIRD = 2
37
- FOURTH = 3
38
- FIFTH = 4
39
- SIXTH = 5
40
- SEVENTH = 6
41
- end
42
-
43
- module Offsets
44
- LOWERED = -1
45
- RAISED = 1
46
- DOUBLE_LOWERED = -2
47
- DOUBLE_RAISED = 2
48
- end
49
-
7
+ self.abstract_class = true
8
+
9
+ # Defines constants representing intervals
10
+ module Interval
11
+ ROOT = 0
12
+ MINOR_2ND = 1
13
+ MAJOR_2ND = 2
14
+ AUGMENTED_2ND = 3
15
+ MINOR_3RD = 3
16
+ MAJOR_3RD = 4
17
+ PERFECT_4TH = 5
18
+ AUGMENTED_4TH = 6
19
+ DIMINISHED_5TH = 6
20
+ TRITONE = 6
21
+ PERFECT_5TH = 7
22
+ AUGMENTED_5TH = 8
23
+ MINOR_6TH = 8
24
+ MAJOR_6TH = 9
25
+ DIMINISHED_7TH = 9
26
+ MINOR_7TH = 10
27
+ DOMINANT_7TH = 10
28
+ MAJOR_7TH = 11
29
+ OCTAVE = 12
30
+ end
31
+
32
+ # Defines constants representing letter intervals
33
+ module LetterInterval
34
+ FIRST = 0
35
+ SECOND = 1
36
+ THIRD = 2
37
+ FOURTH = 3
38
+ FIFTH = 4
39
+ SIXTH = 5
40
+ SEVENTH = 6
41
+ end
42
+
43
+ module Offsets
44
+ LOWERED = -1
45
+ RAISED = 1
46
+ DOUBLE_LOWERED = -2
47
+ DOUBLE_RAISED = 2
48
+ end
50
49
  end
51
- end
50
+ end
@@ -1,62 +1,60 @@
1
1
  module JazzModel
2
- # This module is mixed in wherever a collection of tones is being returned
3
- # and handles some of the fundamental logic involved in key and mode calculations
2
+ # This module is mixed in wherever a collection of tones is being returned
3
+ # and handles some of the fundamental logic involved in key and mode calculations
4
4
  # and note values.
5
- #
5
+ #
6
6
  module ToneSequence
7
- # Takes manually specified key context for this collection or
8
- # delegates to th association owner.
9
- def key
10
- @key || (proxy_owner.key if proxy_owner.respond_to?(:key))
11
- end
12
-
13
- # Manually specifies the key context for this tone sequence only.
14
- def in_key_of(in_key = nil)
15
- @key = in_key.instance_of?(String) ? Key[in_key] : in_key
16
- self
17
- end
18
-
19
- # Shifts indexes to simulate a key change
20
- def in_key_context!
21
- self.each do |tone|
22
- tone.tone = (tone.tone + key.index) % 12
23
- tone.letter_index = (tone.letter_index + key.letter_index) % 7
24
- end
25
- true
26
- end
27
-
28
- # Takes manually specified mode context for this collection or
29
- # delegates to the association owner.
30
- def mode
31
- @mode || (proxy_owner.mode if proxy_owner.respond_to?(:mode))
32
- end
33
-
34
- # Manually specifies the mode context for this tone sequence only.
35
- def in_mode(mode)
36
- @mode = mode
37
- self
38
- end
39
-
40
- # Shifts mode positions to place tone sequence in mode context
41
- def in_mode_context!
42
- self.each {|tone| tone.position = (tone.position - mode) % self.count + 1}
43
- true
44
- end
45
-
46
- # TODO: Have to use this until we figure out how to override find/default collection result
47
- def all
48
- in_key_context! if key
49
- in_mode_context! if mode
50
- self.sort_by(&:position)
51
- end
52
-
53
- # Does the magic in determining the actual note from the tones
54
- # with tone and letter indexes.
55
- def notes
56
- all.map do |tone|
57
- Key.from_index(tone.tone, tone.letter_index).name
58
- end.extend(NoteSequence)
59
- end
60
-
7
+ # Takes manually specified key context for this collection or
8
+ # delegates to the association owner.
9
+ def key
10
+ @key || (owner.key if owner.respond_to?(:key))
11
+ end
12
+
13
+ # Manually specifies the key context for this tone sequence only.
14
+ def in_key_of(in_key = nil)
15
+ @key = in_key.is_a?(String) ? Key[in_key] : in_key
16
+ self
17
+ end
18
+
19
+ # Takes manually specified mode context for this collection or
20
+ # delegates to the association owner.
21
+ def mode
22
+ @mode || (owner.mode if owner.respond_to?(:mode))
23
+ end
24
+
25
+ # Manually specifies the mode context for this tone sequence only.
26
+ def in_mode(mode)
27
+ @mode = mode
28
+ self
29
+ end
30
+
31
+ # Returns the tones ordered by position with key and mode context applied.
32
+ # Each tone is a copy, so the underlying records are never modified.
33
+ def in_context
34
+ tones = to_a
35
+ tones.map do |tone|
36
+ tone.dup.tap do |t|
37
+ if key
38
+ t.tone = (tone.tone + key.index) % 12
39
+ t.letter_index = (tone.letter_index + key.letter_index) % 7
40
+ end
41
+ t.position = (tone.position - mode) % tones.size + 1 if mode
42
+ end
43
+ end.sort_by(&:position)
44
+ end
45
+
46
+ # Does the magic in determining the actual note from the tones
47
+ # with tone and letter indexes.
48
+ def notes
49
+ in_context.map do |tone|
50
+ Key.from_index(tone.tone, tone.letter_index).name
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def owner
57
+ proxy_association.owner if respond_to?(:proxy_association)
58
+ end
61
59
  end
62
- end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module JazzModel
2
- VERSION = "0.1.0"
3
- end
2
+ VERSION = "0.2.0"
3
+ end
@@ -1,12 +1,11 @@
1
1
  module JazzModel
2
2
  # Represents a specific piano voicing.
3
3
  # Work in progress!
4
- #
4
+ #
5
5
  class Voicing < JazzModel::Base
6
- belongs_to :chord
7
- has_many :voicing_tones
8
-
9
- delegate :key, :to => :chord
10
-
6
+ belongs_to :chord
7
+ has_many :voicing_tones
8
+
9
+ delegate :key, to: :chord
11
10
  end
12
- end
11
+ end
@@ -1,11 +1,10 @@
1
1
  module JazzModel
2
2
  # Represents a tone in a piano voicing.
3
3
  # Work in progress!
4
- #
4
+ #
5
5
  class VoicingTone < Tone
6
- belongs_to :voicing
7
-
8
- acts_as_list :scope => :voicing
9
-
6
+ belongs_to :voicing
7
+
8
+ acts_as_list scope: :voicing
10
9
  end
11
- end
10
+ end
data/lib/jazz_model.rb CHANGED
@@ -1,12 +1,11 @@
1
+ require "active_support"
2
+ require "active_record"
3
+ require "acts_as_tree"
4
+ require "acts_as_list"
5
+
1
6
  module JazzModel
2
- require "rubygems"
3
- require "active_support"
4
- require "active_record"
5
- require "acts_as_tree"
6
- require "acts_as_list"
7
-
8
7
  extend ActiveSupport::Autoload
9
-
8
+
10
9
  autoload :Base
11
10
  autoload :Chord
12
11
  autoload :ChordCollection
@@ -20,7 +19,6 @@ module JazzModel
20
19
  autoload :Mode
21
20
  autoload :ModeContext
22
21
  autoload :ModeSequence
23
- autoload :NoteSequence
24
22
  autoload :NotesCollection
25
23
  autoload :Scale
26
24
  autoload :ScaleTone
@@ -28,7 +26,6 @@ module JazzModel
28
26
  autoload :ToneSequence
29
27
  autoload :Voicing
30
28
  autoload :VoicingTone
31
-
29
+
32
30
  autoload :Definition
33
-
34
31
  end