code: def make_transformer_src_mask(
      src: torch.Tensor,
      causal: bool = False,
      dynchunktrain_config: Optional[DynChunkTrainConfig] = None,
  ) -> Optional[torch.Tensor]:
      """Prepare the source transformer mask that restricts which frames can
      attend to which frames depending on causal or other simple restricted
      attention methods.
  
      Arguments
      ---------
      src: torch.Tensor
          The source tensor to build a mask from. The contents of the tensor are
          not actually used currently; only its shape and other metadata (e.g.
          device).
  
      causal: bool
          Whether strict causality shall be used. Frames will not be able to
          attend to any future frame.
  
      dynchunktrain_config: DynChunkTrainConfig, optional
          Dynamic Chunk Training configuration. This implements a simple form of
          chunkwise attention. Incompatible with `causal`."""
  
      if causal:
          assert dynchunktrain_config is None
          return get_lookahead_mask(src)
  
      if dynchunktrain_config is not None:
          # init a mask that masks nothing by default
          # 0 == no mask, 1 == mask
          src_mask = torch.zeros(
              (src.shape[1], src.shape[1]),
              device=src.device,
              dtype=torch.bool,
          )
  
          # The following is not really the sole source used to implement this,
          # but it helps introduce the concept.
          # ref: Unified Streaming and Non-streaming Two-pass End-to-end Model
          # for Speech Recognition
          # https://arxiv.org/pdf/2012.05481.pdf
  
          timesteps = src.size(1)
  
          # mask the future at the right of each chunk
          for t in range(timesteps):
              # if we have a chunk size of 8 then:
              # for 0..7  -> mask 8..
              # for 8..15 -> mask 16..
              # etc.
              next_chunk_index = (
                  t // dynchunktrain_config.chunk_size
              ) + 1
              visible_range = (
                  next_chunk_index * dynchunktrain_config.chunk_size
              )
              src_mask[t, visible_range:] = True
  
          # mask the past at the left of each chunk (accounting for left context)
          # only relevant if using left context
          if not dynchunktrain_config.is_infinite_left_context():
              for t in range(timesteps):
                  chunk_index = t // dynchunktrain_config.chunk_size
                  chunk_first_t = (
                      chunk_index * dynchunktrain_config.chunk_size
                  )
  
                  left_context_frames = (
                      dynchunktrain_config.left_context_size
                      * dynchunktrain_config.chunk_size
                  )
  
                  frame_remaining_context = max(
                      0,
                      chunk_first_t - left_context_frames,
                  )
  
                  # end range is exclusive, so there is no off-by-one here
                  src_mask[t, :frame_remaining_context] = True
  
          return src_mask
  
      return None
  
imports: from dataclasses import dataclass
  import torch
  from torch import nn
  from typing import Any, Optional
  from speechbrain.nnet.linear import Linear
  from speechbrain.nnet.containers import ModuleList
  from speechbrain.lobes.models.transformer.Transformer import TransformerInterface, get_lookahead_mask, get_key_padding_mask, NormalizedEmbedding
  from speechbrain.nnet.activations import Swish
  from speechbrain.dataio.dataio import length_to_mask
  from speechbrain.utils.dynamic_chunk_training import DynChunkTrainConfig
label_desc: Use image node_id 1 for calling a global function with example usage: make_transformer_src_mask(src, causal, dynchunktrain_config) and returns: None, get_lookahead_mask, src_mask