Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 54 additions & 13 deletions native-bridge/src/audio/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ pub struct AudioEngine {

// Connection health tracking
last_browser_read_time: Arc<AtomicU64>,

// Diagnostic counters for effects processing
effects_applied_count: Arc<AtomicU64>,
effects_skipped_count: Arc<AtomicU64>,
}

impl AudioEngine {
Expand Down Expand Up @@ -248,6 +252,9 @@ impl AudioEngine {
browser_stream_overflow_count: Arc::new(AtomicU64::new(0)),
browser_stream_overflow_samples: Arc::new(AtomicU64::new(0)),
last_browser_read_time: Arc::new(AtomicU64::new(0)),
// Diagnostic counters for effects processing
effects_applied_count: Arc::new(AtomicU64::new(0)),
effects_skipped_count: Arc::new(AtomicU64::new(0)),
})
}

Expand Down Expand Up @@ -382,8 +389,33 @@ impl AudioEngine {
}

pub fn update_effects(&self, effects: crate::effects::EffectsSettings) {
if let Ok(mut state) = self.processing_state.write() {
state.effects_chain.update_settings(effects);
// Log which effects are enabled for debugging
let enabled_effects: Vec<&str> = [
("wah", effects.wah.enabled),
("overdrive", effects.overdrive.enabled),
("distortion", effects.distortion.enabled),
("amp", effects.amp.enabled),
("reverb", effects.reverb.enabled),
("delay", effects.delay.enabled),
("chorus", effects.chorus.enabled),
("compressor", effects.compressor.enabled),
("eq", effects.eq.enabled),
]
.iter()
.filter(|(_, enabled)| *enabled)
.map(|(name, _)| *name)
.collect();

info!("Updating effects chain. Enabled: {:?}", enabled_effects);

match self.processing_state.write() {
Ok(mut state) => {
state.effects_chain.update_settings(effects);
info!("Effects chain updated successfully");
}
Err(e) => {
tracing::error!("Failed to acquire write lock for effects update: {:?}", e);
}
}
}

Expand Down Expand Up @@ -980,7 +1012,22 @@ impl AudioEngine {
stereo_buffer.push(right_sample);
}

// Apply effects FIRST so they're included in both browser stream and local monitoring
// This ensures other users in the session hear the effects too
if let Ok(mut state) = processing_state.try_write() {
let gain = state.track_state.input_gain_linear();

// Apply input gain
for sample in stereo_buffer.iter_mut() {
*sample *= gain;
}

// Process through effects chain
state.effects_chain.process(stereo_buffer);
}

// Calculate input levels (stereo) - interleaved L/R samples
// Note: levels are post-effects now
let (level_l, level_r) = stereo_buffer
.chunks_exact(2)
.fold((0.0_f32, 0.0_f32), |(max_l, max_r), chunk| {
Expand Down Expand Up @@ -1015,23 +1062,17 @@ impl AudioEngine {
false // Default to not muted - let audio through
};

// WET monitoring: apply effects chain for local monitoring
// Local monitoring: apply volume, pan, and push to output
// Note: Effects were already applied above (before browser stream)
let should_monitor = monitoring_enabled && !is_muted;

if should_monitor {
if let Ok(mut state) = processing_state.try_write() {
let gain = state.track_state.input_gain_linear();
// Apply volume and pan for local monitoring
// Effects are already applied, just need volume/pan
if let Ok(state) = processing_state.try_read() {
let volume = state.track_state.volume;
let (pan_left, pan_right) = state.track_state.pan_gains();

// Apply input gain first
for sample in stereo_buffer.iter_mut() {
*sample *= gain;
}

// Process through effects chain (if any effects are enabled)
state.effects_chain.process(stereo_buffer);

// Apply volume, pan, and monitoring volume to stereo pairs
for chunk in stereo_buffer.chunks_exact_mut(2) {
let base_gain = volume * mon_vol;
Expand Down
2 changes: 1 addition & 1 deletion native-bridge/src/effects/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct EffectsSettings {
pub overdrive: OverdriveSettings,
#[serde(default)]
pub distortion: DistortionSettings,
#[serde(default)]
#[serde(default, alias = "ampSimulator")]
pub amp: AmpSettings,
#[serde(default)]
pub cabinet: CabinetSettings,
Expand Down
10 changes: 8 additions & 2 deletions src/hooks/useNativeBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,17 +252,21 @@ export function useNativeBridge() {

// Auto-start native bridge when room is connected and bridge is preferred
// This ensures users don't have to manually start audio after joining a room
// DISABLED: This was causing issues by trying to start without an ASIO device selected
// Users must manually start audio from settings after selecting their device
/*
useEffect(() => {
// Subscribe to room store for connection changes
const unsubscribeRoom = useRoomStore.subscribe((roomState) => {
const bridgeState = useBridgeAudioStore.getState();

// Check if we should auto-start: room connected + bridge connected + bridge preferred + not already running
// Check if we should auto-start: room connected + bridge connected + bridge preferred + not already running + device selected
if (
roomState.isConnected &&
bridgeState.isConnected &&
bridgeState.preferNativeBridge &&
!bridgeState.isRunning
!bridgeState.isRunning &&
bridgeState.inputDevice // Must have a device selected
) {
console.log('[useNativeBridge] Room connected with bridge preferred, auto-starting audio...');
// Use a small delay to ensure all other initialization has completed
Expand All @@ -275,6 +279,7 @@ export function useNativeBridge() {
latestBridge.isConnected &&
latestBridge.preferNativeBridge &&
!latestBridge.isRunning &&
latestBridge.inputDevice &&
startAudioRef.current
) {
console.log('[useNativeBridge] Executing auto-start via ref...');
Expand All @@ -292,6 +297,7 @@ export function useNativeBridge() {
unsubscribeRoom();
};
}, []);
*/

// Connect to bridge
const connect = useCallback(async () => {
Expand Down
7 changes: 5 additions & 2 deletions src/stores/bridge-audio-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,14 @@ export const useBridgeAudioStore = create<BridgeAudioState>()(
// Persisted settings
selectedInputDeviceId: null,
selectedOutputDeviceId: null,
// Default to MONO for most common use case (single microphone/instrument)
// Stereo users will configure this in settings
inputChannelConfig: {
channelCount: 2,
channelCount: 1,
leftChannel: 0,
rightChannel: 1,
rightChannel: undefined,
},
// Output stays stereo for monitoring
outputChannelConfig: {
channelCount: 2,
leftChannel: 0,
Expand Down
7 changes: 4 additions & 3 deletions src/stores/user-tracks-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ export const TRACK_COLORS = [
'#c084fc', // Purple
];

// Default channel configuration (stereo)
// Default channel configuration (MONO - most common for single input)
// Users with stereo inputs can change this in settings
const DEFAULT_CHANNEL_CONFIG: InputChannelConfig = {
channelCount: 2,
channelCount: 1,
leftChannel: 0,
rightChannel: 1,
rightChannel: undefined,
};

// Default audio settings with extended effects chain
Expand Down
Loading