[JavaScript] js로 (야매)피아노 만들기

김보나·2022년 2월 16일
0

javascript

목록 보기
5/12
post-thumbnail

개인 프로젝트가 끝난 후 약 3주 동안 자바스크립트 스터디를 진행했다.(22/1/20~2/7)
리액트를 공부하면서 자바스크립트 기본기가 부족하다고 생각했는데, 마침 바닐라 자바스크립트로 진행하는 스터디가 열렸길래 냉큼 신청했다.

자바스크립트로 여러 기능을 구현할 수 있게끔 정리해놓은 사이트를 참고하여
각자 마음에 드는걸 구현하고 내용을 공유하는식으로 진행됐다.

모두 여러개 기능을 구현하셨는데, 나는 첫주 선택한 피아노 만들기가 재밌어서 이것 저것 기능을 붙여보았다. 이런 저런 일이 겹쳐서 시간을 많이 할애하지 못해서 엄청 퀄리티있는 결과물이 나온건 아니지만, 자바스크립트에 대한 이해도를 높일 수 있었다!


1주차

배운점

  • 내가 알고있는건 React지 js가 아니였다.

html

Audio

  • 처음 사용해본 태그
  • 헤맨 이유 : 오디오 태그를 div 안에 넣어줘서 재생이 안되거나 div가 표시되지 않았음...
  • 사용법
    1. audio 안에 source를 넣어줘서 사용
    2. source는 음악파일을 불러오는 역할을 함
    3. audio안에 문장은 브라우저에서 작동 안될 때 나옴.
    4. <audio controls> 의 경우 컨트롤러 표시됨
  • 예제
    <body>
    <audio controls>
        <source src="/examples/media/sample_audio_ogg.ogg" type="audio/ogg">
        <source src="/examples/media/sample_audio_mp3.mp3" type="audio/mpeg">
        이 문장은 여러분의 브라우저가 audio 태그를 지원하지 않을 때 화면에 표시됩니다!
    </audio>
    <!-- 다른 태그들 넣어주기 -->
    <body/>
  • 내가 사용한 방식
    <body>
        <!-- 오디오 태그 삽입 -->
        <audio  id="audioContainer">
          <source id='audioSource' src=''/>
          Your browser does not support the
          <code>audio</code> element.
        </audio>

**svg**

  • 처음 본 태그 (html에 작성되어있었음)
  • 백터 기반 svg그래픽을 xml형식으로 정의하고 담기 위한 요소
  • svg안에 path를 사용하여 영역표시
  • 피아노 건반 버튼을 만드는데 사용됨

javascript

**querySelectorAll**

  • 사용 : html의 태그를 호출 할 때
  • 문제: querySelector를 사용하면 처음 작성한 것만 검색이 됨.
  • querySelectorAll을 사용하여 반환 내용을 [NodeList](https://4ngeunlee.tistory.com/188)로 만듦
  • 내 코드
    • 반환된 값을 가지고 forEach를 이용해 해당되는 모든 클래스에 addEventListener를 적용해 클릭 이벤트 적용

      const playBtn = document.querySelectorAll(".playBtn");
      playBtn.forEach(n => n.addEventListener("click", handleButtonClick));

**unshift**

  • 사용 : 클릭했던 건반의 음계들을 표시하기 위해
  • 문제 : push 사용시 뒤에 입력됨.
  • 큐와 같은 구조인 lastScales를 만들기 위해 사용함.
  • 배열에 값을 추가할 때 맨 앞에 추가하는 메소드
  • 내 코드
    • pop을 통해 맨 마지막요소부터 삭제해주었다.

      const lastScales = [];
      const updateLastScale = btnId => {
        if (lastScales.length === 4) {
          lastScales.pop();
        }
        lastScales.unshift(returnScaleName(btnId));
      return lastScales;
      };
  • shift()의 경우 맨 앞에꺼가 삭제됨

**textContent**

  • 사용 :html 태그들의 내용을 바꿀 때 사용
  • 문제 : 연주 했던 건반을 표시했을 때 innerText가 사용이 안됐음.
  • 요런 차이점 이 있고, 기존 사용하던 innerText보다 성능이 좋다길래 바꿈.
  • 내 코드
    const updateScale = btnId => {
      nowScale.textContent = returnScaleName(btnId);
    };

2주차

배운 점

  • input태그 사용하기

  • txt 파일을 string으로 변환하기

  • 텍스트 파일을 이용해 간이 악보를 만들기로 했다.
    도 레 미 도 미 도 미 레 미 파 파 와 같은 형태로 쓰여있는 텍스트 파일을 읽어 악보로 변환하고, 음계를 하나씩 표시하고, 악보의 음계와 내가 연주한 음계가 같으면 다음 음계가 표시되도록 해주었다.

input태그 사용하기

**input**

  • type을 file로 지정해주면 파일을 선택할 수 있는 창이 뜬다.
  • 이벤트가 발생하면 파일을 선택한다.
function loadFile() {
  let input = document.createElement("input");
  input.type = "file";
  input.accept = "text/plain";

  input.onchange = event => {
    processFile(event.target.files[0]);
  };
  input.click();
}

textfile을 string으로 바꾸기

**FileReader**

  • 파일 선택 후에 FileReader를 통해서 파일을 불러올 수 있다.
  • reader의 result(파일 내용)을 악보칸에 전부 넣어주었다.
  • 파일의 내용을 공백을 기준으로 잘라서 첫번째 음계를 가져올 수 있게 했다.
function processFile(file) {
  let reader = new FileReader();

  reader.onload = () => {
    preScales = reader.result.split(" ");
    score.textContent = reader.result;
    output.textContent = preScales[0];
  };

  reader.readAsText(file, "utf-8");
}
  • 음계를 판단하는 함수
function sliceScale(scale) {
  if (lastScales[0] === scale[0]) {
    scale.shift();
    if (scale.length === 0) {
      score.textContent = "";
      return "연주 완료";
    }
    return scale[0];
  }
}

3주차

배운 점

  • 모달 창 만들기
  • 키보드 이벤트
  • 점수 만들기

모달창 만들기

  • 모달창 구현은 의외로 쉬웠다. 창을 만들어 준 뒤, displaynone으로 주고 열릴 때 flex로 바꿔주는 형식으로 만들 수 있었다.
function displayModal() {
  modal.style.display = "flex";
}
function closeModal() {
  modal.style.display = "none";
}
function tapCloseModal(e) {
  const eventTarget = e.target;
  if (eventTarget.classList.contains("modal-overlay")) {
    modal.style.display = "none";
  }
}

키보드 이벤트

  • 키보드 이벤트는 keydown이라는 이벤트로 컨트롤 할 수 있었다.
  • 대부분의 키 값은 ASCII 코드를 입력하여 제어할 수 있고, 일부 특수키만 특수한 키로 처리를 해줘야한다.
  • 숫자 1부터 8까지를 낮은도 부터 높은 도 까지로 정해서 구현했다.
  • 각각의 케이스에 대해 처리해줘야해서 switch-case문으로 작성했다.
document.addEventListener("keydown", checkKeyPressed, false);

//숫자 1부터 8까지 키 할당
function checkKeyPressed(e) {
  switch (e.keyCode) {
    case 49:
      handleKeyClick("key-01");
      break;
    case 50:
      handleKeyClick("key-02");
      break;

    case 51:
      handleKeyClick("key-03");
      break;

    case 52:
      handleKeyClick("key-04");
      break;

    case 53:
      handleKeyClick("key-05");
      break;

    case 54:
      handleKeyClick("key-06");
      break;

    case 55:
      handleKeyClick("key-07");
      break;

    case 56:
      handleKeyClick("key-08");
      break;
  }
}

점수 계산하기

  • 디폴트 점수를 100점으로 두고, 100/(악보에 포함된 음계의 개수)를 해서 음계당 점수를 구했다. 틀릴 때 마다 점수를 빼주고 점수가 0보다 낮아지면 점수를 0으로 고정했다.
//악보 로드시 개당 점수를 구해줬다.
function processFile(file) {
  let reader = new FileReader();
  reader.onload = () => {
    performanceScore = 100;
    preScales = reader.result.split(" ");
    score.textContent = reader.result;
    output.textContent = preScales[0];
    deductPoints = parseInt(100 / preScales.length);
  };

  //음계를 처리하는 함수에 틀린 경우를 설정해주었다.
  function sliceScale(scale) {
  if (lastScales[0] === scale[0]) {
    scale.shift();
    if (scale.length === 0) {
      score.textContent = "";

      return `연주 완료 ${performanceScore}`;
    }
  } else {
    if (performanceScore < 0) {
      performanceScore = 0;
    }
    performanceScore = performanceScore - deductPoints;
  }
  return scale[0];
}


마치며

3주동안 진행하긴했지만, 긴 시간을 할애하지는 못하고 짬나는대로 틈틈히 진행해서 완성도가 떨어져서 아쉽다. 그렇지만 자바스크립트에 대해 많이 공부할 수 있었고, 프로젝트 때 안써본 오디오 태그, 인풋 태그 등 을 써봐서 재밌었다.

profile
우주최강 개발자가 될 때까지😈

0개의 댓글