注意
Tone.jsを初めてさわってみました、間違いなどありましたらご指摘お願いします
また、題名にある通り私は音楽の知識は全くありません、そんな人でも Tone.js
を使えば簡単に作曲っぽいことができるということで勘弁してください
また、この記事内のコードは全てこちらに同じのを用意してあります
参考
作曲してみた!
といっても、適当に音を羅列したようなものです
超簡単にだけど、人生初作曲 pic.twitter.com/AMLRWRQARm
— 奥村健吾 (@okumurakengo) April 7, 2019
Installation
Tone.jsインストール
npm install tone
自分が作曲したコード
<input type="button" value="play!">
import Tone from "tone";
const synth = new Tone.Synth().toMaster();
// note:ドレミなどの音階を指定
// dur:「4n」->「♩」(四分音符)、「8n」->「♪」(八分音符)
// nullだと休符
const data = [
{ note: "E4", dur: "8n" },
{ note: "F4", dur: "4n" },
[{ note: "G4", dur: "8n" }, { note: "G4", dur: "8n" }],
{ note: "G4", dur: "4n" },
{ note: "E4", dur: "8n" },
[{ note: "G4", dur: "8n" }, { note: "C5", dur: "8n" }],
{ note: "C5", dur: "8n" },
[{ note: "C5", dur: "8n" }, { note: "D5", dur: "2n" }],
null,
{ note: "E5", dur: "8n" },
{ note: "E5", dur: "8n" },
{ note: "D5", dur: "2n" },
null,
[{ note: "C5", dur: "8n" },{ note: "A4", dur: "8n" }],
[{ note: "C5", dur: "2n" },{ note: "C5", dur: "2n" }],
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
seq.loop = false;
Tone.Transport.bpm.value = 150; // テンポ
document.querySelector("[type=button]").addEventListener("click", e => {
Tone.Transport.start();
});
Tone.js
私が勉強したことをまとめす、間違ってたらご指摘お願いします
Hello Tone
音を出してみます
import Tone from "tone";
const synth = new Tone.Synth().toMaster();
document.querySelector("[type=button]").addEventListener("click", e => {
synth.triggerAttackRelease("C4", "8n"); // 8分音符「♪」の、「ド」を弾く
});
— 奥村健吾 (@okumurakengo) April 7, 2019
TypeScript
参考
TypeScriptでも動かせました
npm i typescript git://github.com/Tonejs/TypeScript.git
import * as Tone from "tone";
const synth: Tone.Synth = new Tone.Synth().toMaster();
document.querySelector("[type=button]").addEventListener("click", e => {
synth.triggerAttackRelease("C4", "8n");
});
— 奥村健吾 (@okumurakengo) April 7, 2019
C4
とは?
音楽の初心者のためここでつまづきました。
以下のサイトを見るととても参考になりました
参考サイトそのまま流用した表です
鍵盤番号 | 音階名 | 音階名 | |
---|---|---|---|
1 | ラ | A0 | |
2 | A#0 | ||
3 | シ | B0 | |
4 | ド | C1 | |
5 | C#1 | ||
6 | レ | D1 | |
7 | D#1 | ||
8 | ミ | E1 | |
9 | ファ | F1 | |
10 | F#1 | ||
11 | ソ | G1 | |
12 | G#1 | ||
13 | ラ | A1 | |
14 | A#1 | ||
15 | シ | B1 | |
16 | ド | C2 | |
17 | C#2 | ||
18 | レ | D2 | |
19 | D#2 | ||
20 | ミ | E2 | |
21 | ファ | F2 | |
22 | F#2 | ||
23 | ソ | G2 | |
24 | G#2 | ||
25 | ラ | A2 | |
26 | A#2 | ||
27 | シ | B2 | |
28 | ド | C3 | |
29 | C#3 | ||
30 | レ | D3 | |
31 | D#3 | ||
32 | ミ | E3 | |
33 | ファ | F3 | |
34 | F#3 | ||
35 | ソ | G3 | |
36 | G#3 | ||
37 | ラ | A3 | |
38 | A#3 | ||
39 | シ | B3 | |
40 | ド | C4 | C4 を指定するとここを鳴らしてくれる |
41 | C#4 | ||
42 | レ | D4 | |
43 | D#4 | ||
44 | ミ | E4 | |
45 | ファ | F | |
46 | F#4 | ||
47 | ソ | G4 | |
48 | G#4 | ||
49 | ラ | A4 | |
50 | A#4 | ||
51 | シ | B4 | |
52 | ド | C5 | |
53 | C#5 | ||
54 | レ | D5 | |
55 | D#5 | ||
56 | ミ | E5 | |
57 | ファ | F5 | |
58 | F#5 | ||
59 | ソ | G5 | |
60 | G#5 | ||
61 | ラ | A5 | |
62 | A#5 | ||
63 | シ | B5 | |
64 | ド | C6 | |
65 | C#6 | ||
66 | レ | D6 | |
67 | D#6 | ||
68 | ミ | E6 | |
69 | ファ | F6 | |
70 | F#6 | ||
71 | ソ | G6 | |
72 | G#6 | ||
73 | ラ | A6 | |
74 | A#6 | ||
75 | シ | B6 | |
76 | ド | C7 | |
77 | C#7 | ||
78 | レ | D7 | |
79 | D#7 | ||
80 | ミ | E7 | |
81 | ファ | F7 | |
82 | F#7 | ||
83 | ソ | G7 | |
84 | G#7 | ||
85 | ラ | A7 | |
86 | A#7 | ||
87 | シ | B7 | |
88 | ド | C8 |
C4〜B4を設定することでドレミファソラシと音を出すことができました
import Tone from "tone";
const synth = new Tone.Synth().toMaster();
document.body.insertAdjacentHTML("afterbegin", `
<input type="button" value="ド" id="c">
<input type="button" value="レ" id="d">
<input type="button" value="ミ" id="e">
<input type="button" value="ファ" id="f">
<input type="button" value="ソ" id="g">
<input type="button" value="ラ" id="a">
<input type="button" value="シ" id="b">
<br>
<input type="button" value="ド#" id="cs">
`);
c.addEventListener("click", e => synth.triggerAttackRelease("C4", "8n"));
d.addEventListener("click", e => synth.triggerAttackRelease("D4", "8n"));
e.addEventListener("click", e => synth.triggerAttackRelease("E4", "8n"));
f.addEventListener("click", e => synth.triggerAttackRelease("F4", "8n"));
g.addEventListener("click", e => synth.triggerAttackRelease("G4", "8n"));
a.addEventListener("click", e => synth.triggerAttackRelease("A4", "8n"));
b.addEventListener("click", e => synth.triggerAttackRelease("B4", "8n"));
cs.addEventListener("click", e => synth.triggerAttackRelease("C#4", "8n"));
— 奥村健吾 (@okumurakengo) April 7, 2019
8分音符
とは?
音楽の初心者のためここでもつまづきました。
以下のサイトを見るととても参考になりました
参考サイト引用です
一番上にあるのがすべての音符の基礎となる、一番長い全音符(ぜんおんぷ)です。その全音符を主として、そこから音符の長さを2分割していきます。
全音符が1だとすると、その半分が2分音符(にぶおんぷ)、2分音符の半分が4分音符(しぶおんぷ)。つまり、4分音符は全音符の4分の1ということになります。
実際に音を鳴らすと違いがよくわかりました
import Tone from "tone";
const synth = new Tone.Synth().toMaster();
document.body.insertAdjacentHTML("afterbegin", `
<input type="button" value="全音符" id="note">
<input type="button" value="2分音符" id="halfNote">
<input type="button" value="4分音符" id="quarterNote">
<input type="button" value="8分音符" id="eighthNote">
<input type="button" value="16分音符" id="sixteen">
`);
note.addEventListener("click", e => synth.triggerAttackRelease("C4", "1n"));
halfNote.addEventListener("click", e => synth.triggerAttackRelease("C4", "2n"));
quarterNote.addEventListener("click", e => synth.triggerAttackRelease("C4", "4n"));
eighthNote.addEventListener("click", e => synth.triggerAttackRelease("C4", "8n"));
sixteen.addEventListener("click", e => synth.triggerAttackRelease("C4", "16n"));
— 奥村健吾 (@okumurakengo) April 7, 2019
繰り返し実行する
import Tone from "tone";
const synth = new Tone.Synth().toMaster();
const notes = [
"C4", "E4", "G4",
"C5", "E5", "G5",
];
let index = 0;
Tone.Transport.scheduleRepeat(time => {
let note = notes[index % notes.length];
synth.triggerAttackRelease(note, "8n", time);
index++;
}, "8n");
document.querySelector("[type=button]").addEventListener("click", e => {
Tone.Transport.start();
setTimeout(() => {
Tone.Transport.stop();
}, 5000);
});
— 奥村健吾 (@okumurakengo) April 7, 2019
順に音を鳴らす
import Tone from "tone";
var synth = new Tone.Synth().toMaster();
var seq = new Tone.Sequence((time, note) => {
synth.triggerAttackRelease(note, "4n", time);
}, ["C4", "E4", "G4", "B4", "D5"], "4n").start(0);
seq.loop = false;
document.querySelector("[type=button]").addEventListener("click", e => {
Tone.Transport.start();
});
— 奥村健吾 (@okumurakengo) April 7, 2019
簡単に作曲することができたチュートリアル
こちらの参考サイトが素晴らしかったのでそのままやらせていただきました
音楽の知識がない私が試したという内容ですので、誤りがありましたらご指摘お願いします
本当に素晴らしいので、私の記事はみなくても、こちらの参考ページだけでもみていただければと
まずは音階を無視して音符の長さだけを考えて適当に1小節作ってみます。
例えば「タン タン タ タ タン」という至って普通のリズムです。
import Tone from "tone";
const synth = new Tone.Synth().toMaster();
const data = [
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "E4", dur: "8n" }],
{ note: "E4", dur: "4n" },
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
seq.loop = false;
document.querySelector("[type=button]").addEventListener("click", e => {
Tone.Transport.start();
});
— 奥村健吾 (@okumurakengo) April 7, 2019
次はそのメロディーに音階を付けていきます。
別に凝った事をする必要はありませんので簡単に付けていきましょう。
const data = [
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
— 奥村健吾 (@okumurakengo) April 7, 2019
これで1小節のメロディーが出来ました。
次はそのメロディーを4回くり返して聴いてみます。
const data = [
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
— 奥村健吾 (@okumurakengo) April 7, 2019
4 回目を変えたくなりませんか?
というわけで4小節目を変えてみます。
const data = [
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
{ note: "G4", dur: "4n" },
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
[{ note: "G4", dur: "8n" }, { note: "C5", dur: "2n" }],
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
— 奥村健吾 (@okumurakengo) April 7, 2019
これだけで急にメロディーっぽくなりますね。
次は2小節目を変えてみましょうか。
4小節目をちょっと変化させた形です。
const data = [
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
[{ note: "G4", dur: "8n" }, { note: "C5", dur: "2n" }],
null,
[null, { note: "D5", dur: "8n" }],
{ note: "C5", dur: "2n" },
null,
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
[{ note: "G4", dur: "8n" }, { note: "C5", dur: "2n" }],
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
— 奥村健吾 (@okumurakengo) April 7, 2019
なかなか良い感じになりました。
さらに3小節目を変えてみます。
const data = [
{ note: "E4", dur: "4n" },
{ note: "E4", dur: "4n" },
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
[{ note: "G4", dur: "8n" }, { note: "C5", dur: "2n" }],
null,
[null, { note: "D5", dur: "8n" }],
{ note: "C5", dur: "2n" },
null,
{ note: "B4", dur: "4n" },
{ note: "B4", dur: "4n" },
[{ note: "B4", dur: "8n" }, { note: "A4", dur: "8n" }],
[{ note: "B4", dur: "8n" }, { note: "C5", dur: "2n" }],
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
— 奥村健吾 (@okumurakengo) April 7, 2019
全体的に見て細かい修正をして完成。
const data = [
{ note: "E4", dur: "2n" },
null,
[{ note: "E4", dur: "8n" }, { note: "F4", dur: "8n" }],
[{ note: "G4", dur: "8n" }, { note: "C5", dur: "2n" }],
null,
[null, { note: "D5", dur: "8n" }],
{ note: "C5", dur: "2n" },
null,
null,
{ note: "B4", dur: "4n" },
[{ note: "B4", dur: "8n" }, { note: "A4", dur: "8n" }],
[{ note: "B4", dur: "8n" }, { note: "C5", dur: "2n" }],
];
const seq = new Tone.Sequence((time, { note, dur }) => {
synth.triggerAttackRelease(note, dur, time);
}, data, "4n").start(0);
seq.loop = false;
Tone.Transport.bpm.value = 150;
— 奥村健吾 (@okumurakengo) April 7, 2019
本当に素晴らしい解説でした、ありがとうございました
作成した曲をダウンロードする
参考
参考サイトのまんまですが、こちらも共有させていただきます!
<input type="button" value="play!">
<audio controls></audio>
import Tone from "tone";
const audio = document.querySelector("audio");
const synth = new Tone.Synth().toMaster();
const actx = Tone.context;
const dest = actx.createMediaStreamDestination();
const recorder = new MediaRecorder(dest.stream);
synth.connect(dest);
const chunks = [];
const notes = "CDEFGAB".split("").map(n=>`${n}4`);
let note = 0;
Tone.Transport.scheduleRepeat(time => {
if (note === 0) {
recorder.start();
}
if (note > notes.length) {
synth.triggerRelease(time);
recorder.stop();
Tone.Transport.stop();
} else {
synth.triggerAttack(notes[note], time);
}
note++;
}, "4n");
recorder.ondataavailable = evt => chunks.push(evt.data);
recorder.onstop = evt => {
let blob = new Blob(chunks, { type: "audio/ogg: codecs=opus" })
audio.src = URL.createObjectURL(blob);
};
document.querySelector("[type=button]").addEventListener("click", e => {
Tone.Transport.start();
});
— 奥村健吾 (@okumurakengo) April 7, 2019
audioタグにblob形式で保存して、ブラウザの機能でダウンロードするということのようです
最後まで読んでいただいてありがとうございましたm(_ _)m