from Queue import PriorityQueue, Queue, Full import numpy as np from dspy.generator import Generator from dspy.lib import rechannel, t2f class Player(Generator): def __init__(self, sequence=[], channels=2, live=True, loop=False, clip=True, max_size=0): Generator.__init__(self) self.max_size = max_size self._generators = PriorityQueue(max_size) self._finished = Queue() self._gain = 0.1 self._live = live self._length_cache = max([f+g.length() for (f, g) in sequence] + [0]) self.loop = loop self.clip = clip self.num_channels = channels self.num_gens = 0 if sequence: for (f, g) in sequence: self._append_gen(f, g) if live: assert(not loop) self.auto_reset = loop def _append_gen(self, frame, gen): try: self._generators.put((t2f(frame), gen), False) except Full: print('Too many generators to append another') return def add(self, gen, time=None): if time is None: frame = self.frame else: frame = t2f(time) self._length_cache = max(self._length_cache, gen.length() + frame) if self.num_gens < self.max_size or self.max_size == 0: self.num_gens += 1 self._append_gen(frame, gen) def _reset(self): if self._live: raise Exception('Cannot reset if Player is live') sequence = [] while not self._finished.empty(): frame, gen = self._finished.get() gen.reset() sequence.append((frame, gen)) while not self._generators.empty(): frame, gen = self._generators.get() gen.reset() sequence.append((frame, gen)) for frame, gen in sequence: self._append_gen(frame, gen) def _length(self): if self._live: return float('inf') return self._length_cache @property def gain(self): return self._gain @gain.setter def gain(self, value): self._gain = np.clip(value, 0, 1) def _generate(self, frame_count): output = np.zeros(frame_count * self.num_channels, dtype=np.float32) not_done = [] while not self._generators.empty(): frame, gen = self._generators.get() if frame > self.frame + frame_count: not_done.append((frame, gen)) break delay = 0 if frame > self.frame: delay = frame - self.frame signal, continue_flag = gen.generate(frame_count - delay) signal = rechannel(signal, gen.num_channels, self.num_channels) output[delay * self.num_channels:] += signal if continue_flag: not_done.append((frame, gen)) else: if not self._live: self._finished.put((frame, gen)) self.num_gens -= 1 for frame, gen in not_done: self._append_gen(frame, gen) output *= self.gain if self.clip: output = np.clip(output, -1, 1) return output