PyGame Sound шумы при воспроизведении фрагментов звука, в чем проблема?

Рейтинг: 0Ответов: 1Опубликовано: 21.02.2023

Пишу приложение для создания анимации, есть необходимость нарезки звука на фрагменты соответствующие кадрам анимации. Для этих целей использую PyGame mixer Sound. При воспроизведении этих фрагментов возникают шумы. При сборке фрагментов в новый звук происходит следующее:

  • если собирать от первого до последнего, то звук получается чистый
  • если НЕ от первого до последнего, получается грязный или один шум
  • если от первого НЕ до последнего, получается чистый звук

Причем такое происходит не со всеми WAV файлами, с одними вообще нет проблем, а с другими всё вышеописанное. В чем причина и как с ней бороться?

Дополнение: заметил, что на шумы влияет изменение переменной SPF (количество семплов на кадр), вероятно имеет влияние длина оглавления файла или длина семплов.


Ссылка на звук с которым НЕТ ПРОБЛЕМ.

Ссылка на звук С ПРОБЛЕМАМИ

Пример воспроизводимого кода:

import os.path
import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QMainWindow, QLabel,QFileDialog, QApplication
from pygame import mixer
from pygame.mixer import Sound

class Window(QMainWindow):

    def __init__(self):
        super().__init__()
        mixer.init()
        self.label = QLabel('Click me!', self)
        self.label.setStyleSheet('font-size: 20px')
        self.label.setGeometry(10,10,480,280)
        self.setFixedWidth(500)
        self.setFixedHeight(300)

        # необходимые переменные
        self.FPS = 12  # предустановленная скорость кадров в секунду
        self.Frame_Count = 25  # предустановленное количество кадров
        self.Current_Frame = 0  # текущий кадр
        self.Frame_List = []  # список для нарезанных звуков в кадры
        self.collect_arr = None # переменная для сборки фрагментов звука
        self.interval = [0,24] # значения диапазона для сборки фрагментов звука от 0 до 24

        self.show()

    def mousePressEvent(self, event):
        self.Frame_List = []  # очищаем список
        self.collect_arr = None # очищаем сборку
        PathTuple = QFileDialog.getOpenFileName(None, 'Open file', '', "wav file (*.wav)")
        if PathTuple[0] != '':
            txt_lbl = os.path.basename(PathTuple[0] + '\n')
            snd = Sound(PathTuple[0]) # объект звук из файла
            snd_arr = snd.get_raw() # получаем битовый массив звука
            samples = len(snd_arr) # длина - количество семплов
            txt_lbl += str(samples) + ' семплов\n'
            duration = snd.get_length()  # продолжительнось звука
            txt_lbl += str(duration) + ' длительность\n'
            SPF = int((samples / duration) / self.FPS)  # семплов в одном кадре
            txt_lbl += str(SPF) + ' семплов в кадре\n'

            for i in range(self.Frame_Count): # цикл от 0 до количества кадров
                if i == 0: # добавляем первый фрагмент звука
                    self.Frame_List.append(snd_arr[ :SPF])  # добавляем в список срез массива для каждого кадра
                self.Frame_List.append(snd_arr[i*SPF : (i+1)*SPF])  # далее ОТ значения i ПО i+1

                if i >= self.interval[0] and i <= self.interval[1]: # делаем сборку из фрагментов в заданном диапазоне
                    if self.collect_arr == None:
                        self.collect_arr = snd_arr[i*SPF : (i+1)*SPF]
                    else:
                        self.collect_arr = self.collect_arr + snd_arr[i*SPF : (i+1)*SPF]

            self.timer = QTimer() # создаем таймер
            self.timer.start(84) # запускаем с интервалом соответствующим 12 кадрам в секунду
            self.timer.timeout.connect(self.play_animation_sound) # отправляем сигнал в слот
            txt_lbl += 'ВОСПРОИЗВЕДЕНИЕ\n'

            self.label.setText(str(txt_lbl))  # выводим информацию в лейбл

    def play_animation_sound(self):
        Sound(self.Frame_List[self.Current_Frame]).play() # воспроизводим фрагмент текущего кадра
        self.Current_Frame += 1 # переходим в следующий кадр
        if self.Current_Frame >= 25: # по достижении последнего кадра
            self.timer.stop() # останавливаем таймер
            self.Current_Frame = 0 # возвращаемся в нулевой кадр
            self.label.setText(self.label.text() + '\nВоспроизведение сборки')  # выводим информацию в лейбл
            Sound(self.collect_arr).play() # воспроизводим сборку диапазона

app = QApplication(sys.argv)
app.setApplicationName("Window")
window = Window()
app.exec_()

Ответы

▲ 0

В чем причина возникновения шумов - я так и не разобрался, но проблема устранилась следующим образом: вместо округления SPF с помощью int нужно использовать round.

Строку SPF = int((samples / duration) / self.FPS) # семплов в одном кадре

заменить на SPF = round((samples / duration) / self.FPS) # семплов в одном кадре

Для примера, если без округления получилось 14699,99976238...

int просто обрезает дробную часть 14699

а round округляет по математическим правилам 14700