annotate pyspark/vamp_plugin_dml.py @ 0:e34cf1b6fe09 tip

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