def get_undirected_interval_grade(self, chorale): key = chorale.analyze('key') chorale_distribution = histogram_to_distribution( get_interval_histogram(chorale, directed=False)) dataset_distribution = self.distributions[ f'{key.mode}_undirected_interval_distribution'] u, v, u_weights, v_weights = distributions_to_wasserstein_inputs( chorale_distribution, dataset_distribution) return wasserstein_distance(u, v, u_weights, v_weights)
def get_harmonic_quality_grade(self, chorale): key = chorale.analyze('key') chorale_distribution = histogram_to_distribution( get_harmonic_quality_histogram(chorale)) dataset_distribution = self.distributions[ f'{key.mode}_harmonic_quality_distribution'] u, v, u_weights, v_weights = distributions_to_wasserstein_inputs( chorale_distribution, dataset_distribution) return wasserstein_distance(u, v, u_weights, v_weights)
def get_B_directed_interval_grade(self, chorale): key = chorale.analyze('key') voice_ih = get_SATB_interval_histogram(chorale, voice=3, directed=True) chorale_distribution = histogram_to_distribution(voice_ih) dataset_distribution = self.distributions[ f'{key.mode}_B_directed_interval_distribution'] u, v, u_weights, v_weights = distributions_to_wasserstein_inputs( chorale_distribution, dataset_distribution) return wasserstein_distance(u, v, u_weights, v_weights)
def get_rhythm_grade(self, chorale): """ Arguments chorale: music21.stream.Stream Returns Wasserstein distance between normalized chorale rhythm distribution and normalized dataset rhythm distribution """ chorale_distribution = histogram_to_distribution( get_rhythm_histogram(chorale)) dataset_distribution = self.distributions['rhythm_distribution'] u, v, u_weights, v_weights = distributions_to_wasserstein_inputs( chorale_distribution, dataset_distribution) return wasserstein_distance(u, v, u_weights, v_weights)
def get_note_grade(self, chorale): """ Arguments chorale: music21.stream.Stream Returns Wasserstein distance between normalized chorale note distribution and normalized dataset note distribution """ key = chorale.analyze('key') chorale_distribution = histogram_to_distribution( get_note_histogram(chorale, key)) dataset_distribution = self.distributions[ f'{key.mode}_note_distribution'] u, v, u_weights, v_weights = distributions_to_wasserstein_inputs( chorale_distribution, dataset_distribution) return wasserstein_distance(u, v, u_weights, v_weights)
def get_error_grade(self, chorale): num_notes = len(chorale.flat.notes) chorale_histogram = get_error_histogram(chorale, self.voice_ranges) num_errors = sum(chorale_histogram.values()) # if num_errors == 0, the coefficient will be 0, so we can sidestep the calculation of wasserstein if num_errors == 0: return 0 chorale_distribution = histogram_to_distribution(chorale_histogram) dataset_distribution = self.distributions['error_distribution'] error_note_ratio = num_errors / num_notes u, v, u_weights, v_weights = distributions_to_wasserstein_inputs( chorale_distribution, dataset_distribution) return wasserstein_distance(u, v, u_weights, v_weights) * ( error_note_ratio / self.error_note_ratio)