Class: Musa::Scales::Scale

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/musa-dsl/music/scales.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(kind, root_pitch:) ⇒ Scale

Returns a new instance of Scale.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/musa-dsl/music/scales.rb', line 266

def initialize(kind, root_pitch:)
  @notes_by_grade = {}
  @notes_by_pitch = {}

  @kind = kind

  @root_pitch = root_pitch

  @kind.class.grades_functions.each do |name|
    define_singleton_method name do
      self[name]
    end
  end

end

Instance Attribute Details

#kindObject (readonly)

Returns the value of attribute kind.



284
285
286
# File 'lib/musa-dsl/music/scales.rb', line 284

def kind
  @kind
end

#root_pitchObject (readonly)

Returns the value of attribute root_pitch.



284
285
286
# File 'lib/musa-dsl/music/scales.rb', line 284

def root_pitch
  @root_pitch
end

Instance Method Details

#==(other) ⇒ Object



413
414
415
416
417
# File 'lib/musa-dsl/music/scales.rb', line 413

def ==(other)
  self.class == other.class &&
      @kind == other.kind &&
      @root_pitch == other.root_pitch
end

#[](grade_or_symbol) ⇒ Object

Raises:

  • (ArgumentError)


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/musa-dsl/music/scales.rb', line 304

def [](grade_or_symbol)

  raise ArgumentError, "grade_or_symbol '#{grade_or_symbol}' should be a Integer, String or Symbol" unless grade_or_symbol.is_a?(Symbol) || grade_or_symbol.is_a?(String) || grade_or_symbol.is_a?(Integer)

  wide_grade, sharps = grade_of(grade_or_symbol)

  unless @notes_by_grade.key?(wide_grade)

    octave = wide_grade / @kind.class.grades
    grade = wide_grade % @kind.class.grades

    pitch = @root_pitch +
        octave * @kind.tuning.notes_in_octave +
        @kind.class.pitches[grade][:pitch]

    note = NoteInScale.new self, grade, octave, pitch

    @notes_by_grade[wide_grade] = @notes_by_pitch[pitch] = note
  end


  @notes_by_grade[wide_grade].sharp(sharps)
end

#absolutObject



294
295
296
# File 'lib/musa-dsl/music/scales.rb', line 294

def absolut
  @kind[0]
end

#chord_of(*grades_or_symbols) ⇒ Object



409
410
411
# File 'lib/musa-dsl/music/scales.rb', line 409

def chord_of(*grades_or_symbols)
  Chord.new(notes: grades_or_symbols.collect { |g| self[g] })
end

#chromaticObject



290
291
292
# File 'lib/musa-dsl/music/scales.rb', line 290

def chromatic
  @kind.tuning.chromatic[@root_pitch]
end

#grade_of(grade_or_string_or_symbol) ⇒ Object



328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/musa-dsl/music/scales.rb', line 328

def grade_of(grade_or_string_or_symbol)
  name, wide_grade, accidentals = parse_grade(grade_or_string_or_symbol)

  grade = @kind.class.grade_of_function name if name

  octave = wide_grade / @kind.class.grades if wide_grade
  grade = wide_grade % @kind.class.grades if wide_grade

  octave ||= 0

  return octave * @kind.class.grades + grade, accidentals
end

#inspectObject Also known as: to_s



419
420
421
# File 'lib/musa-dsl/music/scales.rb', line 419

def inspect
  "<Scale: kind = #{@kind} root_pitch = #{@root_pitch}>"
end

#note_of_pitch(pitch, allow_chromatic: nil, allow_nearest: nil) ⇒ Object



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/musa-dsl/music/scales.rb', line 369

def note_of_pitch(pitch, allow_chromatic: nil, allow_nearest: nil)
  allow_chromatic ||= false
  allow_nearest ||= false

  note = @notes_by_pitch[pitch]

  unless note
    pitch_offset = pitch - @root_pitch

    pitch_offset_in_octave = pitch_offset % @kind.tuning.scale_system.notes_in_octave
    pitch_offset_octave = pitch_offset / @kind.tuning.scale_system.notes_in_octave

    grade = @kind.class.pitches.find_index { |pitch_definition| pitch_definition[:pitch] == pitch_offset_in_octave }

    if grade
      wide_grade = pitch_offset_octave * @kind.class.grades + grade
      note = self[wide_grade]

    elsif allow_nearest
      sharps = 0

      until note
        note = note_of_pitch(pitch - (sharps += 1) * @kind.tuning.scale_system.part_of_tone_size)
        note ||= note_of_pitch(pitch + sharps * @kind.tuning.scale_system.part_of_tone_size)
      end

    elsif allow_chromatic
      nearest = note_of_pitch(pitch, allow_nearest: true)

      note = chromatic.note_of_pitch(pitch).with_background(scale: self, grade: nearest.grade, octave: nearest.octave, sharps: (pitch - nearest.pitch) / @kind.tuning.scale_system.part_of_tone_size)
    end
  end

  note
end

#octave(octave) ⇒ Object

Raises:

  • (ArgumentError)


298
299
300
301
302
# File 'lib/musa-dsl/music/scales.rb', line 298

def octave(octave)
  raise ArgumentError, "#{octave} is not integer" unless octave == octave.to_i

  @kind[@root_pitch + octave * @kind.class.grades]
end

#offset_of_interval(interval_name) ⇒ Object



405
406
407
# File 'lib/musa-dsl/music/scales.rb', line 405

def offset_of_interval(interval_name)
  @kind.tuning.offset_of_interval(interval_name)
end

#parse_grade(neuma_grade) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/musa-dsl/music/scales.rb', line 341

def parse_grade(neuma_grade)
  name = wide_grade = nil
  accidentals = 0

  case neuma_grade
  when Symbol, String
    match = /\A(?<name>[^[#|_]]*)(?<accidental_sharps>#*)(?<accidental_flats>_*)\Z/.match neuma_grade.to_s

    if match
      if match[:name] == match[:name].to_i.to_s
        wide_grade = match[:name].to_i
      else
        name = match[:name].to_sym unless match[:name].empty?
      end
      accidentals = match[:accidental_sharps].length - match[:accidental_flats].length
    else
      name = neuma_grade.to_sym unless (neuma_grade.nil? || neuma_grade.empty?)
    end
  when Numeric
    wide_grade = neuma_grade.to_i

  else
    raise ArgumentError, "Cannot eval #{neuma_grade} as name or grade position."
  end

  return name, wide_grade, accidentals
end

#rootObject



286
287
288
# File 'lib/musa-dsl/music/scales.rb', line 286

def root
  self[0]
end