- Sound LABμ μνμλ₯Ό μΉμ©μΌλ‘ μ μν μ곑 μλΉμ€μ λλ€.
- κ°λ¨ν μ‘°μλ²μΌλ‘ μμ½κ² μ곑ν μ μλλ‘ μ μλμμ΅λλ€.
- Sound LAB π§
- Contents
- Motivation
- μμ κΈ°κ°
- Git Work Flow
- λ°°ν¬
- λν 리μΌ
- μ£ΌμκΈ°λ₯
- Usage
- κΈ°μ μ€ν
- κΈ°μ μ μ±λ¦°μ§
- νλ‘μ νΈλ₯Ό λ§μΉλ©΄μ
Sound LABμ μ곑 μλΉμ€μ λλ€. κ³Όκ±°μ μ°Έμ¬νλ ν νλ‘μ νΈμμ WebRTCλ₯Ό μ΄μ©νμ¬ μλΉμ€λ₯Ό ꡬννμμ΅λλ€. νλ‘μ νΈλ₯Ό νλ©΄μ Web APIμ λν΄ μμ°μ€λ½κ² ν₯λ―Έκ° μκ²Όκ³ λ€μν Web APIμ λμ ν΄λ³΄κ³ μΆμμ΅λλ€. νμ μμ μ μ¦κ²¨λ£κ³ λμ μμ κ΄μ¬μ΄ μμ΄ μ€λμ€μ κ΄λ ¨λ Web APIλ₯Ό μ‘°μ¬ν΄λ³΄λ€ Web Audio APIλ₯Ό μ΄μ©ν μ¬μ΄λλ©μ ꡬμνκ² λμμ΅λλ€.
-
κΈ°ν λ° λμμΈ μμ
-
κ°λ° λ° λ°°ν¬
- κΈ°λ₯ ꡬν
- νΌλλ°± λ°μ λ° λ¬Έμ μμ±
- κΈ°λ₯λ³λ‘ feature λΈλμΉ μμ± ν κ°λ°
- λ¨μ κΈ°λ₯ μλ£ ν master λΈλμΉλ‘ λ³ν©
-
Netlify
-
AWS Elastic BeanStalk
-
λ©μΈ νμ΄μ§μμ 곑 νμ΄νμ μ λ ₯ν©λλ€.
-
μ곑 νμ΄μ§λ‘ νλ©΄μ΄ μ΄λν©λλ€.
-
μν νμΌμ΄ μ 곡λκ³ μ¬μν΄ νμΈν μ μμ΅λλ€.
-
νΈλ μΆκ°λ₯Ό ν΄λ¦ν ν μ κΈ°λ₯Ό μ νν©λλ€.
νΈλ μΆκ° μ μ νν μ κΈ°μ λ°λΌ νλ©΄ νλ¨μ 곑μ νΈμ§ν μ μλ μνμκ° μΈν λ©λλ€. λμμ νΈλ 리μ€νΈμ μ νν μ κΈ°μ νΈλμ΄ μΆκ°λ©λλ€.
-
νλ©΄ νλ¨ μνμ λΈλμ ν΄λ¦νλ©΄μ 곑μ νΈμ§ν©λλ€.
-
곑μ μ μ₯ν ν URLμ ν΅ν΄ 곡μ ν μ μμ΅λλ€.
-
32λ°μμ μνμ λΈλμ΄ 16λ§λ μ© AννΈ BννΈ λλ μ νλ©΄μ μΈν λ©λλ€.
-
κ° λ°μμ ν΄λΉνλ μνμ λΈλμ ν΄λ¦νλ©΄ ν΄λΉ λ§λμ μλ¦¬κ° μ λ ₯λ©λλ€.
-
κ° ννΈμ ν΄λΉνλ λ³κ²½ μ¬νμ΄ νλ©΄ μλ¨ μ 보μ λ°μλ©λλ€.
-
μ¬μνλ λμμλ νΈμ§μ΄ κ°λ₯ν©λλ€.
-
νΈλμ΄ μμ°¨μ μΌλ‘ νΈλ 리μ€νΈμ μΆκ°λ©λλ€.
-
νΈλλ³ μμ , μμκ±°λ₯Ό ν μ μμ΅λλ€.
-
νΈμ§μ μνλ νΈλμ ν΄λ¦νλ©΄ νλ©΄ νλ¨ μνμκ° νΈλμ λ§λ μ κΈ°λ‘ λ³κ²½λ©λλ€.
-
BPM μ‘°μ κΈ°λ₯
νλ©΄ μλ¨μ μλ bpm μ‘°μ μΉΈμμ μνλ μλλ₯Ό μ λ ₯νλ©΄ μ¬μ μλλ₯Ό λ³κ²½ν μ μμ΅λλ€. μ΅λ 240 μ΅μ 40 bpmμ λλ€.
-
URL 곡μ κΈ°λ₯
곑μ μ μ₯νμ κ²½μ° URLμ ν΅ν΄ 곑 νΈμ§ νμ΄μ§λ‘ μ κ·Ό κ°λ₯ν©λλ€.
-
Requirements
-
μ΅μ λ²μ μ Chrome Browser μ¬μ©μ κΆμ₯ν©λλ€.
-
Localμμ μ€ννκΈ° μν΄ μ¬μ μ€λΉκ° νμν©λλ€.
-
-
Installation
Root λλ ν 리μ .env νμΌμ μμ±νκ³ , λ€μ νκ²½λ³μλ₯Ό μ λ ₯νκ³ μ€νν©λλ€.
-
Front-end
REACT_APP_SOUND_LAB_PUBLIC_URL=https://api.soundlab.agency/
$ git clone https://github.com/sound-Lab/sound-Lab-client.git $ cd sound-Lab-client $ npm install $ npm start
-
Back-end
MONGO_DB_URL>
$ git clone https://github.com/sound-Lab/sound-Lab-server.git $ cd sound-Lab-server $ npm install $ npm run dev
-
-
React β Redux Saga β Tone.js β Styled-components
-
Node.js β Express β MongoDB Atlas & Mongoose
-
-
React
μ μ μ 곑 νΈμ§ κ·Έλ¦¬κ³ μ¬μλ¨μ λ°λΌ λΉλ²νκ² μΌμ΄λλ λ³νλ₯Ό ν¨κ³Όμ μΌλ‘ λ λλ§νκΈ° μν΄ Reactλ₯Ό μ¬μ©νμ΅λλ€.
-
Redux Saga
곑 νΈμ§μ λ°λΌ λΉλ²νκ² μΌμ΄λλ νΈλ μν λ³νλ₯Ό 곡μ νκ³ μλ μ»΄ν¬λνΈκ° λ€μ μ‘΄μ¬νκΈ°μ μ μ μν κ΄λ¦¬μ νμμ±μ λκΌκ³ Reduxλ₯Ό λμ νμ΅λλ€.
React μ»΄ν¬λνΈμ λΉλκΈ° μμ² λ‘μ§μ κ΄μ¬μ¬ λΆλ¦¬λ₯Ό μν΄ Middlewareλ‘ Redux-sagaλ₯Ό λμ νμμ΅λλ€. sagaλ₯Ό μ νν μ΄μ λ μ§μ μ₯λ²½μ΄ λμ§λ§ Generator ν¨μλ₯Ό μ΄μ©ν΄ μ‘μ μ μμνκ² μ μ§ν μ μλ€λ μ κ·Έλ¦¬κ³ λΉλκΈ° μμ²μ λκΈ°μ μΌλ‘ μμ±ν μ μλ€λ μ μμ μ ννκ² λμμ΅λλ€.
-
Tone.js VS P5.js
μ€λμ€μ κ΄λ ¨λ κΈ°λ₯μ ν¨μ¨μ μΌλ‘ ꡬννκΈ° μν΄ Web audio APIμ κ΄λ ¨λ νλ μμν¬ νΉμ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ νν΄μΌνμ΅λλ€.
-
Tone.jsλ μμ μ μμ μν νλ μμν¬λ‘ Web audio APIλ₯Ό κΈ°λ°μΌλ‘ λ§λ€μ΄μ‘μ΅λλ€. κΈ°λ₯ ꡬνμ κ΄λ ¨λ λ€μν λ©μλμ μλ£λ₯Ό μ 곡ν©λλ€.
-
P5.jsλ Canvas APIλ₯Ό μμ½κ² μ¬μ©ν μ μλ λΌμ΄λΈλ¬λ¦¬λ‘ HTML μ€λμ€ μμλ₯Ό μ¬μ©ν μ μμ΅λλ€. μ€λμ€ κ΄λ ¨ λ©μλλ₯Ό μ 곡νμ§λ§ μ£Όλ κΈ°λ₯μ΄ μλλ©° μ€λμ€ μκ°νμ νΉνλμ΄ μμ΅λλ€.
λ κ°μ νλ μμν¬λ₯Ό λΉκ΅νμ λ Tone.jsκ° νλ‘λ©νΈ λͺ©μ μ λΆν©νλ€κ³ νλ¨νμ¬ μ ννμ΅λλ€.
-
-
-
λ€μν μ κΈ°μ μλ¦¬κ° κ°κ°μ μμ λ΄λ©΄μ μ¬μλ μ μλλ‘ μλμ κ°μ ννλ‘ νΈλμ ꡬμ±νμ΅λλ€.
-
μμ νΈλ
νλμ μμ κ°μ²΄λ tracks λ°°μ΄λ‘ ꡬμ±λμ΄ μκ³ , κ° νΈλμ λ§λ λ°°μ΄κ³Ό μ€ν λ°°μ΄ κ·Έλ¦¬κ³ μ νλ μ κΈ°μ μ½λ μ λ³΄κ° λ€μ΄μμ΅λλ€.
νΈλ ꡬ쑰λ₯Ό ꡬννκΈ° μν΄ design pattern μ€ factory patternμ νμ©νμ¬ νΈλ κ°μ²΄ μμ± νκ²½μ λ¨μννμ΅λλ€.
- factory ν¨ν΄μ μ΄μ©ν΄ TracksFactory νμ±
- νΈλ μΆκ° μ ν΄λΉ TracksFactoryλ₯Ό μ΄μ©ν΄ νΈλμ νμν steps νμ±
νΈλ μμ± μ½λ
function Tracks(tracks) { this.codeName = tracks.codeName; this.bars = tracks.bars || Array(16).fill(0); this.steps = tracks.steps || tracks.codes.map((code) => ({ name: code, step: Array(64).fill(0), })); } function TracksFactory() {} TracksFactory.prototype.tracksClass = Tracks; TracksFactory.prototype.createSteps = function (tracks) { return new this.tracksClass(tracks); }; const stepsFactory = new TracksFactory(); const tracks = stepsFactory.createSteps({ type: instrument[0].name, codes, });
μμ κ°μ κ΅¬μ‘°λ‘ νΈλ κ°μ²΄ μμ± νκ²½μ λ¨μΆν μ μμμ΅λλ€. μ νλλ μ κΈ°μ λ°λΌ λ€λ₯Έ νκ²½μ μ κ³΅ν΄ νλμ μμ±μλ‘ λ€μν νΈλ ꡬ쑰λ₯Ό νμ±ν μ μμμ΅λλ€.
-
μμ progress bar ꡬμ±
μ¬μ μκ°μ μκ°ννκΈ° μν΄ μ¬μμ€μΈ μ€νμ indexλ₯Ό λΉμ¨ μΉννμ¬ μ¬μ©νμ΅λλ€.
- μ μ κ° μ λ ₯ν bpmμ 60μ΄λ₯Ό λλ ν κ·Έ κ°μ 16λ§λλ₯Ό κ³±ν΄ progress bar timeμ μ°μΆνμ΅λλ€.
- ProgressBar componentμ propsλ‘ μ°μΆν΄λΈ κ°μ λ΄λ €μ£Όμμ΅λλ€.
- styled-componentsμ νΉμ§ μ€ propsλ₯Ό μ΄μ©ν μ μλ μ μ μ΄μ©νμ¬ κ±΄λ΄λ°μ κ°μ μ΄μ©νμ¬ μ¬μ μκ°μ μκ°ννμμ΅λλ€.
Progress bar μκ°ν μ½λ
const ProgressBar = styled.div` animation: ${(props) => `progressAnimationStrike ${props.time}s linear`}; animation-iteration-count: infinite; @keyframes progressAnimationStrike { from { width: 0; } to { width: 100%; } } `;
μμ κ°μ κ΅¬μ‘°λ‘ λ³λμ λ°μ΄ν° ꡬνμμ΄ μ¬μ μκ°μ μκ°νν μ μμμ΅λλ€.
-
-
-
λ¬Έμ
μλ‘κ³ μΉ¨κ³Ό URL μ κ·Όμ λμνκΈ° μν΄ κ³‘ μ μ₯ κΈ°λ₯μ κΈ°ννμ΅λλ€. μ΄κΈ° κΈ°ν λ¨κ³μ νΈλμ μΆκ°ν λλ§λ€ μ νν μ κΈ°μ λ°λΌ ν΄λΉ μ κΈ° sample κ°μ²΄λ₯Ό λ‘λν ν 리λμ€μ 보κ΄, μ μ₯ μ μ κΈ° sample κ°μ²΄μ ν¨κ» λ°μ΄ν° λ² μ΄μ€μ μ μ₯νλ λ°©μμ ꡬμνμ΅λλ€. νμ§λ§ ꡬν λ¨κ³μμ μ κΈ° μμ sample κ°μ²΄κ° λ°μ΄ν°λ² μ΄μ€μ μ μ₯λμ§ μλ λ¬Έμ κ° λ°μνμ΅λλ€.
-
μμΈ
Tone.jsλ₯Ό μ΄μ©ν΄ λ‘λν μμ sample κ°μ²΄λ Audio context ννλ‘ λ³νλμ΄ λΈλΌμ°μ μμ μ¬μ©λμκ³ λ°μ΄ν° λ² μ΄μ€μ μ μ₯ν μ μμμ΅λλ€. κ·Έλ κΈ° λλ¬Έμ 곑 νΈμ§ νλ©΄μ μ§μ νμ λ Audio contextλ₯Ό μλ‘κ² νμ±ν΄μΌ νμ΅λλ€.
-
ν΄κ²° λ°©λ²
κΈ°μ‘΄μ κΈ°ννμλ λ°©μ(νΈλ μ νμ sampleκ°μ²΄ λ‘λ)μ΄ μλ νλ©΄μ μ§μ νμ λ λͺ¨λ sample κ°μ²΄λ₯Ό λ‘λ ν 리λμ€ μνλ‘ μ μ₯. νΈλ μΆκ° μ μ νλ μ κΈ°μ λ°λΌ μ μ₯λ μμ sample κ°μ²΄λ₯Ό 리λμ€μμ κ°μ Έμ μ¬μ©νλ λ°©μμΌλ‘ ꡬ쑰λ₯Ό λ³κ²½νμ΅λλ€.
μλν ꡬ쑰 λ³κ²½μ μλμ κ°μ΅λλ€.
- 곑 μ μ₯ μ μμ sample κ°μ²΄ μ μΈ, νΈμ§λ λ§λ μ λ³΄λ§ λ°μ΄ν° λ² μ΄μ€μ μ μ₯.
- κΈ°μ‘΄μ νΈλμ μΆκ°ν λλ§λ€ μ νλ μ κΈ° μμ sample κ°μ²΄λ₯Ό λ‘λνλ ꡬ쑰μμ 곑 νΈμ§ νλ©΄μ μ§μ νμ λ λͺ¨λ μ κΈ° sample κ°μ²΄λ₯Ό λ‘λνμ¬ Audio contextλ‘ λ³ννλ κ΅¬μ‘°λ‘ λ³κ²½.
-
κ²°κ³Ό
μμ κ°μ λ³κ²½μΌλ‘ 곑 νΈμ§ νλ©΄μ μ§μ νμ λ λ‘λ©μ 1μ΄ μ λμ μκ°μ΄ μμλμμΌλ κΈ°μ‘΄μ νΈλμ μΆκ°ν λλ§λ€ μ κΈ° μμ sample κ°μ²΄λ₯Ό λ‘λνκΈ° μν΄ μμλλ μκ°μ μ κ°ν μ μμκ³ URLμ ν΅ν μ κ·Ό κ·Έλ¦¬κ³ μλ‘κ³ μΉ¨μ λμν μ μκ² λμμ΅λλ€.
-
-
-
λ¬Έμ
μ΄μ ν νλ‘μ νΈ λ λΈλΌμ°μ λ³λ‘ ꡬνλμ΄μλ λ©μλκ° μμ΄ν΄ λλ²κΉ μ μ΄λ €μμ κ²ͺμλ κ²½νμ΄ μμ΄ Chrome λΈλΌμ°μ κ·Έλ¦¬κ³ Opera λΈλΌμ°μ λ₯Ό μ΄μ©ν΄ κ°λ°μ μ§ννμ΅λλ€. κ·Έλ¬λ μ€ Chrome λΈλΌμ°μ μμ μ μ₯νμλ 곑 νΈμ§ νλ©΄μ μ§μ νμ λ μ¬μλμ§ μλ λ¬Έμ κ° λ°μνμ΅λλ€.
-
μμΈ
μ¬μμ΄ λμ§ μμλ μ΄μ λ Chrome λΈλΌμ°μ μμ λΉκ΅μ μ΅κ·Όμ κ°μ ν Chrome 71 auto play policy λλ¬Έμ΄μμ΅λλ€. λ΄μ©μ μ μ μ action(ex. click, key down)μ΄ μμΌλ©΄ Audio Contextμ μνκ° suspendedλ‘ μμ±λμ΄ μλ μ¬μμ΄ λΆκ°λ₯νλ€λ κ²μ΄μμ΅λλ€.
λΉμ play button ν΄λ¦ μ΄μ Audio Contextλ₯Ό μ¬μν μ μλ μνλ‘ λ³κ²½ν΄μ£Όλ λ‘μ§μ΄ μλ€λ μ¬μ€μ νμ νμ΅λλ€.
-
ν΄κ²° λ°©λ²
λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μλμ κ°μ΄ λ³κ²½μ μ§ννμ΅λλ€.
- 곑 νΈμ§ νλ©΄μ μ μ κ° μ§μ νμ λ AudioContextμ state νμΈ.
- suspendedμΌ κ²½μ° resume μνλ‘ λ³κ²½νμ¬ play buttonμ ν΄λ¦νμλ resume μνλ‘ μ¬μ
-
κ²°κ³Ό
μμ κ°μ λ³κ²½μΌλ‘ Chrome λΈλΌμ°μ μμλ μ μ₯λ 곑μ λ°λ‘ μ¬μν μ μλλ‘ λμν μ μμμ΅λλ€. λ€μν λΈλΌμ°μ νκ²½μμ ν μ€νΈνκ³ λμν΄μΌνλ€λ μ μ λμκ²Όμ΅λλ€.
-
-
κΈ°νλΆν° κ°λ°κΉμ§ νΌμ ν΄μΌ νλ μν©μ μ€νΈλ μ€λ₯Ό λ°κ³ κ°λ° μΌμ μ΄ λλκ² μ§νλλ©΄ μ΄μ‘°ν¨μ μ λͺ» λ€κΈ°λ νμ΅λλ€. κ°μΈ νλ‘μ νΈλ₯Ό μ§ννλ©΄μ ν νλ‘μ νΈμ λ€λ₯΄κ² λͺ¨λ λ¬Έμ λ₯Ό μ€μ€λ‘ ν΄κ²°ν΄λκ°μΌ νλ€λ μ μ΄ νλ€λλ μκ³ λλ£λ€κ³Ό ν¨κ» λ¬Έμ λ₯Ό ν΄κ²°νλ©΄μ νλ ₯νλ λκ° κ·Έλ¦½κΈ°λ νμ΅λλ€. νμ§λ§ μ§λ©΄ν λ¬Έμ μ λν΄ λ€μν κ΄μ μΌλ‘ μ κ·Όν΄λ³΄λ € νλ κ²½νμ΄ κ°μΈμ μ±μ₯μ λ§μ λμμ΄ λμμ΅λλ€.
-
μ μμΌ μ€νλ¦°νΈ κΈ°κ°μ ν μ€νΈ μΌμ΄μ€λ₯Ό μμ±νμ§ λͺ»ν΄ μμ½μ΅λλ€. μ§μν΄μ μ λ, 리λμ€ λ¦¬λμ κ·Έλ¦¬κ³ E2E ν μ€νΈλ₯Ό μμ±ν΄ μμ μ μΈ μλΉμ€λ₯Ό λ§λ€ μμ μ λλ€.