import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/servicios/servicio_audio.dart'; /// eq-estado-unico item E — `mapearGananciaNativa`, the translation from the /// app's fixed ±12 dB slider scale to whatever range the device's native /// `Equalizer.getBandLevelRange()` reports. /// /// This is the only source-plausible explanation for the reported «suena muy /// alto» half of the bug. The original implementation normalised the input /// across the WHOLE range and mapped it linearly: /// /// normalizado = (db.clamp(-12, 12) + 12) / 24 /// return minDecibels + normalizado * (maxDecibels - minDecibels) /// /// which sends 0 dB to the MIDPOINT of the native range. That is only 0 when /// the range happens to be symmetric. Android does not guarantee that: the /// AudioEffect Equalizer contract only requires a min/max pair, and real /// devices ship asymmetric ranges. On such a device a FLAT preset — every /// band 0 dB — was silently pushing a positive boost into every band, which /// is audibly louder while the on/off button still reads "off". /// /// The contract asserted here: 0 dB always maps to exactly 0, and the two /// sides of the scale are stretched INDEPENDENTLY against their own end of /// the native range, so the sign of the user's intent is never inverted and /// the extremes still reach the device's real limits. void main() { group('mapearGananciaNativa — 0 dB is always exactly 0', () { test('symmetric range (the common case) is unchanged', () { expect( mapearGananciaNativa(0, minDecibels: -15, maxDecibels: 15), 0, ); }); test('asymmetric range no longer boosts a FLAT preset', () { // The reported symptom: on a device reporting [-12, +19] the old // midpoint mapping turned every 0 dB band into +3.5 dB of real boost. expect( mapearGananciaNativa(0, minDecibels: -12, maxDecibels: 19), 0, reason: 'a FLAT preset must be inaudible, on every device', ); }); test('a wholly positive range still cannot boost a FLAT preset', () { expect(mapearGananciaNativa(0, minDecibels: 3, maxDecibels: 19), 0); }); test('a wholly negative range still cannot cut a FLAT preset', () { expect(mapearGananciaNativa(0, minDecibels: -19, maxDecibels: -3), 0); }); }); group('mapearGananciaNativa — the extremes reach the native limits', () { test('+12 dB maps to the native maximum', () { expect(mapearGananciaNativa(12, minDecibels: -12, maxDecibels: 19), 19); }); test('-12 dB maps to the native minimum', () { expect(mapearGananciaNativa(-12, minDecibels: -12, maxDecibels: 19), -12); }); test('values beyond the slider scale are clamped, not extrapolated', () { expect(mapearGananciaNativa(40, minDecibels: -15, maxDecibels: 15), 15); expect(mapearGananciaNativa(-40, minDecibels: -15, maxDecibels: 15), -15); }); }); group('mapearGananciaNativa — each side scales against its own end', () { test('half boost is half of the positive headroom', () { expect( mapearGananciaNativa(6, minDecibels: -12, maxDecibels: 20), closeTo(10, 1e-9), ); }); test('half cut is half of the negative headroom', () { expect( mapearGananciaNativa(-6, minDecibels: -12, maxDecibels: 20), closeTo(-6, 1e-9), ); }); test('the sign of the user intent is never inverted', () { for (final db in [-12.0, -6.0, -1.0, 1.0, 6.0, 12.0]) { final nativo = mapearGananciaNativa( db, minDecibels: -12, maxDecibels: 19, ); expect( nativo.sign, db.sign, reason: 'a cut must never become a boost ($db dB -> $nativo)', ); } }); }); group('mapearGananciaNativa — degenerate ranges reported by the device', () { test('a range with no headroom on one side clamps that side to 0', () { // A device that reports max == 0 can only cut. Asking for a boost must // resolve to "no change", never to a negative value. expect(mapearGananciaNativa(12, minDecibels: -15, maxDecibels: 0), 0); expect(mapearGananciaNativa(-12, minDecibels: -15, maxDecibels: 0), -15); }); test('a zero-width range collapses everything to 0', () { expect(mapearGananciaNativa(12, minDecibels: 0, maxDecibels: 0), 0); expect(mapearGananciaNativa(-12, minDecibels: 0, maxDecibels: 0), 0); }); test('the result never escapes the native range', () { for (final db in [-12.0, -3.0, 0.0, 3.0, 12.0]) { final nativo = mapearGananciaNativa( db, minDecibels: -3, maxDecibels: 19, ); expect(nativo, greaterThanOrEqualTo(-3)); expect(nativo, lessThanOrEqualTo(19)); } }); }); }