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 | |
---|
60 | class aubioinput: |
---|
61 | def __init__(self, location, process = None, hopsize = 512, |
---|
62 | caps = None): |
---|
63 | from os.path import isfile |
---|
64 | if not isfile(location): |
---|
65 | raise ValueError, "location should be a file" |
---|
66 | src = gst.element_factory_make('filesrc') |
---|
67 | src.set_property('location', location) |
---|
68 | dec = gst.element_factory_make('decodebin') |
---|
69 | dec.connect('new-decoded-pad', self.on_new_decoded_pad) |
---|
70 | conv = gst.element_factory_make('audioconvert') |
---|
71 | rsmpl = gst.element_factory_make('audioresample') |
---|
72 | capsfilter = gst.element_factory_make('capsfilter') |
---|
73 | if caps: |
---|
74 | capsfilter.set_property('caps', gst.caps_from_string(caps)) |
---|
75 | sink = AubioSink("AubioSink", process = process) |
---|
76 | sink.set_property('hopsize', hopsize) # * calcsize('f')) |
---|
77 | |
---|
78 | self.pipeline = gst.Pipeline() |
---|
79 | |
---|
80 | self.bus = self.pipeline.get_bus() |
---|
81 | self.bus.add_signal_watch() |
---|
82 | self.bus.connect('message::eos', self.on_eos) |
---|
83 | |
---|
84 | self.apad = conv.get_pad('sink') |
---|
85 | |
---|
86 | self.pipeline.add(src, dec, conv, rsmpl, capsfilter, sink) |
---|
87 | |
---|
88 | src.link(dec) |
---|
89 | gst.element_link_many(conv, rsmpl, capsfilter, sink) |
---|
90 | |
---|
91 | self.mainloop = gobject.MainLoop() |
---|
92 | self.pipeline.set_state(gst.STATE_PLAYING) |
---|
93 | self.mainloop.run() |
---|
94 | |
---|
95 | def on_new_decoded_pad(self, element, pad, last): |
---|
96 | caps = pad.get_caps() |
---|
97 | name = caps[0].get_name() |
---|
98 | #print 'on_new_decoded_pad:', name |
---|
99 | if name == 'audio/x-raw-float' or name == 'audio/x-raw-int': |
---|
100 | if not self.apad.is_linked(): # Only link once |
---|
101 | pad.link(self.apad) |
---|
102 | |
---|
103 | def on_eos(self, bus, msg): |
---|
104 | self.bus.remove_signal_watch() |
---|
105 | self.pipeline.set_state(gst.STATE_PAUSED) |
---|
106 | self.mainloop.quit() |
---|
107 | |
---|
108 | if __name__ == '__main__': |
---|
109 | import sys |
---|
110 | if len(sys.argv) < 2: |
---|
111 | print "Usage: %s <filename>" % sys.argv[0] |
---|
112 | sys.exit(1) |
---|
113 | for filename in sys.argv[1:]: |
---|
114 | peak = [0., 0.] |
---|
115 | def process(buf, hop): |
---|
116 | peak[0] = max( peak[0], abs(buf.max()) ) |
---|
117 | peak[1] = min( peak[1], abs(buf.min()) ) |
---|
118 | aubioinput(filename, process = process, hopsize = 512) |
---|
119 | print "Finished reading %s, peak value is %f" % (filename, min(peak)) |
---|