<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
html, body {
margin: 20;
padding: 0;
}
canvas {
display: block;
border: solid 1px;
}
/**
* 波形: sin(2πft)
* @param {number} t 時間
* @param {number} freq 周波数
*/
function waveSin2npiFunc(t, freq) {
return Math.sin(2 * Math.PI * freq * t);
}
/**
* 波形: cos(2πft)
* @param {number} t 時間
* @param {number} freq 周波数
*/
function waveCos2npiFunc(t, freq) {
return Math.cos(2 * Math.PI * freq * t);
}
/**
* ボタン類
*/
let playSinButton;
let playCosButton;
/**
* 再生中の波形データ
*/
let playWaveData = [];
/**
* sin波再生ボタン押下
*/
function pushSinPlayButton() {
playWaveData = playSound((t) => waveSin2npiFunc(t, 441));
}
/**
* cos波再生ボタン押下
*/
function pushCosPlayButton() {
playWaveData = playSound((t) => waveCos2npiFunc(t, 441));
}
/**
* 初期化処理
*/
function setup() {
createCanvas(ScreenWidth, ScreenHeight);
// ボタン設定
playSinButton = createButton("Play Sin Wave");
playSinButton.mousePressed(pushSinPlayButton);
playSinButton.position(ScreenWidth - (playSinButton.width), 20);
playCosButton = createButton("Play Cos Wave");
playCosButton.mousePressed(pushCosPlayButton);
playCosButton.position(ScreenWidth - (playCosButton.width), 48);
}
/**
* 描画処理
*/
function draw() {
background(255);
drawGrid();
drawWaveData(playWaveData);
}
// ===== サウンド再生 =====
/**
* サンプルレート
*/
const SampleRate = 44100;
/**
* 再生時間(秒)
*/
const PlaySec = 1;
/**
* 再生中の波形データ
*/
let bufferSource = null;
/**
* サウンド再生処理
* 参考: https://developer.mozilla.org/ja/docs/Web/API/BaseAudioContext/createBuffer
* @param {*} func 波形関数
*/
function playSound(func) {
// stop playing sound.
if (bufferSource) {
bufferSource.stop();
}
// create context.
let audioCtx = new AudioContext();
audioCtx.sampleRate = SampleRate;
// create mono channel buffer.
let buffer = audioCtx.createBuffer(1, PlaySec * SampleRate, SampleRate);
let channelData = buffer.getChannelData(0);
for (var i = 0; i < buffer.length; i++) {
let playSec = i / SampleRate;
channelData[i] = func(playSec);
}
// set play wave data.
let playWaveData = channelData;
// play sound.
bufferSource = audioCtx.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(audioCtx.destination);
bufferSource.start();
return playWaveData;
}
// ===== グリッド描画・プロット =====
/**
* 画面設定
*/
const ScreenWidth = 400;
const ScreenHeight = 400;
/**
* 座標の表示範囲
*/
const MinGridValueY = -5;
const MaxGridValueY = 5;
const MinGridValueX = 0;
const MaxGridValueX = 0.005;
/**
* グリッドの描画
*/
function drawGrid() {
strokeWeight(2);
let dx = MaxGridValueX / 10;
let dy = MaxGridValueY / 10;
for (let x = MinGridValueX; x < MaxGridValueX; x+=dx) {
for (let y = MinGridValueY; y < MaxGridValueY; y+=dy) {
// 縦線
stroke(240, 240, 240);
drawLineCanvas(x+dx, y, x+dx, y+dy);
// 横線
stroke(180, 180, 180);
drawLineCanvas(x, y+dy, x+dx, y+dy);
}
}
// 中央線
stroke(120, 120, 120);
drawLineCanvas(MinGridValueX, 0, MaxGridValueX, 0);
drawLineCanvas(0, MinGridValueY, 0, MaxGridValueY);
}
/**
* 波形データを描画
* @param {number[]} waveData 波形データ
*/
function drawWaveData(waveData) {
strokeWeight(4);
stroke(0, 0, 255);
for (let i = 0; i < waveData.length; i++) {
// 最大秒数を超えたらスキップ
if (i / SampleRate > MaxGridValueX) {
break;
}
if (i == waveData.length - 1) {
break;
}
// 次のデータと繋げる
let data = waveData[i];
let time = i / SampleRate;
let nextData = waveData[i + 1];
let nextTime = (i + 1) / SampleRate;
drawLineCanvas(time, data, nextTime, nextData);
}
}
/**
* 関数の描画
* @param {(t: number) => number} func 関数
*/
function drawFunc(func) {
strokeWeight(4);
stroke(0, 0, 255);
let dx = MaxGridValueX / 100;
for (let x = 0; x < MaxGridValueX; x+=dx) {
drawLineCanvas(x, func(x), (x+dx), func(x+dx));
}
}
/**
* 受け取った座標位置で線を繋げて表示する
* @param {number} fromX
* @param {number} fromY
* @param {number} toX
* @param {number} toY
*/
function drawLineCanvas(fromX, fromY, toX, toY) {
fromX *= ScreenWidth/(MaxGridValueX-MinGridValueX);
fromY *= ScreenHeight/(MaxGridValueY-MinGridValueY);
toX *= ScreenWidth/(MaxGridValueX-MinGridValueX)
toY *= ScreenHeight/(MaxGridValueY-MinGridValueY);
let offset = [0, ScreenHeight/2]; // Y軸は反転させる
line(fromX+offset[0], ScreenHeight-(fromY+offset[1]), toX+offset[0], ScreenHeight-(toY+offset[1]));
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.