2016-04-05 7 views
2

Как удалить звуки «popping» и «click» в аудио, созданные путем объединения звуковых звуковых звуковых клипов вместе?Как удалить всплывающие подсказки из конкатенированных звуковых данных в PyAudio

У меня есть этот PyAudio код для генерации ряда тонов:

import time 
import math 
import pyaudio 

class Beeper(object): 

    def __init__(self, **kwargs): 
     self.bitrate = kwargs.pop('bitrate', 16000) 
     self.channels = kwargs.pop('channels', 1) 
     self._p = pyaudio.PyAudio() 
     self.stream = self._p.open(
      format = self._p.get_format_from_width(1), 
      channels = self.channels, 
      rate = self.bitrate, 
      output = True, 
     ) 
     self._queue = [] 

    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     self.stream.stop_stream() 
     self.stream.close() 

    def tone(self, frequency, length=1000, play=False, **kwargs): 

     number_of_frames = int(self.bitrate * length/1000.) 

     ##TODO:fix pops? 
     g = get_generator() 
     for x in xrange(number_of_frames): 
      self._queue.append(chr(int(math.sin(x/((self.bitrate/float(frequency))/math.pi))*127+128))) 

    def play(self): 
     sound = ''.join(self._queue) 
     self.stream.write(sound) 
     time.sleep(0.1) 

with Beeper(bitrate=88000, channels=2) as beeper: 
    i = 0 
    for f in xrange(1000, 800-1, int(round(-25/2.))): 
     i += 1 
     length = log(i+1) * 250/2./2. 
     beeper.tone(frequency=f, length=length) 
    beeper.play() 

, но при изменении тона, есть отличительная «поп» в аудио, и я не знаю, как удалить его.

Во-первых, я думал, что поп происходит, потому что я сразу играл в каждый клип, и время между каждым воспроизведением, когда я генерирую клип, было достаточным для задержки, чтобы звук был плоским. Однако, когда я конкатенировал все клипы в одну строку и играл в нее, поп все еще был там.

Затем я думал, что синусоидальные волны не совпадают на границах для каждого клипа, поэтому я попытался усреднить первые N кадров текущего аудиоклипа с последними N кадрами предыдущего клипа, но это также не имел никакого эффекта.

Что я делаю неправильно? Как это исправить?

+0

вы смотрели ли на сигнал еще? –

+0

Угадайте здесь .. Возможно, изолируйте простой и единственный звуковой сигнал. Звуковой усилитель включен и выключается. Также 88000 казался высокой скоростью передачи битов. Это чириканье? Битовая кодированная амплитуда напряжения, где в качестве частотной полосы частот используется точность. – wbg

ответ

0

Если вы соединяете клипы разных атрибутов, вы можете услышать щелчок, если пики двух клипов в точках конкатенации не совпадают.

Один из способов обойти это - сделать Fade-out в конце первого сигнала, а затем fade-in в начале второго сигнала. затем продолжите эту схему через остаток процесса конкатенации. Check here Подробнее о Fading.

Я бы попробовал конкатенацию в визуальных инструментах, таких как Audacity, попробуйте Fade-out и fade-in на клипах, на которые вы хотите присоединиться и поиграть со временем и настройками, чтобы получить желаемые результаты.

Далее, я не уверен pyAudio имеет любой простой способ реализации fading, однако, если вы можете, вы можете попробовать pyDub. Он предоставляет простые способы управления аудио. Он имеет как методы Fade-in, так и Fade-out, а также метод cross-fade, который в основном выполняет как затухание, так и выход за один шаг.

Вы можете установить pydub в pip install pydub

Вот пример кода для pyDub:

from pydub import AudioSegment 
from pydub.playback import play 

#Load first audio segment 
audio1 = AudioSegment.from_wav("SineWave_440Hz.wav") 

#Load second audio segment 
audio2 = AudioSegment.from_wav("SineWave_150Hz.wav") 

# 1.5 second crossfade 
combinedAudio= audio1.append(audio2, crossfade=1500) 

#Play combined Audio 
play(combinedAudio) 

Наконец, если вы действительно хотите, чтобы шум/POPS освобоженные на профессиональном классе, вы можете посмотрите на PSOLA (Pitch Synchronous Overlap and Add). Здесь можно преобразовать аудиосигналы в frequency domain, а затем выполнить PSOLA на кусках, чтобы объединить звук с минимальным возможным шумом.

Это было долго, но надеюсь, что это поможет.

1

Мое первоначальное подозрение, что отдельные сигналы не были согласованы, было правильным, что я подтвердил, проверив в Audacity. Мое решение состояло в том, чтобы изменить код для запуска и остановки каждого сигнала на пике синусоидальной волны.

def tone(self, frequency, length=1000, play=False, **kwargs): 

    number_of_frames = int(self.bitrate * length/1000.) 

    record = False 
    x = 0 
    y = 0 
    while 1: 
     x += 1 
     v = math.sin(x/((self.bitrate/float(frequency))/math.pi)) 

     # Find where the sin tip starts. 
     if round(v, 3) == +1: 
      record = True 

     if record: 
      self._queue.append(chr(int(v*127+128))) 
      y += 1 
      if y > number_of_frames and round(v, 3) == +1: 
       # Always end on the high tip of the sin wave to clips align. 
       break 
2

Ответ, который вы написали для себя, будет делать трюк, но на самом деле это не правильный способ сделать это.

Одна из проблем заключается в том, что вы проверяете «подсказку» или пик синусоидальной волны по сравнению с 1. Не все частоты синусоиды попадают в это значение или могут потребовать большого количества циклов для этого.

Математически говоря, пик синуса находится в грехе (пи/2 + 2piK) для всех целых значений К.

Чтобы вычислить синус для заданной частоты вы использовать формулу у = sin (2pi * x * f0/fs), где x - номер выборки, f0 - синусоидальная частота, fs - частота дискретизации.

Для приятного числа, как 1 кГц при частоте дискретизации 48 кГц, когда х = 12, то:

sin(2pi * 12 * 1000/48000) = sin(2pi * 12/48) = sin(pi/2) = 1 

Однако на частоте 997Hz, как то истинный пик приходится на долю образца после образца 12.

sin(2pi * 12 * 997/48000) = 0.99087178042 
sin(2pi * 12 * 997/48000) = 0.99998889671 
sin(2pi * 12 * 997/48000) = 0.99209828673 

Лучшим способом сшивания сигналов вместе является отслеживание фазы от одного тона и использование этого в качестве начальной фазы для следующего.

Во-первых, для заданной частоты, необходимо выяснить набега фазы, обратите внимание, что это то же самое, что вы делаете с образцом факторизовали:

phInc = 2*pi*f0/fs 

Далее вычислить синус и обновления переменная, представляющая текущую фазу.

for x in xrange(number_of_frames): 
    y = math.sin(self._phase); 
    self._phase += phaseInc; 

Собираем все вместе:

def tone(self, frequency, length=1000, play=False, **kwargs): 

    number_of_frames = int(self.bitrate * length/1000.) 
    phInc = 2*math.pi*frequency/self.bitrate 

    for x in xrange(number_of_frames): 
     y = math.sin(self._phase) 
     _phase += phaseInc; 
     self._queue.append(chr(int(y)))