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

.chromatic_classClass<ScaleKind>

Returns the chromatic scale kind class.

Returns:

  • (Class<ScaleKind>)

    chromatic ScaleKind subclass

Raises:

  • (RuntimeError)

    if chromatic scale not defined



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

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

Returns:

  • (Float)

    default A frequency in Hz (440.0 standard concert pitch)



306
307
308
# File 'lib/musa-dsl/music/scales.rb', line 306

def self.default_a_frequency
  440.0
end

.default_tuningScaleSystemTuning

Returns the default tuning (A=440Hz).

Examples:

tuning = ScaleSystem.default_tuning

Returns:



356
357
358
# File 'lib/musa-dsl/music/scales.rb', line 356

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

Parameters:

  • pitch (Numeric)

    MIDI pitch number (60 = middle C, 69 = A440)

  • root_pitch (Numeric)

    root pitch of scale (for non-equal temperaments)

  • a_frequency (Numeric)

    reference A frequency in Hz

Returns:

  • (Float)

    frequency in Hz

Raises:

  • (RuntimeError)

    if not implemented in subclass



296
297
298
# File 'lib/musa-dsl/music/scales.rb', line 296

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

.get(a_frequency) ⇒ ScaleSystemTuning Also known as: []

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]

Parameters:

  • a_frequency (Numeric)

    reference A frequency in Hz

Returns:



326
327
328
329
330
331
332
333
# File 'lib/musa-dsl/music/scales.rb', line 326

def self.get(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

.idSymbol

This method is abstract.

Subclass must implement

Returns the unique identifier for this scale system.

Examples:

EquallyTempered12ToneScaleSystem.id  # => :et12

Returns:

  • (Symbol)

    the scale system ID (e.g., :et12)

Raises:

  • (RuntimeError)

    if not implemented in subclass



223
224
225
# File 'lib/musa-dsl/music/scales.rb', line 223

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)

Returns:

  • (Hash{Symbol => Integer})

    interval names to semitone offsets

Raises:

  • (RuntimeError)

    if not implemented in subclass



271
272
273
274
275
276
# File 'lib/musa-dsl/music/scales.rb', line 271

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.

Examples:

EquallyTempered12ToneScaleSystem.notes_in_octave  # => 12

Returns:

  • (Integer)

    notes per octave (e.g., 12 for chromatic)

Raises:

  • (RuntimeError)

    if not implemented in subclass



235
236
237
# File 'lib/musa-dsl/music/scales.rb', line 235

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

Parameters:

  • name (Symbol)

    interval name (e.g., :M3, :P5)

Returns:

  • (Integer)

    semitone offset



346
347
348
# File 'lib/musa-dsl/music/scales.rb', line 346

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.

Examples:

EquallyTempered12ToneScaleSystem.part_of_tone_size  # => 1

Returns:

  • (Integer)

    smallest unit size

Raises:

  • (RuntimeError)

    if not implemented in subclass



250
251
252
# File 'lib/musa-dsl/music/scales.rb', line 250

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.

Examples:

EquallyTempered12ToneScaleSystem.register MajorScaleKind

Parameters:

  • scale_kind_class (Class<ScaleKind>)

    ScaleKind subclass to register

Returns:

  • (self)


367
368
369
370
371
372
373
374
# File 'lib/musa-dsl/music/scales.rb', line 367

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<ScaleKind>

Retrieves a registered scale kind by ID.

Parameters:

  • id (Symbol)

    scale kind identifier

Returns:

Raises:

  • (KeyError)

    if not found



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

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.

Parameters:

  • id (Symbol)

    scale kind identifier

Returns:

  • (Boolean)


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

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

.scale_kind_classesHash{Symbol => Class}

Returns all registered scale kinds.

Returns:

  • (Hash{Symbol => Class})

    scale kind classes



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

def self.scale_kind_classes
  @scale_kind_classes
end

Instance Method Details

#==(other) ⇒ Boolean

Compares scale systems for equality.

Parameters:

Returns:

  • (Boolean)


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

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