音声の制御
音声を再生する場合は一般には再生ボタンを押すのでびっくりすることは少ないです。一方、音声のほとんどは音声オブジェクトの終了で停止します。最後は音声レベルがゼロになるように作られています。

つまり、上図のように音声オブジェクトにおいてフェードイン、フェードアウトを考慮したオブジェクトになっているのがほとんどですが、長いBGMが流れているときに別の要因で音声を停止するとき、緩やかに音声が消えるようになるのが理想です。音が鳴り響くときは徐々に大きくなり、停止する場合は徐々にすぼまることをフェードイン/フェードアウトと言っています。
人の会話のように、話の間、接ぎ穂など細かな会話の技法の代わりになるのがフェードイン/フェードアウト操作です。そのやり方がaudioの音をフェードイン・フェードアウトさせるに解説されていましたので参考にさせて頂きました。
ねらいと手法

audio要素にcontrolsを指定すると再生ボタンなどのインターフェースを表示させることができ、addEventListenerにより、playとpauseイベント関数を設定することができます。その関数でvolume属性を0~1.0に制御するねらいを立てました。
これはplayイベントではねらいどおりになりましたが、pauseではすぐに音声が停止されるのでフェードアウトされず、プチっと音が消えるので不採用になりました。

そこで参考サイトにあるようにbutton要素でplayとpauseのクリックイベントで処理するのがオーソドックスな手法のようです。
play-play、pause-pauseなど誤った操作を処理するのを省くために、一つのクリックボタンをシーソースイッチのように扱ってフェードインとフェードアウトを制御します。
フェードインとフェードアウトの動作コード
<!DOCTYPE html>
<html>
<body>
<audio id="bgm" src="https://aidesign.lolipop.jp/wp-content/uploads/2014/09/yorunowaltz.mp3"></audio> <!-- 56sec -->
<button type="button" id="play" style="color:blueviolet; font-weight:bold;">⏵</button>
<progress id="prog" max="100" value="0"></progress> <span id="outp"></span>
<span style='font-size:12px;color:navy;font-weight:bold;'> ©TacM,2018 Ver0.02</span><BR>参照音楽:『甘茶の音楽工房』《夜のワルツ》
<script type="text/javascript" charset="Shift_JIS">
const baseVol = 1.0; //audioのベース音量
const fadeInSpeed = 400; //フェードインのスピード
const fadeOutSpeed = 1500; //フェードアウトのスピード
var count=0; //シーソースイッチに利用
var music = document.getElementById('bgm'); // audioの作成, 音声ファイルの指定
var audio_func = setInterval(function() { //audioのオブジェクトの進捗度
document.getElementById('outp').innerHTML = HourMinSec(music.currentTime) + " / " + HourMinSec(music.duration);
document.getElementById('prog').value = Math.round(music.currentTime / music.duration * 100);
}, 100);
music.addEventListener("ended", function(){ //音声完了
clearInterval(audio_func);
music.currentTime=0;
}, false);
document.getElementById('play').addEventListener('click', function() { //audioの再生, audioの停止
document.getElementById('play').innerHTML = "\u23F8\u23F5".substr(count%2, 1); //表示する文字を変更
if(++count % 2) feedInFunc(); //フェードイン関数
else feedOutFunc(); //フェードアウト関数
}, false);
function feedInFunc(){ //フェードイン関数, fadeInSpeedでフェードイン
music.volume = 0;
music.play();
var start_func = setInterval(function() { //フェードイン関数, fadeInSpeedでフェードイン
music.volume = music.volume + (baseVol / 100);
if(music.volume >= baseVol - (baseVol / 100)) {
music.volume = baseVol;
clearInterval(start_func);
}
}, fadeInSpeed * baseVol / 100);
}
function feedOutFunc(){ //フェードアウト関数, fadeOutSpeedでフェードアウト
var end_func = setInterval(function() {
music.volume = music.volume - (baseVol / 100);
if(music.volume <= (baseVol / 100)) {
//music.volume = baseVol; //Ver0.02で削除
music.pause();
clearInterval(end_func);
}
}, fadeOutSpeed * baseVol / 100);
}
function HourMinSec(t){ //audioのオブジェクトの進捗度を整えて表示
if(t<3600) return(letter2(Math.floor(t/60)) + ":" + letter2(Math.round(t%60))); //一時間以上は次の機会に
else return("no support");
}
function letter2(num) {return ('0' + num).slice(-2);} //1桁の数字の先頭に0を付加する
</script>
</body>
</html>
フェードインとフェードアウトの動作例
フェードインは400ミリ秒、フェードアウトは1.5秒に設定しています。大音量を好み、心臓を大切にされる方はfadeInSpeedの値を大きくしてください。緩やかに立ち上がります。再生と一時停止を何度かクリックしてフェードインとフェードアウトの効果を試してください。
太古の昔、食事は栄養の補給でしたが、そのうち、食事を楽しむ余裕が生まれて豊かな生活へと進んだことでしょう。フェードインとフェードアウトの効果がその一翼を担えたら幸いです。
©TacM,2018 Ver0.02
参照音楽:『甘茶の音楽工房』《夜のワルツ》
注意
上の動作例は一度、動作完了して再実行するようには配慮されていません。その場合には再読み込みして実行してください。また、フェードアウトの最後にカツッとノイズが入るブラウザがありますが、それはブラウザの好まざる特徴と思われます。少なくもChromeとOperaでは発生しません。
Ver0.02でsetIntervalとclearIntervalにおけるブラウザ間の微妙な挙動の違いを吸収しています。この改訂でノイズの発生は避けられた模様です。(2018-10-10追記)
映像への応用
この手法は映像に応用することができます。img要素にopacity属性を絡めて制御すれば、映像を薄い表示から濃い表示にすることができます。

また、一つが消え去りつつ、他方が緩やかに現れるクロスフェードのような描画も可能になります。限りない可能性を大切にしてください。