class Musicality::NoteSequenceExtractor

Attributes

notes[R]

Public Class Methods

new(notes) click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 5
def initialize notes
  @notes = notes.map {|n| n.clone }
  mark_slurring
  remove_bad_links
  calculate_offsets

  # now, ready to extract sequences!
end

Private Class Methods

continuation_map(note, next_note, separation) click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 134
def self.continuation_map note, next_note, separation
  map = {}

  linked = note.pitches & note.links.keys
  targeted = []
  linked.each do |p|
    l = note.links[p]
    if l.is_a?(Link::Tie)
      map[p] = p
    elsif l.is_a?(Link::TargetedLink) && next_note.pitches.include?(l.target_pitch)
      map[p] = l.target_pitch
    end
  end

  if(separation == Separation::NONE)
    unlinked = note.pitches - linked
    untargeted = next_note.pitches - map.values
    Optimization.linking(unlinked, untargeted).each do |pitch,tgt_pitch|
      map[pitch] = tgt_pitch
    end
  end

  return map
end
note_attack(articulation) click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 60
def self.note_attack articulation
  case articulation
  when Articulations::NORMAL then Attack::NORMAL
  when Articulations::TENUTO then Attack::TENUTO
  when Articulations::ACCENT then Attack::ACCENT
  when Articulations::MARCATO then Attack::ACCENT
  when Articulations::PORTATO then Attack::NORMAL
  when Articulations::STACCATO then Attack::NORMAL
  when Articulations::STACCATISSIMO then Attack::NORMAL
  end
end
note_separation(articulation, under_slur) click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 72
def self.note_separation articulation, under_slur
  if under_slur
    case articulation
    when Articulations::NORMAL then Separation::NONE
    when Articulations::TENUTO then Separation::NONE
    when Articulations::ACCENT then Separation::NONE
    when Articulations::MARCATO then Separation::PORTATO
    when Articulations::PORTATO then Separation::NORMAL
    when Articulations::STACCATO then Separation::PORTATO
    when Articulations::STACCATISSIMO then Separation::STACCATO
    end
  else
    case articulation
    when Articulations::NORMAL then Separation::NORMAL
    when Articulations::TENUTO then Separation::TENUTO
    when Articulations::ACCENT then Separation::NORMAL
    when Articulations::MARCATO then Separation::NORMAL
    when Articulations::PORTATO then Separation::PORTATO
    when Articulations::STACCATO then Separation::STACCATO
    when Articulations::STACCATISSIMO then Separation::STACCATISSIMO
    end
  end
end

Public Instance Methods

extract_sequences(cents_per_step = 10) click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 14
def extract_sequences cents_per_step = 10
  completed_seqs = []
  continuing_sequences = {}

  @notes.each_with_index do |note, idx|
    offset = @offsets[idx]
    duration = note.duration
    attack = NoteSequenceExtractor.note_attack(note.articulation)
    separation = NoteSequenceExtractor.note_separation(note.articulation, @slurring_flags[idx])

    next_note = (idx == (@notes.size-1)) ? Note.quarter : @notes[idx+1]
    continuation_map = NoteSequenceExtractor.continuation_map(note, next_note, separation)

    new_continuing_sequences = {}

    note.pitches.each do |p|
      seq = if continuing_sequences.has_key?(p)
        continuing_sequences[p].elements += note_pitch_elements(note, p, Attack::NONE, cents_per_step)
        continuing_sequences.delete(p)
      else
        NoteSequence.new(offset, separation, note_pitch_elements(note, p, attack, cents_per_step))
      end

      if continuation_map.include?(p)
        new_continuing_sequences[continuation_map[p]] = seq
      else
        completed_seqs.push seq
      end
    end

    if continuing_sequences.any?
      require 'pry'
      binding.pry
      # raise "Should be no previous continuing sequences remaining"
    end
    continuing_sequences = new_continuing_sequences
  end

  raise "Should be no previous continuing sequences remaining" if continuing_sequences.any?

  completed_seqs.each {|seq| seq.simplify! }
  return completed_seqs
end

Private Instance Methods

calculate_offsets() click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 125
def calculate_offsets
  offset = 0.to_r
  @offsets = Array.new(@notes.size) do |i|
    cur_offset = offset
    offset += @notes[i].duration
    cur_offset
  end
end
mark_slurring() click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 96
def mark_slurring
  @slurring_flags = []
  under_slur = false

  @slurring_flags = Array.new(@notes.size) do |i|
    note = @notes[i]

    if note.begins_slur? && !note.ends_slur?
      under_slur = true
    end
    flag = under_slur

    if note.ends_slur? && !note.begins_slur?
      under_slur = false
    end
    flag
  end
end
note_pitch_elements(note, pitch, attack, cents_per_step) click to toggle source
# File lib/musicality/performance/conversion/note_sequence_extractor.rb, line 159
def note_pitch_elements note, pitch, attack, cents_per_step
  duration = note.duration
  link = note.links[pitch]
  elements = if link && link.is_a?(Link::TargetedLink)
    tgt_pitch = link.target_pitch
    case link
    when Link::Glissando
      GlissandoConverter.glissando_elements(pitch, tgt_pitch, duration, attack)
    when Link::Portamento
      PortamentoConverter.portamento_elements(pitch, tgt_pitch, cents_per_step, duration, attack)
    else
      raise "Unexpected targeted link type"
    end
  else
    [ NoteSequence::Element.new(note.duration, pitch, attack) ]
  end

  return elements
end