import argparse import random from sqlite3 import TimeFromTicks import time from pythonosc import udp_client #pip install python-osc import csv import numpy as np #pip install numpy ''' 0: t=0s bis t=20s keine ausgabe per osc 1: t=20s bis t=60s einmal die strophe triggern (also nachricht /3/oscplayer/strophe 1) "zufällig"(=basierend auf heartrate daten) zwischen t=20 und t=60 0: t=60s bis t=70s passiert nichts 2: t=70s bis t=120s nachricht /3/oscplayer/satz/<1-4> 1 . "zufällig" auf heartrate daten basierend triggern (muss nicht im beat sein), nicht zu häufig. ca alle 5-10s einmal 0: t=120s bis t=150s nichts, vorheriges hört auf 3: t=150s bis t=5*60s daten laufen pro zeile als 1/8 bei tempo 50 =0,6s/beat. schnelles durchalufen wie gehabt. mit zufälligen pausen ''' scenetimes=[0,10,60,70,130,150,155,210,220,290,500] #definition of times . Last value will be overwritten by last time of csv file #scenetimes=[0,2,4,5,6,10,300] #definition of times FASTER FOR TESTING scenes =[0,1, 0, 2, 0 ,3 , 0, 3 , 0, 3, -1] #definition of scenes. scene -1 will end the program currentScene=-1 #keeps track of current scene timemultiplier=1.0 #current time multiplier for speed changes topicScene=['','','',''] timemultiplierScene=[1,1,1,1] #only initializiation stropheTriggered=False valueCommulative=0 midiChannel=0 #Can be changed through args TODO: Monday header=None rows=None rowid=0 time_start=0 client=None lastvalue=[] minvalues=[] maxvalues=[] meanvalues=[] def init(): parser = argparse.ArgumentParser() parser.add_argument("--ip", default="127.0.0.1", help="The ip of the OSC server") parser.add_argument("--port", type=int, default=7005, help="The port the OSC server is listening on") parser.add_argument("--channel", type=int, default=None, help="The midi channel to use for osc topic. Default=Automatic") parser.add_argument("--file", type=str, default='heart_cluster_max.csv', help="The csv file used for data input") args = parser.parse_args() global client client = udp_client.SimpleUDPClient(args.ip, args.port) global midiChannel midiChannel=args.channel print("Using midi Channel "+str(midiChannel)) csvfilename=args.file print("Using csv file "+str(csvfilename)) ######### csvlist=None with open(csvfilename, newline='') as csvfile: csvreader = csv.reader(csvfile, delimiter=',', quotechar='|') csvlist = list(csvreader) '''for row in csvreader: if header is None: header=row else: rows.vstack(row) ''' global header header=csvlist[0] global rows rows=csvlist[1:] #discard first row/header rows = [x for x in rows if float(x[1])>40] #filter out rows with value <40 global rowid rowid=0 #waiting for this row to send global lastvalue lastvalue=np.zeros(len(rows)-1) global minvalues global maxvalues global meanvalues minvalues=[min([float(a) for a in x]) for x in filterEmpty(rows)] maxvalues=[max([float(a) for a in x]) for x in filterEmpty(rows)] meanvalues=[np.mean([float(a) for a in x]) for x in filterEmpty(rows)] if midiChannel is None: midiChannel=int(mapRangeConstrain(float(rows[0][1]),minvalues[1],maxvalues[1],1,16)) print("Using midi Channel "+str(midiChannel)) scenetimes[-1]=maxvalues[0] #take maximum value of first column (time) as endtime scenetimes[-2]=maxvalues[0]-20 print("Scenetimes:" + str(scenetimes)) print("minvalues="+str(minvalues)) print("maxvalues="+str(maxvalues)) print("meanvalues="+str(meanvalues)) # Initialize parameters for scenes #Scene 0 #Scene 1 topicScene[1]="/"+str(midiChannel)+"/oscplayer/strophe" stropheTriggered=False #keep track if it is already triggered once #Scene 2 topicScene[2]="/"+str(midiChannel)+"/oscplayer/satz/?" valueCommulative=0 #Scene 3 topicScene[3]="/"+str(midiChannel)+"/oscplayer/value/?" timemultiplierScene[3]=60.0 / 50 / 2 #print(np.mean(np.array((filterEmpty(rows))),axis=1)) #TODO: mittelwert ausrechnen funktioniert noch nicht #exit() #meanvalues=[float(np.mean(x)) for x in filterEmpty(rows)] global time_start time_start = time.time() def getSceneFromTime(t): i=0 while i=scenetimes[i]: i+=1 return scenes[i-1] def update(ctime): global minvalues global maxvalues global meanvalues global rowid global client global lastvalue global timemultiplier global currentScene global stropheTriggered global valueCommulative timeFromStart=ctime-time_start if currentScene!=getSceneFromTime(timeFromStart): #When scene changed currentScene=getSceneFromTime(timeFromStart) timemultiplier=timemultiplierScene[currentScene] #update speed _rowidBefore=rowid rowid=0 while timeFromStart>=(float(rows[rowid%len(rows)][0])+float(rows[len(rows)-1][0])*int(rowid/len(rows)))*timemultiplier: #fast forward rowid rowid+=1 '''if rowid>=len(rows): #ended? rowid=0''' rowid-=1 if _rowidBefore!=rowid: print("Updated Row Id from "+str(_rowidBefore)+" to "+str(rowid)+" of "+str(len(rows))) print("t="+str(timeFromStart)+"s: Changed Scene to "+str(currentScene)+". timemultiplier="+str(timemultiplier)) # Below here things that should happen once on scene change to "currentScene" if currentScene==3: #on scene change to 3 sendOSCTrigger("/sprachsamples/beatrepeatonoff") if currentScene==-1: #ended sendOSCTrigger("/stopcommand") sendOSCTrigger("/sprachsamples/beatrepeatonoff") '''if rowid>=len(rows): #ended? rowid=0 #when finished csv start from beginning #return False ''' if timeFromStart>=(float(rows[rowid%len(rows)][0])+float(rows[len(rows)-1][0])*int(rowid/len(rows)))*timemultiplier: #print(rows[rowid]) crow=rows[rowid%len(rows)] for i in range(len(header)-1): if len(crow[i+1])>0: #value not empty value=float(crow[i+1]) if (i==0): #were only using the first column of the csv file #Below here things that should happen when in "currentScene" every time new data from the csv file is read if currentScene==1: if not stropheTriggered: _threshold=(minvalues[i+1]+(maxvalues[i+1]-minvalues[i+1])*0.2) print("waiting for "+str(value)+"<"+str(_threshold)) if value<_threshold or getSceneFromTime(timeFromStart+1)!=currentScene: #trigger "randomly" or when scene is about to change sendOSCTrigger(topicScene[currentScene]) stropheTriggered=True if currentScene==2: print("waiting. diff="+str(abs(maxvalues[i+1]-value))+" commulative="+str(valueCommulative)) #valueCommulative+=abs(maxvalues[i+1]-value) valueCommulative+=mapRangeConstrain(value,minvalues[i+1],maxvalues[i+1],0,100) if valueCommulative>500: #higher value triggers less valueCommulative-=500 #reset sendvalue=int(mapRangeConstrain(value,minvalues[i+1],maxvalues[i+1],1,4)) sendOSCTrigger(topicScene[currentScene].replace('?',str(sendvalue))) if currentScene==3: sendvalue=int(mapRangeConstrain(value,minvalues[i+1],maxvalues[i+1],1,40)) sendOSCTrigger(topicScene[currentScene].replace('?',str(sendvalue))) print("OSC: "+str(rowid)+"/"+str(len(rows))+" t="+str(round(timeFromStart,2))) lastvalue[i]=value #save last value rowid+=1 return currentScene>=0 def filterEmpty(rows): m=[np.array(rows)[:,i] for i in range(np.shape(np.array(rows))[1])] n=[[x if len(x)>0 else None for x in y] for y in m] n=[list(filter(None, x)) for x in n] return n def mapRange(value, inMin, inMax, outMin, outMax): return outMin + (((value - inMin) / (inMax - inMin)) * (outMax - outMin)) def mapRangeConstrain(v,minIn,maxIn,minOut,maxOut): #include minOut and maxOut and constrain return int(max(minOut,min(maxOut,mapRange(v,minIn,maxIn,minOut,maxOut+1)))) def sendOSCTrigger(mesg): print("OSC: "+str(mesg)+" : 1 and 0") client.send_message(str(mesg), 1) client.send_message(str(mesg), 0) if __name__ == "__main__": init() res=True while res: res=update(time.time())