Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cac50d3099 | |||
| 7c4b859fa2 | |||
| c7aef439b5 | |||
| a24b1eb49c |
@@ -186,6 +186,7 @@ name_blacklist = {
|
||||
"renpy.display.render.IDENTITY",
|
||||
"renpy.loader.auto_lock",
|
||||
"renpy.display.screen.cprof",
|
||||
"renpy.audio.audio.lock",
|
||||
}
|
||||
|
||||
|
||||
|
||||
+180
-80
@@ -31,6 +31,8 @@ import time
|
||||
import pygame_sdl2 # @UnusedImport
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
import sys
|
||||
|
||||
# Import the appropriate modules, or set them to None if we cannot.
|
||||
|
||||
@@ -132,9 +134,13 @@ class MusicContext(renpy.python.RevertableObject):
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
# The next channel number to be assigned.
|
||||
next_channel_number = 0
|
||||
|
||||
# the lock that mediates between the periodic and main threads.
|
||||
lock = threading.Condition()
|
||||
|
||||
|
||||
class Channel(object):
|
||||
"""
|
||||
@@ -459,14 +465,16 @@ class Channel(object):
|
||||
left in the queue unless all is given.
|
||||
"""
|
||||
|
||||
self.queue = self.queue[:self.keep_queue]
|
||||
self.loop = [ ]
|
||||
with lock:
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
self.queue = self.queue[:self.keep_queue]
|
||||
self.loop = [ ]
|
||||
|
||||
if self.keep_queue == 0:
|
||||
renpysound.dequeue(self.number, even_tight)
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
if self.keep_queue == 0:
|
||||
renpysound.dequeue(self.number, even_tight)
|
||||
|
||||
def interact(self):
|
||||
"""
|
||||
@@ -498,47 +506,51 @@ class Channel(object):
|
||||
of seconds. Also clears any queued music.
|
||||
"""
|
||||
|
||||
self.keep_queue = 0
|
||||
self.dequeue()
|
||||
with lock:
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
self.keep_queue = 0
|
||||
self.dequeue()
|
||||
|
||||
if secs == 0:
|
||||
renpysound.stop(self.number)
|
||||
else:
|
||||
renpysound.fadeout(self.number, int(secs * 1000))
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
if secs == 0:
|
||||
renpysound.stop(self.number)
|
||||
else:
|
||||
renpysound.fadeout(self.number, int(secs * 1000))
|
||||
|
||||
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None, loop_only=False):
|
||||
|
||||
for filename in filenames:
|
||||
filename, _, _ = self.split_filename(filename, False)
|
||||
renpy.game.persistent._seen_audio[filename] = True # @UndefinedVariable
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
if not loop_only:
|
||||
|
||||
if tight is None:
|
||||
tight = self.tight
|
||||
|
||||
self.keep_queue += 1
|
||||
with lock:
|
||||
|
||||
for filename in filenames:
|
||||
qe = QueueEntry(filename, int(fadein * 1000), tight, False)
|
||||
self.queue.append(qe)
|
||||
filename, _, _ = self.split_filename(filename, False)
|
||||
renpy.game.persistent._seen_audio[filename] = True # @UndefinedVariable
|
||||
|
||||
# Only fade the first thing in.
|
||||
fadein = 0
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
self.wait_stop = synchro_start
|
||||
self.synchro_start = synchro_start
|
||||
if not loop_only:
|
||||
|
||||
if loop:
|
||||
self.loop = list(filenames)
|
||||
else:
|
||||
self.loop = [ ]
|
||||
if tight is None:
|
||||
tight = self.tight
|
||||
|
||||
self.keep_queue += 1
|
||||
|
||||
for filename in filenames:
|
||||
qe = QueueEntry(filename, int(fadein * 1000), tight, False)
|
||||
self.queue.append(qe)
|
||||
|
||||
# Only fade the first thing in.
|
||||
fadein = 0
|
||||
|
||||
self.wait_stop = synchro_start
|
||||
self.synchro_start = synchro_start
|
||||
|
||||
if loop:
|
||||
self.loop = list(filenames)
|
||||
else:
|
||||
self.loop = [ ]
|
||||
|
||||
def get_playing(self):
|
||||
|
||||
@@ -547,11 +559,13 @@ class Channel(object):
|
||||
|
||||
rv = renpysound.playing_name(self.number)
|
||||
|
||||
if rv is None and self.queue:
|
||||
rv = self.queue[0].filename
|
||||
with lock:
|
||||
|
||||
if rv is None and self.loop:
|
||||
rv = self.loop[0]
|
||||
if rv is None and self.queue:
|
||||
rv = self.queue[0].filename
|
||||
|
||||
if rv is None and self.loop:
|
||||
rv = self.loop[0]
|
||||
|
||||
return rv
|
||||
|
||||
@@ -573,35 +587,45 @@ class Channel(object):
|
||||
return renpysound.get_duration(self.number)
|
||||
|
||||
def set_pan(self, pan, delay):
|
||||
now = get_serial()
|
||||
self.context.pan_time = now
|
||||
self.context.pan = pan
|
||||
|
||||
if pcm_ok:
|
||||
self.pan_time = self.context.pan_time
|
||||
renpysound.set_pan(self.number, self.context.pan, delay)
|
||||
with lock:
|
||||
|
||||
now = get_serial()
|
||||
self.context.pan_time = now
|
||||
self.context.pan = pan
|
||||
|
||||
if pcm_ok:
|
||||
self.pan_time = self.context.pan_time
|
||||
renpysound.set_pan(self.number, self.context.pan, delay)
|
||||
|
||||
def set_secondary_volume(self, volume, delay):
|
||||
now = get_serial()
|
||||
self.context.secondary_volume_time = now
|
||||
self.context.secondary_volume = volume
|
||||
|
||||
if pcm_ok:
|
||||
self.secondary_volume_time = self.context.secondary_volume_time
|
||||
renpysound.set_secondary_volume(self.number, self.context.secondary_volume, delay)
|
||||
with lock:
|
||||
|
||||
now = get_serial()
|
||||
self.context.secondary_volume_time = now
|
||||
self.context.secondary_volume = volume
|
||||
|
||||
if pcm_ok:
|
||||
self.secondary_volume_time = self.context.secondary_volume_time
|
||||
renpysound.set_secondary_volume(self.number, self.context.secondary_volume, delay)
|
||||
|
||||
def pause(self):
|
||||
renpysound.pause(self.number)
|
||||
with lock:
|
||||
renpysound.pause(self.number)
|
||||
|
||||
def unpause(self):
|
||||
renpysound.unpause(self.number)
|
||||
with lock:
|
||||
renpysound.unpause(self.number)
|
||||
|
||||
def read_video(self):
|
||||
if pcm_ok:
|
||||
return renpysound.read_video(self.number)
|
||||
|
||||
return None
|
||||
|
||||
def video_ready(self):
|
||||
|
||||
if not pcm_ok:
|
||||
return 1
|
||||
|
||||
@@ -746,7 +770,16 @@ def set_force_stop(name, value):
|
||||
get_channel(name).context.force_stop = value
|
||||
|
||||
|
||||
# The thread that call periodic.
|
||||
periodic_thread = None
|
||||
|
||||
# True if we need it to quit.
|
||||
periodic_thread_quit = True
|
||||
|
||||
|
||||
def init():
|
||||
global periodic_thread
|
||||
global periodic_thread_quit
|
||||
|
||||
global pcm_ok
|
||||
global mix_ok
|
||||
@@ -783,12 +816,30 @@ def init():
|
||||
renpy.game.preferences.volumes.setdefault(m, default_volume)
|
||||
renpy.game.preferences.mute.setdefault(m, False)
|
||||
|
||||
with lock:
|
||||
|
||||
periodic_thread_quit = False
|
||||
|
||||
periodic_thread = threading.Thread(target=periodic_thread_main)
|
||||
periodic_thread.daemon = True
|
||||
periodic_thread.start()
|
||||
|
||||
|
||||
def quit(): # @ReservedAssignment
|
||||
|
||||
global periodic_thread
|
||||
global periodic_thread_quit
|
||||
|
||||
global pcm_ok
|
||||
global mix_ok
|
||||
|
||||
with lock:
|
||||
if periodic_thread is not None:
|
||||
periodic_thread_quit = True
|
||||
lock.notify()
|
||||
|
||||
periodic_thread.join()
|
||||
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
@@ -808,13 +859,15 @@ def quit(): # @ReservedAssignment
|
||||
pcm_ok = None
|
||||
mix_ok = None
|
||||
|
||||
|
||||
|
||||
# The last-set pcm volume.
|
||||
pcm_volume = None
|
||||
|
||||
old_emphasized = False
|
||||
|
||||
|
||||
def periodic():
|
||||
def periodic_pass():
|
||||
"""
|
||||
The periodic sound callback. This is called at around 20hz, and is
|
||||
responsible for adjusting the volume of the playing music if
|
||||
@@ -888,6 +941,48 @@ def periodic():
|
||||
raise
|
||||
|
||||
|
||||
periodic_exc = None
|
||||
|
||||
|
||||
def periodic_thread_main():
|
||||
|
||||
global periodic_exc
|
||||
|
||||
with lock:
|
||||
while True:
|
||||
|
||||
lock.wait()
|
||||
|
||||
if periodic_thread_quit:
|
||||
return
|
||||
|
||||
try:
|
||||
periodic_pass()
|
||||
except Exception:
|
||||
periodic_exc = sys.exc_info()
|
||||
|
||||
|
||||
def periodic():
|
||||
global periodic_exc
|
||||
|
||||
if not renpy.config.audio_periodic_thread:
|
||||
periodic_pass()
|
||||
return
|
||||
|
||||
with lock:
|
||||
|
||||
for c in all_channels:
|
||||
c.get_context()
|
||||
|
||||
if periodic_exc is not None:
|
||||
exc = periodic_exc
|
||||
periodic_exc = None
|
||||
|
||||
raise exc[0], exc[1], exc[2]
|
||||
|
||||
lock.notify()
|
||||
|
||||
|
||||
def interact():
|
||||
"""
|
||||
Called at least once per interaction.
|
||||
@@ -896,36 +991,38 @@ def interact():
|
||||
if not pcm_ok:
|
||||
return
|
||||
|
||||
try:
|
||||
for c in all_channels:
|
||||
with lock:
|
||||
|
||||
c.interact()
|
||||
try:
|
||||
for c in all_channels:
|
||||
|
||||
# if _music_volumes.get(i, 1.0) != c.chan_volume:
|
||||
# c.set_volume(_music_volumes.get(i, 1.0))
|
||||
c.interact()
|
||||
|
||||
ctx = c.context
|
||||
# if _music_volumes.get(i, 1.0) != c.chan_volume:
|
||||
# c.set_volume(_music_volumes.get(i, 1.0))
|
||||
|
||||
# If we're in the same music change, then do nothing with the
|
||||
# music.
|
||||
if c.last_changed == ctx.last_changed:
|
||||
continue
|
||||
ctx = c.context
|
||||
|
||||
filenames = ctx.last_filenames
|
||||
tight = ctx.last_tight
|
||||
# If we're in the same music change, then do nothing with the
|
||||
# music.
|
||||
if c.last_changed == ctx.last_changed:
|
||||
continue
|
||||
|
||||
if c.loop:
|
||||
if not filenames or c.get_playing() not in filenames:
|
||||
c.fadeout(renpy.config.fade_music)
|
||||
filenames = ctx.last_filenames
|
||||
tight = ctx.last_tight
|
||||
|
||||
if filenames:
|
||||
c.enqueue(filenames, loop=True, synchro_start=True, tight=tight)
|
||||
if c.loop:
|
||||
if not filenames or c.get_playing() not in filenames:
|
||||
c.fadeout(renpy.config.fade_music)
|
||||
|
||||
c.last_changed = ctx.last_changed
|
||||
if filenames:
|
||||
c.enqueue(filenames, loop=True, synchro_start=True, tight=tight)
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
c.last_changed = ctx.last_changed
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
periodic()
|
||||
|
||||
@@ -935,9 +1032,12 @@ def rollback():
|
||||
On rollback, we want to stop all the channels with non-empty sounds.
|
||||
"""
|
||||
|
||||
for c in all_channels:
|
||||
if not c.loop:
|
||||
c.fadeout(0)
|
||||
with lock:
|
||||
|
||||
for c in all_channels:
|
||||
if not c.loop:
|
||||
c.fadeout(0)
|
||||
|
||||
|
||||
global_pause = False
|
||||
|
||||
|
||||
+74
-68
@@ -83,48 +83,50 @@ def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=Fals
|
||||
if isinstance(filenames, basestring):
|
||||
filenames = [ filenames ]
|
||||
|
||||
try:
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
with renpy.audio.audio.lock:
|
||||
|
||||
if loop is None:
|
||||
loop = c.default_loop
|
||||
try:
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
|
||||
if (tight is None) and renpy.config.tight_loop_default:
|
||||
tight = loop
|
||||
if loop is None:
|
||||
loop = c.default_loop
|
||||
|
||||
loop_is_filenames = (c.loop == filenames)
|
||||
if (tight is None) and renpy.config.tight_loop_default:
|
||||
tight = loop
|
||||
|
||||
c.dequeue()
|
||||
loop_is_filenames = (c.loop == filenames)
|
||||
|
||||
if fadeout is None:
|
||||
fadeout = renpy.config.fade_music
|
||||
c.dequeue()
|
||||
|
||||
if if_changed and c.get_playing() in filenames:
|
||||
fadein = 0
|
||||
loop_only = loop_is_filenames
|
||||
else:
|
||||
c.fadeout(fadeout)
|
||||
loop_only = False
|
||||
if fadeout is None:
|
||||
fadeout = renpy.config.fade_music
|
||||
|
||||
c.enqueue(filenames, loop=loop, synchro_start=synchro_start, fadein=fadein, tight=tight, loop_only=loop_only)
|
||||
if if_changed and c.get_playing() in filenames:
|
||||
fadein = 0
|
||||
loop_only = loop_is_filenames
|
||||
else:
|
||||
c.fadeout(fadeout)
|
||||
loop_only = False
|
||||
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
c.enqueue(filenames, loop=loop, synchro_start=synchro_start, fadein=fadein, tight=tight, loop_only=loop_only)
|
||||
|
||||
if loop:
|
||||
ctx.last_filenames = filenames
|
||||
ctx.last_tight = tight
|
||||
else:
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
|
||||
ctx.pause = False
|
||||
if loop:
|
||||
ctx.last_filenames = filenames
|
||||
ctx.last_tight = tight
|
||||
else:
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
ctx.pause = False
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
|
||||
def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tight=None):
|
||||
@@ -170,38 +172,40 @@ def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tig
|
||||
if isinstance(filenames, basestring):
|
||||
filenames = [ filenames ]
|
||||
|
||||
try:
|
||||
with renpy.audio.audio.lock:
|
||||
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
try:
|
||||
|
||||
if loop is None:
|
||||
loop = c.default_loop
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
|
||||
if (tight is None) and renpy.config.tight_loop_default:
|
||||
tight = loop
|
||||
if loop is None:
|
||||
loop = c.default_loop
|
||||
|
||||
if clear_queue:
|
||||
c.dequeue(True)
|
||||
if (tight is None) and renpy.config.tight_loop_default:
|
||||
tight = loop
|
||||
|
||||
c.enqueue(filenames, loop=loop, fadein=fadein, tight=tight)
|
||||
if clear_queue:
|
||||
c.dequeue(True)
|
||||
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
c.enqueue(filenames, loop=loop, fadein=fadein, tight=tight)
|
||||
|
||||
if loop:
|
||||
ctx.last_filenames = filenames
|
||||
ctx.last_tight = tight
|
||||
else:
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
|
||||
ctx.pause = False
|
||||
if loop:
|
||||
ctx.last_filenames = filenames
|
||||
ctx.last_tight = tight
|
||||
else:
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
ctx.pause = False
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
|
||||
def playable(filename, channel="music"):
|
||||
@@ -242,24 +246,26 @@ def stop(channel="music", fadeout=None):
|
||||
if renpy.game.context().init_phase:
|
||||
return
|
||||
|
||||
try:
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
with renpy.audio.audio.lock:
|
||||
|
||||
if fadeout is None:
|
||||
fadeout = renpy.config.fade_music
|
||||
try:
|
||||
c = get_channel(channel)
|
||||
ctx = c.context
|
||||
|
||||
c.fadeout(fadeout)
|
||||
if fadeout is None:
|
||||
fadeout = renpy.config.fade_music
|
||||
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
c.fadeout(fadeout)
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
t = get_serial()
|
||||
ctx.last_changed = t
|
||||
c.last_changed = t
|
||||
ctx.last_filenames = [ ]
|
||||
ctx.last_tight = False
|
||||
|
||||
except:
|
||||
if renpy.config.debug_sound:
|
||||
raise
|
||||
|
||||
|
||||
def set_music(channel, flag, default=False):
|
||||
|
||||
@@ -799,6 +799,8 @@ keep_show_layer_state = True
|
||||
# A list of callbacks that are called when fast skipping happens.
|
||||
fast_skipping_callbacks = [ ]
|
||||
|
||||
# Should the audio periodic callback run in its own thread.
|
||||
audio_periodic_thread = True
|
||||
|
||||
del os
|
||||
del collections
|
||||
|
||||
Reference in New Issue
Block a user