Fix one more warning.
[maemo-rb.git] / utils / parse_testcodec.rb
blob6531b70152437d87734846f379566a269c5dd5d4
1 #!/usr/bin/ruby
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
12 class CodecResult
13     include Comparable
14 private
16     attr_writer :codec
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)
25         case filename
26             when /nero_hev2_.+/
27                 self.codec = "Nero AAC-HEv2 (SBR+PS)"
28             when /.+aache.+/, /nero_he_.+/
29                 self.codec = "Nero AAC-HE (SBR)"
30             when /a52.+/
31                 self.codec = "AC3 (A52)"
32             when /ape_.+/
33                 self.codec = "Monkey Audio"
34             when /lame_.+/
35                 self.codec = "MP3"
36             when /.+\.m4a/
37                 self.codec = "AAC-LC"
38             when /vorbis.+/
39                 self.codec = "Vorbis"
40             when /wma_.+/
41                 self.codec = "WMA Standard"
42             when /wv_.+/
43                 self.codec = "WAVPACK"
44             when /applelossless.+/
45                 self.codec = "Apple Lossless"
46             when /mpc_.+/
47                 self.codec = "Musepack"
48             when /flac_.+/
49                 self.codec = "FLAC"
50             when /cook_.+/
51                 self.codec = "Cook (RA)"
52             when /atrac3.+/
53                 self.codec = "Atrac3"
54             when /true.+/
55                 self.codec = "True Audio"
56             when /toolame.+/, /pegase_l2.+/
57                 self.codec = "MP2"
58             when /atrack1.+/
59                 self.codec = "Atrac1"
60             when /wmapro.+/
61                 self.codec = "WMA Professional"
62             when /wmal.+/
63                 self.codec = "WMA Lossless"
64             when /speex.+/
65                 self.codec = "Speex"
66             when /pegase_l1.+/
67                 self.codec = "MP1"
68             else
69                 self.codec = "CODEC UNKNOWN (#{name})"
70         end
71     end
73     def file_name=(name)
74         @file_name = name
75         get_codec(name)
76     end
78 public
80     attr_reader :file_name
81     attr_reader :codec
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
90     def <=>(other)
91         if self.file_name != other.file_name
92             raise ArgumentError, "Cannot compare different files"
93         end
94         return self.decode_time <=> other.decode_time
95     end
97     def initialize(text_block, cpu_freq = nil)
98         # we need an Array
99         c = text_block.class
100         if (c != Array && c.superclass != Array)
101             raise ArgumentError,
102                  "Argument must be an array but is " + text_block.class.to_s
103         end
105         #~ lame_192.mp3
106         #~ 175909 of 175960
107         #~ Decode time - 8.84s
108         #~ File duration - 175.96s
109         #~ 1990.49% realtime
110         #~ 30.14MHz needed for realtime (not there in RaaA)
112         # file name
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
129         # % realtime
130         self.percent_realtime = text_block[4].to_f
132         # MHz needed for rt
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
137         elsif (cpu_freq)
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
142         end
143     end
146 class TestCodecResults < Array
147     def initialize(file_name, cpu_freq)
148         super()
149         temp = self.clone
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
156                 else
157                     temp << line
158                 end
159             end
160         end
161     end
163     # sort the results by filename (so files of the same codec are near)
164     def sort
165         super { |x, y| x.file_name <=> y.file_name }
166     end
169 class File
170     # walk through each line but have the \n removed
171     def each_chomp
172         self.each_line do |line|
173             yield(line.chomp)
174         end
175     end
178 class Float
179     alias_method(:old_to_s, :to_s)
180     # add the ability to use a different decimal seperator in to_s
181     def to_s
182         string = old_to_s
183         string.sub!(/[.]/ , @@dec_sep) if @@dec_sep
184         string
185     end
187     @@dec_sep = nil
188     def self.decimal_seperator=(sep)
189         @@dec_sep=sep
190     end
193 #files is an Array of TestCodecResultss
194 def for_calc(files)
195     files[0].each_index do |i|
196         string = files[0][i].file_name + "\t"
197         for f in files
198             string += f[i].percent_realtime.to_s + "%\t"
199         end
200         puts string
201     end
204 #files is an Array of TestCodecResultss
205 def for_wiki(files)
206     basefile = files.shift
207     codec = nil
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
211             codec = res.codec
212             puts "| *%s*  ||||%s" % [codec, "|"*files.length]
213         end
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)
218         else
219             row += " - |"
220         end
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)
224         end
225         puts row
226     end
229 # for_xml() anyone? :)
231 def help
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)"
239     puts
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"
245     exit
248 to_call = method(:for_wiki)
249 mhz = nil
250 files = []
252 help if (ARGV.length == 0)
254 ARGV.each do |e|
255     a = e.chars.to_a
256     if (a[0] == '-') # option
257         case a[1]
258             when 'c'
259                 to_call = method(:for_calc)
260             when 'w'
261                 to_call = method(:for_wiki)
262             when 'd'
263                 if (a[2] == '=')
264                     sep = a[3]
265                 else
266                     sep = a[2]
267                 end
268                 Float.decimal_seperator = sep
269             when 's'
270                 if (a[2] == '=')
271                     mhz = a[3..-1].join.to_i
272                 else
273                     mhz = a[2..-1].join.to_i
274                 end
275             else
276                 help
277         end
278     else # filename
279         files << e
280     end
284 tmp = []
285 for file in files do
286     tmp << TestCodecResults.new(file, mhz).sort
288 to_call.call(tmp) # invoke selected method