def frames_adapter(process_func):
import functools<EOL>import numpy as np<EOL>class framesBuffer(object):<EOL><INDENT>def __init__(self, blocksize, stepsize):<EOL><INDENT>self.blocksize = blocksize<EOL>self.stepsize = stepsize<EOL>self.buffer = None<EOL><DEDENT>def frames(self, frames, eod):<EOL><INDENT>if self.buffer is not None:<EOL><INDENT>stack = np.concatenate([self.buffer, frames])<EOL><DEDENT>else:<EOL><INDENT>stack = frames.copy()<EOL><DEDENT>stack_length = len(stack)<EOL>nb_frames = (<EOL>stack_length - self.blocksize + self.stepsize) // self.stepsize<EOL>nb_frames = max(nb_frames, <NUM_LIT:0>)<EOL>frames_length = nb_frames * self.stepsize +self.blocksize - self.stepsize<EOL>last_block_size = stack_length - frames_length<EOL>if eod:<EOL><INDENT>pad_shape = tuple(<EOL>self.blocksize - last_block_size if i == <NUM_LIT:0> else x<EOL>for i, x in enumerate(frames.shape))<EOL>stack = np.concatenate([stack, np.zeros(pad_shape,<EOL>dtype=frames.dtype)])<EOL>nb_frames += <NUM_LIT:1><EOL><DEDENT>self.buffer = stack[nb_frames * self.stepsize:]<EOL>eod_list = np.repeat(False, nb_frames)<EOL>if eod and len(eod_list):<EOL><INDENT>eod_list[-<NUM_LIT:1>] = eod<EOL><DEDENT>for index, eod in zip(xrange(<NUM_LIT:0>, nb_frames * self.stepsize, self.stepsize), eod_list):<EOL><INDENT>yield (stack[index:index + self.blocksize], eod)<EOL><DEDENT><DEDENT><DEDENT>aubio_analyzers = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>@functools.wraps(process_func)<EOL>def wrapper(analyzer, frames, eod):<EOL><INDENT>if not hasattr(analyzer, '<STR_LIT>'):<EOL><INDENT>if analyzer.id() in aubio_analyzers:<EOL><INDENT>analyzer.frames_buffer = framesBuffer(analyzer.input_stepsize,<EOL>analyzer.input_stepsize)<EOL><DEDENT>else:<EOL><INDENT>analyzer.frames_buffer = framesBuffer(analyzer.input_blocksize,<EOL>analyzer.input_stepsize)<EOL><DEDENT><DEDENT>for adapted_frames, adapted_eod in analyzer.frames_buffer.frames(frames, eod):<EOL><INDENT>process_func(analyzer, adapted_frames, adapted_eod)<EOL><DEDENT>return frames, eod<EOL><DEDENT>return wrapper<EOL>
Pre-processing decorator that adapt frames to match input_blocksize and
input_stepsize of the decorated analyzer

>>> from timeside.core.preprocessors import frames_adapter
>>> @frames_adapter
... def process(analyzer,frames,eod):
...     analyzer.frames.append(frames)
...     return frames, eod
>>> class Fake_Analyzer(object):
...     def __init__(self):
...         self.input_blocksize = 4
...         self.input_stepsize = 3
...         self.frames = [] # Container for the frame as viewed by process
...     @staticmethod
...     def id():
...         return 'fake_analyzer'
>>> import numpy as np
>>> analyzer = Fake_Analyzer()
>>> frames = np.asarray(range(0,12))
>>> eod = False
>>> frames_, eod_ = process(analyzer,frames,eod)

Inside the process the frames have been adapted to match input_blocksize
and input_stepsize

>>> analyzer.frames
[array([0, 1, 2, 3]), array([3, 4, 5, 6]), array([6, 7, 8, 9])]

Outside the process, the original frames and eod are preserved:

>>> frames_
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
>>> eod_
False

Releasing the process with eod=True will zeropad the last frame if necessary

>>> frames = np.asarray(range(12,14))
>>> eod = True
>>> frames_, eod_ = process(analyzer,frames,eod)
>>> analyzer.frames
[array([0, 1, 2, 3]), array([3, 4, 5, 6]), array([6, 7, 8, 9]), array([ 9, 10, 11, 12]), array([12, 13,  0,  0])]