Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • TISMIR
  • WASPAA23
  • vPhD
4 results

Target

Select target project
  • a23marmo/autosimilarity_segmentation
1 result
Select Git revision
  • main
  • TISMIR
  • WASPAA23
  • vPhD
4 results
Show changes
Showing
with 750 additions and 5693 deletions
In the files vol.py and sivm_search.py, in the folder ~\AppData\Local\Continuum\anaconda3\envs\neural_net\lib\site-packages\msaf\pymf\ (using Anaconda to handle the MSAF distribution), I had to change:
from scipy.misc import factorial
into:
try:
from scipy.misc import factorial
except:
from scipy.special import factorial
\ No newline at end of file
This diff is collapsed.
......@@ -16,9 +16,7 @@ A tutorial notebook presenting the most important components of this toolbox is
## Experimental notebook ##
Experimental notebooks are available in the folder "Notebooks". They present the code used to compute the main experiments of the paper, in order to improve the reproducibility. Please tell me if any problem would appear when trying to launch them.
Experimental Notebooks requires some pre-computed data to work, which can be found on zenodo: https://zenodo.org/records/10168387. DOI: 10.5281/zenodo.10168386.
A Tutorial notebook is presented in the "Notebooks" folder. In older version of the code, you may find Notebooks presenting experiments associated with publications.
## Data ##
......@@ -40,7 +38,7 @@ In the IEEE style, this should be cited as: A. Marmoret, J.E. Cohen, and F. Bimb
## Credits ##
Code was created by Axel Marmoret (<axel.marmoret@gmail.com>), and strongly supported by Jeremy E. Cohen (<jeremy.cohen@cnrs.fr>).
Code was created by Axel Marmoret (<axel.marmoret@imt-atlantique.fr>), and strongly supported by Jeremy E. Cohen (<jeremy.cohen@cnrs.fr>).
The technique in itself was also developed by Frédéric Bimbot (<bimbot@irisa.fr>).
......
......@@ -172,52 +172,6 @@ def convolutionnal_cost(cropped_autosimilarity, kernels):
#return np.mean(np.multiply(kern,cropped_autosimilarity))
return np.sum(np.multiply(kern,cropped_autosimilarity)) / p**2
def compute_cbm_sum_normalization(autosimilarity, min_size = 1, max_size = 32, penalty_weight = 1, penalty_func = "modulo8", bands_number = None):
scores = [-math.inf for i in range(len(autosimilarity))]
segments_best_starts = [None for i in range(len(autosimilarity))]
segments_best_starts[0] = 0
scores[0] = 0
kernels = compute_all_kernels(max_size, bands_number = bands_number)
max_conv_eight = np.amax(convolution_entire_matrix_computation(autosimilarity, kernels))
for current_idx in range(1, len(autosimilarity)): # Parse all indexes of the autosimilarity
for possible_start_idx in possible_segment_start(current_idx, min_size = min_size, max_size = max_size):
if possible_start_idx < 0:
raise err.ToDebugException("Invalid value of start index, shouldn't happen.") from None
# Convolutionnal cost between the possible start of the segment and the current index (entire segment)
cropped_autosimilarity = autosimilarity[possible_start_idx:current_idx,possible_start_idx:current_idx]
kern = kernels[len(cropped_autosimilarity)]
if np.sum(kern) == 0:
conv_cost = 0
else:
conv_cost = np.sum(np.multiply(kern,cropped_autosimilarity)) / (np.sum(kern) + len(cropped_autosimilarity))
segment_length = current_idx - possible_start_idx
penalty_cost = penalty_cost_from_arg(penalty_func, segment_length)
this_segment_cost = conv_cost * segment_length - penalty_cost * penalty_weight * max_conv_eight
# Note: conv_eight is not normalized by its size (not a problem in itself as size is contant, but generally not specified in formulas).
if possible_start_idx == 0: # Avoiding errors, as scores values are initially set to -inf.
if this_segment_cost > scores[current_idx]: # This segment is of larger score
scores[current_idx] = this_segment_cost
segments_best_starts[current_idx] = 0
else:
if scores[possible_start_idx] + this_segment_cost > scores[current_idx]: # This segment is of larger score
scores[current_idx] = scores[possible_start_idx] + this_segment_cost
segments_best_starts[current_idx] = possible_start_idx
segments = [(segments_best_starts[len(autosimilarity) - 1], len(autosimilarity) - 1)]
precedent_frontier = segments_best_starts[len(autosimilarity) - 1] # Because a segment's start is the previous one's end.
while precedent_frontier > 0:
segments.append((segments_best_starts[precedent_frontier], precedent_frontier))
precedent_frontier = segments_best_starts[precedent_frontier]
if precedent_frontier == None:
raise err.ToDebugException("Well... The dynamic programming algorithm took an impossible path, so it failed. Understand why.") from None
return segments[::-1], scores[-1]
def convolution_entire_matrix_computation(autosimilarity_array, kernels, kernel_size = 8):
"""
Computes the convolution measure on the entire autosimilarity matrix, with a defined and fixed kernel size.
......@@ -331,163 +285,88 @@ def possible_segment_start(idx, min_size = 1, max_size = None):
else:
return []
# %% Sandbox
def dynamic_convolution_computation_test_line(autosimilarity, line_conv_weight = 1, min_size = 2, max_size = 36, novelty_kernel_size = 16, penalty_weight = 1, penalty_func = "modulo8", convolution_type = "eight_bands"):
"""
Segmentation algo with inline convolution test, doesn't work that much in practice.
"""
costs = [-math.inf for i in range(len(autosimilarity))]
segments_best_starts = [None for i in range(len(autosimilarity))]
segments_best_starts[0] = 0
costs[0] = 0
kernels = compute_all_kernels(max_size, convolution_type = convolution_type)
full_kernels = compute_full_kernels(max_size, convolution_type = convolution_type)
#novelty = novelty_computation(autosimilarity, novelty_kernel_size)
conv_eight = convolution_entire_matrix_computation(autosimilarity, kernels)
for current_idx in range(1, len(autosimilarity)): # Parse all indexes of the autosimilarity
for possible_start_idx in possible_segment_start(current_idx, min_size = min_size, max_size = max_size):
if possible_start_idx < 0:
raise err.ToDebugException("Invalid value of start index.")
# Convolutionnal cost between the possible start of the segment and the current index (entire segment)
conv_cost = convolutionnal_cost(autosimilarity[possible_start_idx:current_idx,possible_start_idx:current_idx], kernels)
# Novelty cost, computed with a fixed kernel (doesn't make sense otherwise), on the end of the segment
#nov_cost = novelty[current_idx]
# %% Scikit-learn class
# Author: Axel Marmoret
#
# Adapted from: https://scikit-learn.org/stable/auto_examples/developing_estimators/sklearn_is_fitted.html, Author: Kushan <kushansharma1@gmail.com>
#
# License: BSD 3 clause
segment_length = current_idx - possible_start_idx
penalty_cost = penalty_cost_from_arg(penalty_func, segment_length)
current_line_conv_max = 0
# if possible_start_idx >= segment_length:
# for before_start in range(0, possible_start_idx - segment_length + 1):
# line_conv_cost = convolutionnal_cost(autosimilarity[possible_start_idx:current_idx,before_start:before_start + segment_length], full_kernels)
# if line_conv_cost > current_line_conv_max:
# current_line_conv_max = line_conv_cost
# if current_idx + segment_length < len(autosimilarity):
# for after_start in range(current_idx, len(autosimilarity) - segment_length):
# line_conv_cost = convolutionnal_cost(autosimilarity[possible_start_idx:current_idx,after_start:after_start + segment_length], full_kernels)
# if line_conv_cost > current_line_conv_max:
# current_line_conv_max = line_conv_cost
mat_vec = []
if possible_start_idx >= segment_length:
for before_start in range(0, possible_start_idx - segment_length + 1):
mat_vec.append(autosimilarity[possible_start_idx:current_idx,before_start:before_start + segment_length].flatten())
if current_idx + segment_length < len(autosimilarity):
for after_start in range(current_idx, len(autosimilarity) - segment_length):
mat_vec.append(autosimilarity[possible_start_idx:current_idx,after_start:after_start + segment_length].flatten())
if mat_vec == []:
current_line_conv_max = 0
else:
kern = full_kernels[segment_length]
convs_on_line = np.matmul(kern.reshape(1,segment_length**2), np.array(mat_vec).T)
current_line_conv_max = np.amax(convs_on_line) / segment_length**2
from sklearn.base import BaseEstimator, ClassifierMixin
this_segment_cost = (conv_cost + line_conv_weight * current_line_conv_max) * segment_length - penalty_cost * penalty_weight * np.max(conv_eight)
# Note: the length of the segment does not appear in conv_eight (not a problem in itself as size is contant, but generally not specified in formulas).
# Avoiding errors, as segment_cost are initially set to -inf.
if possible_start_idx == 0:
if this_segment_cost > costs[current_idx]:
costs[current_idx] = this_segment_cost
segments_best_starts[current_idx] = 0
else:
if costs[possible_start_idx] + this_segment_cost > costs[current_idx]:
costs[current_idx] = costs[possible_start_idx] + this_segment_cost
segments_best_starts[current_idx] = possible_start_idx
import as_seg.autosimilarity_computation as as_comp
import as_seg.data_manipulation as dm
segments = [(segments_best_starts[len(autosimilarity) - 1], len(autosimilarity) - 1)]
precedent_frontier = segments_best_starts[len(autosimilarity) - 1] # Because a segment's start is the previous one's end.
while precedent_frontier > 0:
segments.append((segments_best_starts[precedent_frontier], precedent_frontier))
precedent_frontier = segments_best_starts[precedent_frontier]
if precedent_frontier == None:
raise err.ToDebugException("Well... Viterbi took an impossible path, so it failed. Understand why.") from None
return segments[::-1], costs[-1]
class CBMEstimator(BaseEstimator, ClassifierMixin):
"""
Scikit-learn class for the CBM algorithm. May be used for practicity, following the scikit-learn API.
"""
def __init__(self, similarity_function="cosine", max_size=32, penalty_weight=1, penalty_func="modulo8", bands_number=7):
"""
Constructor of the CBM estimator.
Parameters
----------
similarity_function : string, optional
The similarity function to use for computing the autosimilarity.
The default is "cosine".
max_size : integer, optional
The maximal size of segments.
The default is 32.
penalty_weight : float, optional
The ponderation parameter for the penalty function.
The default is 1.
penalty_func : string, optional
The type of penalty function to use.
The default is "modulo8".
bands_number : positive integer or None, optional
The number of bands in the kernel.
For the full kernel, bands_number must be set to None
(or higher than the maximal size, but cumbersome)
See [1] for details.
The default is 7.
"""
self.similarity_function = similarity_function
self.max_size = max_size
self.penalty_weight = penalty_weight
self.penalty_func = penalty_func
self.bands_number = bands_number
self.algorithm_name = "CBM"
def predict(self, barwise_features):
"""
Perform Predictions
def compute_all_kernels_oldway(max_size, convolution_type = "full"):
If the estimator is not fitted, then raise NotFittedError
"""
DEPRECATED but some ideas may be worth the shot.
ssm_matrix = as_comp.switch_autosimilarity(barwise_features, similarity_type=self.similarity_function)
segments = compute_cbm(ssm_matrix, max_size=self.max_size, penalty_weight=self.penalty_weight,
penalty_func=self.penalty_func, bands_number = self.bands_number)[0]
return segments
Precomputes all kernels of size 0 ([0]) to max_size, and feed them to the Dynamic Progamming algorithm.
def predict_in_seconds(self, barwise_features, bars):
"""
Perform Predictions, and convert the segments from bars to seconds.
This is used for acceleration purposes.
If the estimator is not fitted, then raise NotFittedError
"""
segments = self.predict(barwise_features)
return dm.segments_from_bar_to_time(segments, bars)
Parameters
----------
max_size : integer
The maximal size (included) for kernels.
convolution_type: string
The type of convolution. (to explicit)
Possibilities are :
- "full" : squared matrix entirely composed of one, except on the diagonal where it's zero.
The associated convolution cost for a segment (b_1, b_2) will be
.. math::
c_{b_1,b_2} = \\frac{1}{b_2 - b_1 + 1}\\sum_{i,j = 0, i \\ne j}^{n - 1} a_{i + b_1, j + b_1}
- "4_bands" : squared matrix where the only nonzero values are ones on the
4 upper- and 4 sub-diagonals surrounding the main diagonal.
The associated convolution cost for a segment (b_1, b_2) will be
.. math::
c_{b_1,b_2} = \\frac{1}{b_2 - b_1 + 1}\\sum_{i,j = 0, 1 \\leq |i - j| \\leq 4}^{n - 1} a_{i + b_1, j + b_1}
- "mixed" : sum of both previous kernels, i.e. values are zero on the diagonal,
2 on the 4 upper- and 4 sub-diagonals surrounding the main diagonal, and 1 elsewhere.
The associated convolution cost for a segment (b_1, b_2) will be
.. math::
c_{b_1,b_2} = \\frac{1}{b_2 - b_1 + 1}(2*\\sum_{i,j = 0, 1 \\leq |i - j| \\leq 4}^{n - 1} a_{i + b_1, j + b_1} \\ + \sum_{i,j = 0, |i - j| > 4}^{n - 1} a_{i + b_1, j + b_1})
def predict_in_seconds_this_autosimilarity(self, ssm_matrix, bars):
"""
Perform Predictions on a given autosimilarity matrix, and convert the segments from bars to seconds.
Returns
-------
kernels : array of arrays (which are kernels)
All the kernels, of size 0 ([0]) to max_size.
If the estimator is not fitted, then raise NotFittedError
"""
segments = compute_cbm(ssm_matrix, max_size=self.max_size, penalty_weight=self.penalty_weight,
penalty_func=self.penalty_func, bands_number = self.bands_number)[0]
return dm.segments_from_bar_to_time(segments, bars)
def score(self, predictions, annotations):
"""
kernels = [[0]]
for p in range(1,max_size + 1):
if p < 4:
kern = np.ones((p,p)) - np.identity(p)
# elif convolution_type == "7_bands" or convolution_type == "mixed_7_bands":
# if p < 8:
# kern = np.ones((p,p)) - np.identity(p)
# else:
# # Diagonal where only the six subdiagonals surrounding the main diagonal is one
# k = np.array([np.ones(p-7),np.ones(p-6),np.ones(p-5),np.ones(p-4),np.ones(p-3),np.ones(p-2),np.ones(p-1),np.zeros(p),np.ones(p-1),np.ones(p-2),np.ones(p-3),np.ones(p-4),np.ones(p-5),np.ones(p-6),np.ones(p-7)], dtype=object)
# offset = [-7,-6,-5,-4,-3,-2,-1,0,1,2,3, 4, 5, 6, 7]
# if convolution_type == "14_bands":
# kern = diags(k,offset).toarray()
# else:
# kern = np.ones((p,p)) - np.identity(p) + diags(k,offset).toarray()
else:
if convolution_type == "full":
# Full kernel (except for the diagonal)
kern = np.ones((p,p)) - np.identity(p)
elif convolution_type == "4_bands":
# Diagonal where only the eight subdiagonals surrounding the main diagonal is one
k = np.array([np.ones(p-4),np.ones(p-3),np.ones(p-2),np.ones(p-1),np.zeros(p),np.ones(p-1),np.ones(p-2),np.ones(p-3),np.ones(p-4)],dtype=object)
offset = [-4,-3,-2,-1,0,1,2,3,4]
kern = diags(k,offset).toarray()
elif convolution_type == "mixed":
# Sum of both previous kernels
k = np.array([np.ones(p-4),np.ones(p-3),np.ones(p-2),np.ones(p-1),np.zeros(p),np.ones(p-1),np.ones(p-2),np.ones(p-3),np.ones(p-4)],dtype=object)
offset = [-4,-3,-2,-1,0,1,2,3,4]
kern = np.ones((p,p)) - np.identity(p) + diags(k,offset).toarray()
elif convolution_type == "3_bands":
# Diagonal where only the six subdiagonals surrounding the main diagonal is one
k = np.array([np.ones(p-3),np.ones(p-2),np.ones(p-1),np.zeros(p),np.ones(p-1),np.ones(p-2),np.ones(p-3)],dtype=object)
offset = [-3,-2,-1,0,1,2,3]
kern = diags(k,offset).toarray()
elif convolution_type == "mixed_3_bands":
# Sum of both previous kernels
k = np.array([np.ones(p-3),np.ones(p-2),np.ones(p-1),np.zeros(p),np.ones(p-1),np.ones(p-2),np.ones(p-3)],dtype=object)
offset = [-3,-2,-1,0,1,2,3]
kern = np.ones((p,p)) - np.identity(p) + diags(k,offset).toarray()
else:
raise err.InvalidArgumentValueException(f"Convolution type not understood: {convolution_type}.")
kernels.append(kern)
return kernels
Compute the score of the predictions
"""
close_tolerance = dm.compute_score_of_segmentation(annotations, predictions, window_length=0.5)
large_tolerance = dm.compute_score_of_segmentation(annotations, predictions, window_length=3)
return close_tolerance, large_tolerance
\ No newline at end of file
......@@ -2,9 +2,8 @@ from . import autosimilarity_computation
from . import barwise_input
from . import data_manipulation
from . import CBM_algorithm
#from . import foote_novelty
from .model import current_plot
from .model import common_plot
from .model import dataloaders
from .model import errors
from .model import signal_to_spectrogram
from .model import display_results
......@@ -12,10 +12,8 @@ See [1 - Chapter 2.4] or [2] for more information.
References
----------
[1] Unsupervised Machine Learning Paradigms for the Representation of Music Similarity and Structure,
PhD Thesis Marmoret Axel
(not uploaded yet but will be soon!)
(You should check the website hal.archives-ouvertes.fr/ in case this docstring is not updated with the reference.)
[1] Marmoret, A. (2022). Unsupervised Machine Learning Paradigms for the Representation of Music Similarity and Structure (Doctoral dissertation, Université Rennes 1).
https://theses.hal.science/tel-04589687
[2] Marmoret, A., Cohen, J.E, and Bimbot, F., "Barwise Compression Schemes
for Audio-Based Music Structure Analysis"", in: 19th Sound and Music Computing Conference,
......@@ -31,6 +29,19 @@ import librosa
# %% Spectrograms to tensors
# !!! Be extremely careful with the organization of modes, which can be either Frequency-Time at barscale-Bars (FTB) or Bars-Frequency-Time at barscale (BFT) depending on the method.
def spectrogram_to_tensor_barwise(spectrogram, bars, hop_length_seconds, subdivision, mode_order="BFT", subset_nb_bars = None):
"""
Spectrogram to tensor-spectrogram, with the order of modes defined by the mode_order parameter.
"""
if mode_order == "BFT":
return tensorize_barwise_BFT(spectrogram, bars, hop_length_seconds, subdivision, subset_nb_bars)
elif mode_order == "FTB":
return tensorize_barwise_FTB(spectrogram, bars, hop_length_seconds, subdivision, subset_nb_bars)
else:
raise err.InvalidArgumentValueException(f"Unknown mode order: {mode_order}.")
def tensorize_barwise_BFT(spectrogram, bars, hop_length_seconds, subdivision, subset_nb_bars = None):
"""
Returns a 3rd order tensor-spectrogram from the original spectrogram and bars starts and ends.
......@@ -123,6 +134,9 @@ def tensorize_barwise_FTB(spectrogram, bars, hop_length_seconds, subdivision, su
# %% Tensors to spectrograms
def tensor_barwise_to_spectrogram(tensor, mode_order = "BFT", subset_nb_bars = None):
"""
Return a spectrogram from a tensor-spectrogram, with the order of modes defined by the mode_order parameter.
"""
if subset_nb_bars is not None:
tensor = barwise_subset_this_tensor(tensor, subset_nb_bars, mode_order = mode_order)
......@@ -136,6 +150,9 @@ def tensor_barwise_to_spectrogram(tensor, mode_order = "BFT", subset_nb_bars = N
raise err.InvalidArgumentValueException(f"Unknown mode order: {mode_order}.")
def barwise_subset_this_tensor(tensor, subset_nb_bars, mode_order = "BFT"):
"""
Keep only the subset_nb_bars first bars in the tensor.
"""
if mode_order == "BFT":
return tensor[:subset_nb_bars]
......@@ -146,6 +163,9 @@ def barwise_subset_this_tensor(tensor, subset_nb_bars, mode_order = "BFT"):
raise err.InvalidArgumentValueException(f"Unknown mode order: {mode_order}.")
def get_this_bar_tensor(tensor, bar_idx, mode_order = "BFT"):
"""
Return one particular bar of the tensor.
"""
if mode_order == "BFT":
return tensor[bar_idx]
......@@ -182,6 +202,9 @@ def barwise_TF_matrix(spectrogram, bars, hop_length_seconds, subdivision, subset
return tl.unfold(tensor_spectrogram, 0)
def barwise_subset_this_TF_matrix(matrix, subset_nb_bars):
"""
Keep only the subset_nb_bars first bars in the Barwise TF matrix.
"""
assert subset_nb_bars is not None
return matrix[:subset_nb_bars]
......@@ -211,6 +234,9 @@ def TF_vector_to_spectrogram(vector, frequency_dimension, subdivision):
return tl.fold(vector, 0, (frequency_dimension,subdivision))
def TF_matrix_to_spectrogram(matrix, frequency_dimension, subdivision, subset_nb_bars = None):
"""
Encapsulating the conversion from a Barwise TF matrix to a spectrogram.
"""
spectrogram_content = None
if subset_nb_bars is not None:
matrix = barwise_subset_this_TF_matrix(matrix, subset_nb_bars)
......@@ -222,10 +248,13 @@ def TF_matrix_to_spectrogram(matrix, frequency_dimension, subdivision, subset_nb
# Tensor to Barwise TF
def tensor_barwise_to_barwise_TF(tensor, mode_order = "BFT"):
"""
Return the Barwise TF matrix from a tensor-spectrogram, with the order of modes defined by the mode_order parameter.
"""
# Barmode: 0 for BTF, 2 for FTB
if mode_order == "BFT": # Checked
if mode_order == "BFT":
return tl.unfold(tensor, 0)
elif mode_order == "FTB": # Checked
elif mode_order == "FTB":
return tl.unfold(tensor, 2)
else:
raise err.InvalidArgumentValueException(f"Unknown mode order: {mode_order}.")
......
......@@ -59,7 +59,27 @@ def get_bars_from_audio(song_path):
downbeats_times.append(song_length) # adding the last downbeat
return frontiers_to_segments(downbeats_times)
def get_beats_from_audio_madmom(song_path):
"""
Uses madmom to estimate the beats of a song, from its audio signal.
"""
act = bt.TCNBeatProcessor()(song_path)
proc = bt.BeatTrackingProcessor(fps=100)
song_beats = proc(act)
# beats_times = []
# if song_beats[0][1] != 1: # Adding a first downbeat at the start of the song
# beats_times.append(0.1)
# for beat in song_beats:
# if beat[1] == 1: # If the beat is a downbeat
# downbeats_times.append(beat[0])
return frontiers_to_segments(list(song_beats))
def get_beats_from_audio_msaf(signal, sr, hop_length):
"""
Uses MSAF to estimate the beats of a song, from its audio signal.
"""
_, audio_percussive = librosa.effects.hpss(signal)
# Compute beats
......@@ -76,23 +96,6 @@ def get_beats_from_audio_msaf(signal, sr, hop_length):
return beat_times, beat_frames
# %% Read and treat inputs
def get_beats_from_audio_madmom(song_path):
"""
TODO
"""
act = bt.TCNBeatProcessor()(song_path)
proc = bt.BeatTrackingProcessor(fps=100)
song_beats = proc(act)
# beats_times = []
# if song_beats[0][1] != 1: # Adding a first downbeat at the start of the song
# beats_times.append(0.1)
# for beat in song_beats:
# if beat[1] == 1: # If the beat is a downbeat
# downbeats_times.append(beat[0])
return frontiers_to_segments(list(song_beats))
def get_segmentation_from_txt(path, annotations_type):
"""
Reads the segmentation annotations, and returns it in a list of tuples (start, end, index as a number)
......@@ -671,6 +674,9 @@ def compute_rates_of_segmentation(reference, segments_in_time, window_length = 0
# %% High level encapsulation of the computation of scores, based on segments.
## Tolerances are MIREX standards in time (0.5s and 3s), or 0 and 1 bar when barwise aligned.
def get_scores_from_segments_in_time(segments_in_time, ref_tab):
"""
Computes the scores of the segmentation from the segments in time and the references when references may be multiple.
"""
if type(ref_tab[0][0]) != np.ndarray: # ref_tab consist in the references, and should be nested in an array (for consistency).
ref_tab = [ref_tab]
......@@ -689,10 +695,16 @@ def get_scores_from_segments_in_time(segments_in_time, ref_tab):
return res
def get_scores_in_time_from_barwise_segments(segments, bars, ref_tab):
"""
Computes the scores of the segmentation from the segments in bar indexes and the references.
"""
segments_in_time = segments_from_bar_to_time(segments, bars)
return get_scores_from_segments_in_time(segments_in_time, ref_tab)
def get_scores_in_bars_from_barwise_segments(segments, bars, ref_tab):
"""
Get scores from segments in bar indexes and references, with tolerance expressed in bars.
"""
res = -math.inf * np.ones((2, 3))
if type(ref_tab[0][0]) != np.ndarray: # ref_tab consist in the references, and should be nested in an array (for consistency between double anntoations in SALAMI and single in RWC).
......@@ -715,6 +727,9 @@ def get_scores_in_bars_from_barwise_segments(segments, bars, ref_tab):
return res
def get_scores_switch_time_alignment(time_alignment, segments, bars, ref_tab):
"""
Get scores from segments, where the tolerance may be expressed in seconds (absolute time) or in bars (barwise aligned).
"""
if type(ref_tab[0][0]) != np.ndarray: # ref_tab consist in the references, and should be nested in an array (for consistency).
ref_tab = [ref_tab]
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.