Class: Musa::MusicXML::Builder::Internal::Measure Private

Inherits:
Object
  • Object
show all
Extended by:
Extension::AttributeBuilder
Includes:
Extension::With, Helper::ToXML
Defined in:
lib/musa-dsl/musicxml/builder/measure.rb

Overview

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

Measure container for musical content.

Measure represents a single measure (bar) of music, containing musical elements in chronological order: attributes, notes, rests, backup/forward commands, and directions (dynamics, tempo markings, etc.).

Element Order

Elements within a measure follow MusicXML's sequential model:

  1. Attributes (key, time, clef, divisions) - typically in first measure
  2. Directions (tempo, dynamics) - before or between notes
  3. Notes/Rests - musical content
  4. Backup/Forward - timeline navigation for multiple voices/staves

Multiple Voices and Staves

For piano (grand staff) or polyphonic notation, use backup to rewind the timeline:

measure do
  # Right hand (treble clef)
  pitch 'C', octave: 5, duration: 4, type: 'quarter', staff: 1
  pitch 'D', octave: 5, duration: 4, type: 'quarter', staff: 1

  backup 8  # Rewind to start of measure

  # Left hand (bass clef)
  pitch 'C', octave: 3, duration: 8, type: 'half', staff: 2
end

Divisions

The divisions attribute sets timing resolution (divisions per quarter note). Higher values allow finer rhythmic subdivisions:

  • divisions: 1 → quarter, half, whole only
  • divisions: 2 → adds eighths
  • divisions: 4 → adds sixteenths
  • divisions: 8 → adds thirty-seconds
  • divisions: 16 → allows complex tuplets

Duration is calculated as: duration = (note_type_value * divisions) / beat_type

The measure the per-method examples are written against

measure = Measure.new(1, divisions: 4)

Examples:

Simple measure with quarter notes

measure = Measure.new(1, divisions: 2) do
  attributes do
    key fifths: 0  # C major
    time beats: 4, beat_type: 4
    clef sign: 'G', line: 2
  end

  pitch 'C', octave: 4, duration: 2, type: 'quarter'
  pitch 'D', octave: 4, duration: 2, type: 'quarter'
  pitch 'E', octave: 4, duration: 2, type: 'quarter'
  pitch 'F', octave: 4, duration: 2, type: 'quarter'
end

Measure with dynamics and tempo

Measure.new(2, divisions: 4) do
  metronome beat_unit: 'quarter', per_minute: 120

  direction do
    dynamics 'p'
    wedge 'crescendo'
  end

  pitch 'C', octave: 4, duration: 4, type: 'quarter'
  pitch 'D', octave: 4, duration: 4, type: 'quarter'

  direction do
    wedge 'stop'
    dynamics 'f'
  end
end

See Also:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(number, divisions: nil, key_cancel: nil, key_fifths: nil, key_mode: nil, time_senza_misura: nil, time_beats: nil, time_beat_type: nil, clef_sign: nil, clef_line: nil, clef_octave_change: nil) { ... } ⇒ Measure

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 new measure.

Examples:

First measure with all attributes

Measure.new(1,
  divisions: 4,
  key_fifths: 2,  # D major
  time_beats: 3, time_beat_type: 4,
  clef_sign: 'G', clef_line: 2
)

Measure with DSL block

Measure.new(2) do
  pitch 'E', octave: 4, duration: 4, type: 'quarter'
  rest duration: 4, type: 'quarter'
end

Parameters:

  • number (Integer)

    measure number (automatically assigned by Part)

  • divisions (Integer, nil) (defaults to: nil)

    divisions per quarter note (timing resolution)

  • key_cancel (Integer, nil) (defaults to: nil)

    key cancellation

  • key_fifths (Integer, nil) (defaults to: nil)

    key signature (-7 to +7, circle of fifths)

  • key_mode (String, nil) (defaults to: nil)

    mode ('major' or 'minor')

  • time_senza_misura (Boolean, nil) (defaults to: nil)

    unmeasured time

  • time_beats (Integer, nil) (defaults to: nil)

    time signature numerator

  • time_beat_type (Integer, nil) (defaults to: nil)

    time signature denominator

  • clef_sign (String, nil) (defaults to: nil)

    clef sign ('G', 'F', 'C')

  • clef_line (Integer, nil) (defaults to: nil)

    clef line number

  • clef_octave_change (Integer, nil) (defaults to: nil)

    octave transposition

Yields:

  • Optional DSL block for adding measure content



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 131

def initialize(number, divisions: nil,
               key_cancel: nil, key_fifths: nil, key_mode: nil,
               time_senza_misura: nil, time_beats: nil, time_beat_type: nil,
               clef_sign: nil, clef_line: nil, clef_octave_change: nil,
               &block)

  @number = number
  @elements = []

  @attributes = []

  if divisions ||
      key_cancel || key_fifths || key_mode ||
      time_senza_misura || time_beats || time_beat_type ||
      clef_sign || clef_line || clef_octave_change

    add_attributes divisions: divisions,
                   key_cancel: key_cancel, key_fifths: key_fifths, key_mode: key_mode,
                   time_senza_misura: time_senza_misura, time_beats: time_beats, time_beat_type: time_beat_type,
                   clef_sign: clef_sign, clef_line: clef_line, clef_octave_change: clef_octave_change
  end

  with &block if block_given?
end

Instance Attribute Details

#elementsArray<Object> (readonly)

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.

Ordered list of elements in this measure.

Returns:

  • (Array<Object>)

    notes, rests, attributes, directions, etc.



162
163
164
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 162

def elements
  @elements
end

#numberInteger

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.

Measure number.

Returns:

  • (Integer)


158
159
160
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 158

def number
  @number
end

Class Method Details

.attr_complex_adder_to_array(name, klass, plural: nil, variable: nil) ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates methods for adding complex objects (with multiple parameters) to an array.

Supports both positional and keyword arguments when creating instances.

Parameters:

  • name (Symbol)

    singular name.

  • klass (Class)

    class to instantiate.

  • plural (Symbol, nil) (defaults to: nil)

    plural name.

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name.

.attr_complex_adder_to_custom(name, plural: nil, variable: nil) { ... } ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates methods for adding complex objects with custom construction logic.

The block receives parameters and should construct and add the object.

Parameters:

  • name (Symbol)

    singular name.

  • plural (Symbol, nil) (defaults to: nil)

    plural name.

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name.

Yields:

  • Constructor block executed in instance context.

.attr_complex_builder(name, klass, variable: nil, first_parameter: nil) ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates a getter/setter DSL method for complex objects with multiple parameters.

Supports optional first_parameter that's automatically prepended when constructing.

Parameters:

  • name (Symbol)

    attribute name.

  • klass (Class)

    class to instantiate.

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name.

  • first_parameter (Object, nil) (defaults to: nil)

    parameter automatically prepended to constructor.

.attr_simple_builder(name, klass = nil, variable: nil) ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates a simple getter/setter DSL method for a single value.

Parameters:

  • name (Symbol)

    attribute name.

  • klass (Class, nil) (defaults to: nil)

    class to instantiate (nil = use value as-is).

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name.

.attr_tuple_adder_to_array(name, klass, plural: nil, variable: nil) ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates methods for adding id/value tuples to an array collection.

Similar to attr_tuple_adder_to_hash but stores items in an array instead of hash. Useful when order matters or duplicates are allowed.

Parameters:

  • name (Symbol)

    singular name for the item.

  • klass (Class)

    class to instantiate.

  • plural (Symbol, nil) (defaults to: nil)

    plural name.

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name.

.attr_tuple_adder_to_hash(name, klass, plural: nil, variable: nil) ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates methods for adding id/value tuples to a hash collection.

Generates:

  • add_#{name}(id, parameter) → creates instance and adds to hash
  • #{plural}(**parameters) → batch add or retrieve hash

Parameters:

  • name (Symbol)

    singular name for the item.

  • klass (Class)

    class to instantiate (receives id, parameter).

  • plural (Symbol, nil) (defaults to: nil)

    plural name (defaults to name + 's').

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name (defaults to '@' + plural).

.attr_tuple_builder(name, klass, variable: nil) ⇒ Object Originally defined in module Extension::AttributeBuilder

Creates a getter/setter DSL method for a single id/value tuple.

Parameters:

  • name (Symbol)

    attribute name.

  • klass (Class)

    class to instantiate.

  • variable (Symbol, nil) (defaults to: nil)

    instance variable name.

Instance Method Details

#_to_xml(io, indent:, tabs:) ⇒ void

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.

This method returns an undefined value.

Generates the measure XML element with all contained elements.

Outputs elements in the order they were added, which must follow MusicXML's element ordering rules (attributes, then notes/directions/backup/forward).

Parameters:

  • io (IO)

    output stream

  • indent (Integer)

    indentation level

  • tabs (String)

    tab string



412
413
414
415
416
417
418
419
420
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 412

def _to_xml(io, indent:, tabs:)
  io.puts "#{tabs}<measure number=\"#{@number.to_i}\">"

  @elements.each do |element|
    element.to_xml(io, indent: indent + 1)
  end

  io.puts "#{tabs}</measure>"
end

#attributes { ... } ⇒ Attributes

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.

Adds musical attributes to the measure.

Attributes define key signature, time signature, clef, and timing divisions. Typically appear at the start of the first measure or when they change.

Examples:

Via DSL block

measure.attributes do
  divisions 4
  key fifths: 1  # G major
  time beats: 3, beat_type: 4
  clef sign: 'G', line: 2
end

Yields:

  • Optional DSL block for adding keys, times, clefs

Returns:



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 189

attr_complex_adder_to_custom :attributes, plural: :attributes, variable: :@attributes do
| divisions: nil,
    key_cancel: nil, key_fifths: nil, key_mode: nil,
    time_senza_misura: nil, time_beats: nil, time_beat_type: nil,
    clef_sign: nil, clef_line: nil, clef_octave_change: nil,
    &block |

  Attributes.new(divisions: divisions,
                 key_cancel: key_cancel, key_fifths: key_fifths, key_mode: key_mode,
                 time_senza_misura: time_senza_misura, time_beats: time_beats, time_beat_type: time_beat_type,
                 clef_sign: clef_sign, clef_line: clef_line, clef_octave_change: clef_octave_change, &block) \
        .tap do |attributes|

    @attributes << attributes
    @elements << attributes
  end
end

#backupBackup

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.

Rewinds the musical timeline.

Backup moves the current time position backward by the specified duration, allowing multiple voices or staves to be layered in the same time span.

Examples:

Piano grand staff

Measure.new(1, divisions: 2) do
  pitch 'C', octave: 5, duration: 8, type: 'half', staff: 1
  backup 8  # Rewind to start
  pitch 'C', octave: 3, duration: 8, type: 'half', staff: 2
end

Returns:

  • (Backup)

    the created backup element

See Also:



257
258
259
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 257

attr_complex_adder_to_custom :backup do |duration|
  Backup.new(duration).tap { |backup| @elements << backup }
end

#bracketDirection

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.

Adds bracket notation.

Returns:

  • (Direction)

    direction containing bracket



363
364
365
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 363

attr_complex_adder_to_custom(:bracket) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { bracket *p, **kp, &b } }

#dashesDirection

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.

Adds dashed line.

Returns:

  • (Direction)

    direction containing dashes



372
373
374
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 372

attr_complex_adder_to_custom(:dashes) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { dashes *p, **kp, &b } }

#direction { ... } ⇒ Direction

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.

Adds a direction element (dynamics, tempo, expressions).

Directions contain non-note musical instructions like dynamics (p, f), tempo markings, wedges (crescendo/diminuendo), pedal marks, etc.

Examples:

Dynamics with crescendo

measure.direction do
  dynamics 'p'
  wedge 'crescendo'
end

Yields:

  • Optional DSL block for direction content

Returns:

See Also:



293
294
295
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 293

attr_complex_adder_to_custom :direction do |*parameters, **key_parameters, &block|
  Direction.new(*parameters, **key_parameters, &block).tap { |direction| @elements << direction }
end

#dynamicsDirection

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.

Adds dynamics (p, pp, f, ff, etc.).

Examples:

measure.dynamics 'pp'
measure.dynamics ['mf', 'sf']  # Multiple dynamics

Returns:

  • (Direction)

    direction containing dynamics



340
341
342
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 340

attr_complex_adder_to_custom(:dynamics) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { dynamics *p, **kp, &b } }

#forwardForward

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.

Advances the musical timeline.

Forward moves the current time position forward without sounding, creating rests or gaps in the timeline.

Examples:

Skip to beat 3

Measure.new(1, divisions: 2) do
  pitch 'C', octave: 4, duration: 2, type: 'quarter'
  forward 4  # Skip 2 beats
  pitch 'D', octave: 4, duration: 2, type: 'quarter'
end

Returns:

  • (Forward)

    the created forward element



274
275
276
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 274

attr_complex_adder_to_custom :forward do |duration, voice: nil, staff: nil|
  Forward.new(duration, voice: voice, staff: staff).tap { |forward| @elements << forward }
end

#metronome { ... } ⇒ Direction

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.

Adds a metronome (tempo) marking.

Examples:

measure.metronome beat_unit: 'quarter', per_minute: 120

Yields:

  • Optional block

Returns:

  • (Direction)

    direction containing metronome



314
315
316
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 314

attr_complex_adder_to_custom(:metronome) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { metronome *p, **kp, &b } }

#octave_shiftDirection

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.

Adds octave shift (8va/8vb).

Examples:

measure.octave_shift 'up', size: 8

Returns:

  • (Direction)

    direction containing octave_shift



397
398
399
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 397

attr_complex_adder_to_custom(:octave_shift) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { octave_shift *p, **kp, &b } }

#pedalDirection

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.

Adds pedal marking.

Examples:

measure.pedal 'start', line: true

Returns:



353
354
355
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 353

attr_complex_adder_to_custom(:pedal) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { pedal *p, **kp, &b } }

#pitchPitchedNote

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.

Adds a pitched note.

Examples:

measure.pitch 'C', octave: 4, duration: 4, type: 'quarter'
measure.pitch step: 'E', octave: 4, duration: 2, type: 'eighth', dots: 1

Returns:

See Also:



216
217
218
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 216

attr_complex_adder_to_custom :pitch do | *parameters, **key_parameters |
  PitchedNote.new(*parameters, **key_parameters).tap { |note| @elements << note }
end

#restRest

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.

Adds a rest.

Examples:

measure.rest duration: 4, type: 'quarter'
measure.rest duration: 8, type: 'half', measure: true  # whole measure rest

Returns:

  • (Rest)

    the created rest

See Also:



229
230
231
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 229

attr_complex_adder_to_custom :rest do | *parameters, **key_parameters |
  Rest.new(*parameters, **key_parameters).tap { |rest| @elements << rest }
end

#to_xml(io = nil, indent: nil) ⇒ IO, StringIO Originally defined in module Helper::ToXML

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.

Converts the object to MusicXML format.

This method sets up the IO stream and indentation, then delegates to the private _to_xml method for actual XML generation.

Examples:

Writing to file

element = Measure.new(1, divisions: 2)
File.open('output.xml', 'w') do |f|
  element.to_xml(f)
end

Getting XML as string

xml_string = element.to_xml.string
xml_string.start_with?('<measure')  # => true

Parameters:

  • io (IO, StringIO, nil) (defaults to: nil)

    output stream (creates StringIO if nil)

  • indent (Integer, nil) (defaults to: nil)

    indentation level (default: 0)

Returns:

  • (IO, StringIO)

    the io parameter, containing the XML output

#unpitchedUnpitchedNote

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.

Adds an unpitched note (for percussion).

Returns:

See Also:



238
239
240
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 238

attr_complex_adder_to_custom :unpitched do | *parameters, **key_parameters |
  UnpitchedNote.new(*parameters, **key_parameters).tap { |unpitched| @elements << unpitched }
end

#wedgeDirection

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.

Adds a wedge (crescendo/diminuendo).

Examples:

measure.wedge 'crescendo', niente: true

Returns:



327
328
329
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 327

attr_complex_adder_to_custom(:wedge) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { wedge *p, **kp, &b } }

#with(*value_parameters, keep_block_context: nil, **key_parameters, &block) ⇒ Object Originally defined in module Extension::With

Note:

The _ parameter is special: when present, it signals "keep caller's context" and receives self (the object) as its value.

Note:

Uses SmartProcBinder internally to handle parameter matching.

Executes a block with flexible context and parameter handling.

Parameters:

  • value_parameters (Array)

    positional parameters to pass to block.

  • keep_block_context (Boolean, nil) (defaults to: nil)

    explicit control of context switching:

    • true: always keep caller's context
    • false: always use object's context
    • nil: auto-detect based on _ parameter
  • key_parameters (Hash)

    keyword parameters to pass to block.

  • block (Proc)

    block to execute.

Returns:

  • (Object)

    result of block execution.

#wordsDirection

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.

Adds text annotation.

Examples:

measure.words "rit.", placement: 'above'

Returns:



384
385
386
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 384

attr_complex_adder_to_custom(:words) {
|*p, placement: nil, offset: nil, **kp, &b|
direction(placement: placement, offset: offset) { words *p, **kp, &b } }