From 776f4657330335978ad1c01c574f136aaf3cf7fa Mon Sep 17 00:00:00 2001 From: Kristoffer Date: Fri, 13 Dec 2024 13:31:22 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=BA=20NDI=20output=20send=20new=20fram?= =?UTF-8?q?e=20when=20reconnected=20-=20Per=20video=20volume=20-=20Fixed?= =?UTF-8?q?=20per=20audio=20volume=20not=20affecting=20audio=20meter=20-?= =?UTF-8?q?=20Version=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- public/global.css | 91 +++---------------- .../capture/helpers/CaptureTransmitter.ts | 2 +- src/electron/ndi/NdiSender.ts | 12 ++- src/frontend/components/edit/EditTools.svelte | 3 +- .../components/edit/MediaTools.svelte | 9 +- src/frontend/components/edit/values/media.ts | 7 ++ src/frontend/components/helpers/audio.ts | 12 ++- .../components/main/popups/Unsaved.svelte | 2 +- .../output/layers/BackgroundMedia.svelte | 4 +- .../components/show/formatTextEditor.ts | 3 +- src/frontend/utils/createData.ts | 15 +-- 12 files changed, 59 insertions(+), 103 deletions(-) diff --git a/package.json b/package.json index 6e011fd1..22d63a6f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freeshow", - "version": "1.3.3-beta.1", + "version": "1.3.3-beta.2", "private": true, "main": "build/electron/index.js", "description": "Show song lyrics and more for free!", diff --git a/public/global.css b/public/global.css index 9f97f71b..ddfa4260 100644 --- a/public/global.css +++ b/public/global.css @@ -1,3 +1,4 @@ +/* custom CMG Sans */ @font-face { font-family: "CMGSans"; src: url("./fonts/CMGSans-Regular.ttf"); @@ -39,20 +40,26 @@ --hover: rgb(255 255 255 / 0.05); --focus: rgb(255 255 255 / 0.1); - /* --active: rgb(230 52 156 / .8); */ - /* --font-family: sans-serif; */ /* https://css-tricks.com/snippets/css/system-font-stack/ */ - /* --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; */ --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; --font-size: 1em; --border-radius: 0; - /* --navigation-width: 18vw; */ --navigation-width: 290px; } +* { + margin: 0; + padding: 0; + box-sizing: border-box; + user-select: none; + + outline-offset: -4px; + outline-color: var(--secondary); +} + html, body { position: relative; @@ -63,9 +70,6 @@ body { body { display: flex; flex-direction: column; - /* background-color: #292c36; - background-color: var(--primary); */ - color: #f0f0ff; color: var(--text); box-sizing: border-box; transition: background-color 0.5s; @@ -122,76 +126,3 @@ p { overflow: hidden; white-space: nowrap; } - -* { - margin: 0; - padding: 0; - box-sizing: border-box; - user-select: none; - - outline-offset: -4px; - outline-color: var(--secondary); -} - -/* button { - font-family: sans-serif; - font-family: system-ui; -} */ - -/* body { - color: #333; - margin: 0; - padding: 8px; - box-sizing: border-box; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; -} - -a { - color: rgb(0,100,200); - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -a:visited { - color: rgb(0,80,160); -} - -label { - display: block; -} - -input, button, select, textarea { - font-family: inherit; - font-size: inherit; - -webkit-padding: 0.4em 0; - padding: 0.4em; - margin: 0 0 0.5em 0; - box-sizing: border-box; - border: 1px solid #ccc; - border-radius: 2px; -} - -input:disabled { - color: #ccc; -} - -button { - color: #333; - background-color: #f4f4f4; - outline: none; -} - -button:disabled { - color: #999; -} - -button:not(:disabled):active { - background-color: #ddd; -} - -button:focus { - border-color: #666; -} */ diff --git a/src/electron/capture/helpers/CaptureTransmitter.ts b/src/electron/capture/helpers/CaptureTransmitter.ts index dce2df12..28e65f1c 100644 --- a/src/electron/capture/helpers/CaptureTransmitter.ts +++ b/src/electron/capture/helpers/CaptureTransmitter.ts @@ -48,7 +48,7 @@ export class CaptureTransmitter { // WIP one global capture (on the highest frame rate) instead of multiple per frame rate - but using multipe at once is probably an edge case static startChannel(captureId: string, key: string) { const combinedKey = `${captureId}-${key}` - const interval = 1000 / OutputHelper.getOutput(captureId)?.captureOptions?.framerates?.[key] || 30 + const interval = 1000 / (OutputHelper.getOutput(captureId)?.captureOptions?.framerates?.[key] || 30) // console.log("START CHANNEL:", key, interval) if (this.channels[combinedKey]?.timer) { diff --git a/src/electron/ndi/NdiSender.ts b/src/electron/ndi/NdiSender.ts index 43374cb5..ee4a3cba 100644 --- a/src/electron/ndi/NdiSender.ts +++ b/src/electron/ndi/NdiSender.ts @@ -3,8 +3,7 @@ import os from "os" import { toApp } from ".." import { CaptureHelper } from "../capture/CaptureHelper" import util from "./vingester-util" - -// WIP - NDI issue on Linux: libndi.so.5: No such file or dialog +import { CaptureTransmitter } from "../capture/helpers/CaptureTransmitter" // Resources: // https://www.npmjs.com/package/grandiose-mac @@ -63,6 +62,15 @@ export class NdiSender { CaptureHelper.updateFramerate(id) this.NDI[id].previousStatus = newStatus + + if (this.NDI[id].status === "connected") { + Object.keys(CaptureTransmitter.channels).forEach((key) => { + if (key.includes("ndi")) { + // force an instant check / output refresh when reconnected + CaptureTransmitter.channels[key].lastCheck = 999 + } + }) + } } }, 1000) } diff --git a/src/frontend/components/edit/EditTools.svelte b/src/frontend/components/edit/EditTools.svelte index 9c3014df..8a2487fa 100644 --- a/src/frontend/components/edit/EditTools.svelte +++ b/src/frontend/components/edit/EditTools.svelte @@ -12,6 +12,7 @@ import Tabs from "../main/Tabs.svelte" import Center from "../system/Center.svelte" import { getBoxStyle, getFilterStyle, getItemStyle, getSlideStyle, setBoxStyle, setFilterStyle, setItemStyle, setSlideStyle } from "./scripts/itemClipboard" + import { DEFAULT_ITEM_STYLE } from "./scripts/itemHelpers" import { addStyleString } from "./scripts/textStyle" import BoxStyle from "./tools/BoxStyle.svelte" import ItemStyle from "./tools/ItemStyle.svelte" @@ -168,7 +169,7 @@ if (active === "item") { history({ id: "setStyle", - newData: { style: { key: "style", values: ["top:120px;left:50px;height:840px;width:1820px;"] } }, + newData: { style: { key: "style", values: [DEFAULT_ITEM_STYLE] } }, location: { page: "edit", show: $activeShow!, slide, items: $activeEdit.items }, }) return diff --git a/src/frontend/components/edit/MediaTools.svelte b/src/frontend/components/edit/MediaTools.svelte index d2ed1fd2..151abc16 100644 --- a/src/frontend/components/edit/MediaTools.svelte +++ b/src/frontend/components/edit/MediaTools.svelte @@ -47,9 +47,9 @@ let videoDuration = video?.duration || 0 if (!videoDuration) return - edits.video[2].value = currentMedia?.toTime || videoDuration - edits.video[1].values = { max: videoDuration } + edits.video[3].value = currentMedia?.toTime || videoDuration edits.video[2].values = { max: videoDuration } + edits.video[3].values = { max: videoDuration } } } @@ -60,8 +60,9 @@ edits.default[2].value = currentMedia.flippedY || false if (edits.video) { edits.video[0].value = currentMedia.speed || "1" - edits.video[1].value = currentMedia.fromTime || 0 - edits.video[2].value = currentMedia.toTime || edits.video[2].value + edits.video[1].value = currentMedia.volume ?? 100 + edits.video[2].value = currentMedia.fromTime || 0 + edits.video[3].value = currentMedia.toTime || edits.video[3].value } // update filters diff --git a/src/frontend/components/edit/values/media.ts b/src/frontend/components/edit/values/media.ts index 544d4347..b75f73c0 100644 --- a/src/frontend/components/edit/values/media.ts +++ b/src/frontend/components/edit/values/media.ts @@ -46,6 +46,13 @@ export const videoEdit = [ ], }, }, + { + name: "media.volume", + id: "volume", + input: "number", + value: 100, + values: { max: 100 }, + }, { name: "inputs.start", id: "fromTime", diff --git a/src/frontend/components/helpers/audio.ts b/src/frontend/components/helpers/audio.ts index 4a17b481..aa06d5c0 100644 --- a/src/frontend/components/helpers/audio.ts +++ b/src/frontend/components/helpers/audio.ts @@ -80,8 +80,11 @@ export async function playAudio({ path, name = "", audio = null, stream = null } }) let localVolume: number = get(volume) * (get(media)[path]?.volume || 1) - if (analyser.gainNode) analyser.gainNode.gain.value = localVolume * (get(gain) || 1) - else audio.volume = localVolume + if (analyser.gainNode) { + analyser.gainNode.gain.value = localVolume * (get(gain) || 1) + if (get(special).preFaderVolumeMeter) audio.volume = 1 + else audio.volume = localVolume + } else audio.volume = localVolume let waitToPlay = 0 if (audioPlaying && crossfade) { @@ -171,6 +174,9 @@ export function updateVolume(value: number | undefined | "local", changeGain: bo if (a[id].analyser.gainNode) { let gainedValue = localVolume * (get(gain) || 1) a[id].analyser.gainNode.gain.value = gainedValue + + if (get(special).preFaderVolumeMeter) a[id].audio.volume = 1 + else a[id].audio.volume = localVolume } else a[id].audio.volume = localVolume }) @@ -516,7 +522,7 @@ function getPlayingVideos() { videos.map((a) => { // set volume (video in output window) - let newVolume = get(volume) + let newVolume = get(volume) * ((get(media)[a.id]?.volume ?? 100) / 100) if (a.analyser.gainNode) { let gainedValue = newVolume * (get(gain) || 1) a.analyser.gainNode.gain.value = gainedValue diff --git a/src/frontend/components/main/popups/Unsaved.svelte b/src/frontend/components/main/popups/Unsaved.svelte index 97c48373..1b91aadd 100644 --- a/src/frontend/components/main/popups/Unsaved.svelte +++ b/src/frontend/components/main/popups/Unsaved.svelte @@ -46,7 +46,7 @@ {:else} diff --git a/src/frontend/components/output/layers/BackgroundMedia.svelte b/src/frontend/components/output/layers/BackgroundMedia.svelte index f0673e8c..79cf1551 100644 --- a/src/frontend/components/output/layers/BackgroundMedia.svelte +++ b/src/frontend/components/output/layers/BackgroundMedia.svelte @@ -4,7 +4,7 @@ import { OUTPUT } from "../../../../types/Channels" import type { MediaStyle } from "../../../../types/Main" import type { OutBackground, Transition } from "../../../../types/Show" - import { allOutputs, audioChannels, outputs, playingVideos, special, videosData, videosTime } from "../../../stores" + import { allOutputs, audioChannels, media, outputs, playingVideos, special, videosData, videosTime, volume } from "../../../stores" import { destroy, receive, send } from "../../../utils/request" import BmdStream from "../../drawer/live/BMDStream.svelte" import NdiStream from "../../drawer/live/NDIStream.svelte" @@ -163,7 +163,7 @@ // FADE OUT AUDIO $: if (fadingOut && !videoData.muted) fadeoutVideo() - $: if (!fadingOut && !videoData.muted && id) setVolume(1) + $: if (!fadingOut && !videoData.muted && id) setVolume($volume * (($media[id]?.volume ?? 100) / 100)) const speed = 0.01 const margin = 0.9 // video should fade to 0 before clearing function fadeoutVideo() { diff --git a/src/frontend/components/show/formatTextEditor.ts b/src/frontend/components/show/formatTextEditor.ts index fb71dd5f..4e0a03c0 100644 --- a/src/frontend/components/show/formatTextEditor.ts +++ b/src/frontend/components/show/formatTextEditor.ts @@ -9,6 +9,7 @@ import { history } from "../helpers/history" import { isEmptyOrSpecial } from "../helpers/output" import { getGlobalGroup } from "../helpers/show" import { _show } from "../helpers/shows" +import { DEFAULT_ITEM_STYLE } from "../edit/scripts/itemHelpers" export function formatText(text: string, showId: string = "") { if (!showId) showId = get(activeShow)?.id || "" @@ -283,7 +284,7 @@ function getSlide(slideText): Slide { return slide } -export const defaultItem: Item = { type: "text", lines: [], style: "top:120px;left:50px;height:840px;width:1820px;" } +export const defaultItem: Item = { type: "text", lines: [], style: DEFAULT_ITEM_STYLE } const textboxRegex = /\[#(\d+)(?::([^\]]+))?\]/ export function linesToTextboxes(slideLines: string[]) { let items: Item[] = [] diff --git a/src/frontend/utils/createData.ts b/src/frontend/utils/createData.ts index 97e4f98b..00bb8a51 100644 --- a/src/frontend/utils/createData.ts +++ b/src/frontend/utils/createData.ts @@ -3,6 +3,7 @@ import { setShow } from "../components/helpers/setShow" import { audioFolders, dictionary, folders, mediaFolders, overlays, projects, remotePassword, shows, templates } from "../stores" import { stageShows, templateCategories } from "./../stores" import { save } from "./save" +import { DEFAULT_ITEM_STYLE } from "../components/edit/scripts/itemHelpers" export function createData(paths: any) { if (!get(shows).default) { @@ -215,7 +216,7 @@ export function setExampleTemplates() { category: "song", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [{ align: "", text: [{ value: get(dictionary).example?.big || "Big", style: "font-size: 120px;" }] }], }, @@ -227,7 +228,7 @@ export function setExampleTemplates() { category: "song", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [{ align: "", text: [{ value: get(dictionary).example?.default || "Default", style: "font-size: 100px;" }] }], }, @@ -239,7 +240,7 @@ export function setExampleTemplates() { category: "song", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [{ align: "", text: [{ value: get(dictionary).example?.small || "Small", style: "font-size: 80px;" }] }], }, @@ -251,7 +252,7 @@ export function setExampleTemplates() { category: "song", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [ { @@ -273,7 +274,7 @@ export function setExampleTemplates() { category: "song", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [ { @@ -295,7 +296,7 @@ export function setExampleTemplates() { category: "song", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [ { @@ -553,7 +554,7 @@ export function setExampleTemplates() { category: "presentation", items: [ { - style: "top:120px;left:50px;height:840px;width:1820px;", + style: DEFAULT_ITEM_STYLE, align: "", lines: [ {