React Hooks로 피아노 만들기

이 기사에서는 react 고리가 있는 피아노를 만드는 방법을 살펴보겠습니다. React Hooks로 피아노 만들기. 반응 후크를 완전히 처음 사용하는 경우 이course를 확인하십시오.

최근 기사,



TypeScript for React developers in 2020

Building Real time API using graphql subscriptions

더 진행하기 전에 데모를 볼 것입니다.



피아노를 만들 때 고려해야 할 사항은,
  • 랩톱 키를 피아노 음표에 매핑하는 방법.
  • 키 누름으로 오디오를 매핑합니다.
  • 반응에서 피아노 키보드를 렌더링하는 방법입니다.

  • 하나씩 분해해보도록 하겠습니다. 먼저 버튼 클릭으로 오디오를 추가하여 애플리케이션에 반응하는 방법을 살펴보겠습니다.

    우리는 반응 애플리케이션의 오디오에 sound font player이라는 라이브러리를 사용할 것입니다.

    npx create-react-app piano-hooks
    npm i soundfont-player

    완료되면 오디오 플레이어 및 오디오 컨텍스트에 대해 다음 코드를 추가합니다.



    오디오 컨텍스트에는 컨텍스트가 있고 오디오 플레이어에는 setInstrument 및 playNote라는 두 가지 메서드가 있습니다.

    import SoundFontPlayer from "soundfont-player";
    import AudioContext from "./AudioContext";
    
    const NullSoundFontPlayerNoteAudio = {
      stop() {}
    };
    
    const NullSoundFontPlayer = {
      play() {
        return NullSoundFontPlayerNoteAudio;
      }
    };
    const AudioPlayer = () => {
      //Audio Context
      const audioContext = AudioContext && new AudioContext();
    
      //soundPlayer
      let soundPlayer = NullSoundFontPlayer;
      //setInstrument
      const Player = {
        setInstrument(instrumentName) {
          SoundFontPlayer.instrument(audioContext, instrumentName)
            .then(soundfontPlayer => {
              soundPlayer = soundfontPlayer;
            })
            .catch(e => {
              soundPlayer = NullSoundFontPlayer;
            });
        },
        playNote(note) {
          soundPlayer.play(note);
        }
      };
      return Player;
    };
    
    export default AudioPlayer;

    AudioContext.js에는 다음이 포함됩니다.

    export default window.AudioContext;

    그런 다음 제대로 작동하는지 테스트하고 App.js에 다음 코드를 추가하십시오.

    import React, { useEffect } from "react";
    import "./App.css";
    import AudioPlayer from "./core/AudioPlayer";
    function App() {
      const audioPlayer = AudioPlayer();
    
      useEffect(() => {
        audioPlayer.setInstrument("acoustic_grand_piano");
      }, []);
    
      const handleClick = () => {
        audioPlayer.playNote("C4");
      };
    
      return (
        <div className="app-container">
          <button onClick={handleClick}>Play</button>
        </div>
      );
    }
    
    export default App;
    

    기본적으로 클릭하면 음을 재생하는 버튼이 있습니다. 여기에서 useEffect는 모든 구성 요소 마운트에서 실행되고 계측기를 이름으로 설정합니다.



    키보드 - 렌더 소품



    악기에서 렌더 소품 개념을 사용해 봅시다. 렌더 소품에 익숙하지 않은 경우 이 course를 확인하십시오.

    주로 Instrument에는 두 가지 중요한 부분이 있습니다. Instrument 자체와 instrumentAudio입니다.

    먼저 instrumentAudio를 설정하는 방법을 살펴보겠습니다. app.js 로직을 instrumentAudio로 옮길 것입니다.

    InstrumentAudio.js 파일을 만들고 다음 코드를 추가합니다.

    import React, { useEffect, useState } from "react";
    import AudioPlayer from "./AudioPlayer";
    
    const InstrumentAudio = ({ instrumentName, notes }) => {
      const [instrumentPlayer, setInstrumentPlayer] = useState(null);
      useEffect(() => {
        setInstrumentPlayer(AudioPlayer());
      }, []);
    
      useEffect(() => {
        if (instrumentPlayer) {
          setInstrument();
          playNotes();
        }
      }, [instrumentPlayer]);
    
      useEffect(() => {
        if (notes && notes.length > 0) {
          playNotes();
        }
      }, [notes]);
    
      const setInstrument = () => {
        instrumentPlayer.setInstrument(instrumentName);
      };
    
      const playNotes = () => {
        if (instrumentPlayer) {
          instrumentPlayer.playNote(notes[0]);
        }
      };
    
      return null;
    };
    
    export default InstrumentAudio;

    여기에서 우리는 instrumentPlayer를 상태로 유지하고 있으므로 제어할 수 있습니다.

    구성 요소가 먼저 마운트되면 setInstrument 메서드를 호출하여 이름으로 기기를 설정합니다.

    그 후 notes props가 변경될 때마다 notes 종속성을 갖는 useEffect에 정의된 음을 재생합니다.

    이제 Instrument 자체를 구현할 차례입니다. 악기는 소품으로 시작 음과 끝 음이 있습니다. 이를 기반으로 사이에 있는 모든 노트를 렌더링합니다.

    import React, { Fragment } from "react";
    import InstrumentAudio from "./Keyboard/InstrumentAudio";
    import getNotesBetween from "./utils/getNotesBetween";
    
    const Instrument = ({ instrumentName, startNote, endNote }) => {
      const notes = getNotesBetween(startNote, endNote);
      return (
        <Fragment>
          {notes.map(note => {
            return <Fragment>Note is : {note}</Fragment>;
          })}
          <InstrumentAudio />
        </Fragment>
      );
    };
    
    export default Instrument;

    여기에서 시작 음표와 끝 음표 사이의 모든 음표를 얻습니다. notes.js라는 파일을 만들고 다음 코드를 추가합니다.

    const TONES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
    const OCTAVE_NUMBERS = [1, 2, 3, 4, 5, 6, 7];
    
    export default OCTAVE_NUMBERS.reduce((notes, octaveNumber) => {
      const notesInOctave = TONES.map(tone => `${tone}${octaveNumber}`);
      return [...notes, ...notesInOctave];
    }, []);

    그런 다음 getNotesBetween.js 파일을 만들어 시작 노트와 끝 노트 사이의 모든 노트를 가져옵니다.

    import NOTES from "../constants/note";
    
    export default function getNotesBetween(startNote, endNote) {
      const startingIndex = NOTES.indexOf(startNote);
      const endingIndex = NOTES.indexOf(endNote);
      return NOTES.slice(startingIndex, endingIndex + 1);
    }

    이제 Instrument.js에 악기와 상태 노트를 추가할 시간입니다.

    import React, { Fragment, useState } from "react";
    import InstrumentAudio from "./Keyboard/InstrumentAudio";
    import getNotesBetween from "./utils/getNotesBetween";
    import isAccidentalNote from "./utils/isAccidentalNote";
    
    const Instrument = ({
      instrumentName,
      startNote,
      endNote,
      renderPianoKey,
      keyboardMap
    }) => {
      const notes = getNotesBetween(startNote, endNote);
    
      const [state, setState] = useState({
        notesPlaying: []
      });
    
      const onPlayNoteStart = note => {
        setState({ ...state, notesPlaying: [...state.notesPlaying, note] });
      };
    
      const onPlayNoteEnd = note => {
        setState({
          ...state,
          notesPlaying: state.notesPlaying.filter(
            notePlaying => notePlaying !== note
          )
        });
      };
    
      return (
        <Fragment>
          {notes.map(note => {
            return (
              <Fragment key={note}>
                {renderPianoKey({
                  note,
                  isAccidentalNote: isAccidentalNote(note),
                  isNotePlaying: state.notesPlaying.includes(note),
                  startPlayingNote: () => onPlayNoteStart(note),
                  stopPlayingNote: () => onPlayNoteEnd(note),
                  keyboardShortcut: getKeyboardShortcutsForNote(keyboardMap, note)
                })}
              </Fragment>
            );
          })}
          <InstrumentAudio
            instrumentName={instrumentName}
            notes={state.notesPlaying}
          />
        </Fragment>
      );
    };
    
    export default Instrument;

    여기서 논리는 renderPianoKey는 Instrument Component의 상태를 가진 렌더링 소품입니다.

    isAccidentalNote는 메모가 자연 키인지 또는 accidental 키인지 확인합니다.

    isAccidentalNote.js

    import NOTES from '../constants/note'
    export default (note) => {
        return NOTES.includes(note) && note.includes('#')
    }

    isNotePlaying은 음표가 음표를 연주하는 상태인지 여부를 확인합니다.

    사용자가 버튼을 클릭하면 startPlayingNote 메서드가 호출되고 호출되면 특정 메모를 상태에 추가합니다.

    stopPlayingNote에서 상태에서 메모를 제거합니다.

    마지막으로 키보드 동작을 처리하기 위해 keydown 및 keyup과 같은 키보드 동작을 추가합니다.

     useEffect(() => {
        window.addEventListener("keydown", handleKeyDown);
        window.addEventListener("keyup", handleKeyUp);
      }, []);
    
    const handleKeyDown = e => {
        if (isRegularKey(e) && !e.repeat) {
          const note = getNoteFromKeyboardKey(e.key);
          if (note) {
            setState({ ...state, notesPlaying: [...state.notesPlaying, note] });
          }
        }
      };
    
      const handleKeyUp = e => {
        if (isRegularKey(e) && !e.repeat) {
          const note = getNoteFromKeyboardKey(e.key);
          if (note) {
            setState({
              ...state,
              notesPlaying: state.notesPlaying.filter(
                notePlaying => notePlaying !== note
              )
            });
          }
        }
      };

    피아노



    악기는 렌더링 소품을 사용하기 때문입니다. Piano.js 파일에서 악기 구성 요소를 전달해야 합니다.

    여기에는 해당 메서드에서 모든 인수를 가져오는 renderPianoKey 함수가 있습니다. 우발적인 메모인 경우 우발적인 키 구성 요소를 렌더링합니다.

    자연 키 노트인 경우 자연 키 구성 요소를 렌더링합니다. 또한 각 키가 피아노 음표와 매핑되는 키보드 맵을 제공해야 합니다.

    완전한 소스code

    Demo

    좋은 웹페이지 즐겨찾기