Class: Musa::Scales::NoteInScale
Overview
Note within a scale context.
NoteInScale represents a specific note within a scale, providing rich musical functionality including:
- Pitch and frequency information
- Interval navigation (up, down, by named intervals)
- Chromatic alterations (sharp, flat)
- Scale navigation (change scales while keeping pitch)
- Chord construction
- Octave transposition
Creation
Notes are created via scale access, not directly:
scale = tuning.major[60]
note = scale.tonic # NoteInScale instance
note = scale[:V] # Another NoteInScale
Basic Properties
note.pitch # MIDI pitch number
note.grade # Scale degree (0-based)
note.octave # Octave relative to scale root
note.frequency # Frequency in Hz
note.functions # Function names for this degree
Interval Navigation
Natural intervals (diatonic, within scale):
note.up(2) # Up 2 scale degrees
note.down(1) # Down 1 scale degree
Chromatic intervals (by semitones or named intervals):
note.up(:P5) # Up perfect fifth
note.up(7) # Up 7 semitones (if chromatic specified)
note.down(:M3) # Down major third
Chromatic Alterations
note.sharp # Raise by 1 semitone
note.sharp(2) # Raise by 2 semitones
note.flat # Lower by 1 semitone
note.flat(2) # Lower by 2 semitones
Scale Navigation
note.scale(:minor) # Same pitch in minor scale
note.major # Same pitch in major scale
note.chromatic # Same pitch in chromatic scale
Chord Construction
note.chord # Build triad
note.chord :seventh # Build seventh chord
note.chord quality: :minor # Build with features
Background Scale Context
Chromatic notes remember their diatonic context:
c# = c_major.tonic.sharp # C# in C major context
c#.background_scale # => c_major
c#.background_note # => C (natural)
c#.background_sharps # => 1
Instance Attribute Summary collapse
-
#background_scale ⇒ Scale?
readonly
Background diatonic scale (for chromatic notes).
-
#background_sharps ⇒ Integer?
readonly
Sharps/flats from background note.
-
#grade ⇒ Integer
readonly
Scale degree (0-based).
-
#pitch ⇒ Numeric
readonly
MIDI pitch number.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Checks note equality.
-
#background_note ⇒ NoteInScale?
Returns the diatonic note this chromatic note is based on.
-
#chord(*feature_values, allow_chromatic: nil, move: nil, duplicate: nil, **features_hash) ⇒ Chord
Builds a chord rooted on this note.
-
#down(interval_name_or_interval, natural_or_chromatic = nil) ⇒ NoteInScale
Navigates downward by interval.
-
#flat(count = nil) ⇒ NoteInScale
Lowers note by semitones (adds flats).
-
#frequency ⇒ Float
Calculates frequency in Hz.
-
#functions ⇒ Array<Symbol>
Returns function names for this scale degree.
-
#initialize(scale, grade, octave, pitch, background_scale: nil, background_grade: nil, background_octave: nil, background_sharps: nil) ⇒ NoteInScale
constructor
private
Creates a note within a scale.
-
#inspect ⇒ String
(also: #to_s)
Returns string representation.
-
#octave(octave = nil, absolute: false) ⇒ Integer, NoteInScale
Transposes note or returns current octave.
-
#on(scale) ⇒ NoteInScale?
Finds this note in another scale.
-
#scale(kind_id_or_kind = nil) ⇒ Scale, NoteInScale
Changes scale while keeping pitch, or returns current scale.
-
#sharp(count = nil) ⇒ NoteInScale
Raises note by semitones (adds sharps).
-
#up(interval_name_or_interval, natural_or_chromatic = nil, sign: nil) ⇒ NoteInScale
Navigates upward by interval.
-
#wide_grade ⇒ Integer
private
Returns wide grade (grade + octave * grades_per_octave).
-
#with_background(scale:, grade: nil, octave: nil, sharps: nil) ⇒ NoteInScale
private
Creates a copy with background scale context.
Constructor Details
#initialize(scale, grade, octave, pitch, background_scale: nil, background_grade: nil, background_octave: nil, background_sharps: nil) ⇒ NoteInScale
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 note within a scale.
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 |
# File 'lib/musa-dsl/music/scales.rb', line 1165 def initialize(scale, grade, octave, pitch, background_scale: nil, background_grade: nil, background_octave: nil, background_sharps: nil) @scale = scale @grade = grade @octave = octave @pitch = pitch @background_scale = background_scale @background_grade = background_grade @background_octave = background_octave @background_sharps = background_sharps @scale.kind.tuning.scale_system.scale_kind_classes.each_key do |name| define_singleton_method name do scale(name) end end end |
Instance Attribute Details
#background_scale ⇒ Scale? (readonly)
Background diatonic scale (for chromatic notes).
1253 1254 1255 |
# File 'lib/musa-dsl/music/scales.rb', line 1253 def background_scale @background_scale end |
#background_sharps ⇒ Integer? (readonly)
Sharps/flats from background note.
1268 1269 1270 |
# File 'lib/musa-dsl/music/scales.rb', line 1268 def background_sharps @background_sharps end |
#grade ⇒ Integer (readonly)
Scale degree (0-based).
1185 1186 1187 |
# File 'lib/musa-dsl/music/scales.rb', line 1185 def grade @grade end |
#pitch ⇒ Numeric (readonly)
MIDI pitch number.
1189 1190 1191 |
# File 'lib/musa-dsl/music/scales.rb', line 1189 def pitch @pitch end |
Instance Method Details
#==(other) ⇒ Boolean
Checks note equality.
Notes are equal if they have same scale, grade, octave, and pitch.
1492 1493 1494 1495 1496 1497 1498 |
# File 'lib/musa-dsl/music/scales.rb', line 1492 def ==(other) self.class == other.class && @scale == other.scale && @grade == other.grade && @octave == other.octave && @pitch == other.pitch end |
#background_note ⇒ NoteInScale?
Returns the diatonic note this chromatic note is based on.
1262 1263 1264 |
# File 'lib/musa-dsl/music/scales.rb', line 1262 def background_note @background_scale[@background_grade + (@background_octave || 0) * @background_scale.kind.class.grades] if @background_grade end |
#chord(*feature_values, allow_chromatic: nil, move: nil, duplicate: nil, **features_hash) ⇒ Chord
Builds a chord rooted on this note.
Creates a chord using this note as the root. Chord can be specified by:
- Feature values (:triad, :seventh, :major, :minor, etc.)
- Feature hash (quality:, size:)
- Chord definition name (not shown here, see Chord.with_root)
If no features specified, defaults to major triad.
1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 |
# File 'lib/musa-dsl/music/scales.rb', line 1470 def chord(*feature_values, allow_chromatic: nil, move: nil, duplicate: nil, **features_hash) features = { size: :triad } if feature_values.empty? && features_hash.empty? features ||= Musa::Chords::ChordDefinition.features_from(feature_values, features_hash) Musa::Chords::Chord.with_root(self, allow_chromatic: allow_chromatic, move: move, duplicate: duplicate, **features) end |
#down(interval_name_or_interval, natural_or_chromatic = nil) ⇒ NoteInScale
Navigates downward by interval.
Same as #up but in reverse direction.
1351 1352 1353 |
# File 'lib/musa-dsl/music/scales.rb', line 1351 def down(interval_name_or_interval, natural_or_chromatic = nil) up(interval_name_or_interval, natural_or_chromatic, sign: -1) end |
#flat(count = nil) ⇒ NoteInScale
Lowers note by semitones (adds flats).
1376 1377 1378 1379 |
# File 'lib/musa-dsl/music/scales.rb', line 1376 def flat(count = nil) count ||= 1 sharp(-count) end |
#frequency ⇒ Float
Calculates frequency in Hz.
Uses the scale system's frequency calculation (equal temperament, just intonation, etc.) and the tuning's A frequency.
1390 1391 1392 |
# File 'lib/musa-dsl/music/scales.rb', line 1390 def frequency @scale.kind.tuning.frequency_of_pitch(@pitch, @scale.root_pitch) end |
#functions ⇒ Array<Symbol>
Returns function names for this scale degree.
1197 1198 1199 |
# File 'lib/musa-dsl/music/scales.rb', line 1197 def functions @scale.kind.class.pitches[grade][:functions] end |
#inspect ⇒ String Also known as: to_s
Returns string representation.
1503 1504 1505 |
# File 'lib/musa-dsl/music/scales.rb', line 1503 def inspect "<NoteInScale: grade = #{@grade} octave = #{@octave} pitch = #{@pitch} scale = (#{@scale.kind.class.name} on #{scale.root_pitch})>" end |
#octave(octave = nil, absolute: false) ⇒ Integer, NoteInScale
Transposes note or returns current octave.
Without argument: Returns current octave relative to scale root.
With argument: Returns note transposed by octave offset.
1221 1222 1223 1224 1225 1226 1227 1228 1229 |
# File 'lib/musa-dsl/music/scales.rb', line 1221 def octave(octave = nil, absolute: false) if octave.nil? @octave else raise ArgumentError, "#{octave} is not integer" unless octave == octave.to_i @scale[@grade + ((absolute ? 0 : @octave) + octave) * @scale.kind.class.grades] end end |
#on(scale) ⇒ NoteInScale?
Finds this note in another scale.
Searches for a note with the same pitch in the target scale.
1435 1436 1437 |
# File 'lib/musa-dsl/music/scales.rb', line 1435 def on(scale) scale.note_of_pitch @pitch end |
#scale(kind_id_or_kind = nil) ⇒ Scale, NoteInScale
Changes scale while keeping pitch, or returns current scale.
Without argument: Returns current scale.
With argument: Returns note at same pitch in different scale kind.
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 |
# File 'lib/musa-dsl/music/scales.rb', line 1412 def scale(kind_id_or_kind = nil) if kind_id_or_kind.nil? @scale else if kind_id_or_kind.is_a? ScaleKind kind_id_or_kind[@pitch] else @scale.kind.tuning[kind_id_or_kind][@pitch] end end end |
#sharp(count = nil) ⇒ NoteInScale
Raises note by semitones (adds sharps).
1363 1364 1365 1366 |
# File 'lib/musa-dsl/music/scales.rb', line 1363 def sharp(count = nil) count ||= 1 calculate_note_of_pitch(@pitch, count) end |
#up(interval_name_or_interval, natural_or_chromatic = nil, sign: nil) ⇒ NoteInScale
Navigates upward by interval.
Supports both natural (diatonic) and chromatic (semitone) intervals.
- Numeric interval + :natural: Move by scale degrees
- Symbol or numeric interval + :chromatic: Move by semitones or named interval
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 |
# File 'lib/musa-dsl/music/scales.rb', line 1300 def up(interval_name_or_interval, natural_or_chromatic = nil, sign: nil) sign ||= 1 if interval_name_or_interval.is_a?(Numeric) natural_or_chromatic ||= :natural else natural_or_chromatic = :chromatic end if natural_or_chromatic == :chromatic interval = if interval_name_or_interval.is_a?(Symbol) @scale.kind.tuning.offset_of_interval(interval_name_or_interval) else interval_name_or_interval end calculate_note_of_pitch(@pitch, sign * interval) else @scale[@grade + sign * interval_name_or_interval] end end |
#wide_grade ⇒ 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 wide grade (grade + octave * grades_per_octave).
1278 1279 1280 |
# File 'lib/musa-dsl/music/scales.rb', line 1278 def wide_grade @grade + @octave * @scale.kind.class.grades end |
#with_background(scale:, grade: nil, octave: nil, sharps: nil) ⇒ NoteInScale
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 copy with background scale context.
Used internally when creating chromatic notes to remember their diatonic context.
1243 1244 1245 1246 1247 1248 1249 |
# File 'lib/musa-dsl/music/scales.rb', line 1243 def with_background(scale:, grade: nil, octave: nil, sharps: nil) NoteInScale.new(@scale, @grade, @octave, @pitch, background_scale: scale, background_grade: grade, background_octave: octave, background_sharps: sharps) end |