Class: Musicality::PartEngraver

Inherits:
Object
  • Object
show all
Defined in:
lib/musicality/printing/lilypond/part_engraver.rb

Constant Summary collapse

MAX_LINE_LEN =
76
INDENT =
"  "
CLEF_RANGES =
{
  Clef::TREBLE => Pitches::C4..Pitches::A5,
  Clef::ALTO => Pitches::D3..Pitches::B4,
  Clef::TENOR => Pitches::B2..Pitches::G4,
  Clef::BASS => Pitches::E2..Pitches::C4,
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(part, title) ⇒ PartEngraver

Returns a new instance of PartEngraver.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 7

def initialize part, title
  if part.invalid?
    raise ArgumentError, "given part contains errors: #{part.errors}"
  end

  @transpose_interval = part.lilypond_settings.transpose_interval
  @clefs = part.lilypond_settings.clefs
  @part = (@transpose_interval == 0) ? part : part.transpose(@transpose_interval)
  @title = title
  @indent = INDENT

  @triplet_flags = @part.notes.map do |note|
    note.duration.to_r.denominator % 3 == 0
  end
end

Class Method Details

.best_clef(notes, allowed_clefs) ⇒ Object

Raises:

  • (ArgumentError)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 93

def self.best_clef notes, allowed_clefs
  raise ArgumentError unless notes.any?
  raise ArgumentError unless allowed_clefs.any?

  ranges = CLEF_RANGES.select {|clef,range| allowed_clefs.include?(clef) }
  range_scores = Hash.new(0)

  notes.each do |note|
    note.pitches.each do |p|
      ranges.each do |name,range|
        if p >= range.min && p <= range.max
          range_scores[name] += note.duration
        end
      end
    end
  end
  range_score = range_scores.max_by {|range,score| score}
  range_score.nil? ? allowed_clefs.first : range_score[0]
end

Instance Method Details

#decrease_indentObject



27
28
29
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 27

def decrease_indent
  @indent = @indent[0...-INDENT.size]
end

#increase_indentObject



23
24
25
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 23

def increase_indent
  @indent += INDENT
end

#make_body(sharpit) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 56

def make_body sharpit
  i = 0
  pieces = @part.notes.map do |n|
    str = if @triplet_flags[i]
      n.resize(n.duration * Rational(3,2)).to_lilypond(sharpit,
        begins_triplet: i == 0 || !@triplet_flags[i-1],
        ends_triplet: i == (@triplet_flags.size-1) || !@triplet_flags[i+1])
    else
      n.to_lilypond(sharpit)
    end
    i += 1
    str
  end

  output = ""
  while pieces.any?
    line = @indent + pieces.shift
    until pieces.empty? || (line.size + 1 + pieces.first.size) > MAX_LINE_LEN
      line += " " + pieces.shift
    end
    output += line + "\n"
  end
  return output
end

#make_finalObject



81
82
83
84
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 81

def make_final
  decrease_indent
  return @indent + "}\n"
end

#make_lilypond(start_key, start_meter, key_changes: {}, meter_changes: {}, master: false) ⇒ Object



31
32
33
34
35
36
37
38
39
40
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 31

def make_lilypond start_key, start_meter, key_changes: {}, meter_changes: {}, master: false
  if @transpose_interval != 0
    start_key = transpose_start_key(start_key)
    key_changes = transpose_key_changes(key_changes)      
  end

  sharpit = start_key.sharp?
  return make_preliminary(start_meter, start_key, master) + 
    make_body(sharpit) + make_final()
end

#make_preliminary(start_meter, start_key, master) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/musicality/printing/lilypond/part_engraver.rb', line 42

def make_preliminary start_meter, start_key, master
  clef = self.class.best_clef(@part.notes, @clefs)

  output = @indent + "\\new Staff {\n"
  increase_indent
  output += @indent + "\\set Staff.instrumentName = \\markup { \"#{@title}\" }\n"
  output += @indent + "\\clef #{clef}\n"
  if master
    output += @indent + start_meter.to_lilypond + "\n"
  end
  output += @indent + start_key.to_lilypond + "\n"
  return output
end