def copy_elements(elements): """Returns a deep copy of a list of elements""" new_elements = [] for e in elements: if isinstance(e, Gain): new_elements.append(Gain()) elif isinstance(e, UnitDelay): new_elements.append(UnitDelay()) elif isinstance(e, Delay): new_elements.append(Delay(e.length)) elif isinstance(e, Split): chains = [] for chain in e.elements: chains.append(copy_elements(chain)) new_elements.append(Split(chains)) elif isinstance(e, Feedback): fb_elements = copy_elements(e.elements) new_elements.append(Feedback(fb_elements)) return new_elements
""" Benchmark test for the speed of the parameter estimation iteration function """ import os,sys sys.path.append(os.path.abspath('crossroads_scripts')) from param_estimation import get_error_for_model, get_error_for_model_vst from gen_faust import Model, Split, Gain, UnitDelay import numpy as np import time # Test model model = Model() model.elements.append(Split([[Gain(), Gain()], [UnitDelay(), Gain()], [Gain(0.2)]])) name = 'test' # Constants plugin = 'bench' orig_file = 'audio_files/drums.wav' out_file = 'audio_files/bench.wav' N = 50 params, bounds = model.get_params() # Time loop tick = time.time() for _ in range(N): err = get_error_for_model(params, model, plugin, orig_file, out_file, 'audio_files/drums.wav') time = time.time() - tick time_per_iter = time / N
"""Test if the parent models can evolve into the target model""" for _ in range(iters): models = test_generation(model1, model2, num) if any(m == target_model for m in models): return print('Unable to evolve correct structure!') exit(1) print('Test basic') model1 = Model() model1.elements.append(Gain()) model2 = Model() model2.elements.append(UnitDelay()) target = Model() target.elements.append(Gain()) test_success(model1, model2, target) print('Test Comb Filter') model1 = Model() model1.elements.append(Split([[], [Delay(4), Gain()]])) model1.elements.append(Gain()) model2 = Model() model2.elements.append(Split([[], [Delay(5), Gain()]])) target = Model() target.elements.append(Split([[], [Delay(5), Gain()]])) target.elements.append(Gain())
def get_evolved_structure(plugin, dry_file, wet_file, des_file, tol=1e-5): """ Evolve a structure for an audio effect that processes the dry audio to sound like the desired audio """ N_pop = 4 N_gens = 10 N_survive = 3 res = os.system('mkdir {}'.format(plugin)) if (res > 0): exit(res) # create initial model parents models = [] model1 = Model() model1.elements.append(Gain()) models.append(model1) model2 = Model() model2.elements.append(UnitDelay()) models.append(model2) model3 = Model() model3.elements.append(Split([[Gain()], [UnitDelay(), Gain()]])) models.append(model3) # create initial generation models = create_generation(models, N_pop, N_survive) gen_num = 0 converge = False elapsed = time.time() while gen_num < N_gens: # test current generation print('Testing generation: {}'.format(gen_num)) for n in range(N_pop): print(models[n]) pool = mp.Pool(mp.cpu_count()) results = pool.starmap( compute_model_fitness, [(models[n], plugin + f'_{n}', dry_file, wet_file[:-4] + f'_{n}' + wet_file[-4:], des_file, tol) for n in range(N_pop)]) pool.close() errors = np.zeros(N_pop) models = [] for n in range(N_pop): errors[n] = results[n][0] models.append(results[n][1]) # sort aridxs = np.argsort(errors) errors = errors[aridxs] models = [models[i] for i in aridxs] # reorganize to prefer smaller structures n_perfect = 0 for n in range(N_survive): if errors[n] < 5.0e-07: n_perfect += 1 if n_perfect > 1: n_params = [] for n in range(n_perfect): params, _ = models[n].get_params() n_params.append(len(params)) aridxs = np.argsort(n_params) errors[:n_perfect] = errors[:n_perfect][aridxs] models[:n_perfect] = [models[:n_perfect][i] for i in aridxs] # save surviving faust files and plugins for later analysis for n in range(N_survive): models[n].write_to_file(plugin + '.dsp') compile_plugin(plugin) os.system('cp -R faust_plugins/{} {}/gen{}_{}'.format( plugin, plugin, gen_num, n)) os.system('cp faust_scripts/{}.dsp {}/gen{}_{}/'.format( plugin, plugin, gen_num, n)) # Take survivors errors = errors[:N_survive] models = models[:N_survive] print('Surviving errors: {}'.format(errors)) # check for correct answer if errors[0] <= tol: converge = True break # mutate off survivors if N_pop < 24: N_pop += 4 create_generation(models, N_pop, N_survive) gen_num += 1 if converge: print('Converged!') else: print('Not Converged') print('Best error: {}'.format(errors[0])) print('Time elapsed: {}'.format(time.time() - elapsed)) # Save final faust script and plugin models[0].write_to_file(plugin + '.dsp') compile_plugin(plugin) test_plugin(plugin, dry_file, wet_file) os.system('cp -R faust_plugins/{} {}/gen_final'.format(plugin, plugin)) os.system('cp faust_scripts/{}.dsp {}/gen_final/'.format(plugin, plugin)) return models[0]
def get_mutated_model(parent1, parent2): """Create a new model by mutating existing models""" strategy = random.choice( mutation_strategies ) # choose strategy randomly (eventually maybe use weighting?) new_model = Model() print('Mutating with strategy: ' + strategy) if strategy == 'concat_series': # create new model with parent1 in series with parent2 if bool(random.getrandbits(1)): new_model.elements = copy_elements( parent1.elements) + copy_elements(parent2.elements) else: new_model.elements = copy_elements( parent2.elements) + copy_elements(parent1.elements) elif strategy == 'concat_parallel': # create new model with parent1 in parallel with parent2 new_model.elements.append( Split([ copy_elements(parent1.elements), copy_elements(parent2.elements) ])) # create new model by adding new element to random location in parent elif strategy == 'add_gain': parent_to_add = random.choice([parent1, parent2]) new_model.elements = copy_elements(parent_to_add.elements) add_element(new_model, Gain()) elif strategy == 'add_delay': parent_to_add = random.choice([parent1, parent2]) new_model.elements = copy_elements(parent_to_add.elements) add_element(new_model, UnitDelay()) elif strategy == 'add_nl': parent_to_add = random.choice([parent1, parent2]) new_model.elements = copy_elements(parent_to_add.elements) add_element(new_model, CubicNL()) elif strategy == 'add_split': parent_to_add = random.choice([parent1, parent2]) new_model.elements = copy_elements(parent_to_add.elements) add_element(new_model, Split([[Gain()], [UnitDelay(), Gain()]])) elif strategy == 'add_chain': # add new chain to existing parallel structure in parent parent_to_add = random.choice([parent1, parent2]) new_model.elements = copy_elements(parent_to_add.elements) split_idxs = [] for i, e in enumerate(new_model.elements): if isinstance(e, Split): split_idxs.append(i) if split_idxs == []: print('No Splits to add to! Mutating again...') return get_mutated_model(parent1, parent2) split_idx = random.choice(split_idxs) new_model.elements[split_idx].elements.append([UnitDelay(), Gain()]) else: print('Warning: unknown mutation strategy selected') new_model.elements.append(UnitDelay()) new_model.trim_model() # trim unnecessary or repetetive elements of model return new_model
modelTP = Model() fb = FB2() fb.pole_mag = pole_mag fb.pole_angle = pole_angle modelTP.elements.append(fb) add_to_tests(modelTP, 'Two-pole-test', yTP, ys, names, models) # Lowpass filter b, a = adsp.design_LPF2(1000, 0.7071, fs) yLPF = np.zeros(np.shape(x)) yLPF[:, 0] = signal.lfilter(b, a, x[:, 0]) yLPF[:, 1] = signal.lfilter(b, a, x[:, 1]) modelLPF = Model('DF2_Test') modelLPF.elements.append( Feedback([Split([[Gain(a[1])], [UnitDelay(), Gain(a[2])]]), Gain(-1.0)])) modelLPF.elements.append( Split([[Gain(b[0])], [UnitDelay(), Gain(b[1])], [UnitDelay(), UnitDelay(), Gain(b[2])]])) add_to_tests(modelLPF, 'test_DF2', yLPF, ys, names, models) for n in range(len(models)): print(f'Generating Faust for: {names[n]}') print(models[n]) # Write to file and compile models[n].write_to_file(f'{names[n]}.dsp') compile_plugin(f'{names[n]}') # Test
y2 = 0.5 * (x + del_sig * mix) model2 = Model() model2.elements.append(Split([[], [Delay(5), Gain(0.9)]])) model2.elements.append(Gain(-0.1)) add_to_tests(model2, 'delay', y2, ys, names, models) # 4th-order FIR filter b = [0.3, -0.4, 0.12, 0.2, -0.75] y3 = np.zeros(np.shape(x)) y3[:, 0] = signal.lfilter(b, [1], x[:, 0]) y3[:, 1] = signal.lfilter(b, [1], x[:, 1]) model3 = Model() model3.elements.append( Split([[Gain()], [UnitDelay(), Gain()], [Delay(2), Gain()], [Delay(3), Gain()], [Delay(4), Gain()]])) add_to_tests(model3, 'FIR filter', y3, ys, names, models) # One-pole filter fb_gain = -0.2 y4 = np.zeros(np.shape(x)) y4[:, 0] = signal.lfilter([1], [1, -fb_gain], x[:, 0]) y4[:, 1] = signal.lfilter([1], [1, -fb_gain], x[:, 1]) model4 = Model() model4.elements.append(Feedback([Gain()])) add_to_tests(model4, 'One-pole', y4, ys, names, models) # Soft-clip distortion in_gain = 2.0