웹에는 더 많은 (맛있는) 사운드가 필요합니다!
이 라이브러리는 React DOM에서만 작동하지만 @remigallego는 React Native에 대한 대안을 만들었습니다! 반응 네이티브 사용 사운드를 확인하세요.
이 프로젝트는 "반 유지"됩니까?
지금은 극단적인 문제를 조사하거나 문제 해결에 도움을 줄 여력이 없지만 주요 React 릴리스를 최신 상태로 유지하고 심각하고 일반적인 문제를 해결할 계획입니다.
기능에 대한 아이디어가 있거나 이상한 점에 부딪히면 프로젝트를 포크하여 자신만의 것으로 만드는 것이 좋습니다! 위협적으로 보일 수도 있지만 소스는 다른 많은 NPM 패키지만큼 복잡하지 않습니다. 나는 모든 어려운 오디오 작업을 Howler에게 맡깁니다.) 한동안 React를 사용해왔고 Hook에 익숙하다면 이 패키지의 코드가 편안함을 느낄 것입니다.
실을 사용하여 패키지를 추가할 수 있습니다.
yarn add use-sound
또는 NPM을 사용하세요.
npm install use-sound
unpkg에서 UMD 빌드를 사용할 수 있습니다.
프로젝트에서 TypeScript를 사용하는 경우 @types/howler
패키지도 개발 종속성으로 설치해야 합니다.
튜토리얼 에는 다양한 데모와 음향 효과를 찾고 준비하기 위한 지침이 포함되어 있습니다. 시작하기 좋은 곳입니다.
또한 간단한 예제가 많이 포함된 스토리북을 볼 수도 있습니다.
import useSound from 'use-sound' ;
import boopSfx from '../../sounds/boop.mp3' ;
const BoopButton = ( ) => {
const [ play ] = useSound ( boopSfx ) ;
return < button onClick = { play } > Boop! < / button > ;
} ;
이 데모는 요소 위로 마우스를 가져가는 동안에만 사운드를 재생합니다. 마우스가 요소를 벗어나면 사운드가 일시 중지됩니다.
참고: 많은 브라우저는 사용자가 페이지의 아무 곳이나 클릭할 때까지 소리를 비활성화합니다. 이 예에서 아무 소리도 들리지 않으면 아무 곳이나 클릭하고 다시 시도해 보세요.
import useSound from 'use-sound' ;
import fanfareSfx from '../../sounds/fanfare.mp3' ;
const FanfareButton = ( ) => {
const [ play , { stop } ] = useSound ( fanfareSfx ) ;
return (
< button onMouseEnter = { ( ) => play ( ) } onMouseLeave = { ( ) => stop ( ) } >
< span role = "img" aria-label = "trumpet" >
?
< / span >
< / button >
) ;
} ;
playbackRate
옵션을 사용하면 샘플의 속도/피치를 변경할 수 있습니다. 이 예에서는 사운드를 재생하고 매번 10% 더 빠르게 만듭니다.
import useSound from 'use-sound' ;
import glugSfx from '../../sounds/glug.mp3' ;
export const RisingPitch = ( ) => {
const [ playbackRate , setPlaybackRate ] = React . useState ( 0.75 ) ;
const [ play ] = useSound ( glugSfx , {
playbackRate ,
// `interrupt` ensures that if the sound starts again before it's
// ended, it will truncate it. Otherwise, the sound can overlap.
interrupt : true ,
} ) ;
const handleClick = ( ) => {
setPlaybackRate ( playbackRate + 0.1 ) ;
play ( ) ;
} ;
return (
< Button onClick = { handleClick } >
< span role = "img" aria-label = "Person with lines near mouth" >
?
< / span >
< / Button >
) ;
} ;
useSound
오디오 파일에 대한 경로가 필요하며 React 애플리케이션에서 이를 제공하는 방법이 명확하지 않습니다.
create-react-app
사용하면 MP3 파일을 "가져올" 수 있습니다. 동적으로 생성된 경로로 확인됩니다.
import someAudioFile from '../sounds/sound.mp3' ;
console . log ( someAudioFile ) ; // “/build/sounds/sound-abc123.mp3”
Next.js와 같은 다른 React 빌드 시스템에서 이 트릭을 가져오려고 하면 다음과 같은 오류가 발생할 수 있습니다.
이 파일 형식을 처리하려면 적절한 로더가 필요할 수 있습니다. 현재 이 파일을 처리하도록 구성된 로더가 없습니다.
문제는 Webpack(JS 번들을 생성하기 위해 내부적으로 사용되는 번들러)이 MP3 파일을 처리하는 방법을 모른다는 것입니다.
Webpack 구성에 대한 액세스 권한이 있는 경우 파일 로더를 사용하도록 업데이트하여 공개적으로 액세스 가능한 파일 경로를 생성할 수 있습니다.
또는 대부분의 도구는 "공개"(create-react-app, Next.js) 또는 "정적"(Gatsby) 폴더를 제공합니다. 거기에 오디오 파일을 놓은 다음 문자열 경로를 사용할 수 있습니다.
use-sound
와 함께 사용할 사운드 파일은 이미지나 글꼴과 같은 다른 정적 자산과 동일한 규칙을 따릅니다. 선택한 메타 프레임워크에 대한 가이드를 따르세요.
️ 비동기 사운드 경로?️ 오디오 파일의 URL이 비동기적으로 로드되면 몇 가지 문제가 발생할 수 있습니다. 아마도 해당 사용 사례에 적합한 패키지가 아닐 수 있습니다.
사용자를 위해 브라우저는 사용자가 웹사이트와 상호작용(예: 무언가를 클릭)할 때까지 웹사이트에서 소리를 생성하는 것을 허용하지 않습니다. 사용자가 무언가를 클릭하거나 탭하거나 트리거할 때까지 소리가 생성되지 않습니다.
useSound
이를 활용합니다. 로드 시 사운드가 즉시 필요하지 않다는 것을 알고 있기 때문에 타사 종속성을 지연 로드할 수 있습니다.
useSound
번들에 약 1kb gzip을 추가하고 로드 후 추가 패키지를 비동기적으로 가져옵니다. 이 패키지는 약 9kb gzip에 해당합니다.
이 종속성을 로드하고 가져오기 전에 사용자가 소음을 내는 항목을 클릭하면 아무 작업도 수행되지 않습니다(모든 것이 계속 작동하지만 사운드 효과는 재생되지 않습니다). 내 경험상 이런 경우는 극히 드뭅니다.
다음 코드 조각을 고려해보세요.
const [ playbackRate , setPlaybackRate ] = React . useState ( 0.75 ) ;
const [ play ] = useSound ( '/path/to/sound' , { playbackRate } ) ;
playbackRate
사운드 효과의 초기 값으로만 사용되는 것이 아닙니다. playbackRate
변경되면 사운드가 즉시 새로운 속도로 재생되기 시작합니다. 이는 useSound
후크에 전달된 모든 옵션에 해당됩니다.
useSound
후크는 두 가지 인수를 사용합니다.
HookOptions
)두 가지 값을 가진 배열을 생성합니다.
ExposedData
) 사운드를 재생하는 함수를 호출할 때 옵션 세트( PlayOptions
)를 전달할 수 있습니다.
이들 각각을 차례로 살펴보겠습니다.
useSound
호출할 때 다양한 옵션을 전달할 수 있습니다:
이름 | 값 |
---|---|
용량 | 숫자 |
재생속도 | 숫자 |
방해하다 | 불리언 |
사운드 활성화됨 | 불리언 |
요정 | 스프라이트맵 |
[위임됨] | — |
volume
은 0
에서 1
사이의 숫자입니다. 여기서 1
은 전체 볼륨이고 0
완전히 음소거됩니다.playbackRate
는 0.5
에서 4
사이의 숫자입니다. 샘플 속도를 늦추거나 높이는 데 사용할 수 있습니다. 턴테이블과 마찬가지로 속도 변화도 피치에 영향을 미칩니다.interrupt
사운드가 끝나기 전에 play
함수를 다시 호출하는 경우 사운드가 "중복"될 수 있는지 여부를 지정합니다.soundEnabled
사용하면 (일반적으로 context나 redux 등에서) 값을 전달하여 모든 사운드를 음소거할 수 있습니다. 이는 PlayOptions
에서 재정의될 수 있습니다. 아래를 참조하세요.sprite
사용하면 여러 사운드 효과에 단일 useSound
후크를 사용할 수 있습니다. 아래의 "스프라이트"를 참조하세요. [delegated]
HookOptions
에 전달하는 추가 인수가 Howl
생성자로 전달된다는 사실을 나타냅니다. 자세한 내용은 아래의 "탈출 해치"를 참조하세요.
play
기능후크를 호출하면 튜플의 첫 번째 항목으로 재생 함수가 반환됩니다.
const [ play ] = useSound ( '/meow.mp3' ) ;
// ^ What we're talking about
사운드를 트리거하려는 경우 인수 없이 이 함수를 호출할 수 있습니다. PlayOptions
개체를 사용하여 호출할 수도 있습니다.
이름 | 값 |
---|---|
ID | 끈 |
강제사운드 활성화됨 | 불리언 |
재생속도 | 숫자 |
id
스프라이트 식별에 사용됩니다. 아래의 "스프라이트"를 참조하세요.forceSoundEnabled
사용하면 HookOptions
에 전달된 soundEnabled
부울을 재정의할 수 있습니다. 당신은 일반적으로 이것을하고 싶지 않습니다. 내가 찾은 유일한 예외는 "음소거" 버튼에서 소리가 나는 것입니다.playbackRate
는 HookOptions
와 마찬가지로 새로운 재생 속도를 설정할 수 있는 또 다른 방법입니다. 일반적으로 HookOptions
통해 수행하는 것을 선호해야 하며 이는 탈출구입니다. 후크는 재생 함수와 ExposedData
객체라는 두 가지 옵션이 있는 튜플을 생성합니다.
const [ play , exposedData ] = useSound ( '/meow.mp3' ) ;
// ^ What we're talking about
이름 | 값 |
---|---|
멈추다 | 함수 ((id?: string) => void) |
정지시키다 | 함수 ((id?: string) => void) |
지속 | 숫자(또는 null) |
소리 | 하울링(또는 null) |
stop
은 사전에 사운드를 정지하는 데 사용할 수 있는 기능입니다.pause
동일한 지점에서 다시 시작할 수 있다는 점을 제외하면 stop
와 같습니다. 재개할 것인지 알지 못하는 경우에는 stop
사용해야 합니다. pause
는 어느 시점에서 재개될 것으로 예상되므로 리소스를 많이 소모합니다.duration
은 샘플의 길이(밀리초)입니다. 샘플이 로드될 때까지 null
입니다. 스프라이트의 경우 전체 파일의 길이입니다.sound
탈출용 해치입니다. 기본 Howl
인스턴스에 대한 액세스 권한을 부여합니다. 사용 방법에 대한 자세한 내용은 Howler 문서를 참조하세요. 구성요소가 마운트된 후 처음 몇 분 동안은 null
이 됩니다. 오디오 스프라이트는 여러 샘플을 포함하는 단일 오디오 파일입니다. 많은 개별 사운드를 로드하는 대신 단일 파일을 로드하고 독립적으로 트리거할 수 있는 여러 섹션으로 분할할 수 있습니다.
병렬 네트워크 요청이 적기 때문에 성능상의 이점이 있을 수 있지만 단일 구성 요소에 여러 샘플이 필요한 경우에도 이 작업을 수행할 가치가 있습니다. 예를 보려면 Drum Machine 이야기를 참조하세요.
스프라이트의 경우 SpriteMap
정의해야 합니다. 다음과 같습니다.
const spriteMap = {
laser : [ 0 , 300 ] ,
explosion : [ 1000 , 300 ] ,
meow : [ 2000 , 75 ] ,
} ;
SpriteMap
객체입니다. 키는 개별 사운드의 id
입니다. 값은 2개의 항목이 있는 튜플(고정 길이 배열)입니다.
이 시각화를 통해 더 명확해질 수 있습니다.
SpriteMap을 HookOption 중 하나로 전달할 수 있습니다.
const [ play ] = useSound ( '/path/to/sprite.mp3' , {
sprite : {
laser : [ 0 , 300 ] ,
explosion : [ 1000 , 300 ] ,
meow : [ 2000 , 75 ] ,
} ,
} ) ;
특정 스프라이트를 재생하기 위해 play
함수를 호출할 때 해당 id
전달합니다.
< button
onClick = { ( ) => play ( { id : 'laser' } ) }
>
Howler는 매우 강력한 라이브러리이며 useSound
에서 수행할 수 있는 작업 중 아주 작은 부분만 노출했습니다. 더 많은 제어권을 제공하기 위해 두 개의 탈출구를 노출합니다.
첫째, HookOptions
에 전달한 인식할 수 없는 옵션은 Howl
에 위임됩니다. Howler 문서에서 전체 옵션 목록을 볼 수 있습니다. 다음은 사운드 재생이 중지될 때 onend
사용하여 함수를 실행하는 방법에 대한 예입니다.
const [ play ] = useSound ( '/thing.mp3' , {
onend : ( ) => {
console . info ( 'Sound ended!' ) ;
} ,
} ) ;
더 많은 제어가 필요하다면 Howler의 인스턴스인 sound
개체를 직접 사용할 수 있어야 합니다.
예: Howler는 사운드를 페이드 인하거나 페이드 아웃할 수 있는 fade
메서드를 제공합니다. sound
객체에서 직접 이 메서드를 호출할 수 있습니다.
const Arcade = ( ) => {
const [ play , { sound } ] = useSound ( '/win-theme.mp3' ) ;
return (
< button
onClick = { ( ) => {
// You win! Fade in the victory theme
sound . fade ( 0 , 1 , 1000 ) ;
} }
>
Click to win
< / button >
) ;
} ;