Help us understand the problem. What is going on with this article?

threeでsound

More than 1 year has passed since last update.

threeで実装してみた。

サンプルコード

```const DURATION = 6;
const WIDTH = 512;
const HEIGHT = 512;
precision mediump float;
uniform float iSampleRate;
uniform float iBlockOffset;
#define PI              3.1415926535
#define A               0.0
#define B               2.0
#define C               3.0
#define D               5.0
#define E               7.0
#define F               8.0
#define G               10.0
float rand(vec2 co)
{
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}
float calcHertz(float scale)
{
return 441.0 * pow(2.0, scale / 12.0) * PI;
}
float calcHertz(float octave, float note)
{
return calcHertz(octave * 12.0 + note);
}
float rect(float time)
{
return sign(fract(time / PI / 2.0) - 0.5);
}
float rect2(float time)
{
return sign(fract(time / PI / 2.0) - 0.25);
}
float rect3(float time)
{
return sign(fract(time / PI / 2.0) - 0.125);
}
float eg(float time, float gate)
{
return  exp(-gate * (time));
}
#define Sin1(u, v)          sound += clamp(sin(time * calcHertz(u, v)) * (1.0 - localTime2 + sin(time * 80.0) * 0.1), -0.3, 0.3);
#define Rect1(u, v, l)      sound += rect(time * calcHertz(u, v)) * l;
#define Rect2(u, v, l)      sound += rect2(time * calcHertz(u, v)) * l;
#define Rect3(u, v, l)      sound += rect3(time * calcHertz(u, v)) * l;
#define BD_Rect1(u, v, l)   sound += rect(time * calcHertz(u, v +  eg(localTime2, 2.0))) * l;
vec2 mainSound(float time)
{
float localTime = mod(time * 0.5 , 8.0);
float localTime2 = mod(localTime , 1.0);
vec2 sound = vec2(0.0);
if (rand(vec2 (localTime2)) * 2.0 > 0.2)
{
localTime2 = mod(localTime * 16.0, 1.0);
BD_Rect1(0.0, C, eg(localTime2, 8.0));
}
if (localTime < 2.0)
{
localTime2 = mod(localTime * 2.0, 1.0);
float op0 = sin(1.0 * calcHertz(1.0, C) * time) * eg(localTime2, 1.0);
float op1 = sin(1.14 * op0) * eg(localTime2, 2.0);
float op2 = sin(1.5 * calcHertz(1.0, C) * time) * eg(localTime2, 5.0);
float op3 = sin(2.14 * op2) * eg(localTime2, 2.0);
sound += vec2(op1 * 0.5 + op3 * 0.5);
}
else if (localTime < 4.0)
{
localTime2 = mod(localTime * 2.0, 1.0);
float op0 = sin(8.0 * calcHertz(1.0, C) * time) * eg(localTime2, 3.0);
float op1 = sin(6.5 * op0) *  eg(localTime2, 1.0);
float op2 = sin(3.14 * calcHertz(1.0, C) * time) * eg(localTime2, 1.0);
float op3 = sin(6.5 * op2) *  eg(localTime2, 1.0);
sound += vec2(op1 * 0.5 + op3 * 0.5);
}
else if (localTime < 6.0)
{
localTime2 = mod(localTime * 1.0, 1.0);
Rect1(0.0, C, eg(localTime2, 1.0));
Rect1(1.0, E, eg(localTime2, 1.0));
Rect1(1.0, G, eg(localTime2, 1.0));
Rect1(1.0, B, eg(localTime2, 1.0));
sound *= 0.25;
}
else if (localTime < 7.0)
{
localTime2 = mod(localTime * 3.0, 1.0);
Rect2(0.0, C, eg(localTime2, 1.0));
Rect2(1.0, E, eg(localTime2, 1.0));
Rect2(1.0, F, eg(localTime2, 1.0));
Rect2(1.0, A, eg(localTime2, 1.0));
sound *= 0.25;
}
else if (localTime < 8.0)
{
localTime2 = mod(localTime * 6.0, 1.0);
Rect3(0.0, G, eg(localTime2, 2.0));
Rect3(2.0, E, eg(localTime2, 2.0));
Rect3(1.0, F, eg(localTime2, 3.0));
Rect3(1.0, B, eg(localTime2, 3.0));
sound *= 0.25;
}
return vec2(sound);
}
void main()
{
float t = iBlockOffset + ((gl_FragCoord.x - 0.5) + (gl_FragCoord.y - 0.5) * 512.0) / iSampleRate;
vec2 y = mainSound(t);
vec2 v  = floor((0.5 + 0.5 * y) * 65536.0);
vec2 vl = mod(v, 256.0) / 255.0;
vec2 vh = floor(v / 256.0) / 255.0;
gl_FragColor = vec4(vl.x, vh.x, vl.y, vh.y);
}`;
const ctx = new window.AudioContext();
const node = ctx.createBufferSource();
node.connect(ctx.destination);
node.loop = true;
const audioBuffer = ctx.createBuffer(2, ctx.sampleRate * DURATION, ctx.sampleRate);
const canvas = document.createElement('canvas');
canvas.width = WIDTH;
canvas.height = HEIGHT;
const renderer = new THREE.WebGLRenderer({
canvas,
alpha: true
});
const wctx = renderer.getContext();
const uniforms = {
iBlockOffset: {
type: 'f',
value: 0.0
},
iSampleRate: {
type: 'f',
value: ctx.sampleRate
},
};
const geometry = new THREE.PlaneGeometry(2, 2);
uniforms,
});
const plane = new THREE.Mesh(geometry, material);
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
camera.position.set(0, 0, 1);
camera.lookAt(scene.position);
const target = new THREE.WebGLRenderTarget(WIDTH, HEIGHT);
const samples = WIDTH * HEIGHT;
const numBlocks = (ctx.sampleRate * DURATION) / samples;
for (let i = 0; i < numBlocks; i++)
{
uniforms.iBlockOffset.value = i * samples / ctx.sampleRate;
renderer.render(scene, camera, target, true);
const pixels = new Uint8Array(WIDTH * HEIGHT * 4);
wctx.readPixels(0, 0, WIDTH, HEIGHT, wctx.RGBA, wctx.UNSIGNED_BYTE, pixels);
const outputDataL = audioBuffer.getChannelData(0);
const outputDataR = audioBuffer.getChannelData(1);
for (let j = 0; j < samples; j++)
{
outputDataL[i * samples + j] = (pixels[j * 4 + 0] + 256 * pixels[j * 4 + 1]) / 65535 * 2 - 1;
outputDataR[i * samples + j] = (pixels[j * 4 + 2] + 256 * pixels[j * 4 + 3]) / 65535 * 2 - 1;
}
}
node.buffer = audioBuffer;
node.start(0);

```

成果物

http://jsdo.it/ohisama1/wk5b

Why do not you register as a user and use Qiita more conveniently?
1. We will deliver articles that match you
By following users and tags, you can catch up information on technical fields that you are interested in as a whole
2. you can read useful information later efficiently
By "stocking" the articles you like, you can search right away