diff --git a/src/mixer/audio.ts b/src/mixer/audio.ts index 900ef3a..568310b 100644 --- a/src/mixer/audio.ts +++ b/src/mixer/audio.ts @@ -8,7 +8,12 @@ import NewsEndCountdown from "../assets/audio/NewsEndCountdown.wav"; import NewsIntro from "../assets/audio/NewsIntro.wav"; import StereoAnalyserNode from "stereo-analyser-node"; -import { DEFAULT_TRIM_DB, OFF_LEVEL_DB } from "./state"; + +export const DEFAULT_TRIM_DB = -6; // The default trim applied to channel players. + +export const OFF_LEVEL_DB = -40; +export const BED_LEVEL_DB = -13; +export const FULL_LEVEL_DB = 0; interface PlayerEvents { loadComplete: (duration: number) => void; diff --git a/src/mixer/state.ts b/src/mixer/state.ts index f1a5f9a..2b8f3a5 100644 --- a/src/mixer/state.ts +++ b/src/mixer/state.ts @@ -12,9 +12,17 @@ import Keys from "keymaster"; import { Track, MYRADIO_NON_API_BASE, AuxItem } from "../api"; import { AppThunk } from "../store"; import { RootState } from "../rootReducer"; + import { audioEngine, ChannelMapping } from "./audio"; import * as TheNews from "./the_news"; +import { + DEFAULT_TRIM_DB, + OFF_LEVEL_DB, + BED_LEVEL_DB, + FULL_LEVEL_DB, +} from "./audio"; + const playerGainTweens: Array<{ target: VolumePresetEnum; tweens: Between[]; @@ -27,12 +35,6 @@ type PlayerRepeatEnum = "none" | "one" | "all"; type VolumePresetEnum = "off" | "bed" | "full"; type MicVolumePresetEnum = "off" | "full"; export type MicErrorEnum = "NO_PERMISSION" | "NOT_SECURE_CONTEXT" | "UNKNOWN"; - -export const DEFAULT_TRIM_DB = -6; // The default trim applied to channel players. - -export const OFF_LEVEL_DB = -40; -export const BED_LEVEL_DB = -13; -export const FULL_LEVEL_DB = 0; interface PlayerState { loadedItem: PlanItem | Track | AuxItem | null; loading: number; diff --git a/src/showplanner/index.tsx b/src/showplanner/index.tsx index 959c5da..7230759 100644 --- a/src/showplanner/index.tsx +++ b/src/showplanner/index.tsx @@ -2,18 +2,7 @@ import React, { useState, useReducer, useEffect } from "react"; import { Menu, Item as CtxMenuItem } from "react-contexify"; import "react-contexify/dist/ReactContexify.min.css"; import { useBeforeunload } from "react-beforeunload"; -import { - FaBookOpen, - FaFileImport, - FaBars, - FaMicrophone, - FaTrash, - FaUpload, - FaPlayCircle, - FaCircleNotch, - FaPencilAlt, -} from "react-icons/fa"; -import { VUMeter } from "../optionsMenu/helpers/VUMeter"; +import { FaBars, FaTrash, FaCircleNotch, FaPencilAlt } from "react-icons/fa"; import { MYRADIO_NON_API_BASE, TimeslotItem } from "../api"; import appLogo from "../assets/images/webstudio.svg"; @@ -36,33 +25,22 @@ import { addItem, removeItem, setItemPlayed, - getPlaylists, PlanItemBase, } from "./state"; import * as MixerState from "../mixer/state"; -import * as OptionsMenuState from "../optionsMenu/state"; + import { Item, TS_ITEM_MENU_ID } from "./Item"; -import { - CentralMusicLibrary, - CML_CACHE, - AuxLibrary, - AUX_CACHE, - ManagedPlaylistLibrary, -} from "./libraries"; +import { CML_CACHE, AUX_CACHE } from "./libraries"; import { Player } from "./Player"; import { CombinedNavAlertBar } from "../navbar"; import { OptionsMenu } from "../optionsMenu"; import { WelcomeModal } from "./WelcomeModal"; import { PisModal } from "./PISModal"; -import { AutoPlayoutModal } from "./AutoPlayoutModal"; -import { LibraryUploadModal } from "./LibraryUploadModal"; -import { ImporterModal } from "./ImporterModal"; import "./channel.scss"; import Modal from "react-modal"; -import { Button } from "reactstrap"; -import { secToHHMM, useInterval } from "../lib/utils"; +import { Sidebar } from "./sidebar"; function Channel({ id, data }: { id: number; data: PlanItem[] }) { return ( @@ -89,216 +67,6 @@ function Channel({ id, data }: { id: number; data: PlanItem[] }) { ); } -function LibraryColumn() { - const [sauce, setSauce] = useState("None"); - const dispatch = useDispatch(); - const { auxPlaylists, managedPlaylists, userPlaylists } = useSelector( - (state: RootState) => state.showplan - ); - - const [autoPlayoutModal, setAutoPlayoutModal] = useState(false); - const [showLibraryUploadModal, setShowLibraryModal] = useState(false); - const [showImporterModal, setShowImporterModal] = useState(false); - - useEffect(() => { - dispatch(getPlaylists()); - }, [dispatch]); - - return ( - <> - setAutoPlayoutModal(false)} - /> - setShowLibraryModal(false)} - /> - setShowImporterModal(false)} - isOpen={showImporterModal} - /> -
-
-

- - Libraries -

- - - -
-
- -
-
- {sauce === "CentralMusicLibrary" && } - {(sauce.startsWith("aux-") || sauce.match(/^\d/)) && ( - - )} - {sauce.startsWith("managed-") && ( - - )} - - -
- Select a library to search. -
-
- - ); -} - -function MicControl() { - const state = useSelector((state: RootState) => state.mixer.mic); - const proMode = useSelector((state: RootState) => state.settings.proMode); - const stereo = useSelector( - (state: RootState) => state.settings.channelVUsStereo - ); - const dispatch = useDispatch(); - - const [count, setCount] = useState(0); - - // Make a persistant mic counter. - useInterval(() => { - if (state.volume === 0 || !state.open) { - setCount(0); - } else { - setCount((c) => c + 1); - } - }, 1000); - - return ( -
-
-

- - Microphone -

- -
-
- {!state.open && ( -

- The microphone has not been setup. Go to{" "} - - . -

- )} - {state.open && proMode && ( - 0 ? "live" : ""}> - Mic Live: - {state.volume > 0 ? secToHHMM(count) : "00:00:00"} - - )} - {state.open && ( - <> -
- -
-
-
- - -
- - )} -
-
- ); -} - function MicLiveIndicator() { const micState = useSelector((state: RootState) => state.mixer.mic); if (micState.open && micState.volume > 0) { @@ -439,11 +207,7 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {   Toggle Sidebar - + diff --git a/src/showplanner/libraries.tsx b/src/showplanner/libraries.tsx index 5f6c0f1..3a4aeec 100644 --- a/src/showplanner/libraries.tsx +++ b/src/showplanner/libraries.tsx @@ -7,11 +7,25 @@ import { AuxItem, loadPlaylistLibrary, } from "../api"; -import { itemId } from "./state"; +import { getPlaylists, itemId } from "./state"; import { Droppable } from "react-beautiful-dnd"; -import { FaCog, FaSearch, FaTimesCircle } from "react-icons/fa"; +import { + FaBookOpen, + FaCog, + FaFileImport, + FaPlayCircle, + FaSearch, + FaTimesCircle, + FaUpload, +} from "react-icons/fa"; +import { AutoPlayoutModal } from "./AutoPlayoutModal"; +import { LibraryUploadModal } from "./LibraryUploadModal"; +import { ImporterModal } from "./ImporterModal"; import { Item } from "./Item"; import "./libraries.scss"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "../rootReducer"; +import { Button } from "reactstrap"; export const CML_CACHE: { [recordid_trackid: string]: Track } = {}; @@ -21,6 +35,131 @@ type searchingStateEnum = | "results" | "no-results"; +export function LibraryColumn() { + const [sauce, setSauce] = useState("None"); + const dispatch = useDispatch(); + const { auxPlaylists, managedPlaylists, userPlaylists } = useSelector( + (state: RootState) => state.showplan + ); + + const [autoPlayoutModal, setAutoPlayoutModal] = useState(false); + const [showLibraryUploadModal, setShowLibraryModal] = useState(false); + const [showImporterModal, setShowImporterModal] = useState(false); + + useEffect(() => { + dispatch(getPlaylists()); + }, [dispatch]); + + return ( + <> + setAutoPlayoutModal(false)} + /> + setShowLibraryModal(false)} + /> + setShowImporterModal(false)} + isOpen={showImporterModal} + /> +
+
+

+ + Libraries +

+ + + +
+
+ +
+
+ {sauce === "CentralMusicLibrary" && } + {(sauce.startsWith("aux-") || sauce.match(/^\d/)) && ( + + )} + {sauce.startsWith("managed-") && ( + + )} + + +
+ Select a library to search. +
+
+ + ); +} + export function CentralMusicLibrary() { const [track, setTrack] = useState(""); const [artist, setArtist] = useState(""); diff --git a/src/showplanner/sidebar.tsx b/src/showplanner/sidebar.tsx new file mode 100644 index 0000000..158d097 --- /dev/null +++ b/src/showplanner/sidebar.tsx @@ -0,0 +1,104 @@ +import React, { useState } from "react"; +import { FaMicrophone, FaBars } from "react-icons/fa"; +import { useDispatch, useSelector } from "react-redux"; +import { secToHHMM, useInterval } from "../lib/utils"; +import { VUMeter } from "../optionsMenu/helpers/VUMeter"; +import { RootState } from "../rootReducer"; +import { LibraryColumn } from "./libraries"; + +import * as OptionsMenuState from "../optionsMenu/state"; +import * as MixerState from "../mixer/state"; + +export function Sidebar() { + return ( + + ); +} +function MicControl() { + const state = useSelector((state: RootState) => state.mixer.mic); + const proMode = useSelector((state: RootState) => state.settings.proMode); + const stereo = useSelector( + (state: RootState) => state.settings.channelVUsStereo + ); + const dispatch = useDispatch(); + + const [count, setCount] = useState(0); + + // Make a persistant mic counter. + useInterval(() => { + if (state.volume === 0 || !state.open) { + setCount(0); + } else { + setCount((c) => c + 1); + } + }, 1000); + + return ( +
+
+

+ + Microphone +

+ +
+
+ {!state.open && ( +

+ The microphone has not been setup. Go to{" "} + + . +

+ )} + {state.open && proMode && ( + 0 ? "live" : ""}> + Mic Live: + {state.volume > 0 ? secToHHMM(count) : "00:00:00"} + + )} + {state.open && ( + <> +
+ +
+
+
+ + +
+ + )} +
+
+ ); +}