Description
Issue №694 opened by l0rb at 2018-12-25 22:59:33
I'm playing a sound on a channel and repeatedly queue it whenever the queue is empty. if the sound becomes very short, there is very audible stuttering of the sound. it happens with lengths that fall below about 0.1s.
here is how my code approximately looks:
# data = a numpy array with nice sound
sound = pygame.sndarray.make_sound(data)
channel = sound.play()
while True:
if not channel.get_queue():
# if this would work, the goal is to create a new sound object with different data here
channel.queue(sound)
Related Docs:
https://www.pygame.org/docs/ref/mixer.html
https://www.pygame.org/docs/ref/sndarray.html
Comments
# # e1000 commented at 2018-12-30 16:58:20
I think it could be related to # 322 , so can you try if this bug disappear if you change the mixer buffering, eg with
pygame.mixer.pre_init(buffer=2048)
at the beginning of your code, cf [pygame doc](https://www.pygame.org/docs/ref/mixer.html# pygame.mixer.pre_init)
# # l0rb commented at 2019-01-01 21:38:33
I tried again with decreased buffer size which does help, but does not cure the problem fully. I am now able to queue sounds with a length of about 0.01s but anything below and the stuttering reappears. (0.01s = about 500 frames at a sample rate of 44100)
# # e1000 commented at 2019-01-02 13:54:55
I might be wrong, but it seemed to me that SDL doesn't check any new input during the duration corresponding to the buffer?
so for very small sound snippets, maybe we should be considering to use pygame.midi
?
Which buffer size did you use for your 10 ms sounds?
# # illume commented at 2019-01-02 13:57:45
I can't reproduce since that code is not complete.
Have you tried buffer=512
? This should work on most systems. Maybe even 256 is ok for your application.
The other issue with repeated sounds is if they do not match up on their boundary. Like if you have a sine wave repeating, and because of numeric inaccuracy the border of the sound does not match up. This is why when making synths they usually repeat the sound multiple times until there is a match on the border. Another way to avoid the problem is to use 32bit samples (but you can only use those in pygame 2).
Additionally, I would try pygame with SDL2. But you have to compile from source currently. It has a rewritten mixer, and is better in many respects. See https://www.pygame.org/wiki/Compilation for instructions (for each platform there is a sdl2 specific instruction).
# # l0rb commented at 2019-01-04 12:04:08
I created a minimum working sample that has the buggy behavior so it can easily be reproduced. I made sure that the sounds do match up at the boundary, and I experimented with different buffer sizes but going very low (below 128) doesn't seem to change anything.
import math
import pygame
import numpy as np
# this is the (approximate) sample duration in seconds
# putting 0.01 here works fine, putting 0.005 or lower creates very audible stuttering and sometimes no sound at all (numbers might be hardware dependent?)
sample_duration = 0.005
buffer = 128
freq = 44100
pygame.mixer.pre_init(frequency=freq, size=8, channels=1, buffer=buffer)
pygame.init()
pygame.mixer.init()
# creating a sine wave of `cycle_length` frames and append it `repeat` times to get close to `sample_duration` in duration of the sound
cycle_length = 200
repeat = max(1, round(freq * sample_duration / cycle_length))
frame_rad = 2*math.pi / float(cycle_length)
data = np.array([math.sin(frame_rad * frame) for frame in range(cycle_length)])
data = np.resize(data, cycle_length*repeat)
data = (data * 127).astype('i1')
piece = pygame.sndarray.make_sound(data)
channel = piece.play()
while True:
if not channel.get_queue():
channel.queue(piece)
# # ankith26 commented at 2021-11-23 03:22:26
Testing whether this issue still reproduces on pygame 2, so I ran the test code and with pygame 2+, I get the following error
Traceback (most recent call last):
File "E:\test.py", line 21, in <module>
piece = pygame.sndarray.make_sound(data)
File "C:\Users\Ankith\AppData\Local\Programs\Python\Python310\lib\site-packages\pygame\sndarray.py", line 88, in make_sound
return mixer.Sound(array=array)
ValueError: Array must be 2-dimensional for stereo mixer
Is this a regression? clearly the number of mixer channels is set to 1?