#!/usr/bin/env python # # pmix.py # # select random length chunks from random files # from all pool directories # ### FIXME: eliminate multiple eci instances by clearing chains between operations # just add cs-remove after each cs-disconnect when i/o's will change # make a helper function to do this # ai-remove # ao-remove # cs-remove # set things up properly after creating e # cs-add foo # c-add foo # cs-set-audio-format # check for errors after cs-connect # make repeated operations into reusable functions # get-length # fade in/out # normalize # make a library of such functions # for use in scripts like this import glob import random import pyeca import time import os pmix_pool = "/mnt/audio/pool/" tmp_dir = "/mnt/audio/in_progress/pmix/listen/" date = time.strftime("%Y-%m%d-%H%M",time.localtime()) pmix_out = tmp_dir + date + "pmix.wav" chunk_length_min = 2 pool_list = glob.glob(pmix_pool+'*/*.wav') ### randomly set total processing time random.seed() session_length = random.uniform(60,420) print "session length: %s" % ( session_length ) ### randomly select random number of audio chunks loop_count = random.randint(2,9) print loop_count i = 0 while i < loop_count: loop = tmp_dir + "loop" + str(i) loop_file = loop + ".wav" loop_ewf = loop + ".ewf" print print loop_file random_file = random.choice(pool_list) print "random file: %s" % ( random_file ) ### select random chunk from random file # get length of random file e = pyeca.ECA_CONTROL_INTERFACE(0) e.command("ai-add " + random_file) tmp_out = tmp_dir + "foo.wav" e.command("-f:24,1,48000 -o:" + tmp_out) e.command("cs-connect") e.command("ai-iselect 1") e.command("ai-get-length") random_file_length = e.last_float() print "random file length: %s" % ( random_file_length ) e.command("cs-disconnect") # set length of chunk if random_file_length > session_length: chunk_length_max = session_length else: chunk_length_max = random_file_length print "max chunk length: %s" % ( chunk_length_max ) chunk_length = random.uniform(chunk_length_min,chunk_length_max) print "chunk length: %s" % ( chunk_length ) # set starting offset chunk_offset = (random_file_length - chunk_length) * random.random() print "chunk offset: %s" % ( chunk_offset ) # crop chunk e.command_float_arg("ai-setpos", chunk_offset) e.command_float_arg("cs-set-length", chunk_length) e.command("cs-connect") e.command("start") while 1: time.sleep(1) e.command("engine-status") if e.last_string() != "running": break e.command("cs-disconnect") # get actual length of chunk file e2 = pyeca.ECA_CONTROL_INTERFACE(0) e2.command("ai-add " + tmp_out) e2.command("-f:24,1,48000 -o:" + loop_file) e2.command("cs-connect") e2.command("ai-iselect 1") e2.command("ai-get-length") actual_chunk_length = e2.last_float() print "actual chunk length: %s" % ( actual_chunk_length ) e2.command("cs-disconnect") # time stretch/compress chunk if int(random.random()*2) == 1: # pitch_shift_percent >= 100 i.e. time_compress such that # final_chunk_length >= chunk_length_min max_compress_x = ( actual_chunk_length / chunk_length_min ) shift_percent = random.uniform(1,max_compress_x) * 100 print "max compress multiple: %s, shift %%: %s" % ( max_compress_x, shift_percent ) else: # pitch_shift_percent <= 100 i.e. time_stretch such that # final_chunk_length <= session_length max_stretch_x = ( session_length / actual_chunk_length ) shift_percent = 1 / (random.uniform(1,max_stretch_x)) * 100 print "max stretch multiple: %s, shift %%: %s" % ( max_stretch_x, shift_percent ) e2.command("cop-add -ei:" + str(shift_percent)) e2.command("cs-connect") e2.command("start") while 1: time.sleep(1) e2.command("engine-status") if e2.last_string() != "running": break e2.command("cs-disconnect") ### get length of time (stretched|compressed) chunk e3 = pyeca.ECA_CONTROL_INTERFACE(0) e3.command("ai-add " + loop_file) e3.command("-f:24,1,48000 -o:" + loop_file) e3.command("cs-connect") e3.command("ai-iselect 1") e3.command("ai-get-length") shifted_chunk_length = e3.last_float() print "shifted chunk length: %s" % ( shifted_chunk_length ) e3.command("cs-disconnect") # fade-in/out start/end of chunk e3.command("cop-add -ea:0") e3.command("ctrl-add -kl:1,0,100,1") e3.command("cop-add -ea:0") e3.command("ctrl-add -kl2:1,100,0," + str(shifted_chunk_length - 1.0 ) + ",1") e3.command("cop-add -ev") e3.command_float_arg("cs-set-length", shifted_chunk_length) e3.command("cs-connect") e3.command("start") while 1: time.sleep(1) e3.command("engine-status") if e3.last_string() != "running": break e3.command("cs-disconnect") # normalize chunk e3.command("cop-select 3") e3.command("copp-select 2") e3.command("copp-get"); amplify_percent = e3.last_float() * 99.8 print "amplify percent: %s%%" % ( amplify_percent ) e3.command("c-clear") e3.command("cop-add -ea:" + str(amplify_percent)) e3.command("setpos 0") e3.command("cs-connect") e3.command("start") while 1: time.sleep(1) e3.command("engine-status") if e3.last_string() != "running": break e3.command("cs-disconnect") ### FIXME: add routine to reverse chunk 1/4 of time # if int(random.random()*4) == 1: # write .ewf file for finished chunk output = open(loop_ewf,'w') lines = [] lines.append("source = " + loop_file + "\n") lines.append("offset = 0\n") lines.append("start-position = 0\n") lines.append("length = " + str(shifted_chunk_length) + "\n") lines.append("looping = true\n") output.writelines(lines) output.close() os.remove(tmp_out) i = i + 1 print print "session length: %s" % ( session_length ) print loop_count print ### create ecasound session # total processing time set to session_length # 8 inputs = 8 .ewf files # mixdown to stereo .wav ### Set up global chainsettup options ### add output file e4 = pyeca.ECA_CONTROL_INTERFACE() # set global buffer size smaller to get smoother oscillators e4.command("cs-set-param -b:64") e4.command("c-select default") e4.command("c-remove default") ### Loop to add each .ewf file as an input and set effects and effect controllers i = 0 while i < loop_count: loop = tmp_dir + "loop" + str(i) + ".ewf" print loop e4.command("c-add " + str(i) ) e4.command("ai-add " + loop) ### amplify controllers ea_max = loop_count*99.8 e4.command("cop-add -ea:100") # -kos:copp, min, max, Hz, phase ea_ctrl = "-kos:1,0," + str(ea_max) + "," + str(random.uniform(0,0.5)) + "," + str(random.uniform(0,1)) print ea_ctrl e4.command("ctrl-add " + ea_ctrl) e4.command("ctrl-selected") ea_ctrl_id = e4.last_integer() # vary ea_ctrl min if int(random.random()*2) == 1: e4.command("ctrl-select " + str(ea_ctrl_id) ) e4.command("ctrl-add -kx") ea_ctrl_2 = "-kos:2,0," + str(ea_max/2.1) + "," + str(random.uniform(0,0.01)) + "," + str(random.uniform(0,1)) print ea_ctrl_2 e4.command("ctrl-add " + ea_ctrl_2) # vary ea_ctrl max if int(random.random()*2) == 1: e4.command("ctrl-select " + str(ea_ctrl_id) ) e4.command("ctrl-add -kx") ea_ctrl_3 = "-kos:3," + str(ea_max/1.9) + "," + str(ea_max) + "," + str(random.uniform(0,0.01)) + "," + str(random.uniform(0,1)) print ea_ctrl_3 e4.command("ctrl-add " + ea_ctrl_3) # vary ea_ctrl Hz if int(random.random()*2) == 1: e4.command("ctrl-select " + str(ea_ctrl_id) ) e4.command("ctrl-add -kx") ea_ctrl_4 = "-kos:4,0," + str(random.uniform(0,9)) + "," + str(random.uniform(0,0.1)) + "," + str(random.uniform(0,1)) print ea_ctrl_4 e4.command("ctrl-add " + ea_ctrl_4) ### pan controllers e4.command("cop-add -erc:1,2") e4.command("cop-add -epp:0") # -kos:copp, min,max, Hz, phase epp_ctrl = "-kos:1,0,100," + str(random.uniform(0,0.25)) + "," + str(random.uniform(0,1)) print epp_ctrl e4.command("ctrl-add " + epp_ctrl) e4.command("ctrl-selected") epp_ctrl_id = e4.last_integer() # vary epp_ctrl min if int(random.random()*2) == 1: e4.command("ctrl-select " + str(epp_ctrl_id) ) e4.command("ctrl-add -kx") epp_ctrl_2 = "-kos:2,0,49," + str(random.uniform(0,0.01)) + "," + str(random.uniform(0,1)) print epp_ctrl_2 e4.command("ctrl-add " + epp_ctrl_2) # vary epp_ctrl max if int(random.random()*2) == 1: e4.command("ctrl-select " + str(epp_ctrl_id) ) e4.command("ctrl-add -kx") epp_ctrl_3 = "-kos:3,51,100," + str(random.uniform(0,0.01)) + "," + str(random.uniform(0,1)) print epp_ctrl_3 e4.command("ctrl-add " + epp_ctrl_3) # vary epp_ctrl Hz if int(random.random()*2) == 1: e4.command("ctrl-select " + str(epp_ctrl_id) ) e4.command("ctrl-add -kx") epp_ctrl_4 = "-kos:4,0," + str(random.uniform(0,2)) + "," + str(random.uniform(0,0.02)) + "," + str(random.uniform(0,1)) print epp_ctrl_4 e4.command("ctrl-add " + epp_ctrl_4) e4.command("ctrl-list") print "ctrl-list:" print e4.last_string_list() ### FIXME: add other effects??? i = i + 1 e4.command("cs") print "chain status:" print e4.last_string() # mixdown to stereo e4.command("c-select-all") e4.command("-f:24,2,48000 -o:" + pmix_out) print "pmix_out: %s" % ( pmix_out ) e4.command_float_arg("cs-set-length", session_length) e4.command("cs-connect") e4.command("start") while 1: time.sleep(1) e4.command("engine-status") if e4.last_string() != "running": break e4.command("cs-disconnect") e4.command("cs-remove") e4.command("st") print e4.last_string() ## ### get length of pmix e4.command("cs-add default") e4.command("c-add default") e4.command("ai-add " + pmix_out) e4.command("-f:24,2,48000 -o:" + pmix_out) e4.command("cs-connect") e4.command("ai-iselect 1") e4.command("ai-get-length") pmix_length = e4.last_float() print "pmix length: %s" % ( pmix_length ) e4.command("cs-disconnect") e4.command("st") print e4.last_string() ### shape overall dynamics ### FIXME: make this a function max_pos_count = int(pmix_length / 10.) pos_count = random.randint(1,max_pos_count) print "pos_count:" print pos_count pos_dict = [] i = 0 while i < pos_count: pos = random.uniform(0,pmix_length) pos_val = random.uniform(0,1) pos_dict.append((pos,pos_val)) i = i + 1 pos_dict.sort() # -klg: copp,min,max, point_count, 0_point,val, klg_str = "-klg:1,0,98," + str(pos_count+2) + ",0,0," j = 0 while j < pos_count: # j_point, val, klg_str = klg_str + str(pos_dict[j][0]) + "," + str(pos_dict[j][1]) + "," j = j + 1 # end_point, val klg_str = klg_str + str(pmix_length) + ",0" print print klg_str ### process klg e4.command("cop-add -ea:0") e4.command("ctrl-add " + klg_str) e4.command("cop-add -ev") e4.command("c-select-all") e4.command("cs-set-audio-format 24,2,48000") e4.command_float_arg("cs-set-length", pmix_length) e4.command("cs-connect") e4.command("start") while 1: time.sleep(1) e4.command("engine-status") if e4.last_string() != "running": break e4.command("cs-disconnect") ### normalize e4.command("cop-select 2") e4.command("copp-select 2") e4.command("copp-get"); amplify_percent = e4.last_float() * 98. print "amplify percent: %s%%" % ( amplify_percent ) e4.command("c-clear") e4.command("cop-add -ea:" + str(amplify_percent)) e4.command("c-select-all") e4.command("cs-set-audio-format 24,2,48000") e4.command("setpos 0") e4.command("cs-connect") e4.command("start") while 1: time.sleep(1) e4.command("engine-status") if e4.last_string() != "running": break e4.command("cs-disconnect") e4.command("cs-remove") ### cleanup for next run i=0 while i < loop_count: os.remove(tmp_dir + "loop" + str(i) + ".ewf") os.remove(tmp_dir + "loop" + str(i) + ".wav") i = i + 1