improve audio timeline, normalize to full width
This commit is contained in:
parent
efc81d7bc9
commit
0f3045f829
1 changed files with 46 additions and 63 deletions
|
@ -13,8 +13,7 @@ import gst
|
||||||
|
|
||||||
|
|
||||||
class Audio(gst.Pipeline):
|
class Audio(gst.Pipeline):
|
||||||
left = []
|
volume = []
|
||||||
right = []
|
|
||||||
position = 0
|
position = 0
|
||||||
|
|
||||||
def __init__(self, uri, channels=2):
|
def __init__(self, uri, channels=2):
|
||||||
|
@ -34,12 +33,12 @@ class Audio(gst.Pipeline):
|
||||||
self.queue = gst.element_factory_make("queue")
|
self.queue = gst.element_factory_make("queue")
|
||||||
self.rate = gst.element_factory_make("audioresample")
|
self.rate = gst.element_factory_make("audioresample")
|
||||||
self.conv = gst.element_factory_make("audioconvert")
|
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 = 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)
|
self.src.link(self.sbin)
|
||||||
|
@ -61,61 +60,10 @@ class Audio(gst.Pipeline):
|
||||||
self.conv.link(self.rate,
|
self.conv.link(self.rate,
|
||||||
gst.Caps("audio/x-raw-int,channels=%s,width=16,depth=16" %
|
gst.Caps("audio/x-raw-int,channels=%s,width=16,depth=16" %
|
||||||
(self.channels, )))
|
(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" %
|
gst.Caps("audio/x-raw-int,rate=%s,channels=%s,width=16,depth=16" %
|
||||||
(self.samplerate, self.channels)))
|
(self.samplerate, self.channels)))
|
||||||
|
self.level.link(self.sink)
|
||||||
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()
|
|
||||||
|
|
||||||
def getDuration(self):
|
def getDuration(self):
|
||||||
if self.duration < 0:
|
if self.duration < 0:
|
||||||
|
@ -126,6 +74,21 @@ class Audio(gst.Pipeline):
|
||||||
format, self.duration = q.parse_duration()
|
format, self.duration = q.parse_duration()
|
||||||
return self.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):
|
class Timeline(Audio):
|
||||||
def __init__(self, uri, prefix, width, height):
|
def __init__(self, uri, prefix, width, height):
|
||||||
Audio.__init__(self, uri)
|
Audio.__init__(self, uri)
|
||||||
|
@ -150,6 +113,31 @@ class Timeline(Audio):
|
||||||
self.set_state(gst.STATE_PLAYING)
|
self.set_state(gst.STATE_PLAYING)
|
||||||
self.mainloop.run()
|
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):
|
for i in range(ntiles):
|
||||||
tile = self.tiles[i]
|
tile = self.tiles[i]
|
||||||
if tile.size[0] != self.tile_width:
|
if tile.size[0] != self.tile_width:
|
||||||
|
@ -167,8 +155,3 @@ class Timeline(Audio):
|
||||||
|
|
||||||
def done(self):
|
def done(self):
|
||||||
self.mainloop.quit()
|
self.mainloop.quit()
|
||||||
|
|
||||||
def onBusMessage(self, bus, message):
|
|
||||||
if message.src == self and message.type == gst.MESSAGE_EOS:
|
|
||||||
self.done()
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue