[1c190d5] | 1 | #! /usr/bin/python |
---|
| 2 | |
---|
| 3 | import pygst |
---|
| 4 | pygst.require('0.10') |
---|
| 5 | import gst |
---|
| 6 | import gobject |
---|
| 7 | gobject.threads_init () |
---|
| 8 | |
---|
| 9 | def gst_buffer_to_numpy_array(buffer, chan): |
---|
| 10 | import numpy |
---|
| 11 | samples = numpy.frombuffer(buffer.data, dtype=numpy.float32) |
---|
| 12 | samples.resize([len(samples)/chan, chan]) |
---|
| 13 | return samples.T |
---|
| 14 | |
---|
| 15 | class AubioSink(gst.BaseSink): |
---|
| 16 | _caps = gst.caps_from_string('audio/x-raw-float, \ |
---|
| 17 | rate=[ 1, 2147483647 ], \ |
---|
| 18 | channels=[ 1, 2147483647 ], \ |
---|
| 19 | endianness={ 1234, 4321 }, \ |
---|
| 20 | width=32') |
---|
| 21 | |
---|
| 22 | __gsttemplates__ = ( |
---|
| 23 | gst.PadTemplate ("sink", |
---|
| 24 | gst.PAD_SINK, |
---|
| 25 | gst.PAD_ALWAYS, |
---|
| 26 | _caps), |
---|
| 27 | ) |
---|
| 28 | |
---|
| 29 | def __init__(self, name, process): |
---|
| 30 | self.__gobject_init__() |
---|
| 31 | self.set_name(name) |
---|
| 32 | self.process = process |
---|
| 33 | self.adapter = gst.Adapter() |
---|
| 34 | self.set_property('sync', False) |
---|
| 35 | self.pos = 0 |
---|
| 36 | |
---|
| 37 | def set_property(self, name, value): |
---|
| 38 | if name == 'hopsize': |
---|
| 39 | # blocksize is in byte, convert from hopsize |
---|
| 40 | from struct import calcsize |
---|
| 41 | self.set_property('blocksize', value * calcsize('f')) |
---|
| 42 | else: |
---|
| 43 | super(gst.BaseSink, self).set_property(name, value) |
---|
| 44 | |
---|
| 45 | def do_render(self, buffer): |
---|
| 46 | blocksize = self.get_property('blocksize') |
---|
| 47 | caps = buffer.get_caps() |
---|
| 48 | chan = caps[0]['channels'] |
---|
| 49 | self.adapter.push(buffer) |
---|
| 50 | while self.adapter.available() >= blocksize: |
---|
| 51 | block = self.adapter.take_buffer(blocksize) |
---|
| 52 | v = gst_buffer_to_numpy_array(block, chan) |
---|
| 53 | if self.process: |
---|
| 54 | self.process(v, self.pos) |
---|
| 55 | self.pos += 1 |
---|
| 56 | return gst.FLOW_OK |
---|
| 57 | |
---|
| 58 | gobject.type_register(AubioSink) |
---|
| 59 | |
---|
[1f8e522] | 60 | class aubioinput(gst.Bin): |
---|
| 61 | |
---|
| 62 | ret = 0 |
---|
| 63 | |
---|
| 64 | def __init__(self, uri, process = None, hopsize = 512, |
---|
[1c190d5] | 65 | caps = None): |
---|
[1f8e522] | 66 | if uri.startswith('/'): |
---|
| 67 | from urllib import quote |
---|
| 68 | uri = 'file://'+quote(uri) |
---|
| 69 | src = gst.element_factory_make('uridecodebin') |
---|
| 70 | src.set_property('uri', uri) |
---|
| 71 | src.connect('pad-added', self.source_pad_added_cb) |
---|
[1c190d5] | 72 | conv = gst.element_factory_make('audioconvert') |
---|
[1f8e522] | 73 | self.conv = conv |
---|
[1c190d5] | 74 | rsmpl = gst.element_factory_make('audioresample') |
---|
| 75 | capsfilter = gst.element_factory_make('capsfilter') |
---|
| 76 | if caps: |
---|
| 77 | capsfilter.set_property('caps', gst.caps_from_string(caps)) |
---|
| 78 | sink = AubioSink("AubioSink", process = process) |
---|
| 79 | sink.set_property('hopsize', hopsize) # * calcsize('f')) |
---|
| 80 | |
---|
| 81 | self.pipeline = gst.Pipeline() |
---|
| 82 | |
---|
| 83 | self.bus = self.pipeline.get_bus() |
---|
| 84 | self.bus.add_signal_watch() |
---|
[1f8e522] | 85 | self.bus.connect('message', self.on_eos) |
---|
[1c190d5] | 86 | |
---|
| 87 | self.apad = conv.get_pad('sink') |
---|
| 88 | |
---|
[1f8e522] | 89 | self.pipeline.add(src, conv, rsmpl, capsfilter, sink) |
---|
[1c190d5] | 90 | |
---|
| 91 | gst.element_link_many(conv, rsmpl, capsfilter, sink) |
---|
| 92 | |
---|
| 93 | self.mainloop = gobject.MainLoop() |
---|
| 94 | self.pipeline.set_state(gst.STATE_PLAYING) |
---|
[1f8e522] | 95 | |
---|
| 96 | def run(self): |
---|
[1c190d5] | 97 | self.mainloop.run() |
---|
[1f8e522] | 98 | return self.ret |
---|
[1c190d5] | 99 | |
---|
[1f8e522] | 100 | def source_pad_added_cb(self, src, pad): |
---|
| 101 | name = pad.get_caps()[0].get_name() |
---|
[1c190d5] | 102 | if name == 'audio/x-raw-float' or name == 'audio/x-raw-int': |
---|
[1f8e522] | 103 | pad.link(self.conv.get_pad("sink")) |
---|
| 104 | |
---|
| 105 | def source_pad_removed_cb(self, src, pad): |
---|
| 106 | pad.unlink(self.conv.get_pad("sink")) |
---|
[1c190d5] | 107 | |
---|
| 108 | def on_eos(self, bus, msg): |
---|
[1f8e522] | 109 | if msg.type == gst.MESSAGE_EOS: |
---|
| 110 | self.bus.remove_signal_watch() |
---|
| 111 | self.pipeline.set_state(gst.STATE_PAUSED) |
---|
| 112 | self.mainloop.quit() |
---|
| 113 | elif msg.type == gst.MESSAGE_ERROR: |
---|
| 114 | print "ERROR", msg.parse_error() |
---|
| 115 | self.bus.remove_signal_watch() |
---|
| 116 | self.pipeline.set_state(gst.STATE_PAUSED) |
---|
| 117 | self.mainloop.quit() |
---|
| 118 | self.ret = 1 # set return value to 1 in case of error |
---|
[1c190d5] | 119 | |
---|
| 120 | if __name__ == '__main__': |
---|
| 121 | import sys |
---|
| 122 | if len(sys.argv) < 2: |
---|
| 123 | print "Usage: %s <filename>" % sys.argv[0] |
---|
| 124 | sys.exit(1) |
---|
| 125 | for filename in sys.argv[1:]: |
---|
[1f8e522] | 126 | peak = [0.] # use a mutable |
---|
[1c190d5] | 127 | def process(buf, hop): |
---|
| 128 | peak[0] = max( peak[0], abs(buf.max()) ) |
---|
[1f8e522] | 129 | a = aubioinput(filename, process = process, hopsize = 512) |
---|
| 130 | if a.run() == 0: # only display the results if no |
---|
| 131 | print "Finished reading %s, peak value is %f" % (filename, max(peak)) |
---|