comparison pyspark/vamp_plugin_dml.py @ 0:e34cf1b6fe09 tip

commit
author Daniel Wolff
date Sat, 20 Feb 2016 18:14:24 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e34cf1b6fe09
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (c) 2013 Paul Brossier <piem@piem.org>
4
5 # This file is part of TimeSide.
6
7 # TimeSide is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 2 of the License, or
10 # (at your option) any later version.
11
12 # TimeSide is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16
17 # You should have received a copy of the GNU General Public License
18 # along with TimeSide. If not, see <http://www.gnu.org/licenses/>.
19
20 # Author: Paul Brossier <piem@piem.org>
21
22 from timeside.core import implements, interfacedoc
23 from timeside.analyzer.core import Analyzer
24 from timeside.api import IAnalyzer
25 import re
26 import subprocess
27 import numpy as np
28
29
30 def simple_host_process(argslist):
31 """Call vamp-simple-host"""
32
33 vamp_host = 'vamp-simple-host'
34 command = [vamp_host]
35 command.extend(argslist)
36 # try ?
37 stdout = subprocess.check_output(
38 command, stderr=subprocess.STDOUT).splitlines()
39
40 return stdout
41
42
43 # Raise an exception if Vamp Host is missing
44 from timeside.exceptions import VampImportError
45 try:
46 simple_host_process(['-v'])
47 WITH_VAMP = True
48 except OSError:
49 WITH_VAMP = False
50 raise VampImportError
51
52
53 class VampSimpleHostDML(Analyzer):
54
55 """Vamp plugins library interface analyzer"""
56
57 implements(IAnalyzer)
58
59 def __init__(self, plugin_list=None):
60 super(VampSimpleHostDML, self).__init__()
61 if plugin_list is None:
62 plugin_list = self.get_plugins_list()
63 #plugin_list = [['vamp-example-plugins', 'percussiononsets', 'detectionfunction']]
64
65 self.plugin_list = plugin_list
66
67 @interfacedoc
68 def setup(self, channels=None, samplerate=None,
69 blocksize=None, totalframes=None):
70 super(VampSimpleHostDML, self).setup(
71 channels, samplerate, blocksize, totalframes)
72
73 @staticmethod
74 @interfacedoc
75 def id():
76 return "vamp_simple_host_dml"
77
78 @staticmethod
79 @interfacedoc
80 def name():
81 return "Vamp Plugins Host for DML"
82
83 @staticmethod
84 @interfacedoc
85 def unit():
86 return ""
87
88 def process(self, frames, eod=False):
89 pass
90 return frames, eod
91
92 def post_process(self):
93 #plugin = 'vamp-example-plugins:amplitudefollower:amplitude'
94
95 wavfile = self.mediainfo()['uri'].split('file://')[-1]
96
97 for plugin_line in self.plugin_list:
98
99 plugin = ':'.join(plugin_line)
100 (time, duration, value) = self.vamp_plugin(plugin, wavfile)
101 if value is None:
102 return
103
104 if duration is not None:
105 plugin_res = self.new_result(
106 data_mode='value', time_mode='segment')
107 plugin_res.data_object.duration = duration
108 else:
109 plugin_res = self.new_result(
110 data_mode='value', time_mode='event')
111
112 plugin_res.data_object.time = time
113 plugin_res.data_object.value = value
114
115 # Fix strat, duration issues if audio is a segment
116 # if self.mediainfo()['is_segment']:
117 # start_index = np.floor(self.mediainfo()['start'] *
118 # self.result_samplerate /
119 # self.result_stepsize)
120 #
121 # stop_index = np.ceil((self.mediainfo()['start'] +
122 # self.mediainfo()['duration']) *
123 # self.result_samplerate /
124 # self.result_stepsize)
125 #
126 # fixed_start = (start_index * self.result_stepsize /
127 # self.result_samplerate)
128 # fixed_duration = ((stop_index - start_index) * self.result_stepsize /
129 # self.result_samplerate)
130 #
131 # plugin_res.audio_metadata.start = fixed_start
132 # plugin_res.audio_metadata.duration = fixed_duration
133 #
134 # value = value[start_index:stop_index + 1]
135 plugin_res.id_metadata.id += '.' + '.'.join(plugin_line[1:])
136 plugin_res.id_metadata.name += ' ' + \
137 ' '.join(plugin_line[1:])
138
139 self.process_pipe.results.add(plugin_res)
140
141 @staticmethod
142 def vamp_plugin(plugin, wavfile):
143
144 args = [plugin, wavfile]
145
146 stdout = simple_host_process(args) # run vamp-simple-host
147
148 stderr = stdout[0:8] # stderr containing file and process information
149 res = stdout[8:] # stdout containg the feature data
150
151 if len(res) == 0:
152 return ([], [], [])
153
154 # Parse stderr to get blocksize and stepsize
155 blocksize_info = stderr[4]
156
157 import re
158 # Match agianst pattern 'Using block size = %d, step size = %d'
159 m = re.match(
160 'Using block size = (\d+), step size = (\d+)', blocksize_info)
161
162 blocksize = int(m.groups()[0])
163 stepsize = int(m.groups()[1])
164 # Get the results
165
166 # how are types defined in this? what types can timeside use?
167 # value = np.asfarray([line.split(': ')[1] for line in res if (len(line.split(': ')) > 1)])
168 value = [line.split(': ')[1] for line in res if (len(line.split(': ')) > 1)]
169 value = [re.sub("[^0-9\.\s]","",x) for x in value]
170 value = np.asfarray([[x.split(' ')[0] for x in value], [x.split(' ')[1] for x in value]]) # only get the first thing in the string
171 time = np.asfarray([r.split(':')[0].split(',')[0] for r in res])
172
173 time_len = len(res[0].split(':')[0].split(','))
174 if time_len == 1:
175 # event
176 duration = None
177 elif time_len == 2:
178 # segment
179 duration = np.asfarray(
180 [r.split(':')[0].split(',')[1] for r in res])
181
182 return (time, duration, value)
183
184 @staticmethod
185 def get_plugins_list():
186 arg = ['--list-outputs']
187 stdout = simple_host_process(arg)
188
189 return [line.split(':')[1:] for line in stdout]