Source code for GenerIter.process

"""
Abstract base class for all Process-based generator algorithms.

Copyright 2020 Thomas Jackson Park & Jeremy Pavier

"""
import os
import math
import random
from pydub import AudioSegment
from GenerIter.selector import Selector
from GenerIter.source import WavSource
from GenerIter.util import debug, jStr, mkdir_p

[docs]class Process(): """This is the abstract base class from which all other processors are derived. As such it implements the core interface as well as several important generic helper services which can simplify the derived algorithm implementations. """ # Currently only WAV is supported, but this list is expected to grow SUPPORTED_FORMATS = ["wav"] TSHIRT = { "s" : 180, "m" : 300, "l" : 480, "xl" : 780, "xxl" : 1260, "xxxl" : 2640 } def __init__(self, prefix=None): self._config = None self._inventory = None self._destination = None self._format = "wav" self._content = [] self._prefix = prefix self._tsize = "m" debug('Process()')
[docs] def configure(self, inventory, configuration, destination, forrmat, tsize): self._config = configuration self._inventory = inventory self._destination = destination self._format = forrmat self._tsize = tsize
[docs] def default(self): debug('No-op default processing logic') debug(type(self))
[docs] def declick(self, segment, value=10): """This is a helper function with which a fade/rise can be applied to each end of an AudioSegment to reduce the potential for 'clicking' when they are connected end-to-end. Can also be used, with longer fade times, if large track fades are required. Args: value (int) : number of milliseconds across which the segment will be faded from full gain to zero (typically 10 seems to work well). Returns: AudioSegment """ segment = segment.fade_in(value) segment = segment.fade_out(value) return segment
[docs] def deamplify(self, segment, limits): diminish = random.randrange(limits[0], limits[1]) segment = segment - diminish return segment
[docs] def getsegment(self, sample, limits, fade): retval = AudioSegment.from_wav(sample) retval = self.deamplify(retval, limits) retval = self.declick(retval, fade) return retval
[docs] def getsegmentm(self, sample, muted, fade): retval = AudioSegment.from_wav(sample) if muted > 0: retval = retval - muted if fade > 0: retval = self.declick(retval, fade) return retval
[docs] def intwidth(self, value): retval = 1 + int(math.log10(value)) return retval
[docs] def supported(self, value): return value in self.SUPPORTED_FORMATS
[docs] def threshold(self): if self._tsize in self.TSHIRT: target = self.TSHIRT[self._tsize] else: target = self.TSHIRT["m"] lbnd = (9 * target) // 10 ubnd = (11 * target) // 10 retval = random.randrange(lbnd, ubnd) return retval
[docs] def padtolength(self, segment, length, fader, front=False): quiet = length - len(segment) if quiet <= 0: retval = segment[:length] retval = self.declick(retval, fader) else: pad = AudioSegment.silent(duration=quiet, frame_rate=segment.frame_rate) if front is False: retval = segment + pad else: retval = pad + segment return retval
[docs] def bracket(self, segment, frontmult=1.0, backmult=1.0): frunt = random.randrange(int(frontmult * len(segment))) bak = random.randrange(int(backmult * len(segment))) front = AudioSegment.silent(duration=frunt, frame_rate=segment.frame_rate) back = AudioSegment.silent(duration=bak, frame_rate=segment.frame_rate) retval = front + segment + back return retval
[docs] def write(self, algorithm, counter, source): # How many times do you want this to run? iterations = int(self._config["tracks"]) # Need to be able to pad the correct number of zeroes digits = self.intwidth(iterations) # What's the base root name of the outputs? base = type(self).__name__ # Set the correct sub directory and ensure it exists destdir = os.path.join(self._destination, base) mkdir_p(destdir) # Zero pad the counter string ctr = str(counter).zfill(digits) track = f"{base}_{algorithm}_{ctr}" debug(f"Track: {track}") # Create the output file name with zero padded counter value if self.supported(self._format) is True: filename = "{0}.{1}".format(track, self._format) # Set up the output path dest = os.path.join(destdir, filename) print(f"\t{dest}") # Write it out source.export(dest, format=self._format) src = WavSource(dpath=dest, dexist=True) self._inventory.insert(src) else: print("Unsupported output format : {0}".format(self._format))