Fadeouts and gain

This commit is contained in:
2025-08-05 02:43:29 +01:00
parent 8fa467cb93
commit 18f4a6168f
3 changed files with 69 additions and 11 deletions

View File

@@ -16,7 +16,10 @@ class Event:
self._at.set_timings(timings) self._at.set_timings(timings)
def set_audiencecontent(self, audiencecontent): def set_audiencecontent(self, audiencecontent):
self.audiencecontent = audiencecontent self._audiencecontent = audiencecontent
def set_eventrunner(self, eventrunner):
self._eventrunner = eventrunner
@property @property
def scheduled(self): def scheduled(self):
@@ -39,6 +42,9 @@ class Event:
def stop(self): def stop(self):
pass pass
def notify(self, *args, **kwargs):
pass
class Display(Event): class Display(Event):
def __init__(self, media, *args, **kwargs): def __init__(self, media, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -46,7 +52,7 @@ class Display(Event):
class Playback(Event): class Playback(Event):
def __init__(self, media, device=None, channels=[1,2], tempo=None, beats=None, leadin=0, loop=False, *args, **kwargs): def __init__(self, media, device=None, channels=[1,2], tempo=None, beats=None, leadin=0, loop=False, gain=0, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._media = media self._media = media
self._device = device self._device = device
@@ -57,6 +63,9 @@ class Playback(Event):
self._beats = beats self._beats = beats
self._leadin = leadin self._leadin = leadin
self._loop = loop self._loop = loop
self._gain = 10**(gain/10) # Convert from dB to linear gain
self._fadecurve = None
self._fadeframe = None
def prepare(self): def prepare(self):
self._at._timings.register_tempo(self._tempo, self._beats, self._at) self._at._timings.register_tempo(self._tempo, self._beats, self._at)
@@ -68,11 +77,13 @@ class Playback(Event):
def start(self): def start(self):
print("Start playback") print("Start playback")
self._data, fs = soundfile.read(self._media) self._data, self._fs = soundfile.read(self._media)
self._current_frame = 0 self._current_frame = 0
self._fadecurve = None
self._fadeframe = None
self._stream = sounddevice.OutputStream( self._stream = sounddevice.OutputStream(
samplerate=fs, device=self._device, channels=self._channels, samplerate=self._fs, device=self._device, channels=self._channels,
callback=self.callback, finished_callback=self.finished_callback) callback=self.callback, finished_callback=self.finished_callback)
self._stream.start() self._stream.start()
@@ -80,7 +91,12 @@ class Playback(Event):
if status: if status:
print(status) print(status)
chunksize = min(len(self._data) - self._current_frame, frames) chunksize = min(len(self._data) - self._current_frame, frames)
outdata[:chunksize, self._mapping] = self._data[self._current_frame:self._current_frame + chunksize] if self._fadecurve is not None:
chunksize = min(chunksize, len(self._fadecurve) - self._fadeframe)
outdata[:chunksize, self._mapping] = self._data[self._current_frame:self._current_frame + chunksize] * self._gain
if self._fadecurve is not None:
outdata[:chunksize, self._mapping] *= self._fadecurve[self._fadeframe:self._fadeframe + chunksize, np.newaxis]
self._fadeframe += chunksize
if chunksize < frames: if chunksize < frames:
outdata[chunksize:, self._mapping] = 0 outdata[chunksize:, self._mapping] = 0
raise sounddevice.CallbackStop() raise sounddevice.CallbackStop()
@@ -88,7 +104,10 @@ class Playback(Event):
def finished_callback(self): def finished_callback(self):
self._data = None self._data = None
self._fadecurve = None
self._fadeframe = None
print("Playback finished") print("Playback finished")
self._eventrunner.finished(self)
def stop(self): def stop(self):
print("Stop playback") print("Stop playback")
@@ -96,6 +115,22 @@ class Playback(Event):
self._stream.close(True) self._stream.close(True)
self._stream = None self._stream = None
def notify(self, message, fadetime=10, db=30, *args, **kwargs):
if message == 'fadeout':
self._fadecurve = np.logspace(0, -db/10, fadetime * self._fs)
self._fadeframe = 0
class FadeOut(Event):
def __init__(self, duration=10, db=30, *args, **kwargs):
super().__init__(*args, **kwargs)
self._duration = duration
self._db = db
def start(self):
print("Fading out")
self._eventrunner.notify('fadeout', fadetime=self._duration, db=self._db)
self._eventrunner.finished(self)
class SetTempo(Event): class SetTempo(Event):
def __init__(self, tempo=None, beats=None, *args, **kwargs): def __init__(self, tempo=None, beats=None, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -106,7 +141,7 @@ class SetTempo(Event):
self._at._timings.register_tempo(self._tempo, self._beats, self._at) self._at._timings.register_tempo(self._tempo, self._beats, self._at)
def start(self): def start(self):
pass self._eventrunner.finished(self)
def stop(self): def stop(self):
pass pass
@@ -120,7 +155,7 @@ class SetMark(Event):
self._at._timings.register_mark(self._name, self._at) self._at._timings.register_mark(self._name, self._at)
def start(self): def start(self):
pass self._eventrunner.finished(self)
def stop(self): def stop(self):
pass pass
@@ -134,7 +169,7 @@ class ButtonMark(Event):
self._at._timings.register_mark(self._name, None) self._at._timings.register_mark(self._name, None)
def start(self): def start(self):
pass self._eventrunner.finished(self)
def stop(self): def stop(self):
pass pass
@@ -146,10 +181,15 @@ class Lyrics(Event):
self._duration = duration self._duration = duration
def start(self): def start(self):
self.audiencecontent.new_content(display.DisplayLyrics(self._text)) self._audiencecontent.new_content(display.DisplayLyrics(self._text))
print("Started displaying lyrics") print("Started displaying lyrics")
print(self._text) print(self._text)
def stop(self): def stop(self):
self.audiencecontent.new_content(display.DisplayContent()) self._audiencecontent.new_content(display.DisplayContent())
print("Stopped displaying lyrics") print("Stopped displaying lyrics")
def notify(self, message, *args, **kwargs):
if message == 'newdisplay':
self._eventrunner.finished(self)

14
gig.py
View File

@@ -24,6 +24,8 @@ class EventRunner:
self._playing = None self._playing = None
self._active = [] self._active = []
self._currentitem = None self._currentitem = None
for item in self._gigconfig['items']:
self._gigconfig['items'][item].set_eventrunner(self)
def set_audiencecontent(self, audiencecontent): def set_audiencecontent(self, audiencecontent):
for item in self._gigconfig['items']: for item in self._gigconfig['items']:
@@ -75,6 +77,7 @@ class EventRunner:
self._playing = None self._playing = None
self._selected = None self._selected = None
for event in self._active: for event in self._active:
if event is not None:
event.stop() event.stop()
self._active = [] self._active = []
if self._currentitem is not None: if self._currentitem is not None:
@@ -84,6 +87,17 @@ class EventRunner:
event.start() event.start()
self._active.append(event) self._active.append(event)
def notify(self, *args, **kwargs):
for event in self._active:
if event is not None:
event.notify(*args, **kwargs)
def finished(self, event):
# We might get called back here from within a notify or other such construct
for i, e in enumerate(self._active):
if e is event:
self._active[i] = None
def pause(self): def pause(self):
pass pass

View File

@@ -51,3 +51,7 @@ class Item:
def set_audiencecontent(self, audiencecontent): def set_audiencecontent(self, audiencecontent):
for event in self._events: for event in self._events:
event.set_audiencecontent(audiencecontent) event.set_audiencecontent(audiencecontent)
def set_eventrunner(self, eventrunner):
for event in self._events:
event.set_eventrunner(eventrunner)