var playlist = WaveformPlaylist.init({ container: document.getElementById("playlist"), timescale: true, state: 'select', samplesPerPixel: 16384, zoomLevels: [2048, 4096, 8192, 16384], controls: { show: true, width: 150, widgets: { stereoPan: false, } }, waveHeight: 80, }); function onFinishedLoading() { //initialize the WAV exporter. playlist.initExporter(); const tracks = playlist.tracks; for (var i = 0; i < tracks.length; i++) { playlist.collapseTrack(tracks[i], {collapsed: true}); } const highlight = window.location.hash.split('#').filter(Boolean); for(var i = 0; i < highlight.length; i++) { const guid = highlight[i]; for (var j = 0; j < tracks.length; j++) { if (tracks[j].name == guid) { tracks[j].setWaveOutlineColor('#d1e7dd'); } } for (var j = 0; j < g_chats.length; j++) { if (g_chats[j].player_guid == guid) { chatRows[j].classList.add("table-active"); } } } playlist.drawRequest(); } function collapseTrack(guid, collapse) { const tracks = playlist.tracks; for (var i = 0; i < tracks.length; i++) { if (guid === null || tracks[i].name == guid) { playlist.collapseTrack(tracks[i], {collapsed: collapse}); if (guid != null) { break; } } } } function updateTrackInfo(guid, info) { const tracks = playlist.tracks; for (var i = 0; i < tracks.length; i++) { if (guid === null || tracks[i].name == guid) { tracks[i].setInfo(info); if (guid != null) { break; } } } } var ee = playlist.getEventEmitter(); var $container = $("body"); var $time = $container.find(".audio-pos"); var $time_ = $container.find(".audio-pos-2"); var audioPos = 0; function clockFormat(seconds, decimals) { var hours, minutes, secs, result; hours = parseInt(seconds / 3600, 10) % 24; minutes = parseInt(seconds / 60, 10) % 60; secs = seconds % 60; secs = secs.toFixed(decimals); result = (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes) + ":" + (secs < 10 ? "0" + secs : secs); return result; } var lastChunkIdx = 0; var lastUpdateTime = 0; function updateTime(time) { $time.html(clockFormat(time, 3)); audioPos = time; if (time < lastUpdateTime) { lastChunkIdx = 0; } var tick = time / g_session.tickinterval; var silenceTicks = 0; for (; lastChunkIdx < g_session.silence_chunks.length; lastChunkIdx++) { var chunk = g_session.silence_chunks[lastChunkIdx]; if (tick > chunk[0]) { silenceTicks = chunk[1]; } else { break; } } tick += silenceTicks; var tickedTime = tick * g_session.tickinterval; $time_.html(clockFormat(tickedTime, 3)); lastUpdateTime = time; if (lastChunkIdx > 0) { lastChunkIdx -= 1; } onTick(tick, tickedTime); } updateTime(audioPos); function onEvent(idx, event) { var update = 0; if (event.event == "player_connect") { collapseTrack(event.player_guid, false); updateTrackInfo(event.player_guid, event.data.name); update += 1; } else if (event.event == "player_disconnect") { collapseTrack(event.player_guid, true); update += 1; } else if (event.event == "player_changename") { updateTrackInfo(event.player_guid, event.data.newname); update += 1; } return update; } var chatBox = $("div#chat"); var chatRows = $("div#chat>table>tbody").children(); var lastPrimaryRow = undefined; function onChat(idx, chat) { if (idx == lastPrimaryRow) { return 0; } if (lastPrimaryRow != undefined) { chatRows[lastPrimaryRow].classList.remove("table-primary"); } chatRows[idx].classList.add("table-primary"); if (autoScrollChat) { chatRows[idx].scrollIntoViewIfNeeded(); } lastPrimaryRow = idx; return 1; } var lastTick = undefined; var lastChatIdx = 0; var lastEventIdx = 0; function onTick(tick, time) { var update = 0; if (tick == lastTick) { return; } if (tick < lastTick) { lastChatIdx = 0; lastEventIdx = 0; } for (; lastEventIdx < g_events.length; lastEventIdx++) { const event = g_events[lastEventIdx]; if (tick > event.tick) { update += onEvent(lastEventIdx, event); } else { break; } } if (lastEventIdx > 0) { lastEventIdx -= 1; } for (; lastChatIdx < g_chats.length; lastChatIdx++) { const chat = g_chats[lastChatIdx]; if (tick < chat.tick) { if (lastChatIdx > 0) { lastChatIdx -= 1; } update += onChat(lastChatIdx, chat); break; } } lastTick = tick; if (update) { playlist.drawRequest(); } } function gameTimeToAudio(tick) { tick += 1; var silenceTicks = 0; for (var i = 0; i < g_session.silence_chunks.length; i++) { const chunk = g_session.silence_chunks[i]; if ((tick - chunk[1]) > chunk[0]) { silenceTicks = chunk[1]; } else { break; } } return (tick - silenceTicks) * g_session.tickinterval; } function jumpToGameTick(tick) { var audioTime = gameTimeToAudio(tick); playlist.seek(audioTime); playlist.drawRequest(); updateTime(audioTime); } $container.on("click", ".btn-play", function() { ee.emit("play"); }); $container.on("click", ".btn-pause", function() { isLooping = false; ee.emit("pause"); }); $container.on("click", ".btn-stop", function() { isLooping = false; ee.emit("stop"); }); $container.on("click", ".btn-rewind", function() { isLooping = false; ee.emit("rewind"); }); $container.on("click", ".btn-fast-forward", function() { isLooping = false; ee.emit("fastforward"); }); // zoom buttons $container.on("click", ".btn-zoom-in", function() { ee.emit("zoomin"); }); $container.on("click", ".btn-zoom-out", function() { ee.emit("zoomout"); }); // download var downloadUrl = undefined; var downloadName = undefined; $container.on("click", ".btn-download", function () { if (downloadName) { return; } downloadName = g_session.demoname; if (playlist.isSegmentSelection()) { const segment = playlist.getTimeSelection(); downloadName += "-" + clockFormat(segment.start).replaceAll(':', '-') + "_" + clockFormat(segment.end).replaceAll(':', '-'); } downloadName += ".wav"; ee.emit('startaudiorendering', 'wav'); }); ee.on('audiorenderingfinished', function (type, data) { if (type != 'wav') { return; } if (downloadUrl) { window.URL.revokeObjectURL(downloadUrl); } downloadUrl = window.URL.createObjectURL(data); const tempLink = document.createElement('a'); tempLink.style.display = 'none'; tempLink.href = downloadUrl; tempLink.setAttribute('download', downloadName); document.body.appendChild(tempLink); tempLink.click(); document.body.removeChild(tempLink); downloadName = undefined; }); $container.on("input change", ".master-gain", function(e){ ee.emit("mastervolumechange", e.target.value); }); $container.find(".master-gain").change(); var autoScrollVoice = false; $container.on("change", "#autoscroll_voice", function(e){ autoScrollVoice = $(e.target).is(':checked'); ee.emit("automaticscroll", autoScrollVoice); }); $container.find("#autoscroll_voice").change(); var autoScrollChat = false; $container.on("change", "#autoscroll_chat", function(e){ autoScrollChat = $(e.target).is(':checked'); }); $container.find("#autoscroll_chat").change(); ee.on("timeupdate", updateTime); function getParent(el) { var parent = el.parentNode; if (parent === document) { return document; } else if (parent.offsetHeight < parent.scrollHeight || parent.offsetWidth < parent.scrollWidth) { return parent; } else { return getParent(parent); } } if (!Element.prototype.scrollIntoViewIfNeeded) { Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) { centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded; var parent = getParent(this), parentComputedStyle = window.getComputedStyle(parent, null), parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')), parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')), overTop = this.offsetTop - parent.offsetTop < parent.scrollTop, overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight), overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft, overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth), alignWithTop = overTop && !overBottom; if ((overTop || overBottom) && centerIfNeeded) { parent.scrollTop = this.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + this.clientHeight / 2; } if ((overLeft || overRight) && centerIfNeeded) { parent.scrollLeft = this.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + this.clientWidth / 2; } if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) { this.scrollIntoView(alignWithTop); } }; }