def segment_specs(y, seg_length=15, seg_hop=4, max_length=None):
    """Segments a spectrogram into smaller segments for input to a CNN. 
    Each segment includes neighboring frequency bins to preserve 
    contextual information.

    Args:
        y (torch.Tensor): Input spectrogram tensor of shape [B, H, W], 
                          where B is batch size, H is number of mel bands, 
                          and W is the length of the spectrogram.
        seg_length (int): Length of each segment (must be odd). Default is 15.
        seg_hop (int): Hop length for segmenting the spectrogram. Default is 4.
        max_length (int, optional): Maximum number of windows allowed. If the number of 
                                     windows exceeds this, a ValueError is raised.

    Returns:
        torch.Tensor: Segmented tensor with shape [B*n, C, H, seg_length], where n is the 
                      number of segments, C is the number of channels (always 1).
    
    Raises:
        ValueError: If seg_length is even or if the number of windows exceeds max_length.
    """
    # Ensure segment length is odd
    if seg_length % 2 == 0:
        raise ValueError('seg_length must be odd! (seg_length={})'.format(seg_length))
    
    # Convert input to tensor if it's not already
    if not torch.is_tensor(y):
        y = torch.tensor(y)

    B, _, _ = y.size()  # Extract batch size and dimensions
    for b in range(B):
        x = y[b, :, :]  # Extract the current batch's spectrogram
        n_wins = x.shape[1] - (seg_length - 1)  # Calculate number of windows
        
        # Segment the mel-spectrogram
        idx1 = torch.arange(seg_length)  # Indices for segment length
        idx2 = torch.arange(n_wins)  # Indices for number of windows
        idx3 = idx1.unsqueeze(0) + idx2.unsqueeze(1)  # Create indices for segments
        x = x.transpose(1, 0)[idx3, :].unsqueeze(1).transpose(3, 2)  # Rearrange dimensions for CNN input

        # Adjust segments based on hop length
        if seg_hop > 1:
            x = x[::seg_hop, :]  # Downsample segments
            n_wins = int(np.ceil(n_wins / seg_hop))  # Update number of windows

        # Pad the segments if max_length is specified
        if max_length is not None:
            if max_length < n_wins:
                raise ValueError('n_wins {} > max_length {}. Increase max window length max_segments!'.format(n_wins, max_length))
            x_padded = torch.zeros((max_length, x.shape[1], x.shape[2], x.shape[3]))  # Create a padded tensor
            x_padded[:n_wins, :] = x  # Fill the padded tensor with the segments
            x = x_padded  # Update x to the padded tensor

        # Concatenate segments from each batch
        if b == 0:
            z = x.unsqueeze(0)  # Initialize z for the first batch
        else:
            z = torch.cat((z, x.unsqueeze(0)), axis=0)  # Concatenate to z

    # Reshape the final tensor for output
    B, n, c, f, t = z.size()
    z = z.view(B * n, c, f, t)  # Combine batch and segment dimensions
    return z  # Return the segmented spectrogram tensor
Segments a spectrogram into smaller segments for input to a CNN. 
    Each segment includes neighboring frequency bins to preserve 
    contextual information.

    Args:
        y (torch.Tensor): Input spectrogram tensor of shape [B, H, W], 
                          where B is batch size, H is number of mel bands, 
                          and W is the length of the spectrogram.
        seg_length (int): Length of each segment (must be odd). Default is 15.
        seg_hop (int): Hop length for segmenting the spectrogram. Default is 4.
        max_length (int, optional): Maximum number of windows allowed. If the number of 
                                     windows exceeds this, a ValueError is raised.

    Returns:
        torch.Tensor: Segmented tensor with shape [B*n, C, H, seg_length], where n is the 
                      number of segments, C is the number of channels (always 1).
    
    Raises:
        ValueError: If seg_length is even or if the number of windows exceeds max_length.
    
clearvoice/clearvoice/models/mossformer_gan_se/discriminator.py