Search code examples
pythonaudiowav

How can I remove an annoying 'snap' noise each time I loop a wav file?


I'm trying to create a simple controllable and non-blocking looping wavplayer. The following class created using simpleaudio works, however, there is a brief pause and noticeable popping/snapping noise between each loop of the audio. I'm honestly not sure what's causing it and I'm not sure how I could fix it either than using a different audio module entirely. Any suggestions?

import simpleaudio as sa
from threading import Thread

class WavPlayer(Thread):
    def __init__(self,filepath,loop=False):

        self.loop = loop
        self.wav_obj = sa.WaveObject.from_wave_file(filepath)
        self.play_obj = None

        Thread.__init__(self)

    def run(self):
        self.play_obj = self.wav_obj.play() #initialize play buffer and play once

        while self.loop is True:
            if not self.play_obj.is_playing():
                print("played again")
                self.play_obj = self.wav_obj.play()

    def terminate(self):
        print("music terminated")
        self.play_obj.stop()
        self.loop = False
        self.join()

main_loop = WavPlayer("main_loop.wav",True)
menu_loop = WavPlayer("menu.wav",True)

main_loop.start()
z = input("Enter to end theme looping")
main_loop.loop = False

z = input("Enter to terminate music")
main_loop.terminate()

print("playing next song")
menu_loop.start()

cont = ''
while cont != 'n':
    cont = input("continue testing non-blocking? enter n to stop: ")

menu_loop.terminate()

Filedropper link to menu_loop wav file

Filedropper link to main_loop wav file


Solution

  • I encounterded the same problem while programming a tuner that generates an infinitely long note from a limited number of samples (I used pyaudio, and a tuning note is a very simple sound, which makes the pops very obvious, but the remedy much easier).

    If you loop a wave object like:

       **                    **
           *              *      *
             *          *          *
               *      *              *
                  **                    **
    

    ... you'll hear a pop because of the large difference between the last and the first samples. Dropping a few samples until the last and the first sample match will eliminate the pops (simpleaudio allows you to read the samples into numpy arrays which you then can truncate (slightly) until the first and last samples match).

    Cutting at zero crossings is a special case of this, see this discussion. Of course, some sound libraries may already truncate your samples at zero crossings.

    Before you take the trouble to extend your program to convert your samples to numpy arrays and truncating them, you first could try using a sound editor like Audacity and do it by hand, and then listen to the result.