Blinking Hello Kitty Angel

javascript

gameEffect01 뮤직 플레이어 만들기

xoouxa 2023. 4. 27. 22:03

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90

안녕하세요 ヾ(≧▽≦*)o 오늘은 저번에 만든 사이트를 기반으로 뮤직플레이어를 추가해 주도록 하겠습니다 !

하나만 추가했는데도 엄청나게 많은 코드를 작성해주어서 당황 !! 했지만

내가 해냄 😏

 

저번에 했던 코드에서 html은 건들지 않고 json파일을 작업해 주었습니다 !

소스들은 마지막 git 페이지에서 확인하실 수 있습니다.

💛 완성화면입니다.

 

 

플레이 버튼을 누르시면 노래가 나옵니다 🎧🤍

json파일

const allMusic = [
    {
        name : "1. 바닷가",
        artist : "darin",
        img : "music__view001",
        audio: "music_audio01"
    },
    {
        name : "2. 바닷가",
        artist : "darin",
        img : "music__view002",
        audio: "music_audio02"
    },
    {
        name : "3. 바닷가",
        artist : "darin",
        img : "music__view003",
        audio: "music_audio03"
    },
    {
        name : "4. 바닷가",
        artist : "darin",
        img : "music__view004",
        audio: "music_audio04"
    },
    {
        name : "5. 바닷가",
        artist : "darin",
        img : "music__view005",
        audio: "music_audio05"
    },
    {
        name : "6. 바닷가",
        artist : "darin",
        img : "music__view006",
        audio: "music_audio06"
    },
    {
        name : "7. 바닷가",
        artist : "darin",
        img : "music__view007",
        audio: "music_audio07"
    },
    {
        name : "8. 바닷가",
        artist : "darin",
        img : "music__view008",
        audio: "music_audio08"
    },
    {
        name : "9. 바닷가",
        artist : "darin",
        img : "music__view009",
        audio: "music_audio09"
    },    {
        name : "10. 바닷가",
        artist : "darin",
        img : "music__view010",
        audio: "music_audio10"
    },
]

우선 10곡을 작업해 주기 위해서 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 .current");
const musicProgressduration = musicWrap.querySelector(".progress .timer .duration");



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

변수를 설정해줍니다.

let musicIndex = 는 json파일에서 지정해 준 순서입니다. let musicIndex = 1을 해주면 json파일에 설정해준 첫 번째 음악이 나오도록 해주었습니다.

음악 재생

// 음악 재생
const loadMusic = (num) => {
    musicName.innerHTML = allMusic[num-1].name;             // 재생되고 있는 음악 제목 바꾸기
    musicArtist.innerHTML = 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`   // 재생되고 있는 음악 바꾸기
};

위 변수에서 설정해준 musicName을 가져옵니다.

전체 뮤직에서 -1을 해주는 이유는 num-1은 배열의 인덱스를 나타냅니다.

일반적으로 배열의 인덱스는 0부터 시작합니다.

그러나 이 코드에서는 사용자가 입력한 인덱스 번호를 1부터 시작하도록 하였기 때문에, num-1을 해주어 배열에서 해당 음악의 정보를 가져올 수 있도록 합니다.

예를 들어, 사용자가 첫 번째 음악을 재생하고 싶어서 loadMusic(1)을 호출하면, num-1은 0이 되어 allMusic 배열에서 0번째 인덱스에 해당하는 첫 번째 음악의 정보를 가져올 수 있습니다.

이렇게 음악의 제목 , 아티스트 , 이미지, 이미지(alt) , 음악을 바꾸는 반복 작업을 해주면 됩니다.

 

재생

// 재생
const playMusic = () => {
    musicWrap.classList.add("paused");
    musicPlay.setAttribute("title", "정지");
    musicPlay.setAttribute("class", "stop");
    musicAudio.play();
};

이 코드는 음악을 재생하는 함수인 playMusic를 정의합니다.

함수 내부에서는 musicWrap 요소에 paused 클래스를 추가하고, musicPlay 요소의 title 속성과 class 속성을 변경합니다.

musicWrap은 음악을 감싸고 있는 요소를 나타내며, paused 클래스가 추가되면 재생 버튼의 아이콘 등이 변경됩니다.

musicPlay는 재생/정지 버튼을 나타내는 요소를 가리키며, setAttribute 메서드를 이용하여 버튼의 title 속성을 "정지"로, class 속성을 "stop"으로 변경합니다.

마지막으로 musicAudio 객체의 play() 메서드를 호출하여 음악을 재생합니다.

 

정지

// 정지
const pauseMusic = () => {
    musicWrap.classList.remove("paused");
    musicPlay.setAttribute("title", "재생");
    musicPlay.setAttribute("class", "play");
    musicAudio.pause();
};

 

정지 또한 재생과 같은 원리로 작동합니다.

하지만 paused를 remove 상태로 해주면 재생 버튼이 삭제되고 정지 버튼이 생성됩니다.

 

이전 곡 듣기

// 이전 곡 듣기
const prevMusic = () => {
    musicIndex == 1  ? musicIndex = allMusic.length : musicIndex--; //노래를 반복적으로 재생핳기 위한 방법 삼항연산자
    console.log(musicIndex)
    loadMusic(musicIndex);
    playMusic();
};

이 코드는 음악 재생 웹앱에서 "이전 곡 듣기" 버튼을 클릭하면 실행되는 함수인 prevMusic()을 정의합니다.

함수 내부에서는 먼저 musicIndex 변수를 사용하여 현재 재생 중인 음악의 인덱스를 나타냅니다. 이전 곡을 재생하므로, musicIndex를 1 감소시켜 이전 곡의 인덱스로 변경합니다.

다음으로, musicIndex가 1인 경우에는 현재 재생 중인 곡이 첫 번째 곡이므로, musicIndex를 allMusic 배열의 마지막 인덱스 값으로 변경합니다. 이렇게 하면 마지막 곡에서 "이전 곡 듣기"를 클릭하면 이전에 재생했던 첫 번째 곡으로 돌아갑니다.

그 다음으로는 loadMusic(musicIndex) 함수를 호출하여 musicIndex에 해당하는 음악 파일을 로드합니다. 마지막으로, playMusic() 함수를 호출하여 이전 곡을 재생합니다.

 

if 문을 이용한 방법

if (musicIndex == 1) {
  musicIndex = allMusic.length;
} else {
  musicIndex--;
}

이 방법은 반복적으로 음악을 재생할 수 있는 방법으로 삼항 연산자를 사용하여 구현됩니다.

 

다음 곡 듣기

// 다음 곡 듣기
const nextMusic = () => {
    // musicIndex++;
    // if(musicIndex == 9)  musicIndex == 1;       //노래를 반복적으로 재생핳기 위한 방법을 if문으로 사용 그 밑은 if문을 바꾼 것

    musicIndex == allMusic.length ? musicIndex = 1 : musicIndex++; //노래를 반복적으로 재생핳기 위한 방법 삼항연산자

    loadMusic(musicIndex);
    playMusic();
};

다음곡도 이전곡과 마찬가지로 반복되는 코드입니다.

삼항연산자에서 이전 곡이 아닌 다음 곡이니 ++로 작업해 주면 됩니다.

 

뮤직 바

//뮤직 진행바
musicAudio.addEventListener("timeupdate", e => {
    console.log(e)
    const currentTime = e.target.currentTime;  //재생 되는 시간
    const duration = e.target.duration;    //오디오의 총 길이
    let progressWidth = (currentTime/duration) * 100;    //전체 길이에서 현재 잔향되는 시간을 백분위 단위로 나누면 됨

    console.log(progressWidth)

    musicProgressBar.style.width = `${progressWidth}%`

다음은 노래가 흘러가는 시간에 맞춰 뮤직 바도 흘러가도록 작업해 줍니다.

 

addEventListener 함수를 사용하여 timeupdate 이벤트를 등록합니다. timeupdate 이벤트는 오디오 요소에서 재생 시간이 변경될 때마다 발생하며, 이벤트 핸들러 함수의 매개변수 e는 이벤트 객체를 나타냅니다.

 

이벤트 핸들러 함수 내부에서는 e.target.currentTime을 사용하여 현재 재생 중인 음악 파일의 재생 시간을 가져옵니다. e.target.duration을 사용하여 현재 재생 중인 음악 파일의 총 길이를 가져옵니다.

 

그 다음으로, (currentTime/duration) * 100을 계산하여 전체 길이에서 현재 재생되고 있는 시간을 백분율로 나타냅니다. 이렇게 계산된 progressWidth 값을 사용하여 프로그레스 바의 너비를 업데이트합니다.

 

마지막으로, musicProgressBar.style.width를 사용하여 프로그레스 바 요소의 너비를 설정합니다. 이때, 너비 값에는 % 단위를 포함하여 문자열로 설정합니다.

 

🐣 여기서 잠깐 target 함수란 ? !

target은 이벤트 객체에서 발생한 이벤트를 받은 요소를 나타내는 속성입니다. 즉, 이벤트 핸들러 함수를 등록한 요소를 가리킵니다.

예를 들어, addEventListener 함수를 사용하여 버튼 요소에 클릭 이벤트 핸들러 함수를 등록한 경우, 클릭 이벤트가 발생하면 이벤트 객체에는 target 속성이 포함되며, 이 속성은 클릭된 버튼 요소를 나타냅니다.

따라서, e.target을 사용하면 이벤트가 발생한 요소를 쉽게 참조할 수 있습니다. 이벤트 핸들러 함수에서 이벤트가 발생한 요소에 대한 정보가 필요한 경우에는 e.target을 사용하여 요소를 조작하거나 속성 값을 가져올 수 있습니다. 🐣

 

전체 시간 구하기

    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}`;
    });

다음은 노래 길이의 전체 시간을 구하는 함수입니다.

 

addEventListener 함수를 사용하여 loadeddata 이벤트를 등록합니다. loadeddata 이벤트는 오디오 요소가 재생 준비를 마치고, 오디오의 메타데이터가 로드되면 발생합니다.

이벤트 핸들러 함수 내부에서는 musicAudio.duration을 사용하여 오디오 요소에서 재생할 음악 파일의 총 길이를 가져옵니다. Math.floor 함수를 사용하여 총 재생 시간을 분과 초로 변환합니다.

totalMin 변수는 audioDuration / 60을 계산하여 총 재생 시간에서 분을 계산합니다. totalSec 변수는 audioDuration % 60을 계산하여 총 재생 시간에서 초를 계산합니다.

이후, if(totalSec < 10) totalSec = 0${totalSec}; 구문을 사용하여 totalSec가 10보다 작을 경우 0을 추가하여 표시하도록 합니다.

마지막으로, musicProgressduration.innerText를 사용하여 HTML 요소의 텍스트 내용을 설정합니다. 이때, 재생 시간을 분과 초로 표시하도록 문자열을 조합하여 설정합니다.

 

🐣 여기서 잠깐 ! Math.floor란 ?

Math.floor() 함수는 주어진 숫자보다 작거나 같은 가장 큰 정수를 반환하는 JavaScript의 내장 함수입니다. 즉, 소수점 이하를 모두 버린 다음 남은 정수 값을 반환합니다. 🐣

 

진행 시간 구하기

    let currentMin = Math.floor(currentTime / 60); 
    let currentSec = Math.floor(currentTime % 60); 
    if(currentSec < 10) currentSec = `0${currentSec}`;
    musicProgressCurrent.innerText = `${currentMin}:${currentSec}`;
});

현재 재생 중인 음악 파일의 재생 시간을 계산하여, 분과 초 단위로 표시하는 기능을 구현합니다.

currentTime 변수에는 e.target.currentTime을 통해 음악 파일의 현재 재생 시간을 가져옵니다. Math.floor 함수를 사용하여 분과 초를 계산합니다.

currentMin 변수는 currentTime / 60을 계산하여 현재 재생 시간에서 분을 계산합니다. currentSec 변수는 currentTime % 60을 계산하여 현재 재생 시간에서 초를 계산합니다.

그리고 if(currentSec < 10) currentSec = 0${currentSec}; 구문을 사용하여 currentSec가 10보다 작을 경우 0을 추가하여 표시하도록 합니다.

마지막으로, 현재 재생 시간을 분과 초로 표시하도록 문자열을 조합하여 HTML 요소의 텍스트 내용을 설정합니다. 이때, musicProgresscurrent.innerText를 사용하여 HTML 요소의 텍스트 내용을 설정합니다.

 

음악 플레이어의 진행 바를 클릭하여 특정 위치에서 음악을 재생할 수 있는 기능

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

    //백분위로 나눈 숫자에 다시 전체 길이를 곱해 현재 재생값으로 바꿈
    musicAudio.currentTime = (clickOffsetX /progressWidth) * songDuration;

    console.log(songDuration)
});

musicProgress 요소에 클릭 이벤트 리스너를 등록합니다. 클릭 이벤트가 발생하면, 콜백 함수가 실행됩니다.

콜백 함수에서는 musicProgress 요소의 전체 길이인 progressWidth 값을 계산합니다. 그리고 클릭한 위치를 나타내는 e.offsetX 값을 가져옵니다. 마지막으로 musicAudio.duration을 사용하여 오디오 파일의 전체 길이를 가져옵니다.

이제 클릭한 위치를 기준으로 음악을 재생할 위치를 계산합니다. 먼저, 클릭한 위치를 진행 바 전체 길이로 나누어 백분율 값을 계산합니다. 그리고 이 값을 오디오 파일의 전체 길이로 곱하여, 현재 재생할 위치를 계산합니다.

마지막으로, musicAudio.currentTime을 사용하여, 계산한 현재 재생 위치로 음악 파일의 재생 위치를 변경합니다. 즉, 클릭한 위치에서부터 음악 파일이 재생되도록 설정합니다.

 

플레이 버튼 클릭

musicPlay.addEventListener("click", () => {
    const isMusicPaused = musicWrap.classList.contains("paused");   // 음악 재생중
    isMusicPaused ? pauseMusic() : playMusic();   //toggle 사용
});

musicPlay 요소에 클릭 이벤트 리스너를 등록합니다. 클릭 이벤트가 발생하면, 콜백 함수가 실행됩니다.

콜백 함수에서는 musicWrap 요소가 paused 클래스를 포함하고 있는지 확인합니다. paused 클래스가 포함되어 있다면, 음악이 현재 일시 중지된 상태이므로 pauseMusic() 함수를 호출하여 음악을 다시 재생합니다. paused 클래스가 포함되어 있지 않다면, 음악이 현재 재생 중이므로 playMusic() 함수를 호출하여 음악을 일시 중지합니다.

따라서, 클릭할 때마다 음악을 재생하거나 일시 중지할 수 있게 됩니다. 이러한 동작을 토글(toggle)이라고 합니다.

 

🐣 여기서 잠깐 ! toggle 이란 ?!

toggle은 하나의 상태를 번갈아가며 전환하는 것을 의미합니다. 보통 UI 요소의 활성화/비활성화 상태나, 스위치 등의 on/off 상태를 전환하는 데 사용됩니다.

JavaScript에서는 classList 객체의 toggle() 메서드를 사용하여 요소의 클래스를 토글할 수 있습니다. toggle() 메서드는 요소가 클래스를 가지고 있다면 해당 클래스를 제거하고, 가지고 있지 않다면 클래스를 추가합니다. 이를 통해 요소의 클래스를 번갈아가며 전환할 수 있습니다. 🐣

 

// 이전 곡 버튼 클릭
musicPrevBtn.addEventListener("click", () => {
    prevMusic();
});


// 다음 곡 버튼 클릭
musicNextBtn.addEventListener("click", () => {
    nextMusic();
});


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

마지막 요소들까지 추가해 주시면 처음과 같은 완성화면이 나오게 됩니다 🥰🥰

 

 

 

깃허브 주소입니다 !

https://leeyouna21.github.io/web2023/javascript/game/gameEffect01.html

 

GAME EFFECT

Wish You Were Gay Billie Eilish 0:00 2:50

leeyouna21.github.io

 

🥰 오늘도 감사합니당 !