v0.5 — cleanup orphan code, add MIDI master volume learn, fix turn-deck crashes
- Remove vestigial lufs_meter_widget.py and debug_audio.py - Delete unused WaveformWidget/WaveformMonitor classes, dead stubs, duplicate code - Fix turn-mode deck crashes (deck3/deck4 missing from engine.decks, uninitialized manual_elapsed/duration) - Replace raw print() with logging in main.py - Add master_volume MIDI learn signal + settings popup entry - Bump version to 0.5
This commit is contained in:
+43
-27
@@ -89,6 +89,8 @@ class DeckState:
|
||||
self.position = 0
|
||||
self.playing = False
|
||||
self.lock = threading.Lock()
|
||||
self.manual_elapsed = 0.0
|
||||
self.manual_duration = 0.0
|
||||
|
||||
def load(self, track: Track):
|
||||
with self.lock:
|
||||
@@ -131,15 +133,17 @@ class DeckState:
|
||||
self.position = self.track.num_samples - 1
|
||||
|
||||
def get_elapsed(self) -> str:
|
||||
if not self.track:
|
||||
return "00:00"
|
||||
s = self.position / self.track.sr
|
||||
with self.lock:
|
||||
if not self.track:
|
||||
return "00:00"
|
||||
s = self.position / self.track.sr
|
||||
return f"{int(s//60):02d}:{int(s%60):02d}"
|
||||
|
||||
def get_remaining(self) -> str:
|
||||
if not self.track:
|
||||
return "-00:00"
|
||||
remaining = max(0, self.track.duration - (self.position / self.track.sr))
|
||||
with self.lock:
|
||||
if not self.track:
|
||||
return "-00:00"
|
||||
remaining = max(0, self.track.duration - (self.position / self.track.sr))
|
||||
return f"-{int(remaining//60):02d}:{int(remaining%60):02d}"
|
||||
|
||||
|
||||
@@ -228,6 +232,8 @@ class MasterBus:
|
||||
self.limiter = Limiter()
|
||||
self.vu_peak = 0.0
|
||||
self.lufs_current = -70.0
|
||||
self.volume = 1.0
|
||||
self._lufs_accum = 0
|
||||
|
||||
|
||||
class AudioEngine:
|
||||
@@ -289,6 +295,8 @@ class AudioEngine:
|
||||
self.decks = {
|
||||
'deck1': DeckState(),
|
||||
'deck2': DeckState(),
|
||||
'deck3': DeckState(),
|
||||
'deck4': DeckState(),
|
||||
'cart1': DeckState(),
|
||||
'cart2': DeckState(),
|
||||
'cart3': DeckState(),
|
||||
@@ -301,10 +309,6 @@ class AudioEngine:
|
||||
def get_channel(self, index: int) -> MixerChannel:
|
||||
return self.mixer['channels'][index]
|
||||
|
||||
def set_channel_name(self, index: int, name: str):
|
||||
if 0 <= index < NUM_MIXER_CHANNELS:
|
||||
self.mixer['channels'][index].name = name
|
||||
|
||||
def set_channel_volume(self, index: int, volume: float):
|
||||
if 0 <= index < NUM_MIXER_CHANNELS:
|
||||
self.mixer['channels'][index].volume = max(0.0, min(1.0, volume))
|
||||
@@ -327,25 +331,30 @@ class AudioEngine:
|
||||
buf_L.fill(0.0)
|
||||
buf_R.fill(0.0)
|
||||
|
||||
if not deck.playing or deck.track is None:
|
||||
with deck.lock:
|
||||
playing = deck.playing
|
||||
track = deck.track
|
||||
pos = deck.position
|
||||
|
||||
if not playing or track is None:
|
||||
return
|
||||
|
||||
pos = deck.position
|
||||
track = deck.track
|
||||
end = min(pos + frames, track.num_samples)
|
||||
n = end - pos
|
||||
|
||||
if n <= 0:
|
||||
deck.playing = False
|
||||
with deck.lock:
|
||||
deck.playing = False
|
||||
return
|
||||
|
||||
buf_L[:n] = track.audio[0, pos:end]
|
||||
buf_R[:n] = track.audio[1, pos:end]
|
||||
deck.position += n
|
||||
|
||||
if deck.position >= track.num_samples:
|
||||
deck.playing = False
|
||||
deck.position = track.num_samples - 1
|
||||
with deck.lock:
|
||||
deck.position += n
|
||||
if deck.position >= track.num_samples:
|
||||
deck.playing = False
|
||||
deck.position = track.num_samples - 1
|
||||
|
||||
def _process(self, frames: int):
|
||||
# ── Digital decks ───────────────────────────────────────────────
|
||||
@@ -360,21 +369,25 @@ class AudioEngine:
|
||||
|
||||
for cart_key in ('cart1', 'cart2', 'cart3', 'cart4'):
|
||||
deck = self.decks[cart_key]
|
||||
if not deck.playing or deck.track is None:
|
||||
with deck.lock:
|
||||
playing = deck.playing
|
||||
track = deck.track
|
||||
pos = deck.position
|
||||
if not playing or track is None:
|
||||
continue
|
||||
pos = deck.position
|
||||
track = deck.track
|
||||
end = min(pos + frames, track.num_samples)
|
||||
n = end - pos
|
||||
if n <= 0:
|
||||
deck.playing = False
|
||||
with deck.lock:
|
||||
deck.playing = False
|
||||
continue
|
||||
buf_L[:n] += track.audio[0, pos:end]
|
||||
buf_R[:n] += track.audio[1, pos:end]
|
||||
deck.position += n
|
||||
if deck.position >= track.num_samples:
|
||||
deck.playing = False
|
||||
deck.position = track.num_samples - 1
|
||||
with deck.lock:
|
||||
deck.position += n
|
||||
if deck.position >= track.num_samples:
|
||||
deck.playing = False
|
||||
deck.position = track.num_samples - 1
|
||||
|
||||
# ── External input monitors (deck3, deck4) ─────────────────────
|
||||
gate_linear = 10 ** (-46.0 / 20.0)
|
||||
@@ -456,7 +469,10 @@ class AudioEngine:
|
||||
master_peak = max(np.max(np.abs(master_audio[0])), np.max(np.abs(master_audio[1])))
|
||||
self.mixer['master'].vu_peak = master_peak
|
||||
|
||||
if frames % 512 < frames:
|
||||
master = self.mixer['master']
|
||||
master._lufs_accum += frames
|
||||
if master._lufs_accum >= 512:
|
||||
master._lufs_accum -= 512
|
||||
self._calculate_lufs(master_audio)
|
||||
|
||||
def _calculate_lufs(self, audio: np.ndarray):
|
||||
|
||||
Reference in New Issue
Block a user