]> git.parisson.com Git - timeside.git/commitdiff
Analyzer: Decorates some analyzers with preprocessors for downmixing and frames block...
authorThomas Fillon <thomas@parisson.com>
Fri, 15 Nov 2013 15:39:58 +0000 (16:39 +0100)
committerThomas Fillon <thomas@parisson.com>
Fri, 15 Nov 2013 15:39:58 +0000 (16:39 +0100)
tests/__init__.py [new file with mode: 0644]
tests/unit_timeside.py
timeside/analyzer/aubio_melenergy.py
timeside/analyzer/aubio_mfcc.py
timeside/analyzer/aubio_pitch.py
timeside/analyzer/aubio_specdesc.py
timeside/analyzer/aubio_temporal.py
timeside/analyzer/odf.py
timeside/analyzer/preprocessors.py
timeside/analyzer/spectrogram.py
timeside/analyzer/waveform.py

diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
index f31ac4cc21269343e7ba267ac01d760931741f17..01a1b7681a20ffe7ad9a0ed7a6928b7d42d7a6d2 100644 (file)
@@ -142,4 +142,6 @@ class TestRunner:
             self.stream.writeln("OK")
         return result
 
-
+def runTestModule(module):
+    suite = unittest.loader.TestLoader().loadTestsFromModule(module)
+    TestRunner().run(suite)
index e8629347c065c2caf36f1c13adc4ae7e68dc0465..451a0ae37d65c093005fa34ab258b50ce8f4b855 100644 (file)
@@ -22,7 +22,7 @@
 from timeside.core import implements, interfacedoc
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
+from preprocessors import downmix_to_mono, frames_adapter
 
 import numpy
 from aubio import filterbank, pvoc
@@ -47,7 +47,7 @@ class AubioMelEnergy(Analyzer):
         self.melenergy = filterbank(self.n_filters, self.input_blocksize)
         self.melenergy.set_mel_coeffs_slaney(samplerate)
         self.block_read = 0
-        self.melenergy_results = numpy.zeros([self.n_filters, ])
+        self.melenergy_results = []
 
     @staticmethod
     @interfacedoc
@@ -64,13 +64,13 @@ class AubioMelEnergy(Analyzer):
     def unit():
         return ""
 
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
-        for samples in downsample_blocking(frames, self.input_stepsize):
-            # TODO : check pourquoi on utilise pas le blocksize ?
-            fftgrain = self.pvoc(samples)
-            self.melenergy_results = numpy.vstack(
-                [self.melenergy_results, self.melenergy(fftgrain)])
-            self.block_read += 1
+
+        fftgrain = self.pvoc(frames)
+        self.melenergy_results.append(self.melenergy(fftgrain))
+        self.block_read += 1
         return frames, eod
 
     def post_process(self):
index 2fa8c2357a26670b2f51418c736b41a7ed591737..0b44368d1cbefed83b38471b603533e574f5e4fe 100644 (file)
@@ -22,7 +22,7 @@
 from timeside.core import implements, interfacedoc
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
+from preprocessors import downmix_to_mono, frames_adapter
 
 import numpy
 from aubio import mfcc, pvoc
@@ -66,12 +66,13 @@ class AubioMfcc(Analyzer):
     def unit():
         return ""
 
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
-        for samples in downsample_blocking(frames, self.input_stepsize):
-            fftgrain = self.pvoc(samples)
-            coeffs = self.mfcc(fftgrain)
-            self.mfcc_results = numpy.vstack((self.mfcc_results, coeffs))
-            self.block_read += 1
+        fftgrain = self.pvoc(frames)
+        coeffs = self.mfcc(fftgrain)
+        self.mfcc_results = numpy.vstack((self.mfcc_results, coeffs))
+        self.block_read += 1
         return frames, eod
 
     def post_process(self):
index b358bb30cbe245bbaf6c4fb9de1914cb582a5efd..46ad3d3e8ec4980d0567d2930d9a51359f19a646 100644 (file)
@@ -22,7 +22,7 @@
 from timeside.core import Processor, implements, interfacedoc, FixedSizeInputAdapter
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
+from preprocessors import downmix_to_mono, frames_adapter
 from aubio import pitch
 
 
@@ -65,11 +65,12 @@ class AubioPitch(Analyzer):
     def __str__(self):
         return "pitch values"
 
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
-        for samples in downsample_blocking(frames, self.input_stepsize):
-            #time = self.block_read * self.input_stepsize * 1. / self.samplerate()
-            self.pitches += [self.p(samples)[0]]
-            self.block_read += 1
+        #time = self.block_read * self.input_stepsize * 1. / self.samplerate()
+        self.pitches += [self.p(frames)[0]]
+        self.block_read += 1
         return frames, eod
 
     def post_process(self):
index ce4d04871259d7dd38e456bb7d6c11ac99deb5da..931969d21b436ed3717873b92218365483cb6234 100644 (file)
@@ -22,7 +22,7 @@
 from timeside.core import Processor, implements, interfacedoc, FixedSizeInputAdapter
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
+from preprocessors import downmix_to_mono, frames_adapter
 
 from aubio import specdesc, pvoc
 
@@ -72,12 +72,13 @@ class AubioSpecdesc(Analyzer):
     def unit():
         return ""
 
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
-        for samples in downsample_blocking(frames, self.input_stepsize):
-            fftgrain = self.pvoc(samples)
-            for method in self.methods:
-                self.specdesc_results[method] += [
-                    self.specdesc[method](fftgrain)[0]]
+        fftgrain = self.pvoc(frames)
+        for method in self.methods:
+            self.specdesc_results[method] += [
+                self.specdesc[method](fftgrain)[0]]
         return frames, eod
 
     def post_process(self):
index 71d5f604804739d1d8dc232bc5025d5e5dffb08d..27d1c3d982c06edf70ffacacf7130bb53e3eedcd 100644 (file)
@@ -22,7 +22,7 @@
 from timeside.core import implements, interfacedoc
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
+from preprocessors import downmix_to_mono, frames_adapter
 from aubio import onset, tempo
 
 import numpy
@@ -70,13 +70,15 @@ class AubioTemporal(Analyzer):
     def __str__(self):
         return "%s %s" % (str(self.value), self.unit())
 
+
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
-        for samples in downsample_blocking(frames, self.input_stepsize):
-            if self.o(samples):
-                self.onsets += [self.o.get_last_s()]
-            if self.t(samples):
-                self.beats += [self.t.get_last_s()]
-            self.block_read += 1
+        if self.o(frames):
+            self.onsets += [self.o.get_last_s()]
+        if self.t(frames):
+            self.beats += [self.t.get_last_s()]
+        self.block_read += 1
         return frames, eod
 
     def post_process(self):
index fab3e702357f314f01f892b130a42abea75160e1..42eb0bce5c3a49ff1492d8805a44061c5632887d 100644 (file)
@@ -17,7 +17,7 @@
 # You should have received a copy of the GNU General Public License
 # along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
 
-# Author: Paul Brossier <piem@piem.org>
+# Author: Thomas Fillon <thomas@parisson.com>
 
 from timeside.core import implements, interfacedoc
 from timeside.analyzer.core import Analyzer
@@ -74,11 +74,23 @@ class OnsetDetectionFunction(Analyzer):
         #spectrogram = self.pipe._results[self.parents()[0].id]
 
         # Low-pass filtering of the spectrogram amplitude along the time axis
-        S = signal.lfilter(signal.hann(15), 1, abs(spectrogram), axis=0)
+        S = signal.lfilter(signal.hann(15)[8:], 1, abs(spectrogram), axis=0)
+
+
+        import matplotlib.pyplot as plt
+#        plt.figure()
+#        plt.imshow(np.log10(abs(spectrogram)), origin='lower', aspect='auto', interpolation='nearest')
+
+
         # Clip small value to a minimal threshold
         np.maximum(S, 1e-9, out=S)
 
         S = np.log10(S)
+
+#        plt.figure()
+#        plt.imshow(S,origin='lower', aspect='auto', interpolation='nearest')
+#        plt.show()
+
         # S[S<1e-3]=0
         np.maximum(S, 1e-3, out=S)
 
index c96a236aaa5b0026642f6dc00f6b825d675f9997..d1dd8b3b23b12729c13cc413479810e8bf1bcbac 100644 (file)
 # along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
 #
 # Author : Thomas fillon <thomas@parisson.fr>
+'''
+    Collections of preprocessors to use as decorators for the analyzers process
 
+    Preprocessors process the (frame, eod) arguments in order to handle various
+    preprocessing such as :
+        - Downmixing to mono
+        - Adapt the frames to match the input_blocksize and input_stepsize
+            of the analyzer
+'''
 
 def downmix_to_mono(process_func):
     '''
     Pre-processing decorator that downmixes frames from multi-channel to mono
-    Downmix by averaging all channels
+
+    Downmix is achieved by averaging all channels
+
     >>> @downmix_to_mono
     ... def process(analyzer,frames,eod):
     ...     print 'Frames, eod inside process :'
@@ -66,7 +76,9 @@ def downmix_to_mono(process_func):
 
 def frames_adapter(process_func):
     '''
-    Pre-processing decorator that adapt frames to match blocksize and stepsize
+    Pre-processing decorator that adapt frames to match input_blocksize and
+    input_stepsize of the decorated analyzer
+
     >>> @frames_adapter
     ... def process(analyzer,frames,eod):
     ...     analyzer.frames.append(frames)
@@ -164,5 +176,11 @@ def frames_adapter(process_func):
 
 
 if __name__ == "__main__":
+    # Run doctest
     import doctest
     doctest.testmod()
+
+    # Run unittest from test_analyzer_preprocessors
+    from tests import test_analyzer_preprocessors
+    from tests.unit_timeside import runTestModule
+    runTestModule(test_analyzer_preprocessors)
index adc2e555336ec9d2469b8c72ac9fb8b30d66b87e..9728c6aa2ac58dd974adab5ffc5b0fa0c3283c01 100644 (file)
@@ -22,7 +22,7 @@
 from timeside.core import implements, interfacedoc
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
+from preprocessors import downmix_to_mono, frames_adapter
 import numpy as np
 
 
@@ -62,11 +62,11 @@ class Spectrogram(Analyzer):
     def unit():
         return ""
 
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
-        for samples in downsample_blocking(frames, self.input_stepsize):
-            #time = self.block_read * self.input_stepsize * 1. / self.samplerate()
-            self.values.append(np.abs(np.fft.rfft(samples, self.FFT_SIZE)))
-        return frames, eod
+            self.values.append(np.abs(np.fft.rfft(frames, self.FFT_SIZE)))
+            return frames, eod
 
     def post_process(self):
         spectrogram = self.new_result(data_mode='value', time_mode='framewise')
index eb8b09f1c2de66860d3dc2b7aa30d6ffd6d9d9be..db55043c0aaab1cf3f724d5eefdc4c2489ef8e2c 100644 (file)
 from timeside.core import implements, interfacedoc
 from timeside.analyzer.core import Analyzer
 from timeside.api import IAnalyzer
-from utils import downsample_blocking
 import numpy as np
 
+from preprocessors import downmix_to_mono, frames_adapter
 
 class Waveform(Analyzer):
     implements(IAnalyzer)  # TODO check if needed with inheritance
 
     def __init__(self):
+        super(Waveform, self).__init__()
         self.input_blocksize = 2048
         self.input_stepsize = self.input_blocksize / 2
 
@@ -57,6 +58,8 @@ class Waveform(Analyzer):
     def unit():
         return ""
 
+    @downmix_to_mono
+    @frames_adapter
     def process(self, frames, eod=False):
         for samples in downsample_blocking(frames, self.input_blocksize):
             self.values.append(samples)