code: # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  from typing import Iterable, List, Optional, Tuple, TypeVar
  
  import numpy as np
  from numpy import ndarray as array
  from paddleaudio.backends import depth_convert
  from paddleaudio.utils import ParameterError
  
  __all__ = [
      'depth_augment',
      'spect_augment',
      'random_crop1d',
      'random_crop2d',
      'adaptive_spect_augment',
  ]
  
  
  def randint(high: int) -> int:
      """Generate one random integer in range [0 high)
  
       This is a helper function for random data augmentaiton
      """
      return int(np.random.randint(0, high=high))
  
  
  def rand() -> float:
      """Generate one floating-point number in range [0 1)
  
      This is a helper function for random data augmentaiton
      """
      return float(np.random.rand(1))
  
  
  def depth_augment(y: array,
                    choices: List = ['int8', 'int16'],
                    probs: List[float] = [0.5, 0.5]) -> array:
      """ Audio depth augmentation
  
      Do audio depth augmentation to simulate the distortion brought by quantization.
      """
      assert len(probs) == len(
          choices
      ), 'number of choices {} must be equal to size of probs {}'.format(
          len(choices), len(probs))
      depth = np.random.choice(choices, p=probs)
      src_depth = y.dtype
      y1 = depth_convert(y, depth)
      y2 = depth_convert(y1, src_depth)
  
      return y2
  
  
  def adaptive_spect_augment(spect: array,
                             tempo_axis: int = 0,
                             level: float = 0.1) -> array:
      """Do adpative spectrogram augmentation
  
      The level of the augmentation is gowern by the paramter level,
      ranging from 0 to 1, with 0 represents no augmentation。
  
      """
      assert spect.ndim == 2., 'only supports 2d tensor or numpy array'
      if tempo_axis == 0:
          nt, nf = spect.shape
      else:
          nf, nt = spect.shape
  
      time_mask_width = int(nt * level * 0.5)
      freq_mask_width = int(nf * level * 0.5)
  
      num_time_mask = int(10 * level)
      num_freq_mask = int(10 * level)
  
      if tempo_axis == 0:
          for _ in range(num_time_mask):
              start = randint(nt - time_mask_width)
              spect[start:start + time_mask_width, :] = 0
          for _ in range(num_freq_mask):
              start = randint(nf - freq_mask_width)
              spect[:, start:start + freq_mask_width] = 0
      else:
          for _ in range(num_time_mask):
              start = randint(nt - time_mask_width)
              spect[:, start:start + time_mask_width] = 0
          for _ in range(num_freq_mask):
              start = randint(nf - freq_mask_width)
              spect[start:start + freq_mask_width, :] = 0
  
      return spect
  
  
  def spect_augment(spect: array,
                    tempo_axis: int = 0,
                    max_time_mask: int = 3,
                    max_freq_mask: int = 3,
                    max_time_mask_width: int = 30,
                    max_freq_mask_width: int = 20) -> array:
      """Do spectrogram augmentation in both time and freq axis
  
      Reference:
  
      """
      assert spect.ndim == 2., 'only supports 2d tensor or numpy array'
      if tempo_axis == 0:
          nt, nf = spect.shape
      else:
          nf, nt = spect.shape
  
      num_time_mask = randint(max_time_mask)
      num_freq_mask = randint(max_freq_mask)
  
      time_mask_width = randint(max_time_mask_width)
      freq_mask_width = randint(max_freq_mask_width)
  
      if tempo_axis == 0:
          for _ in range(num_time_mask):
              start = randint(nt - time_mask_width)
              spect[start:start + time_mask_width, :] = 0
          for _ in range(num_freq_mask):
              start = randint(nf - freq_mask_width)
              spect[:, start:start + freq_mask_width] = 0
      else:
          for _ in range(num_time_mask):
              start = randint(nt - time_mask_width)
              spect[:, start:start + time_mask_width] = 0
          for _ in range(num_freq_mask):
              start = randint(nf - freq_mask_width)
              spect[start:start + freq_mask_width, :] = 0
  
      return spect
  
  
  def random_crop1d(y: array, crop_len: int) -> array:
      """ Do random cropping on 1d input signal
  
      The input is a 1d signal, typically a sound waveform
      """
      if y.ndim != 1:
          'only accept 1d tensor or numpy array'
      n = len(y)
      idx = randint(n - crop_len)
      return y[idx:idx + crop_len]
  
  
  def random_crop2d(s: array, crop_len: int, tempo_axis: int = 0) -> array:
      """ Do random cropping for 2D array, typically a spectrogram.
  
      The cropping is done in temporal direction on the time-freq input signal.
      """
      if tempo_axis >= s.ndim:
          raise ParameterError('axis out of range')
  
      n = s.shape[tempo_axis]
      idx = randint(high=n - crop_len)
      sli = [slice(None) for i in range(s.ndim)]
      sli[tempo_axis] = slice(idx, idx + crop_len)
      out = s[tuple(sli)]
      return out
  
apis: numpy.random.rand numpy.random.randint numpy.random.choice