-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbrains.py
112 lines (98 loc) · 3.92 KB
/
brains.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# encoding: utf=8
from scripts.file_retrieval import get_file
from config import ECHO_NEST_API_KEY
from pyechonest import config
config.ECHO_NEST_API_KEY=ECHO_NEST_API_KEY
from pyechonest.song import search as song_search
import echonest.remix.audio as audio
from echonest.remix.action import Crossmatch
import urllib2
import time
from random import shuffle
from common import VALID_MOODS, PARTIAL_MASHUP_DIR, OUTPUT_DIR
from helpers import get_beat_tuples, match_beat_length
from scripts.file_retrieval import get_file
class MoodBoombox(object):
def __init__(self, mood=None, output_name=None):
start = time.time()
if not mood:
raise Exception("NO MOOD SPECIFIED")
elif not output_name:
raise Exception("Please specify a file output name")
elif mood not in VALID_MOODS:
raise Exception("Invalid mood: {}".format(mood))
self.output_name = output_name
self.mood = mood
self.lead_track = {'sample_url': '', 'local_url': ''}
self.other_tracks = {'sample_urls': [], 'local_urls': []}
self.other_track_urls = []
self.run()
end = time.time()
print 'that took {}'.format(end-start)
def run(self):
self.set_other_track()
self.set_other_track()
self.set_lead_track()
self.make_song()
def set_lead_track(self):
track_url = self.get_track('lead', mood=self.mood, min_speechiness=0.5,
min_danceability=0.6, buckets=['id:7digital-US', 'tracks'], results=6)
local_url = get_file(track_url)
self.lead_track['sample_url'] = track_url
self.lead_track['local_url'] = local_url
def set_other_track(self):
track_url = self.get_track('other', mood=self.mood, max_speechiness=0.3,
min_danceability=0.8, buckets=['id:7digital-US', 'tracks'], results=8)
local_url = get_file(track_url)
self.other_tracks['local_urls'].append(local_url)
self.other_tracks['sample_urls'].append(track_url)
def get_track(self, search_type, **song_preferences):
if search_type == 'other' and self.other_track_urls:
track_urls = self.other_track_urls
else:
results = song_search(**song_preferences)
shuffle(results)
track_urls = [s.get_tracks("7digital-US")[0].get("preview_url") for s in results\
if s.get_tracks("7digital-US") and \
s.get_tracks("7digital-US")[0].get("preview_url")]
self.other_track_urls = track_urls if search_type == 'other' else self.other_track_urls
for url in track_urls:
try:
urllib2.urlopen(url)
except:
continue
else:
if url not in [self.lead_track['sample_url']]+self.other_tracks['sample_urls']:
return url
else:
continue
# if we got this far, then you got no tracks for the request
raise Exception("We either didn't get enough results for that mood or the urls for the song samples were faulty")
# "crossmatch" the two other tracks
# then crossmatch the result w the lead
def make_song(self, t1_url=None, t2_url=None, is_lead=False):
if not t1_url and not t2_url:
t1_url, t2_url = tuple(self.other_tracks['local_urls'])
t1, t2 = audio.LocalAudioFile(t1_url), audio.LocalAudioFile(t2_url)
mashup = Mashup('crossmatch', t1, t2)
out = mashup.process_tracks()
if not is_lead:
file_name = "{dir}{name}.mp3".format(dir=PARTIAL_MASHUP_DIR, name=self.output_name)
out.encode(file_name)
self.make_song(t1_url=file_name, t2_url=self.lead_track['local_url'], is_lead=True)
else:
out.encode("{dir}{name}.mp3".format(dir=OUTPUT_DIR, name=self.output_name))
class Mashup(object):
accepted_methods = ['crossmatch']
def __init__(self, method, *tracks):
self.method = method
for i,track in enumerate(tracks):
setattr(self,'t{}'.format(i+1), track)
def process_tracks(self):
if self.method == "crossmatch":
tracks, _beats = match_beat_length(self.t1, self.t2)
beats = (get_beat_tuples(_beats[0]), get_beat_tuples(_beats[1]))
cm = Crossmatch(tracks, beats)
return cm.render()
elif method not in accepted_methods:
raise Exception("You must use one of these valid methods: {}".format(', '.join(accepted_methods)))