@@ -165,6 +165,12 @@ def __init__(self,
165165 .track property that can be used to identify the track that the event occurred on.
166166 """
167167
168+ self .on_exception_callback : Optional [Callable ] = None
169+ """
170+ Optional callback to trigger each time an exception is raised during event processing.
171+ Receives args: (exception, traceback)
172+ """
173+
168174 self .events_in_last_second : int = 0
169175 self .events_per_second : float = 0.0
170176 def _measure_events_per_second ():
@@ -381,8 +387,12 @@ def tick(self):
381387 try :
382388 track .tick ()
383389 except Exception as e :
384- if self .ignore_exceptions :
385- tb = traceback .format_exc ()
390+ tb = traceback .format_exc ()
391+
392+ if self .on_exception_callback :
393+ self .on_exception_callback (e , tb )
394+
395+ if self .ignore_exceptions :
386396 logger .warning ("*** Exception in track: %s" % tb )
387397 # TODO: Possibly don't remove tracks specifically for the case in which SignalFlow
388398 # throws a CPU exception? Generally, tracks should be stopped to prevent runaway repeats
@@ -817,7 +827,8 @@ def automation(self,
817827 curve = curve ,
818828 boundaries = boundaries ,
819829 default_duration = default_duration )
820- self .automations .append (automation )
830+ if automation not in self .automations :
831+ self .automations .append (automation )
821832 return automation
822833
823834 def get_track (self , track_id : Union [int , str ]) -> Optional [Track ]:
0 commit comments