yading@9
|
1 #!/usr/bin/env python
|
yading@9
|
2 # encoding: utf-8
|
yading@9
|
3
|
yading@9
|
4 """
|
yading@9
|
5 Created by Yading Song on 2013-04-21 for Music Hack Day in Paris
|
yading@9
|
6 Copyright (c) 2013 . All rights reserved.
|
yading@9
|
7 """
|
yading@9
|
8
|
yading@12
|
9 #import soundcloud
|
yading@12
|
10 #import musixmatch
|
yading@12
|
11 #import musixmatch.ws
|
yading@12
|
12
|
yading@12
|
13 import json
|
yading@9
|
14 import os,sys,optparse,signal,time,math
|
yading@9
|
15 import cherrypy as cp
|
yading@10
|
16 import numpy
|
yading@10
|
17 import sys
|
yading@10
|
18 sys.path.append('/usr/local/lib/python2.7/site-packages')
|
yading@9
|
19 from cherrypy.lib import static
|
yading@9
|
20 import subprocess as sp
|
yading@9
|
21 from subprocess import Popen as spopen
|
yading@9
|
22
|
yading@10
|
23 import time
|
yading@10
|
24 import random
|
yading@9
|
25 """"*********************************************************************************"""
|
yading@9
|
26
|
yading@9
|
27 from xml.dom import minidom
|
yading@9
|
28 import urllib2 #call url function
|
yading@9
|
29 import os
|
yading@9
|
30 import sys
|
yading@9
|
31 import cPickle
|
yading@9
|
32
|
yading@9
|
33 import pyechonest # import echonest API
|
yading@9
|
34 from pyechonest import artist, catalog, config, playlist # How it works instead of pyechonest
|
yading@9
|
35
|
yading@10
|
36 from echonest.remix import audio, modify
|
yading@9
|
37
|
yading@10
|
38 # echonest API for pitch shifting
|
yading@10
|
39 config.ECHO_NEST_API_KEY="SFXNKMTRAZ3ULHK6U "
|
yading@10
|
40
|
yading@12
|
41 # musiXmatch API key
|
yading@12
|
42 apikey = '8496dd1c715c69a74ef9fcde1716cf4a'
|
yading@10
|
43
|
yading@10
|
44
|
yading@10
|
45 # 7 digital API key
|
yading@10
|
46 DIGITAL7_API_KEY = '7dbpa63h3y3d'
|
yading@10
|
47
|
yading@10
|
48
|
yading@10
|
49 usage = """
|
yading@10
|
50 Usage:
|
yading@10
|
51 python beatshift.py <input_filename> <output_filename>
|
yading@10
|
52 Exampel:
|
yading@10
|
53 python beatshift.py CryMeARiver.mp3 CryMeAShifty.mp3
|
yading@10
|
54 """
|
yading@9
|
55
|
yading@9
|
56
|
yading@9
|
57
|
yading@9
|
58 # this is just a parser for command line options for the server.
|
yading@9
|
59 op = optparse.OptionParser()
|
yading@9
|
60 op.add_option('-u', '--user', action="store", dest="USER", default="devel", type="str")
|
yading@9
|
61 options, args = op.parse_args()
|
yading@9
|
62 CONFIG_FILE = "%(USER)s.cfg" %options.__dict__
|
yading@9
|
63
|
yading@9
|
64 if not os.path.isfile(CONFIG_FILE) :
|
yading@9
|
65 print >> sys.stderr, "Config file not found: %s" %CONFIG_FILE
|
yading@9
|
66 sys.exit(-1)
|
yading@9
|
67
|
yading@9
|
68 # This is the server side of the actual Web-application
|
yading@9
|
69 class ServerExample:
|
yading@9
|
70
|
yading@9
|
71 def __init__(self):
|
yading@9
|
72 self.inputs = []
|
yading@9
|
73
|
yading@9
|
74 def index(self):
|
yading@9
|
75 return ""
|
yading@9
|
76
|
yading@10
|
77
|
yading@9
|
78 @cp.expose
|
yading@9
|
79 def receiveinput(self, userinput):
|
yading@10
|
80 # type in the title of the song you like
|
yading@10
|
81 print "\n\n >>>The user entered the text: %(userinput)s\n\n" %locals()
|
yading@9
|
82
|
yading@12
|
83 #lyrics = musixmatch.ws.track.lyrics.get('Baby',apikey=apikey)
|
yading@11
|
84
|
yading@12
|
85 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><div id="dz-root"></div><div class="container-narrow"><hr><div class="jumbotron"> <h1>Results</h1> '''
|
yading@11
|
86
|
yading@12
|
87 content = '''<div style="text-align:center"> <p> You have chosen <b> %s </b> music </p></div>''' %userinput
|
yading@12
|
88 html_tail = '''</div><div style="margin:0 auto;width:75%;text-align:center"><script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script><br /> <a href="javascript: history.go(-1)">Back</a> </div></body> </html>'''
|
yading@10
|
89 audio_url = ""
|
yading@10
|
90
|
yading@12
|
91 #(tracktitle, trackid) = get_trackid_from_text_search(userinput,'Justin Bieber')
|
yading@13
|
92 (tracktitle, trackid) = get_trackid_from_text_search(userinput,'')
|
yading@13
|
93
|
yading@10
|
94 audio_url = get_preview_from_trackid(trackid)
|
yading@10
|
95
|
yading@12
|
96 content = content + '''<div style="text-align:center"><p><a href=" %s ">''' % audio_url + '''<b> %s </b>''' % userinput
|
yading@9
|
97
|
yading@10
|
98 file_name = tracktitle + u'.mp3'
|
yading@10
|
99 file_name = file_name.replace(u'/', u' ')
|
yading@10
|
100
|
yading@10
|
101 #file_name = t.title + u'.mp3'
|
yading@10
|
102 # download_path = os.path.join(file_path, file_name)
|
yading@10
|
103
|
yading@12
|
104 file_name = "Baby.mp3"
|
yading@10
|
105 # download the song in the same path folder
|
yading@10
|
106 path_name = './' + file_name
|
yading@10
|
107 mp3 = download_file(audio_url, path_name)
|
yading@10
|
108
|
yading@13
|
109 os.system('ffmpeg -i Baby.mp3 -ac 1 Baby.wav')
|
yading@12
|
110 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 " " ')
|
yading@13
|
111
|
yading@10
|
112
|
yading@10
|
113 print "Pitch Shifting Done"
|
yading@10
|
114
|
yading@10
|
115 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step1('Baby.wav');exit;\" ")
|
yading@10
|
116 #os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step1('Baby.wav');exit;\" ")
|
yading@10
|
117 print "Melody"
|
yading@10
|
118
|
yading@10
|
119 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step2('Baby.wav');exit;\" ")
|
yading@10
|
120 #os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step2('Baby_ps12.wav');exit;\" ")
|
yading@10
|
121 print "Instrument"
|
yading@10
|
122 #os.system('/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r "mcc -m filename.m;exit;"')
|
yading@9
|
123
|
yading@10
|
124 print "Done STEP 1"
|
yading@12
|
125
|
yading@12
|
126 # light version
|
yading@10
|
127 pitchshifting5('melody.wav','melody_ps5.wav')
|
yading@13
|
128 print "pitch shifting 5"
|
yading@12
|
129 # heaven version
|
yading@10
|
130 pitchshifting12('melody.wav','melody_ps12.wav')
|
yading@9
|
131
|
yading@10
|
132
|
yading@10
|
133 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step3('melody_ps5.wav');exit;\"")
|
yading@12
|
134 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"step3_heavy('melody_ps12.wav');exit;\"")
|
yading@10
|
135 print "Step 3"
|
yading@12
|
136
|
yading@12
|
137 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"fix_offset('melody.wav','ysbaby_voice_light.wav');exit;\"")
|
yading@12
|
138 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"fix_offset('melody.wav','ysbaby_voice_heavy.wav');exit;\"")
|
yading@12
|
139
|
yading@10
|
140 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"final_mix('ysbaby_voice_light.wav','instrumental.wav');exit;\"")
|
yading@12
|
141 os.system("/Applications/MATLAB_R2012b.app/bin/matlab -nojvm -nosplash -nodisplay -r \"final_mix_heavy('ysbaby_voice_heavy.wav','instrumental.wav');exit;\"")
|
yading@12
|
142
|
yading@10
|
143 lightaudio_url = 'light_' + tracktitle
|
yading@10
|
144 midaudio_url = 'mid_' + tracktitle
|
yading@10
|
145 heavyaudio_url = 'heavy_' + tracktitle
|
yading@10
|
146
|
yading@12
|
147 content = content + '''<div style="text-align:center"><p><a href="MIX.wav">''' + '''<b> Light Version </b></div>'''
|
yading@12
|
148 content = content + '''<div style="text-align:center"><p><a href="MIX_heavy.wav">''' + '''<b> Heavy Version </b>'''
|
yading@10
|
149 #content = content + '''<p><a href=" %s ">''' % heavyaudio_url + '''<b> Heaven Version </b>'''
|
yading@10
|
150
|
yading@9
|
151 return html_head, content, html_tail
|
yading@9
|
152
|
yading@9
|
153 @cp.expose
|
yading@9
|
154 def testpage(self):
|
yading@9
|
155 return "<html> <body> You have accessed the test page </body> </html>"
|
yading@9
|
156
|
yading@10
|
157 def pitchshifting5(input_filename, output_filename):
|
yading@10
|
158 soundtouch = modify.Modify()
|
yading@10
|
159 audiofile = audio.LocalAudioFile(input_filename)
|
yading@10
|
160 beats = audiofile.analysis.beats
|
yading@10
|
161 out_shape = (len(audiofile.data),)
|
yading@10
|
162 out_data = audio.AudioData(shape=out_shape, numChannels=1, sampleRate=44100)
|
yading@10
|
163
|
yading@10
|
164 for i, beat in enumerate(beats):
|
yading@10
|
165 data = audiofile[beat].data
|
yading@10
|
166 number = beat.local_context()[0] % 12
|
yading@10
|
167 #new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], number*-1)
|
yading@10
|
168 new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], -5)
|
yading@10
|
169 out_data.append(new_beat)
|
yading@10
|
170
|
yading@10
|
171 out_data.encode(output_filename)
|
yading@10
|
172
|
yading@10
|
173
|
yading@10
|
174 def pitchshifting12(input_filename, output_filename):
|
yading@10
|
175 soundtouch = modify.Modify()
|
yading@10
|
176 audiofile = audio.LocalAudioFile(input_filename)
|
yading@10
|
177 beats = audiofile.analysis.beats
|
yading@10
|
178 out_shape = (len(audiofile.data),)
|
yading@10
|
179 out_data = audio.AudioData(shape=out_shape, numChannels=1, sampleRate=44100)
|
yading@10
|
180
|
yading@10
|
181 for i, beat in enumerate(beats):
|
yading@10
|
182 data = audiofile[beat].data
|
yading@10
|
183 number = beat.local_context()[0] % 12
|
yading@10
|
184 #new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], number*-1)
|
yading@12
|
185 new_beat = soundtouch.shiftPitchSemiTones(audiofile[beat], -12)
|
yading@10
|
186 out_data.append(new_beat)
|
yading@10
|
187
|
yading@10
|
188 out_data.encode(output_filename)
|
yading@10
|
189
|
yading@10
|
190
|
yading@9
|
191 def url_call(url):
|
yading@9
|
192 """
|
yading@10
|
193 ***This method is from get_preview_url.py by Thierry Bertin-Mahieux***
|
yading@10
|
194 Do a simple request to the 7digital API
|
yading@10
|
195 We assume we don't do intense querying, this function is not robust
|
yading@10
|
196 Return the answer as na xml document
|
yading@10
|
197 """
|
yading@9
|
198 stream = urllib2.urlopen(url)
|
yading@9
|
199 xmldoc = minidom.parse(stream).documentElement
|
yading@9
|
200 stream.close()
|
yading@9
|
201 return xmldoc
|
yading@9
|
202
|
yading@10
|
203
|
yading@10
|
204 def download_file(file_url, file_name):
|
yading@10
|
205 # open the url
|
yading@10
|
206 mp3file = urllib2.urlopen(file_url)
|
yading@10
|
207
|
yading@10
|
208 # open the local file for writing
|
yading@10
|
209 local_file = open(file_name, "wb")
|
yading@10
|
210 # write to file
|
yading@10
|
211 local_file.write(mp3file.read())
|
yading@10
|
212 local_file.close()
|
yading@10
|
213
|
yading@9
|
214 """"*********************************************************************************"""
|
yading@9
|
215
|
yading@10
|
216 def get_trackid_from_text_search(title,artistname=''):
|
yading@10
|
217 """
|
yading@10
|
218 ***This method is from get_preview_url.py by Thierry Bertin-Mahieux***
|
yading@10
|
219 Search for an artist + title using 7digital search API
|
yading@10
|
220 Return None if there is a problem, or tuple (title,trackid)
|
yading@10
|
221 """
|
yading@10
|
222 url = 'http://api.7digital.com/1.2/track/search?'
|
yading@10
|
223 url += 'oauth_consumer_key='+DIGITAL7_API_KEY
|
yading@10
|
224 query = title
|
yading@10
|
225 if artistname != '':
|
yading@10
|
226 query = artistname + ' ' + query
|
yading@10
|
227 query = urllib2.quote(query)
|
yading@10
|
228 url += '&q='+query
|
yading@10
|
229 xmldoc = url_call(url)
|
yading@10
|
230 status = xmldoc.getAttribute('status')
|
yading@10
|
231 if status != 'ok':
|
yading@10
|
232 return None
|
yading@10
|
233 resultelem = xmldoc.getElementsByTagName('searchResult')
|
yading@10
|
234 if len(resultelem) == 0:
|
yading@10
|
235 return None
|
yading@10
|
236 track = resultelem[0].getElementsByTagName('track')[0]
|
yading@10
|
237 tracktitle = track.getElementsByTagName('title')[0].firstChild.data
|
yading@10
|
238 trackid = int(track.getAttribute('id'))
|
yading@10
|
239 return (tracktitle,trackid)
|
yading@10
|
240
|
yading@10
|
241
|
yading@9
|
242 def get_preview_from_trackid(trackid):
|
yading@9
|
243 """
|
yading@9
|
244 ***This method is from get_preview_url.py by Thierry Bertin-Mahieux***
|
yading@9
|
245 Ask for the preview to a particular track, get the XML answer
|
yading@9
|
246 After calling the API with a given track id,
|
yading@9
|
247 we get an XML response that looks like:
|
yading@9
|
248
|
yading@9
|
249 <response status="ok" version="1.2" xsi:noNamespaceSchemaLocation="http://api.7digital.com/1.2/static/7digitalAPI.xsd">
|
yading@9
|
250 <url>
|
yading@9
|
251 http://previews.7digital.com/clips/34/6804688.clip.mp3
|
yading@9
|
252 </url>
|
yading@9
|
253 </response>
|
yading@9
|
254
|
yading@9
|
255 We parse it for the URL that we return, or '' if a problem
|
yading@9
|
256 """
|
yading@9
|
257 url = 'http://api.7digital.com/1.2/track/preview?redirect=false'
|
yading@9
|
258 url += '&trackid='+str(trackid)
|
yading@9
|
259 url += '&oauth_consumer_key='+DIGITAL7_API_KEY
|
yading@9
|
260 xmldoc = url_call(url)
|
yading@9
|
261 status = xmldoc.getAttribute('status')
|
yading@9
|
262 if status != 'ok':
|
yading@9
|
263 return ''
|
yading@9
|
264 urlelem = xmldoc.getElementsByTagName('url')[0]
|
yading@9
|
265 preview = urlelem.firstChild.nodeValue
|
yading@9
|
266 return preview
|
yading@9
|
267
|
yading@9
|
268
|
yading@9
|
269
|
yading@9
|
270 """"*********************************************************************************"""
|
yading@9
|
271
|
yading@9
|
272
|
yading@9
|
273 def getProcessPids(port,kill=False):
|
yading@9
|
274 '''Get the pid of the offending Python process given a port after an unsuccessful restart.'''
|
yading@9
|
275 print "Running lsof -i :"+str(port)," ...\n\n"
|
yading@9
|
276 command = "lsof -i :"+str(port)
|
yading@9
|
277 w = spopen(command,stdout=sp.PIPE,stderr=sp.PIPE,shell=True)
|
yading@9
|
278 se = w.stderr.readlines()
|
yading@9
|
279 result = w.stdout.readlines()
|
yading@9
|
280 exitcode = w.wait()
|
yading@9
|
281 if not result :
|
yading@9
|
282 print "getProcessPid:: Unable to obtain process pid. (lsof returned nothing. exitcode: %s)" %str(exitcode)
|
yading@9
|
283 return False
|
yading@9
|
284 import pprint
|
yading@9
|
285 pprint.pprint(result)
|
yading@9
|
286
|
yading@9
|
287 # get heading:
|
yading@9
|
288 ix = None
|
yading@9
|
289 head = result[0].upper()
|
yading@9
|
290 if 'PID' in head:
|
yading@9
|
291 head = filter(lambda x: x != str(), head.split(' '))
|
yading@9
|
292 head = map(lambda x: x.strip().replace(' ',''), head)
|
yading@9
|
293 if 'PID' in head : ix = head.index('PID')
|
yading@9
|
294 # get process pid
|
yading@9
|
295 pids = []
|
yading@9
|
296 for line in result :
|
yading@9
|
297 if 'python' in line.lower() :
|
yading@9
|
298 line = filter(lambda x: x != str(), line.split(' '))
|
yading@9
|
299 line = map(lambda x: x.strip().replace(' ',''), line)
|
yading@9
|
300 try :
|
yading@9
|
301 if ix :
|
yading@9
|
302 pids.append(int(line[ix]))
|
yading@9
|
303 else:
|
yading@9
|
304 numbers = filter(lambda x: x.isdigit(), line)
|
yading@9
|
305 pids.append(int(numbers[0]))
|
yading@9
|
306 except:
|
yading@9
|
307 print 'Error parsing lsof results.'
|
yading@9
|
308 return False
|
yading@9
|
309 print 'Pids found: ',pids
|
yading@9
|
310 # kill if specified
|
yading@9
|
311 if kill :
|
yading@9
|
312 pids_killed = []
|
yading@9
|
313 import signal
|
yading@9
|
314 for pid in pids:
|
yading@9
|
315 print 'Killing process: ',pid
|
yading@9
|
316 try :
|
yading@9
|
317 os.kill(pid,signal.SIGKILL)
|
yading@9
|
318 pids_killed.append(pid)
|
yading@9
|
319 except :
|
yading@9
|
320 print 'Failed: ',pid
|
yading@9
|
321 if pids_killed :
|
yading@9
|
322 print 'Processes killed:',pids_killed,' Waiting 10 seconds...'
|
yading@9
|
323 import time
|
yading@9
|
324 time.sleep(10)
|
yading@9
|
325 return True
|
yading@9
|
326 return False
|
yading@9
|
327
|
yading@9
|
328
|
yading@9
|
329 def main(argv=None):
|
yading@9
|
330
|
yading@9
|
331 # Configure and start
|
yading@9
|
332
|
yading@9
|
333
|
yading@9
|
334 cp.config.update(CONFIG_FILE)
|
yading@9
|
335 cp.config.update({'tools.staticdir.root': os.getcwd()})
|
yading@10
|
336 cp.tree.mount(ServerExample(),script_name="/MusicHackParis",config=CONFIG_FILE)
|
yading@9
|
337 port = int(cp.server.socket_port)
|
yading@9
|
338 ip = cp.server.socket_host
|
yading@9
|
339 print "Trying to bind: %(ip)s:%(port)s" %locals()
|
yading@9
|
340 getProcessPids(port,kill=True)
|
yading@9
|
341 cp.quickstart()
|
yading@9
|
342
|
yading@9
|
343 if __name__ == "__main__":
|
yading@9
|
344 main()
|