281 lines
No EOL
9 KiB
Python
281 lines
No EOL
9 KiB
Python
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
|
|
|
|
scenes =[0,2,2,2,2,2,2,2,2,2, -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<len(scenetimes) and t>=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()) |