音つくる。


import numpy as np
from IPython.display import Audio

# パラメータ設定
fs = 44100       # サンプリングレート
duration = 1.0   # 音の持続時間(秒)
frequency = 440.0  # サイン波の周波数(Hz)

# サイン波の生成
t = np.linspace(0, duration, int(fs * duration), endpoint=False)
audio = 0.5 * np.sin(2 * np.pi * frequency * t)

# オーディオの再生
Audio(audio, rate=fs, autoplay=True)


パラメータ設定

fs = 44100       # サンプリングレート
duration = 1.0   # 音の持続時間(秒)
frequency = 440.0  # サイン波の周波数(Hz)
  • fs: サンプリングレート。1秒間に44100回サンプリングすることを意味します。これはCD音質の標準的なレートです。

  • duration: 音の持続時間。ここでは1秒間の音を生成します。

  • frequency: サイン波の周波数。440Hzは標準的なA音(ラ)です。

サイン波の生成

t = np.linspace(0, duration, int(fs * duration), endpoint=False)
audio = 0.5 * np.sin(2 * np.pi * frequency * t)
  • t: 0から`duration`秒までの間の時間を等間隔に分割した配列を生成します。この場合、44100個の点を持つ配列になります。

  • audio: サイン波を生成します。`0.5`は音量の調整で、振幅を半分にしています。`np.sin(2 * np.pi * frequency * t)`はサイン波の生成式です。

np.linspace
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)

np.linspaceは、指定した範囲の数値を均等に分割して配列を作成する関数です。

start: 配列の開始値
stop: 配列の終了値
num: 生成する数値の数(デフォルトは50)
endpoint: Trueの場合、stopを配列に含めます。Falseの場合、stopを含めません。
retstep: Trueの場合、生成された数値間の間隔も返します。
dtype: 配列のデータ型を指定します。
axis: 配列が生成される軸を指定します。

オーディオの再生

Audio(audio, rate=fs, autoplay=True)
  • `Audio`: 生成したサイン波データ`audio`を再生します。

  • `rate`: サンプリングレートを指定します。

  • `autoplay`: `True`にすることで、自動再生を有効にします。

このコードを実行すると、440Hzのサイン波(音)が1秒間再生されます。


音量

音量調整はサイン派の振幅

import numpy as np
from IPython.display import Audio

# パラメータ設定
fs = 44100       # サンプリングレート
duration = 1.0   # 音の持続時間(秒)
frequency = 440.0  # サイン波の周波数(Hz)
amplitude = 0.1  # サイン波の振幅(音量)

# サイン波の生成
t = np.linspace(0, duration, int(fs * duration), endpoint=False)
audio = amplitude * np.sin(2 * np.pi * frequency * t)

# オーディオの再生
Audio(audio, rate=fs, autoplay=True)

音階

音階の周波数は12音階の等比数列に従います。基準となるA4(440Hz)を基にして、それぞれの音の周波数を計算できます。以下に、一般的な音階の周波数をA4(440Hz)を基準として列挙します。

主要な音階の周波数

各オクターブの基準音$${A4}$$の周波数を基に、12音の音階を列挙します。計算には次の公式を使用します:
$${ f(n) = 440 \times 2^{\frac{n}{12}} }$$
ここで、$${ n }$$ はA4からの半音の数です。例えば、A#4はA4から1半音上がった音ですので、$${ n = 1 }$$ です。

A4 = 440Hz

  • C4 (261.63Hz)

  • C#4/Db4 (277.18Hz)

  • D4 (293.66Hz)

  • D#4/Eb4 (311.13Hz)

  • E4 (329.63Hz)

  • F4 (349.23Hz)

  • F#4/Gb4 (369.99Hz)

  • G4 (392.00Hz)

  • G#4/Ab4 (415.30Hz)

  • A4 (440.00Hz)

  • A#4/Bb4 (466.16Hz)

  • B4 (493.88Hz)

その他のオクターブの音階

各オクターブにおける音の周波数も同様に計算できます。例えば、C5はC4の1オクターブ上(倍の周波数)です。

C音のオクターブ

  • C0 (16.35Hz)

  • C1 (32.70Hz)

  • C2 (65.41Hz)

  • C3 (130.81Hz)

  • C4 (261.63Hz)

  • C5 (523.25Hz)

  • C6 (1046.50Hz)

  • C7 (2093.00Hz)

  • C8 (4186.01Hz)

D音のオクターブ

  • D0 (18.35Hz)

  • D1 (36.71Hz)

  • D2 (73.42Hz)

  • D3 (146.83Hz)

  • D4 (293.66Hz)

  • D5 (587.33Hz)

  • D6 (1174.66Hz)

  • D7 (2349.32Hz)

  • D8 (4698.64Hz)



html+JavaScript

なんかpython、音がでかい。


%%html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Melody Generator</title>
</head>
<body>
    <h1>Melody Generator</h1>
    <label for="note">Note:</label>
    <select id="note">
        <option value="16.35">C0</option>
        <option value="17.32">C#0/Db0</option>
        <option value="18.35">D0</option>
        <option value="19.45">D#0/Eb0</option>
        <option value="20.60">E0</option>
        <option value="21.83">F0</option>
        <option value="23.12">F#0/Gb0</option>
        <option value="24.50">G0</option>
        <option value="25.96">G#0/Ab0</option>
        <option value="27.50">A0</option>
        <option value="29.14">A#0/Bb0</option>
        <option value="30.87">B0</option>
        <option value="32.70">C1</option>
        <option value="34.65">C#1/Db1</option>
        <option value="36.71">D1</option>
        <option value="38.89">D#1/Eb1</option>
        <option value="41.20">E1</option>
        <option value="43.65">F1</option>
        <option value="46.25">F#1/Gb1</option>
        <option value="49.00">G1</option>
        <option value="51.91">G#1/Ab1</option>
        <option value="55.00">A1</option>
        <option value="58.27">A#1/Bb1</option>
        <option value="61.74">B1</option>
        <option value="65.41">C2</option>
        <option value="69.30">C#2/Db2</option>
        <option value="73.42">D2</option>
        <option value="77.78">D#2/Eb2</option>
        <option value="82.41">E2</option>
        <option value="87.31">F2</option>
        <option value="92.50">F#2/Gb2</option>
        <option value="98.00">G2</option>
        <option value="103.83">G#2/Ab2</option>
        <option value="110.00">A2</option>
        <option value="116.54">A#2/Bb2</option>
        <option value="123.47">B2</option>
        <option value="130.81">C3</option>
        <option value="138.59">C#3/Db3</option>
        <option value="146.83">D3</option>
        <option value="155.56">D#3/Eb3</option>
        <option value="164.81">E3</option>
        <option value="174.61">F3</option>
        <option value="185.00">F#3/Gb3</option>
        <option value="196.00">G3</option>
        <option value="207.65">G#3/Ab3</option>
        <option value="220.00">A3</option>
        <option value="233.08">A#3/Bb3</option>
        <option value="246.94">B3</option>
        <option value="261.63">C4</option>
        <option value="277.18">C#4/Db4</option>
        <option value="293.66">D4</option>
        <option value="311.13">D#4/Eb4</option>
        <option value="329.63">E4</option>
        <option value="349.23">F4</option>
        <option value="369.99">F#4/Gb4</option>
        <option value="392.00">G4</option>
        <option value="415.30">G#4/Ab4</option>
        <option value="440.00">A4</option>
        <option value="466.16">A#4/Bb4</option>
        <option value="493.88">B4</option>
        <option value="523.25">C5</option>
        <option value="554.37">C#5/Db5</option>
        <option value="587.33">D5</option>
        <option value="622.25">D#5/Eb5</option>
        <option value="659.25">E5</option>
        <option value="698.46">F5</option>
        <option value="739.99">F#5/Gb5</option>
        <option value="783.99">G5</option>
        <option value="830.61">G#5/Ab5</option>
        <option value="880.00">A5</option>
        <option value="932.33">A#5/Bb5</option>
        <option value="987.77">B5</option>
        <option value="1046.50">C6</option>
        <option value="1108.73">C#6/Db6</option>
        <option value="1174.66">D6</option>
        <option value="1244.51">D#6/Eb6</option>
        <option value="1318.51">E6</option>
        <option value="1396.91">F6</option>
        <option value="1479.98">F#6/Gb6</option>
        <option value="1567.98">G6</option>
        <option value="1661.22">G#6/Ab6</option>
        <option value="1760.00">A6</option>
        <option value="1864.66">A#6/Bb6</option>
        <option value="1975.53">B6</option>
        <option value="2093.00">C7</option>
        <option value="2217.46">C#7/Db7</option>
        <option value="2349.32">D7</option>
        <option value="2489.02">D#7/Eb7</option>
        <option value="2637.02">E7</option>
        <option value="2793.83">F7</option>
        <option value="2959.96">F#7/Gb7</option>
        <option value="3135.96">G7</option>
        <option value="3322.44">G#7/Ab7</option>
        <option value="3520.00">A7</option>
        <option value="3729.31">A#7/Bb7</option>
        <option value="3951.07">B7</option>
        <option value="4186.01">C8</option>
    </select>

    <label for="duration">Duration (s):</label>
    <input type="range" id="duration" min="0.1" max="2.0" step="0.1" value="0.5">
    <span id="durationValue">0.5</span>

    <label for="volume">Volume:</label>
    <input type="range" id="volume" min="0.0" max="1.0" step="0.1" value="0.5">
    <span id="volumeValue">0.5</span>

    <button id="addNote">Add Note</button>
    <button id="playMelody">Play Melody</button>

    <div id="melodyOutput"></div>

    <script>
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        let melody = [];

        document.getElementById('duration').addEventListener('input', function() {
            document.getElementById('durationValue').textContent = this.value;
        });

        document.getElementById('volume').addEventListener('input', function() {
            document.getElementById('volumeValue').textContent = this.value;
        });

        document.getElementById('addNote').addEventListener('click', function() {
            const note = document.getElementById('note').value;
            const duration = parseFloat(document.getElementById('duration').value);
            melody.push({ frequency: parseFloat(note), duration: duration });
            const noteName = document.getElementById('note').options[document.getElementById('note').selectedIndex].text;
            document.getElementById('melodyOutput').innerHTML += `<p>Added: ${noteName} - ${duration}s</p>`;
        });

        document.getElementById('playMelody').addEventListener('click', async function() {
            const volume = parseFloat(document.getElementById('volume').value);
            for (let note of melody) {
                await playTone(note.frequency, note.duration, volume);
            }
        });

        function playTone(frequency, duration, volume) {
            return new Promise((resolve) => {
                const oscillator = audioContext.createOscillator();
                const gainNode = audioContext.createGain();

                oscillator.type = 'square';
                oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
                gainNode.gain.setValueAtTime(volume, audioContext.currentTime);

                oscillator.connect(gainNode);
                gainNode.connect(audioContext.destination);

                oscillator.start();
                oscillator.stop(audioContext.currentTime + duration);

                oscillator.onended = resolve;
            });
        }
    </script>
</body>
</html>


マウスオーバーでピロピロ鳴るやつ


%%html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Melody Generator</title>
    <style>
        .note-container {
            display: flex;
            flex-wrap: wrap;
        }
        .note {
            padding: 10px;
            margin: 0 0 30px 0; /* 上下の行間を10pxに設定 */
            background-color: #f0f0f0;
            width: 20px;            
            border: 1px solid #ccc;
            cursor: pointer;
        }
        .note:hover {
            background-color: #e0e0e0;
        }
        .melody-note {
            display: flex;
            align-items: center;
            margin-bottom: 5px;
        }
        .melody-note button {
            margin-left: 10px;
        }
        #melodyOutput > div {
            display: flex;
            flex-direction: column;
        }
    </style>
</head>
<body>
    <h1>Melody Generator</h1>
    <button id="toggleMode">Switch to Mouse Over Mode</button>
    <label for="duration">Duration (s):</label>
    <input type="range" id="duration" min="0.1" max="2.0" step="0.1" value="0.5">
    <span id="durationValue">0.5</span>
    <label for="volume">Volume:</label>
    <input type="range" id="volume" min="0.0" max="1.0" step="0.1" value="0.5">
    <span id="volumeValue">0.5</span>
    <button id="playMelody">Play Melody</button>
    <div class="note-container" id="noteContainer"></div>
    <div id="melodyOutput"></div>

    <script>
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        let melody = [];
        let mode = 'mouseover';
        let action = 'play';

        const notes = [
            { name: 'C0 (ド)', freq: 16.35 }, { name: 'C#0/Db0 (ド#)', freq: 17.32 }, { name: 'D0 (レ)', freq: 18.35 }, { name: 'D#0/Eb0 (レ#)', freq: 19.45 }, { name: 'E0 (ミ)', freq: 20.60 },
            { name: 'F0 (ファ)', freq: 21.83 }, { name: 'F#0/Gb0 (ファ#)', freq: 23.12 }, { name: 'G0 (ソ)', freq: 24.50 }, { name: 'G#0/Ab0 (ソ#)', freq: 25.96 }, { name: 'A0 (ラ)', freq: 27.50 },
            { name: 'A#0/Bb0 (ラ#)', freq: 29.14 }, { name: 'B0 (シ)', freq: 30.87 }, { name: 'C1 (ド)', freq: 32.70 }, { name: 'C#1/Db1 (ド#)', freq: 34.65 }, { name: 'D1 (レ)', freq: 36.71 },
            { name: 'D#1/Eb1 (レ#)', freq: 38.89 }, { name: 'E1 (ミ)', freq: 41.20 }, { name: 'F1 (ファ)', freq: 43.65 }, { name: 'F#1/Gb1 (ファ#)', freq: 46.25 }, { name: 'G1 (ソ)', freq: 49.00 },
            { name: 'G#1/Ab1 (ソ#)', freq: 51.91 }, { name: 'A1 (ラ)', freq: 55.00 }, { name: 'A#1/Bb1 (ラ#)', freq: 58.27 }, { name: 'B1 (シ)', freq: 61.74 }, { name: 'C2 (ド)', freq: 65.41 },
            { name: 'C#2/Db2 (ド#)', freq: 69.30 }, { name: 'D2 (レ)', freq: 73.42 }, { name: 'D#2/Eb2 (レ#)', freq: 77.78 }, { name: 'E2 (ミ)', freq: 82.41 }, { name: 'F2 (ファ)', freq: 87.31 },
            { name: 'F#2/Gb2 (ファ#)', freq: 92.50 }, { name: 'G2 (ソ)', freq: 98.00 }, { name: 'G#2/Ab2 (ソ#)', freq: 103.83 }, { name: 'A2 (ラ)', freq: 110.00 }, { name: 'A#2/Bb2 (ラ#)', freq: 116.54 },
            { name: 'B2 (シ)', freq: 123.47 }, { name: 'C3 (ド)', freq: 130.81 }, { name: 'C#3/Db3 (ド#)', freq: 138.59 }, { name: 'D3 (レ)', freq: 146.83 }, { name: 'D#3/Eb3 (レ#)', freq: 155.56 },
            { name: 'E3 (ミ)', freq: 164.81 }, { name: 'F3 (ファ)', freq: 174.61 }, { name: 'F#3/Gb3 (ファ#)', freq: 185.00 }, { name: 'G3 (ソ)', freq: 196.00 }, { name: 'G#3/Ab3 (ソ#)', freq: 207.65 },
            { name: 'A3 (ラ)', freq: 220.00 }, { name: 'A#3/Bb3 (ラ#)', freq: 233.08 }, { name: 'B3 (シ)', freq: 246.94 }, { name: 'C4 (ド)', freq: 261.63 }, { name: 'C#4/Db4 (ド#)', freq: 277.18 },
            { name: 'D4 (レ)', freq: 293.66 }, { name: 'D#4/Eb4 (レ#)', freq: 311.13 }, { name: 'E4 (ミ)', freq: 329.63 }, { name: 'F4 (ファ)', freq: 349.23 }, { name: 'F#4/Gb4 (ファ#)', freq: 369.99 },
            { name: 'G4 (ソ)', freq: 392.00 }, { name: 'G#4/Ab4 (ソ#)', freq: 415.30 }, { name: 'A4 (ラ)', freq: 440.00 }, { name: 'A#4/Bb4 (ラ#)', freq: 466.16 }, { name: 'B4 (シ)', freq: 493.88 },
            { name: 'C5 (ド)', freq: 523.25 }, { name: 'C#5/Db5 (ド#)', freq: 554.37 }, { name: 'D5 (レ)', freq: 587.33 }, { name: 'D#5/Eb5 (レ#)', freq: 622.25 }, { name: 'E5 (ミ)', freq: 659.25 },
            { name: 'F5 (ファ)', freq: 698.46 }, { name: 'F#5/Gb5 (ファ#)', freq: 739.99 }, { name: 'G5 (ソ)', freq: 783.99 }, { name: 'G#5/Ab5 (ソ#)', freq: 830.61 }, { name: 'A5 (ラ)', freq: 880.00 },
            { name: 'A#5/Bb5 (ラ#)', freq: 932.33 }, { name: 'B5 (シ)', freq: 987.77 }, { name: 'C6 (ド)', freq: 1046.50 }, { name: 'C#6/Db6 (ド#)', freq: 1108.73 }, { name: 'D6 (レ)', freq: 1174.66 },
            { name: 'D#6/Eb6 (レ#)', freq: 1244.51 }, { name: 'E6 (ミ)', freq: 1318.51 }, { name: 'F6 (ファ)', freq: 1396.91 }, { name: 'F#6/Gb6 (ファ#)', freq: 1479.98 }, { name: 'G6 (ソ)', freq: 1567.98 },
            { name: 'G#6/Ab6 (ソ#)', freq: 1661.22 }, { name: 'A6 (ラ)', freq: 1760.00 }, { name: 'A#6/Bb6 (ラ#)', freq: 1864.66 }, { name: 'B6 (シ)', freq: 1975.53 }, { name: 'C7 (ド)', freq: 2093.00 },
            { name: 'C#7/Db7 (ド#)', freq: 2217.46 }, { name: 'D7 (レ)', freq: 2349.32 }, { name: 'D#7/Eb7 (レ#)', freq: 2489.02 }, { name: 'E7 (ミ)', freq: 2637.02 }, { name: 'F7 (ファ)', freq: 2793.83 },
            { name: 'F#7/Gb7 (ファ#)', freq: 2959.96 }, { name: 'G7 (ソ)', freq: 3135.96 }, { name: 'G#7/Ab7 (ソ#)', freq: 3322.44 }, { name: 'A7 (ラ)', freq: 3520.00 }, { name: 'A#7/Bb7 (ラ#)', freq: 3729.31 },
            { name: 'B7 (シ)', freq: 3951.07 }, { name: 'C8 (ド)', freq: 4186.01 }
        ];

        function createNoteDiv(note) {
            const div = document.createElement('div');
            div.className = 'note';
            div.textContent = note.name;
            div.dataset.freq = note.freq;

            if (mode === 'click') {
                div.addEventListener('click', handleNoteClick);
            } else if (mode === 'mouseover') {
                div.addEventListener('mouseover', handleNoteMouseOver);
            } else if (mode === 'add') {
                div.addEventListener('click', handleNoteAdd);
            }

            return div;
        }

        function updateNoteDivs() {
            const container = document.getElementById('noteContainer');
            container.innerHTML = '';
            notes.forEach(note => {
                container.appendChild(createNoteDiv(note));
            });
        }

        document.getElementById('toggleMode').addEventListener('click', function() {
            if (mode === 'mouseover') {
                mode = 'click';
                this.textContent = 'Click Mode';
            } else if (mode === 'click') {
                mode = 'add';
                this.textContent = 'Add Note Mode';
            } else if (mode === 'add') {
                mode = 'mouseover';
                this.textContent = 'Mouseover Mode';
            }
            updateNoteDivs(); // モード変更後にupdateNoteDivsを呼び出して正しいリスナーを設定する
        });

        document.getElementById('duration').addEventListener('input', function() {
            document.getElementById('durationValue').textContent = this.value;
        });

        document.getElementById('volume').addEventListener('input', function() {
            document.getElementById('volumeValue').textContent = this.value;
        });

        document.getElementById('playMelody').addEventListener('click', async function() {
            for (let note of melody) {
                await playTone(note.frequency, note.duration, note.volume);
            }
        });

        function handleNoteClick(event) {
            const freq = parseFloat(event.target.dataset.freq);
            const duration = parseFloat(document.getElementById('duration').value);
            const volume = parseFloat(document.getElementById('volume').value);
            playTone(freq, duration, volume);
        }

        function handleNoteMouseOver(event) {
            const freq = parseFloat(event.target.dataset.freq);
            const duration = parseFloat(document.getElementById('duration').value);
            const volume = parseFloat(document.getElementById('volume').value);
            playTone(freq, duration, volume);
        }

        function handleNoteAdd(event) {
            const noteName = event.target.textContent;
            const frequency = parseFloat(event.target.dataset.freq);
            const duration = parseFloat(document.getElementById('duration').value);
            const volume = parseFloat(document.getElementById('volume').value);
            melody.push({ name: noteName, frequency, duration, volume });
            updateMelodyOutput();
        }

        function updateMelodyOutput() {
            const container = document.getElementById('melodyOutput');
            container.innerHTML = '';
            melody.forEach((note, index) => {
                const div = document.createElement('div');
                div.className = 'melody-note';
                div.textContent = `${note.name} - ${note.duration}s - Volume: ${note.volume}`;
                const deleteButton = document.createElement('button');
                deleteButton.textContent = 'Delete';
                deleteButton.addEventListener('click', () => {
                    melody.splice(index, 1);
                    updateMelodyOutput();
                });
                div.appendChild(deleteButton);
                container.appendChild(div);
            });
        }

        function playTone(frequency, duration, volume) {
            return new Promise((resolve) => {
                const oscillator = audioContext.createOscillator();
                const gainNode = audioContext.createGain();

                oscillator.type = 'square';
                oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
                gainNode.gain.setValueAtTime(volume, audioContext.currentTime);

                oscillator.connect(gainNode);
                gainNode.connect(audioContext.destination);

                oscillator.start();
                oscillator.stop(audioContext.currentTime + duration);

                oscillator.onended = resolve;
            });
        }

        updateNoteDivs();
    </script>
</body>
</html>


この記事が気に入ったらサポートをしてみませんか?