]> git.parisson.com Git - timeside.git/commitdiff
Add Yaafe wrapper as a new TimeSide analyzer
authorThomas Fillon <thomas@parisson.com>
Sat, 15 Jun 2013 12:09:47 +0000 (14:09 +0200)
committerThomas Fillon <thomas@parisson.com>
Sat, 15 Jun 2013 12:09:47 +0000 (14:09 +0200)
Yaafe wrapper needs a proper Yaafe install (don't forget to set all the environment variables required by Yaafe). Yaafe analyzer uses the Yaafe python engine to which TimeSide sends the audio data during process() and gets back the results when result() is called. The corresponding tests are also included in this commit. Enjoy !

tests/test_yaafe.py [new file with mode: 0644]
tests/yaafe_config/yaafeDataFlow [new file with mode: 0644]
tests/yaafe_config/yaafeFeaturePlan [new file with mode: 0644]
timeside/analyzer/__init__.py
timeside/analyzer/yaafe.py [new file with mode: 0644]

diff --git a/tests/test_yaafe.py b/tests/test_yaafe.py
new file mode 100644 (file)
index 0000000..0f6ccf3
--- /dev/null
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+
+from unit_timeside import *
+from timeside.decoder import *
+from timeside.analyzer import Yaafe
+from yaafelib import DataFlow,FeaturePlan
+
+class TestYaafe(TestCase):
+
+    def setUp(self):
+        self.sample_rate = 16000
+    
+    def testOnSweepWithFeaturePlan(self):
+        "runs on sweep and define feature plan manualy"
+        self.source = os.path.join (os.path.dirname(__file__),  "samples", "sweep.wav")
+
+        # Setup Yaafe Analyzer
+        # Define Yaafe Feature Plan
+        fp = FeaturePlan(sample_rate=self.sample_rate)
+        # add feature definitions manually
+        fp.addFeature('mfcc: MFCC blockSize=512 stepSize=256')
+        fp.addFeature('mfcc_d1: MFCC blockSize=512 stepSize=256 > Derivate DOrder=1')
+        fp.addFeature('mfcc_d2: MFCC blockSize=512 stepSize=256 > Derivate DOrder=2')
+        
+        # Setup a new Yaafe TimeSide analyzer 
+        # from FeaturePlan
+        self.analyzer = Yaafe(fp)
+
+    def testOnGuitarWithFeaturePlanFromFile(self):
+        "runs on guitar and load Yaafe feature plan from file"
+        self.source = os.path.join (os.path.dirname(__file__),  "samples", "guitar.wav")
+        # Setup Yaafe Analyzer
+        # Load Yaafe Feature Plan
+        fp = FeaturePlan(sample_rate=self.sample_rate)
+        fp_file = os.path.join (os.path.dirname(__file__),  "yaafe_config", "yaafeFeaturePlan")
+        
+        fp.loadFeaturePlan(fp_file)
+        # Setup a new Yaafe TimeSide analyzer 
+        # from FeaturePlan
+        self.analyzer = Yaafe(fp)
+    
+    def testOnGuitarWithDataFlow(self):
+        "runs on guitar and load Yaafe dataflow from file"
+        self.source = os.path.join (os.path.dirname(__file__),  "samples", "guitar.wav")
+        # Setup Yaafe Analyzer
+        # Load DataFlow from file
+        df = DataFlow() 
+        df_file = os.path.join (os.path.dirname(__file__),  "yaafe_config", "yaafeDataFlow")
+        df.load(df_file)
+        
+        # Setup a new Yaafe TimeSide analyzer 
+        # from DataFlow
+        self.analyzer = Yaafe(df)
+
+    def tearDown(self):
+        decoder = FileDecoder(self.source)
+        decoder.output_samplerate = self.sample_rate
+        (decoder | self.analyzer).run()
+        results = self.analyzer.results()
+        #print results
+        #print results.to_yaml()
+        #print results.to_json()
+        #print results.to_xml()
+
+if __name__ == '__main__':
+    unittest.main(testRunner=TestRunner())
diff --git a/tests/yaafe_config/yaafeDataFlow b/tests/yaafe_config/yaafeDataFlow
new file mode 100644 (file)
index 0000000..a7191a6
--- /dev/null
@@ -0,0 +1,38 @@
+useComponentLibrary yaafe-components
+audio := Input Resample="yes" SampleRate="16000"
+n1 := FrameTokenizer blockSize="512" stepSize="256"
+n2 := FFT FFTLength="512" FFTWindow="Hanning"
+n3 := Abs
+n4 := MelFilterBank MelMaxFreq="6854.0" MelMinFreq="130.0" MelNbFilters="40"
+n5 := Cepstrum CepsIgnoreFirstCoeff="1" CepsNbCoeffs="13"
+mfcc := Output normalize="-1" resample="yes" samplerate="16000" version="0.64" yaafedefinition="MFCC blockSize=512 stepSize=256"
+n7 := Derivate DO1Len="4" DO2Len="1" DOrder="1"
+mfcc_d1 := Output normalize="-1" resample="yes" samplerate="16000" version="0.64" yaafedefinition="MFCC blockSize=512 stepSize=256 > Derivate DOrder=1"
+n9 := FrameTokenizer blockSize="1024" stepSize="1024"
+n10 := FFT FFTLength="1024" FFTWindow="Hanning"
+n11 := Abs
+n12 := MelFilterBank MelMaxFreq="6854.0" MelMinFreq="130.0" MelNbFilters="40"
+n13 := Cepstrum CepsIgnoreFirstCoeff="1" CepsNbCoeffs="11"
+n14 := Output normalize="-1" resample="yes" samplerate="16000" version="0.64" yaafedefinition="MFCC blockSize=1024 stepSize=1024 CepsNbCoeffs=11"
+n15 := Derivate DO1Len="4" DO2Len="1" DOrder="1"
+n16 := Output normalize="-1" resample="yes" samplerate="16000" version="0.64" yaafedefinition="MFCC blockSize=1024 stepSize=1024 CepsNbCoeffs=11 > Derivate DOrder=1"
+n17 := Derivate DO1Len="4" DO2Len="1" DOrder="2"
+mfcc_d2 := Output normalize="-1" resample="yes" samplerate="16000" version="0.64" yaafedefinition="MFCC blockSize=1024 stepSize=1024 CepsNbCoeffs=11 > Derivate DOrder=2"
+audio > n1
+n1 > n2
+n2 > n3
+n3 > n4
+n4 > n5
+n5 > mfcc
+n5 > n7
+n7 > mfcc_d1
+audio > n9
+n9 > n10
+n10 > n11
+n11 > n12
+n12 > n13
+n13 > n14
+n13 > n15
+n15 > n16
+n13 > n17
+n17 > mfcc_d2
diff --git a/tests/yaafe_config/yaafeFeaturePlan b/tests/yaafe_config/yaafeFeaturePlan
new file mode 100644 (file)
index 0000000..b92c647
--- /dev/null
@@ -0,0 +1,3 @@
+mfcc: MFCC blockSize=1024 stepSize=1024 CepsNbCoeffs=11
+mfcc_d1: MFCC blockSize=1024 stepSize=1024 CepsNbCoeffs=11 > Derivate DOrder=1
+mfcc_d2: MFCC blockSize=1024 stepSize=1024 CepsNbCoeffs=11 > Derivate DOrder=2
\ No newline at end of file
index 4c1c6804ca0f9479010cbe5f2abcbf164f195f0f..0747b3afa106e40622395e3aea2952e08c8eb8ae 100644 (file)
@@ -7,3 +7,4 @@ from aubio_pitch import *
 from aubio_mfcc import *
 from aubio_melenergy import *
 from aubio_specdesc import *
+from yaafe import * # TF : add Yaafe analyzer
\ No newline at end of file
diff --git a/timeside/analyzer/yaafe.py b/timeside/analyzer/yaafe.py
new file mode 100644 (file)
index 0000000..50c85bd
--- /dev/null
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2013 Thomas Fillon <thomas@parisson.com>
+
+# This file is part of TimeSide.
+
+# TimeSide is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+
+# TimeSide is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
+
+# Author : Thomas Fillon <thomas@parisson.com>
+"""
+Module Yaafe Analyzer 
+Created on Thu Jun 13 16:05:02 2013
+
+@author: Thomas Fillon
+"""
+from timeside.core import Processor, implements, interfacedoc, FixedSizeInputAdapter
+from timeside.analyzer.core import *
+from timeside.api import IValueAnalyzer
+#
+from yaafelib import *
+#
+import numpy
+
+class Yaafe(Processor):
+    implements(IValueAnalyzer)
+    def __init__(self, yaafeSpecification):
+        # Check arguments
+        if isinstance(yaafeSpecification,DataFlow):
+            self.dataFlow = yaafeSpecification
+        elif isinstance(yaafeSpecification,FeaturePlan):
+            self.featurePlan = yaafeSpecification
+            self.dataFlow = self.featurePlan.getDataFlow()
+        else:
+            raise TypeError("'%s' Type must be either '%s' or '%s'" % (str(yaafeSpecification),str(DataFlow),str(FeaturePlan)))
+        
+    @interfacedoc
+    def setup(self, channels=None, samplerate=None, blocksize=None, totalframes=None):
+        super(Yaafe, self).setup(channels, samplerate, blocksize, totalframes)
+        # Configure a YAAFE engine
+        self.yaafe_engine = Engine()
+        self.yaafe_engine.load(self.dataFlow)
+        self.yaafe_engine.reset()
+
+    @staticmethod
+    @interfacedoc
+    def id():
+        return "yaafe"
+
+    @staticmethod
+    @interfacedoc
+    def name():
+        return "Yaafe Descriptor"
+
+    def process(self, frames, eod=False):
+        # do process things...
+        # Downmixing to mono and convert to float64 for compatibility with Yaafe       
+        yaafe_frames = frames.sum(axis=-1,dtype=numpy.float64) / frames.shape[-1]
+        # Reshape for compatibility with Yaafe input format        
+        yaafe_frames.shape = (1,yaafe_frames.shape[0]) 
+        # write audio array on 'audio' input
+        self.yaafe_engine.writeInput('audio',yaafe_frames) 
+        # process available data        
+        self.yaafe_engine.process() 
+        if eod:
+            # flush yaafe engine to process remaining data
+            self.yaafe_engine.flush() 
+           
+        return frames, eod
+
+    def results(self):
+        # Get back current container
+        container = AnalyzerResultContainer()
+        # Get feature extraction results from yaafe        
+        featNames = self.yaafe_engine.getOutputs().keys()
+        for featName in featNames:
+            # Define ID fields            
+            id = 'yaafe_' + featName
+            name = 'Yaafe ' + featName
+            unit = ''
+            # Get results from Yaafe engine
+            result = AnalyzerResult(id = id, name = name, unit = unit)
+            result.value = self.yaafe_engine.readOutput(featName)  # Read Yaafe Results       
+            # Store results in Container
+            if len(result.value):
+                container.add_result(result)
+        
+        return container
+
+
+
+