@@ -1458,7 +1458,7 @@ <h4 class="modal-title w-100 text-center" id="simulateWelcomeModalLabel">Welcome
14581458 </ div >
14591459 < div class ="col-12 col-md-auto mt-2 mt-md-0 d-flex align-items-center gap-2 ms-md-2 ">
14601460 < label class ="text-nowrap mb-0 text-white " id ="synth-level-label " for ="synth-level-slider " style ="font-size:0.875rem; cursor:pointer; " title ="Click to set a MIDI CC for this channel's level "> Level</ label >
1461- < input type ="range " class ="form-range " id ="synth-level-slider " min ="0.001 " max ="7 " step ="0.001 " value ="1 " style ="width:100px; ">
1461+ < input type ="range " class ="form-range " id ="synth-level-slider " min ="0 " max ="1 " step ="0.001 " value ="0.521 " style ="width:100px; ">
14621462 </ div >
14631463 < div class ="col-12 col-md-auto mt-2 mt-md-0 d-flex align-items-center gap-2 ms-md-2 ">
14641464 < label class ="text-nowrap mb-0 text-white " for ="bus-select " style ="font-size:0.875rem; " title ="Which mix bus this channel's synth is routed to. Each bus has its own Effects. "> Bus</ label >
@@ -1473,7 +1473,7 @@ <h4 class="modal-title w-100 text-center" id="simulateWelcomeModalLabel">Welcome
14731473 < div class ="patch-global-title ">
14741474 < span > FX</ span >
14751475 < label class ="text-nowrap mb-0 " id ="fx-level-label " for ="fx-level-slider " style ="font-size:0.75rem; font-weight:400; letter-spacing:normal; text-transform:none; cursor:pointer; " title ="Master level of this channel's mix bus. Click to set a MIDI CC. "> Level</ label >
1476- < input type ="range " class ="form-range " id ="fx-level-slider " min ="0.001 " max ="7 " step ="0.001 " value ="1 " style ="width:100px; ">
1476+ < input type ="range " class ="form-range " id ="fx-level-slider " min ="0 " max ="1 " step ="0.001 " value ="0.521 " style ="width:100px; ">
14771477 </ div >
14781478 </ div >
14791479 < div class ="patch-layout-body ">
@@ -1988,14 +1988,32 @@ <h5 class="modal-title" id="adminTokenModalLabel">Admin Token Required</h5>
19881988 const patchLoadModalButton = document . getElementById ( "patch-open-load-modal-btn" ) ;
19891989 const loadPatchModalEl = document . getElementById ( "loadPatchModal" ) ;
19901990 const patchClearChannelButton = document . getElementById ( "patch-clear-channel-btn" ) ;
1991+ // Pseudo-log mapping for both Level sliders (channel and FX/bus):
1992+ // slider position p in [0,1] -> level = 10^(2(p-0.5)) - 0.1, so the
1993+ // level is 0.0 at the left edge, ~1 at mid, 9.9 at the right edge.
1994+ // Same curve as AMY's log MIDI-CC mapping with min 0, max 9.9,
1995+ // offset 0.1 (which the dedicated level knobs use), so a hardware CC
1996+ // sweep and a slider sweep track identically.
1997+ function levelSliderToValue ( p ) {
1998+ p = Math . min ( 1 , Math . max ( 0 , Number ( p ) || 0 ) ) ;
1999+ return Math . pow ( 10 , 2 * ( p - 0.5 ) ) - 0.1 ;
2000+ }
2001+ function levelValueToSlider ( v ) {
2002+ v = Number ( v ) ;
2003+ if ( ! Number . isFinite ( v ) || v < 0 ) v = 0 ;
2004+ return Math . min ( 1 , Math . max ( 0 , 0.5 + 0.5 * Math . log10 ( v + 0.1 ) ) ) ;
2005+ }
2006+
19912007 const synthLevelSlider = document . getElementById ( "synth-level-slider" ) ;
19922008 const _synthLevels = { } ; // per-channel level storage
19932009 function getSynthLevel ( ch ) { return _synthLevels [ ch ] != null ? _synthLevels [ ch ] : 1 ; }
19942010 function setSynthLevel ( val , send ) {
19952011 const ch = Number ( window . current_synth || 1 ) ;
1996- val = Math . min ( 7 , Math . max ( 0.001 , Number ( val ) || 1 ) ) ;
2012+ val = Number ( val ) ;
2013+ if ( ! Number . isFinite ( val ) ) val = 1 ;
2014+ val = Math . min ( 9.9 , Math . max ( 0 , val ) ) ;
19972015 _synthLevels [ ch ] = val ;
1998- if ( synthLevelSlider ) synthLevelSlider . value = val ;
2016+ if ( synthLevelSlider ) synthLevelSlider . value = levelValueToSlider ( val ) ;
19992017 if ( send && typeof window . amy_add_log_message === "function" ) {
20002018 var code = "i" + ch + "v0a" + val . toFixed ( 3 ) ;
20012019 window . amy_add_log_message ( code ) ;
@@ -2011,17 +2029,18 @@ <h5 class="modal-title" id="adminTokenModalLabel">Admin Token Required</h5>
20112029 function syncSynthLevelForChannel ( ) {
20122030 var ch = Number ( window . current_synth || 1 ) ;
20132031 var val = getSynthLevel ( ch ) ;
2014- if ( synthLevelSlider ) synthLevelSlider . value = val ;
2032+ if ( synthLevelSlider ) synthLevelSlider . value = levelValueToSlider ( val ) ;
20152033 }
20162034 if ( synthLevelSlider ) {
2017- synthLevelSlider . addEventListener ( "input" , function ( ) { setSynthLevel ( synthLevelSlider . value , true ) ; } ) ;
2035+ synthLevelSlider . addEventListener ( "input" , function ( ) { setSynthLevel ( levelSliderToValue ( synthLevelSlider . value ) , true ) ; } ) ;
20182036 }
20192037 window . syncSynthLevelForChannel = syncSynthLevelForChannel ;
20202038 window . setSynthLevelFromAmy = function ( ch , val ) {
2021- val = Math . min ( 7 , Math . max ( 0.001 , Number ( val ) || 1 ) ) ;
2039+ val = Number ( val ) ;
2040+ if ( ! Number . isFinite ( val ) || val < 0 ) val = 1 ;
20222041 _synthLevels [ ch ] = val ;
20232042 if ( Number ( window . current_synth || 1 ) === ch ) {
2024- if ( synthLevelSlider ) synthLevelSlider . value = val ;
2043+ if ( synthLevelSlider ) synthLevelSlider . value = levelValueToSlider ( val ) ;
20252044 }
20262045 } ;
20272046 // Clicking the "Level" label opens the same MIDI-CC popup the knobs use,
@@ -2076,14 +2095,16 @@ <h5 class="modal-title" id="adminTokenModalLabel">Admin Token Required</h5>
20762095 var bus = currentBus ( ) ;
20772096 var vols = Array . isArray ( window . amy_bus_volumes ) ? window . amy_bus_volumes : [ ] ;
20782097 var val = ( vols [ bus ] != null ) ? vols [ bus ] : 1 ;
2079- if ( fxLevelSlider ) fxLevelSlider . value = val ;
2098+ if ( fxLevelSlider ) fxLevelSlider . value = levelValueToSlider ( val ) ;
20802099 }
20812100 window . syncFxLevelForBus = syncFxLevelForBus ;
20822101 function setFxLevel ( val , send ) {
20832102 var bus = currentBus ( ) ;
2084- val = Math . min ( 7 , Math . max ( 0.001 , Number ( val ) || 1 ) ) ;
2103+ val = Number ( val ) ;
2104+ if ( ! Number . isFinite ( val ) ) val = 1 ;
2105+ val = Math . min ( 9.9 , Math . max ( 0 , val ) ) ;
20852106 if ( Array . isArray ( window . amy_bus_volumes ) ) window . amy_bus_volumes [ bus ] = val ;
2086- if ( fxLevelSlider ) fxLevelSlider . value = val ;
2107+ if ( fxLevelSlider ) fxLevelSlider . value = levelValueToSlider ( val ) ;
20872108 if ( send && typeof window . amy_add_log_message === "function" ) {
20882109 // Bus-addressed volume: y<bus>V<val> sets that bus's mixdown gain.
20892110 var code = "y" + bus + "V" + val . toFixed ( 3 ) ;
@@ -2095,7 +2116,7 @@ <h5 class="modal-title" id="adminTokenModalLabel">Admin Token Required</h5>
20952116 }
20962117 }
20972118 if ( fxLevelSlider ) {
2098- fxLevelSlider . addEventListener ( "input" , function ( ) { setFxLevel ( fxLevelSlider . value , true ) ; } ) ;
2119+ fxLevelSlider . addEventListener ( "input" , function ( ) { setFxLevel ( levelSliderToValue ( fxLevelSlider . value ) , true ) ; } ) ;
20992120 }
21002121 // Clicking the Effects "Level" label opens the MIDI-CC popup for the
21012122 // bus's dedicated level knob (template i%iV%v — resolves the bus from
0 commit comments