"""
Generator class for some Process-based soloing algorithms.
Copyright 2020 Thomas Jackson Park & Jeremy Pavier
"""
import os
import random
import inspect
from pydub import AudioSegment
from GenerIter.process import Process
from GenerIter.util import debug
import GenerIter.excepts as robox
[docs]class Solo(Process):
SOLOMAP = [
{
"upper" : 10000,
"variation" : (800, 2400),
"fades" : 100,
"back_silence" : 4000
},
{
"upper" : 60000,
"variation" : (8000, 24000),
"fades" : 3000,
"front_silence" : 20000,
"back_silence" : 40000
},
{
"upper" : 60000,
"variation" : (20000, 36000),
"fades" : 3000,
"front_silence" : 60000,
"back_silence" : 40000
},
{
"upper" : 10000,
"variation" : (200, 800),
"fades" : 10,
"front_silence" : 60000,
"back_silence" : 40000,
"reps" : (5, 30)
}
]
def __init__(self):
super().__init__()
debug('Solo()')
[docs] def generic(self):
VOL_UP = 14
VOL_DN = 18
# How many times do you want this to run?
iterations = int(self._config["tracks"])
voice = self._config["voice"]
for ctr in range(iterations):
# Grab some source material
sample = self._inventory.selectRandom(voice)
newAudio = AudioSegment.from_wav(sample)
alen = len(newAudio)
# Randomly select the parameters
params = random.choice(self.SOLOMAP)
# Are we trimming the input sample?
if alen > params["upper"]:
# Pick a random length
samplen = random.randrange(params["variation"][0], params["variation"][1])
# Define the range in which we can start the cut
sampst = alen - samplen
# Generate a start cut point in the defined range
t1 = random.randrange(sampst)
# Derive the endpoint of the cut
t2 = (t1 + samplen)
# Cut
newAudio = newAudio[t1:t2]
# Set a volume
newvol = random.randrange(VOL_UP, VOL_DN)
newAudio = newAudio - newvol
# Set fades as defined by the params
newAudio = self.declick(newAudio, params["fades"])
# Do we need to pad front and/or back with some silence?
if "front_silence" in params:
if "back_silence" in params:
fsil = random.randrange(params["front_silence"])
bsil = random.randrange(params["back_silence"])
front = AudioSegment.silent(duration=fsil)
back = AudioSegment.silent(duration=bsil)
newAudio = front + newAudio + back
else:
fsil = random.randrange(params["front_silence"])
front = AudioSegment.silent(duration=fsil)
newAudio = front + newAudio
else:
if "back_silence" in params:
bsil = random.randrange(params["back_silence"])
back = AudioSegment.silent(duration=bsil)
newAudio = newAudio + back
# Do we wish to build repeats of this sample?
if "reps" in params:
addAudio = newAudio
reps = random.randrange(params["reps"][0], params["reps"][1])
for sam in range(reps):
newAudio += addAudio
# Randomise front and back padding on the whole shebang
dic = random.randrange(10)
if dic == 7:
sil1 = random.randrange(90000)
sil2 = random.randrange(90000)
solofront = AudioSegment.silent(duration = sil1)
soloback = AudioSegment.silent(duration = sil2)
newAudio = solofront + newAudio + soloback
# Write it out
fname = inspect.currentframe().f_code.co_name
self.write(algorithm=fname, counter=ctr, source=newAudio)
[docs] def multivoice_serial_ordered(self):
"""
"""
declick = 10
# How many times do you want this to run?
iterations = int(self._config["tracks"])
voices = self._config["voices"]
nvoices = len(voices)
for ctr in range(iterations):
audios = []
# Set a soft threshold for the size of the piece
size_limit = self.threshold()
solo_base = AudioSegment.empty()
# Randomly select our samples
for voice in voices:
samp = self._inventory.selectRandom(voice)
audio = self.getsegmentm(sample=samp, muted=0, fade=0)
audios.append(audio)
ctr2 = 0
while solo_base.duration_seconds < size_limit:
solo_base = solo_base + self.bracket(audios[ctr2 % nvoices])
ctr2 += 1
# Write it out
fname = inspect.currentframe().f_code.co_name
self.write(algorithm=fname, counter=ctr, source=solo_base)