class_docstr: Shift the samples forwards or backwards, with or without rollover
code: def apply(
      self, samples: NDArray[np.float32], sample_rate: int
  ) -> NDArray[np.float32]:
      if self.shift_unit == "samples":
          num_places_to_shift = self.parameters["shift_amount"]
      elif self.shift_unit == "fraction":
          num_places_to_shift = int(
              round(self.parameters["shift_amount"] * samples.shape[-1])
          )
      elif self.shift_unit == "seconds":
          num_places_to_shift = int(
              round(self.parameters["shift_amount"] * sample_rate)
          )
      else:
          raise ValueError("invalid shift_unit")
  
      shifted_samples = np.roll(samples, num_places_to_shift, axis=-1)
  
      if not self.rollover:
          if num_places_to_shift > 0:
              shifted_samples[..., :num_places_to_shift] = 0.0
          elif num_places_to_shift < 0:
              shifted_samples[..., num_places_to_shift:] = 0.0
  
      if self.fade:
          fade_length = int(sample_rate * self.fade_duration)
          fade_in, fade_out = get_crossfade_mask_pair(fade_length)
  
          if num_places_to_shift > 0:
              fade_in_start = num_places_to_shift
              fade_in_end = min(
                  num_places_to_shift + fade_length,
                  shifted_samples.shape[-1],
              )
              fade_in_length = fade_in_end - fade_in_start
  
              shifted_samples[
                  ...,
                  fade_in_start:fade_in_end,
              ] *= fade_in[:fade_in_length]
  
              if self.rollover:
                  fade_out_start = max(
                      num_places_to_shift - fade_length, 0
                  )
                  fade_out_end = num_places_to_shift
                  fade_out_length = fade_out_end - fade_out_start
  
                  shifted_samples[
                      ..., fade_out_start:fade_out_end
                  ] *= fade_out[-fade_out_length:]
  
          elif num_places_to_shift < 0:
              positive_num_places_to_shift = (
                  shifted_samples.shape[-1] + num_places_to_shift
              )
  
              fade_out_start = max(
                  positive_num_places_to_shift - fade_length, 0
              )
              fade_out_end = positive_num_places_to_shift
              fade_out_length = fade_out_end - fade_out_start
  
              shifted_samples[
                  ..., fade_out_start:fade_out_end
              ] *= fade_out[-fade_out_length:]
  
              if self.rollover:
                  fade_in_start = positive_num_places_to_shift
                  fade_in_end = min(
                      positive_num_places_to_shift + fade_length,
                      shifted_samples.shape[-1],
                  )
                  fade_in_length = fade_in_end - fade_in_start
                  shifted_samples[
                      ...,
                      fade_in_start:fade_in_end,
                  ] *= fade_in[:fade_in_length]
  
      return shifted_samples
  
file_path: audiomentations/audiomentations/augmentations/shift.py
imports: import random
  from typing import Union
  import numpy
  from numpy.typing import NDArray
  from audiomentations.core.transforms_interface import BaseWaveformTransform
  from audiomentations.core.utils import get_crossfade_mask_pair
label_desc: Use image node_id 3 for calling the Shift obj's underlying member method code with example usage: obj.apply(samples, sample_rate) and returns: shifted_samples