Class: Musa::Scales::ScaleSystem Abstract
Overview
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:
- ScaleSystem.id: Unique symbol identifier
- ScaleSystem.notes_in_octave: Number of notes in an octave
- ScaleSystem.part_of_tone_size: Size of smallest pitch unit (for sharps/flats)
- ScaleSystem.intervals: Hash of named intervals to semitone offsets
- ScaleSystem.frequency_of_pitch: Pitch to frequency conversion
Optionally override:
- ScaleSystem.default_a_frequency: Reference A frequency (defaults to 440.0 Hz)
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
Class Method Summary collapse
-
.chromatic_class ⇒ Class<ScaleKind>
Returns the chromatic scale kind class.
-
.default_a_frequency ⇒ Float
Returns the default A frequency.
-
.default_tuning ⇒ ScaleSystemTuning
Returns the default tuning (A=440Hz).
-
.frequency_of_pitch(pitch, root_pitch, a_frequency) ⇒ Float
abstract
Calculates frequency for a given pitch.
-
.get(a_frequency) ⇒ ScaleSystemTuning
(also: [])
Creates or retrieves a tuning for this scale system.
-
.id ⇒ Symbol
abstract
Returns the unique identifier for this scale system.
-
.intervals ⇒ Hash{Symbol => Integer}
abstract
Returns available intervals as name-to-offset mapping.
-
.notes_in_octave ⇒ Integer
abstract
Returns the number of notes in one octave.
-
.offset_of_interval(name) ⇒ Integer
Returns semitone offset for a named interval.
-
.part_of_tone_size ⇒ Integer
abstract
Returns the size of the smallest pitch unit.
-
.register(scale_kind_class) ⇒ self
Registers a scale kind (major, minor, etc.) with this system.
-
.scale_kind_class(id) ⇒ Class<ScaleKind>
Retrieves a registered scale kind by ID.
-
.scale_kind_class?(id) ⇒ Boolean
Checks if a scale kind is registered.
-
.scale_kind_classes ⇒ Hash{Symbol => Class}
Returns all registered scale kinds.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Compares scale systems for equality.
Class Method Details
.chromatic_class ⇒ Class<ScaleKind>
Returns the chromatic scale kind class.
447 448 449 450 451 |
# File 'lib/musa-dsl/music/scales.rb', line 447 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_frequency ⇒ Float
Returns the default A frequency.
322 323 324 |
# File 'lib/musa-dsl/music/scales.rb', line 322 def self.default_a_frequency 440.0 end |
.default_tuning ⇒ ScaleSystemTuning
Returns the default tuning (A=440Hz).
373 374 375 |
# File 'lib/musa-dsl/music/scales.rb', line 373 def self.default_tuning self[default_a_frequency] end |
.frequency_of_pitch(pitch, root_pitch, a_frequency) ⇒ Float
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.).
312 313 314 |
# File 'lib/musa-dsl/music/scales.rb', line 312 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.
343 344 345 346 347 348 349 350 |
# File 'lib/musa-dsl/music/scales.rb', line 343 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 |
.id ⇒ Symbol
Subclass must implement
Returns the unique identifier for this scale system.
240 241 242 |
# File 'lib/musa-dsl/music/scales.rb', line 240 def self.id raise 'Method not implemented. Should be implemented in subclass.' end |
.intervals ⇒ Hash{Symbol => Integer}
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
289 290 291 292 293 294 |
# File 'lib/musa-dsl/music/scales.rb', line 289 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_octave ⇒ Integer
Subclass must implement
Returns the number of notes in one octave.
252 253 254 |
# File 'lib/musa-dsl/music/scales.rb', line 252 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.
363 364 365 |
# File 'lib/musa-dsl/music/scales.rb', line 363 def self.offset_of_interval(name) intervals[name] end |
.part_of_tone_size ⇒ Integer
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.
267 268 269 |
# File 'lib/musa-dsl/music/scales.rb', line 267 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.
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/musa-dsl/music/scales.rb', line 396 def self.register(scale_kind_class) @scale_kind_classes ||= {} # Same reasoning as ChordDefinition.register, with a twist that made it # worse: replacing the class here does NOT reach the tunings that have # already built a scale of that kind, because those are cached. So a # silent replacement gave two different answers depending on whether # anyone had asked before. if (existing = @scale_kind_classes[scale_kind_class.id]) raise ArgumentError, "scale kind #{scale_kind_class.id.inspect} is already registered " \ "as #{existing.name}; unregister it first if you mean to replace it" end @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.
422 423 424 425 426 |
# File 'lib/musa-dsl/music/scales.rb', line 422 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.
432 433 434 |
# File 'lib/musa-dsl/music/scales.rb', line 432 def self.scale_kind_class?(id) @scale_kind_classes.key? id end |
.scale_kind_classes ⇒ Hash{Symbol => Class}
Returns all registered scale kinds.
439 440 441 |
# File 'lib/musa-dsl/music/scales.rb', line 439 def self.scale_kind_classes @scale_kind_classes end |
Instance Method Details
#==(other) ⇒ Boolean
Compares scale systems for equality.
457 458 459 |
# File 'lib/musa-dsl/music/scales.rb', line 457 def ==(other) self.class == other.class end |