def run(self, args): d = self.median_filter(ld.LinearDecomposition().load(args.infile), args.window, False) meta = md.FileMetadata(args.infile) for k, data, metadata in d.right(): metadata.activation_input = meta d.save(args.outfile)
def compute(self, s, note, instrument, number_frames=10, frame_skip=2, save_metadata=True): """Builds a basis from the mean of a spectrogram. Uses a part of the spectrogram to compute the mean value. Args: s: Spectrogram object. note: note's name. instrument: instrument's name. number_frames: number of frames to use. Default: 10. frame_skip: number of frames to skip after the attack. Default: 2. save_metadata: flag indicating whether the metadata should be computed. Default: True. Returns: LinearDecomposition object with the window's mean on the left. """ data = s.data # Detects attack energy = numpy.sum(data, 0) energy_peak = numpy.argmax(energy) # Max number of frames availables max_frames = numpy.size(data, 1) # Avoids getting less frames because data ended if energy_peak > (max_frames - number_frames - frame_skip - 1): energy_peak = max_frames - number_frames - frame_skip - 1 # But if there's enough data, skip a few frames after energy peak else: energy_peak += frame_skip # Cuts data data = data[:, energy_peak:energy_peak + number_frames] # Computes the mean data = numpy.array([numpy.mean(data, 1)]).transpose() # Saves metadata input_metadata = md.ObjectMetadata(s) if save_metadata else None # Stores the basis as a decompositon d = ld.LinearDecomposition() d.add((instrument, note), left=data, left_metadata=md.Metadata(method='mean', number_of_frames=number_frames, frame_skip=frame_skip, spectrogram=s.metadata, spectrogram_input=input_metadata)) return d
def extract(self, d, side): """Extracts one side of a linear decomposition. The variables are only assigned, not copied. Any change to one object affects both the input and output. Args: d: LinearDecomposition object. side: name of the side that must be kept. Must be 'left' or 'right'. Returns: new LinearDecomposition object with the other side clear. Raises: ValueError: argument 'side' isn't either 'left' or 'right'. """ new_d = ld.LinearDecomposition() if side == 'left': new_d.data.left = d.data.left new_d.metadata.left = d.metadata.left elif side == 'right': new_d.data.right = d.data.right new_d.metadata.right = d.metadata.right else: raise ValueError("Invalid side '%r'." % side) return new_d
def find_best_elbow(self, args): best_file_name = None best_elbow = -1.0 this_elbow = 0 th_list = [] for filename in args.infile: with open(filename, 'rb') as handler: a = ld.LinearDecomposition().load(handler) # Stack periodicities for all instruments: full_data = None for k in a.data.right.keys(): if full_data is None: full_data = a.data.right[k] else: full_data = numpy.vstack( (full_data,\ a.data.right[k])) frac = numpy.sum(full_data) /\ (full_data.shape[0] * full_data.shape[1]) th_list.append([frac, filename]) th_list.sort(key=lambda x: x[0]) for i in xrange(len(th_list) - 2): this_elbow = self.knee(th_list[i][0], th_list[i+1][0],\ th_list[i+2][0]) if this_elbow > best_elbow: best_elbow = this_elbow best_file_name = th_list[i + 3][1] print best_file_name
def run(self, args): # Loads basis if present if args.basis is not None: b = ld.LinearDecomposition().load(args.basis) else: b = None if args.basis is not None and b.data.right != {}: print "Basis doesn't have empty right side. Ignoring it." # Size of the decomposition (used when finding a basis too) if args.size is None: args.size = [None, None, None] # Simulate 3 values for i in range(len(args.size)): if args.size[i] == 'None' or args.size[i] == 'null': args.size[i] = None # Gather input spectrograms s_list = [] s_meta = [] for filename in args.piece: with open(filename, 'rb') as handler: s_list.append(spectrogram.Spectrogram().load(handler)) s_meta.append(md.FileMetadata(handler)) # Converts arguments size = int(args.size[0]) if args.size[0] is not None else None instrument = args.size[1] if args.size[1] is not None else '' note = args.size[2] if args.size[2] is not None else '' # Decompose d = self.compute(s_list, size, instrument, note, b, args.beta, args.min_delta, args.max_iterations, False) # Associates an activation metadata with its given spectrogram's # metadata for k, data, metadata in d.right(): metadata.spectrogram_input = s_meta[k[-1]] # Checks if basis was provided if b is not None: # If provided, adds it as basis metadata for each activation meta = md.FileMetadata(args.basis) for k, data, metadata in d.right(): metadata.basis_input = meta else: # Otherwise, the basis was computed right now, so we set its # metadata with the list of all spectrograms' metadata d.metadata.left[(args.size[1], args.size[2])].spectrogram_input = \ s_meta d.save(args.outfile)
def run(self, args): d = self.hard_sparsity(ld.LinearDecomposition().load(args.infile), args.sparsity, False) meta = md.FileMetadata(args.infile) for k, data, metadata in d.right(): metadata.activation_input = meta d.save(args.outfile)
def run(self, args): d_list = [] for filename in args.infile: with open(filename, 'rb') as handler: d_list.append(ld.LinearDecomposition().load(handler)) new_d = self.merge(d_list) new_d.save(args.outfile)
def run(self, args): decompositions = [] for filename in args.infile: with open(filename, 'rb') as handler: decompositions.append(ld.LinearDecomposition().load(handler)) for level in self.get_levels(decompositions, args.number_values, args.use_max): print level
def merge(self, decompositions_list): """Merges the linear decompositions given into a single one. Args: decompositions_list: a list of linear decompositions to be merged. Returns: LinearDecomposition object with inputs merged. """ d = ld.LinearDecomposition() for other in decompositions_list: for key, data, metadata in other.left(): d.add(key, left=data, left_metadata=metadata) for key, data, metadata in other.right(): d.add(key, right=data, right_metadata=metadata) return d
def find_best_periodicity(self, args): best_file_name = None best_periodicity = -1.0 this_periodicity = 0.0 for filename in args.infile: with open(filename, 'rb') as handler: a = ld.LinearDecomposition().load(handler) # Stack periodicities for all instruments: full_data = None for k in a.data.right.keys(): if full_data is None: full_data = a.data.right[k] else: full_data = numpy.vstack( (full_data,\ a.data.right[k])) this_periodicity = per.periodicity(full_data, e=args.exponent) if this_periodicity > best_periodicity: best_periodicity = this_periodicity best_file_name = filename print best_file_name
def run(self, args): s = self.convert(ld.LinearDecomposition().load(args.infile), args.instrument, args.frequency, args.minimum_length, False) s.metadata.input = md.FileMetadata(args.infile) s.save(args.outfile)
def run(self, args): d = ld.LinearDecomposition().load(args.infile) new_d = self.extract(d, args.side) new_d.save(args.outfile)
def run(self, args): d = self.compute(ld.LinearDecomposition().load(args.infile)) d.save(args.outfile)
def compute(self, spectrograms, size=None, instrument=None, note=None, basis=None, beta=2., min_delta=0., max_iterations=100, save_metadata=True): """Computes the activation matrix from a basis matrix and a spectrogram. Uses the beta divergence to compute the activations. If min_delta is zero, the code may run faster because no beta divergence is actually computed. Otherwise, the code stops computing if two iterations of the algorithm don't improve the result by more than min_delta. Only one of 'basis' and 'size' arguments may be set, as they specify different things. With 'size', the user extracts both a basis and an activation from the spectrogram, while with 'basis' only an activation is computed. Each activation computed has the same key as the corresponding basis plus the spectrogram's index in the list provided. If a basis is being created, it's name is a tuple of (instrument, note), even if they are None. Args: spectrograms: list of Spectrograms to be merged and used to compute the activations. size: Number of basis to extract from the spectrogram. Must be None if the 'basis' argument is defined. instrument: Name of the instrument. This is used only if size is set. If None, it's ignored. Default: None. note: Name of the note. This is used only if size is set. If None, it's ignored. Default: None. basis: LinearDecomposition object describing the basis to be used. Must be none if the 'size' argument is defined. beta: value for the beta used in divergence. Default: 2. min_delta: threshold for early stop. Default: 0. max_iterations: maximum number of iterations to use. Default: 100. save_metadata: flag indicating whether the metadata should be computed. Default: True. Returns: LinearDecomposition object with basis and activations for the spectrograms. Raises: ValueError: matrices have incompatible sizes. """ # Check arguments compatibility if size is None and basis is None: raise ValueError("One of 'size' or 'basis' must not be None.") if basis is not None and size is not None: raise ValueError("Only one of 'size' or 'basis' must not be None.") # Saves metadata if save_metadata: s_meta = [md.ObjectMetadata(s) for s in spectrograms] else: s_meta = [None for s in spectrograms] # Marks the limits of each spectrogram X_start = [0] for s in spectrograms: X_start.append(X_start[-1]+s.data.shape[1]) # Merges spectrograms X = numpy.hstack([s.data for s in spectrograms]) # If we have a basis, we only need to compute the activations if basis is not None: # Merges basis but keep track where each one starts so that it can # be used to characterize the activations B = [] B_start = [0] for k, data, metadata in basis.left(): B.append(data) B_start.append(B_start[-1]+data.shape[1]) B = numpy.hstack(B) # Saves metadata if save_metadata: b_meta = md.ObjectMetadata(B) else: b_meta = None # Initilizes activations A = numpy.ones((B.shape[1], X.shape[1])) # Computes the activation self.compute_activation(X, B, A, beta, min_delta, max_iterations) # Starts creating the decomposition object d = ld.LinearDecomposition() # Copy the left stuff from the basis, since they came from there d.data.left = basis.data.left d.metadata.left = basis.metadata.left # Cuts the activation. For each combination of basis and # spectrograms, we get an activation i = 0 for k, data, metadata in basis.left(): for j in range(len(spectrograms)): # Since spectrograms don't have name, we call it by its # sequence number s_name = (j,) # Cuts the activation A_cut = A[B_start[i]:B_start[i+1], X_start[j]:X_start[j+1]] # Merges the basis key with the spectrogram name to create a # key for the activation. Then stores a lot of metadata # about what was used to compute it. d.add(k+s_name, right=A_cut, right_metadata=md.Metadata( method="beta_nmf", beta=beta, min_delta=min_delta, max_iterations=max_iterations, spectrogram_input=s_meta[j], spectrogram=s.metadata, basis_input=b_meta, basis=metadata)) # Increase basis iterator i += 1 else: # Everyone gets the same matrices to work with every time, so we # avoid consistency problems. However, we can't have the same values # filling the matrices or the algorithm can't separate the basis and # activations (everyone keeps getting the same value). numpy.random.seed(0) B = numpy.random.rand(X.shape[0], size) A = numpy.random.rand(size, X.shape[1]) # Computes both basis and activations self.compute_both(X, B, A, beta, min_delta, max_iterations) # Key for the basis created key = (instrument, note) # Starts creating the decomposition object d = ld.LinearDecomposition() # Adds basis d.add(key, left=B, left_metadata=md.Metadata( method="beta_nmf", beta=beta, min_delta=min_delta, max_iterations=max_iterations, spectrogram_input=s_meta, spectrogram=[s.metadata for s in spectrograms])) # Adds the activations cutted to match the spectrograms for j in range(len(spectrograms)): # Since spectrograms don't have name, we call it by its sequence # number s = spectrograms[j] s_name = (j,) # Cuts the activation A_cut = A[:, X_start[j]:X_start[j+1]] # Merges the basis key with the spectrogram name to create a key # for the activation. Then stores a lot of metadata about what # was used to compute it. d.add(key+s_name, right=A_cut, right_metadata=md.Metadata( method="beta_nmf", beta=beta, min_delta=min_delta, max_iterations=max_iterations, spectrogram_input=s_meta[j], spectrogram=s.metadata)) return d