view start.py @ 11:f445c3017523

new files
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Sun, 21 Apr 2013 11:16:23 +0200
parents 6840f77b83aa
children 80a9556123da
line wrap: on
line source
#!/usr/bin/env python
# encoding: utf-8

"""
Created by Yading Song on 2013-04-21 for Music Hack Day in Paris
Copyright (c) 2013 . All rights reserved.
"""

import os,sys,optparse,signal,time,math
import cherrypy as cp
import numpy
import sys
sys.path.append('/usr/local/lib/python2.7/site-packages')
from cherrypy.lib import static
import subprocess as sp
from subprocess import Popen as spopen

import time
import random
""""*********************************************************************************"""

from xml.dom import minidom
import urllib2 #call url function
import os 
import sys
import cPickle

import pyechonest # import echonest API 
from pyechonest import artist, catalog, config, playlist # How it works instead of pyechonest

from echonest.remix import audio, modify

# echonest API for pitch shifting 
config.ECHO_NEST_API_KEY="SFXNKMTRAZ3ULHK6U "




# 7 digital API key
DIGITAL7_API_KEY = '7dbpa63h3y3d'


usage = """
Usage:
    python beatshift.py <input_filename> <output_filename>
Exampel:
    python beatshift.py CryMeARiver.mp3 CryMeAShifty.mp3
"""



# this is just a parser for command line options for the server.
op = optparse.OptionParser()
op.add_option('-u', '--user', action="store", dest="USER", default="devel", type="str")
options, args = op.parse_args()
CONFIG_FILE = "%(USER)s.cfg" %options.__dict__

if not os.path.isfile(CONFIG_FILE) :
	print >> sys.stderr, "Config file not found: %s" %CONFIG_FILE
	sys.exit(-1)

# This is the server side of the actual Web-application
class ServerExample:
	
	def __init__(self):
		self.inputs = []
	
	def index(self):
		return ""
	

	@cp.expose
	def receiveinput(self, userinput):
            # type in the title of the song you like 
            print "\n\n >>>The user entered the text: %(userinput)s\n\n" %locals() 
            
            html_head = '''<!DOCTYPE html> <html lang="en"> <head>
                    <meta charset="utf-8">
    <title>BrutalizeMe</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">

    <!-- Le styles -->
    <link href="css/bootstrap.css" rel="stylesheet">
    <style type="text/css">
        body {
            padding-top: 20px;
            padding-bottom: 40px;
        }

            /* Custom container */
        .container-narrow {
            margin: 0 auto;
            max-width: 700px;
        }

        .container-narrow > hr {
            margin: 30px 0;
        }

            /* Main marketing message and sign up button */
        .jumbotron {
            margin: 60px 0;
            text-align: center;
        }

        .jumbotron h1 {
            font-size: 72px;
            line-height: 1;
        }

        .jumbotron .btn {
            font-size: 21px;
            padding: 14px 24px;
        }

            /* Supporting marketing content */
        .marketing {
            margin: 60px 0;
        }

        .marketing p + h4 {
            margin-top: 28px;
        }
        .input {
            border: 1px solid #006;
            background: #ffc;
        }
    </style>
    <link href="css/bootstrap-responsive.css" rel="stylesheet">

    <!-- Fav and touch icons -->
    <link rel="shortcut icon" href="../assets/ico/favicon.ico">
    <link rel="apple-touch-icon-precomposed" sizes="144x144" href="../assets/ico/apple-touch-icon-144-precomposed.png">
    <link rel="apple-touch-icon-precomposed" sizes="114x114" href="../assets/ico/apple-touch-icon-114-precomposed.png">
    <link rel="apple-touch-icon-precomposed" sizes="72x72" href="../assets/ico/apple-touch-icon-72-precomposed.png">
    <link rel="apple-touch-icon-precomposed" href="../assets/ico/apple-touch-icon-57-precomposed.png">
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css"/>
    <link rel="stylesheet" href="css/styles.css"/>
    <script src="js/jquery.min.js"></script>
    <script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>
    <script type="text/javascript" src="js/main.js"></script>
    <script type="text/javascript" src="js/infoSongs.js"></script>
    <script type="text/javascript" src="js/genre.js"></script>

</head>
<body> Here are the music<br /> ''' 


            content = '''<h> You have chosen <b> %s </b> music" </h>''' %userinput
            html_tail = '''<script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script><br /> <a href="javascript: history.go(-1)">Back</a> </body> </html>''' 
            audio_url = ""        


            (tracktitle, trackid) = get_trackid_from_text_search(userinput,'Justin Bieber')

            audio_url = get_preview_from_trackid(trackid)
    
            content = content + '''<p><a href=" %s ">''' % audio_url + '''<b> %s </b>''' % userinput
            
            file_name = tracktitle + u'.mp3'
            file_name = file_name.replace(u'/', u' ')
            
            #file_name = t.title + u'.mp3'  
            print("downloading")                
            # download_path = os.path.join(file_path, file_name)
            
            # download the song in the same path folder 
            path_name = './' + file_name
            mp3 = download_file(audio_url, path_name)                                                          


            #os.system('ffmpeg -i song.mp3 -ac 1 song.wav')
            os.system('./sonic-annotator-0.7-osx-x86_64/sonic-annotator -d vamp:mtg-melodia:melodia:melody Baby.wav -w csv --csv-one-file baby.txt --csv-separator " "')
            os.system('ffmpeg -i Baby.mp3 -ac 1 Baby.wav')

            
            print "Pitch Shifting Done"

            os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step1('Baby.wav');exit;\" ")
            #os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step1('Baby.wav');exit;\" ")
            print "Melody"

            os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step2('Baby.wav');exit;\" ")
            #os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step2('Baby_ps12.wav');exit;\" ")
            print "Instrument"
            #os.system('/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r "mcc -m filename.m;exit;"')                
    
            print "Done STEP 1"
    
            pitchshifting5('melody.wav','melody_ps5.wav')
            pitchshifting12('melody.wav','melody_ps12.wav')


            os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step3('melody_ps5.wav');exit;\"")
            print "Step 3"

            os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"final_mix('ysbaby_voice_light.wav','instrumental.wav');exit;\"")

            lightaudio_url = 'light_' + tracktitle 
            midaudio_url = 'mid_' + tracktitle
            heavyaudio_url = 'heavy_' + tracktitle 

            content = content + '''<p><a href="MIX.wav">''' + '''<b> Light Version </b>''' 
            #content = content + '''<p><a href=" %s ">''' % midaudio_url + '''<b> Middle Version </b>'''  
            #content = content + '''<p><a href=" %s ">''' % heavyaudio_url + '''<b> Heaven Version </b>'''  

            return html_head, content, html_tail

	@cp.expose
	def testpage(self):
		return "<html> <body> You have accessed the test page </body> </html>"

def pitchshifting5(input_filename, output_filename):
    soundtouch = modify.Modify()
    audiofile = audio.LocalAudioFile(input_filename)
    beats = audiofile.analysis.beats
    out_shape = (len(audiofile.data),)
    out_data = audio.AudioData(shape=out_shape, numChannels=1, sampleRate=44100)
    
    for i, beat in enumerate(beats):
        data = audiofile[beat].data
        number = beat.local_context()[0] % 12
        #new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], number*-1)
        new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], -5)
        out_data.append(new_beat)
    
    out_data.encode(output_filename)


def pitchshifting12(input_filename, output_filename):
    soundtouch = modify.Modify()
    audiofile = audio.LocalAudioFile(input_filename)
    beats = audiofile.analysis.beats
    out_shape = (len(audiofile.data),)
    out_data = audio.AudioData(shape=out_shape, numChannels=1, sampleRate=44100)
    
    for i, beat in enumerate(beats):
        data = audiofile[beat].data
        number = beat.local_context()[0] % 12
        #new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], number*-1)
        new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], -5)
        out_data.append(new_beat)
    
    out_data.encode(output_filename)


def url_call(url):
    """
    ***This method is from get_preview_url.py by Thierry Bertin-Mahieux***
    Do a simple request to the 7digital API
    We assume we don't do intense querying, this function is not robust
    Return the answer as na xml document
    """
    stream = urllib2.urlopen(url)
    xmldoc = minidom.parse(stream).documentElement
    stream.close()
    return xmldoc


def download_file(file_url, file_name):
    # open the url
    mp3file = urllib2.urlopen(file_url)   
    
    # open the local file for writing
    local_file = open(file_name, "wb")
    # write to file
    local_file.write(mp3file.read())
    local_file.close()

""""*********************************************************************************"""

def get_trackid_from_text_search(title,artistname=''):
    """
        ***This method is from get_preview_url.py by Thierry Bertin-Mahieux***
        Search for an artist + title using 7digital search API
        Return None if there is a problem, or tuple (title,trackid)
        """
    url = 'http://api.7digital.com/1.2/track/search?'
    url += 'oauth_consumer_key='+DIGITAL7_API_KEY
    query = title
    if artistname != '':
        query = artistname + ' ' + query
    query = urllib2.quote(query)
    url += '&q='+query
    xmldoc = url_call(url)
    status = xmldoc.getAttribute('status')
    if status != 'ok':
        return None
    resultelem = xmldoc.getElementsByTagName('searchResult')
    if len(resultelem) == 0:
        return None
    track = resultelem[0].getElementsByTagName('track')[0]
    tracktitle = track.getElementsByTagName('title')[0].firstChild.data
    trackid = int(track.getAttribute('id'))
    return (tracktitle,trackid)  


def get_preview_from_trackid(trackid):
    """
        ***This method is from get_preview_url.py by Thierry Bertin-Mahieux***
        Ask for the preview to a particular track, get the XML answer
        After calling the API with a given track id,
        we get an XML response that looks like:
        
        <response status="ok" version="1.2" xsi:noNamespaceSchemaLocation="http://api.7digital.com/1.2/static/7digitalAPI.xsd">
        <url>
        http://previews.7digital.com/clips/34/6804688.clip.mp3
        </url>
        </response>
        
        We parse it for the URL that we return, or '' if a problem
        """
    url = 'http://api.7digital.com/1.2/track/preview?redirect=false'
    url += '&trackid='+str(trackid)
    url += '&oauth_consumer_key='+DIGITAL7_API_KEY
    xmldoc = url_call(url)
    status = xmldoc.getAttribute('status')
    if status != 'ok':
        return ''
    urlelem = xmldoc.getElementsByTagName('url')[0]
    preview = urlelem.firstChild.nodeValue
    return preview   



""""*********************************************************************************"""


def getProcessPids(port,kill=False):
	'''Get the pid of the offending Python process given a port after an unsuccessful restart.'''
	print "Running lsof -i :"+str(port)," ...\n\n"
	command = "lsof -i :"+str(port)
	w = spopen(command,stdout=sp.PIPE,stderr=sp.PIPE,shell=True)
	se = w.stderr.readlines()
	result = w.stdout.readlines()
	exitcode = w.wait()
	if not result : 
		print "getProcessPid:: Unable to obtain process pid. (lsof returned nothing. exitcode: %s)" %str(exitcode)
		return False
	import pprint
	pprint.pprint(result)
	
	# get heading:
	ix = None
	head = result[0].upper()
	if 'PID' in head:
		head = filter(lambda x: x != str(), head.split(' '))
		head = map(lambda x: x.strip().replace(' ',''), head)
		if 'PID' in head : ix = head.index('PID')
	# get process pid
	pids = []
	for line in result :
		if 'python' in line.lower() :
			line = filter(lambda x: x != str(), line.split(' '))
			line = map(lambda x: x.strip().replace(' ',''), line)
			try :
				if ix : 
					pids.append(int(line[ix]))
				else:
					numbers = filter(lambda x: x.isdigit(), line)
					pids.append(int(numbers[0]))
			except:
				print 'Error parsing lsof results.' 
				return False
	print 'Pids found: ',pids
	# kill if specified
	if kill :
		pids_killed = []
		import signal
		for pid in pids:
			print 'Killing process: ',pid
			try :
				os.kill(pid,signal.SIGKILL)
				pids_killed.append(pid)
			except :
				print 'Failed: ',pid
		if pids_killed :
			print 'Processes killed:',pids_killed,' Waiting 10 seconds...'
			import time
			time.sleep(10)
			return True
	return False


def main(argv=None):
	
	# Configure and start
	

	cp.config.update(CONFIG_FILE)
	cp.config.update({'tools.staticdir.root': os.getcwd()})
	cp.tree.mount(ServerExample(),script_name="/MusicHackParis",config=CONFIG_FILE)	
	port = int(cp.server.socket_port)
	ip = cp.server.socket_host
	print "Trying to bind: %(ip)s:%(port)s" %locals()
	getProcessPids(port,kill=True)
	cp.quickstart()

if __name__ == "__main__":
	main()