diff options
Diffstat (limited to 'voctogui/lib')
-rw-r--r-- | voctogui/lib/audioleveldisplay.py | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/voctogui/lib/audioleveldisplay.py b/voctogui/lib/audioleveldisplay.py index 1d91d35..1a4be14 100644 --- a/voctogui/lib/audioleveldisplay.py +++ b/voctogui/lib/audioleveldisplay.py @@ -12,9 +12,12 @@ class AudioLevelDisplay(object): self.levelrms = [] self.levelpeak = [] self.leveldecay = [] + + # register on_draw handler self.drawing_area.connect('draw', self.on_draw) def on_draw(self, widget, cr): + # number of audio-channels channels = len(self.levelrms) if channels == 0: @@ -22,44 +25,71 @@ class AudioLevelDisplay(object): width = self.drawing_area.get_allocated_width() height = self.drawing_area.get_allocated_height() - margin = 2 # px - channel_width = int((width - (margin * (channels - 1))) / channels) + # space between the channels in px + margin = 2 + + # 1 channel -> 0 margins, 2 channels -> 1 margin, 3 channels… + channel_width = int( (width - (margin * (channels - 1))) / channels ) + # self.log.debug( # 'width: %upx filled with %u channels of each %upx ' # 'and %ux margin of %upx', # width, channels, channel_width, channels-1, margin) + # normalize db-value to 0…1 and multiply with the height rms_px = [ self.normalize_db(db) * height for db in self.levelrms ] peak_px = [ self.normalize_db(db) * height for db in self.levelpeak ] decay_px = [ self.normalize_db(db) * height for db in self.leveldecay ] - cr.set_line_width(channel_width) + # set the line-width >1, to get a nice overlap + cr.set_line_width(2) + + # iterate over all pixels for y in range(0, height): - pct = self.clamp(((y / height) - 0.6) / 0.42, 0, 1) + + # calculate our place in the color-gradient, clamp to 0…1 + # 0 -> green, 0.5 -> yellow, 1 -> red + color = self.clamp(((y / height) - 0.6) / 0.42) for channel in range(0, channels): + # start-coordinate for this channel x = (channel * channel_width) + (channel * margin) + # calculate the brightness based on whether this line is in the + # active region + + # default to 0.25, dark bright = 0.25 if int(y - decay_px[channel]) in range(0, 2): + # decay marker, 2px wide, extra bright bright = 1.5 elif y < rms_px[channel]: + # rms bar, full bright bright = 1 elif y < peak_px[channel]: + # peak bar, a little darker bright = 0.75 - cr.set_source_rgb(pct * bright, (1-pct) * bright * 0.75, 0 * bright) + # set the color with a little reduced green + cr.set_source_rgb( + color * bright, + (1-color) * bright * 0.75, + 0 + ) + # draw the marker cr.move_to(x, height-y) cr.line_to(x + channel_width, height-y) cr.stroke() + # draw a black line for the margin cr.set_source_rgb(0,0,0) cr.move_to(x + channel_width, height-y) cr.line_to(x + channel_width + margin, height-y) cr.stroke() + # draw db text-markers cr.set_source_rgb(1, 1, 1) for db in [-40, -20, -10, -5, -4, -3, -2, -1]: text = str(db) @@ -70,7 +100,6 @@ class AudioLevelDisplay(object): cr.move_to((width-textwidth) / 2, height - y - textheight) cr.show_text(text) - return True def normalize_db(self, db): @@ -80,10 +109,9 @@ class AudioLevelDisplay(object): # -5db -> 0.25 # -0db -> 0.00 (very loud) logscale = 1 - math.log10(-0.15 * db + 1) - normalized = self.clamp(logscale, 0, 1) - return normalized + return self.clamp(logscale) - def clamp(self, value, min_value, max_value): + def clamp(self, value, min_value=0, max_value=1): return max(min(value, max_value), min_value) def level_callback(self, rms, peak, decay): |