2 # (c) 2010 by Thomas Martitz
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
10 # parse test codec output files and give wiki or spreadsheet formatted output
17 attr_writer :decoded_frames
18 attr_writer :max_frames
19 attr_writer :decode_time
20 attr_writer :file_duration
21 attr_writer :percent_realtime
22 attr_writer :mhz_needed
24 def get_codec(filename)
27 self.codec = "Nero AAC-HEv2 (SBR+PS)"
28 when /.+aache.+/, /nero_he_.+/
29 self.codec = "Nero AAC-HE (SBR)"
31 self.codec = "AC3 (A52)"
33 self.codec = "Monkey Audio"
41 self.codec = "WMA Standard"
43 self.codec = "WAVPACK"
44 when /applelossless.+/
45 self.codec = "Apple Lossless"
47 self.codec = "Musepack"
51 self.codec = "Cook (RA)"
55 self.codec = "True Audio"
56 when /toolame.+/, /pegase_l2.+/
61 self.codec = "WMA Professional"
63 self.codec = "WMA Lossless"
69 self.codec = "CODEC UNKNOWN (#{name})"
80 attr_reader :file_name
82 attr_reader :decoded_frames
83 attr_reader :max_frames
84 attr_reader :decode_time
85 attr_reader :file_duration
86 attr_reader :percent_realtime
87 attr_reader :mhz_needed
89 # make results comparable, allows for simple faster/slower/equal
91 if self.file_name != other.file_name
92 raise ArgumentError, "Cannot compare different files"
94 return self.decode_time <=> other.decode_time
97 def initialize(text_block, cpu_freq = nil)
100 if (c != Array && c.superclass != Array)
102 "Argument must be an array but is " + text_block.class.to_s
107 #~ Decode time - 8.84s
108 #~ File duration - 175.96s
110 #~ 30.14MHz needed for realtime (not there in RaaA)
113 self.file_name = text_block[0]
115 # decoded & max frames
116 test = Regexp.new(/(\d+) of (\d+)/)
117 res = text_block[1].match(test)
118 self.decoded_frames = res[1].to_i
119 self.max_frames = res[2].to_i
121 # decode time, in centiseconds
122 test = Regexp.new(/Decode time - ([.\d]+)s/)
123 self.decode_time = text_block[2].match(test)[1].to_f
125 # file duration, in centiseconds
126 test = Regexp.new(/File duration - ([.\d]+)s/)
127 self.file_duration = text_block[3].match(test)[1].to_f
130 self.percent_realtime = text_block[4].to_f
133 test = Regexp.new(/[.\d]+MHz needed for realtime/)
134 self.mhz_needed = nil
135 if (text_block[5] != nil && text_block[5].length > 0)
136 self.mhz_needed = text_block[5].match(test)[0].to_f
138 # if not given, calculate it as per passed cpu frequency
139 # duration to microseconds
140 speed = self.file_duration / self.decode_time
141 self.mhz_needed = cpu_freq / speed
146 class TestCodecResults < Array
147 def initialize(file_name, cpu_freq)
150 # go through the results, create a CodecResult for each block
151 # of text (results for the codecs are seperated by an empty line)
152 File.open(file_name, File::RDONLY) do |file|
153 file.each_chomp do |line|
154 if (line.length == 0) then
155 self << CodecResult.new(temp, cpu_freq);temp.clear
163 # sort the results by filename (so files of the same codec are near)
165 super { |x, y| x.file_name <=> y.file_name }
170 # walk through each line but have the \n removed
172 self.each_line do |line|
179 alias_method(:old_to_s, :to_s)
180 # add the ability to use a different decimal seperator in to_s
183 string.sub!(/[.]/ , @@dec_sep) if @@dec_sep
188 def self.decimal_seperator=(sep)
193 #files is an Array of TestCodecResultss
195 files[0].each_index do |i|
196 string = files[0][i].file_name + "\t"
198 string += f[i].percent_realtime.to_s + "%\t"
204 #files is an Array of TestCodecResultss
206 basefile = files.shift
208 basefile.each_index do |i| res = basefile[i]
209 # make a joined row for each codec
210 if (codec == nil || res.codec != codec) then
212 puts "| *%s* ||||%s" % [codec, "|"*files.length]
214 row = sprintf("| %s | %.2f%%%% realtime | Decode time - %.2fs |" %
215 [res.file_name, res.percent_realtime, res.decode_time])
216 if (res.mhz_needed != nil) # column for mhz needed, | - | if unknown
217 row += sprintf(" %.2fMHz |" % res.mhz_needed.to_s)
221 for f in files # calculate speed up compared to the rest files
222 delta = (res.percent_realtime / f[i].percent_realtime)*100
223 row += sprintf(" %.2f%%%% |" % delta)
229 # for_xml() anyone? :)
232 puts "#{$0} [OPTIONS] FILE [FILES]..."
233 puts "Options:\t-w\tOutput in Fosswiki format (default)"
234 puts "\t\t-c\tOutput in Spreadsheet-compatible format (tab-seperated)"
235 puts "\t\t-s=MHZ\tAssume MHZ cpu frequency for \"MHz needed for realtime\" calculation"
236 puts "\t\t\t(if not given by the log files, e.g. for RaaA)"
237 puts "\t\t-d=CHAR\tUse CHAR as decimal seperator in the -c output"
238 puts "\t\t\t(if your spreadsheed tool localized and making problems)"
240 puts "\tOne file is needed. This is the basefile."
241 puts "\tIn -c output, the % realtime values of each"
242 puts "\tcodec from each file is printed on the screen onto the screen"
243 puts "\tIn -w output, a wiki table is made from the basefile with one column"
244 puts "\tfor each additional file representing relative speed of the basefile"
248 to_call = method(:for_wiki)
252 help if (ARGV.length == 0)
256 if (a[0] == '-') # option
259 to_call = method(:for_calc)
261 to_call = method(:for_wiki)
268 Float.decimal_seperator = sep
271 mhz = a[3..-1].join.to_i
273 mhz = a[2..-1].join.to_i
286 tmp << TestCodecResults.new(file, mhz).sort
288 to_call.call(tmp) # invoke selected method