Class: Musicality::NoteFIFO

Inherits:
Object
  • Object
show all
Defined in:
lib/musicality/composition/sequencing/note_fifo.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(initial_notes = []) ⇒ NoteFIFO

Returns a new instance of NoteFIFO.



5
6
7
8
9
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 5

def initialize initial_notes = []
  @notes = []
  @duration = 0
  add_notes(initial_notes) if initial_notes.any?
end

Instance Attribute Details

#durationObject (readonly)

Returns the value of attribute duration.



4
5
6
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 4

def duration
  @duration
end

#notesObject (readonly)

Returns the value of attribute notes.



4
5
6
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 4

def notes
  @notes
end

Instance Method Details

#add_note(note) ⇒ Object



15
16
17
18
19
20
21
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 15

def add_note note
  if note.duration <= 0
    raise ArgumentError, "note have non-positive duration: #{note}"
  end
  @notes.push note
  @duration += note.duration
end

#add_notes(notes) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 23

def add_notes notes
  nonpositive = notes.select {|x| x.duration <= 0}
  if nonpositive.any?
    raise ArgumentError, "one or more notes have non-positive duration: #{notes}"
  end
  @notes += notes
  @duration += notes.inject(0) {|sum, note| sum + note.duration }
end

#empty?Boolean

Returns:

  • (Boolean)


11
12
13
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 11

def empty?
  @notes.empty?
end

#remove_notes(target_duration) ⇒ Object

Return a sequence of notes with total duration equal to the given target duration, and remove the same notes from the accumulator. Any notes beyond the given target duration are left in the accumulator. Split a note into two tied notes if needed.

Raises:

  • (ArgumentError)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/musicality/composition/sequencing/note_fifo.rb', line 35

def remove_notes target_duration
  raise ArgumentError, "negative target duration #{target_duration}" if target_duration < 0

  if target_duration > duration
    raise ArgumentError, "target duration #{target_duration} is greater than duration of accumulated notes #{duration}"
  end

  removed_notes = if target_duration == 0
    []
  elsif target_duration == duration
    notes.shift(notes.size)
  else
    dur_so_far = 0.to_r
    num_notes_taking = 0
    @notes.each_with_index do |note, idx|
      dur_so_far += note.duration
      num_notes_taking += 1
      break if dur_so_far >= target_duration
    end

    notes_taking = notes.shift(num_notes_taking)
    excess_dur = dur_so_far - target_duration

    if excess_dur > 0
      @notes.unshift(notes_taking[-1].resize(excess_dur))
      notes_taking[-1] = notes_taking[-1].resize(notes_taking[-1].duration - excess_dur)
      notes_taking[-1].pitches.each do |pitch|
        notes_taking[-1].links[pitch] = Link::Tie.new
      end
    end
    notes_taking
  end

  @duration = @duration - target_duration
  return removed_notes
end