update,
This commit is contained in:
3
task1/_poc/useAudioPlayer-main/examples/.npmignore
Normal file
3
task1/_poc/useAudioPlayer-main/examples/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.cache
|
||||
dist
|
18
task1/_poc/useAudioPlayer-main/examples/index.html
Normal file
18
task1/_poc/useAudioPlayer-main/examples/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>Playground</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="./src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
31
task1/_poc/useAudioPlayer-main/examples/package.json
Normal file
31
task1/_poc/useAudioPlayer-main/examples/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "example",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"browserslist": [
|
||||
"last 1 Chrome version"
|
||||
],
|
||||
"scripts": {
|
||||
"start": "parcel index.html",
|
||||
"build": "parcel build.html"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-app-polyfill": "^1.0.0",
|
||||
"react-router-dom": "^6.11.0"
|
||||
},
|
||||
"alias": {
|
||||
"react": "../node_modules/react",
|
||||
"react-dom": "../node_modules/react-dom",
|
||||
"scheduler/tracing": "../node_modules/scheduler/tracing-profiling",
|
||||
"react-use-audio-player": "../src",
|
||||
"typescript": "../node_modules/typescript"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.9.11",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"parcel": "^1.12.3",
|
||||
"parcel-plugin-static-files-copy": "^2.2.1",
|
||||
"sass": "^1.26.3"
|
||||
}
|
||||
}
|
44
task1/_poc/useAudioPlayer-main/examples/src/App.tsx
Normal file
44
task1/_poc/useAudioPlayer-main/examples/src/App.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from "react"
|
||||
import { BrowserRouter, Link, Route, Routes } from "react-router-dom"
|
||||
import { BasicExample } from "./GlobalAudioSource/AudioPlayerState"
|
||||
import { Spotifyish } from "./GlobalAudioSource/SoundLibrary"
|
||||
import { AutoPlayNextSound } from "./GlobalAudioSource/AutoPlayNextSound"
|
||||
import { MultipleSounds } from "./MultipleSounds"
|
||||
import { GlobalAudioSource } from "./GlobalAudioSource"
|
||||
import "./app.scss"
|
||||
import { Streaming } from "./Streaming"
|
||||
|
||||
function ExampleSelect() {
|
||||
return (
|
||||
<div className="page">
|
||||
<h3>Examples</h3>
|
||||
<Link to="/globalAudio">useGlobalAudioPlayer examples</Link>
|
||||
<Link to="/multipleSounds">Multiple sound sources</Link>
|
||||
<Link to="/streaming">Streaming example</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route index path="/" element={<ExampleSelect />} />
|
||||
<Route path="globalAudio" element={<GlobalAudioSource />}>
|
||||
<Route path="state" element={<BasicExample />} />
|
||||
<Route path="library" element={<Spotifyish />} />
|
||||
<Route
|
||||
path="playNextSound"
|
||||
element={<AutoPlayNextSound />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="multipleSounds" element={<MultipleSounds />} />
|
||||
<Route path="streaming" element={<Streaming />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
@@ -0,0 +1,10 @@
|
||||
.audioSeekBar {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
|
||||
&__tick {
|
||||
background-color: #a1d0d1;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
67
task1/_poc/useAudioPlayer-main/examples/src/AudioSeekBar.tsx
Normal file
67
task1/_poc/useAudioPlayer-main/examples/src/AudioSeekBar.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
FunctionComponent,
|
||||
MouseEvent
|
||||
} from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
import "./AudioSeekBar.scss"
|
||||
|
||||
interface AudioSeekBarProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const AudioSeekBar: FunctionComponent<AudioSeekBarProps> = props => {
|
||||
const { className = "" } = props
|
||||
const { playing, getPosition, duration, seek } = useGlobalAudioPlayer()
|
||||
const [pos, setPos] = useState(0)
|
||||
const frameRef = useRef<number>()
|
||||
|
||||
const seekBarElem = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const animate = () => {
|
||||
setPos(getPosition())
|
||||
frameRef.current = requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
frameRef.current = window.requestAnimationFrame(animate)
|
||||
|
||||
return () => {
|
||||
if (frameRef.current) {
|
||||
cancelAnimationFrame(frameRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
const goTo = useCallback(
|
||||
(event: MouseEvent) => {
|
||||
const { pageX: eventOffsetX } = event
|
||||
|
||||
if (seekBarElem.current) {
|
||||
const elementOffsetX = seekBarElem.current.offsetLeft
|
||||
const elementWidth = seekBarElem.current.clientWidth
|
||||
const percent = (eventOffsetX - elementOffsetX) / elementWidth
|
||||
seek(percent * duration)
|
||||
}
|
||||
},
|
||||
[duration, playing, seek]
|
||||
)
|
||||
|
||||
if (duration === Infinity) return null
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`audioSeekBar ${className} `}
|
||||
ref={seekBarElem}
|
||||
onClick={goTo}
|
||||
>
|
||||
<div
|
||||
style={{ width: `${(pos / duration) * 100}%` }}
|
||||
className="audioSeekBar__tick"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
10
task1/_poc/useAudioPlayer-main/examples/src/BackToHome.tsx
Normal file
10
task1/_poc/useAudioPlayer-main/examples/src/BackToHome.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React, { FunctionComponent } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
interface BackToHomeProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const BackToHome: FunctionComponent<BackToHomeProps> = (props) => {
|
||||
return <Link className={ props.className || "" } to="/">{"< -"} Example Select</Link>
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
import React, { useEffect, useState, FunctionComponent } from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
|
||||
export const AudioControls: FunctionComponent<{}> = () => {
|
||||
const {
|
||||
play,
|
||||
pause,
|
||||
stop,
|
||||
mute,
|
||||
muted,
|
||||
playing,
|
||||
loop,
|
||||
looping
|
||||
} = useGlobalAudioPlayer()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => (playing ? pause() : play())}>
|
||||
{playing ? "pause" : "play"}
|
||||
</button>
|
||||
<button onClick={() => stop()}>stop</button>
|
||||
<button onClick={() => mute(!muted)}>toggle mute</button>
|
||||
<button onClick={() => loop(!looping)}>toggle loop</button>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
import React, {
|
||||
useState,
|
||||
FunctionComponent,
|
||||
ChangeEvent,
|
||||
useEffect
|
||||
} from "react"
|
||||
import { AudioLoadOptions, useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
|
||||
export const FileLoader: FunctionComponent = () => {
|
||||
const [audioFile, setAudioFile] = useState("/audio.mp3")
|
||||
const { load, isReady, error } = useGlobalAudioPlayer()
|
||||
|
||||
useEffect(() => {
|
||||
const loadOptions: AudioLoadOptions = { initialVolume: 0.5 }
|
||||
if (audioFile.includes("stream")) {
|
||||
loadOptions.html5 = true
|
||||
loadOptions.format = "mp3"
|
||||
}
|
||||
|
||||
load(audioFile, loadOptions)
|
||||
}, [audioFile, load])
|
||||
|
||||
const selectAudioFile = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const { value } = e.target
|
||||
if (value) {
|
||||
setAudioFile(value)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h5>select audio file:</h5>
|
||||
<select onChange={selectAudioFile} value={audioFile}>
|
||||
<option value="/audio.mp3">audio</option>
|
||||
<option value="/cats.mp3">cats</option>
|
||||
<option value="/dog.mp3">dog</option>
|
||||
<option value="/ch_tunes - baby_seal.wav">
|
||||
ch_tunes - baby_seal
|
||||
</option>
|
||||
<option value="/doesntExist.mp3">does not exist</option>
|
||||
<option value="https://stream.toohotradio.net/128">
|
||||
streaming internet radio
|
||||
</option>
|
||||
</select>
|
||||
{!isReady && !error && <p>Fetching audio file...</p>}
|
||||
{error && <p className="errorMessage">Failed to load</p>}
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
import React, { FunctionComponent } from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
import { FileLoader } from "./FileLoader"
|
||||
import { AudioControls } from "./AudioControls"
|
||||
import { AudioSeekBar } from "../../AudioSeekBar"
|
||||
import { TimeLabel } from "../../TimeLabel"
|
||||
import "./styles.scss"
|
||||
|
||||
const Player = () => {
|
||||
const state = useGlobalAudioPlayer()
|
||||
if (state.isReady) {
|
||||
return (
|
||||
<div className="player">
|
||||
<AudioControls />
|
||||
<AudioSeekBar className="player__seek" />
|
||||
<TimeLabel />
|
||||
<br />
|
||||
<p>
|
||||
Below are all the fields available on the result of
|
||||
useGlobalAudioPlayer/useAudioPlayer which can be used to
|
||||
help build user interfaces for your sounds
|
||||
</p>
|
||||
<h3>Audio state:</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
{Object.entries(state).map(([k, v]) => {
|
||||
if (typeof v === "function") return null
|
||||
|
||||
return (
|
||||
<tr key={k}>
|
||||
<td>{k}</td>
|
||||
<td>{v?.toString() ?? "--"}</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export const BasicExample: FunctionComponent = () => {
|
||||
return (
|
||||
<div className="basicExample">
|
||||
<FileLoader />
|
||||
<br />
|
||||
<Player />
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
.basicExample {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.player {
|
||||
&__seek {
|
||||
width: 400px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
td {
|
||||
border: solid 1px white;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
import { TimeLabel } from "../../TimeLabel"
|
||||
import "./styles"
|
||||
import { Howl } from "howler"
|
||||
|
||||
const songs = [
|
||||
"/ch_tunes - jam_10.wav",
|
||||
"/ch_tunes - baby_seal.wav",
|
||||
"/ch_tunes - jam_4.wav"
|
||||
]
|
||||
|
||||
export function AutoPlayNextSound() {
|
||||
const [songIndex, setSongIndex] = useState(0)
|
||||
|
||||
const {
|
||||
togglePlayPause,
|
||||
isReady,
|
||||
load,
|
||||
seek,
|
||||
duration,
|
||||
playing
|
||||
} = useGlobalAudioPlayer()
|
||||
|
||||
useEffect(() => {
|
||||
load(songs[songIndex], {
|
||||
autoplay: true,
|
||||
onend: () => {
|
||||
setSongIndex(index => {
|
||||
if (index === songs.length - 1) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return index + 1
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [load, songIndex])
|
||||
|
||||
if (!isReady) return <h1>audio {songs[songIndex]} is loading</h1>
|
||||
|
||||
return (
|
||||
<div className="page autoPlayNextSound">
|
||||
<div className="autoPlayNextSound__player">
|
||||
<div className="trackList">
|
||||
<div className="trackList__title">Now playing...</div>
|
||||
{songs.map((s, i) => (
|
||||
<div
|
||||
key={s}
|
||||
className={`trackList__song${
|
||||
i === songIndex ? "--selected" : ""
|
||||
}`}
|
||||
>
|
||||
{s}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="autoPlayNextSound__controls">
|
||||
<button onClick={togglePlayPause}>
|
||||
{playing ? "pause" : "play"}
|
||||
</button>
|
||||
<button onClick={() => seek(duration * 0.99)}>
|
||||
skip to end
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<TimeLabel />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AutoPlayNextSound
|
@@ -0,0 +1,44 @@
|
||||
.autoPlayNextSound {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.autoPlayNextSound a {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.autoPlayNextSound__player {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 8px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.trackList {
|
||||
border: 1px solid lightblue;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.trackList__title {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.trackList__song--selected {
|
||||
font-weight: bolder;
|
||||
color: lightcyan;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.autoPlayNextSound__controls {
|
||||
display: flex;
|
||||
margin-bottom: 16px;
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
import React from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
import { AudioSeekBar } from "../AudioSeekBar"
|
||||
import { TimeLabel } from "../TimeLabel"
|
||||
import { VolumeControl } from "../VolumeControl"
|
||||
|
||||
export const PlayBar = () => {
|
||||
const {
|
||||
togglePlayPause,
|
||||
playing,
|
||||
isReady,
|
||||
setRate,
|
||||
rate,
|
||||
src
|
||||
} = useGlobalAudioPlayer()
|
||||
|
||||
return (
|
||||
<div className="playBar">
|
||||
<div className="playBar__track">Track: {src}</div>
|
||||
<div className="playBar__mainControls">
|
||||
<button
|
||||
className="playBar__playButton"
|
||||
onClick={togglePlayPause}
|
||||
disabled={!isReady}
|
||||
>
|
||||
<i className={`fa ${playing ? "fa-pause" : "fa-play"}`} />
|
||||
</button>
|
||||
<div className="playBar__timeStuff">
|
||||
<AudioSeekBar className="playBar__seek" />
|
||||
<TimeLabel />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="playBar__rateControl">
|
||||
<span>Playback Speed:</span>
|
||||
<select
|
||||
className="playBar__rateSelect"
|
||||
name="rateSelect"
|
||||
id="rate"
|
||||
value={rate}
|
||||
onChange={e => setRate(Number(e.target.value))}
|
||||
>
|
||||
<option value="0.5">1/2x</option>
|
||||
<option value="1">1x</option>
|
||||
<option value="2">2x</option>
|
||||
</select>
|
||||
</div>
|
||||
<VolumeControl />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
import React from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
import "./styles.scss"
|
||||
|
||||
export const Spotifyish = () => {
|
||||
const sounds = [
|
||||
"/audio.mp3",
|
||||
"/cats.mp3",
|
||||
"/dog.mp3",
|
||||
"/ch_tunes - baby_seal.wav",
|
||||
"/ch_tunes - jam_2.wav",
|
||||
"/ch_tunes - jam_4.wav",
|
||||
"/ch_tunes - jam_8.wav",
|
||||
"/ch_tunes - jam_10.wav"
|
||||
]
|
||||
const { load, src: loadedSrc } = useGlobalAudioPlayer()
|
||||
return (
|
||||
<div className="soundLibrary page">
|
||||
<div className="page__title">Sound Library</div>
|
||||
<p>
|
||||
This page lists the full set of sounds available in the demos.
|
||||
</p>
|
||||
<div className="soundLibrary__sounds">
|
||||
{sounds.map((src, i) => {
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={`track ${
|
||||
src === loadedSrc ? "track--playing" : ""
|
||||
}`}
|
||||
onClick={() => load(src, { autoplay: true })}
|
||||
>
|
||||
<i className="fa fa-music track__icon" />
|
||||
<div className="track__title">
|
||||
{src.slice(1, src.indexOf("."))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
.soundLibrary {
|
||||
&__sounds {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.track {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 10px 10px;
|
||||
margin-bottom:25px;
|
||||
border: solid 1px white;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
&--playing {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: medium;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: medium;
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
import React from "react"
|
||||
import { Link, Outlet, useMatch } from "react-router-dom"
|
||||
import "./styles.scss"
|
||||
import { PlayBar } from "./PlayBar"
|
||||
|
||||
const ExampleSelect = () => {
|
||||
return (
|
||||
<>
|
||||
<Link to="..">go back</Link>
|
||||
<p>
|
||||
The following examples leverage useGlobalAudioPlayer to control
|
||||
a single, global audio source. At any time, this audio can be
|
||||
managed by the playbar at the bottom of the page.
|
||||
</p>
|
||||
<h4>Examples</h4>
|
||||
<Link to="state">Audio Player State</Link>
|
||||
<Link to="library">Full Sound Library</Link>
|
||||
<Link to="playNextSound">Auto Play Next Example</Link>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const ExitExample = () => {
|
||||
return (
|
||||
<Link to=".." relative="path">
|
||||
Exit Example
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export const GlobalAudioSource = () => {
|
||||
const matches = useMatch("/globalAudio")
|
||||
return (
|
||||
<div className="page globalAudioSourceExamples">
|
||||
<div className="globalAudioSourceExamples__header">
|
||||
{matches !== null ? <ExampleSelect /> : <ExitExample />}
|
||||
</div>
|
||||
<Outlet />
|
||||
<PlayBar />
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
.globalAudioSourceExamples {
|
||||
|
||||
}
|
||||
|
||||
.globalAudioSourceExamples__header {
|
||||
|
||||
}
|
||||
|
||||
|
||||
.playBar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-color: #1c192f;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 25px 50px;
|
||||
|
||||
&__track {
|
||||
align-self: flex-start;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
&__mainControls {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__playButton {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
padding-top: 5px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&__timeStuff {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__seek {
|
||||
width: 400px;
|
||||
height: 10px;
|
||||
border-radius: 12px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&__rateControl {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
&__rateControl span {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
&__rateSelect {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
import React, { useState, useCallback, useEffect } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import { useAudioPlayer } from "react-use-audio-player"
|
||||
import "./styles.scss"
|
||||
|
||||
export const MultipleSounds = () => {
|
||||
const [xFadeValue, setXFadeValue] = useState(50)
|
||||
const song1 = useAudioPlayer()
|
||||
const song2 = useAudioPlayer()
|
||||
|
||||
useEffect(() => {
|
||||
song1.load("/ch_tunes - jam_4.wav", { autoplay: false })
|
||||
song2.load("/ch_tunes - baby_seal.wav", { autoplay: false })
|
||||
}, [])
|
||||
|
||||
const togglePlayingBoth = useCallback(() => {
|
||||
song1.togglePlayPause()
|
||||
song2.togglePlayPause()
|
||||
}, [song1.togglePlayPause, song2.togglePlayPause])
|
||||
|
||||
const handleFade = useCallback(e => {
|
||||
setXFadeValue(e.target.value)
|
||||
const ratio = e.target.value / 100
|
||||
song1.setVolume(1 - ratio)
|
||||
song2.setVolume(ratio)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="page multipleSounds">
|
||||
<Link
|
||||
to=".."
|
||||
onClick={() => {
|
||||
song1.cleanup()
|
||||
song2.cleanup()
|
||||
}}
|
||||
>
|
||||
go back
|
||||
</Link>
|
||||
<div className="multipleSounds__tracks">
|
||||
<div className="multipleSounds__track">
|
||||
<p>{song1.src}</p>
|
||||
<div className="hstack">
|
||||
<label htmlFor="song1vol">volume</label>
|
||||
<input
|
||||
name="song1vol"
|
||||
type="range"
|
||||
readOnly
|
||||
value={Number(song1.volume.toFixed(2)) * 100}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="multipleSounds__track">
|
||||
<p>{song2.src}</p>
|
||||
<div className="hstack">
|
||||
<label htmlFor="song2vol">volume</label>
|
||||
<input
|
||||
name="song2vol"
|
||||
type="range"
|
||||
readOnly
|
||||
value={Number(song2.volume.toFixed(2)) * 100}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="multipleSounds__controls">
|
||||
<button onClick={togglePlayingBoth}>
|
||||
{song1.playing ? "Pause" : "Play"}
|
||||
</button>
|
||||
<input type="range" value={xFadeValue} onChange={handleFade} />
|
||||
<p>Adjust the slider to fade between the two songs</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
.multipleSounds {
|
||||
|
||||
&__tracks {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__track {
|
||||
|
||||
}
|
||||
|
||||
&__controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
margin-top: 50px;
|
||||
|
||||
input[type="range"] {
|
||||
margin: 10px 0;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
import React, { useEffect } from "react"
|
||||
import { useAudioPlayer } from "react-use-audio-player"
|
||||
import "./styles.scss"
|
||||
|
||||
export function Streaming() {
|
||||
const player = useAudioPlayer()
|
||||
|
||||
useEffect(() => {
|
||||
player.load("http://mp3-128.streamthejazzgroove.com", {
|
||||
html5: true,
|
||||
format: "mp3"
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<table>
|
||||
<tbody>
|
||||
{Object.entries(player).map(([k, v]) => {
|
||||
if (typeof v === "function") return null
|
||||
|
||||
return (
|
||||
<tr key={k}>
|
||||
<td>{k}</td>
|
||||
<td>{v?.toString() ?? "--"}</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="stateupdate"></div>
|
||||
<button onClick={() => player.togglePlayPause()}>
|
||||
{player.playing ? "pause" : "play"}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
td {
|
||||
border: solid 1px white;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.wave {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background-color: #ccc;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wave::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
animation: waveAnimation 4s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes waveAnimation {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
}
|
33
task1/_poc/useAudioPlayer-main/examples/src/TimeLabel.tsx
Normal file
33
task1/_poc/useAudioPlayer-main/examples/src/TimeLabel.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
|
||||
const formatTime = (seconds: number) => {
|
||||
if (seconds === Infinity) {
|
||||
return "--"
|
||||
}
|
||||
const floored = Math.floor(seconds)
|
||||
let from = 14
|
||||
let length = 5
|
||||
// Display hours only if necessary.
|
||||
if (floored >= 3600) {
|
||||
from = 11
|
||||
length = 8
|
||||
}
|
||||
|
||||
return new Date(floored * 1000).toISOString().substr(from, length)
|
||||
}
|
||||
|
||||
export const TimeLabel = () => {
|
||||
const [pos, setPos] = useState(0)
|
||||
const { duration, getPosition, playing } = useGlobalAudioPlayer()
|
||||
|
||||
useEffect(() => {
|
||||
const i = setInterval(() => {
|
||||
setPos(getPosition())
|
||||
}, 500)
|
||||
|
||||
return () => clearInterval(i)
|
||||
}, [getPosition])
|
||||
|
||||
return <div>{`${formatTime(pos)} / ${formatTime(duration)}`}</div>
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
.volumeControl {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&__icon {
|
||||
color: white;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
import React, { ChangeEvent, useCallback } from "react"
|
||||
import { useGlobalAudioPlayer } from "react-use-audio-player"
|
||||
import "./VolumeControl.scss"
|
||||
|
||||
export const VolumeControl = () => {
|
||||
const { setVolume, volume } = useGlobalAudioPlayer()
|
||||
|
||||
const handleChange = useCallback(
|
||||
(slider: ChangeEvent<HTMLInputElement>) => {
|
||||
const volValue = parseFloat(
|
||||
(Number(slider.target.value) / 100).toFixed(2)
|
||||
)
|
||||
return setVolume(volValue)
|
||||
},
|
||||
[setVolume]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="volumeControl">
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={100}
|
||||
onChange={handleChange}
|
||||
value={volume * 100}
|
||||
/>
|
||||
<i className="fa fa-volume-up volumeControl__icon" />
|
||||
</div>
|
||||
)
|
||||
}
|
77
task1/_poc/useAudioPlayer-main/examples/src/app.scss
Normal file
77
task1/_poc/useAudioPlayer-main/examples/src/app.scss
Normal file
@@ -0,0 +1,77 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #272a51;
|
||||
color: #e1fdff;
|
||||
font-weight: 400;
|
||||
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: #79b7c0;
|
||||
}
|
||||
a:hover {
|
||||
color: #5593aa;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
|
||||
#root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page {
|
||||
width: 100%;
|
||||
height: calc(100% - 125px);
|
||||
padding: 25px;
|
||||
|
||||
&__title {
|
||||
font-size: xx-large;
|
||||
font-weight: 200;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.hstack {
|
||||
display:flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/*
|
||||
#e1fdff
|
||||
#e5f9f9
|
||||
#e9f3f3
|
||||
#ddeaea
|
||||
#c4dfde
|
||||
#a1d0d1
|
||||
#79b7c0
|
||||
#5593aa
|
||||
#3a6891
|
||||
#324672
|
||||
#272a51
|
||||
#1c192f
|
||||
*/
|
19
task1/_poc/useAudioPlayer-main/examples/src/index.tsx
Normal file
19
task1/_poc/useAudioPlayer-main/examples/src/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from "react"
|
||||
import ReactDOM from "react-dom/client"
|
||||
import "./app.scss"
|
||||
import App from "./App"
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"))
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
)
|
||||
|
||||
// ReactDOM.render(
|
||||
// <React.StrictMode>
|
||||
// <App />
|
||||
// </React.StrictMode>,
|
||||
// document.getElementById("root")
|
||||
// )
|
BIN
task1/_poc/useAudioPlayer-main/examples/static/audio.mp3
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/audio.mp3
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/cats.mp3
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/cats.mp3
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - baby_seal.wav
(Stored with Git LFS)
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - baby_seal.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_10.wav
(Stored with Git LFS)
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_10.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_2.wav
(Stored with Git LFS)
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_2.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_4.wav
(Stored with Git LFS)
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_4.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_8.wav
(Stored with Git LFS)
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/ch_tunes - jam_8.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
task1/_poc/useAudioPlayer-main/examples/static/dog.mp3
Normal file
BIN
task1/_poc/useAudioPlayer-main/examples/static/dog.mp3
Normal file
Binary file not shown.
22
task1/_poc/useAudioPlayer-main/examples/tsconfig.json
Normal file
22
task1/_poc/useAudioPlayer-main/examples/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"removeComments": true,
|
||||
"strictNullChecks": true,
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": true,
|
||||
"lib": ["es2021", "dom"],
|
||||
"baseUrl": ".",
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"react-use-audio-player": ["../src"]
|
||||
}
|
||||
}
|
||||
}
|
5349
task1/_poc/useAudioPlayer-main/examples/yarn.lock
Normal file
5349
task1/_poc/useAudioPlayer-main/examples/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user