def linear_envelope(start_amp, end_amp, width): ''' Generate an envelope, which spans some line. Args: start_amp - starting amplitude of envelope end_amp - ending amplitude of envelope width - floating point #/chunks wide that the envelope is Yields: A numpy array representing a linear envelope. ''' #FIXME: width should be a note duration, not a multiple of chunk size #FIXME: need a way to end attack early to start release, for short notes chunk_size = oscil.get_chunk_size() last_amp = start_amp slope = (end_amp - start_amp) / width for pos in it.count(chunk_size, chunk_size): amp = slope * pos samples = np.linspace(last_amp, amp, chunk_size, False) if pos > width: overlap = slice(width - pos, None) samples[overlap] = 1 yield samples raise StopIteration yield samples last_amp = amp
def multiply(*args, **kwargs): '''Produces a wave that is the product of all supplied waves. Args: *args - see _do_op() **kwargs - see _do_op() Returns: Wave chunk yielded by _do_op() operation. ''' fill = np.ones(oscil.get_chunk_size()) return _do_op(functools.partial(np.prod, axis=0), "multiply", fill, *args, **kwargs)
def add(*args, **kwargs): '''Produces a wave that is the sum of all supplied waves. Args: *args - see _do_op() **kwargs - see _do_op() Returns: Wave chunk yielded by _do_op() operation. ''' fill = np.zeros(oscil.get_chunk_size()) return _do_op(functools.partial(np.sum, axis=0), "add", fill, *args, **kwargs)
def filter(wave, taps): '''This FIR filter *appproximation* is of too poor quality to be of use. ''' highpass = 0 if taps < 0: taps = -taps highpass = 1 buff = np.zeros(taps) num_samples = oscil.get_chunk_size() moving_averages = np.zeros(num_samples) i = j = 0 for chunk in wave: moving_averages = np.convolve(chunk, np.ones((taps,))/taps)[(taps-1):] # apply "filter" if (highpass): chunk -= moving_averages else: chunk = moving_averages yield chunk
def echo(timer, wave, vol, delay): '''Apply an echo to a wave. Args: timer - used to calculate the delay wave - numpy array of base wave, which will be echoed vol - volume of echo [0,1] the volume of the wave will be reduced to (1 - vol) delay - delay of echo, in units of whole note duration Yields: Numpy array of original wave with echo applied. ''' limits.validate.vol(vol) width = timer.samples_per_note(1) * delay chunk_size = oscil.get_chunk_size() num_chunks = ceil(width / chunk_size) buff = deque([np.zeros(chunk_size) for _ in range(num_chunks)]) for chunk in wave: buff.append(chunk) yield chunk*(1-vol) + buff.popleft()*vol