Skip to content

Commit 87aa96f

Browse files
authored
Merge pull request #8 from open-cogsci/pygame_soundrenderer_fix
Pygame soundrenderer fix & custom pygame mixer challenge ID
2 parents 775a790 + c3025e6 commit 87aa96f

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

mediadecoder/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Media-decoding library based on MoviePy"""
22

3-
__version__ = "0.2.1"
3+
__version__ = "0.2.2"
44
__author__ = "Daniel Schreij"
55
__license__ = "MIT"
66

mediadecoder/soundrenderers/pygamerenderer.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
class SoundrendererPygame(threading.Thread, SoundRenderer):
1919
"""Uses pygame.mixer to play sound"""
2020

21-
def __init__(self, audioformat, queue=None, pygame_buffersize=None):
21+
def __init__(self, audioformat, queue=None, pygame_buffersize=None,
22+
pygame_channel_id=None):
2223
"""Constructor.
2324
Creates a pygame sound renderer using pygame.mixer.
2425
@@ -31,6 +32,9 @@ def __init__(self, audioformat, queue=None, pygame_buffersize=None):
3132
audio frames are placed by the decoder (default=None).
3233
pygame_buffersize : int, optional
3334
The buffersize to be used in the Pygame mixer (default=None).
35+
pygame_channel_id : int, optional
36+
The ID of a specific pygame mixer channel to use. If none set,
37+
an appropriate channel is selected automatically (default=None).
3438
3539
"""
3640
global pygame
@@ -63,6 +67,8 @@ def __init__(self, audioformat, queue=None, pygame_buffersize=None):
6367
else:
6468
self._own_mixer = False
6569

70+
self._channel_id = pygame_channel_id
71+
6672
def run(self):
6773
"""Main thread function."""
6874
global pygame
@@ -75,8 +81,15 @@ def run(self):
7581
if not hasattr(self, "queue"):
7682
raise RuntimeError("Audio queue is not intialized.")
7783

84+
if self._channel_id is not None:
85+
channel = pygame.mixer.Channel(self._channel_id)
86+
else:
87+
channel = pygame.mixer.find_channel(force=True)
88+
7889
chunk = None
79-
channel = None
90+
first_chunk_played = False
91+
last_channel_state = None
92+
last_channel_state_change = None
8093
self.keep_listening = True
8194
while self.keep_listening:
8295
if chunk is None:
@@ -101,12 +114,27 @@ def run(self):
101114
except Empty:
102115
continue
103116

104-
if channel is None:
105-
channel = chunk.play()
117+
if not first_chunk_played:
118+
channel.play(chunk)
119+
chunk = None
120+
first_chunk_played = True
106121
else:
107-
if not channel.get_queue():
122+
playing_sound = channel.get_sound()
123+
queued_sound = channel.get_queue()
124+
if not queued_sound:
108125
channel.queue(chunk)
109126
chunk = None
127+
else:
128+
# Fix Pygame channel getting "stuck" (for some reason)
129+
now = time.perf_counter()
130+
if last_channel_state != [playing_sound, queued_sound]:
131+
last_channel_state = [playing_sound, queued_sound]
132+
last_channel_state_change = now
133+
elif last_channel_state_change is not None:
134+
if now - last_channel_state_change > \
135+
2 * chunk.get_length():
136+
channel.play(chunk)
137+
110138
time.sleep(0.005)
111139

112140
if not channel is None and pygame.mixer.get_init():

0 commit comments

Comments
 (0)