Пример #1
0
    def run(self):
        for oqueue, settings in zip(self.oqueues, self.settings):
            e = Lame(oqueue=oqueue, **settings)
            self.encoders.append(e)
            e.start()

        try:
            self.ctime = None
            for i, actions in enumerate(self.loop()):
                log.info("Rendering audio data for %d actions.", len(actions))
                for a in actions:
                    try:
                        with Timer() as t:
                            #   TODO: Move the "multiple encoding" support into
                            #   LAME itself - it should be able to multiplex the
                            #   streams itself.
                            self.encoders[0].add_pcm(a)
                            self.infoqueue.put(generate_metadata(a))
                        log.info("Rendered in %fs!", t.ms)
                    except:
                        log.error("Could not render %s. Skipping.\n%s", a,
                                  traceback.format_exc())
                gc.collect()
        except:
            log.error("Something failed in mixer.run:\n%s",
                      traceback.format_exc())
            self.stop()
            return
Пример #2
0
	def run(self):
		database.reset_played()
		self.encoder = Lame(oqueue=self.oqueue)
		self.encoder.start()

		try:
			self.ctime = None
			for actions in self.generate_tracks():
				log.info("Rendering audio data for %d actions.", len(actions))
				for a in actions:
					try:
						with Timer() as t:
							#   TODO: Move the "multiple encoding" support into
							#   LAME itself - it should be able to multiplex the
							#   streams itself.
							self.encoder.add_pcm(a)
							if self.infoqueue: self.infoqueue.put(generate_metadata(a))
						log.info("Rendered in %fs!", t.ms)
					except Exception:
						log.error("Could not render %s. Skipping.\n%s SEE???", a,
								  traceback.format_exc())
				gc.collect()
		except Exception:
			log.error("Something failed in mixer.run:\n%s",
					  traceback.format_exc())
			self.stop()
			return
Пример #3
0
def audition_render(actions, filename):
	"""Calls render on each action in actions, concatenates the results,
	and renders an audio file"""
	print("Calling render()!")
	print(actions)
	print(filename)
	encoder = Lame(ofile=open(filename, 'wb'))
	encoder.start()
	for a in actions:
		print("add_pcm: %r"%a)
		encoder.add_pcm(a)
	encoder.finish()
	print("render() finished!")
Пример #4
0
            async def ensure_playing(self):
                async with self.cond:
                    if not self.load_future:

                        print('Waiting to play %s' % trackId)
                        self.audio_fetcher.semaphore.acquire()
                        print('Playing %s' % trackId)

                        self.lame = Lame(**lame_args)
                        self.lame.init_params()

                        self.audio_fetcher.sink.target = self

                        load_future = self.audio_fetcher.player.load(
                            SpotifyId(trackId))
                        self.load_future = asyncio.futures.wrap_future(
                            load_future, loop=self.audio_fetcher.loop)

                        def done_cb(fut):
                            x = asyncio.run_coroutine_threadsafe(
                                self._load_complete(fut.exception()),
                                loop=self.audio_fetcher.loop)

                        self.load_future.add_done_callback(done_cb)
Пример #5
0
def build_entire_track(dest):
	"""Build the entire-track file, saving to dest"""
	with open(dest,"wb") as f:
		encoder = Lame(ofile=f)
		print("Building...")
		encoder.start()
		mixer = Mixer(None, None)
		for idx,track in enumerate(database.get_many_mp3(order_by="sequence,id")):
			print("Adding [%d]: ##%d %s (%r)"%(idx,track.id,track.track_details["artist"],track.filename))
			mixer.add_track(track)
		for actions in mixer.generate_tracks():
			print("Encoder: Got %d actions"%len(actions))
			for a in actions:
				print("Encoder: Adding %r"%(a,))
				encoder.add_pcm(a)
		encoder.finish()
		print("Build complete.")
Пример #6
0
class Mixer(multiprocessing.Process):
	def __init__(self, oqueue, infoqueue):
		self.infoqueue = infoqueue

		self.encoder = None
		self.oqueue = oqueue

		self.__track_lock = threading.Lock()
		self.__tracks = []

		self.transition_time = 30 if not test else 5
		self.__stop = False

		multiprocessing.Process.__init__(self)

	@property
	def tracks(self):
		self.__track_lock.acquire()
		tracks = self.__tracks
		self.__track_lock.release()
		return tracks

	@tracks.setter
	def tracks(self, new_val):
		self.__track_lock.acquire()
		self.__tracks = new_val
		self.__track_lock.release()

	@property
	def current_track(self):
		return self.tracks[0]

	def get_stream(self, x):
		for fname in (x.filename, "audio/"+x.filename):
			if os.path.isfile(fname):
				return fname
		# TODO: Fetch the contents from the database and save to fname
		raise NotImplementedError

	def analyze(self, x):
		if isinstance(x, list):
			return [self.analyze(y) for y in x]
		if isinstance(x, AudioData):
			return self.process(x)
		if isinstance(x, tuple):
			return self.analyze(*x)

		log.info("Grabbing stream [%r]...", x.id)
		saved = database.get_analysis(x.id)
		laf = LocalAudioStream(self.get_stream(x), saved)
		if not saved:
			database.save_analysis(x.id, base64.b64encode(cPickle.dumps(laf.analysis,-1)))
		setattr(laf, "_metadata", x)
		return self.process(laf)

	def add_track(self, track):
		self.tracks.append(self.analyze(track))

	def process(self, track):
		if not hasattr(track.analysis.pyechonest_track, "title"):
			setattr(track.analysis.pyechonest_track, "title", track._metadata.track_details['title'])
		log.info("Resampling features [%r]...", track._metadata.id)
		if len(track.analysis.beats):
			track.resampled = resample_features(track, rate='beats')
			track.resampled['matrix'] = timbre_whiten(track.resampled['matrix'])
		else:
			log.info("no beats returned for this track.")
			track.resampled = {"rate":'beats', "matrix": []}

		track.gain = self.__db_2_volume(track.analysis.loudness)
		log.info("Done processing [%r].", track._metadata.id)
		return track

	def __db_2_volume(self, loudness):
		return (1.0 - LOUDNESS_THRESH * (LOUDNESS_THRESH - loudness) / 100.0)

	def generate_tracks(self):
		"""Yield a series of lists of track segments - helper for run()"""
		while len(self.tracks) < 2:
			log.info("Waiting for a new track.")
			track = database.get_track_to_play()
			try:
				self.add_track(track)
				log.info("Got a new track.")
			except Exception: # TODO: Why?
				log.error("Exception while trying to add new track:\n%s",
					traceback.format_exc())

		# Initial transition. 
		# yield initialize(self.tracks[0], self.tracks[1])

		mixer_state = {}

		while not self.__stop:
			while len(self.tracks) > 1:
				tra = managed_transition(self.tracks[0],
					self.tracks[1], mixer_state)
				del self.tracks[0].analysis
				gc.collect()
				yield tra
				log.debug("Finishing track 0 [%r]",self.tracks[0])
				from datetime import datetime
				now = datetime.now().time()
				self.tracks[0].finish()
				del self.tracks[0]
				gc.collect()
			if self.infoqueue is None: break # Hack: If we're not in infinite mode, don't wait for more tracks.
			log.info("Waiting for a new track.")
			try:
				self.add_track(database.get_track_to_play())
				log.info("Got a new track.")
			except ValueError:
				log.warning("Track too short! Trying another.")
			except Exception:
				log.error("Got an Exception while trying to add new track:\n%s",
					traceback.format_exc())

		log.error("Stopping!")
		# Last chunk. Should contain 1 instruction: fadeout.
		# CJA 20150227: Seems to be broken. Commenting this out may mean we ignore the
		# last track's transition info when building MajorGlitch.mp3, but this is not
		# serious. The track itself is correctly rendered; it will simply go on until
		# it reaches the end, and then stop, as per the King's advice.
		# yield terminate(self.tracks[-1], FADE_OUT)

	def run(self):
		database.reset_played()
		self.encoder = Lame(oqueue=self.oqueue)
		self.encoder.start()

		try:
			self.ctime = None
			for actions in self.generate_tracks():
				log.info("Rendering audio data for %d actions.", len(actions))
				for a in actions:
					try:
						with Timer() as t:
							#   TODO: Move the "multiple encoding" support into
							#   LAME itself - it should be able to multiplex the
							#   streams itself.
							self.encoder.add_pcm(a)
							if self.infoqueue: self.infoqueue.put(generate_metadata(a))
						log.info("Rendered in %fs!", t.ms)
					except Exception:
						log.error("Could not render %s. Skipping.\n%s SEE???", a,
								  traceback.format_exc())
				gc.collect()
		except Exception:
			log.error("Something failed in mixer.run:\n%s",
					  traceback.format_exc())
			self.stop()
			return

	def stop(self):
		self.__stop = True

	@property
	def stopped(self):
		return self.__stop
Пример #7
0
        class reader:
            def __init__(self, audio_fetcher):
                self.audio_fetcher = audio_fetcher
                self.lame = None
                self.buf = b''
                self.load_future = None
                self.finished = False
                self.error = False
                self.cond = asyncio.Condition()

            async def ensure_playing(self):
                async with self.cond:
                    if not self.load_future:

                        print('Waiting to play %s' % trackId)
                        self.audio_fetcher.semaphore.acquire()
                        print('Playing %s' % trackId)

                        self.lame = Lame(**lame_args)
                        self.lame.init_params()

                        self.audio_fetcher.sink.target = self

                        load_future = self.audio_fetcher.player.load(
                            SpotifyId(trackId))
                        self.load_future = asyncio.futures.wrap_future(
                            load_future, loop=self.audio_fetcher.loop)

                        def done_cb(fut):
                            x = asyncio.run_coroutine_threadsafe(
                                self._load_complete(fut.exception()),
                                loop=self.audio_fetcher.loop)

                        self.load_future.add_done_callback(done_cb)

            async def read(self, offset, length, full=False):
                await self.ensure_playing()

                async with self.cond:
                    min_buf_size = offset + length if full else offset + 1

                    # Wait until: Enough data is available -OR- the strean is complete -OR- there was an error
                    await self.cond.wait_for(
                        lambda: self.finished or len(self.buf) >= min_buf_size)

                    # raise exception if there was an error before the desired chunk was fetched
                    if len(self.buf) < min_buf_size:
                        self.load_future.result()

                    # return the desired chunk
                    return self.buf[offset:offset + length]

            async def _load_chunk(self, buf):
                #Append data to encoding
                encoded = self.lame.encode_buffer(buf)
                async with self.cond:
                    self.buf += encoded
                    self.cond.notify_all()

            async def _load_complete(self, error):
                print('Audio stream ended:', trackId)

                # Release audio_fetcher to play next track
                self.audio_fetcher.sink.target = None
                self.audio_fetcher.semaphore.release()

                #Finish encoding
                encoded = self.lame.encode_flush_nogap()

                async with self.cond:
                    self.buf += encoded
                    self.finished = True
                    if self.error is None and error:
                        self.error = error
                    self.cond.notify_all()
                    print('Audio stream ended2')

            async def close(self):
                print('File reader closed for %s' % trackId)
                async with self.cond:
                    if not self.finished:
                        self.error = asyncio.CancelledError()
                        if self.load_future:
                            self.audio_fetcher.player.stop()

            async def wait(self):
                await self.ensure_playing()
                async with self.cond:
                    await self.cond.wait_for(lambda: self.finished)
                    if self.error:
                        raise Exception("Failed to fetch music")
                    return self.buf