-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
146 lines (116 loc) · 4 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @module audio-shader
*/
var Through = require('audio-through');
var inherits = require('inherits');
var createShader = require('nogl-shader-output');
var createContext = require('nogl');
var Shader = require('gl-shader');
/**
* @constructor
*
* @param {Function} fn Shader code
* @param {Object} options Options
*/
function AudioShader (shaderCode, options) {
if (!(this instanceof AudioShader)) return new AudioShader(shaderCode, options);
options = options || {};
Through.call(this, options);
//refine number of channels - vec4 is max output
var channels = this.format.channels = Math.min(this.format.channels, 4);
//refine shader code, if not passed
if (!shaderCode) {
var vecType = channels === 1 ? 'float' : ('vec' + channels);
shaderCode = `${vecType} mainSound( float time ){
return ${vecType}( sin(6.2831*440.0*time)*exp(-3.0*time) );
}`;
}
var gl = options.gl || createContext();
var shader = Shader(gl, `
precision mediump float;
precision mediump int;
attribute vec2 position;
uniform float iGlobalTime;
uniform float iSampleRate;
uniform vec3 iResolution;
varying float time;
void main (void) {
gl_Position = vec4(position, 0, 1);
time = iGlobalTime + (position.x * 0.5 + 0.5) * iResolution.x / iSampleRate;
}
`, `
precision mediump float;
precision mediump int;
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform float iGlobalTime; // shader playback time (in seconds)
uniform int iFrame; // shader playback frame
uniform vec4 iDate; // (year, month, day, time in seconds)
uniform float iSampleRate; // sound sample rate (i.e., 44100)
uniform vec3 iChannelResolution[4]; // channel resolution (in pixels)
// uniform sampler2D iChannel0; // input channel1
// uniform sampler2D iChannel1; // input channel2
// uniform sampler2D iChannel2; // input channel3
// uniform sampler2D iChannel3; // input channel4
varying float time;
${shaderCode}
void main (void) {
vec4 result = vec4(mainSound(time)${
channels === 1 ? ', 0, 0, 0' :
channels === 3 ? ', 0' :
channels === 4 ? '' : ', 0, 0'
});
gl_FragColor = result;
}`);
//setup shader
this.draw = createShader(shader, {
width: this.format.samplesPerFrame,
height: 1
});
//clean on end
this.on('end', function () {
throw Error('Unimplemented');
});
}
inherits(AudioShader, Through);
/**
* Send chunk to audio-shader, invoke done on return.
* The strategy: render each audio channel to it’s own line in result
* TODO: thing to replace with textures
* TODO: provide input channels as textures
* TODO: provide values of previous input/output to implement filters
*/
AudioShader.prototype.process = function (chunk, done) {
var w = this.format.samplesPerFrame;
var channels = Math.min(chunk.numberOfChannels, this.format.channels);
//set up current chunk as a channels data
// for (var channel = 0; channel < channels; channel++) {
// var texture = new Texture(gl, chunk.getChannelData(channel));
// this.shader.uniforms[`iChannel${channel}`] = texture.bind();
// this.shader.uniforms.iChannelResolution[channel] = [chunk.length, 1, 1];
// this.shader.uniforms.iChannelTime[channel] = [];
// }
//preset new time value
var d = new Date();
//render chunk
var result = this.draw({
iResolution: [w, 1, 1],
iSampleRate: this.format.sampleRate,
iGlobalTime: this.time,
iFrame: this.frame,
iDate: [
d.getFullYear(), // the year (four digits)
d.getMonth(), // the month (from 0-11)
d.getDate(), // the day of the month (from 1-31)
d.getHours()*60.0*60 + d.getMinutes()*60 + d.getSeconds()
]
});
//transform result to buffer channels (color channel per audio channel)
for (var channel = 0; channel < channels; channel++) {
var cData = chunk.getChannelData(channel);
for (var i = 0; i < w; i++) {
cData[i] = result[i * 4 + channel];
}
}
done();
}
module.exports = AudioShader;