Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

native: fix -80dB attenuation from system_volume=-1 + software volume keys

ROOT CAUSE of super-quiet speaker audio: read_system_volume_card()
returns -1 when no "Master" mixer exists (SOF cards). The audio
thread's gain stage computed vol = (-0.01)^2 = 0.0001 → -80dB!

Fixes:
- Treat system_volume < 0 as 100% (no attenuation)
- Volume keys: when no hardware Master, step software gain ±5%
- S32_LE shift: <<8 instead of <<16 (24-bit DAI alignment)
- Dither reduced to ±1 LSB (±160 was audible as 24kHz fizz)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+30 -7
+30 -7
fedac/native/src/audio.c
··· 1480 1480 1481 1481 // Apply system volume (software gain — hardware mixer may not attenuate) 1482 1482 { 1483 - double vol = audio->system_volume * 0.01; // 0-100 → 0.0-1.0 1483 + int sv = audio->system_volume; 1484 + // -1 means no Master mixer found (SOF cards) — treat as 100% 1485 + if (sv < 0) sv = 100; 1486 + double vol = sv * 0.01; // 0-100 → 0.0-1.0 1484 1487 // Use squared curve for more natural volume perception 1485 1488 vol = vol * vol; 1486 1489 mix_l *= vol; ··· 1589 1592 } 1590 1593 } 1591 1594 /* Widen int16→int32 for S32_LE PCMs (SOF topology). 1592 - * Left-shift by 16 places the 16-bit sample in the top half 1593 - * of the 32-bit word, which maps correctly to the S24_LE BE 1594 - * DAI after the DSP truncates the bottom 8 bits. */ 1595 + * The SSP1 BE DAI runs S24_LE. SOF DSP uses the bottom 24 1596 + * bits of the S32 container (bits 23:0). Shifting int16 by 1597 + * 8 places our 16-bit audio in bits 23:8, which fills the 1598 + * top portion of the 24-bit window — correct for S24-in-S32 1599 + * bottom-aligned format. (<<16 put data in bits 31:16 which 1600 + * the DSP's 24-bit window barely saw → super quiet.) */ 1595 1601 const void *write_buf = buffer; 1596 1602 if (buffer32) { 1597 1603 for (int j = 0; j < (int)(period_frames * AUDIO_CHANNELS); j++) 1598 - buffer32[j] = (int32_t)buffer[j] << 16; 1604 + buffer32[j] = (int32_t)buffer[j] << 8; 1599 1605 write_buf = buffer32; 1600 1606 } 1601 1607 int remaining = (int)period_frames; ··· 3452 3458 } 3453 3459 snd_mixer_close(mixer); 3454 3460 3455 - // Update cached system volume 3456 - audio->system_volume = muted ? 0 : read_system_volume_card(audio->card_index); 3461 + // Update cached system volume. On SOF cards without a "Master" mixer, 3462 + // read_system_volume_card returns -1. In that case, use software-only 3463 + // volume: start at 100 and step ±5 with volume keys. 3464 + if (muted) { 3465 + audio->system_volume = 0; 3466 + } else { 3467 + int hw_vol = read_system_volume_card(audio->card_index); 3468 + if (hw_vol >= 0) { 3469 + audio->system_volume = hw_vol; 3470 + } else { 3471 + // No Master mixer — software gain mode 3472 + int sv = audio->system_volume; 3473 + if (sv < 0) sv = 100; // first call: default 100% 3474 + if (delta > 0) sv = (sv + 5 > 100) ? 100 : sv + 5; 3475 + else if (delta < 0) sv = (sv - 5 < 0) ? 0 : sv - 5; 3476 + audio->system_volume = sv; 3477 + ac_log("[audio] Software volume: %d%%\n", sv); 3478 + } 3479 + } 3457 3480 } 3458 3481 3459 3482 void audio_boot_beep(ACAudio *audio) {