def multitrack(self): # How many times do you want this to run? iterations = int(self._config["tracks"]) voices = self._config["voices"] nvoices = len(voices) if nvoices < 2: raise robox.GIParameterErr( "Insufficient voices specified for the multitrack algorithm") mute = 1.5 * nextPowerOf2(nvoices) for ctr in range(iterations): audios = [] # Randomly select our samples for voice in voices: sample = self._inventory.selectRandom(voice) audio = AudioSegment.from_wav(sample) audio = audio.normalize() audio = audio - mute audios.append(audio) summation = audios[0] for nctr in range(nvoices - 1): summation = summation.overlay(audios[nctr + 1], loop=True) summation = summation.normalize() fname = inspect.currentframe().f_code.co_name self.write(algorithm=fname, counter=ctr, source=summation)
def path(self, value): """Sets value of full path. Also derives various component features from the path """ if value is None: raise robox.GIParameterErr("No path given on Source class path setting accessor.") self._path = value self._fname = os.path.basename(self._path) self._dname = os.path.basename(os.path.dirname(self._path)) self._root, self._ext = os.path.splitext(self._fname)
def voices(self): """ This developmental prototype algorithm uses the same algorithm as voices3, but allows the user to designate the 3 or more voices to be used in the compose file. Warning: This is example code used during early development, and should really only be used for reference and study. """ # These could be parameterised in the config declick = 10 vol_range = (14, 22) # How many times do you want this to run? iterations = int(self._config["tracks"]) # Track repeats repeats = int(self._config["repeats"]) voices = self._config["voices"] nvoices = len(voices) if nvoices < 3: raise robox.GIParameterErr( "Insufficient voices specified for the 'voices' algorithm") for ctr in range(iterations): audios = [] # Randomly select our samples for voice in voices: sample = self._inventory.selectRandom(voice) audio = self.getsegment(sample, vol_range, declick) audios.append(audio) summation = audios[0] for nctr in range(nvoices - 2): summation = summation.overlay(audios[nctr + 1]) composite = summation + summation + summation + summation final_overlay = composite.overlay(audios[nvoices - 1]) for ctr2 in range(repeats): final_overlay = final_overlay + final_overlay fname = inspect.currentframe().f_code.co_name self.write(algorithm=fname, counter=ctr, source=final_overlay)
def voices_shifted(self): """ This algorithm uses the same algorithm as voices, but implements a sequential shift as each new voice is incorporated. Warning: This is example code used during early development, and should really only be used for reference and study. """ # These could be parameterised in the config declick = 10 vol_range = (14, 22) # How many times do you want this to run? iterations = int(self._config["tracks"]) # Track repeats repeats = int(self._config["repeats"]) voices = self._config["voices"] nvoices = len(voices) if nvoices < 3: raise robox.GIParameterErr( "Insufficient voices specified for the 'voices' algorithm") for ctr in range(iterations): audios = [] # Randomly select our samples for voice in voices: sample = self._inventory.selectRandom(voice) audio = self.getsegment(sample, vol_range, declick) audios.append(audio) summation = audios[0] for nctr in range(nvoices - 1): summation = summation.overlay(audios[nctr + 1]) summation = summation + summation for ctr2 in range(repeats): summation = summation + summation fname = inspect.currentframe().f_code.co_name self.write(algorithm=fname, counter=ctr, source=summation)
def voices_shifted(self): """ This algorithm uses the same algorith as voices3, but allows the user to designate the 3 or more voices to be used in the compose file.""" # These could be parameterised in the config declick = 10 vol_range = (14, 22) # How many times do you want this to run? iterations = int(self._config["tracks"]) # Track repeats repeats = int(self._config["repeats"]) voices = self._config["voices"] nvoices = len(voices) if nvoices < 3: raise robox.GIParameterErr( "Insufficient voices specified for the 'voices' algorithm") for ctr in range(iterations): audios = [] # Randomly select our samples for voice in voices: sample = self._inventory.selectRandom(voice) audio = self.getsegment(sample, vol_range, declick) audios.append(audio) summation = audios[0] for nctr in range(nvoices - 1): summation = summation.overlay(audios[nctr + 1]) summation = summation + summation for ctr2 in range(repeats): summation = summation + summation fname = inspect.currentframe().f_code.co_name self.write(algorithm=fname, counter=ctr, source=summation)
def groove(self): """The `Basic.groove` algorithm is used to form a rhythmic backbone to a composition. This algorithm attempts to make sensible alignment choices for the samples in use. It is considered a *production* algorithm. .. image:: images/Basic.groove.jpg The number of voices can be 3 or more. In this example we are using 4, which we can think of as **A**, **B**, **C** and **D** corresponding to their declaration position in the configuration list. Segments **A** and **B** are randomly selected from their inventory categories. These are then length-aligned. That is, whichever is the shorter of the two is padded with exactly the right amount of silence to make the frame lengths of both segments equal. These are then overlayed to form a composite rhythmic unit referred to as **AB**. The basic rhythmic beat is created by replicating a sequence of these **AB** segments end-to-end until the track size limit is surpassed. This is the `groove_base`. The `cycle` parameter specifies the number of these **AB** components tahe represent a higher level repetition unit called the `cycle` (obviously). Subsequent voices are also length-aligned (or curtailed) to match the size of the **AB** unit. A new segment, `groove_layer` is created, into which the later voices **C**, **D**, etc. are injected in a cyclic sequence, aligned precisely to the `groove_base` cycles and beats. Finally, the `groove_base` is overlayed with the `groove_layer` to create a composite whole track which is output as an audio file. Parameters: tracks (int) : number of times the process is to run. voices (list) : list of voice categories to select and use in the track cycle (int) : length of a repeat cycle in terms of groove_base *beats* Example: .. code:: json { "Basic" : { "groove" : { "tracks" : 50, "cycle" : 4, "voices" : [ "Bass", "Beat", "Percussion", "Pad" ] } } } Raises: GenerIter.excepts.GIParameterErr """ declick = 10 # How many times do you want this to run? iterations = int(self._config["tracks"]) voices = self._config["voices"] nvoices = len(voices) cycle = self._config["cycle"] if nvoices < 3: raise robox.GIParameterErr( "Insufficient voices specified for the groove algorithm") # Need to keep all overlays below the clipping threshold mute = 6.0 * nextPowerOf2(nvoices) for ctr in range(iterations): audios = [] maxlen = 0 # Set a soft threshold for the size of the piece size_limit = self.threshold() # Randomly select our samples for voice in voices: sample = self._inventory.selectRandom(voice) audio = self.getsegmentm(sample, mute, declick) audios.append(audio) for aud in range(2): if len(audios[aud]) > maxlen: maxlen = len(audios[aud]) for aud in range(2, nvoices): audios[aud] = self.padtolength(audios[aud], maxlen, declick) # Create the groove's rhythmic base layer rhythm = audios[0].overlay(audios[1]) rlen = len(rhythm) groove_base = rhythm print("{0} < {1}".format(str(groove_base.duration_seconds), str(size_limit))) while groove_base.duration_seconds < size_limit: #groove_base = groove_base + rhythm groove_base = groove_base + rhythm # Create a blank segment of same size and frame rate groove_layer = AudioSegment.silent( duration=len(groove_base), frame_rate=groove_base.frame_rate) for ctr2 in range(2, nvoices): compound = AudioSegment.silent( duration=cycle * len(rhythm), frame_rate=groove_layer.frame_rate) offset = ((ctr2 - 2) % cycle) * rlen compound = compound.overlay(audios[ctr2], position=offset) groove_layer = groove_layer.overlay(compound, loop=True) summation = groove_base.overlay(groove_layer) fname = inspect.currentframe().f_code.co_name self.write(algorithm=fname, counter=ctr, source=summation)