Class: Musa::Scales::ScaleSystem Abstract

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

Overview

This class is abstract.

Subclass and implement abstract methods

Abstract base class for musical scale systems.

ScaleSystem defines the foundation of a tuning system, including:

  • Number of notes per octave
  • Available intervals
  • Frequency calculation method
  • Registered scale kinds (major, minor, etc.)

Subclass Requirements

Subclasses must implement:

Optionally override:

Usage

ScaleSystem is accessed via Scales module, not instantiated directly:

system = Scales[:et12]           # Get system
tuning = system[440.0]           # Get tuning
scale = tuning.major[60]         # Get scale

Direct Known Subclasses

TwelveSemitonesScaleSystem

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.[](a_frequency) ⇒ ScaleSystemTuning

Creates or retrieves a tuning for this scale system.

Returns a Musa::Scales::ScaleSystemTuning instance for the specified A frequency. Tunings are cached—repeated calls with same frequency return same instance.

Examples:

Standard pitch

tuning = ScaleSystem[440.0]

Baroque pitch

baroque = ScaleSystem[415.0]

Modern high pitch

modern = ScaleSystem[442.0]


322
323
324
325
326
327
328
329
# File 'lib/musa-dsl/music/scales.rb', line 322

def self.[](a_frequency)
  a_frequency = a_frequency.to_f

  @a_tunings ||= {}
  @a_tunings[a_frequency] = ScaleSystemTuning.new self, a_frequency unless @a_tunings.key?(a_frequency)

  @a_tunings[a_frequency]
end

.chromatic_classClass

Returns the chromatic scale kind class.

Raises:

  • (RuntimeError)

    if chromatic scale not defined



398
399
400
401
402
# File 'lib/musa-dsl/music/scales.rb', line 398

def self.chromatic_class
  raise "Chromatic scale kind class for [#{self.id}] scale system undefined" if @chromatic_scale_kind_class.nil?

  @chromatic_scale_kind_class
end

.default_a_frequencyFloat

Returns the default A frequency.

Examples:

ScaleSystem.default_a_frequency  # => 440.0


302
303
304
# File 'lib/musa-dsl/music/scales.rb', line 302

def self.default_a_frequency
  440.0
end

.default_tuningScaleSystemTuning

Returns the default tuning (A=440Hz).

Examples:

tuning = ScaleSystem.default_tuning


348
349
350
# File 'lib/musa-dsl/music/scales.rb', line 348

def self.default_tuning
  self[default_a_frequency]
end

.frequency_of_pitch(pitch, root_pitch, a_frequency) ⇒ Float

This method is abstract.

Subclass must implement

Calculates frequency for a given pitch.

Converts MIDI pitch numbers to frequencies in Hz. The calculation method depends on the tuning system (equal temperament, just intonation, etc.).

Examples:

Equal temperament

# A440 (MIDI 69)
frequency_of_pitch(69, 60, 440.0)  # => 440.0

# Middle C (MIDI 60)
frequency_of_pitch(60, 60, 440.0)  # => ~261.63 Hz

Raises:

  • (RuntimeError)

    if not implemented in subclass



292
293
294
# File 'lib/musa-dsl/music/scales.rb', line 292

def self.frequency_of_pitch(pitch, root_pitch, a_frequency)
  raise 'Method not implemented. Should be implemented in subclass.'
end

.idSymbol

This method is abstract.

Subclass must implement

Returns the unique identifier for this scale system.

Examples:

EquallyTempered12ToneScaleSystem.id  # => :et12

Raises:

  • (RuntimeError)

    if not implemented in subclass



219
220
221
# File 'lib/musa-dsl/music/scales.rb', line 219

def self.id
  raise 'Method not implemented. Should be implemented in subclass.'
end

.intervalsHash{Symbol => Integer}

This method is abstract.

Subclass must implement

Returns available intervals as name-to-offset mapping.

Intervals are named using standard music theory notation:

  • P (Perfect): P1, P4, P5, P8
  • M (Major): M2, M3, M6, M7
  • m (minor): m2, m3, m6, m7
  • TT: Tritone

Examples:

intervals[:M3]   # => 4  (major third = 4 semitones)
intervals[:P5]   # => 7  (perfect fifth = 7 semitones)
intervals[:m7]   # => 10 (minor seventh = 10 semitones)

Raises:

  • (RuntimeError)

    if not implemented in subclass



267
268
269
270
271
272
# File 'lib/musa-dsl/music/scales.rb', line 267

def self.intervals
  # TODO: implementar intérvalos sinónimos (p.ej, m3 = A2)
  # TODO: implementar identificación de intérvalos, teniendo en cuenta no sólo los semitonos sino los grados de separación
  # TODO: implementar inversión de intérvalos
  raise 'Method not implemented. Should be implemented in subclass.'
end

.notes_in_octaveInteger

This method is abstract.

Subclass must implement

Returns the number of notes in one octave.

Raises:

  • (RuntimeError)

    if not implemented in subclass



231
232
233
# File 'lib/musa-dsl/music/scales.rb', line 231

def self.notes_in_octave
  raise 'Method not implemented. Should be implemented in subclass.'
end

.offset_of_interval(name) ⇒ Integer

Returns semitone offset for a named interval.

Examples:

offset_of_interval(:P5)  # => 7


338
339
340
# File 'lib/musa-dsl/music/scales.rb', line 338

def self.offset_of_interval(name)
  intervals[name]
end

.part_of_tone_sizeInteger

This method is abstract.

Subclass must implement

Returns the size of the smallest pitch unit.

Used for calculating sharp (#) and flat (♭) alterations. In equal temperament, this is 1 semitone.

Raises:

  • (RuntimeError)

    if not implemented in subclass



246
247
248
# File 'lib/musa-dsl/music/scales.rb', line 246

def self.part_of_tone_size
  raise 'Method not implemented. Should be implemented in subclass.'
end

.register(scale_kind_class) ⇒ self

Registers a scale kind (major, minor, etc.) with this system.



359
360
361
362
363
364
365
366
# File 'lib/musa-dsl/music/scales.rb', line 359

def self.register(scale_kind_class)
  @scale_kind_classes ||= {}
  @scale_kind_classes[scale_kind_class.id] = scale_kind_class
  if scale_kind_class.chromatic?
    @chromatic_scale_kind_class = scale_kind_class
  end
  self
end

.scale_kind_class(id) ⇒ Class

Retrieves a registered scale kind by ID.

Raises:

  • (KeyError)

    if not found



373
374
375
376
377
# File 'lib/musa-dsl/music/scales.rb', line 373

def self.scale_kind_class(id)
  raise KeyError, "Scale kind class [#{id}] not found in scale system [#{self.id}]" unless @scale_kind_classes.key? id

  @scale_kind_classes[id]
end

.scale_kind_class?(id) ⇒ Boolean

Checks if a scale kind is registered.



383
384
385
# File 'lib/musa-dsl/music/scales.rb', line 383

def self.scale_kind_class?(id)
  @scale_kind_classes.key? id
end

.scale_kind_classesHash{Symbol => Class}

Returns all registered scale kinds.



390
391
392
# File 'lib/musa-dsl/music/scales.rb', line 390

def self.scale_kind_classes
  @scale_kind_classes
end

Instance Method Details

#==(other) ⇒ Boolean

Compares scale systems for equality.



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

def ==(other)
  self.class == other.class
end