Bomb Kirby Running

JAVASCRIPT

게임이펙트01-뮤직플레이어 구현

^. ̫ .^ 2023. 4. 27. 20:36

728x90

음악 플레이 재생 버튼을 누르면 음악이 재생되고 한번 더 누르면 음악이 멈춥니다.

이전 버튼을 누르면 이전 곡이 재생되고 다음 버튼을 누르면 다음 곡이 재생됩니다.

그리고 듣고 싶은 부분을 바에서 클릭하면 해당 부분부터 음악이 재생됩니다.

 

music.js

const allMusic = [
    {
        name : "1.음악제목",
        artist : "아티스트",
        img: "music_view01",
        audio : "music_audio01"
    }, {
        name : "2.음악제목",
        artist : "아티스트",
        img: "music_view02",
        audio : "music_audio02"
    }, {
        name : "3.음악제목",
        artist : "아티스트",
        img: "music_view03",
        audio : "music_audio03"
    }, {
        name : "4.음악제목",
        artist : "아티스트",
        img: "music_view04",
        audio : "music_audio04"
    }, {
        name : "5.음악제목",
        artist : "아티스트",
        img: "music_view05",
        audio : "music_audio05"
    }, {
        name : "6.음악제목",
        artist : "아티스트",
        img: "music_view06",
        audio : "music_audio06"
    }, {
        name : "7.음악제목",
        artist : "아티스트",
        img: "music_view07",
        audio : "music_audio07"
    }, {
        name : "8.음악제목",
        artist : "아티스트",
        img: "music_view08",
        audio : "music_audio08"
    }, {
        name : "9.음악제목",
        artist : "아티스트",
        img: "music_view09",
        audio : "music_audio09"
    }, {
        name : "10.음악제목",
        artist : "아티스트",
        img: "music_view10",
        audio : "music_audio10"
    }
];

먼저 json파일을 만들고 안에 음악 제목과 곡들을 넣은 배열을 만들어 주었습니다.

저는 제목과 아티스트를 각각 수정하고 앨범커버 이미지를 이미지 이름에 맞게 넣고 노래도 노래 이름에 맞게 수정하여 넣어주었습니다.

 

선택자

const musicWrap = document.querySelector(".music__wrap");
const musicName = musicWrap.querySelector(".music__control .title h3");
const musicArtist = musicWrap.querySelector(".music__control .title p");
const musicView = musicWrap.querySelector(".music__view .image img");
const musicAudio = musicWrap.querySelector("#main-audio");
const musicPlay = musicWrap.querySelector("#control-play");
const musicPrevBtn = musicWrap.querySelector("#control-prev");
const musicNextBtn = musicWrap.querySelector("#control-next");
const musicProgress = musicWrap.querySelector(".progress");
const musicProgressBar = musicWrap.querySelector(".progress .bar");
const musicProgressCurrent = musicWrap.querySelector(".progress .timer .currnet");
const musicProgressDuration = musicWrap.querySelector(".progress .timer .duration");

let musicIndex = 1;     //현재 음악 인덱스

배열 밑에 각각 영역의 선택자들을 만들어주었습니다.

그리고 인덱스를 첫번째 값으로 설정해주었습니다.

 

페이지 로드

window.addEventListener("load", () => {
    loadMusic(musicIndex);
});

먼저 addEventListener로 페이지 창이 로드 되었을떄 해당 인덱스 값의 노래가 로드되도록 설정해줍니다.

 

음악재생

// 음악 재생
const loadMusic = (num) => {
    musicName.innerText = allMusic[num-1].name;             //뮤직 이름
    musicArtist.innerText = allMusic[num-1].artist;         //뮤직 아티스트
    musicView.src = `img/${allMusic[num-1].img}.png`;       //뮤직 이미지
    musicView.alt = allMusic[num-1].name;                   //뮤직 이미지 alt
    musicAudio.src = `audio/${allMusic[num-1].audio}.mp3`;  //뮤직 파일
}

배열의 인덱스는 0부터 시작하므로 함수의 num 매개변수는 사용자가 선택한 음악의 인덱스보다 1 큰 값을 갖기 때문에 num값을 1빼줍니다.

기능 추가

//재생
const playMusic = () => {
    musicWrap.classList.add("paused");
    musicPlay.setAttribute("title", "정지");
    musicPlay.setAttribute("class", "stop");
    musicAudio.play();
}
//정지 
const pauseMusic = () => {
    musicWrap.classList.remove("paused");
    musicPlay.setAttribute("title", "재생");
    musicPlay.setAttribute("class", "play");
    musicAudio.pause();
}
//이전곡 듣기  
const prevMusic = () => {
    musicIndex == 1 ? musicIndex = allMusic.length : musicIndex--;
    loadMusic(musicIndex);
    playMusic();
}
//다음 곡 듣기 
const nextMusic = () => {
    musicIndex == allMusic.length ?  musicIndex == 1 : musicIndex++;

    loadMusic(musicIndex);
    playMusic();
}

 

playMusic 함수는 음악을 재생하는 함수로, musicWrap 요소에 paused 클래스를 추가하여 재생 중임을 나타내고, musicPlay 요소의 title 속성을 "정지"로, class 속성을 "stop"으로 변경합니다.

musicAudio 요소의 play 메소드를 호출하여 음악을 재생합니다.

 

PauseMusic 함수는 음악을 정지하는 함수로, musicWrap 요소에서 paused 클래스를 제거하여 재생 중이 아님을 나타내고, musicPlay 요소의 title 속성을 "재생"으로, class 속성을 "play"로 변경합니다.

musicAudio 요소의 pause 메소드를 호출하여 음악을 정지합니다.

 

prevMusic 함수는 이전 곡을 재생하는 함수로, 현재 재생 중인 곡의 인덱스 musicIndex를 1 감소시킵니다.

만약 musicIndex가 1이라면, allMusic 배열의 마지막 인덱스로 이동합니다.

loadMusic 함수를 호출하여 이전 곡을 로드하고, playMusic 함수를 호출하여 재생합니다.

 

nextMusic 함수는 다음 곡을 재생하는 함수로, 현재 재생 중인 곡의 인덱스 musicIndex를 1 증가시킵니다.

만약 musicIndexallMusic 배열의 마지막 인덱스라면, 첫 번째 곡으로 이동합니다.

loadMusic 함수를 호출하여 다음 곡을 로드하고, playMusic 함수를 호출하여 재생합니다.

 

버튼 클릭

//플레이 버튼 클릭
musicPlay.addEventListener("click", () => {
    const isMusicPaused = musicWrap.classList.contains("paused");   //음악 재생중
    isMusicPaused ? pauseMusic() : playMusic();
});
//이전곡 버튼 클릭
musicPrevBtn.addEventListener("click", () => {
    prevMusic();
});
//다음곡 버튼 클릭
musicNextBtn.addEventListener("click", () => {
    nextMusic();
});

플레이 버튼을 클릭하면 musicWrap 요소에 paused 클래스가 있는지 확인하여 음악이 일시정지 상태인지, 재생 상태인지 판별합니다.

isMusicPaused 변수가 true이면 pauseMusic 함수를 호출하여 음악을 일시정지시키고, false이면 playMusic 함수를 호출하여 음악을 재생합니다.

 

이전 곡 버튼을 클릭하면 함수를 호출하여 이전 곡으로 넘어갑니다.

다음 곡 버튼을 클릭하면 함수를 호출하여 다음 곡으로 넘어갑니다.

 

뮤직 진행 바

//뮤직 진행바
musicAudio.addEventListener("timeupdate", e => {
    console.log(e);
    const currentTime = e.target.currentTime;   //현재 재생되는 시간
    const duration = e.target.duration; //오디오 총 길이
    let progressWidth = (currentTime/duration) * 100;   //전체길이에서 현재 진행되는 시간을 백분위 단위로 나눔
    
    musicProgressBar.style.width = `${progressWidth}%`;

    //전체 시간
    musicAudio.addEventListener("loadeddata", ()=> {
        let audioDuration = musicAudio.duration;
        let totalMin = Math.floor(audioDuration / 60);
        let totalSec = Math.floor(audioDuration % 60);
        if(totalSec < 10) totalSec = `0${totalSec}`
        musicProgressDuration.innerText = `${totalMin}:${totalSec}`
    })
    //진행시간 
    let currentMin = Math.floor(currentTime / 60);
    let currentSec = Math.floor(currentTime % 60);
    if(currentSec < 10) currentSec = `0${currentSec}`
    musicProgressCurrent.innerText = `${currentMin}:${currentSec}`
});

시간이 업데이트 될 때마다 다음과 같이 실행됩니다.

 

e.target.currentTime과 e.target.duration으로 현재 재생되는 시간과 오디오 총 길이를 가져옵니다.

그리고 전체 길이에서 현재 재생 시간을 백분위 단위로 나누고, 스타일을 width값을 주어 몇 퍼센트 진행하고 있는지 나타냅니다.

 

음악 파일이 로드되어 loadeddata가 발생했을 때 musicAudio.duration로 총 재생 시간을 초 단위로 얻습니다.

이후에는 Math.floor 함수를 사용하여 분과 초 단위로 분리하고, 각각을 totalMintotalSec 변수에 할당합니다.

if문을 사용하여, totalSec가 10보다 작으면 앞에 0을 붙여서 두 자리 수로 만듭니다.

musicProgressDuration 요소에 총 재생 시간을 innerText로 화면에 출력합니다.

 

currentTime 속성을 이용하여 현재 음악 파일의 재생 위치를 초 단위로 얻습니다.

Math.floor 함수를 사용하여 분과 초 단위로 분리하고, 각각을 currentMincurrentSec 변수에 할당합니다.

if문을 사용하여, currentSec가 10보다 작으면 앞에 0을 붙여서 두 자리 수로 만듭니다.

musicProgressCurrent 요소에 현재 재생 위치를 innerText로 화면에 출력합니다.

 

//진행 버튼 클릭 
musicProgress.addEventListener("click", (e) => {
    let progressWidth = musicProgress.clientWidth;  //진행바 전체 길이
    let clickedOffsetX = e.offsetX; //진행바를 기준으로 측정되는 X좌표값
    let songDuration = musicAudio.duration; //오디오 전체 길이

    //백분위로 나눈 전체 길이를 곱해서 현재 재생값으로 바꿈
    musicAudio.currentTime = (clickedOffsetX / progressWidth) * songDuration;
    
})

musicProgress 요소를 클릭하면 이벤트 객체 e를 이용하여, 클릭된 위치의 X좌표값을 offsetX 속성으로 얻어옵니다.

musicProgress 요소의 전체 길이를 clientWidth 속성으로 얻어온 후, clickedOffsetX값을 백분위로 나누고 다시 전체의 길이를 곱하여 현재의 재생값을 구해줍니다. 그래서 음악의 재생시간을 나타내는 바에 현재 재생된다고 표시되는 곳과 다른 곳을 클릭하면 해당 부분으로 노래가 재생됩니다.