From 02671ef14c005698e07df95d37196f64057f432f Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 19 Sep 2026 16:42:31 -0700 Subject: [PATCH] Start late apex breaths smoothly at unity gain --- roadscore/prototype/core_apex.py | 17 ++++++----- roadscore/prototype/test_core_apex.py | 44 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 roadscore/prototype/test_core_apex.py diff --git a/roadscore/prototype/core_apex.py b/roadscore/prototype/core_apex.py index 02685c5939..5a57f29f37 100644 --- a/roadscore/prototype/core_apex.py +++ b/roadscore/prototype/core_apex.py @@ -4,23 +4,24 @@ import numpy as np class CoreApex: def __init__(self, grid, rate=48000, enabled=False,dip_db=-1.): - self.dip_db=max(-3.,min(0.,float(dip_db)));self.grid=grid;self.rate=rate;self.enabled=enabled;self.last_activation=None;self.peak=None;self.events=[];self.rendered_active=False;self.rendered_end=0. + self.dip_db=max(-3.,min(0.,float(dip_db)));self.grid=grid;self.rate=rate;self.enabled=enabled;self.last_activation=None;self.peak=None;self.breath_start=None;self.events=[];self.rendered_active=False;self.rendered_end=0. def process(self, pcm, start_frame, state): self.rendered_active=False;self.rendered_end=(start_frame+len(pcm))/self.rate - if not self.enabled or not self.grid.usable:return pcm + if not self.enabled:return pcm activation=state.get('activation');lead=state.get('lead');now=start_frame/self.rate - if (state.get('kind')=='curve' and state.get('phase')=='anticipation' and activation is not None + if (self.grid.usable and state.get('kind')=='curve' and state.get('phase')=='anticipation' and activation is not None and activation!=self.last_activation and lead is not None and math.isfinite(lead) and .25<=lead<=1.5): self.last_activation=activation if (not self.events or now-self.events[-1]['trigger_seconds']>=8) and sum(now-e['trigger_seconds']<60 for e in self.events)<3: subdivision=60/self.grid.bpm/2 target=self.grid.beat_phase+round((now+lead-self.grid.beat_phase)/subdivision)*subdivision - self.peak=round(target*self.rate);self.events.append({'trigger_seconds':now,'peak_seconds':target,'activation':activation,'dip_db':self.dip_db,'peak_gain':1.}) + self.peak=round(target*self.rate);self.breath_start=max(start_frame,self.peak-round(.7*self.rate));self.events.append({'trigger_seconds':now,'peak_seconds':target,'activation':activation,'dip_db':self.dip_db,'peak_gain':1.}) if self.peak is None:return pcm - offset=(np.arange(start_frame,start_frame+len(pcm))-self.peak)/self.rate - # Half-second breath, then original unity source at the estimated apex. Never boosts/clips the hook. - gain=np.ones(len(pcm),np.float32);inside=(offset>-.7)&(offset<0) - gain[inside]=1-(1-10**(self.dip_db/20))*np.sin(np.pi*(offset[inside]+.7)/.7)**2 + frames=np.arange(start_frame,start_frame+len(pcm)) + # A late prediction shortens the breath instead of jumping into a partly completed dip. + gain=np.ones(len(pcm),np.float32);inside=(frames>self.breath_start)&(frames