module Alda::EventList

Including this module can make your class have the ability to have an event list. See docs below to get an overview of its functions.

Attributes

events[RW]

The array containing the events (Alda::Event objects), most of which are Alda::EventContainer objects.

variables[RW]

The set containing the available variable names.

Public Class Methods

new(&block) → Alda::EventList click to toggle source

The parameter block is to be passed with the Alda::EventList object as self.

Note that block is not called immediately. It is instead called in on_contained. Specially, Alda::Score::new calls on_contained.

Alda::Score.new do
  tempo! 108           # inline lisp
  piano_               # piano part
  o4                   # octave 4
  c8; d; e; f          # notes
  g4 g a f g e f d e c # a sequence
  d4_8                 # cannot have '~', use '_' instead
  o3 b8 o4 c2          # a sequence
end
# => #<Alda::Score:0x... @events=[...]>

For a list of sugars, see method_missing.

# File lib/alda-rb/event_list.rb, line 184
def initialize &block
  @events ||= []
  @variables ||= Set.new
  @block ||= block
end

Public Instance Methods

event_list == other → true or false click to toggle source

Returns true if other is of the same class as event_list and they have the same (in the sense of ==) events and variables.

Calls superclass method
# File lib/alda-rb/event_list.rb, line 215
def == other
  super || self.class == other.class && @events == other.events && @variables == other.variables
end
events_alda_codes(delimiter=" ") → String click to toggle source

Join the alda codes of events with a specified delimiter. Returns a string representing the result.

# File lib/alda-rb/event_list.rb, line 205
def events_alda_codes delimiter = ' '
  @events.map(&:to_alda_code).join delimiter
end
has_variable?(name) → true or false click to toggle source

Whether there is a previously declared alda variable whose name is specified by name.

Searches variables in parent.

# File lib/alda-rb/event_list.rb, line 145
def has_variable? name
  @variables.include?(name) || !!@parent&.has_variable?(name)
end
import(event_list) → nil click to toggle source

Append the events of another Alda::EventList object here. This method covers the disadvantage of alda’s being unable to import scores from other files (alda-lang/alda-core#8).

# File lib/alda-rb/event_list.rb, line 157
def import event_list
  @events.concat event_list.events
  nil
end
(some sugar) → Alda::EventContainer click to toggle source

Make the object have the ability to append its events conveniently.

Here is a list of sugar. When the name of a method meets certain condition, the method is regarded as an event appended to events.

  1. Ending with 2 underlines: set variable. See Alda::SetVariable.

  2. Starting with 2 lowercase letters and ending with underline character: instrument. See Alda::Part. This will trigger a warning if we are using Alda 2 because parts inside a sequence are not allowed in Alda 2 (alda-lang/alda#441).

  3. Starting with 2 lowercase letters: inline lisp code, set variable, or get variable. One of the above three is chosen intelligently. See Alda::InlineLisp, Alda::SetVariable, Alda::GetVariable.

  4. Starting with “t”: CRAM. See Alda::Cram.

  5. Starting with one of “a”, “b”, …, “g”: note. See Alda::Note.

  6. Starting with “r”: rest. See Alda::Rest.

  7. “x”: chord. See Alda::Chord.

  8. “s”: sequence. See Alda::Sequence.

  9. Starting with “o”: octave. See Alda::Octave.

  10. Starting with “v”: voice. See Alda::Voice.

  11. Starting with “__” (2 underlines): at marker. See Alda::AtMarker.

  12. Starting with “_” (underline) and ending with “_” (underline): lisp identifier. See Alda::LispIdentifier.

  13. Starting with “_” (underline): marker. See Alda::Marker.

All the appended events are contained in an Alda::EventContainer object, which is to be returned.

These sugars forms a DSL. See ::new for examples.

Calls superclass method
# File lib/alda-rb/event_list.rb, line 75
def method_missing name, *args, &block
  if @parent&.respond_to? name, true
    return @parent.__send__ name, *args, &block
  end
  sequence_sugar = ->event do
    if args.size == 1
      Alda::Sequence.join event, args.first.tap(&:detach_from_parent)
    else
      event
    end
  end
  case
  when /\A(?<head>[a-z][a-z].*)__\z/        =~ name
    Alda::SetVariable.new head, *args, &block
  when /\A(?<part>[a-z][a-z].*)_\z/         =~ name
    if args.first.is_a? String
      Alda::Part.new [part], args.first
    else
      Alda::Utils.warn 'parts in sequence not allowed in v2' if Alda.v2? && !args.empty?
      sequence_sugar.(Alda::Part.new [part])
    end
  when /\A[a-z][a-z].*\z/                   =~ name
    arg = args.first
    if block || !has_variable?(name) && args.size == 1 && arg.is_a?(Alda::Event) &&
        !arg.is_event_of?(Alda::InlineLisp) && !arg.is_event_of?(Alda::LispIdentifier)
      Alda::SetVariable.new name, *args, &block
    elsif has_variable?(name) && (args.empty? || args.size == 1 && arg.is_a?(Alda::Event))
      sequence_sugar.(Alda::GetVariable.new name)
    else
      Alda::InlineLisp.new name, *args
    end
  when /\At(?<duration>.*)\z/               =~ name
    Alda::Cram.new duration, &block
  when /\A(?<pitch>[a-g])(?<duration>.*)\z/ =~ name
    sequence_sugar.(Alda::Note.new pitch, duration)
  when /\Ar(?<duration>.*)\z/               =~ name
    sequence_sugar.(Alda::Rest.new duration)
  when /\Ax\z/                              =~ name
    Alda::Chord.new &block
  when /\As\z/                              =~ name
    Alda::Sequence.new *args, &block
  when /\Ao!\z/                             =~ name
    sequence_sugar.(Alda::Octave.new('').tap { _1.up_or_down = 1})
  when /\Ao\?\z/                            =~ name
    sequence_sugar.(Alda::Octave.new('').tap { _1.up_or_down = -1})
  when /\Ao(?<num>\d*)\z/                   =~ name
    sequence_sugar.(Alda::Octave.new num)
  when /\Av(?<num>\d+)\z/                   =~ name
    sequence_sugar.(Alda::Voice.new num)
  when /\A__(?<head>.+)\z/                  =~ name
    sequence_sugar.(Alda::AtMarker.new head)
  when /\A_(?<head>.+)_\z/                  =~ name
    sequence_sugar.(Alda::LispIdentifier.new head)
  when /\A_(?<head>.+)\z/                   =~ name
    sequence_sugar.(Alda::Marker.new head)
  else
    super
  end.then do |event|
    Alda::EventContainer.new event, self
  end.tap { @events.push _1 }
end
on_contained() click to toggle source

When the module is included by a subclass of Alda::Event, this method overrides Alda::Event#on_contained. When invoked, calls the overridden method (if any) and then evaluates the block given when ::new was called.

Calls superclass method
# File lib/alda-rb/event_list.rb, line 23
def on_contained
  super if defined? super
  instance_eval &@block if @block
end
to_a → Array click to toggle source

Same as events.

# File lib/alda-rb/event_list.rb, line 195
def to_a
  @events
end