def forward(self, x):
        """
        @param x: 16kHz input waveform, shape (batch, seq_len),
        where seq_len can be arbitrary if segmenting_in_forward is True, and must be 122880 if segmenting_in_forward is False

        @return: predicted MOS score, range 1..5, shape (batch,)
        """
        # segmenting / padding
        if not self.segmenting_in_forward:
            assert (
                x.shape[1] == SEQ_LEN
            ), f"input shape {x.shape} does not match SEQ_LEN={SEQ_LEN}"
        else:
            wav_overlength = x.shape[1] - SEQ_LEN
            if wav_overlength < 0:
                x = F.pad(x, (0, -wav_overlength))
                wav_overlength = 0
            num_hops = int(np.ceil(wav_overlength / MAX_HOP_LEN)) + 1
            rel_crop_region_start = list(np.linspace(0, 1, num_hops))
            wav_all = [
                x[:, int(c * wav_overlength) : int(c * wav_overlength) + SEQ_LEN]
                for c in rel_crop_region_start
            ]
            x = torch.cat(wav_all, dim=0)  # concatenate along batch dimension

        # normalization
        x = x / (torch.max(torch.abs(x), dim=1, keepdim=True).values + 1e-8)

        # NN processing
        feat = self.cnn(x)
        feat = feat.permute(0, 2, 1)
        norm_qual = self.transformer_pool_attn(feat)

        if self.segmenting_in_forward:
            norm_qual = norm_qual.reshape(num_hops, -1, 1)
            norm_qual = torch.mean(norm_qual, dim=0)

        return 1 + 4 * norm_qual

        @param x: 16kHz input waveform, shape (batch, seq_len),
        where seq_len can be arbitrary if segmenting_in_forward is True, and must be 122880 if segmenting_in_forward is False

        @return: predicted MOS score, range 1..5, shape (batch,)
        
speechscore/scores/distill_mos/sqa.py