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

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 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



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

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.



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

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)


154
155
156
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 154

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



408
409
410
411
412
413
414
415
416
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 408

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:



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 185

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 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:



253
254
255
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 253

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



359
360
361
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 359

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



368
369
370
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 368

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:



289
290
291
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 289

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



336
337
338
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 336

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 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



270
271
272
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 270

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



310
311
312
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 310

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



393
394
395
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 393

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:



349
350
351
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 349

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:



212
213
214
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 212

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:



225
226
227
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 225

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

File.open('output.xml', 'w') do |f|
  element.to_xml(f)
end

Getting XML as string

xml_string = element.to_xml.string

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:



234
235
236
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 234

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:



323
324
325
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 323

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:



380
381
382
# File 'lib/musa-dsl/musicxml/builder/measure.rb', line 380

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