Class: Musa::MusicXML::Builder::Internal::Time Private

Inherits:
Object
  • Object
show all
Includes:
Extension::With, Helper::ToXML
Defined in:
lib/musa-dsl/musicxml/builder/attributes.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.

Time signature specification.

Time represents time signatures in MusicXML. It supports simple meters (4/4, 3/4), compound meters (6/8), complex meters (5/4), and compound time signatures with multiple beat groups. Also supports unmeasured time (senza misura) for cadenzas and free-form sections.

For multi-staff parts (like piano), the number attribute specifies which staff the time signature applies to.

Simple Time Signatures

Most common meters use a single beats/beat_type pair:

  • 4/4 (common time): beats=4, beat_type=4
  • 3/4 (waltz): beats=3, beat_type=4
  • 6/8 (compound): beats=6, beat_type=8
  • 2/2 (cut time): beats=2, beat_type=2

Reaching it

Time signatures are written through the attributes DSL rather than constructed directly. The examples below are against:

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

The class itself is Musa::MusicXML::Builder::Internal::Time, which collides with Ruby's own Time anywhere outside this file.

Compound Time Signatures

Some meters combine multiple beat groups (e.g., 3+2+3/8). These are built by calling #add_beats once per group, either on the object or inside the configuration block, which is the only route the DSL has -- the adder builds the Time itself and hands back no reference.

Senza Misura (Unmeasured Time)

For cadenzas and free-form sections without strict meter, pass senza_misura: ''.

Examples:

Common time (4/4)

measure.attributes { time beats: 4, beat_type: 4 }

# The element it builds, on its own. The name has to be qualified:
# bare `Time` is Ruby's own.
Musa::MusicXML::Builder::Internal::Time.new(beats: 4, beat_type: 4).to_xml.string
# => "<time>\n\t<beats>4</beats>\n\t<beat-type>4</beat-type>\n</time>\n"

Waltz (3/4)

measure.attributes { time beats: 3, beat_type: 4 }

Compound meter (6/8)

measure.attributes { time beats: 6, beat_type: 8 }

Compound signature (3+2+3/8)

signature = Musa::MusicXML::Builder::Internal::Time.new
signature.add_beats(beats: 3, beat_type: 8)
signature.add_beats(beats: 2, beat_type: 8)
signature.add_beats(beats: 3, beat_type: 8)
signature.beats.size  # => 3

signature.to_xml.string
# => "<time>\n\t<beats>3</beats>\n\t<beat-type>8</beat-type>\n\t<beats>2</beats>\n\t<beat-type>8</beat-type>\n\t<beats>3</beats>\n\t<beat-type>8</beat-type>\n</time>\n"

# Three beats/beat-type pairs inside ONE <time>: that is how MusicXML
# writes an additive signature, and it is why `add_beats` exists
# alongside the `beats:` keyword.

The same, through the DSL

compound = measure.attributes do
  time do
    add_beats beats: 3, beat_type: 8
    add_beats beats: 2, beat_type: 8
    add_beats beats: 3, beat_type: 8
  end
end
compound.times.first.beats.size  # => 3

Piano - different time per staff

measure.attributes do
  time 1, beats: 4, beat_type: 4  # Treble: 4/4
  time 2, beats: 3, beat_type: 4  # Bass: 3/4
end

Cadenza (unmeasured)

measure.attributes { time senza_misura: '' }

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(number = nil, senza_misura: nil, beats: nil, beat_type: nil, &block) ⇒ Time

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 time signature.

Examples:

4/4 time

measure.attributes { time beats: 4, beat_type: 4 }

6/8 time

measure.attributes { time beats: 6, beat_type: 8 }

Unmeasured time

measure.attributes { time senza_misura: '' }

Compound meter (3+2+3/8), which needs the block

attributes = Musa::MusicXML::Builder::Internal::Attributes.new
attributes.time do
  add_beats beats: 3, beat_type: 8
  add_beats beats: 2, beat_type: 8
  add_beats beats: 3, beat_type: 8
end
attributes.times.first.beats.size  # => 3

Parameters:

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

    staff number (for multi-staff parts)

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

    unmeasured time indicator (typically empty string)

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

    time signature numerator (beats per measure)

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

    time signature denominator (note value per beat)



229
230
231
232
233
234
235
236
237
238
# File 'lib/musa-dsl/musicxml/builder/attributes.rb', line 229

def initialize(number = nil, senza_misura: nil, beats: nil, beat_type: nil, &block)
  @number = number

  @senza_misura = senza_misura unless beats && beat_type
  @beats = []

  add_beats beats: beats, beat_type: beat_type if beats && beat_type

  with &block if block_given?
end

Instance Attribute Details

#beatsArray<Hash> (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.

Array of beat groups for compound time signatures.

Returns:



250
251
252
# File 'lib/musa-dsl/musicxml/builder/attributes.rb', line 250

def beats
  @beats
end

#numberInteger? (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.

Staff number (for multi-staff instruments).

Returns:

  • (Integer, nil)


242
243
244
# File 'lib/musa-dsl/musicxml/builder/attributes.rb', line 242

def number
  @number
end

#senza_misuraString?

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.

Senza misura indicator for unmeasured time.

Returns:



246
247
248
# File 'lib/musa-dsl/musicxml/builder/attributes.rb', line 246

def senza_misura
  @senza_misura
end

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 time signature XML element.

Parameters:

  • io (IO)

    output stream

  • indent (Integer)

    indentation level

  • tabs (String)

    tab string



279
280
281
282
283
284
285
286
287
288
289
# File 'lib/musa-dsl/musicxml/builder/attributes.rb', line 279

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

  io.puts "#{tabs}\t<senza-misura>#{@senza_misura}</senza-misura>" if @senza_misura
  @beats.each do |beats|
    io.puts "#{tabs}\t<beats>#{beats[:beats].to_i}</beats>"
    io.puts "#{tabs}\t<beat-type>#{beats[:beat_type].to_i}</beat-type>"
  end

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

#add_beats(beats:, beat_type:) ⇒ 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.

Adds a beat group to the time signature.

Used for compound time signatures that combine multiple beat groups (e.g., 3+2+3/8 or 2+2+3/4).

Examples:

Complex meter (3+2+3/8)

signature = Musa::MusicXML::Builder::Internal::Time.new
signature.add_beats(beats: 3, beat_type: 8)
signature.add_beats(beats: 2, beat_type: 8)
signature.add_beats(beats: 3, beat_type: 8)
signature.beats.size  # => 3

Parameters:

  • beats (Integer)

    numerator for this beat group

  • beat_type (Integer)

    denominator for this beat group



267
268
269
# File 'lib/musa-dsl/musicxml/builder/attributes.rb', line 267

def add_beats(beats:, beat_type:)
  @beats << { beats: beats, beat_type: beat_type }
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

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