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]

Parameters:

  • a_frequency (Numeric)

    reference A frequency in Hz

Returns:



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

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.

Returns:

  • (Class)

    chromatic ScaleKind subclass

Raises:

  • (RuntimeError)

    if chromatic scale not defined



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

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)



277
278
279
# File 'lib/musa-dsl/music/scales.rb', line 277

def self.default_a_frequency
  440.0
end

.default_tuningScaleSystemTuning

Returns the default tuning (A=440Hz).

Examples:

tuning = ScaleSystem.default_tuning

Returns:



323
324
325
# File 'lib/musa-dsl/music/scales.rb', line 323

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



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

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

Returns:

  • (Symbol)

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

Raises:

  • (RuntimeError)

    if not implemented in subclass



194
195
196
# File 'lib/musa-dsl/music/scales.rb', line 194

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



242
243
244
245
246
247
# File 'lib/musa-dsl/music/scales.rb', line 242

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.

Returns:

  • (Integer)

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

Raises:

  • (RuntimeError)

    if not implemented in subclass



206
207
208
# File 'lib/musa-dsl/music/scales.rb', line 206

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



313
314
315
# File 'lib/musa-dsl/music/scales.rb', line 313

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.

Returns:

  • (Integer)

    smallest unit size

Raises:

  • (RuntimeError)

    if not implemented in subclass



221
222
223
# File 'lib/musa-dsl/music/scales.rb', line 221

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.

Parameters:

  • scale_kind_class (Class)

    ScaleKind subclass to register

Returns:

  • (self)


334
335
336
337
338
339
340
341
# File 'lib/musa-dsl/music/scales.rb', line 334

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.

Parameters:

  • id (Symbol)

    scale kind identifier

Returns:

  • (Class)

    ScaleKind subclass

Raises:

  • (KeyError)

    if not found



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

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)


358
359
360
# File 'lib/musa-dsl/music/scales.rb', line 358

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



365
366
367
# File 'lib/musa-dsl/music/scales.rb', line 365

def self.scale_kind_classes
  @scale_kind_classes
end

Instance Method Details

#==(other) ⇒ Boolean

Compares scale systems for equality.

Parameters:

Returns:

  • (Boolean)


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

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