ì´ ë¬¸ìë ë§ì°ì¤ë¥¼ ì¬ì©í´ íë ì´í ì ìë ë¹ëì¤ í¤ë³´ëì ë°ëª¨ì ì½ë를 ë³´ì¬ì¤ëë¤. ì´ í¤ë³´ëë íì¤ ííë¤ê³¼ ì¬ì©ì ì ì íí ì¤ìì ì íí ì ìë 기ë¥ì ì ê³µíê³ , í¤ë³´ë ìëì ìë 볼륨 ì¬ë¼ì´ë를 ì¬ì©íì¬ ë©ì¸ gainì ì ì´í ì ììµëë¤. ì´ ìì ë ë¤ìì Web API ì¸í°íì´ì¤ë¥¼ ì¬ì©í©ëë¤: AudioContext
, OscillatorNode
, PeriodicWave
, ê·¸ë¦¬ê³ GainNode
.
OscillatorNode
ê° AudioScheduledSourceNode
ì 기ë°í기 ë문ì, ì´ê²ì ëí ì¼ë§ê° ê·¸ê²ì ëí ìì ì´ê¸°ë í©ëë¤.
ì´ ê°ì í¤ë³´ëì ëì¤íë ì´ìë ì¸ ê°ì§ 주ìí ì»´í¬ëí¸ê° ììµëë¤. 첫ë²ì§¸ë 뮤ì§ì»¬ í¤ë³´ë ê·¸ ìì²´ì
ëë¤. ì°ë¦¬ë ì´ê²ì ì¤ì²©ë <div>
ììì ìì¼ë¡ ê·¸ë ¤ ë§ì½ 모ë ê±´ë°ì´ íë©´ì ë§ì§ ìì¼ë©´ ê·¸ê²ë¤ì´ ì¤ë°ê¿ëë ì¼ ìì´ í¤ë³´ë를 ê°ë¡ë¡ ì¤í¬ë¡¤í ì ìê² ëëë¡ ë§ë¤ ê²ì
ëë¤.
첫째ë¡, í¤ë³´ë를 ë£ì ê³µê°ì ë§ëëë¤. ì°ë¦¬ë íë¡ê·¸ëë°ì ì¼ë¡ í¤ë³´ë를 구ì±í ê²ì¸ë°, ìëíë©´ ê·¸ë ê² íë ê²ì ì°ë¦¬ìê² í´ë¹íë ìì ëí ì ì í ë°ì´í°ë¥¼ ê²°ì íë©´ì ê°ê°ì ê±´ë°ì ì¤ì íë ì ì°ì±ì 주기 ë문ì ëë¤. ì°ë¦¬ì ê²½ì°, ì°ë¦¬ë íë¡ë¶í° ê° ìì 주íì를 ì»ì§ë§, ì´ê²ì ëí ìê³ ë¦¬ì¦ì ì¼ë¡ë ê³ì°ë ì ììµëë¤.
<div class="container">
<div class="keyboard"></div>
</div>
"container"
ë¼ë ì´ë¦ì <div>
ë ë§ì½ ì´ê²ì´ ì´ì© ê°ë¥í ê³µê°ì ëí´ ë무 ëì¼ë©´ ê°ë¡ë¡ ì¤í¬ë¡¤ë ì ìë ë°ì¤ì
ëë¤. ê±´ë°ë¤ ìì²´ë "keyboard"
í´ëì¤ì ë¸ë¡ ìì¼ë¡ ì½ì
ë ê²ì
ëë¤.
í¤ë³´ë ìëì, ì°ë¦¬ë ë ì´ì´ë¥¼ ì¤ì í기 ìí ì¡°ì¢ ì¥ì¹ë¥¼ ëì ê²ì ëë¤. ì°ì ì, ì°ë¦¬ë ë ì¡°ì¢ ì¥ì¹ë¥¼ ê°ì§ê³ ììµëë¤: íëë ë©ì¸ 볼륨ì ì¤ì í기 ìí ê²ì´ê³ ëë¨¸ì§ íëë ë ¸í¸ë¥¼ ìì±í ë ì´ë¤ 주기ì ì¸ ííì ì¬ì©í ì§ ê³ ë¥´ê¸° ìí ê²ì ëë¤.
볼륨 컨í¸ë¡¤ì²«ì§¸ë¡ ì°ë¦¬ë íìí ëë¡ ì¤íì¼ë ì ìëë¡, ì¤ì ë°ë¥¼ í¬í¨íë <div>
를 ìì±í©ëë¤. ê·¸ë¦¬ê³ ëì ë°ì ì¢ì¸¡ì ëíë ë°ì¤ë¥¼ ìì±íê³ ë¼ë²¨ê³¼ "range"
ì íì <input>
ìì를 ë°°ì¹í©ëë¤. range ììë ë³´íµ ì¬ë¼ì´ëë¡ ííë©ëë¤; ê° ìì¹ë§ë¤ 0.01ë§í¼ ìì§ì´ë©° 0.0ê³¼ 1.0 ì¬ì´ì 모ë ê°ì íì©íê² ì¤ì í©ëë¤.
<div class="settingsBar">
<div class="left">
<span>Volume: </span>
<input
type="range"
min="0.0"
max="1.0"
step="0.01"
value="0.5"
list="volumes"
name="volume" />
<datalist id="volumes">
<option value="0.0" label="Mute"></option>
<option value="1.0" label="100%"></option>
</datalist>
</div>
</div>
ì°ë¦¬ë 기본ê°ì 0.5ë¡ ëª
ìíê³ , IDê° ë§ë ìµì
목ë¡ì 찾기 ìí´ name
í¹ì±ì ì¬ì©íì¬ rangeì ì°ê²°ë <datalist>
ìì를 ì ê³µí©ëë¤; ì´ ê²½ì°, ë°ì´í°ì
ì "volume"
ì´ë¼ë ì´ë¦ì
ëë¤. ì´ë ì°ë¦¬ë¡ íì¬ê¸ ë¸ë¼ì°ì ê° ìµì
ì ì¼ë¡ ì´ë¤ ë°©ìì¼ë¡ ëì¤íë ì´í기를 ì íí ì§ë 모르ë í¹ë³í 문ìì´ê³¼ ì¼ë°ì ì¸ ê°ì ì§í©ì ì ê³µíê² í©ëë¤; ì°ë¦¬ë ê° 0.0 ("무ì")ê³¼ 1.0 ("100%")ì ëí´ ì´ë¦ì ì ê³µí©ëë¤.
ì¸í
ë°ì ì°ì¸¡ì, ì°ë¦¬ë ë¼ë²¨ê³¼ ì´ì© ê°ë¥í ííì ë¶í©íë ìµì
ì ê°ì§ê³ ìë "waveform"
ë¼ë ì´ë¦ì <select>
ìì를 ë°°ì¹í©ëë¤.
<div class="right">
<span>Current waveform: </span>
<select name="waveform">
<option value="sine">Sine</option>
<option value="square" selected>Square</option>
<option value="sawtooth">Sawtooth</option>
<option value="triangle">Triangle</option>
<option value="custom">Custom</option>
</select>
</div>
</div>
.container {
overflow-x: scroll;
overflow-y: hidden;
width: 660px;
height: 110px;
white-space: nowrap;
margin: 10px;
}
.keyboard {
width: auto;
padding: 0;
margin: 0;
}
.key {
cursor: pointer;
font:
16px "Open Sans",
"Lucida Grande",
"Arial",
sans-serif;
border: 1px solid black;
border-radius: 5px;
width: 20px;
height: 80px;
text-align: center;
box-shadow: 2px 2px darkgray;
display: inline-block;
position: relative;
margin-right: 3px;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.key div {
position: absolute;
bottom: 0;
text-align: center;
width: 100%;
pointer-events: none;
}
.key div sub {
font-size: 10px;
pointer-events: none;
}
.key:hover {
background-color: #eef;
}
.key:active {
background-color: #000;
color: #fff;
}
.octave {
display: inline-block;
padding: 0 6px 0 0;
}
.settingsBar {
padding-top: 8px;
font:
14px "Open Sans",
"Lucida Grande",
"Arial",
sans-serif;
position: relative;
vertical-align: middle;
width: 100%;
height: 30px;
}
.left {
width: 50%;
position: absolute;
left: 0;
display: table-cell;
vertical-align: middle;
}
.left span,
.left input {
vertical-align: middle;
}
.right {
width: 50%;
position: absolute;
right: 0;
display: table-cell;
vertical-align: middle;
}
.right span {
vertical-align: middle;
}
.right input {
vertical-align: baseline;
}
JavaScript
JavaScript ì½ëë ëª ê°ì ë³ì를 ì´ê¸°íí¨ì¼ë¡ì¨ ììí©ëë¤.
let audioContext = new (window.AudioContext || window.webkitAudioContext)();
let oscList = [];
let mainGainNode = null;
audioContext
ë ì ì AudioContext
ê°ì²´ë¥¼ (ëë íìíë¤ë©´ webkitAudioContext
를) 참조í기 ìí´ ì¤ì ëììµëë¤.oscList
ë íì¬ ì¬ìëê³ ìë 모ë oscillator를 í¬í¨í ì¤ë¹ê° ë기 ìí´ ì¤ì ëììµëë¤. ì´ê²ì ë¹ ìíë¡ ììíëë°, ìëíë©´ ìì§ ì´ë¤ ê²ë ì¬ìëê³ ìì§ ì기 ë문ì
ëë¤.mainGainNode
ì nullë¡ ì¤ì ëììµëë¤; ì¤ì ê³¼ì ì¤ì, ì´ê²ì ì¬ìëë 모ë oscillatorê° ì°ê²°ëê³ ì¬ë¼ì´ë를 ì¬ì©í´ ì ì²´ ë³¼ë¥¨ì´ ì ì´ëëë¡ íë GainNode
를 í¬í¨íëë¡ ì¤ì ë ê²ì
ëë¤.let keyboard = document.querySelector(".keyboard");
let wavePicker = document.querySelector("select[name='waveform']");
let volumeControl = document.querySelector("input[name='volume']");
ì ê·¼ì´ íìí ììë¤ìì 참조ë ìì ê°ì´ ì»ì´ì§ëë¤:
keyboard
ë ê±´ë°ì´ ë°°ì¹ë 컨í
ì´ëì
ëë¤.wavePicker
ë ìì ëí´ ì¬ì©í ííì ì ííë ë° ì¬ì©ëë <select>
ììì
ëë¤.volumeControl
ë ë©ì¸ ì¤ëì¤ ë³¼ë¥¨ì ì ì´í기 ìí´ ì¬ì©ëë ("range"
ì íì) <input>
ììì
ëë¤.let noteFreq = null;
let customWaveform = null;
let sineTerms = null;
let cosineTerms = null;
ë§ì§ë§ì¼ë¡, ííì ìì±í ë ì¬ì©ë ì ì ë³ìë¤ì´ ìì±ë©ëë¤:
noteFreq
ë ë°°ì´ë¤ì ë°°ì´ì
ëë¤; ê° ë°°ì´ì íëì ì¥íë¸ë¥¼ ëíë´ëë°, ê·¸ ì¥íë¸ì ìë ê° ìì ëí í목ì í¬í¨í©ëë¤. ê°ê°ì ëí ê°ì ìì ììì ëíë´ë í¤ë¥´ì¸ ë¡ ííëë 주íìì
ëë¤.customWaveform
ë ì¬ì©ìê° "Custom"ì íí ì í기ìì ì ííì ë ì¬ì©í ííì 기ì íë PeriodicWave
ë¡ ì¤ì ë ê²ì
ëë¤.sineTerms
ì cosineTerms
ë ííì ìì±í기 ìí ë°ì´í°ë¥¼ ì ì¥í기 ìí´ ì¬ì©ë ê²ì
ëë¤; ê°ê°ì ì¬ì©ìê° "Custom"ì ì ííì ë ìì±ëë ë°°ì´ì í¬í¨í ê²ì
ëë¤.createNoteTable()
í¨ìë ê° ì¥íë¸ë¥¼ ëíë´ë ê°ì²´ì ë°°ì´ì í¬í¨íë noteFreq
ë°°ì´ì ë§ëëë¤. ì°¨ë¡ë¡ ê° ì¥íë¸ë ê·¸ ì¥íë¸ì ìë ê° ìì ëí íëì ì§ì ë ìì±ì ê°ì§ëë¤; ê·¸ ìì±ì ì´ë¦ì ìì ì´ë¦ì
ëë¤ (ì를 ë¤ìë©´ C-sharpë "C#"ë¡ ííë©ëë¤), ê·¸ë¦¬ê³ ê°ì í¤ë¥´ì¸ ë¡ ííëë ê·¸ ìì 주íìì
ëë¤.
function createNoteTable() {
let noteFreq = [];
for (let i=0; i< 9; i++) {
noteFreq[i] = [];
}
noteFreq[0]["A"] = 27.500000000000000;
noteFreq[0]["A#"] = 29.135235094880619;
noteFreq[0]["B"] = 30.867706328507756;
noteFreq[1]["C"] = 32.703195662574829;
noteFreq[1]["C#"] = 34.647828872109012;
noteFreq[1]["D"] = 36.708095989675945;
noteFreq[1]["D#"] = 38.890872965260113;
noteFreq[1]["E"] = 41.203444614108741;
noteFreq[1]["F"] = 43.653528929125485;
noteFreq[1]["F#"] = 46.249302838954299;
noteFreq[1]["G"] = 48.999429497718661;
noteFreq[1]["G#"] = 51.913087197493142;
noteFreq[1]["A"] = 55.000000000000000;
noteFreq[1]["A#"] = 58.270470189761239;
noteFreq[1]["B"] = 61.735412657015513;
... ê°ê²°ì±ì ìí´ ëªëª ì¥íë¸ë ìëµëììµëë¤ ...
noteFreq[2]["C"] = 65.406391325149658;
noteFreq[2]["C#"] = 69.295657744218024;
noteFreq[2]["D"] = 73.41619197935189;
noteFreq[2]["D#"] = 77.781745930520227;
noteFreq[2]["E"] = 82.406889228217482;
noteFreq[2]["F"] = 87.307057858250971;
noteFreq[2]["F#"] = 92.498605677908599;
noteFreq[2]["G"] = 97.998858995437323;
noteFreq[2]["G#"] = 103.826174394986284;
noteFreq[2]["A"] = 110.0;
noteFreq[2]["A#"] = 116.540940379522479;
noteFreq[2]["B"] = 123.470825314031027;
noteFreq[3]["C"] = 130.812782650299317;
noteFreq[3]["C#"] = 138.591315488436048;
noteFreq[3]["D"] = 146.83238395870378;
noteFreq[3]["D#"] = 155.563491861040455;
noteFreq[3]["E"] = 164.813778456434964;
noteFreq[3]["F"] = 174.614115716501942;
noteFreq[3]["F#"] = 184.997211355817199;
noteFreq[3]["G"] = 195.997717990874647;
noteFreq[3]["G#"] = 207.652348789972569;
noteFreq[3]["A"] = 220.0;
noteFreq[3]["A#"] = 233.081880759044958;
noteFreq[3]["B"] = 246.941650628062055;
noteFreq[4]["C"] = 261.625565300598634;
noteFreq[4]["C#"] = 277.182630976872096;
noteFreq[4]["D"] = 293.66476791740756;
noteFreq[4]["D#"] = 311.12698372208091;
noteFreq[4]["E"] = 329.627556912869929;
noteFreq[4]["F"] = 349.228231433003884;
noteFreq[4]["F#"] = 369.994422711634398;
noteFreq[4]["G"] = 391.995435981749294;
noteFreq[4]["G#"] = 415.304697579945138;
noteFreq[4]["A"] = 440.0;
noteFreq[4]["A#"] = 466.163761518089916;
noteFreq[4]["B"] = 493.883301256124111;
noteFreq[5]["C"] = 523.251130601197269;
noteFreq[5]["C#"] = 554.365261953744192;
noteFreq[5]["D"] = 587.32953583481512;
noteFreq[5]["D#"] = 622.253967444161821;
noteFreq[5]["E"] = 659.255113825739859;
noteFreq[5]["F"] = 698.456462866007768;
noteFreq[5]["F#"] = 739.988845423268797;
noteFreq[5]["G"] = 783.990871963498588;
noteFreq[5]["G#"] = 830.609395159890277;
noteFreq[5]["A"] = 880.0;
noteFreq[5]["A#"] = 932.327523036179832;
noteFreq[5]["B"] = 987.766602512248223;
noteFreq[6]["C"] = 1046.502261202394538;
noteFreq[6]["C#"] = 1108.730523907488384;
noteFreq[6]["D"] = 1174.659071669630241;
noteFreq[6]["D#"] = 1244.507934888323642;
noteFreq[6]["E"] = 1318.510227651479718;
noteFreq[6]["F"] = 1396.912925732015537;
noteFreq[6]["F#"] = 1479.977690846537595;
noteFreq[6]["G"] = 1567.981743926997176;
noteFreq[6]["G#"] = 1661.218790319780554;
noteFreq[6]["A"] = 1760.0;
noteFreq[6]["A#"] = 1864.655046072359665;
noteFreq[6]["B"] = 1975.533205024496447;
noteFreq[7]["C"] = 2093.004522404789077;
noteFreq[7]["C#"] = 2217.461047814976769;
noteFreq[7]["D"] = 2349.318143339260482;
noteFreq[7]["D#"] = 2489.015869776647285;
noteFreq[7]["E"] = 2637.020455302959437;
noteFreq[7]["F"] = 2793.825851464031075;
noteFreq[7]["F#"] = 2959.955381693075191;
noteFreq[7]["G"] = 3135.963487853994352;
noteFreq[7]["G#"] = 3322.437580639561108;
noteFreq[7]["A"] = 3520.000000000000000;
noteFreq[7]["A#"] = 3729.310092144719331;
noteFreq[7]["B"] = 3951.066410048992894;
noteFreq[8]["C"] = 4186.009044809578154;
return noteFreq;
}
ê²°ê³¼ë noteFreq
ë°°ì´ì¸ë°, ì´ë ê° ì¥íë¸ì ëí ê°ì²´ë¥¼ ê°ì§ê³ ììµëë¤. ê° ì¥íë¸ ê°ì²´ë ìì± ì´ë¦ì´ ìì ì´ë¦ì´ê³ (ì를 ë¤ìë©´ C-sharpë "C#"ë¡ ííë©ëë¤) ìì±ì ê°ì í¤ë¥´ì¸ ë¡ ííëë ìì 주íìì¸ ì§ì ë ìì±ë¤ì ê°ì§ê³ ììµëë¤. ë¶ë¶ì ì¼ë¡ë, ê²°ê³¼ ê°ì²´ë ë¤ìê³¼ ê°ì´ ë³´ì
ëë¤:
ì¤ë¹ë ì´ í를 ê°ì§ê³ , ì°ë¦¬ë í¹ì í ì¥íë¸ì ìë 주ì´ì§ ìì ëí 주íì를 꽤 ì½ê² ì°¾ì ì ììµëë¤. ë§ì½ ì°ë¦¬ê° ì¥íë¸ 1ì G# ìì 주íì를 ìíë¤ë©´, ì°ë¦¬ë noteFreq[1]["G#"]
ì ì¬ì©íì¬ ê²°ê³¼ë¡ 51.9ì ê°ì ì»ìµëë¤.
ì°¸ê³ : ìì ìì íì ê°ë¤ì ìì«ì ë째 ì리ê¹ì§ ë°ì¬ë¦¼ëììµëë¤.
í¤ë³´ë ë§ë¤ê¸°setup()
í¨ìì ìí ì í¤ë³´ë를 ë§ë¤ê³ ì±ì´ ìì
ì ì¬ìíëë¡ ì¤ë¹íë ê²ì
ëë¤.
function setup() {
noteFreq = createNoteTable();
volumeControl.addEventListener("change", changeVolume, false);
mainGainNode = audioContext.createGain();
mainGainNode.connect(audioContext.destination);
mainGainNode.gain.value = volumeControl.value;
// Create the keys; skip any that are sharp or flat; for
// our purposes we don't need them. Each octave is inserted
// into a <div> of class "octave".
noteFreq.forEach(function (keys, idx) {
let keyList = Object.entries(keys);
let octaveElem = document.createElement("div");
octaveElem.className = "octave";
keyList.forEach(function (key) {
if (key[0].length == 1) {
octaveElem.appendChild(createKey(key[0], idx, key[1]));
}
});
keyboard.appendChild(octaveElem);
});
document
.querySelector("div[data-note='B'][data-octave='5']")
.scrollIntoView(false);
sineTerms = new Float32Array([0, 0, 1, 0, 1]);
cosineTerms = new Float32Array(sineTerms.length);
customWaveform = audioContext.createPeriodicWave(cosineTerms, sineTerms);
for (i = 0; i < 9; i++) {
oscList[i] = {};
}
}
setup();
createNoteTable()
를 í¸ì¶í¨ì¼ë¡ì¨ ìì±ë©ëë¤.change
ì´ë²¤í¸ë¥¼ ë¤ë£¨ê¸° ìí´ addEventListener()
를 í¸ì¶í¨ì¼ë¡ì¨ ì´ë²¤í¸ í¸ë¤ë¬ê° ìì±ëììµëë¤. ì´ê²ì ë©ì¸ gain ë
¸ëì ìëì ì ì´ì ì ê°ì¼ë¡ ì
ë°ì´í¸ í©ëë¤.Object.entries()
를 ì¬ì©í©ëë¤.<div>
를 ìì±íê³ (ì´ë ê² í¨ì¼ë¡ì¨ ì°ë¦¬ë ì¥íë¸ë¤ ì¬ì´ì ì½ê°ì ê³µê°ì ê°ì§ ì ììµëë¤), ì´ê²ì í´ëì¤ëª
ì "octave"ë¡ ì¤ì í©ëë¤.createKey()
를 í¸ì¶íëë°, ì´ë ìì 문ìì´, ì¥íë¸, ê·¸ë¦¬ê³ ì£¼íì를 ëª
ìí©ëë¤. ì´ ë°íë ììë ë¨ê³ 4ìì ìì±ë ì¥íë¸ ììì ì¶ê°ë©ëë¤.AudioContext.createPeriodicWave()
를 ì¬ì©íì¬ ìì±ë©ëë¤. ì´ ííì ì¸ì ë ì§ ì¬ì©ìê° íí ì í기ìì "Custom"ì ì ííì ë ì¬ì©ë ê²ì
ëë¤.createKey()
í¨ìë ê°ì í¤ë³´ëì íìí기를 ìíë ê°ê°ì ê±´ë°ì ëí´ í ë² í¸ì¶ë©ëë¤. ì´ê²ì ê±´ë°ê³¼ ê±´ë°ì ë¼ë²¨ì¼ë¡ 구ì±ëë ìì를 ìì±íê³ , ì¶íì ì¬ì©ì ìí´ ê·¸ ììì ë°ì´í° í¹ì±ì ì¶ê°íê³ , ê·¸ë¦¬ê³ ì°ë¦¬ê° ê´ì¬ì ê°ì§ê³ ìë ì´ë²¤í¸ì ëí ì´ë²¤í¸ í¸ë¤ë¬ë¥¼ ë¶ì¬í©ëë¤.
function createKey(note, octave, freq) {
let keyElement = document.createElement("div");
let labelElement = document.createElement("div");
keyElement.className = "key";
keyElement.dataset["octave"] = octave;
keyElement.dataset["note"] = note;
keyElement.dataset["frequency"] = freq;
labelElement.innerHTML = note + "<sub>" + octave + "</sub>";
keyElement.appendChild(labelElement);
keyElement.addEventListener("mousedown", notePressed, false);
keyElement.addEventListener("mouseup", noteReleased, false);
keyElement.addEventListener("mouseover", notePressed, false);
keyElement.addEventListener("mouseleave", noteReleased, false);
return keyElement;
}
ê±´ë°ê³¼ ê±´ë°ì ë¼ë²¨ì ííí ìì를 ìì±í ì´í, ê±´ë°ì í´ëì¤ë¥¼ (ì¸ìì ì¤ì íë) "key"ë¡ ì¤ì í¨ì¼ë¡ì¨ ê±´ë°ì ìì를 ì¤ì í©ëë¤. ê·¸ë¦¬ê³ ëì ê±´ë°ì ì¥íë¸(data-octave
í¹ì±), ì¬ìí ìì íííë 문ìì´(data-note
í¹ì±), í¤ë¥´ì¸ ë¡ ííëë 주íì(data-frequency
í¹ì±)를 í¬í¨íë data-*
í¹ì±ì ì¶ê°í©ëë¤. ì´ê²ì ì°ë¦¬ë¡ íì¬ê¸ ì´ë²¤í¸ë¥¼ ë¤ë£° ë íìí ê²½ì° ì½ê² ì´ ì 보를 ê°ì ¸ì¬ ì ìëë¡ í ê²ì
ëë¤.
playTone()
í¨ìì ìí ì 주ì´ì§ 주íìì ìì ì¬ìíë ê²ì
ëë¤. ì´ê²ì ì ì í ìì ì¬ìíë í¤ë³´ë ê±´ë°ì ì´ë²¤í¸ í¸ë¤ë¬ì ìí´ ì¬ì©ë ê²ì
ëë¤.
function playTone(freq) {
let osc = audioContext.createOscillator();
osc.connect(mainGainNode);
let type = wavePicker.options[wavePicker.selectedIndex].value;
if (type == "custom") {
osc.setPeriodicWave(customWaveform);
} else {
osc.type = type;
}
osc.frequency.value = freq;
osc.start();
return osc;
}
playTone()
ì AudioContext.createOscillator()
ë©ìë를 í¸ì¶íì¬ ìë¡ì´ OscillatorNode
를 ìì±í¨ì¼ë¡ì¨ ììí©ëë¤. ê·¸ë¦¬ê³ ëì ì°ë¦¬ë ì´ê²ì ë©ì¸ gain ë
¸ëì ìë¡ì´ oscillatorì OscillatorNode.connect()
ë©ìë를 í¸ì¶í¨ì¼ë¡ì¨ ì°ê²°íëë°, ì´ë oscillatorìê² ì´ê²ì 결과를 ì´ëë¡ ë³´ë¼ì§ ìë ¤ì¤ëë¤. ì´ë ê² í¨ì¼ë¡ì¨, ë©ì¸ gain ë
¸ëì gainì ë³ê²½íë ê²ì ìì±ëë 모ë ìì 볼륨ì ìí¥ì ë¯¸ì¹ ê²ì
ëë¤.
ê·¸ë¦¬ê³ ëì ì°ë¦¬ë ì¬ì©í ííì ì íì ì¸í
ë°ì íí ì í기ì ê°ì ê²ì¬í¨ì¼ë¡ì¨ ì»ìµëë¤. ë§ì½ ì¬ì©ìê° ì´ê²ì "custom"
ì¼ë¡ ì¤ì íë¤ë©´, ì°ë¦¬ë ì¬ì©ì ì ì ííì ì¬ì©í oscillator를 ì¤ì í기 ìíì¬ OscillatorNode.setPeriodicWave()
를 í¸ì¶í©ëë¤. ì´ë¥¼ íë ê²ì ìëì ì¼ë¡ oscillatorì type
ì custom
ì¼ë¡ ì¤ì í©ëë¤. ë§ì½ íí ì í기ìì ë¤ë¥¸ ííì´ ì íëìë¤ë©´, ì°ë¦¬ë oscillatorì ì íì ì í기ì ê°ì¼ë¡ ì¤ì í©ëë¤; ê·¸ ê°ì sine
, square
, triangle
, ê·¸ë¦¬ê³ sawtooth
ì¤ íëì¼ ê²ì
ëë¤.
oscillatorì 주íìë Oscillator.frequency
AudioParam
ê°ì²´ì ê°ì ì¤ì í¨ì¼ë¡ì¨ freq
íë¼ë¯¸í°ì ëª
ìë ê°ì¼ë¡ ì¤ì ë©ëë¤. ê·¸ë¦¬ê³ ì, ë§ì¹¨ë´, oscillatorë ììë AudioScheduledSourceNode.start()
ë©ìë를 í¸ì¶íì¬ ì리를 ìì±íëë¡ ììë©ëë¤.
mousedown
ì´ë mouseover
ì´ë²¤í¸ê° ê±´ë°ìì ë°ìíì ë, ì°ë¦¬ë ëìíë ìì ì¬ìí기를 ìí©ëë¤. notePressed()
í¨ìë ì´ ì´ë²¤í¸ë¤ì ëí ì´ë²¤í¸ í¸ë¤ë¬ë¡ ì¬ì©ë©ëë¤.
function notePressed(event) {
if (event.buttons & 1) {
let dataset = event.target.dataset;
if (!dataset["pressed"]) {
let octave = +dataset["octave"];
oscList[octave][dataset["note"]] = playTone(dataset["frequency"]);
dataset["pressed"] = "yes";
}
}
}
ë ê°ì§ ì´ì ë¡, ì°ë¦¬ë 주ì ë§ì°ì¤ ë²í¼ì´ ëë¬ì¡ëì§ë¥¼ íì¸í¨ì¼ë¡ì¨ ììí©ëë¤. 첫째ë¡, ì°ë¦¬ë ì¤ì§ 주ì ë§ì°ì¤ ë²í¼ì´ ë
¸í¸ ì¬ìì í ì ìê² íì©í기를 ìí©ëë¤. ë째ë¡, ê·¸ë¦¬ê³ ëì± ì¤ìíê², ì°ë¦¬ë ì ì ê° ììì ìì¼ë¡ ëëê·¸íë ê²½ì°ì ëí´ mouseover
를 ë¤ë£¨ê¸° ìí´ ì´ê²ì ì¬ì©íê³ , ì°ë¦¬ë ì¤ì§ ë§ì°ì¤ê° ììì ë¤ì´ìì ë ëë¬ì¡ë¤ë©´ ë
¸í¸ë¥¼ ì¬ìí기를 ìí©ëë¤.
ë§ì½ ë§ì°ì¤ ë²í¼ì´ ì¤ì ë¡ ëë¬ì¡ë¤ë©´, ì°ë¦¬ë ëë¬ì§ ê±´ë°ì dataset
í¹ì±ì ì»ìµëë¤; ì´ë ììì ì¬ì©ì ì ì ë°ì´í° í¹ì±ì ì ê·¼íë ê²ì ì½ê² í´ ì¤ëë¤. ì°ë¦¬ë data-pressed
í¹ì±ì ì°¾ìµëë¤; ë§ì½ (ìì´ ì´ë¯¸ ì¬ìëê³ ìì§ ìë¤ë ê²ì ëíë´ë) ê·¸ê²ì´ ìë¤ë©´, ììì data-frequency
í¹ì± ê°ì ì ë¬íë©°, ì°ë¦¬ë ìì ì¬ìí기 ìí´ playTone()
ì í¸ì¶í©ëë¤. ë°íë oscillatorë oscList
ì 미ëì 참조를 ìí´ ì ì¥ëê³ , data-pressed
ë ìì´ ì¬ìëê³ ìë¤ë ê²ì ëíë´ê¸° ìí´ yes
ë¡ ì¤ì ëì´ ë¤ì ë²ì ì´ê²ì´ í¸ì¶ëìì ë ì´ê²ì ë¤ì ììíì§ ììµëë¤.
noteReleased()
í¨ìë ì¬ì©ìê° ë§ì°ì¤ ë²í¼ì ë¼ê±°ë ë§ì°ì¤ë¥¼ íì¬ ì¬ìëê³ ìë ê±´ë° ë°ì¼ë¡ ì´ëìì¼°ì ë í¸ì¶ëë ì´ë²¤í¸ í¸ë¤ë¬ì
ëë¤.
function noteReleased(event) {
let dataset = event.target.dataset;
if (dataset && dataset["pressed"]) {
let octave = +dataset["octave"];
oscList[octave][dataset["note"]].stop();
delete oscList[octave][dataset["note"]];
delete dataset["pressed"];
}
}
noteReleased()
ë ì¬ì©ì ì ì data-octave
ì data-note
í¹ì±ì ê±´ë°ì oscillator를 ì°¾ì보기 ìí´ ì¬ì©íê³ , ê·¸ë¦¬ê³ ëì ì ì¬ìì ë©ì¶ê¸° ìí´ oscillatorì ììë stop()
ë©ìë를 í¸ì¶í©ëë¤. ë§ì§ë§ì¼ë¡, ìì´ íì¬ ì¬ìëê³ ìì§ ìë¤ë ê²ì ëíë´ê¸° ìí´, ìì ëí oscList
í목ì ì§ìì§ê³ data-pressed
í¹ì±ì (event.target
ì ìí´ ìë³ë) ê±´ë° ììë¡ë¶í° ì ê±°ë©ëë¤.
ì¸í
ë°ì 볼륨 ì¬ë¼ì´ëë ë©ì¸ gain ë
¸ëì gain ê°ì ë³ê²½í기 ìí ê°ë¨í ì¸í°íì´ì¤ë¥¼ ì ê³µíëë°, ì´ë¡ì¨ ì¬ìëë 모ë ìì ì¸ê¸°ë¥¼ ë³ê²½í©ëë¤. changeVolume()
ë©ìëë ì¬ë¼ì´ëì change
ì´ë²¤í¸ì ëí í¸ë¤ë¬ì
ëë¤.
function changeVolume(event) {
mainGainNode.gain.value = volumeControl.value;
}
ì´ê²ì ë©ì¸ gain ë
¸ëì gain
AudioParam
ì ê°ì ì¬ë¼ì´ëì ìë¡ì´ ê°ì¼ë¡ ì¤ì í©ëë¤.
ì´ë¥¼ 모ë í©íë©´, ê²°ê³¼ë ê°ë¨íì§ë§ ìëíë ë§ì°ì¤ë¡ ì´ì© ê°ë¥í 뮤ì§ì»¬ í¤ë³´ëì ëë¤.
ê°ì´ 보기RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4