#!/usr/bin/python3 -u

# old file, prefer use sooperlooper_nsm. But it's maybe used by someones.

import sys
import subprocess
import time

try:
    import liblo
    import xml.etree.ElementTree as ET
    from signal import signal, SIGINT, SIGTERM, SIGUSR1, SIGUSR2
except:
    sys.exit()

class OSCServer(liblo.Server):
    def __init__(self):
        liblo.Server.__init__(self)
        
        self.m_number_of_loops = 0
        self.m_last_called_looplen = 0
        self.sl_url = liblo.Address(sooploop_port)
        self.m_save_last_called_loop = True
        
        self.add_method('/pingfromsl', None, self.pingFeedBack)
        self.add_method('/audio_save_error', None, self.audioSaveError)
        self.add_method('/loop_lenght', None, self.setLoopLenght)
        
    def pingFeedBack(self, path, arg_list):
        if len(arg_list) > 1:
            self.m_number_of_loops = arg_list[2]
        
    def setLoopLenght(self, path, arg_list):
        self.m_last_called_looplen = arg_list[2]
        
    def audioSaveError(self, path, arg_list):
        if len(arg_list) > 1:
            if arg_list[1] == 'Loop Save Failed':
                self.m_save_last_called_loop = False
            
    def saveSession(self):
        self.send(self.sl_url, '/ping', ('s', self.url), ('s', '/pingfromsl'))
        self.send(self.sl_url, '/save_session', ('s', filename), ('s', ''), ('s', ''))
        
        self.recv(1)
        
        #save audio loops
        basefile = filename.rsplit('.slsess', 1)[0]
        for i in range(self.m_number_of_loops):
            #send signal to know if loop contains audio
            self.send(self.sl_url, '/sl/%i/get' % i, ('s', 'loop_len'), ('s', self.url), ('s', '/loop_lenght'))
            
            self.recv(1)
            
            if self.m_last_called_looplen > 0: #if loop contains audio
                audio_filename = basefile + str(i) + '.wav'
                
                server.send(self.sl_url,
                            '/sl/' + str(i) + '/save_loop', 
                            ('s', audio_filename), 
                            ('s', ''), 
                            ('s', ''), 
                            ('s', self.url), 
                            ('s', '/audio_save_error'))
                
                server.recv(10)
                
                if self.m_save_last_called_loop:
                    #rewrite .slsess file to include audio
                    tree = ET.parse(filename)
                    root = tree.getroot()
                    Loopers = root.find('Loopers')
                    for Looper in Loopers.iter('Looper'):
                        if str(Looper.get('index')) == str(i):
                            Looper.set('loop_audio', audio_filename)
                    tree.write(filename)
                    
            self.m_save_last_called_loop = True
    
    def pingSooperLooper(self, port):
        self.send(self.sl_url, '/ping', ('s', self.url), ('s', '/pingfromsl'))
        self.recv(1)
        if self.sl_port == None:
            return False
        else:
            return self.sl_port
    
    def quitSooperLooper(self):
        self.send(self.sl_url, '/quit')
        

def signalHandler(sig, frame):
    if sig in (SIGTERM, SIGINT):
        slgui_process.send_signal(SIGTERM)
        server.quitSooperLooper()
    elif sig == SIGUSR1:
        server.saveSession()
        return
    
    global main_loop
    main_loop = False

########################################SCRIPT START#########################################################


#set filename from argument, exit if no argument
try:
    filename = sys.argv[1]
except:
    print('need file as argument, exit', file=sys.stderr)
    sys.exit(0)


#get a free OSC port for sooperlooper, start from 9951 (default soopperlooper osc port)
sooploop_port = 9951
UsedPort = True
testport = None

while UsedPort:
    try:
        testport = liblo.Server(sooploop_port)
        UsedPort = False
    except:
        sooploop_port += 1
        UsedPort = True

del testport, UsedPort

#lanch sooperlooper
sooperlooper_process = subprocess.Popen(['sooperlooper', '-p', str(sooploop_port),'--load-session', filename ])

#launch slgui
slgui_process = subprocess.Popen(['slgui', '-P', str(sooploop_port)])

#construct OSC server
server = OSCServer()


main_loop = True

while main_loop:
    #quit script if slgui closed
    if slgui_process.poll() != None:
        server.quitSooperLooper()
        break
    
    #send signal if any
    signal(SIGINT,  signalHandler)
    signal(SIGTERM, signalHandler)
    signal(SIGUSR1, signalHandler)
        
    time.sleep(0.050) #refresh time (50ms)
