0

Prop Maker Audio Bug - Slurping Noise After Playback
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Prop Maker Audio Bug - Slurping Noise After Playback

by TRGPAndrew on Tue May 14, 2019 12:17 pm

This is a short video demonstration of an audio bug I am experiencing in the hardware of my Ray Gun prop. https://youtu.be/1owbqYGVhlw

3-5 seconds after audio playback, a loud slurping noise can be heard. It doesn't matter what file I play, the slurping happens consistently within a few seconds after playback is finished. Audio quality degrades if I trigger audio playback multiple times before the slurping can happen.

I'm running a Feather M4 Express with Prop-Maker Featherwing and 4 Ohm 3 Watt 40mm speaker. Audio is triggered by a SPDT limit switch.

I am also running NeoPixels, a hall effect sensor, and a potentiometer.

Here's my code:

Code: Select all | TOGGLE FULL SIZE
#  RayGun Final Code Test 4/26/19
import time
import board
import neopixel
import math
import audioio
import digitalio
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogIn, AnalogOut

bar_pin = board.D5
dial_pin = board.D13
bar_pixels = 15
dial_pixels = 3
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)

phase = 0

barrel = neopixel.NeoPixel(bar_pin, bar_pixels, brightness=1.0, auto_write=False)
dial = neopixel.NeoPixel(dial_pin, dial_pixels, brightness=1.0, auto_write=False)

#  Give power to D10 which powers the speaker amplifier
enable = digitalio.DigitalInOut(board.D10)
enable.direction = digitalio.Direction.OUTPUT
enable.value = True

#  Set up audio channel/Open audio files and prep for playback
audio = audioio.AudioOut(board.A0)
startup = audioio.WaveFile(open("Startup.wav", "rb"))
shoot = audioio.WaveFile(open("RayGunPew.wav", "rb"))
empty = audioio.WaveFile(open("Empty.wav", "rb"))
quote1 = audioio.WaveFile(open("Dempsey_1.wav", "rb"))
quote2 = audioio.WaveFile(open("Dempsey_2.wav", "rb"))
quote3 = audioio.WaveFile(open("Dempsey_3.wav", "rb"))
reloadOpen = audioio.WaveFile(open("Reload_Open.wav", "rb"))
reloadClose = audioio.WaveFile(open("Reload_Close.wav", "rb"))

trigger = DigitalInOut(board.D11)
trigger.direction = Direction.INPUT
trigger.pull = Pull.UP

sensor = DigitalInOut(board.D12)
sensor.direction = Direction.INPUT
sensor.pull = Pull.UP

pot_read = AnalogIn(board.A2)
galv_out = AnalogOut(board.A1)

barrel_open = False
hallstate = barrel_open
trigger_count = 0
ct = 0

def get_mode(mode):
    if mode <= 100:
        barrel.fill((15, 100, 175))
        barrel.show()
    elif mode > 100 and mode <= 200:
        barrel.fill((0, 255, 0))
        barrel.show()
    elif mode > 200 and mode <= 300:
        barrel.fill((255, 0, 0))
        barrel.show()
    elif mode > 300 and mode <= 400:
        blue_wave()
    else:
        white_wave()

def blue_wave():
    for p in range(bar_pixels):
        BLUE = int(abs(math.sin((p - phase)*3.14 / 18) * 175))+15
        barrel[p] = (0, 0, BLUE)
        barrel.show()
        time.sleep(0.002)

def white_wave():
    for p in range(bar_pixels):
        WHITE = int(abs(math.sin((p - phase)*3.14 / 18) * 115))+15
        barrel[p] = (WHITE, WHITE, WHITE)
        barrel.show()
        time.sleep(0.002)

def dial_disp():
    dial[0] = RED
    dial[1] = YELLOW
    dial[2] = GREEN
    dial.show()

def bad_fire(i):
    if i == 0:
        audio.play(empty)
    elif i == 1:
        audio.play(quote1)
    elif i == 2:
        audio.play(quote2)
    elif i == 3:
        audio.play(quote3)

audio.play(startup)
while audio.playing:
    for i in range(255):
        dial[0] = (i, 0, 0)
        dial[1] = (i, i, 0)
        dial[2] = (0, i, 0)
        dial.show()

#  Main loop
while True:

    dial_disp()
    reading = pot_read.value
    val = (reading * 500.0) / 65536
    get_mode(val)
    phase += 1
    last_hallstate = hallstate
    hallstate = sensor.value

    if not trigger.value and not sensor.value:  # If trigger is pulled while the barrel is closed
        if trigger_count < 20:
            galv_out.value = 7000
            audio.play(shoot)
            while audio.playing:
                get_mode(val)
                phase += 1
            galv_out.value = 0
        elif ct < 4:
            galv_out.value = 0
            bad_fire(ct)
            while audio.playing:
                get_mode(val)
                phase += 1
            ct += 1
        else:
            ct = 0
        trigger_count += 1
    elif hallstate and hallstate != last_hallstate:
        galv_out.value = 7000
        audio.play(reloadOpen)
        while audio.playing:
            get_mode(val)
            phase += 1
    elif not hallstate and hallstate != last_hallstate:
        trigger_count = 0
        audio.play(reloadClose)
        while audio.playing:
            galv_out.value = 0
            get_mode(val)
            phase += 1

TRGPAndrew
 
Posts: 6
Joined: Mon Mar 26, 2018 6:10 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by adafruit_support_carter on Tue May 14, 2019 2:08 pm

If you try a simple code that basically just plays one of the sounds when the trigger is pulled, does it also make the slurping noise.

Cool ray gun, BTW.

adafruit_support_carter
 
Posts: 12971
Joined: Tue Nov 29, 2016 2:45 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by TRGPAndrew on Tue May 14, 2019 2:15 pm

I just ran a few tests editing the code and it would seem that the slurping is correlated to the "while audio.play" part of the code. If I remove the "while" loop, there is no slurp.

Can you think of any reason why the logic would interfere with the performance of the speaker in this way?

TRGPAndrew
 
Posts: 6
Joined: Mon Mar 26, 2018 6:10 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by TRGPAndrew on Tue May 14, 2019 2:40 pm

I just went back to the full version of the code and without the "while audio.playing:" loop, the performance of the logic is very unstable even though the code itself is stable. I would really like to be able to use this bit of logic, but it seems I might have to find a creative way around it.

TRGPAndrew
 
Posts: 6
Joined: Mon Mar 26, 2018 6:10 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by adafruit_support_carter on Tue May 14, 2019 6:45 pm

It looks you are trying to have things happen with NeoPixels while the audio is playing back? Is that correct? Some of them appear to be simple fills, but some appear to be more animated. Does it happen with any of those "modes"?

Can you describe what you want to happen while audio is playing back.

adafruit_support_carter
 
Posts: 12971
Joined: Tue Nov 29, 2016 2:45 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by TRGPAndrew on Wed May 15, 2019 6:46 pm

While I am using NeoPixels, the tests I ran eliminated all of the code pertaining to the LEDs. The slurping occured in every part of the code where "while audio.playing:" was present after audio was triggered.

While I still believe that this is a bug that should be addressed if possible, I have found a workaround. I simply added another qualifier in the logic to only let you trigger audio if an audio file isn't already playing "if ... not audio.playing:". This allowed me to eliminate all the "while audio.playing:" loops and still maintain a stable code when tested on the hardware.

Now, the only issue I have with my current configuration is a high frequency hum that persist while the boards are on. I think this might be audible PWM frequency to the NeoPixels or other oscillating processes that affect the speaker.

If you have any advice on eliminating high frequency humming from the Feather M4 or Prop-Maker, I would appreciate the help.

Here's the code showing the change in the first "if" statement of the main loop that eliminated the slurp by getting rid of the "while: audio.playing:" loops.

Code: Select all | TOGGLE FULL SIZE
#  RayGun Final Code Test 4/26/19
import time
import board
import neopixel
import math
import audioio
import digitalio
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogIn, AnalogOut

bar_pin = board.D5
dial_pin = board.D4
bar_pixels = 15
dial_pixels = 3
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)

phase = 0

barrel = neopixel.NeoPixel(bar_pin, bar_pixels, brightness=1.0, auto_write=False)
dial = neopixel.NeoPixel(dial_pin, dial_pixels, brightness=1.0, auto_write=False)

#  Give power to D10 which powers the speaker amplifier
enable = digitalio.DigitalInOut(board.D10)
enable.direction = digitalio.Direction.OUTPUT
enable.value = True

#  Set up audio channel/Open audio files and prep for playback
audio = audioio.AudioOut(board.A0)
startup = audioio.WaveFile(open("Startup.wav", "rb"))
shoot = audioio.WaveFile(open("RayGunPew.wav", "rb"))
empty = audioio.WaveFile(open("Empty.wav", "rb"))
quote1 = audioio.WaveFile(open("Dempsey_1.wav", "rb"))
quote2 = audioio.WaveFile(open("Dempsey_2.wav", "rb"))
quote3 = audioio.WaveFile(open("Dempsey_3.wav", "rb"))
reloadOpen = audioio.WaveFile(open("Reload_Open.wav", "rb"))
reloadClose = audioio.WaveFile(open("Reload_Close.wav", "rb"))

trigger = DigitalInOut(board.D11)
trigger.direction = Direction.INPUT
trigger.pull = Pull.UP

sensor = DigitalInOut(board.D12)
sensor.direction = Direction.INPUT
sensor.pull = Pull.UP

pot_read = AnalogIn(board.A2)
galv_out = AnalogOut(board.A1)

barrel_open = False
hallstate = barrel_open
trigger_count = 0
ct = 0

def get_mode(mode):
    if mode <= 100:
        barrel.fill((15, 100, 175))
        barrel.show()
    elif mode > 100 and mode <= 200:
        barrel.fill((0, 255, 0))
        barrel.show()
    elif mode > 200 and mode <= 300:
        barrel.fill((255, 0, 0))
        barrel.show()
    elif mode > 300 and mode <= 400:
        blue_wave()
    else:
        white_wave()

def blue_wave():
    for p in range(bar_pixels):
        BLUE = int(abs(math.sin((p - phase)*3.14 / 18) * 235))+15
        barrel[p] = (0, 0, BLUE)
        barrel.show()
        time.sleep(0.002)

def white_wave():
    for p in range(bar_pixels):
        WHITE = int(abs(math.sin((p - phase)*3.14 / 18) * 175))+15
        barrel[p] = (WHITE, WHITE, WHITE)
        barrel.show()
        time.sleep(0.002)

def dial_disp():
    dial[0] = RED
    dial[1] = YELLOW
    dial[2] = GREEN
    dial.show()

def bad_fire(i):
    if i == 0:
        audio.play(empty)
    elif i == 1:
        audio.play(quote1)
    elif i == 2:
        audio.play(quote2)
    elif i == 3:
        audio.play(quote3)

audio.play(startup)

for i in range(255):
    barrel.fill((i, i, i))
    dial[0] = (i, 0, 0)
    dial[1] = (i, i, 0)
    dial[2] = (0, i, 0)
    dial.show()
    barrel.show()
    time.sleep(0.001)
dial_disp()

#  Main loop
while True:
    reading = pot_read.value
    val = (reading * 500.0) / 65536
    get_mode(val)
    phase += 1
    last_hallstate = hallstate
    hallstate = sensor.value

    if not trigger.value and not sensor.value and not audio.playing:  # If trigger is pulled while the barrel is closed
        if trigger_count < 20:
            galv_out.value = 7000
            audio.play(shoot)
            galv_out.value = 0
        elif ct < 4:
            galv_out.value = 0
            bad_fire(ct)
            ct += 1
        else:
            ct = 0
        trigger_count += 1
    elif hallstate and hallstate != last_hallstate:
        galv_out.value = 7000
        audio.play(reloadOpen)
    elif not hallstate and hallstate != last_hallstate:
        trigger_count = 0
        audio.play(reloadClose)

TRGPAndrew
 
Posts: 6
Joined: Mon Mar 26, 2018 6:10 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by adafruit_support_carter on Thu May 16, 2019 11:30 am

No specific guidance for eliminating the hum. Just make sure everything is grounded well, etc. If possible try routing wires differently, etc.

Can you work up the most simple example sketch that demonstrates the original issue and post the code here. That will help up check what might be going on with that slurp noise.

adafruit_support_carter
 
Posts: 12971
Joined: Tue Nov 29, 2016 2:45 pm

Re: Prop Maker Audio Bug - Slurping Noise After Playback

by TRGPAndrew on Thu May 16, 2019 12:00 pm

I've attached the stripped down version of the code. Notice that I'm triggering audio from 2 sources, an SPDT switch and a Hall Effect sensor.

The slurp doesn't happen on "audio.play(startup)". I've concluded that this is due to the absence of the "while audio.playing:" loop because the slurping is present when triggering audio in the main loop.
Code: Select all | TOGGLE FULL SIZE
#  RayGun Final Code Test 4/26/19
import board
import audioio
import digitalio
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogIn, AnalogOut

#  Give power to D10 which powers the speaker amplifier
enable = digitalio.DigitalInOut(board.D10)
enable.direction = digitalio.Direction.OUTPUT
enable.value = True

#  Set up audio channel/Open audio files and prep for playback
audio = audioio.AudioOut(board.A0)
startup = audioio.WaveFile(open("Startup.wav", "rb"))
shoot = audioio.WaveFile(open("RayGunPew.wav", "rb"))
empty = audioio.WaveFile(open("Empty.wav", "rb"))
quote1 = audioio.WaveFile(open("Dempsey_1.wav", "rb"))
quote2 = audioio.WaveFile(open("Dempsey_2.wav", "rb"))
quote3 = audioio.WaveFile(open("Dempsey_3.wav", "rb"))
reloadOpen = audioio.WaveFile(open("Reload_Open.wav", "rb"))
reloadClose = audioio.WaveFile(open("Reload_Close.wav", "rb"))

trigger = DigitalInOut(board.D11)
trigger.direction = Direction.INPUT
trigger.pull = Pull.UP

sensor = DigitalInOut(board.D12)
sensor.direction = Direction.INPUT
sensor.pull = Pull.UP

pot_read = AnalogIn(board.A2)

barrel_open = False
hallstate = barrel_open
trigger_count = 0
ct = 0

def bad_fire(i):
    if i == 0:
        audio.play(empty)
    elif i == 1:
        audio.play(quote1)
    elif i == 2:
        audio.play(quote2)
    elif i == 3:
        audio.play(quote3)

audio.play(startup)

#  Main loop
while True:
    last_hallstate = hallstate
    hallstate = sensor.value

    if not trigger.value and not sensor.value:  # If trigger is pulled while the barrel is closed
        if trigger_count < 20:
            audio.play(shoot)
            while audio.playing:
                pass
        elif ct < 4:
            bad_fire(ct)
            while audio.playing:
                pass
            ct += 1
        else:
            ct = 0
        trigger_count += 1
    elif hallstate and hallstate != last_hallstate:
        audio.play(reloadOpen)
        while audio.playing:
            pass
    elif not hallstate and hallstate != last_hallstate:
        trigger_count = 0
        audio.play(reloadClose)
        while audio.playing:
            pass

TRGPAndrew
 
Posts: 6
Joined: Mon Mar 26, 2018 6:10 pm

Please be positive and constructive with your questions and comments.