자바에서 주파수를 재생하는 글 자바 예제: 특정 주파수의 소리 재생 을 자바스크립트로 바꾼 예제입니다. 외부 온라인 소스나 라이브러리 필요 없이 자바스크립트 자체 엔진으로 소리를 재생합니다.

 

1) AudioContext 인스턴스 생성
var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var osc, gn;

사파리 등 모바일 브라우저에서는 웹킷 접두어가 붙은 webkitAudioContext만 인식하므로 이 부분도 추가합니다. osc, gn은 오실레이터, 게인노드 인스턴스에서 사용할 변수명입니다.

 

2) 변수 osc, gn 선언 및 연결
osc = audioCtx.createOscillator() // 오실레이터 생성
osc.type = "sine" // 그래프 타입 설정 (sine(기본값), saw, triangle 등)
osc.frequency.value = 440 // 주파수(Hz) 입력

gn = audioCtx.createGain() // 게인노드 생성
osc.connect(gn) // 오실레이터와 게인노드 연결
gn.connect(audioCtx.destination) // 게인노드를 추상화된 출력장치(스피커 등)에 연결

 

3) 재생 및 정지
osc.start() // 오실레이터 스타트(음 재생)

// 1초간 재생 후 페이드아웃하면서 정지 (마지막의 튀는 음을 방지하기 위함)
setTimeout(function() {
  gn.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 0.04)
}, 1000)

브라우저에 따라서 osc.start()는 사용자의 이벤트 행동에 의해서만 (마우스 클릭, 키보드 버튼 누름 등) 동작하도록 되어있는 경우도 있습니다. 재생의 정지는 osc.stop()으로도 가능하지만 마지막에 튀는 음을 방지하기 위해 위와 같은 방법을 사용하였습니다. (참고 사이트)

 

4) stop후 다른 이벤트를 통해 다른 음을 재생하고자 하는 경우 
if (osc && gn) {
  gn.disconnect(audioCtx.destination)
  osc.disconnect(gn)
}

// 다시 인스턴스 생성
osc = audioCtx.createOscillator()

디스커넥트 후 osc 인스턴스를 다시 생성해야 합니다. 기존의 osc 인스턴스를 재활용하려고 한다면 에러가 발생하면서 작동하지 않습니다. (참고 사이트)

 

추가 예제: 음악의 평균율 주파수 테이블 (JQuery 포함)


<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Frequencies for equal-tempered scale</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
tr {
line-height: 15px;
min-height: 15px;
height: 15px;
}
.tr-of-base-note{
background-color:lavender;
}
.td-of-freq {
cursor: pointer;
}
</style>
</head>
<body class="container">
<header>
<h2>Frequencies for equal-tempered scale</h2>
</header>
<nav>
<label>A4 = </label>
<input type="number" id="input-freq" value="440" min="413" max="460">
<button type="button" id="btn-change-freq" class="btn btn-primary btn-sm" >Change A<sub>4</sub></button>
<button type="button" id="btn-help" class="btn btn-secondary btn-sm">Help</button>
<div id="div-help" class="alert alert-dismissible alert-info" style="display:none;">
<p>Enter the frequency value in the Frequency field and click the Change button or press the Enter key to see the changed frequency table.</p>
<p>Click on each row of the table to hear the note at that frequency. If you are using a mobile device, turn off silent mode.</p>
</div>
</nav>
<article class="wrapper">
<table id="freq-table" class="table table-hover">
<thead>
<tr class="table-info">
<th>Note</th>
<th>Frequnecy (Hz)</th>
<th>Wavelength (cm)</th>
</tr>
</thead>
<tbody id="freq-tbody">
</tbody>
</table>
</article>
<footer>
</script>
Copyright by <a href="http://yoonbumtae.com" target="_blank">BGSMM</a>
</footer>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script>
var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var osc, gn;
var isNowPlaying = false;
var NOTES = {
names: ["C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"],
altNames: {
"C♯": "D♭",
"D♯": "E♭",
"F♯": "G♭",
"G♯": "A♭",
"A♯": "B♭"
},
baseNote: "A",
baseOctave: 4,
speedOfSound: 34500
}
var EXP = Math.pow(2, 1 / 12)
var noteStart = 1
var noteEnd = 7
var distanceFromBaseToLowest = NOTES.names.length * (NOTES.baseOctave – noteStart) +
NOTES.names.indexOf("A")
//alert(distanceFromBaseToLowest)
console.log(audioCtx)
drawTable()
$("#btn-change-freq").on("click", function() {
drawTable($("#input-freq").val())
})
$("#input-freq").on("keyup", function(e) {
if (e.keyCode === 13) {
drawTable($("#input-freq").val())
}
})
$("#btn-help").on("click", function(e){
$("#div-help").toggle()
})
function playOneNote(freq, ms, opt_type) {
if (osc && gn) {
gn.disconnect(audioCtx.destination)
osc.disconnect(gn)
}
osc = audioCtx.createOscillator()
osc.type = opt_type || "sine"
osc.frequency.value = freq
gn = audioCtx.createGain()
console.log(osc, gn)
osc.connect(gn)
gn.connect(audioCtx.destination)
osc.start()
setTimeout(function() {
gn.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 0.04)
}, ms)
}
function drawTable(freq) {
freq = freq || 440
var tbody = $("#freq-tbody").html("")
var distIndex = 0
// draw initial table
for (var i = noteStart; i <= noteEnd; i++) {
for (var j in NOTES.names) {
var td1 = $("<td/>")
var noteName = makeNoteStr(NOTES.names[j]) + "<sub>" + i + "</sub>"
if(NOTES.altNames[NOTES.names[j]]){
noteName += " / " + makeNoteStr(NOTES.altNames[NOTES.names[j]]) + "<sub>" + i + "</sub>"
}
td1.html(noteName)
var dist = distanceFromBaseToLowest * -1 + parseInt(distIndex++)
var eachFreq = freq * Math.pow(EXP, dist)
var td2 = $("<td/>", {
text: eachFreq.toFixed(2),
class: "td-of-freq",
"data-dist": dist
})
var td3 = $("<td/>", {
text: (NOTES.speedOfSound / eachFreq).toFixed(2)
})
var tr = $("<tr/>", {
"onclick": "playOneNote(" + eachFreq + ", 1000, 'triangle')"
})
if (dist == 0) {
tr.addClass("tr-of-base-note")
}
tr.append(td1, td2, td3)
tbody.append(tr)
}
}
}
function makeNoteStr(str){
return str.substr(0, 1) + "<sup>" + str.substr(1, 1) + "</sup>"
}
</script>
</body>
</html>

view raw

freq-table.html

hosted with ❤ by GitHub

예제 사이트 바로가기

자바스크립트를 이용해 C1 ~ B7까지 각 노트의 주파수가 얼마인지 계산한 테이블입니다. 테이블의 행을 클릭하면 위의 방법을 이용한 해당 주파수의 소리가 납니다. (아이폰의 경우 무음 해제해야 함)

 

 

문의 | 코멘트 또는 yoonbumtae@gmail.com




0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다