Class: Musa::Scales::ScaleKind 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 scale types (major, minor, chromatic, etc.).

ScaleKind defines a type of scale (major, minor, chromatic, etc.) independent of root pitch or tuning. It specifies:

  • Scale degrees and their pitch offsets
  • Function names for each degree (tonic, dominant, etc.)
  • Number of grades per octave
  • Whether the scale is chromatic (contains all pitches)

Subclass Requirements

Subclasses must implement:

Pitch Structure

The ScaleKind.pitches array defines the scale structure:

[{ functions: [:I, :tonic, :_1], pitch: 0 },
 { functions: [:II, :supertonic, :_2], pitch: 2 },
 ...]
  • functions: Array of symbols that can access this degree
  • pitch: Semitone offset from root

Dynamic Method Creation

Each scale instance gets methods for all registered scale kinds:

note.major     # Get major scale rooted on this note
note.minor     # Get minor scale rooted on this note

Usage

ScaleKind instances are accessed via tuning:

tuning = Scales[:et12][440.0]
major_kind = tuning[:major]        # ScaleKind instance
c_major = major_kind[60]           # Scale instance

Or directly via convenience methods:

c_major = tuning.major[60]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tuning) ⇒ ScaleKind

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates a scale kind instance.



535
536
537
538
# File 'lib/musa-dsl/music/scales.rb', line 535

def initialize(tuning)
  @tuning = tuning
  @scales = {}
end

Instance Attribute Details

#tuningScaleSystemTuning (readonly)

The tuning context.



542
543
544
# File 'lib/musa-dsl/music/scales.rb', line 542

def tuning
  @tuning
end

Class Method Details

.chromatic?Boolean

Indicates whether this is the chromatic scale.

Only one scale kind per system should return true. The chromatic scale contains all notes in the scale system and is used as a fallback for non-diatonic notes.

Examples:

ChromaticScaleKind.chromatic?  # => true
MajorScaleKind.chromatic?      # => false


640
641
642
# File 'lib/musa-dsl/music/scales.rb', line 640

def self.chromatic?
  false
end

.grade_of_function(symbol) ⇒ Integer?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns grade index for a function symbol.

Examples:

MajorScaleKind.grade_of_function(:tonic)     # => 0
MajorScaleKind.grade_of_function(:dominant)  # => 4
MajorScaleKind.grade_of_function(:V)         # => 4


669
670
671
672
# File 'lib/musa-dsl/music/scales.rb', line 669

def self.grade_of_function(symbol)
  create_grade_functions_index unless @grade_names_index
  @grade_names_index[symbol]
end

.gradesInteger

Returns the number of grades per octave.

For scales defining extended harmony (8th, 9th, etc.), this returns the number of diatonic degrees within one octave. Defaults to the number of pitch definitions.

Examples:

MajorScaleKind.grades  # => 7 (not 13, even with extended degrees)


654
655
656
# File 'lib/musa-dsl/music/scales.rb', line 654

def self.grades
  pitches.length
end

.grades_functionsArray<Symbol>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns all function symbols for accessing scale degrees.

Examples:

MajorScaleKind.grades_functions
# => [:I, :_1, :tonic, :first, :II, :_2, :supertonic, :second, ...]


683
684
685
686
# File 'lib/musa-dsl/music/scales.rb', line 683

def self.grades_functions
  create_grade_functions_index unless @grade_names_index
  @grade_names_index.keys
end

.idSymbol

This method is abstract.

Subclass must implement

Returns the unique identifier for this scale kind.

Examples:

MajorScaleKind.id  # => :major

Raises:

  • (RuntimeError)

    if not implemented in subclass



605
606
607
# File 'lib/musa-dsl/music/scales.rb', line 605

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

.pitchesArray<Hash>

This method is abstract.

Subclass must implement

Returns the pitch structure definition.

Defines the scale degrees and their pitch offsets from the root. Each entry specifies function names and semitone offset.

Examples:

Major scale structure (partial)

[{ functions: [:I, :tonic, :_1], pitch: 0 },
 { functions: [:II, :supertonic, :_2], pitch: 2 },
 { functions: [:III, :mediant, :_3], pitch: 4 },
 ...]

Raises:

  • (RuntimeError)

    if not implemented in subclass



625
626
627
# File 'lib/musa-dsl/music/scales.rb', line 625

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

Instance Method Details

#==(other) ⇒ Boolean

Checks scale kind equality.



584
585
586
# File 'lib/musa-dsl/music/scales.rb', line 584

def ==(other)
  self.class == other.class && @tuning == other.tuning
end

#[](root_pitch) ⇒ Scale

Creates or retrieves a scale rooted on specific pitch.

Scales are cached—repeated calls with same pitch return same instance.

Examples:

major_kind = tuning[:major]
c_major = major_kind[60]     # C major
g_major = major_kind[67]     # G major


555
556
557
558
# File 'lib/musa-dsl/music/scales.rb', line 555

def [](root_pitch)
  @scales[root_pitch] = Scale.new(self, root_pitch: root_pitch) unless @scales.key?(root_pitch)
  @scales[root_pitch]
end

#absolutScale

Returns scale with absolute root (MIDI 0).

Examples:

tuning.major.absolut  # Scale rooted at MIDI 0


576
577
578
# File 'lib/musa-dsl/music/scales.rb', line 576

def absolut
  self[0]
end

#default_rootScale

Returns scale with default root (middle C, MIDI 60).

Examples:

tuning.major.default_root  # C major


566
567
568
# File 'lib/musa-dsl/music/scales.rb', line 566

def default_root
  self[60]
end

#inspectString Also known as: to_s

Returns string representation.



591
592
593
# File 'lib/musa-dsl/music/scales.rb', line 591

def inspect
  "<#{self.class.name}: tuning = #{@tuning}>"
end