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