Dynamic Audio UI: more controls (#1127)

* Added control to audio ui to select bgm/ambient and lock selection to overide dynamic audio update. Load both assets and char specific audio assets

* correct ambient label and default value when no assets available.

* add padding in audio select

* Correct audio change of background ambient when locked. Updated CSS of audio ui for mobile friendly.

* add space between mixer

* Add checkbox to enable dynamic bgm/ambient switch

* correct background ambient fadout

* continue debuging ambient audio update

* finish debuging

* Fix BGM console error on first run. Reformat plugin code

* Changed audio bgm lock into loop on/off. Added random pick button for bgm. Moved ambient lock button to right.

* Add mouse wheel event handler on volume controls

* Change bgm select to only contain current chat character bgm (solo/group). When enable expression bgm is off, any of the char+asset bgm can play next if not looping.

* Corrected bgm looping at start. Force random to play another song if there is any.

* Format code

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
Tony Ribeiro
2023-09-20 20:36:50 +02:00
committed by GitHub
parent f4d1e2a46e
commit c9783640c0
3 changed files with 514 additions and 63 deletions

View File

@@ -1,6 +1,9 @@
/* /*
Ideas: Ideas:
- Clean design of new ui
- change select text versus options for playing: audio
- cross fading between bgm / start a different time - cross fading between bgm / start a different time
- fading should appear before end when switching randomly
- Background based ambient sounds - Background based ambient sounds
- import option on background UI ? - import option on background UI ?
- Allow background music edition using background menu - Allow background music edition using background menu
@@ -59,6 +62,8 @@ const DEFAULT_EXPRESSIONS = [
]; ];
const SPRITE_DOM_ID = "#expression-image"; const SPRITE_DOM_ID = "#expression-image";
let current_chat_id = null
let fallback_BGMS = null; // Initialized only once with module workers let fallback_BGMS = null; // Initialized only once with module workers
let ambients = null; // Initialized only once with module workers let ambients = null; // Initialized only once with module workers
let characterMusics = {}; // Updated with module workers let characterMusics = {}; // Updated with module workers
@@ -69,16 +74,27 @@ let currentBackground = null;
let cooldownBGM = 0; let cooldownBGM = 0;
let bgmEnded = true;
//#############################// //#############################//
// Extension UI and Settings // // Extension UI and Settings //
//#############################// //#############################//
const defaultSettings = { const defaultSettings = {
enabled: false, enabled: false,
dynamic_bgm_enabled: false,
//dynamic_ambient_enabled: false,
bgm_locked: true,
bgm_muted: true, bgm_muted: true,
ambient_muted: true,
bgm_volume: 50, bgm_volume: 50,
bgm_selected: null,
ambient_locked: true,
ambient_muted: true,
ambient_volume: 50, ambient_volume: 50,
ambient_selected: null,
bgm_cooldown: 30 bgm_cooldown: 30
} }
@@ -90,6 +106,8 @@ function loadSettings() {
Object.assign(extension_settings.audio, defaultSettings) Object.assign(extension_settings.audio, defaultSettings)
} }
$("#audio_enabled").prop('checked', extension_settings.audio.enabled); $("#audio_enabled").prop('checked', extension_settings.audio.enabled);
$("#audio_dynamic_bgm_enabled").prop('checked', extension_settings.audio.dynamic_bgm_enabled);
//$("#audio_dynamic_ambient_enabled").prop('checked', extension_settings.audio.dynamic_ambient_enabled);
$("#audio_bgm_volume").text(extension_settings.audio.bgm_volume); $("#audio_bgm_volume").text(extension_settings.audio.bgm_volume);
$("#audio_ambient_volume").text(extension_settings.audio.ambient_volume); $("#audio_ambient_volume").text(extension_settings.audio.ambient_volume);
@@ -110,6 +128,41 @@ function loadSettings() {
$("#audio_bgm").prop("muted", false); $("#audio_bgm").prop("muted", false);
} }
if (extension_settings.audio.bgm_locked) {
//$("#audio_bgm_lock_icon").removeClass("fa-lock-open");
//$("#audio_bgm_lock_icon").addClass("fa-lock");
$("#audio_bgm").attr("loop", true);
$("#audio_bgm_lock").addClass("redOverlayGlow");
}
else {
//$("#audio_bgm_lock_icon").removeClass("fa-lock");
//$("#audio_bgm_lock_icon").addClass("fa-lock-open");
$("#audio_bgm").attr("loop", false);
$("#audio_bgm_lock").removeClass("redOverlayGlow");
}
/*
if (extension_settings.audio.bgm_selected !== null) {
$("#audio_bgm_select").append(new Option(extension_settings.audio.bgm_selected, extension_settings.audio.bgm_selected));
$("#audio_bgm_select").val(extension_settings.audio.bgm_selected);
}*/
if (extension_settings.audio.ambient_locked) {
$("#audio_ambient_lock_icon").removeClass("fa-lock-open");
$("#audio_ambient_lock_icon").addClass("fa-lock");
$("#audio_ambient_lock").addClass("redOverlayGlow");
}
else {
$("#audio_ambient_lock_icon").removeClass("fa-lock");
$("#audio_ambient_lock_icon").addClass("fa-lock-open");
}
/*
if (extension_settings.audio.ambient_selected !== null) {
$("#audio_ambient_select").append(new Option(extension_settings.audio.ambient_selected, extension_settings.audio.ambient_selected));
$("#audio_ambient_select").val(extension_settings.audio.ambient_selected);
}*/
if (extension_settings.audio.ambient_muted) { if (extension_settings.audio.ambient_muted) {
$("#audio_ambient_mute_icon").removeClass("fa-volume-high"); $("#audio_ambient_mute_icon").removeClass("fa-volume-high");
$("#audio_ambient_mute_icon").addClass("fa-volume-mute"); $("#audio_ambient_mute_icon").addClass("fa-volume-mute");
@@ -125,7 +178,7 @@ function loadSettings() {
$("#audio_bgm_cooldown").val(extension_settings.audio.bgm_cooldown); $("#audio_bgm_cooldown").val(extension_settings.audio.bgm_cooldown);
$("#audio_debug_div").hide(); // DBG $("#audio_debug_div").hide(); // DBG: comment to see debug mode
} }
async function onEnabledClick() { async function onEnabledClick() {
@@ -142,6 +195,51 @@ async function onEnabledClick() {
saveSettingsDebounced(); saveSettingsDebounced();
} }
async function onDynamicBGMEnabledClick() {
extension_settings.audio.dynamic_bgm_enabled = $('#audio_dynamic_bgm_enabled').is(':checked');
currentCharacterBGM = null;
currentExpressionBGM = null;
cooldownBGM = 0;
saveSettingsDebounced();
}
/*
async function onDynamicAmbientEnabledClick() {
extension_settings.audio.dynamic_ambient_enabled = $('#audio_dynamic_ambient_enabled').is(':checked');
currentBackground = null;
saveSettingsDebounced();
}
*/
async function onBGMLockClick() {
extension_settings.audio.bgm_locked = !extension_settings.audio.bgm_locked;
if (extension_settings.audio.bgm_locked) {
extension_settings.audio.bgm_selected = $("#audio_bgm_select").val();
$("#audio_bgm").attr("loop", true);
}
else {
$("#audio_bgm").attr("loop", false);
}
//$("#audio_bgm_lock_icon").toggleClass("fa-lock");
//$("#audio_bgm_lock_icon").toggleClass("fa-lock-open");
$("#audio_bgm_lock").toggleClass("redOverlayGlow");
saveSettingsDebounced();
}
async function onBGMRandomClick() {
var select = document.getElementById('audio_bgm_select');
var items = select.getElementsByTagName('option');
if (items.length < 2)
return;
var index;
do {
index = Math.floor(Math.random() * items.length);
} while (index == select.selectedIndex);
select.selectedIndex = index;
onBGMSelectChange();
}
async function onBGMMuteClick() { async function onBGMMuteClick() {
extension_settings.audio.bgm_muted = !extension_settings.audio.bgm_muted; extension_settings.audio.bgm_muted = !extension_settings.audio.bgm_muted;
$("#audio_bgm_mute_icon").toggleClass("fa-volume-high"); $("#audio_bgm_mute_icon").toggleClass("fa-volume-high");
@@ -151,6 +249,20 @@ async function onBGMMuteClick() {
saveSettingsDebounced(); saveSettingsDebounced();
} }
async function onAmbientLockClick() {
extension_settings.audio.ambient_locked = !extension_settings.audio.ambient_locked;
if (extension_settings.audio.ambient_locked)
extension_settings.audio.ambient_selected = $("#audio_ambient_select").val();
else {
extension_settings.audio.ambient_selected = null;
currentBackground = null;
}
$("#audio_ambient_lock_icon").toggleClass("fa-lock");
$("#audio_ambient_lock_icon").toggleClass("fa-lock-open");
$("#audio_ambient_lock").toggleClass("redOverlayGlow");
saveSettingsDebounced();
}
async function onAmbientMuteClick() { async function onAmbientMuteClick() {
extension_settings.audio.ambient_muted = !extension_settings.audio.ambient_muted; extension_settings.audio.ambient_muted = !extension_settings.audio.ambient_muted;
$("#audio_ambient_mute_icon").toggleClass("fa-volume-high"); $("#audio_ambient_mute_icon").toggleClass("fa-volume-high");
@@ -176,6 +288,20 @@ async function onAmbientVolumeChange() {
//console.debug(DEBUG_PREFIX,"UPDATED Ambient MAX TO",extension_settings.audio.ambient_volume); //console.debug(DEBUG_PREFIX,"UPDATED Ambient MAX TO",extension_settings.audio.ambient_volume);
} }
async function onBGMSelectChange() {
extension_settings.audio.bgm_selected = $("#audio_bgm_select").val();
updateBGM(true);
saveSettingsDebounced();
//console.debug(DEBUG_PREFIX,"UPDATED BGM MAX TO",extension_settings.audio.bgm_volume);
}
async function onAmbientSelectChange() {
extension_settings.audio.ambient_selected = $("#audio_ambient_select").val();
updateAmbient(true);
saveSettingsDebounced();
//console.debug(DEBUG_PREFIX,"UPDATED BGM MAX TO",extension_settings.audio.bgm_volume);
}
async function onBGMCooldownInput() { async function onBGMCooldownInput() {
extension_settings.audio.bgm_cooldown = ~~($("#audio_bgm_cooldown").val()); extension_settings.audio.bgm_cooldown = ~~($("#audio_bgm_cooldown").val());
cooldownBGM = extension_settings.audio.bgm_cooldown * 1000; cooldownBGM = extension_settings.audio.bgm_cooldown * 1000;
@@ -222,11 +348,42 @@ async function getCharacterBgmList(name) {
} }
} }
//#############################// //#############################//
// Module Worker // // Module Worker //
//#############################// //#############################//
function fillBGMSelect() {
let found_last_selected_bgm = false;
// Update bgm list in UI
$("#audio_bgm_select")
.find('option')
.remove();
for (const file of fallback_BGMS) {
$('#audio_bgm_select').append(new Option("asset: " + file.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, ""), file));
if (file === extension_settings.audio.bgm_selected) {
$('#audio_bgm_select').val(extension_settings.audio.bgm_selected);
found_last_selected_bgm = true;
}
}
// Update bgm list in UI
for (const char in characterMusics)
for (const e in characterMusics[char])
for (const file of characterMusics[char][e]) {
$('#audio_bgm_select').append(new Option(char + ": " + file.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, ""), file));
if (file === extension_settings.audio.bgm_selected) {
$('#audio_bgm_select').val(extension_settings.audio.bgm_selected);
found_last_selected_bgm = true;
}
}
if (!found_last_selected_bgm) {
$('#audio_bgm_select').val($("#audio_bgm_select option:first").val());
extension_settings.audio.bgm_selected = null;
}
}
/* /*
- Update ambient sound - Update ambient sound
- Update character BGM - Update character BGM
@@ -246,6 +403,8 @@ async function moduleWorker() {
fallback_BGMS = await getAssetsList(ASSETS_BGM_FOLDER); fallback_BGMS = await getAssetsList(ASSETS_BGM_FOLDER);
fallback_BGMS = fallback_BGMS.filter((filename) => filename != ".placeholder") fallback_BGMS = fallback_BGMS.filter((filename) => filename != ".placeholder")
console.debug(DEBUG_PREFIX, "Detected assets:", fallback_BGMS); console.debug(DEBUG_PREFIX, "Detected assets:", fallback_BGMS);
fillBGMSelect();
} }
if (ambients == null) { if (ambients == null) {
@@ -253,10 +412,33 @@ async function moduleWorker() {
ambients = await getAssetsList(ASSETS_AMBIENT_FOLDER); ambients = await getAssetsList(ASSETS_AMBIENT_FOLDER);
ambients = ambients.filter((filename) => filename != ".placeholder") ambients = ambients.filter((filename) => filename != ".placeholder")
console.debug(DEBUG_PREFIX, "Detected assets:", ambients); console.debug(DEBUG_PREFIX, "Detected assets:", ambients);
// Update bgm list in UI
$("#audio_ambient_select")
.find('option')
.remove();
if (extension_settings.audio.ambient_selected !== null) {
let ambient_label = extension_settings.audio.ambient_selected;
if (ambient_label.includes("assets"))
ambient_label = "asset: " + ambient_label.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "");
else {
ambient_label = ambient_label.substring("/characters/".length);
ambient_label = ambient_label.substring(0, ambient_label.indexOf("/")) + ": " + ambient_label.substring(ambient_label.indexOf("/") + "/bgm/".length);
ambient_label = ambient_label.replace(/\.[^/.]+$/, "");
}
$('#audio_ambient_select').append(new Option(ambient_label, extension_settings.audio.ambient_selected));
}
for (const file of ambients) {
if (file !== extension_settings.audio.ambient_selected)
$("#audio_ambient_select").append(new Option("asset: " + file.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, ""), file));
}
} }
// 1) Update ambient audio // 1) Update ambient audio
// --------------------------- // ---------------------------
//if (extension_settings.audio.dynamic_ambient_enabled) {
let newBackground = $("#bg1").css("background-image"); let newBackground = $("#bg1").css("background-image");
const custom_background = getContext()["chatMetadata"]["custom_background"]; const custom_background = getContext()["chatMetadata"]["custom_background"];
@@ -275,6 +457,7 @@ async function moduleWorker() {
updateAmbient(); updateAmbient();
} }
} }
//}
const context = getContext(); const context = getContext();
//console.debug(DEBUG_PREFIX,context); //console.debug(DEBUG_PREFIX,context);
@@ -288,6 +471,14 @@ async function moduleWorker() {
// 1) Update BGM (single chat) // 1) Update BGM (single chat)
// ----------------------------- // -----------------------------
if (!chatIsGroup) { if (!chatIsGroup) {
// Reset bgm list on new chat
if (context.chatId != current_chat_id) {
current_chat_id = context.chatId;
characterMusics = {};
cooldownBGM = 0;
}
newCharacter = context.name2; newCharacter = context.name2;
//console.log(DEBUG_PREFIX,"SOLO CHAT MODE"); // DBG //console.log(DEBUG_PREFIX,"SOLO CHAT MODE"); // DBG
@@ -307,7 +498,7 @@ async function moduleWorker() {
if (currentCharacterBGM !== newCharacter) { if (currentCharacterBGM !== newCharacter) {
currentCharacterBGM = newCharacter; currentCharacterBGM = newCharacter;
try { try {
await updateBGM(); await updateBGM(false, true);
cooldownBGM = extension_settings.audio.bgm_cooldown * 1000; cooldownBGM = extension_settings.audio.bgm_cooldown * 1000;
} }
catch (error) { catch (error) {
@@ -346,6 +537,34 @@ async function moduleWorker() {
// 2) Update BGM (group chat) // 2) Update BGM (group chat)
// ----------------------------- // -----------------------------
// Load current chat character bgms
// Reset bgm list on new chat
if (context.chatId != current_chat_id) {
current_chat_id = context.chatId;
characterMusics = {};
cooldownBGM = 0;
for (const message of context.chat) {
if (characterMusics[message.name] === undefined)
await loadCharacterBGM(message.name);
}
try {
newCharacter = context.chat[context.chat.length - 1].name;
currentCharacterBGM = newCharacter;
await updateBGM(false, true);
cooldownBGM = extension_settings.audio.bgm_cooldown * 1000;
currentCharacterBGM = newCharacter;
currentExpressionBGM = FALLBACK_EXPRESSION;
console.debug(DEBUG_PREFIX, "(GROUP) Updated current character BGM to", currentExpressionBGM, "cooldown", cooldownBGM);
}
catch (error) {
console.debug(DEBUG_PREFIX, "Error while trying to update BGM group, will try again");
currentCharacterBGM = null
}
return;
}
newCharacter = context.chat[context.chat.length - 1].name; newCharacter = context.chat[context.chat.length - 1].name;
const userName = context.name1; const userName = context.name1;
@@ -353,17 +572,17 @@ async function moduleWorker() {
//console.log(DEBUG_PREFIX,"GROUP CHAT MODE"); // DBG //console.log(DEBUG_PREFIX,"GROUP CHAT MODE"); // DBG
// 2.1) First time character appear // 2.1) New character appear
if (characterMusics[newCharacter] === undefined) { if (characterMusics[newCharacter] === undefined) {
await loadCharacterBGM(newCharacter); await loadCharacterBGM(newCharacter);
return; return;
} }
// 2.2) Switched chat // 2.2) Switched char
if (currentCharacterBGM !== newCharacter) { if (currentCharacterBGM !== newCharacter) {
// Check cooldown // Check cooldown
if (cooldownBGM > 0) { if (cooldownBGM > 0) {
//console.debug(DEBUG_PREFIX,"(GROUP) BGM switch on cooldown:",cooldownBGM); console.debug(DEBUG_PREFIX, "(GROUP) BGM switch on cooldown:", cooldownBGM);
return; return;
} }
@@ -429,6 +648,8 @@ async function loadCharacterBGM(newCharacter) {
characterMusics[newCharacter][e].push(i); characterMusics[newCharacter][e].push(i);
} }
console.debug(DEBUG_PREFIX, "Updated BGM map of", newCharacter, "to", characterMusics[newCharacter]); console.debug(DEBUG_PREFIX, "Updated BGM map of", newCharacter, "to", characterMusics[newCharacter]);
fillBGMSelect();
} }
function getNewExpression() { function getNewExpression() {
@@ -458,8 +679,29 @@ function getNewExpression() {
return newExpression; return newExpression;
} }
async function updateBGM() { async function updateBGM(isUserInput = false, newChat = false) {
let audio_files = characterMusics[currentCharacterBGM][currentExpressionBGM];// Try char expression BGM if (!isUserInput && !extension_settings.audio.dynamic_bgm_enabled && $("#audio_bgm").attr("src") != "" && !bgmEnded && !newChat) {
console.debug(DEBUG_PREFIX, "BGM already playing and dynamic switch disabled, no update done");
return;
}
let audio_file_path = ""
if (isUserInput || (extension_settings.audio.bgm_locked && extension_settings.audio.bgm_selected !== null)) {
audio_file_path = extension_settings.audio.bgm_selected;
if (isUserInput)
console.debug(DEBUG_PREFIX, "User selected BGM", audio_file_path);
if (extension_settings.audio.bgm_locked)
console.debug(DEBUG_PREFIX, "BGM locked keeping current audio", audio_file_path);
}
else {
let audio_files = null;
if (extension_settings.audio.dynamic_bgm_enabled) {
extension_settings.audio.bgm_selected = null;
saveSettingsDebounced();
audio_files = characterMusics[currentCharacterBGM][currentExpressionBGM];// Try char expression BGM
if (audio_files === undefined || audio_files.length == 0) { if (audio_files === undefined || audio_files.length == 0) {
console.debug(DEBUG_PREFIX, "No BGM for", currentCharacterBGM, currentExpressionBGM); console.debug(DEBUG_PREFIX, "No BGM for", currentCharacterBGM, currentExpressionBGM);
@@ -474,8 +716,15 @@ async function updateBGM() {
} }
} }
} }
}
else {
audio_files = [];
$("#audio_bgm_select option").each(function () { audio_files.push($(this).val()); });
}
audio_file_path = audio_files[Math.floor(Math.random() * audio_files.length)];
}
const audio_file_path = audio_files[Math.floor(Math.random() * audio_files.length)];
console.log(DEBUG_PREFIX, "Updating BGM"); console.log(DEBUG_PREFIX, "Updating BGM");
console.log(DEBUG_PREFIX, "Checking file", audio_file_path); console.log(DEBUG_PREFIX, "Checking file", audio_file_path);
try { try {
@@ -485,20 +734,30 @@ async function updateBGM() {
console.log(DEBUG_PREFIX, "File not found!") console.log(DEBUG_PREFIX, "File not found!")
} }
else { else {
console.log(DEBUG_PREFIX, "Switching BGM to", currentExpressionBGM) console.log(DEBUG_PREFIX, "Switching BGM to", currentExpressionBGM);
$("#audio_bgm_select").val(audio_file_path);
const audio = $("#audio_bgm"); const audio = $("#audio_bgm");
if (audio.attr("src") == audio_file_path) { if (audio.attr("src") == audio_file_path && !bgmEnded) {
console.log(DEBUG_PREFIX, "Already playing, ignored"); console.log(DEBUG_PREFIX, "Already playing, ignored");
return; return;
} }
audio.animate({ volume: 0.0 }, 2000, function () { let fade_time = 2000;
bgmEnded = false;
if (isUserInput || extension_settings.audio.bgm_locked) {
audio.attr("src", audio_file_path);
audio[0].play();
}
else {
audio.animate({ volume: 0.0 }, fade_time, function () {
audio.attr("src", audio_file_path); audio.attr("src", audio_file_path);
audio[0].play(); audio[0].play();
audio.volume = extension_settings.audio.bgm_volume * 0.01; audio.volume = extension_settings.audio.bgm_volume * 0.01;
audio.animate({ volume: extension_settings.audio.bgm_volume * 0.01 }, 2000); audio.animate({ volume: extension_settings.audio.bgm_volume * 0.01 }, fade_time);
}) });
}
} }
} catch (error) { } catch (error) {
@@ -506,8 +765,19 @@ async function updateBGM() {
} }
} }
async function updateAmbient() { async function updateAmbient(isUserInput = false) {
let audio_file_path = null; let audio_file_path = null;
if (isUserInput || extension_settings.audio.ambient_locked) {
audio_file_path = extension_settings.audio.ambient_selected;
if (isUserInput)
console.debug(DEBUG_PREFIX, "User selected Ambient", audio_file_path);
if (extension_settings.audio.bgm_locked)
console.debug(DEBUG_PREFIX, "Ambient locked keeping current audio", audio_file_path);
}
else {
extension_settings.audio.ambient_selected = null;
for (const i of ambients) { for (const i of ambients) {
console.debug(i) console.debug(i)
if (i.includes(currentBackground)) { if (i.includes(currentBackground)) {
@@ -515,9 +785,10 @@ async function updateAmbient() {
break; break;
} }
} }
}
if (audio_file_path === null) { if (audio_file_path === null) {
console.debug(DEBUG_PREFIX, "No ambient file found for background", currentBackground); console.debug(DEBUG_PREFIX, "No bgm file found for background", currentBackground);
const audio = $("#audio_ambient"); const audio = $("#audio_ambient");
audio.attr("src", ""); audio.attr("src", "");
audio[0].pause(); audio[0].pause();
@@ -527,45 +798,87 @@ async function updateAmbient() {
//const audio_file_path = AMBIENT_FOLDER+currentBackground+".mp3"; //const audio_file_path = AMBIENT_FOLDER+currentBackground+".mp3";
console.log(DEBUG_PREFIX, "Updating ambient"); console.log(DEBUG_PREFIX, "Updating ambient");
console.log(DEBUG_PREFIX, "Checking file", audio_file_path); console.log(DEBUG_PREFIX, "Checking file", audio_file_path);
$("#audio_ambient_select").val(audio_file_path);
let fade_time = 2000;
if (isUserInput)
fade_time = 0;
const audio = $("#audio_ambient"); const audio = $("#audio_ambient");
audio.animate({ volume: 0.0 }, 2000, function () {
if (audio.attr("src") == audio_file_path) {
console.log(DEBUG_PREFIX, "Already playing, ignored");
return;
}
audio.animate({ volume: 0.0 }, fade_time, function () {
audio.attr("src", audio_file_path); audio.attr("src", audio_file_path);
audio[0].play(); audio[0].play();
audio.volume = extension_settings.audio.ambient_volume * 0.01; audio.volume = extension_settings.audio.ambient_volume * 0.01;
audio.animate({ volume: extension_settings.audio.ambient_volume * 0.01 }, 2000); audio.animate({ volume: extension_settings.audio.ambient_volume * 0.01 }, fade_time);
}); });
} }
/**
* Handles wheel events on volume sliders.
* @param {WheelEvent} e Event
*/
function onVolumeSliderWheelEvent(e) {
const slider = $(this);
e.preventDefault();
e.stopPropagation();
const delta = e.deltaY / 20;
const sliderVal = Number(slider.val());
let newVal = sliderVal - delta;
if (newVal < 0) {
newVal = 0;
} else if (newVal > 100) {
newVal = 100;
}
slider.val(newVal).trigger('input');
}
//#############################// //#############################//
// Extension load // // Extension load //
//#############################// //#############################//
// This function is called when the extension is loaded // This function is called when the extension is loaded
jQuery(async () => { jQuery(async () => {
// This is an example of loading HTML from a file
const windowHtml = $(await $.get(`${extensionFolderPath}/window.html`)); const windowHtml = $(await $.get(`${extensionFolderPath}/window.html`));
$('#extensions_settings').append(windowHtml); $('#extensions_settings').append(windowHtml);
loadSettings(); loadSettings();
$("#audio_bgm").attr("loop", true); $("#audio_enabled").on("click", onEnabledClick);
$("#audio_dynamic_bgm_enabled").on("click", onDynamicBGMEnabledClick);
//$("#audio_dynamic_ambient_enabled").on("click", onDynamicAmbientEnabledClick);
//$("#audio_bgm").attr("loop", false);
$("#audio_ambient").attr("loop", true); $("#audio_ambient").attr("loop", true);
$("#audio_bgm").hide(); $("#audio_bgm").hide();
$("#audio_ambient").hide(); $("#audio_bgm_lock").on("click", onBGMLockClick);
$("#audio_bgm_mute").on("click", onBGMMuteClick); $("#audio_bgm_mute").on("click", onBGMMuteClick);
$("#audio_ambient_mute").on("click", onAmbientMuteClick);
$("#audio_enabled").on("click", onEnabledClick);
$("#audio_bgm_volume_slider").on("input", onBGMVolumeChange); $("#audio_bgm_volume_slider").on("input", onBGMVolumeChange);
$("#audio_bgm_random").on("click", onBGMRandomClick);
$("#audio_ambient").hide();
$("#audio_ambient_lock").on("click", onAmbientLockClick);
$("#audio_ambient_mute").on("click", onAmbientMuteClick);
$("#audio_ambient_volume_slider").on("input", onAmbientVolumeChange); $("#audio_ambient_volume_slider").on("input", onAmbientVolumeChange);
document.getElementById('audio_ambient_volume_slider').addEventListener('wheel', onVolumeSliderWheelEvent, { passive: false });
document.getElementById('audio_bgm_volume_slider').addEventListener('wheel', onVolumeSliderWheelEvent, { passive: false });
$("#audio_bgm_cooldown").on("input", onBGMCooldownInput); $("#audio_bgm_cooldown").on("input", onBGMCooldownInput);
// Reset assets container, will be redected like if ST restarted // Reset assets container, will be redected like if ST restarted
$("#audio_refresh_assets").on("click", function () { $("#audio_refresh_assets").on("click", function () {
console.debug(DEBUG_PREFIX, "Refreshing audio assets"); console.debug(DEBUG_PREFIX, "Refreshing audio assets");
current_chat_id = null
fallback_BGMS = null; fallback_BGMS = null;
ambients = null; ambients = null;
characterMusics = {}; characterMusics = {};
@@ -574,6 +887,9 @@ jQuery(async () => {
currentBackground = null; currentBackground = null;
}) })
$("#audio_bgm_select").on("change", onBGMSelectChange);
$("#audio_ambient_select").on("change", onAmbientSelectChange);
// DBG // DBG
$("#audio_debug").on("click", function () { $("#audio_debug").on("click", function () {
if ($("#audio_debug").is(':checked')) { if ($("#audio_debug").is(':checked')) {
@@ -587,6 +903,14 @@ jQuery(async () => {
}); });
// //
$("#audio_bgm").on("ended", function () {
console.debug(DEBUG_PREFIX, "END OF BGM")
if (!extension_settings.audio.bgm_locked) {
bgmEnded = true;
updateBGM();
}
});
const wrapper = new ModuleWorkerWrapper(moduleWorker); const wrapper = new ModuleWorkerWrapper(moduleWorker);
setInterval(wrapper.update.bind(wrapper), UPDATE_INTERVAL); setInterval(wrapper.update.bind(wrapper), UPDATE_INTERVAL);
moduleWorker(); moduleWorker();

View File

@@ -1,15 +1,68 @@
.mixer-div { .audio-ui-block {
margin-bottom: 1em;
}
.audio-mixer-div {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 5px; padding: 5px;
background-color: rgba(38, 38, 38, 0.5);
border: 1px rgb(75, 75, 75) solid;
border-radius: 10px;
}
.audio-mixer-element {
height: 60px;
float: left;
margin-right: 10px;
label {
text-align: top;
}
input {
margin-top: 15px;
}
select {
margin-top: 5px;
padding: 5px;
width: 100%;
}
}
.audio-label {
display: block;
text-align: center;
}
.audio-volume-div {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.audio-lock-button {
padding: 1rem;
width: 100%;
height: 2em;
}
.audio-random-button {
padding: 1rem;
width: 100%;
height: 2em;
} }
.audio-mute-button { .audio-mute-button {
padding: 5px; padding: 1rem;
width: 50px; width: 100%;
height: 30px; height: 2em;
}
.audio-slider {
width: 100% !important;
vertical-align: center;
} }
.audio-mute-button-muted { .audio-mute-button-muted {
@@ -20,3 +73,23 @@
width: 50px; width: 50px;
height: 30px; height: 30px;
} }
.audio-mixer-mute {
width: 10%;
}
.audio-mixer-volume {
width: 25%;
}
.audio-mixer-playlist {
width: 45%;
}
.audio-mixer-lock {
width: 10%;
}
.audio-mixer-random {
width: 10%;
}

View File

@@ -10,6 +10,20 @@
<input type="checkbox" id="audio_enabled" name="audio_enabled"> <input type="checkbox" id="audio_enabled" name="audio_enabled">
<small>Enabled</small> <small>Enabled</small>
</label> </label>
<div id="audio_bgm_dynamic_enable_div">
<label class="checkbox_label" for="audio_dynamic_bgm_enabled">
<input type="checkbox" id="audio_dynamic_bgm_enabled" name="audio_dynamic_bgm_enabled">
<small>Enable expression BGM switch (req. character expression)</small>
</label>
</div>
<!--
<div id="audio_ambient_dynamic_enable_div">
<label class="checkbox_label" for="audio_dynamic_ambient_enabled">
<input type="checkbox" id="audio_dynamic_ambient_enabled" name="audio_dynamic_ambient_enabled">
<small>Enable ambient background switch (req. chat background)</small>
</label>
</div>
-->
<div id="audio_debug_div"> <div id="audio_debug_div">
<label class="checkbox_label" for="audio_debug"> <label class="checkbox_label" for="audio_debug">
<input type="checkbox" id="audio_debug" name="audio_debug"> <input type="checkbox" id="audio_debug" name="audio_debug">
@@ -24,23 +38,63 @@
</div> </div>
</div> </div>
<div> <div>
<div> <div class="audio-ui-block">
<label for="audio_bgm_volume_slider">Music <span id="audio_bgm_volume"></span></label> <label for="audio_bgm_volume_slider">Music</label>
<div class="mixer-div"> <div class="audio-mixer-div">
<div class="audio-mixer-element audio-mixer-mute">
<label for="audio_bgm_lock" class="audio-label">Mute</label>
<div id="audio_bgm_mute" class="menu_button audio-mute-button"> <div id="audio_bgm_mute" class="menu_button audio-mute-button">
<i class="fa-solid fa-volume-high fa-lg" id="audio_bgm_mute_icon"></i> <i class="fa-solid fa-volume-high fa-lg" id="audio_bgm_mute_icon"></i>
</div> </div>
<input type="range" class ="slider" id ="audio_bgm_volume_slider" value = "0" maxlength ="100"> </div>
<div class="audio-mixer-element audio-mixer-volume">
<label for="audio_bgm_lock" class="audio-label">Vol <span id="audio_bgm_volume"></span></label>
<input type="range" class ="audio-slider" id ="audio_bgm_volume_slider" value = "0" maxlength ="100">
</div>
<div class="audio-mixer-element audio-mixer-playlist">
<label for="audio_bgm_lock" class="audio-label">Playlist</label>
<select id="audio_bgm_select">
</select>
</div>
<div class="audio-mixer-element audio-mixer-lock">
<label for="audio_bgm_lock" class="audio-label">Loop</label>
<div id="audio_bgm_lock" class="menu_button audio-lock-button">
<i class="fa-solid fa-repeat fa-lg" id="audio_bgm_lock_icon"></i>
</div>
</div>
<div class="audio-mixer-element audio-mixer-random">
<label for="audio_bgm_random" class="audio-label">Roll</label>
<div id="audio_bgm_random" class="menu_button audio-random-button">
<i class="fa-solid fa-random fa-lg" id="audio_bgm_random_icon"></i>
</div>
</div>
</div> </div>
<audio id="audio_bgm" controls src=""> <audio id="audio_bgm" controls src="">
</div> </div>
<div> <div>
<label for="audio_ambient_volume_slider">Ambient <span id="audio_ambient_volume"></span></label> <label for="audio_ambient_volume_slider">Ambient</label>
<div class="mixer-div"> <div class="audio-mixer-div">
<div class="audio-mixer-element audio-mixer-mute">
<label for="audio_ambient_lock" class="audio-label">Mute</label>
<div id="audio_ambient_mute" class="menu_button audio-mute-button"> <div id="audio_ambient_mute" class="menu_button audio-mute-button">
<i class="fa-solid fa-volume-high fa-lg" id="audio_ambient_mute_icon"></i> <i class="fa-solid fa-volume-high fa-lg" id="audio_ambient_mute_icon"></i>
</div> </div>
<input type="range" class ="slider" id ="audio_ambient_volume_slider" value = "0" maxlength ="100"> </div>
<div class="audio-mixer-element audio-mixer-volume">
<label for="audio_ambient_lock" class="audio-label">Vol <span id="audio_ambient_volume"></span></label>
<input type="range" class ="audio-slider" id ="audio_ambient_volume_slider" value = "0" maxlength ="100">
</div>
<div class="audio-mixer-element audio-mixer-playlist">
<label for="audio_ambient_lock" class="audio-label">Playlist</label>
<select id="audio_ambient_select">
</select>
</div>
<div class="audio-mixer-element">
<label for="audio_ambient_lock audio-mixer-lock" class="audio-label">Lock</label>
<div id="audio_ambient_lock" class="menu_button audio-lock-button">
<i class="fa-solid fa-lock-open fa-lg" id="audio_ambient_lock_icon"></i>
</div>
</div>
</div> </div>
<audio id="audio_ambient" controls src=""> <audio id="audio_ambient" controls src="">
</div> </div>