def validate_cut(c: Cut, read_data: bool = False) -> None: # Validate MixedCut if isinstance(c, MixedCut): assert len( c.tracks ) > 0, f'MonoCut {c.id}: Mixed cut must have at least one track.' for idx, track in enumerate(c.tracks): validate_cut(track.cut, read_data=read_data) assert track.offset >= 0, f'MonoCut: {c.id}: track {idx} has a negative offset.' return # Validate MonoCut and PaddingCut assert c.start >= 0, f'MonoCut {c.id}: start must be 0 or greater (got {c.start})' assert c.duration > 0, f'MonoCut {c.id}: duration must be greater than 0 (got {c.duration})' assert c.sampling_rate > 0, f'MonoCut {c.id}: sampling_rate must be greater than 0 (got {c.sampling_rate})' assert c.has_features or c.has_recording, f'MonoCut {c.id}: must have either Features or Recording attached.' # The rest pertains only to regular Cuts if isinstance(c, PaddingCut): return # Conditions related to features if c.has_features: validate_features(c.features) assert c.channel == c.features.channels if read_data: # We are not passing "read_data" to "validate_features" to avoid loading feats twice; # we'll just validate the subset of the features relevant for the cut. feats = c.load_features() n_fr, n_ft = feats.shape assert c.num_frames == n_fr, f'MonoCut {c.id}: expected num_frames: {c.num_frames}, actual: {n_fr}' assert c.num_features == n_ft, f'MonoCut {c.id}: expected num_features: {c.num_features}, actual: {n_ft}' # Conditions related to recording if c.has_recording: validate_recording(c.recording) assert c.channel in c.recording.channel_ids if read_data: # We are not passing "read_data" to "validate_recording" to avoid loading audio twice; # we'll just validate the subset of the recording relevant for the cut. samples = c.load_audio() assert c.num_samples == samples.shape[1], \ f'MonoCut {c.id}: expected {c.num_samples} samples, got {samples.shape[1]}' # Conditions related to supervisions for s in c.supervisions: validate_supervision(s) assert s.recording_id == c.recording_id, \ f'MonoCut {c.id}: supervision {s.id} has a mismatched recording_id ' \ f'(expected {c.recording_id}, supervision has {s.recording_id})' assert s.channel == c.channel, \ f'MonoCut {c.id}: supervision {s.id} has a mismatched channel ' \ f'(expected {c.channel}, supervision has {s.channel})'
def _read_features(cut: Cut) -> torch.Tensor: return torch.from_numpy(cut.load_features())
def validate_cut(c: Cut, read_data: bool = False) -> None: # Validate MixedCut if isinstance(c, MixedCut): assert (len(c.tracks) > 0), f"MonoCut {c.id}: Mixed cut must have at least one track." for idx, track in enumerate(c.tracks): validate_cut(track.cut, read_data=read_data) assert (track.offset >= 0), f"MonoCut: {c.id}: track {idx} has a negative offset." return # Validate MonoCut and PaddingCut assert c.start >= 0, f"MonoCut {c.id}: start must be 0 or greater (got {c.start})" assert ( c.duration > 0 ), f"MonoCut {c.id}: duration must be greater than 0 (got {c.duration})" assert ( c.sampling_rate > 0 ), f"MonoCut {c.id}: sampling_rate must be greater than 0 (got {c.sampling_rate})" assert ( c.has_features or c.has_recording ), f"MonoCut {c.id}: must have either Features or Recording attached." # The rest pertains only to regular Cuts if isinstance(c, PaddingCut): return # Conditions related to features if c.has_features: validate_features(c.features) assert c.channel == c.features.channels if read_data: # We are not passing "read_data" to "validate_features" to avoid loading feats twice; # we'll just validate the subset of the features relevant for the cut. feats = c.load_features() n_fr, n_ft = feats.shape assert ( c.num_frames == n_fr ), f"MonoCut {c.id}: expected num_frames: {c.num_frames}, actual: {n_fr}" assert ( c.num_features == n_ft ), f"MonoCut {c.id}: expected num_features: {c.num_features}, actual: {n_ft}" # Conditions related to recording if c.has_recording: validate_recording(c.recording) assert c.channel in c.recording.channel_ids if read_data: # We are not passing "read_data" to "validate_recording" to avoid loading audio twice; # we'll just validate the subset of the recording relevant for the cut. samples = c.load_audio() assert ( c.num_samples == samples.shape[1] ), f"MonoCut {c.id}: expected {c.num_samples} samples, got {samples.shape[1]}" # Conditions related to supervisions for s in c.supervisions: validate_supervision(s) assert s.recording_id == c.recording_id, ( f"MonoCut {c.id}: supervision {s.id} has a mismatched recording_id " f"(expected {c.recording_id}, supervision has {s.recording_id})") assert s.channel == c.channel, ( f"MonoCut {c.id}: supervision {s.id} has a mismatched channel " f"(expected {c.channel}, supervision has {s.channel})") # Conditions related to custom fields if c.custom is not None: assert isinstance( c.custom, dict ), f"MonoCut {c.id}: custom field has to be set to a dict or None." for key, value in c.custom.items(): if isinstance(value, Array): validate_array(value, read_data=read_data) elif isinstance(value, TemporalArray): validate_temporal_array(value, read_data=read_data) if not isclose(c.duration, value.duration): logging.warning( f"MonoCut {c.id}: possibly mismatched " f"duration between cut ({c.duration}s) and temporal array " f"in custom field '{key}' (num_frames={value.num_frames} * " f"frame_shift={value.frame_shift} == duration={value.duration})." )