class Song
encoding: utf-8
Attributes
file[RW]
info[RW]
melody[RW]
order[RW]
verses[RW]
Public Class Methods
capo(chord, fret)
click to toggle source
# File Creator/capo.rb, line 10 def self.capo(chord, fret) idx = OCTAVE.index(chord[0..1]) range = 0..1 if idx.nil? then idx = OCTAVE.index(chord[0]) range = 0 end raise StandardError.new("Unknown Chords #{chord}!") if idx.nil? chord[range] = OCTAVE[(idx + fret) % OCTAVE.size] return chord end
new()
click to toggle source
# File Creator/song.rb, line 4 def initialize @verses = [] @info = {} end
parse(f)
click to toggle source
# File Creator/parser.rb, line 98 def self.parse(f) s = Song.new s.parse_song_chords(f) s.parse_abc return s end
split_chords(line)
click to toggle source
# File Creator/parser.rb, line 13 def self.split_chords(line) return line.enum_for(:scan, /\b\w+\b/).map{[Regexp.last_match[0], Regexp.last_match.begin(0)]} end
Public Instance Methods
capo!(fret)
click to toggle source
# File Creator/capo.rb, line 2 def capo!(fret) capo_melody!(fret) unless melody.nil? or melody.empty? verses.each{|v| v.capo!(fret)} %w[key K].each{|k| info[k] = Song.capo(info[k], fret) if info.include?(k)} return self end
desc()
click to toggle source
# File Creator/song.rb, line 10 def desc; (info["desc"] || info["N"]).to_s.gsub("'", "’"); end
emoji()
click to toggle source
# File Creator/song.rb, line 13 def emoji; info.fetch("emoji", "").strip.split(""); end
eps!()
click to toggle source
# File Creator/latex_formatter.rb, line 57 def eps! return nil if melody.nil? or melody.empty? Open3.popen2("abcm2ps -E -O #{slug} -") do |i,o,t| other_info = [] # other_info << "%%textfont Times-Italic 14" # other_info << "%%text Key of #{self.key}" # other_info << "%%textoption right" # other_info << "%%text #{self.author}" i.print(melody.sub(/^([^:]*)$/, "#{other_info.join("\n")}\\1").to_s) i.close t.join end return "#{slug}001.eps" end
key()
click to toggle source
# File Creator/song.rb, line 11 def key; (info["key"] || info["K"]).to_s.gsub("maj", "").gsub("min", "m"); end
parse_abc(f = nil)
click to toggle source
# File Creator/parser.rb, line 17 def parse_abc(f = nil) f ||= "#{File.dirname(file)}/#{slug}.abc" return log.debug("No such file #{f}") unless File.exist?(f) remove_sections = %w[T Q C N] self.melody = File.read(f) self.file = File.absolute_path(f) if file.nil? self.info.merge!(self.melody.each_line.map{|l|l.split(":")}.reject{|i|i.size != 2}.inject({}){|h,k| h[k[0]]=k[1].strip; h}) self.melody = self.melody.each_line.reject{|l| remove_sections.include?(l.split(":").first)}.join return self rescue log "Could not parse ABC for #{f}" raise end
parse_song_chords(f)
click to toggle source
# File Creator/parser.rb, line 31 def parse_song_chords(f) state = :none last_key = :text current_line = Song::Line.new self.file = File.absolute_path(f) File.open(f).each_line do |raw_line| line = raw_line.strip # log.debug("#{state}: #{line[0..20]}") case (state) when :none then if line == "---" then log.debug "Starting header" state = :header next end if line.start_with?("Additional Verses") then next end unless line.empty? then log.debug "Starting new verse" state = :verse self.verses << Song::Verse.new redo end when :header then if line == "---" then log.debug "Ending header" state = :none next end key, value = line.scan(/(\w*):(.*)/).flatten log.debug("k: #{key}, v:#{value}, lk: #{last_key}") if key.nil? or value.nil? then info[last_key] += " " + line.strip elsif last_key info[key] = value.strip last_key = key end when :verse then if line.empty? then state = :none next end if line.match(/^\[?[Cc]horus:?\]?$/) then self.verses.last.chorus = true next end if raw_line.gsub('\r', '').match(/[ \t]{2}/) then current_line.raw_chords = raw_line.gsub('\t', ' ').gsub('\r', '').gsub('\n', '') current_line.chords = Song.split_chords(raw_line.gsub('\t', ' ')) # log.debug "Chords #{current_line.chords}" else current_line.lyrics = line self.verses.last.lines << current_line current_line = Song::Line.new end end end return self end
preview_latex()
click to toggle source
# File Creator/latex_formatter.rb, line 72 def preview_latex Dir.chdir("/tmp/") { eps! } File.write("/tmp/preview.tex", SongBook.templatize(to_latex)) Dir.chdir("/tmp") do return unless system("xelatex -shell-escape /tmp/preview.tex") end spawn("evince /tmp/preview.pdf") end
short?()
click to toggle source
# File Creator/song.rb, line 20 def short?; info['short'] == 'true'; end
slug()
click to toggle source
# File Creator/song.rb, line 15 def slug; File.basename(file, File.extname(file)); end
song?()
click to toggle source
# File Creator/song.rb, line 17 def song?; return !tune?; end
title()
click to toggle source
# File Creator/song.rb, line 9 def title; (info["title"] || info["T"]).to_s.gsub("'", "’"); end
to_html()
click to toggle source
# File Creator/html_formatter.rb, line 39 def to_html verses.map(&:to_html).join("\n\n") end
to_latex()
click to toggle source
# File Creator/latex_formatter.rb, line 34 def to_latex parts = [] case when short? then parts << "\\newshortsong" when song? then parts << "\\newsong" when tune? then parts << "\\newtune" end parts << "\\section{#{title}}" parts << "\\songdesc{#{desc}}\n\n" if desc parts << "\\#{(melody.nil? or melody.empty?) ? "nm" : ""}songinfo{#{key.empty? ? "No Key Specified" : "Key of #{key}"}}{#{author}}" parts << "\\melody{#{slug}001.eps}" unless melody.nil? or melody.empty? # parts << "\\begin{abc}[name=#{title.downcase.gsub(/[^\w]/, "")}]\n#{melody}\\end{abc}" unless melody.nil? or melody.empty? # parts << "\\begin{lilypond}[quoted,staffsize=26]\n#{lilypond}\\end{lilypond}" unless melody.nil? or melody.empty? unless verses.empty? then parts << "\\begin{lyrics}" parts << verses.collect{|v| v.to_latex}.join("\n") parts << "\\end{lyrics}" end return parts.join("\n") end
to_midi()
click to toggle source
# File Creator/midi_formatter.rb, line 2 def to_midi return nil if melody.nil? or melody.empty? Open3.popen2("abc2midi - -o #{slug}.mid") do |i,o,t| other_info = [] # other_info << "%%textfont Times-Italic 14" # other_info << "%%text Key of #{self.key}" # other_info << "%%textoption right" # other_info << "%%text #{self.author}" i.print(melody.sub(/^([^:]*)$/, "#{other_info.join("\n")}\\1").to_s) i.close t.join end return "#{slug}.mid" end
tune?()
click to toggle source
# File Creator/song.rb, line 18 def tune?; return verses.empty?; end
Private Instance Methods
capo_melody!(fret)
click to toggle source
# File Creator/capo.rb, line 24 def capo_melody!(fret) Open3.popen2("abc2abc - -t #{fret}") do |i,o,t| i.print(melody.to_s) i.close t.join self.melody = o.read end end