Skip to content

Instantly share code, notes, and snippets.

@zakuroishikuro
Last active April 20, 2016 16:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zakuroishikuro/6f5ea9e5098308e9c86fa9cc2fda23ba to your computer and use it in GitHub Desktop.
Save zakuroishikuro/6f5ea9e5098308e9c86fa9cc2fda23ba to your computer and use it in GitHub Desktop.
どれみ再生機
<style>
body { background-color: #CCC; }
textarea { width: 500px; height: 300px; }
</style>
<script>
var ctx, gain;
window.addEventListener("DOMContentLoaded", ()=>{
ctx = new AudioContext();
gain = ctx.createGain();
gain.connect(ctx.destination);
})
String.prototype.count = function(pattern){
var r = new RegExp(pattern, "g");
var m = this.match(r);
return m ? m.length : 0;
}
function parse_frequency(note, pitch){
if (pitch === undefined) pitch = 440;
var n;
switch (note.trim()[0]) {
case "ラ": n = 1 + 12; break;
case "シ": n = 3 + 12; break;
case "ド": n = 4; break;
case "レ": n = 6; break;
case "ミ": n = 8; break;
case "フ": n = 9; break;
case "ソ": n = 11; break;
default: return;
}
n += note.count("#");
n += (note.count("↑") - note.count("↓")) * 12;
return pitch * Math.pow(Math.pow(2, 1.0/12), n - 1);
}
function parse_duration(note, tempo){
if (tempo === undefined) tempo = 120;
var dur = 60.0 / tempo;
return dur / Math.pow(2, note.count("/")) + dur * note.count("-");
}
function play_notes(notes, pitch, type, tempo){
var scanner = /[ドレミフソラシ_]ァ?[^ドレミフソラシ_]*/g;
var m = notes.match(scanner);
var delay = 0;
var oscillators = [];
for (var i = 0, len = m.length; i < len; i++){
var note = m[i];
var hz = parse_frequency(note, pitch);
var dur = parse_duration(note, tempo);
if (!/_/.test(note)){
oscillators.push(create_oscillator(hz, type, delay, dur - 0.01));
};
delay += dur;
}
return oscillators;
}
function create_oscillator(freq, type, delay, duration){
var osc = ctx.createOscillator();
osc.connect(gain);
osc.frequency.value = freq;
osc.type = type || "sine";
osc.start(ctx.currentTime + delay);
osc.stop(ctx.currentTime + delay + duration);
return osc;
}
var osc_list = [];
function start(){
var notes = document.getElementById("notes").value;
notes = notes.replace(/\([^(]*?\)/gm, "");
var pitch = document.getElementById("pitch").value;
var type = document.getElementById("type").value;
var tempo = document.getElementById("tempo").value;
if (osc_list) stop();
osc_list = play_notes(notes, parseInt(pitch), type, tempo);
}
function stop(){
if (osc_list) osc_list.forEach(osc=>osc.stop());
}
</script>
<p><button onclick="start()">鳴らす</button><button onclick="stop()">止める</button></p>
<textarea id="notes">
シ-レ↑ ラ-- シ-レ↑ ラ--
シ-レ↑ ラ↑-ソ↑ レ↑-ド↑/シ/ ラ--
シ-レ↑ ラ-ソ/ラ/ シ-レ↑ ラ--
シ-レ↑ ラ↑-ソ↑ レ↑↑-- ---
レ↑↑-ド↑↑/シ↑/ ド↑↑/シ↑/ソ↑- ド↑↑-シ↑/ラ↑/ シ↑/ラ↑/ミ↑-
レ↑↑-ド↑↑/シ↑/ ド↑↑/シ↑/ソ↑ ド↑↑ ソ↑↑-- ---
</textarea>
<ul>
<li>「ドレミファソラシド」のいずれかを書くとその音が鳴る</li>
<li>音の高さ変更:「#」で半音上がり、上下の矢印で1オクターブ上下する</li>
<li>音の長さ変更:「-」は音符1つ分伸ばし、「/」は半分にする(例えば4分音符が8分音符になる)</li>
<li>音を出さない:「_」で音符1つ分休む。丸括弧で囲んだ箇所は無視される
<li>それ以外の文字は無視される</li>
</ul>
<p>音色:
<select id="type">
<option value="sine">正弦波(sine) ... 口笛、オルガン</option>
<option value="square">矩形波(square) ... クラリネット</option>
<option value="sawtooth">ノコギリ波(sawtooth) ... バイオリン、トランペット</option>
<option value="triangle">三角波(triangle) ... リコーダー、フルート</option>
</select>
</p>
<p>音符の長さ:1秒に<input id="tempo" type="number" value="120" style="width: 5em">回</p>
<p>
ピッチ(ラの周波数):<input id="octave" type="range" min=110 max=14080 value="440" list="freq_list" oninput="document.getElementById('pitch').value = this.value">
<input type="number" id="pitch" value="440" style="width: 10em">ヘルツ
<datalist id="freq_list">
<option value="110" />
<option value="220" />
<option value="440" />
<option value="880" />
<option value="1760" />
<option value="3520" />
<option value="7040" />
<option value="14080" />
</datalist>
</p>
<div style="font-size: 0.8em">
<ul>
<li>音階は「ラ」の音(周波数:440Hz)に合わせて調律され、1オクターブ上がると2倍になる(880Hz)</li>
<li>人間の可聴域は20Hz〜20000Hz程度で、15000Hz以上になると20代後半からは聞こえづらくなる(モスキート音)</li>
</ul>
<div>
<div class="comment" style="display: none">
tempo: 120
シ-レ↑ ラ-- シ-レ↑ ラ--
シ-レ↑ ラ↑-ソ↑ レ↑-ド↑/シ/ ラ--
シ-レ↑ ラ-ソ/ラ/ シ-レ↑ ラ--
シ-レ↑ ラ↑-ソ↑ レ↑↑-- ---
レ↑↑-ド↑↑/シ↑/ ド↑↑/シ↑/ソ↑- ド↑↑-シ↑/ラ↑/ シ↑/ラ↑/ミ↑-
レ↑↑-ド↑↑/シ↑/ ド↑↑/シ↑/ソ↑ ド↑↑ ソ↑↑-- ---
tempo: 120
ソ/ミ/レ- ソ/ミ/レ-
ソ/ミ/レミ レ--
シ↓ラ#↓シ↓ ファ#/ソ/ミ-
ソソソ ファ#/ミ/レ-
ソ/ミ/レ- ソ/ミ/レ-
ソ/ミ/レミ レ--
シ↓ラ#↓シ↓ ミ/ファ#/ソ-
ソソラソ--/
tempo: 180
レ/ファ/レ↑- レ/ファ/レ↑-
ミ↑-/ファ↑/ミ↑/ ファ↑/ミ↑/ド↑/ラ--/
ラレファ/ソ/ラ-- ラレファ/ソ/ミ--
レ/ファ/レ↑- レ/ファ/レ↑-
ミ↑-/ファ↑/ミ↑/ ファ↑/ミ↑/ド↑/ラ--/
ラレファ/ソ/ラ- ラレ- ---
tempo: 280
ファラシ- ファラシ-
ファラシミ↑レ↑- シド↑
シソミ----レ
ミソミ-----
ファラシ- ファラシ-
ファラシミ↑レ↑-シド↑
ミ↑シソ----シ
ソレミ-----
レミファ-ソラシ- ド↑シミ-----
レミファ-ソラシ- ド↑レ↑ミ↑-----
レミファ-ソラシ- ド↑シミ-----
ファミラソ シラド↑シ
レ↑ド↑ミ↑レ↑ファ↑ミ↑ ミ↑/ファ↑/_/
レ↑/ミ↑-------
tempo: 120
ソ/レ-/ソ/レ/ミ/ソ-
http://www.cosp.jp/community_topic.aspx?id=7735&ti=41219
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment