blob: 9a2a6e917061c1fe869459eec1dfe56f96c4d0a8 [file] [log] [blame]
#!/usr/bin/ruby
# (c) 2010 by Thomas Martitz
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# parse test codec output files and give wiki or spreadsheet formatted output
#
class CodecResult
include Comparable
private
attr_writer :codec
attr_writer :decoded_frames
attr_writer :max_frames
attr_writer :decode_time
attr_writer :file_duration
attr_writer :percent_realtime
attr_writer :mhz_needed
def get_codec(filename)
case filename
when /.+aache.+/, /nero_he_.+/
self.codec = "Nero AAC-HE"
when /a52.+/
self.codec = "AC3 (A52)"
when /ape_.+/
self.codec = "Monkey Audio"
when /lame_.+/
self.codec = "MP3"
when /.+\.m4a/
self.codec = "AAC-LC"
when /vorbis.+/
self.codec = "Vorbis"
when /wma_.+/
self.codec = "WMA Standard"
when /wv_.+/
self.codec = "WAVPACK"
when /applelossless.+/
self.codec = "Apple Lossless"
when /mpc_.+/
self.codec = "Musepack"
when /flac_.+/
self.codec = "FLAC"
when /cook_.+/
self.codec = "Cook (RA)"
when /atrac3.+/
self.codec = "Atrac3"
when /true.+/
self.codec = "True Audio"
when /toolame.+/
self.codec = "MP2"
when /atrack1.+/
self.codec = "Atrac1"
when /wmapro.+/
self.codec = "WMA Professional"
when /wmal.+/
self.codec = "WMA Lossless"
when /speex.+/
self.codec = "Speex"
else
self.codec = "CODEC UNKNOWN (#{name})"
end
end
def file_name=(name)
@file_name = name
get_codec(name)
end
public
attr_reader :file_name
attr_reader :codec
attr_reader :decoded_frames
attr_reader :max_frames
attr_reader :decode_time
attr_reader :file_duration
attr_reader :percent_realtime
attr_reader :mhz_needed
# make results comparable, allows for simple faster/slower/equal
def <=>(other)
if self.file_name != other.file_name
raise ArgumentError, "Cannot compare different files"
end
return self.decode_time <=> other.decode_time
end
def initialize(text_block, cpu_freq = nil)
# we need an Array
c = text_block.class
if (c != Array && c.superclass != Array)
raise ArgumentError,
"Argument must be an array but is " + text_block.class.to_s
end
#~ lame_192.mp3
#~ 175909 of 175960
#~ Decode time - 8.84s
#~ File duration - 175.96s
#~ 1990.49% realtime
#~ 30.14MHz needed for realtime (not there in RaaA)
# file name
self.file_name = text_block[0]
# decoded & max frames
test = Regexp.new(/(\d+) of (\d+)/)
res = text_block[1].match(test)
self.decoded_frames = res[1].to_i
self.max_frames = res[2].to_i
# decode time, in centiseconds
test = Regexp.new(/Decode time - ([.\d]+)s/)
self.decode_time = text_block[2].match(test)[1].to_f
# file duration, in centiseconds
test = Regexp.new(/File duration - ([.\d]+)s/)
self.file_duration = text_block[3].match(test)[1].to_f
# % realtime
self.percent_realtime = text_block[4].to_f
# MHz needed for rt
test = Regexp.new(/[.\d]+MHz needed for realtime/)
self.mhz_needed = nil
if (text_block[5] != nil && text_block[5].length > 0)
self.mhz_needed = text_block[5].match(test)[1].to_f
elsif (cpu_freq)
# if not given, calculate it as per passed cpu frequency
# duration to microseconds
speed = self.file_duration / self.decode_time
self.mhz_needed = cpu_freq / speed
end
end
end
class TestCodecResults < Array
def initialize(file_name, cpu_freq)
super()
temp = self.clone
# go through the results, create a CodecResult for each block
# of text (results for the codecs are seperated by an empty line)
File.open(file_name, File::RDONLY) do |file|
file.each_chomp do |line|
if (line.length == 0) then
self << CodecResult.new(temp, cpu_freq);temp.clear
else
temp << line
end
end
end
end
# sort the results by filename (so files of the same codec are near)
def sort
super { |x, y| x.file_name <=> y.file_name }
end
end
class File
# walk through each line but have the \n removed
def each_chomp
self.each_line do |line|
yield(line.chomp)
end
end
end
class Float
alias_method(:old_to_s, :to_s)
# add the ability to use a different decimal seperator in to_s
def to_s
string = old_to_s
string.sub!(/[.]/ , @@dec_sep) if @@dec_sep
string
end
@@dec_sep = nil
def self.decimal_seperator=(sep)
@@dec_sep=sep
end
end
#files is an Array of TestCodecResultss
def for_calc(files)
files[0].each_index do |i|
string = files[0][i].file_name + "\t"
for f in files
string += f[i].percent_realtime.to_s + "%\t"
end
puts string
end
end
#files is an Array of TestCodecResultss
def for_wiki(files)
basefile = files.shift
codec = nil
basefile.each_index do |i| res = basefile[i]
# make a joined row for each codec
if (codec == nil || res.codec != codec) then
codec = res.codec
puts "| *%s* ||||%s" % [codec, "|"*files.length]
end
row = sprintf("| %s | %.2f%%%% realtime | Decode time - %.2fs |" %
[res.file_name, res.percent_realtime, res.decode_time])
if (res.mhz_needed != nil) # column for mhz needed, | - | if unknown
row += sprintf(" %.2fMHz |" % res.mhz_needed.to_s)
else
row += " - |"
end
for f in files # calculate speed up compared to the rest files
delta = (res.percent_realtime / f[i].percent_realtime)*100
row += sprintf(" %.2f%%%% |" % delta)
end
puts row
end
end
# for_xml() anyone? :)
def help
puts "#{$0} [OPTIONS] FILE [FILES]..."
puts "Options:\t-w\tOutput in Fosswiki format (default)"
puts "\t\t-c\tOutput in Spreadsheet-compatible format (tab-seperated)"
puts "\t\t-s=MHZ\tAssume MHZ cpu frequency for \"MHz needed for realtime\" calculation"
puts "\t\t\t(if not given by the log files, e.g. for RaaA)"
puts "\t\t-d=CHAR\tUse CHAR as decimal seperator in the -c output"
puts "\t\t\t(if your spreadsheed tool localized and making problems)"
puts
puts "\tOne file is needed. This is the basefile."
puts "\tIn -c output, the % realtime values of each"
puts "\tcodec from each file is printed on the screen onto the screen"
puts "\tIn -w output, a wiki table is made from the basefile with one column"
puts "\tfor each additional file representing relative speed of the basefile"
exit
end
to_call = method(:for_wiki)
mhz = nil
files = []
help if (ARGV.length == 0)
ARGV.each do |e|
a = e.chars.to_a
if (a[0] == '-') # option
case a[1]
when 'c'
to_call = method(:for_calc)
when 'w'
to_call = method(:for_wiki)
when 'd'
if (a[2] == '=')
sep = a[3]
else
sep = a[2]
end
Float.decimal_seperator = sep
when 's'
if (a[2] == '=')
mhz = a[3..-1].join.to_i
else
mhz = a[2..-1].join.to_i
end
else
help
end
else # filename
files << e
end
end
tmp = []
for file in files do
tmp << TestCodecResults.new(file, mhz).sort
end
to_call.call(tmp) # invoke selected method