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,48 +1,48 @@
1
1
  JazzModel::Definition.define :keys do
2
- JazzModel::Key.create!(:name => 'C', :long_name => 'C', :index => 0, :letter_index => 0, :cycle_index => 0)
3
- JazzModel::Key.create!(:name => 'B#', :long_name => 'B Sharp', :index => 0, :letter_index => 6, :cycle_index => 0, :primary => false)
4
- JazzModel::Key.create!(:name => 'Dbb', :long_name => 'D Double-Flat', :index => 0, :letter_index => 1, :cycle_index => 0, :primary => false)
2
+ JazzModel::Key.create!(name: "C", long_name: "C", index: 0, letter_index: 0, cycle_index: 0)
3
+ JazzModel::Key.create!(name: "B#", long_name: "B Sharp", index: 0, letter_index: 6, cycle_index: 0, primary: false)
4
+ JazzModel::Key.create!(name: "Dbb", long_name: "D Double-Flat", index: 0, letter_index: 1, cycle_index: 0, primary: false)
5
5
 
6
- JazzModel::Key.create!(:name => 'F', :long_name => 'F', :index => 5, :letter_index => 3, :cycle_index => 1)
7
- JazzModel::Key.create!(:name => 'E#', :long_name => 'E Sharp', :index => 5, :letter_index => 2, :cycle_index => 1, :primary => false)
8
- JazzModel::Key.create!(:name => 'Gbb', :long_name => 'G Double-Flat', :index => 5, :letter_index => 4, :cycle_index => 1, :primary => false)
6
+ JazzModel::Key.create!(name: "F", long_name: "F", index: 5, letter_index: 3, cycle_index: 1)
7
+ JazzModel::Key.create!(name: "E#", long_name: "E Sharp", index: 5, letter_index: 2, cycle_index: 1, primary: false)
8
+ JazzModel::Key.create!(name: "Gbb", long_name: "G Double-Flat", index: 5, letter_index: 4, cycle_index: 1, primary: false)
9
9
 
10
- JazzModel::Key.create!(:name => 'Bb', :long_name => 'B Flat', :index => 10, :letter_index => 6, :cycle_index => 2)
11
- JazzModel::Key.create!(:name => 'A#', :long_name => 'A Sharp', :index => 10, :letter_index => 5, :cycle_index => 2, :primary => false)
12
- JazzModel::Key.create!(:name => 'Cbb', :long_name => 'C Double-Flat', :index => 10, :letter_index => 0, :cycle_index => 2, :primary => false)
10
+ JazzModel::Key.create!(name: "Bb", long_name: "B Flat", index: 10, letter_index: 6, cycle_index: 2)
11
+ JazzModel::Key.create!(name: "A#", long_name: "A Sharp", index: 10, letter_index: 5, cycle_index: 2, primary: false)
12
+ JazzModel::Key.create!(name: "Cbb", long_name: "C Double-Flat", index: 10, letter_index: 0, cycle_index: 2, primary: false)
13
13
 
14
- JazzModel::Key.create!(:name => 'Eb', :long_name => 'E Flat', :index => 3, :letter_index => 2, :cycle_index => 3)
15
- JazzModel::Key.create!(:name => 'D#', :long_name => 'D Sharp', :index => 3, :letter_index => 1, :cycle_index => 3, :primary => false)
16
- JazzModel::Key.create!(:name => 'Fbb', :long_name => 'F Double Flat', :index => 3, :letter_index => 3, :cycle_index => 3, :primary => false)
14
+ JazzModel::Key.create!(name: "Eb", long_name: "E Flat", index: 3, letter_index: 2, cycle_index: 3)
15
+ JazzModel::Key.create!(name: "D#", long_name: "D Sharp", index: 3, letter_index: 1, cycle_index: 3, primary: false)
16
+ JazzModel::Key.create!(name: "Fbb", long_name: "F Double Flat", index: 3, letter_index: 3, cycle_index: 3, primary: false)
17
17
 
18
- JazzModel::Key.create!(:name => 'Ab', :long_name => 'A Flat', :index => 8, :letter_index => 5, :cycle_index => 4)
19
- JazzModel::Key.create!(:name => 'G#', :long_name => 'G Sharp', :index => 8, :letter_index => 4, :cycle_index => 4, :primary => false)
18
+ JazzModel::Key.create!(name: "Ab", long_name: "A Flat", index: 8, letter_index: 5, cycle_index: 4)
19
+ JazzModel::Key.create!(name: "G#", long_name: "G Sharp", index: 8, letter_index: 4, cycle_index: 4, primary: false)
20
20
 
21
- JazzModel::Key.create!(:name => 'Db', :long_name => 'D Flat', :index => 1, :letter_index => 1, :cycle_index => 5)
22
- JazzModel::Key.create!(:name => 'C#', :long_name => 'C Sharp', :index => 1, :letter_index => 0, :cycle_index => 5, :primary => false)
23
- JazzModel::Key.create!(:name => 'B##', :long_name => 'B Double-Sharp', :index => 1, :letter_index => 6, :cycle_index => 5, :primary => false)
21
+ JazzModel::Key.create!(name: "Db", long_name: "D Flat", index: 1, letter_index: 1, cycle_index: 5)
22
+ JazzModel::Key.create!(name: "C#", long_name: "C Sharp", index: 1, letter_index: 0, cycle_index: 5, primary: false)
23
+ JazzModel::Key.create!(name: "B##", long_name: "B Double-Sharp", index: 1, letter_index: 6, cycle_index: 5, primary: false)
24
24
 
25
- JazzModel::Key.create!(:name => 'Gb', :long_name => 'G Flat', :index => 6, :letter_index => 4, :cycle_index => 6)
26
- JazzModel::Key.create!(:name => 'F#', :long_name => 'F Sharp', :index => 6, :letter_index => 3, :cycle_index => 6, :primary => false)
27
- JazzModel::Key.create!(:name => 'E##', :long_name => 'E Double-Sharp', :index => 6, :letter_index => 2, :cycle_index => 6, :primary => false)
25
+ JazzModel::Key.create!(name: "Gb", long_name: "G Flat", index: 6, letter_index: 4, cycle_index: 6)
26
+ JazzModel::Key.create!(name: "F#", long_name: "F Sharp", index: 6, letter_index: 3, cycle_index: 6, primary: false)
27
+ JazzModel::Key.create!(name: "E##", long_name: "E Double-Sharp", index: 6, letter_index: 2, cycle_index: 6, primary: false)
28
28
 
29
- JazzModel::Key.create!(:name => 'B', :long_name => 'B', :index => 11, :letter_index => 6, :cycle_index => 7)
30
- JazzModel::Key.create!(:name => 'Cb', :long_name => 'C Flat', :index => 11, :letter_index => 0, :cycle_index => 7, :primary => false)
31
- JazzModel::Key.create!(:name => 'A##', :long_name => 'A Double-Sharp', :index => 11, :letter_index => 5, :cycle_index => 7, :primary => false)
29
+ JazzModel::Key.create!(name: "B", long_name: "B", index: 11, letter_index: 6, cycle_index: 7)
30
+ JazzModel::Key.create!(name: "Cb", long_name: "C Flat", index: 11, letter_index: 0, cycle_index: 7, primary: false)
31
+ JazzModel::Key.create!(name: "A##", long_name: "A Double-Sharp", index: 11, letter_index: 5, cycle_index: 7, primary: false)
32
32
 
33
- JazzModel::Key.create!(:name => 'E', :long_name => 'E', :index => 4, :letter_index => 2, :cycle_index => 8)
34
- JazzModel::Key.create!(:name => 'Fb', :long_name => 'F Flat', :index => 4, :letter_index => 3, :cycle_index => 8, :primary => false)
35
- JazzModel::Key.create!(:name => 'D##', :long_name => 'D Double-Sharp', :index => 4, :letter_index => 1, :cycle_index => 8, :primary => false)
33
+ JazzModel::Key.create!(name: "E", long_name: "E", index: 4, letter_index: 2, cycle_index: 8)
34
+ JazzModel::Key.create!(name: "Fb", long_name: "F Flat", index: 4, letter_index: 3, cycle_index: 8, primary: false)
35
+ JazzModel::Key.create!(name: "D##", long_name: "D Double-Sharp", index: 4, letter_index: 1, cycle_index: 8, primary: false)
36
36
 
37
- JazzModel::Key.create!(:name => 'A', :long_name => 'A', :index => 9, :letter_index => 5, :cycle_index => 9)
38
- JazzModel::Key.create!(:name => 'Bbb', :long_name => 'B Double-Flat', :index => 9, :letter_index => 6, :cycle_index => 9, :primary => false)
39
- JazzModel::Key.create!(:name => 'G##', :long_name => 'G Double-Sharp', :index => 9, :letter_index => 4, :cycle_index => 9, :primary => false)
37
+ JazzModel::Key.create!(name: "A", long_name: "A", index: 9, letter_index: 5, cycle_index: 9)
38
+ JazzModel::Key.create!(name: "Bbb", long_name: "B Double-Flat", index: 9, letter_index: 6, cycle_index: 9, primary: false)
39
+ JazzModel::Key.create!(name: "G##", long_name: "G Double-Sharp", index: 9, letter_index: 4, cycle_index: 9, primary: false)
40
40
 
41
- JazzModel::Key.create!(:name => 'D', :long_name => 'D', :index => 2, :letter_index => 1, :cycle_index => 10)
42
- JazzModel::Key.create!(:name => 'C##', :long_name => 'C Double-Sharp', :index => 2, :letter_index => 0, :cycle_index => 10, :primary => false)
43
- JazzModel::Key.create!(:name => 'Ebb', :long_name => 'E Double-Flat', :index => 2, :letter_index => 2, :cycle_index => 10, :primary => false)
41
+ JazzModel::Key.create!(name: "D", long_name: "D", index: 2, letter_index: 1, cycle_index: 10)
42
+ JazzModel::Key.create!(name: "C##", long_name: "C Double-Sharp", index: 2, letter_index: 0, cycle_index: 10, primary: false)
43
+ JazzModel::Key.create!(name: "Ebb", long_name: "E Double-Flat", index: 2, letter_index: 2, cycle_index: 10, primary: false)
44
44
 
45
- JazzModel::Key.create!(:name => 'G', :long_name => 'G', :index => 7, :letter_index => 4, :cycle_index => 11)
46
- JazzModel::Key.create!(:name => 'F##', :long_name => 'F Double-Sharp', :index => 7, :letter_index => 3, :cycle_index => 11, :primary => false)
47
- JazzModel::Key.create!(:name => 'Abb', :long_name => 'A Double-Flat', :index => 7, :letter_index => 5, :cycle_index => 11, :primary => false)
48
- end
45
+ JazzModel::Key.create!(name: "G", long_name: "G", index: 7, letter_index: 4, cycle_index: 11)
46
+ JazzModel::Key.create!(name: "F##", long_name: "F Double-Sharp", index: 7, letter_index: 3, cycle_index: 11, primary: false)
47
+ JazzModel::Key.create!(name: "Abb", long_name: "A Double-Flat", index: 7, letter_index: 5, cycle_index: 11, primary: false)
48
+ end
@@ -0,0 +1,3 @@
1
+ require "jazz_model"
2
+
3
+ JazzModel::Base.load_definitions
@@ -1,49 +1,46 @@
1
1
  module JazzModel
2
- # A key represents a specific theoretic tone mapped to a pitch and a letter
3
- # index. Keys are defined for all letters A-G and all sharp/flat values
2
+ # A key represents a specific theoretic tone mapped to a pitch and a letter
3
+ # index. Keys are defined for all letters A-G and all sharp/flat values
4
4
  # within two semitons (e.g. Dbb, D Double-Flat enharmonic with C).
5
5
  #
6
- # Each key is associated an index between 0-11 to represent the actual pitch
7
- # within the chromatic scale.
8
- # Each key is also assigned a "letter index" which represents a relative letter
9
- # value. This index is crucial as it disambiguates theoretical tone differences
10
- # such as Eb and D#. Doing so also supports correct double-sharp and double-flat
11
- # interpretations which are rare but theoretically different from their enharmonic
6
+ # Each key is associated an index between 0-11 to represent the actual pitch
7
+ # within the chromatic scale.
8
+ # Each key is also assigned a "letter index" which represents a relative letter
9
+ # value. This index is crucial as it disambiguates theoretical tone differences
10
+ # such as Eb and D#. Doing so also supports correct double-sharp and double-flat
11
+ # interpretations which are rare but theoretically different from their enharmonic
12
12
  # counterparts.
13
- #
13
+ #
14
14
  class Key < JazzModel::Base
15
- Letters = ['C' => 0, 'D' => 1, 'E' => 2, 'F' => 3, 'G' => 4, 'A' => 5, 'B' => 6]
16
-
17
15
  # Finds a key given a tonal index 0-11 and a letter index (to disambiguate enharmonic keys)
18
16
  def self.from_index(value, preferred_letter = nil)
19
- self.all.find {|k| k.index == value && (preferred_letter.nil? || k.letter_index == preferred_letter)}
17
+ all.find { |k| k.index == value && (preferred_letter.nil? || k.letter_index == preferred_letter) }
20
18
  end
21
-
19
+
22
20
  # Finds a key object given the name (such as Eb)
23
21
  def self.from_name(value)
24
- self.all.find {|k| k.name == value}
22
+ all.find { |k| k.name == value }
25
23
  end
26
-
24
+
27
25
  # Finds a key object based on the name:
28
26
  # +Key['Eb']+
29
- #
27
+ #
30
28
  def self.[](value)
31
- self.from_name(value) || self.from_index(value)
29
+ from_name(value) || from_index(value)
32
30
  end
33
-
31
+
34
32
  # Returns an array of the 12 primary keys (definitions around the cycle of fourths)
35
33
  def self.primaries
36
- self.find_all_by_primary(true)
34
+ where(primary: true).to_a
37
35
  end
38
-
36
+
39
37
  def self.default
40
- self['C']
38
+ self["C"]
41
39
  end
42
-
40
+
43
41
  # Tests whether the current key is enharmonic with +another_key+.
44
42
  def enharmonic_with?(another_key)
45
- self.index == another_key.index
43
+ index == another_key.index
46
44
  end
47
-
48
45
  end
49
- end
46
+ end
@@ -1,28 +1,37 @@
1
1
  module JazzModel
2
- # Key context is a module intended to be mixed in to classes requiring
3
- # the notion of "key context". Concepts such as chords and scales exist
2
+ # Key context is a module intended to be mixed in to classes requiring
3
+ # the notion of "key context". Concepts such as chords and scales exist
4
4
  # as mathematical relationships absent key, but can be put into key context.
5
- # Adds a key instance variable to the including class and two new methods:
6
- #
5
+ # Adds a key attribute to the including class and two new methods:
6
+ #
7
7
  # * +in_key_of+(new_key) - Sets the key context to the specified new_key.
8
8
  # * +without_key+ - Removes key context.
9
- #
9
+ #
10
10
  module KeyContext
11
- def self.included(klass)
12
- klass.class_eval do
13
- attr_accessor :key
14
-
15
- def in_key_of(name)
16
- self.key = Key.find_by_name(name)
17
- self
18
- end
19
- alias_method :in, :in_key_of
20
-
21
- def without_key
22
- self.key = nil
23
- self
24
- end
25
- end
26
- end
11
+ attr_accessor :key
12
+
13
+ def in_key_of(name)
14
+ self.key = name.is_a?(Key) ? name : Key.find_by_name(name)
15
+ self
16
+ end
17
+ alias_method :in, :in_key_of
18
+
19
+ def without_key
20
+ self.key = nil
21
+ self
22
+ end
23
+
24
+ # Yields each way +symbol+ can be read as an optional key prefix followed
25
+ # by the rest of the symbol, longest key first and finally with no key at
26
+ # all. For example "Cb5" yields [Cb, "5"], [C, "b5"], then [nil, "Cb5"],
27
+ # letting callers pick the first reading that resolves to something.
28
+ def self.each_split(symbol)
29
+ return enum_for(:each_split, symbol) unless block_given?
30
+
31
+ Key.all.sort_by { |k| -k.name.length }.each do |k|
32
+ yield k, symbol.delete_prefix(k.name).strip if symbol.start_with?(k.name)
33
+ end
34
+ yield nil, symbol
35
+ end
27
36
  end
28
- end
37
+ end
@@ -1,47 +1,42 @@
1
1
  module JazzModel
2
- # In music theory a mode is essentially a slice of a scale with an offset.
3
- # For example second mode of the C major scale would begin and end on D
2
+ # In music theory a mode is essentially a slice of a scale with an offset.
3
+ # For example second mode of the C major scale would begin and end on D
4
4
  # but otherwise have the exact same tones as the C major scale.
5
- #
6
- # This class represents a mode within the context of a +Scale+.
7
- #
5
+ #
6
+ # This class represents a mode within the context of a +Scale+.
7
+ #
8
8
  # == Associations
9
- #
9
+ #
10
10
  # * +scale+ - The related scale.
11
11
  # * +chord_scales+ - +ChordScale+ relationships to this mode.
12
12
  # * +chords+ - Direct access to a collection of chords through +chord_scales+.
13
- #
13
+ #
14
14
  # == Tones and Mode Context
15
- #
16
- # Tones are directly related to scales, not modes. There is a +tones+ method
17
- # (and a +notes+ method that delegates to +tones+) here that simulates the tones for
18
- # the mode by setting the mode context of the scale tones, effectively returning
15
+ #
16
+ # Tones are directly related to scales, not modes. There is a +tones+ method
17
+ # (and a +notes+ method that delegates to +tones+) here that simulates the tones for
18
+ # the mode by setting the mode context of the scale tones, effectively returning
19
19
  # the tones shifted by X where X is the mode number.
20
- # Therefore, you can access tones directly off of the mode because they are proxied
21
- # through scale with the correct offset.
22
- #
20
+ # Therefore, you can access tones directly off of the mode because they are proxied
21
+ # through scale with the correct offset.
22
+ #
23
23
  # == Examples
24
- #
25
- # Since modes should be accessed within the context of scales, mode-related examples are
24
+ #
25
+ # Since modes should be accessed within the context of scales, mode-related examples are
26
26
  # actually in scale. See +Scale+.
27
- #
27
+ #
28
28
  class Mode < JazzModel::Base
29
- include KeyContext
30
-
31
- belongs_to :scale
32
-
33
- has_many :chord_scales
34
- has_many :chords, :through => :chord_scales, :extend => ChordCollection
35
-
36
- delegate :notes, :to => :tones
37
-
38
- def tones
39
- if self.key
40
- self.scale.tones.in_mode(self.mode).in_key_of(self.key)
41
- else
42
- self.scale.tones.in_mode(self.mode)
43
- end
44
- end
45
-
29
+ include KeyContext
30
+
31
+ belongs_to :scale
32
+
33
+ has_many :chord_scales
34
+ has_many :chords, through: :chord_scales, extend: ChordCollection
35
+
36
+ delegate :notes, to: :tones
37
+
38
+ def tones
39
+ scale.tones.in_mode(mode).in_key_of(key)
40
+ end
46
41
  end
47
- end
42
+ end
@@ -1,32 +1,28 @@
1
1
  module JazzModel
2
- # Mode context is a module intended to be mixed in to classes requiring
3
- # the notion of "mode context". Right now the only class that uses this
4
- # is scale. Mode context allows scales to take on a mode context which
2
+ # Mode context is a module intended to be mixed in to classes requiring
3
+ # the notion of "mode context". Right now the only class that uses this
4
+ # is scale. Mode context allows scales to take on a mode context which
5
5
  # effectively offsets tone sequences to retrieve tones in the given scale mode.
6
- #
7
- # * +in_mode(new_mode)+ - Sets the mode context to the specified mode (integer).
6
+ #
7
+ # * +in_mode(new_mode)+ - Sets the mode context to the specified mode (integer or name).
8
8
  # * +without_mode+ - Removes mode context.
9
9
  #
10
10
  module ModeContext
11
- def self.included(klass)
12
- klass.class_eval do
13
- attr_accessor :mode
14
-
15
- def in_mode(value)
16
- if value.is_a?(String)
17
- mode_object = self.respond_to?(:modes) ? self.modes.find_by_name(value) : Mode.find_by_name(value)
18
- self.mode = mode_object.mode unless mode_object.nil?
19
- else
20
- self.mode = value
21
- end
22
- self
23
- end
24
-
25
- def without_mode
26
- self.mode = nil
27
- self
28
- end
29
- end
30
- end
11
+ attr_accessor :mode
12
+
13
+ def in_mode(value)
14
+ if value.is_a?(String)
15
+ mode_object = respond_to?(:modes) ? modes.find_by_name(value) : Mode.find_by_name(value)
16
+ self.mode = mode_object.mode unless mode_object.nil?
17
+ else
18
+ self.mode = value
19
+ end
20
+ self
21
+ end
22
+
23
+ def without_mode
24
+ self.mode = nil
25
+ self
26
+ end
31
27
  end
32
- end
28
+ end
@@ -1,15 +1,16 @@
1
1
  module JazzModel
2
- # Extends the Scale.modes association by allowing indexed access to modes.
3
- # Whn using it in this manner, key context is passed along.
4
- #
2
+ # Extends the Scale.modes association by allowing indexed access to modes.
3
+ # When using it in this manner, key context is passed along.
4
+ #
5
5
  module ModeSequence
6
- def [](value)
7
- mode_object = self.find(:first, :conditions => ["name = ? OR mode = ?", value, value])
8
- return nil if mode_object.nil?
9
-
10
- # Pass Along Key Information
11
- mode_object.key = proxy_owner.key if proxy_owner.respond_to?(:key) and !proxy_owner.key.nil?
12
- mode_object
13
- end
6
+ def [](value)
7
+ mode_object = where("name = ? OR mode = ?", value, value).first
8
+ return nil if mode_object.nil?
9
+
10
+ # Pass Along Key Information
11
+ owner = proxy_association.owner
12
+ mode_object.key = owner.key if owner.respond_to?(:key) && !owner.key.nil?
13
+ mode_object
14
+ end
14
15
  end
15
- end
16
+ end
@@ -1,89 +1,82 @@
1
- require 'set'
2
-
3
1
  module JazzModel
4
2
  # NotesCollection represents a collection of notes. Using this collection,
5
- # you can determine chord and scale/mode matches in specific or all keys.
6
- # This class is currently under heavily development and will eventually be home to heavy logic involved
7
- # in associating an arbitrary collection of notes with chords, given that
3
+ # you can determine chord and scale/mode matches in specific or all keys.
4
+ # This class is currently under heavily development and will eventually be home to heavy logic involved
5
+ # in associating an arbitrary collection of notes with chords, given that
8
6
  # some scales tone may be "omitable", etc.
9
- #
7
+ #
10
8
  # == Creating a NotesCollection object
11
- #
12
- # Creating the collection of notes should be done by indexing
9
+ #
10
+ # Creating the collection of notes should be done by indexing
13
11
  # the Notes class directly with a comma-separated string of notes.
14
- #
12
+ #
15
13
  # == Current Limitations
16
- #
14
+ #
17
15
  # Will only do exact 100% match of notes given and notes in chords. No fuzzyness
18
- # such as the ability to omit the root and other non-important tones. Does not yet
16
+ # such as the ability to omit the root and other non-important tones. Does not yet
19
17
  # find supersets or subsets.
20
- #
18
+ #
21
19
  # == Examples
22
- #
20
+ #
23
21
  # === Finding All Associated Chords
24
- #
22
+ #
25
23
  # NotesCollection['C, E, G, A'].chords.symbols
26
24
  # # => "Amin7, Cmaj6"
27
- #
25
+ #
28
26
  # === Finding Associated Chords in Given Key
29
27
  #
30
28
  # NotesCollection['C, E, G, A'].in_key_of('A').chords.symbols
31
29
  # # => "Amin7"
32
- #
30
+ #
33
31
  class NotesCollection
34
- include Enumerable
35
- include KeyContext
36
-
37
- attr_accessor :keys
38
- attr_accessor :invalid_keys
39
-
40
- def initialize(value = [])
41
- @value_as_given = value
42
- @keys = []
43
- @invalid_keys = []
44
-
45
- value = value.split(/,| /).map(&:strip) if value.instance_of?(String)
46
- value.each do |key_name|
47
- key_object = Key[key_name]
48
-
49
- if key_object.nil?
50
- @invalid_keys << key_name
51
- else
52
- @keys << key_object
53
- end
54
- end
55
- end
56
-
57
- class << self
58
- alias_method :[], :new
59
- end
60
-
61
- delegate :each, :to => :keys
62
-
63
- # Chords associated with this collection of notes
64
- def chords
65
- if key
66
- chords_in_key(key)
67
- else
68
- Key.primaries.map do |in_key|
69
- chords_in_key(in_key)
70
- end.flatten
71
- end.extend(ChordCollection)
72
- end
73
-
74
- # XML Representation
75
- def to_xml
76
- '<NotesCollection name="' + @value_as_given.to_s + '"></NotesCollection>'
77
- end
78
-
79
-
80
- private
81
-
82
- def chords_in_key(in_key)
83
- Chord.all.select do |c|
84
- c.tones.map(&:tone).to_set == keys.map {|k| (k.index - (in_key ? in_key.index : 0)) % 12 }.to_set
85
- end.map {|c| c.key = in_key; c}
86
- end
87
-
32
+ include Enumerable
33
+ include KeyContext
34
+
35
+ attr_accessor :keys
36
+ attr_accessor :invalid_keys
37
+
38
+ def initialize(value = [])
39
+ @keys = []
40
+ @invalid_keys = []
41
+
42
+ value = value.split(/,| /).map(&:strip) if value.instance_of?(String)
43
+ value.each do |key_name|
44
+ key_object = Key[key_name]
45
+
46
+ if key_object.nil?
47
+ @invalid_keys << key_name
48
+ else
49
+ @keys << key_object
50
+ end
51
+ end
52
+ end
53
+
54
+ class << self
55
+ alias_method :[], :new
56
+ end
57
+
58
+ delegate :each, to: :keys
59
+
60
+ # Chords associated with this collection of notes
61
+ def chords
62
+ if key
63
+ chords_in_key(key)
64
+ else
65
+ Key.primaries.map do |in_key|
66
+ chords_in_key(in_key)
67
+ end.flatten
68
+ end.extend(ChordCollection)
69
+ end
70
+
71
+ private
72
+
73
+ def chords_in_key(in_key)
74
+ Chord.all.select do |c|
75
+ c.tones.map(&:tone).to_set == keys.map { |k| (k.index - (in_key ? in_key.index : 0)) % 12 }.to_set
76
+ end.map { |c|
77
+ c.key = in_key
78
+ c
79
+ }
80
+ end
88
81
  end
89
- end
82
+ end