class_docstr: Implement the MP3 compression defense approach.
docstr: Apply MP3 compression to sample `x`.
  
  :param x: Sample to compress with shape `(batch_size, length, channel)` or an array of sample arrays with shape
            (length,) or (length, channel).
  :param y: Labels of the sample `x`. This function does not affect them in any way.
  :return: Compressed sample.
code: def __call__(
      self, x: np.ndarray, y: Optional[np.ndarray] = None
  ) -> Tuple[np.ndarray, Optional[np.ndarray]]:
      """
      Apply MP3 compression to sample `x`.
  
      :param x: Sample to compress with shape `(batch_size, length, channel)` or an array of sample arrays with shape
                (length,) or (length, channel).
      :param y: Labels of the sample `x`. This function does not affect them in any way.
      :return: Compressed sample.
      """
  
      def wav_to_mp3(x, sample_rate):
          """
          Apply MP3 compression to audio input of shape (samples, channel).
          """
          from pydub import AudioSegment
          from scipy.io.wavfile import write
  
          x_dtype = x.dtype
          normalized = bool(x.min() >= -1.0 and x.max() <= 1.0)
          if x_dtype != np.int16 and not normalized:
              # input is not of type np.int16 and seems to be unnormalized. Therefore casting to np.int16.
              x = x.astype(np.int16)
          elif x_dtype != np.int16 and normalized:
              # x is not of type np.int16 and seems to be normalized. Therefore undoing normalization and
              # casting to np.int16.
              x = (x * 2**15).astype(np.int16)
  
          tmp_wav, tmp_mp3 = BytesIO(), BytesIO()
          write(tmp_wav, sample_rate, x)
          AudioSegment.from_wav(tmp_wav).export(tmp_mp3)
          audio_segment = AudioSegment.from_mp3(tmp_mp3)
          tmp_wav.close()
          tmp_mp3.close()
          x_mp3 = np.array(
              audio_segment.get_array_of_samples()
          ).reshape((-1, audio_segment.channels))
  
          # WARNING: Sometimes we *still* need to manually resize x_mp3 to original length.
          # This should not be the case, e.g. see https://github.com/jiaaro/pydub/issues/474
          if x.shape[0] != x_mp3.shape[0]:  # pragma: no cover
              logger.warning(
                  "Lengths original input and compressed output don't match. Truncating compressed result."
              )
              x_mp3 = x_mp3[: x.shape[0]]
  
          if normalized:
              # x was normalized. Therefore normalizing x_mp3.
              x_mp3 = x_mp3 * 2**-15
          return x_mp3.astype(x_dtype)
  
      x_orig_type = x.dtype
      if x.dtype != object and x.ndim == 2:
          x = x.astype(object)
  
      if x.dtype != object and x.ndim != 3:
          raise ValueError(
              "Mp3 compression can only be applied to temporal data across at least one channel."
          )
  
      if x.dtype != object and self.channels_first:
          x = np.swapaxes(x, 1, 2)
  
      # apply mp3 compression per audio item
      x_mp3 = x.copy()
      for i, x_i in enumerate(
          tqdm(x, desc="MP3 compression", disable=not self.verbose)
      ):
          x_i_ndim_0 = x_i.ndim
          if x.dtype == object:
              if x_i.ndim == 1:
                  x_i = np.expand_dims(x_i, axis=1)
  
              if x_i_ndim_0 == 2 and self.channels_first:
                  x_i = np.swapaxes(x_i, 0, 1)
  
          x_i = wav_to_mp3(x_i, self.sample_rate)
  
          if x.dtype == object:
              if x_i_ndim_0 == 2 and self.channels_first:
                  x_i = np.swapaxes(x_i, 0, 1)
  
              if x_i_ndim_0 == 1:
                  x_i = np.squeeze(x_i)
  
          x_mp3[i] = x_i
  
      if x.dtype != object and self.channels_first:
          x_mp3 = np.swapaxes(x_mp3, 1, 2)
  
      if x_orig_type != object and x.dtype == object and x.ndim == 2:
          x_mp3 = x_mp3.astype(x_orig_type)
  
      return x_mp3, y
  
file_path: adversarial-robustness-toolbox/art/defences/preprocessor/mp3_compression.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from io import BytesIO
  from typing import Optional, Tuple
  import numpy
  from tqdm.auto import tqdm
  from art.defences.preprocessor.preprocessor import Preprocessor
label_desc: Use image node_id 2 for calling the Mp3Compression obj's underlying member method code with example usage: obj.__call__(x, y) and returns: x_mp3,  y, x_mp3