From 0f3045f82953249df62f5002f2ba6d454cfc78c8 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Wed, 7 Mar 2012 15:36:48 +0100 Subject: [PATCH] improve audio timeline, normalize to full width --- oxtimeline/audio.py | 109 +++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/oxtimeline/audio.py b/oxtimeline/audio.py index b02fbc5..67bbc02 100644 --- a/oxtimeline/audio.py +++ b/oxtimeline/audio.py @@ -13,8 +13,7 @@ import gst class Audio(gst.Pipeline): - left = [] - right = [] + volume = [] position = 0 def __init__(self, uri, channels=2): @@ -34,12 +33,12 @@ class Audio(gst.Pipeline): self.queue = gst.element_factory_make("queue") self.rate = gst.element_factory_make("audioresample") self.conv = gst.element_factory_make("audioconvert") + self.level = gst.element_factory_make("level") + self.level.props.interval = int(gst.SECOND / self.framerate) self.sink = gst.element_factory_make("fakesink") - self.sink.props.signal_handoffs = True - self.sink.connect('handoff', self._data_callback) - self.add(self.src, self.sbin, self.conv, self.queue, self.rate, self.sink) + self.add(self.src, self.sbin, self.conv, self.queue, self.rate, self.level, self.sink) self.src.link(self.sbin) @@ -61,61 +60,10 @@ class Audio(gst.Pipeline): self.conv.link(self.rate, gst.Caps("audio/x-raw-int,channels=%s,width=16,depth=16" % (self.channels, ))) - self.rate.link(self.sink, + self.rate.link(self.level, gst.Caps("audio/x-raw-int,rate=%s,channels=%s,width=16,depth=16" % (self.samplerate, self.channels))) - - def _data_callback(self, sink, buff, pad): - timestamp = buff.timestamp - samples = int(buff.size // 2 / self.channels) - fmt = "<" + str(samples) + "h" - - data = unpack(fmt, buff.data[:2*samples]) + unpack(fmt, buff.data[2*samples:]) - n = 0 - for i in data: - if n%2 == 0: - self.left.append(i) - else: - self.right.append(i) - n += 1 - - samples_per_pixel = int(self.samplerate / self.framerate) - while len(self.left) > samples_per_pixel: - tile = int(math.floor(float(self.position) / self.input_tile_width)) - tilePos = int(self.position - (tile * self.input_tile_width)) - - def plot(p, start): - p = int(p / 256) - height = int((p * self.tile_height) / 256) * 2 - crop = int((self.tile_height-height) / 2) - if p: p += 20 - color = (p, p, p) - color = (255,255,255) - - if start: - end = self.tile_height - crop - else: - start = crop - end = int(self.tile_height/2) - #for i in range(0, self.tile_height): - for i in range(start, end): - self.tiles[tile].putpixel((tilePos, i), color) - #left - pixel = np.asarray(self.left[:samples_per_pixel]) - self.left = self.left[samples_per_pixel:] - p = np.sum(np.abs(pixel)) / samples_per_pixel - plot(p, 0) - - #right - pixel = np.asarray(self.right[:samples_per_pixel]) - self.right = self.right[samples_per_pixel:] - p = np.sum(np.abs(pixel)) / samples_per_pixel - plot(p, int(self.tile_height/2)) - - self.position += 1 - - if self.mainloop and timestamp >= self.duration: - self.done() + self.level.link(self.sink) def getDuration(self): if self.duration < 0: @@ -126,6 +74,21 @@ class Audio(gst.Pipeline): format, self.duration = q.parse_duration() return self.duration + def done(self): + pass + + def onBusMessage(self, bus, message): + if message.src == self.level: + struct = message.structure + if struct.get_name() == 'level': + self.volume.append(( + pow (10, struct['rms'][0] / 20), + pow (10, struct['rms'][1] / 20) + )) + + if message.src == self and message.type == gst.MESSAGE_EOS: + self.done() + class Timeline(Audio): def __init__(self, uri, prefix, width, height): Audio.__init__(self, uri) @@ -150,6 +113,31 @@ class Timeline(Audio): self.set_state(gst.STATE_PLAYING) self.mainloop.run() + normalize = 1/max([max(*v) for v in self.volume]) + for volume in self.volume: + tile = int(math.floor(float(self.position) / self.input_tile_width)) + tilePos = int(self.position - (tile * self.input_tile_width)) + + def plot(p, start): + height = normalize * p * self.tile_height + crop = int((self.tile_height-height) / 2) + color = (p, p, p) + color = (255,255,255) + + if start: + end = self.tile_height - crop + else: + start = crop + end = int(self.tile_height/2) + for i in range(start, end): + self.tiles[tile].putpixel((tilePos, i), color) + #left + plot(volume[0], 0) + #right + plot(volume[1], int(self.tile_height/2)) + + self.position += 1 + for i in range(ntiles): tile = self.tiles[i] if tile.size[0] != self.tile_width: @@ -167,8 +155,3 @@ class Timeline(Audio): def done(self): self.mainloop.quit() - - def onBusMessage(self, bus, message): - if message.src == self and message.type == gst.MESSAGE_EOS: - self.done() -