hamiltron / py-simple-audio

A simple audio playback Python extension - cross-platform, asynchronous, dependency-free
Other
155 stars 36 forks source link

PlayObject causes SegFault when the program terminates #74

Open nic-obert opened 4 weeks ago

nic-obert commented 4 weeks ago

I've tried running one of the examples shown here.

Here's a working example that reproduces the SegFault (the example on the tutorial page causes a TypeError, so I've fixed the code so that it runs):

import numpy as np
import simpleaudio as sa
import math

# calculate note frequencies
A_freq = 440

# get timesteps for each sample, T is note duration in seconds
sample_rate = 44100
T = 0.25
t = np.linspace(0, T, math.floor(T * sample_rate), False)

# generate sine wave notes
audio = np.sin(A_freq * t * 2 * np.pi)

# normalize to 16-bit range
audio *= 32767 / np.max(np.abs(audio))
# convert to 16-bit data
audio = audio.astype(np.int16)

# start playback
play_obj = sa.play_buffer(audio, 1, 2, sample_rate)

# wait for playback to finish before exiting
play_obj.wait_done()

When running the program above, a SegFault always happens upon exiting.

Without calling play_obj.wait_done(), the program exits before finishing reproducing the tone, and no Segfault occurs:

import numpy as np
import simpleaudio as sa
import math

# calculate note frequencies
A_freq = 440

# get timesteps for each sample, T is note duration in seconds
sample_rate = 44100
T = 0.25
t = np.linspace(0, T, math.floor(T * sample_rate), False)

# generate sine wave notes
audio = np.sin(A_freq * t * 2 * np.pi)

# normalize to 16-bit range
audio *= 32767 / np.max(np.abs(audio))
# convert to 16-bit data
audio = audio.astype(np.int16)

# start playback
play_obj = sa.play_buffer(audio, 1, 2, sample_rate)

# wait for playback to finish before exiting
# play_obj.wait_done()

However, if we wait for the tone to finish by sleeping and without calling wait_done(), the program SegFaults:

import numpy as np
import simpleaudio as sa
import math
import time

# calculate note frequencies
A_freq = 440

# get timesteps for each sample, T is note duration in seconds
sample_rate = 44100
T = 0.25
t = np.linspace(0, T, math.floor(T * sample_rate), False)

# generate sine wave notes
audio = np.sin(A_freq * t * 2 * np.pi)

# normalize to 16-bit range
audio *= 32767 / np.max(np.abs(audio))
# convert to 16-bit data
audio = audio.astype(np.int16)

# start playback
play_obj = sa.play_buffer(audio, 1, 2, sample_rate)

# wait for playback to finish before exiting
# play_obj.wait_done()

time.sleep(0.5)

Note that no SegFault happens if I don't create the PlayObject with sa.play_buffer().

System information: Host: 20EQS2AU0H ThinkPad P50 Kernel: 6.10.2-arch1-2 Python 3.12.4 numpy==2.0.1 simpleaudio==1.0.4

nic-obert commented 4 weeks ago

I've just tested the library using Python 3.7.17 and it works without SegFaulting.