43
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Tone.jsを使えば音楽知識ゼロの私でも簡単に作曲して遊べた!

Last updated at Posted at 2019-04-07

注意

Tone.jsを初めてさわってみました、間違いなどありましたらご指摘お願いします:bow:
また、題名にある通り私は音楽の知識は全くありません、そんな人でも Tone.js を使えば簡単に作曲っぽいことができるということで勘弁してください:bow:

また、この記事内のコードは全てこちらに同じのを用意してあります

参考


作曲してみた!

といっても、適当に音を羅列したようなものです:bow:

コードはこちらにも用意しました

Installation

Tone.jsインストール

npm install tone

自分が作曲したコード

index.html
<input type="button" value="play!">
index.js
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

私が勉強したことをまとめす、間違ってたらご指摘お願いします:bow:

Hello Tone

音を出してみます

hello-tone.js
import Tone from "tone";

const synth = new Tone.Synth().toMaster();

document.querySelector("[type=button]").addEventListener("click", e => {
    synth.triggerAttackRelease("C4", "8n"); // 8分音符「♪」の、「ド」を弾く
});

TypeScript

参考

TypeScriptでも動かせました

npm i typescript git://github.com/Tonejs/TypeScript.git
ts-index.ts
import * as Tone from "tone";

const synth: Tone.Synth = new Tone.Synth().toMaster();

document.querySelector("[type=button]").addEventListener("click", e => {
    synth.triggerAttackRelease("C4", "8n");
});

C4 とは?

音楽の初心者のためここでつまづきました。

以下のサイトを見るととても参考になりました

参考サイトそのまま流用した表です:bow:

鍵盤番号 音階名 音階名
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を設定することでドレミファソラシと音を出すことができました

cdefgab.js
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"));

8分音符 とは?

音楽の初心者のためここでもつまづきました。

以下のサイトを見るととても参考になりました

新規プロジェクト.png

参考サイト引用です

一番上にあるのがすべての音符の基礎となる、一番長い全音符(ぜんおんぷ)です。その全音符を主として、そこから音符の長さを2分割していきます。

全音符が1だとすると、その半分が2分音符(にぶおんぷ)、2分音符の半分が4分音符(しぶおんぷ)。つまり、4分音符は全音符の4分の1ということになります。

実際に音を鳴らすと違いがよくわかりました

note.js
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"));

繰り返し実行する

loops.js
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);
});

順に音を鳴らす

sequence.js
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();
});

簡単に作曲することができたチュートリアル

こちらの参考サイトが素晴らしかったのでそのままやらせていただきました
音楽の知識がない私が試したという内容ですので、誤りがありましたらご指摘お願いします:bow:
本当に素晴らしいので、私の記事はみなくても、こちらの参考ページだけでもみていただければと:muscle:

まずは音階を無視して音符の長さだけを考えて適当に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();
});

次はそのメロディーに音階を付けていきます。
別に凝った事をする必要はありませんので簡単に付けていきましょう。

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);

これで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);

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);

これだけで急にメロディーっぽくなりますね。
次は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);

なかなか良い感じになりました。
さらに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);

全体的に見て細かい修正をして完成。

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;

本当に素晴らしい解説でした、ありがとうございました:bow:

作成した曲をダウンロードする

参考

参考サイトのまんまですが、こちらも共有させていただきます!

index.html
    <input type="button" value="play!">
    <audio controls></audio>
download.js
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();
});

audioタグにblob形式で保存して、ブラウザの機能でダウンロードするということのようです

image.png


最後まで読んでいただいてありがとうございましたm(_ _)m

43
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?