def get_song_meta(song_filename, chunk_size): music_file = audio_decoder.open(song_filename) sample_rate = music_file.getframerate() num_channels = music_file.getnchannels() sample_width = music_file.getsampwidth() frame = music_file.readframes(1) filename = os.path.basename(song_filename) dirname = os.path.dirname(song_filename) config_cache, fft_cache = check_cache_exists(dirname, filename) # TODO(mdietz): Try to get an id3 tag so we can get album and title meta = { "filename": filename, "path": dirname, "sample_rate": sample_rate, "num_channels": num_channels, "sample_width": sample_width, "frame_width": sample_width * num_channels, "config_cache": config_cache, "fft_cache": fft_cache, "chunk_size": chunk_size } meta.update(fetch_id3_meta(song_filename)) music_file.close() return meta
def cache_song(song_filename, chunk_size): music_file = audio_decoder.open(song_filename) sample_rate = music_file.getframerate() num_channels = music_file.getnchannels() logging.info("Sample rate: %s" % sample_rate) logging.info("Channels: %s" % num_channels) logging.info("Frame size: %s" % music_file.getsampwidth()) fft_calc = fft.FFT(chunk_size, sample_rate, hc.GPIOLEN, _MIN_FREQUENCY, _MAX_FREQUENCY, _CUSTOM_CHANNEL_MAPPING, _CUSTOM_CHANNEL_FREQUENCIES) # Init cache matrix cache_matrix = np.empty(shape=[0, hc.GPIOLEN]) cache_filename = os.path.dirname(song_filename) + "/." + os.path.basename( song_filename) + ".sync" cache_found = fft_calc.compare_config(cache_filename) if cache_found: mean, std, cache_matrix = load_cached_fft(fft_calc, cache_filename) else: # The values 12 and 1.5 are good estimates for first time playing back # (i.e. before we have the actual mean and standard deviations # calculated for each channel). mean = [12.0] * hc.GPIOLEN std = [1.5] * hc.GPIOLEN total = 0 while True: data = music_file.readframes(chunk_size) if not data: break total += len(data) matrix = fft_calc.calculate_levels(data) # Add the matrix to the end of the cache cache_matrix = np.vstack([cache_matrix, matrix]) for i in range(0, hc.GPIOLEN): std[i] = np.std([item for item in cache_matrix[:, i] if item > 0]) mean[i] = np.mean( [item for item in cache_matrix[:, i] if item > 0]) # Add mean and std to the top of the cache cache_matrix = np.vstack([mean, cache_matrix]) cache_matrix = np.vstack([std, cache_matrix]) # Save the cache using numpy savetxt np.savetxt(cache_filename, cache_matrix) # Save fft config fft_calc.save_config() logging.info("Cached sync data written to '." + cache_filename + "' [" + str(len(cache_matrix)) + " rows]") logging.info("Cached config data written to '." + fft_calc.config_filename) music_file.close() return mean, std, cache_matrix
def __init__(self, song_filename, chunk_size): music_file = audio_decoder.open(song_filename) self._chunk_size = chunk_size # TODO(mdietz): We can get this from the cache, too self.sample_rate = music_file.getframerate() self.num_channels = music_file.getnchannels() self.sample_width = music_file.getsampwidth() # Just a vanity metric chunk_period = float(self._chunk_size) / float(self.sample_rate) logging.info("Playing: %s" % song_filename) logging.info("Sample Rate: %d" % self.sample_rate) logging.info("Number of Channels: %d" % self.num_channels) logging.info("Chunk size: %d" % self._chunk_size) logging.info("Chunk period: %f" % chunk_period) self._stream = music_file
def cache_song(song_filename, chunk_size): music_file = audio_decoder.open(song_filename) sample_rate = music_file.getframerate() num_channels = music_file.getnchannels() logging.info("Sample rate: %s" % sample_rate) logging.info("Channels: %s" % num_channels) logging.info("Frame size: %s" % music_file.getsampwidth()) fft_calc = fft.FFT(chunk_size, sample_rate, hc.GPIOLEN, _MIN_FREQUENCY, _MAX_FREQUENCY, _CUSTOM_CHANNEL_MAPPING, _CUSTOM_CHANNEL_FREQUENCIES) # Init cache matrix cache_matrix = np.empty(shape=[0, hc.GPIOLEN]) cache_filename = os.path.dirname(song_filename) + "/." + os.path.basename( song_filename) + ".sync" cache_found = fft_calc.compare_config(cache_filename) if cache_found: mean, std, cache_matrix = load_cached_fft(fft_calc, cache_filename) else: # The values 12 and 1.5 are good estimates for first time playing back # (i.e. before we have the actual mean and standard deviations # calculated for each channel). mean = [12.0] * hc.GPIOLEN std = [1.5] * hc.GPIOLEN total = 0 while True: data = music_file.readframes(chunk_size) if not data: break total += len(data) matrix = fft_calc.calculate_levels(data) # Add the matrix to the end of the cache cache_matrix = np.vstack([cache_matrix, matrix]) for i in range(0, hc.GPIOLEN): std[i] = np.std([item for item in cache_matrix[:, i] if item > 0]) mean[i] = np.mean([item for item in cache_matrix[:, i] if item > 0]) # Add mean and std to the top of the cache cache_matrix = np.vstack([mean, cache_matrix]) cache_matrix = np.vstack([std, cache_matrix]) # Save the cache using numpy savetxt np.savetxt(cache_filename, cache_matrix) # Save fft config fft_calc.save_config() logging.info("Cached sync data written to '." + cache_filename + "' [" + str(len(cache_matrix)) + " rows]") logging.info("Cached config data written to '." + fft_calc.config_filename) music_file.close() return mean, std, cache_matrix