musical-chords 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/music.rb +462 -0
  3. metadata +44 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7abf3d598f5b033312d3a9c86fef9306bd4577ad
4
+ data.tar.gz: 43b915af57b05ddc45f39a6201b236aebcd2dd6c
5
+ SHA512:
6
+ metadata.gz: f25d035e439b9818a86f0ac26b3f5c6d0b181b1b3ae3070c8da1d01e452d7e4491cf9137e552a28adfe3271fa97a6b95ee7dfaedbbeef5003c0fdaaec6e70ebe
7
+ data.tar.gz: c18f0206111b45f7efc55ae34ddfb2948cbc678fdd5db851672695c5aa72e1692fc1d252d803bd355d292148689165419886818229c81aae814bba23b2385e74
data/lib/music.rb ADDED
@@ -0,0 +1,462 @@
1
+ # This class is designed for music manipulation
2
+ # It is useful for finding notes and chords, and transpositions.
3
+ #
4
+ # Author:: Patrick Sereno (mailto:patrick@6orbits.com)
5
+ # Copyright:: Copyright (c) 2017 Patrick Sereno
6
+ #
7
+ # ToDos::
8
+ # 1. Include minor scales
9
+
10
+ # This class contains the variables and methods based upon contemporary western music turning.
11
+ class Music
12
+
13
+ # This array is the chromatic scale.
14
+ @@notes = %w( A A#/Bb B C C#/Db D D#/Eb E F F#/Gb G G#/Ab )
15
+
16
+ # The modules is used for "wrapping" notes back to the beginning of the scale. For instance, the 12th note above A in the current scale with a modules of 12 would be A ( A + 12 mod 12 = A ).
17
+ @@scale_modulus = @@notes.count
18
+
19
+ # This array is the chromatic scale written using sharps.
20
+ @@sharp_notes = %w( A A# B C C# D D# E F F# G G# )
21
+
22
+ # This array is the chromatic scale written using flats.
23
+ @@flat_notes = %w( A Bb B C Db D Eb E F Gb G Ab )
24
+
25
+ # This array is of keys that are contain sharps. This array is useful for determining if a note should be labeled as a sharp. For instance A#/Bb in one of these keys would be written as A#. (While the key of C has no sharps, it's common for accidentals to contain sharps when used in the key of C.)
26
+ @@sharps = %w( C G D A E B )
27
+
28
+ # This array is of keys that are contain flats. This array is useful for determining if a note should be labeled as a flat. For instance A#/Bb in one of these keys would be written as Bb.
29
+ @@flats = %w( F Bb Eb Ab Db Gb )
30
+
31
+ # These notes are the white keys on a piano
32
+ @@white_keys = %w( C D E F G A B )
33
+
34
+ # These notes are the black keys on a piano
35
+ @@black_keys = ( %w( C# D# ) << nil << %w( F# G# A# ) ).flatten
36
+
37
+ # This hash is used to convert the different ways of writing notes into a consistent form.
38
+ # For example, @@note_transforms["B#"] => "C", @@note_transforms["B-SHARP"] => "C"
39
+ # Note: all keys are in uppercase
40
+ @@note_transforms = {
41
+ "G#/Ab" => "G#/Ab",
42
+ "AB" => "G#/Ab",
43
+ "A-FLAT" => "G#/Ab",
44
+ "A" => "A",
45
+ "A#/Bb" => "A#/Bb",
46
+ "A-SHARP" => "A#/Bb",
47
+ "A#" => "A#/Bb",
48
+ "BB" => "A#/Bb",
49
+ "B-FLAT" => "A#/Bb",
50
+ "B" => "B",
51
+ "B-SHARP" => "C",
52
+ "B#" => "C",
53
+ "CB" => "B",
54
+ "C-FLAT" => "B",
55
+ "C" => "C",
56
+ "C#/Db" => "C#/Db",
57
+ "C-SHARP" => "C#/Db",
58
+ "C#" => "C#/Db",
59
+ "DB" => "C#/Db",
60
+ "D-FLAT" => "C#/Db",
61
+ "D" => "D",
62
+ "D#/Eb" => "D#/Eb",
63
+ "D-SHARP" => "D#/Eb",
64
+ "D#" => "D#/Eb",
65
+ "EB" => "D#/Eb",
66
+ "E-FLAT" => "D#/Eb",
67
+ "E" => "E",
68
+ "E-SHARP" => "F",
69
+ "E#" => "F",
70
+ "FB" => "E",
71
+ "F-FLAT" => "E",
72
+ "F" => "F",
73
+ "F#/Gb" => "F#/Gb",
74
+ "F-SHARP" => "F#/Gb",
75
+ "F#" => "F#/Gb",
76
+ "GB" => "F#/Gb",
77
+ "G-FLAT" => "F#/Gb",
78
+ "G" => "G",
79
+ "G-SHARP" => "G#/Ab",
80
+ "G#" => "G#/Ab"
81
+ }
82
+
83
+ # This hash is used to convert the different notes into a consistent form
84
+ # primarily for use with other class varibles or methods.
85
+ # Usage: #note_normalized_names["G##"] => "a"
86
+ # Note: all keys are in uppercase; all values are in lowercase.
87
+ @@note_normalized_names = {
88
+ "G##" => "a",
89
+ "A" => "a",
90
+ "BBB" => "a",
91
+ "A-SHARP" => "a-sharp",
92
+ "A#/BB" => "a-sharp",
93
+ "A#" => "a-sharp",
94
+ "BB" => "a-sharp",
95
+ "A##" => "b",
96
+ "B" => "b",
97
+ "CB" => "b",
98
+ "B#" => "c",
99
+ "C" => "c",
100
+ "DBB" => "c",
101
+ "C-SHARP" => "c-sharp",
102
+ "B##" => "c-sharp",
103
+ "C#" => "c-sharp",
104
+ "C#/DB" => "c-sharp",
105
+ "DB" => "c-sharp",
106
+ "C##" => "d",
107
+ "D" => "d",
108
+ "EBB" => "d",
109
+ "D-SHARP" => "d-sharp",
110
+ "D#" => "d-sharp",
111
+ "D#/EB" => "d-sharp",
112
+ "EB" => "d-sharp",
113
+ "FBB" => "d-sharp",
114
+ "D##" => "e",
115
+ "E" => "e",
116
+ "FB" => "e",
117
+ "E#" => "f",
118
+ "F" => "f",
119
+ "GBB" => "f",
120
+ "F-SHARP" => "F-SHARP",
121
+ "E##" => "f-sharp",
122
+ "F#" => "f-sharp",
123
+ "F#/GB" => "f-sharp",
124
+ "GB" => "f-sharp",
125
+ "F##" => "g",
126
+ "G" => "g",
127
+ "ABB" => "g",
128
+ "G-SHARP" => "G-SHARP",
129
+ "G#" => "g-sharp",
130
+ "G#/AB" => "g-sharp",
131
+ "AB" => "g-sharp",
132
+ }
133
+
134
+ # An array of common scales.
135
+ #
136
+ # The key,value pairs are the symbolized name of the scale and the offset in semitones from the base note.
137
+ @@scales = {
138
+ major: [0,2,4,5,7,9,11],
139
+ minor: [0,2,3,5,7,9,11],
140
+ chromatic: [ 0,1,2,3,4,5,6,7,8,9,10,11 ],
141
+ }
142
+
143
+ # Chords are constructed as an array of half-steps beginning with the root of the chord as 0.
144
+ #
145
+ # A major chord, usually written as 1-3-5 would be constructed here as [ 0, 4, 7 ].
146
+ # The root note is always 0. The second arry member is 4, because the thrid note in a scale is *four* half-steps (semitones) higher than the root.
147
+ @@chords = {
148
+ "maj" => [0,4,7],
149
+ "maj6" => [0, 4, 7, 9],
150
+ "maj7" => [0, 4, 7, 11],
151
+ "maj9" => [0, 4, 7, 11, 14],
152
+ "maj11" => [0, 4, 7, 11, 14, 17],
153
+ "maj13" => [0, 4, 7, 11, 14, 17, 21],
154
+ "maj+9" => [0, 4, 7, 14],
155
+ "maj-9" => [0, 4, 7, 13],
156
+ "maj+69" => [0, 4, 7, 9, 14],
157
+ "maj7#5" => [0, 4, 8, 11],
158
+ "maj7b5" => [0, 4, 6, 11],
159
+
160
+
161
+ "min" => [0, 3, 7],
162
+ "min6" => [0, 3, 7, 9],
163
+ "min7" => [0, 3, 7, 10],
164
+ "min9" => [0, 3, 7, 10, 14],
165
+ "min11" => [0, 3, 7, 10, 14, 17],
166
+ "min13" => [0, 3, 7, 10, 14, 17, 21],
167
+ "min-maj7" => [0, 3, 7, 11],
168
+ "min-maj9" => [0, 3, 7, 11, 14],
169
+ "min+9" => [0, 3, 7, 14],
170
+ "min-9" => [0, 3, 7, 13],
171
+ "min+69" => [0, 3, 7, 9, 14],
172
+
173
+ "dom7" => [0, 4, 7, 10],
174
+ "dom7#5" => [0, 4, 8, 10],
175
+ "dom7b5" => [0, 4, 6, 10],
176
+ "dom9" => [0, 4, 7, 10, 14],
177
+ "dom11" => [0, 4, 7, 10, 14, 17],
178
+ "dom13" => [0, 4, 7, 10, 14, 17, 21],
179
+
180
+ "dim" => [0, 3, 6],
181
+ "dim7" => [0, 3, 6, 9],
182
+ "half-dim7" => [0, 3, 6, 10],
183
+
184
+ "aug" => [0, 4, 8],
185
+ "aug7" => [0, 4, 8, 10],
186
+
187
+ "sus" => [0, 5, 7],
188
+ "sus2" => [0, 2, 7],
189
+ "7sus4" => [0, 5, 7, 10],
190
+
191
+ "major-scale" => [0,2,4,5,7,9,11],
192
+ "minor-scale" => [0,2,3,5,7,9,11],
193
+ "chromatic-scale" => [ 0,1,2,3,4,5,6,7,8,9,10,11 ],
194
+
195
+ "alt9" => [4,7,10,14],
196
+ }
197
+
198
+ # An array that represents every note in the scale.
199
+ @@chromatic_scale = (0...@@notes.count).to_a
200
+
201
+ # Chords that are arranged by their common types
202
+ @@chord_groups = {
203
+ scales: %w( major-scale minor-scale chromatic-scale ),
204
+ major: %w( maj maj6 maj7 maj9 maj11 maj13 maj+9 maj-9 maj+69 maj7#5 maj7b5 ),
205
+ minor: %w( min min6 min7 min9 min11 min13 min-maj7 min-maj9 min+9 min-9 min+69 ),
206
+ dominant: %w( dom7 dom7#5 dom7b5 dom9 dom11 dom13 ),
207
+ diminished: %w( dim dim7 half-dim7 ),
208
+ augmented: %w( aug aug7 ),
209
+ suspended: %w( sus 7sus4 sus2 ),
210
+ alternate: %w( alt9 ),
211
+ }
212
+
213
+ # Returns the notes allowed as input to class methods
214
+ def self.allowed_notes
215
+ @@note_transforms.keys
216
+ end
217
+
218
+ # Returns the keys allowed an input to class methods
219
+ def self.allowed_keys
220
+ (@@sharp_notes + @@flat_notes).uniq.sort
221
+ end
222
+
223
+ # Returns the allowed chords
224
+ def self.allowed_chords
225
+ @@chords.keys
226
+ end
227
+
228
+ # Returns the note as a sharp note.
229
+ #
230
+ # Params:
231
+ #
232
+ # * note: (see Music::allowed_notes)
233
+ def self.note_as_sharp( note )
234
+ @@sharp_notes[ @@notes.index( @@note_transforms[note] ) ]
235
+ end
236
+
237
+ # Returns the note as a flat note.
238
+ #
239
+ # Params:
240
+ #
241
+ # * note: (see Music::allowed_notes)
242
+ def self.note_as_flat( note )
243
+ @@flat_notes[ @@notes.index( @@note_transforms[note] ) ]
244
+ end
245
+
246
+ # Returns the note as a flat or sharp based upon the given key
247
+ #
248
+ # Params:
249
+ #
250
+ # * key: (see Music::allowed_keys)
251
+ # * note: (see Music::allowed_notes)
252
+ def self.name_note( key, note )
253
+ if @@sharps.include?( key )
254
+ note_as_sharp( note )
255
+ else
256
+ note_as_flat( note )
257
+ end
258
+ end
259
+
260
+ # Converts an array of notes to flats or sharps based upon the given key
261
+ #
262
+ # Params:
263
+ #
264
+ # * key: (see Music::allowed_keys)
265
+ # * note: (see Music::allowed_notes)
266
+ def self.name_notes( key, notes = [] )
267
+ notes.map { |n|
268
+ name_note( key, n )
269
+ }
270
+ end
271
+
272
+ # Returns the position (index in the chromatic scale) of the note in the given key.
273
+ # For instance, C# is note 1 in the chromatic scale of C. (Note 0 in the key of C is C.)
274
+ #
275
+ # Params:
276
+ #
277
+ # * key: (see Music::allowed_keys)
278
+ # * note: (see Music::allowed_notes)
279
+ def self.note_position( key, note )
280
+ chromatic_scale( key ).index( @@note_transforms[note] )
281
+ end
282
+
283
+ # Returns the position (index in the chromatic scale) of each note in the array in the given key.
284
+ # For instance, C# is note 1 in the chromatic scale of C. (Note 0 in the key of C is C.)
285
+ #
286
+ # Params:
287
+ #
288
+ # * key: (see Music::allowed_keys)
289
+ # * note: (see Music::allowed_notes)
290
+ def self.note_positions( key, notes )
291
+ notes.map do |note|
292
+ note_position(key, note)
293
+ end
294
+ end
295
+
296
+ # Returns a hash indexing arrays of chords grouped according to their type
297
+ #
298
+ # Optional Params:
299
+ #
300
+ # * max_length : (integer) specifies the maximum length of any given chord. Useful for instruments that are limited in the number of simultaneous notes they can play. The default is 0, or no maximum length
301
+ # * exclude_scales : (boolean) specifies that the scales should not be included. Ignored if max_length = 0
302
+ def self.chord_groups( params = { } )
303
+ options = { max_length: 0, exclude_scales: false }.merge params
304
+ case options[:max_length]
305
+ when 0
306
+ @@chord_groups
307
+ else
308
+ Hash[
309
+ @@chord_groups.map { |name,group|
310
+ if name == :scales and !options[:exclude_scales]
311
+ [ name, group ]
312
+ else
313
+ [ name, group.select { |chord| @@chords[chord].length <= options[:max_length] } ]
314
+ end
315
+ }
316
+ ]
317
+ end
318
+ end
319
+
320
+
321
+ # Returns an array of notes comprising the chromatic scale (all semi-tones) beginning at the root note of the key provided.
322
+ #
323
+ # Params:
324
+ #
325
+ # * key: (see Music::allowed_keys)
326
+ def self.chromatic_scale( key )
327
+ self.chord( key, @@chords["chromatic-scale"] )
328
+ end
329
+
330
+ # Returns a hash of the included scales and their semi-tone members as an array
331
+ def self.scales
332
+ @@scales
333
+ end
334
+
335
+ # Returns the names/notes of the white keys on a piano
336
+ def self.white_keys
337
+ @@white_keys
338
+ end
339
+
340
+ # Returns the names/notes of the black keys on a piano
341
+ def self.black_keys
342
+ @@black_keys
343
+ end
344
+
345
+ # Returns the notes in the specifed key and chord type
346
+ #
347
+ # Params:
348
+ #
349
+ # * key: (see Music::allowed_keys)
350
+ # * chord_name : (see Music::allowed_chords)
351
+ def self.chord_from_name( key, chord_name )
352
+ self.chord( key, @@chords[chord_name.downcase] )
353
+ end
354
+
355
+ # Returns notes in a normalized fashon.
356
+ # This method is not used and may be deprecated in the future
357
+ #
358
+ # Params:
359
+ #
360
+ # * base_note : of the form "Cb" or "C#" or "c-sharp"
361
+ def self.normalize_name( base_note )
362
+ @@note_normalized_names[ base_note.upcase ]
363
+ end
364
+
365
+ # Returns a numeric pointer to the note provided within the @@notes class array
366
+ #
367
+ # Params:
368
+ #
369
+ # * note: (see Music::allowed_notes)
370
+ def self.index_note( note )
371
+ return @@notes.index( @@note_transforms[ note.upcase ] )
372
+ end
373
+
374
+ # Converts the given note into a normalized form.
375
+ # THis method is used primarly for chord manipulation.
376
+ #
377
+ # Params:
378
+ #
379
+ # * note: (see Music::allowed_notes)
380
+ #
381
+ # Returns:
382
+ # * nil : if the note is not valid
383
+ def self.normalize_note( note )
384
+ return @@notes.include?(note.upcase) ? note.upcase : @@note_transforms[ note.upcase ]
385
+ end #Music#normalize_note
386
+
387
+ # Returns a major chord : 1-3-5 with the given base_note (key)
388
+ # This method will likelhy be deprecated in the future. Use Music::chord(base_note,"maj") instead.
389
+ #
390
+ # Params:
391
+ #
392
+ # * base_note: (see Music::allowed_notes)
393
+ def self.major( base_note )
394
+ self.chord( base_note, @@chords["maj"] )
395
+ end # Music#major_triad
396
+
397
+ # Returns a major scale : 1-2-3-4-5-6-7 with the given base_note (key)
398
+ #
399
+ # Params:
400
+ #
401
+ # * base_note: (see Music::allowed_notes)
402
+ def self.major_scale( base_note )
403
+ self.chord( base_note, @@scales[:major] )
404
+ end
405
+
406
+ # Returns a major chord : 1-3b-5 with the given base_note (key)
407
+ # This method will likelhy be deprecated in the future. Use Music::chord(base_note,"min") instead.
408
+ #
409
+ # Params:
410
+ #
411
+ # * base_note: (see Music::allowed_notes)
412
+ def self.minor( base_note )
413
+ self.chord( base_note, @@chords["min"] )
414
+ end
415
+
416
+ # Returns a manor scale : 1-2-3-4-5-6-7 with the given base_note (key)
417
+ #
418
+ # Params:
419
+ #
420
+ # * base_note: (see Music::allowed_notes)
421
+ def self.minor_scale( base_note )
422
+ self.chord( base_note, @@scales[:minor] )
423
+ end
424
+
425
+ # Returns the note with a postivie number of semitones away from the base note
426
+ #
427
+ # Params:
428
+ #
429
+ # * base_note: (see Music::allowed_notes)
430
+ # * offset: a positive integer representing half-steps (semitones) above the base note
431
+ def self.note_from_offset( base_note, offset, params = { } )
432
+ options = { key: nil }.merge params
433
+ base = @@notes.index( Music.normalize_note(base_note))
434
+ raise "Invalid note: #{base_note}" if base.nil?
435
+ options[:key].nil? ? @@notes[ (base + offset) % @@scale_modulus ] : name_note( options[:key], @@notes[ (base + offset) % @@scale_modulus ] )
436
+ end
437
+
438
+ # Returns an array of notes in a chord given a chord pattern
439
+ #
440
+ # Params:
441
+ # * base_note: (see Music::allowed_notes)
442
+ # * chord_pattern: am array positive integers representing half-steps (semitones) above the base note
443
+ def self.chord( base_note, chord_pattern )
444
+ base = @@notes.index( Music.normalize_note(base_note) )
445
+ raise "Invalid note: #{base_note}" if base.nil?
446
+ raise "Invalid chord: #{chord_pattern}" if chord_pattern.nil?
447
+ chord_pattern.map do |step|
448
+ @@notes[ ( base + step ) % @@scale_modulus ]
449
+ end
450
+ end
451
+
452
+ # Converts the specified note to html formatting.
453
+ # Useful for sharps and flats
454
+ #
455
+ # Params:
456
+ #
457
+ # * note:
458
+ def self.note_to_html( note )
459
+ note.gsub("#","&#9839;").gsub(/(\w)[bB]/) { $1 + "&#9837;" }
460
+ end
461
+
462
+ end # Class Music
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: musical-chords
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Patrick Sereno
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This library is designed primarity for rendering chords.
14
+ email: patrick@6orbits.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/music.rb
20
+ homepage: http://6orbits.com/gems/music
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.5.2
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: A library for music theory and practice.
44
+ test_files: []