diff --git a/README.md b/README.md index 22d0993..7009c38 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Forward Midi events to redis/OSC Miredis hooks to all midi devices connected and listen for events. +Miredis can optionnaly hook to Link protocol -> "/beats" & "/bpm" All events are forwarded to a redis server and an OSC server. Run : @@ -20,6 +21,10 @@ python3 miredis.py -h "/midi/cc/midichannel/ccnumber" value : "ccvalue" +"/beats" value : "beatnumber" + +"/bpm" value : "currentbpm" + ## OSC /midi/noteon midichannel note velocity @@ -32,4 +37,8 @@ python3 miredis.py -h /midi/start -/midi/stop \ No newline at end of file +/midi/stop + +/beats beatnumber + +/bpm bpm diff --git a/libs/__pycache__/midix.cpython-38.pyc b/libs/__pycache__/midix.cpython-38.pyc index 5d78572..9e714f7 100644 Binary files a/libs/__pycache__/midix.cpython-38.pyc and b/libs/__pycache__/midix.cpython-38.pyc differ diff --git a/libs/alink.py b/libs/alink.py new file mode 100644 index 0000000..454e15c --- /dev/null +++ b/libs/alink.py @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# -*- mode: Python -*- + +''' + +Ableton Link + +LICENCE : CC +Sam Neurohack + + +Get: + +git clone --recursive https://github.com/gonzaloflirt/link-python.git + +Build: + +Make sure python 3 is installed on your system. + +mkdir build +cd build +cmake .. +cmake --build . + +''' +from libs import midix +import sys + +prevphase = 0 +bpm = 120 + +def Start(): + global lnk + from libs import link + + print("Link ENABLED") + lnk = link.Link(120) + lnk.enabled = True + lnk.startStopSyncEnabled = True + linked = True + +def RedOSC(tempo_str, beats_str): + + print() + print("Link : BPM " +tempo_str+" Beat "+str(beats_str) + ' \r') + #sys.stdout.flush() + + + # redis key : "/beats" value : currentbeat + if midix.toKey('/beats', beats_str)==True: + print("redis :", '/beats', beats_str) + + # OSC : /midi/cc midichannel ccnumber value + midix.SendOSC('/beats', [beats_str]) + print("osc :",'/beats', [beats_str]) + + # redis key : "/bpm" value : newbpm + if midix.toKey('/bpm', bpm)==True: + print("redis :", '/bpm', bpm) + + # OSC : /bpm newbpm + midix.SendOSC('/bpm', [bpm]) + print("osc :",'/bpm', [bpm]) + + +def BeatEvent(): + global lnk, prevphase + + + lnkstr = lnk.captureSessionState() + link_time = lnk.clock().micros(); + tempo_str = '{0:.2f}'.format(lnkstr.tempo()) + bpm = float(tempo_str) + #beatstep.SendOSCUI('/bpm', [bpm]) + beats_str = '{0:.2f}'.format(lnkstr.beatAtTime(link_time, 0)) + playing_str = str(lnkstr.isPlaying()) # always False ??? + phase = lnkstr.phaseAtTime(link_time, 4) + + + # new beat ? + if int(phase) != prevphase: + prevphase = int(phase) + + RedOSC(tempo_str, beats_str) + currentbeat = float(beats_str) + #midix.SendAU('/aurora/beats', beats_str) + #AllStatus("Beat "+str(beats_str)) + + + +# Change current Link Tempo. +def newtempo(tempo): + global lnk + + #print("val2", val2, "tempo", tempo) + + if linked == True: + lnk.enabled = False + lnk.startStopSyncEnabled = False + lnk = link.Link(tempo) + lnk.enabled = True + lnk.startStopSyncEnabled = True + bpm = tempo + print("New BPM to Link", bpm) + RedOSC(str(tempo), "0.0") + + ''' + # redis key : "/bpm" value : newbpm + if midix.toKey('/bpm', bpm)==True: + print("redis :", '/bpm', bpm) + + # OSC : /bpm newbpm + midix.SendOSC('/bpm', [bpm]) + print("osc :",'/bpm', [bpm]) + ''' + + else: + print("Link is disabled") + + +# increase or decrease BPM +def BPMAdj(val1, keyname): + + + # + 1 + if val1 == 1: + newtempo(bpm+1) + + # -1 + if val1 == 127 and bpm > 0: + newtempo(bpm-1) + + + diff --git a/libs/link.cpython-35m-x86_64-linux-gnu.so b/libs/link.cpython-35m-x86_64-linux-gnu.so new file mode 100644 index 0000000..adb24f3 Binary files /dev/null and b/libs/link.cpython-35m-x86_64-linux-gnu.so differ diff --git a/libs/link.cpython-36m-x86_64-linux-gnu.so b/libs/link.cpython-36m-x86_64-linux-gnu.so new file mode 100644 index 0000000..070fd06 Binary files /dev/null and b/libs/link.cpython-36m-x86_64-linux-gnu.so differ diff --git a/libs/link.cpython-37m-darwin.so b/libs/link.cpython-37m-darwin.so new file mode 100644 index 0000000..de923c1 Binary files /dev/null and b/libs/link.cpython-37m-darwin.so differ diff --git a/libs/link.cpython-38-darwin.so b/libs/link.cpython-38-darwin.so new file mode 100755 index 0000000..fe0d275 Binary files /dev/null and b/libs/link.cpython-38-darwin.so differ diff --git a/libs/link.so b/libs/link.so new file mode 100755 index 0000000..a56bff8 Binary files /dev/null and b/libs/link.so differ diff --git a/libs/midix.py b/libs/midix.py index bc9504b..066e544 100644 --- a/libs/midix.py +++ b/libs/midix.py @@ -146,7 +146,18 @@ def SendUI(oscaddress,oscargs=''): log.err('Connection to Aurora UI refused : died ?') pass #time.sleep(0.001 +# Ask redis for a given key +def fromKey(keyname): + + return r.get(keyname) + +# +# Write to redis key +def toKey(keyname,keyvalue): + #print(keyname,keyvalue) + # Store encoded data in Redis + return r.set(keyname,keyvalue) def GetTime(): return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime()) diff --git a/miredis.py b/miredis.py index c859c28..8e24c66 100644 --- a/miredis.py +++ b/miredis.py @@ -96,7 +96,8 @@ argsparser.add_argument("-p","--port",help="Port of the Redis server ",default=" # OSC Args argsparser.add_argument("-o","--oscip",help="IP address of the OSC server to forward midi events.",default="127.0.0.1",type=str) argsparser.add_argument("-q","--oscport",help="Port of the OSC server ",default="9000",type=str) - +argsparser.add_argument('-link',help="Enable Ableton Link (disabled by default)", dest='link', action='store_true') +argsparser.set_defaults(link=False) args = argsparser.parse_args() redisIP = args.ip @@ -105,7 +106,15 @@ midix.oscIP = args.oscip midix.oscPORT = int(args.oscport) midix.debug = args.verbose +# with Ableton Link +if args.link == True: + from libs import alink + alink.Start() + linked = True +else: + print("Link DISABLED") + linked = False r = redis.StrictRedis(host=redisIP , port=redisPORT, db=0) midix.r = r @@ -122,7 +131,9 @@ if __name__ == '__main__': try: while True: - time.sleep(0.1) + time.sleep(0.001) + if linked: + alink.BeatEvent() except Exception: traceback.print_exc()