A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 290 lines 8.8 kB view raw
1#!/usr/bin/ruby 2# (c) 2010 by Thomas Martitz 3# 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. 8 9# 10# parse test codec output files and give wiki or spreadsheet formatted output 11# 12class CodecResult 13 include Comparable 14private 15 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 23 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 when /opus.+/ 69 self.codec = "Opus" 70 else 71 self.codec = "CODEC UNKNOWN (#{name})" 72 end 73 end 74 75 def file_name=(name) 76 @file_name = name 77 get_codec(name) 78 end 79 80public 81 82 attr_reader :file_name 83 attr_reader :codec 84 attr_reader :decoded_frames 85 attr_reader :max_frames 86 attr_reader :decode_time 87 attr_reader :file_duration 88 attr_reader :percent_realtime 89 attr_reader :mhz_needed 90 91 # make results comparable, allows for simple faster/slower/equal 92 def <=>(other) 93 if self.file_name != other.file_name 94 raise ArgumentError, "Cannot compare different files" 95 end 96 return self.decode_time <=> other.decode_time 97 end 98 99 def initialize(text_block, cpu_freq = nil) 100 # we need an Array 101 c = text_block.class 102 if (c != Array && c.superclass != Array) 103 raise ArgumentError, 104 "Argument must be an array but is " + text_block.class.to_s 105 end 106 107 #~ lame_192.mp3 108 #~ 175909 of 175960 109 #~ Decode time - 8.84s 110 #~ File duration - 175.96s 111 #~ 1990.49% realtime 112 #~ 30.14MHz needed for realtime (not there in RaaA) 113 114 # file name 115 self.file_name = text_block[0] 116 117 # decoded & max frames 118 test = Regexp.new(/(\d+) of (\d+)/) 119 res = text_block[1].match(test) 120 self.decoded_frames = res[1].to_i 121 self.max_frames = res[2].to_i 122 123 # decode time, in centiseconds 124 test = Regexp.new(/Decode time - ([.\d]+)s/) 125 self.decode_time = text_block[2].match(test)[1].to_f 126 127 # file duration, in centiseconds 128 test = Regexp.new(/File duration - ([.\d]+)s/) 129 self.file_duration = text_block[3].match(test)[1].to_f 130 131 # % realtime 132 self.percent_realtime = text_block[4].to_f 133 134 # MHz needed for rt 135 test = Regexp.new(/[.\d]+MHz needed for realtime/) 136 self.mhz_needed = nil 137 if (text_block[5] != nil && text_block[5].length > 0) 138 self.mhz_needed = text_block[5].match(test)[0].to_f 139 elsif (cpu_freq) 140 # if not given, calculate it as per passed cpu frequency 141 # duration to microseconds 142 speed = self.file_duration / self.decode_time 143 self.mhz_needed = cpu_freq / speed 144 end 145 end 146end 147 148class TestCodecResults < Array 149 def initialize(file_name, cpu_freq) 150 super() 151 temp = self.clone 152 # go through the results, create a CodecResult for each block 153 # of text (results for the codecs are seperated by an empty line) 154 File.open(file_name, File::RDONLY) do |file| 155 file.each_chomp do |line| 156 if (line.length == 0) then 157 self << CodecResult.new(temp, cpu_freq);temp.clear 158 else 159 temp << line 160 end 161 end 162 end 163 end 164 165 # sort the results by filename (so files of the same codec are near) 166 def sort 167 super { |x, y| x.file_name <=> y.file_name } 168 end 169end 170 171class File 172 # walk through each line but have the \n removed 173 def each_chomp 174 self.each_line do |line| 175 yield(line.chomp) 176 end 177 end 178end 179 180class Float 181 alias_method(:old_to_s, :to_s) 182 # add the ability to use a different decimal seperator in to_s 183 def to_s 184 string = old_to_s 185 string.sub!(/[.]/ , @@dec_sep) if @@dec_sep 186 string 187 end 188 189 @@dec_sep = nil 190 def self.decimal_seperator=(sep) 191 @@dec_sep=sep 192 end 193end 194 195#files is an Array of TestCodecResultss 196def for_calc(files) 197 files[0].each_index do |i| 198 string = files[0][i].file_name + "\t" 199 for f in files 200 string += f[i].percent_realtime.to_s + "%\t" 201 end 202 puts string 203 end 204end 205 206#files is an Array of TestCodecResultss 207def for_wiki(files) 208 basefile = files.shift 209 codec = nil 210 basefile.each_index do |i| res = basefile[i] 211 # make a joined row for each codec 212 if (codec == nil || res.codec != codec) then 213 codec = res.codec 214 puts "| *%s* ||||%s" % [codec, "|"*files.length] 215 end 216 row = sprintf("| %s | %.2f%%%% realtime | Decode time - %.2fs |" % 217 [res.file_name, res.percent_realtime, res.decode_time]) 218 if (res.mhz_needed != nil) # column for mhz needed, | - | if unknown 219 row += sprintf(" %.2fMHz |" % res.mhz_needed.to_s) 220 else 221 row += " - |" 222 end 223 for f in files # calculate speed up compared to the rest files 224 delta = (res.percent_realtime / f[i].percent_realtime)*100 225 row += sprintf(" %.2f%%%% |" % delta) 226 end 227 puts row 228 end 229end 230 231# for_xml() anyone? :) 232 233def help 234 puts "#{$0} [OPTIONS] FILE [FILES]..." 235 puts "Options:\t-w\tOutput in Fosswiki format (default)" 236 puts "\t\t-c\tOutput in Spreadsheet-compatible format (tab-seperated)" 237 puts "\t\t-s=MHZ\tAssume MHZ cpu frequency for \"MHz needed for realtime\" calculation" 238 puts "\t\t\t(if not given by the log files, e.g. for RaaA)" 239 puts "\t\t-d=CHAR\tUse CHAR as decimal seperator in the -c output" 240 puts "\t\t\t(if your spreadsheed tool localized and making problems)" 241 puts 242 puts "\tOne file is needed. This is the basefile." 243 puts "\tIn -c output, the % realtime values of each" 244 puts "\tcodec from each file is printed on the screen onto the screen" 245 puts "\tIn -w output, a wiki table is made from the basefile with one column" 246 puts "\tfor each additional file representing relative speed of the basefile" 247 exit 248end 249 250to_call = method(:for_wiki) 251mhz = nil 252files = [] 253 254help if (ARGV.length == 0) 255 256ARGV.each do |e| 257 a = e.chars.to_a 258 if (a[0] == '-') # option 259 case a[1] 260 when 'c' 261 to_call = method(:for_calc) 262 when 'w' 263 to_call = method(:for_wiki) 264 when 'd' 265 if (a[2] == '=') 266 sep = a[3] 267 else 268 sep = a[2] 269 end 270 Float.decimal_seperator = sep 271 when 's' 272 if (a[2] == '=') 273 mhz = a[3..-1].join.to_i 274 else 275 mhz = a[2..-1].join.to_i 276 end 277 else 278 help 279 end 280 else # filename 281 files << e 282 end 283end 284 285 286tmp = [] 287for file in files do 288 tmp << TestCodecResults.new(file, mhz).sort 289end 290to_call.call(tmp) # invoke selected method