203 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // from https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletNode
 | |
| 
 | |
| function create_thread(func) {
 | |
| 
 | |
| }
 | |
| 
 | |
| class AudioThread extends AudioWorkletProcessor {
 | |
|   constructor(options) {
 | |
|     super();
 | |
| 
 | |
|     const self = this;
 | |
| 
 | |
|     this.port.onmessageerror = (e) => {
 | |
|       this.port.postMessage('Error: ' + JSON.stringify(e));
 | |
|     };
 | |
| 
 | |
|     const mod = options.processorOptions.mod;
 | |
|     const memory = options.processorOptions.memory;
 | |
|     
 | |
|     const importObject = {
 | |
|       env: { memory },
 | |
|       imports: {
 | |
|         imported_func: arg => console.log('thread: ' + arg),
 | |
|         create_thread,
 | |
|         glViewport: function(x, y, width, height) { },
 | |
|         glScissor: function(x, y, width, height) { },
 | |
|         glGetIntegerv: function(pname, data) { },
 | |
|         glGetFloatv: function(pname, data) { },
 | |
|         glGetString: function(name) { },
 | |
|         glDrawElements: function(mode, count, type, offset) { },
 | |
|         glDrawElementsInstanced: function(mode, count, type, indices, instancecount) { },
 | |
|         glVertexAttribDivisor: function(index, divisor) { },
 | |
|         glBindFramebuffer: function(target, framebuffer) { },
 | |
|         glFramebufferTexture2D: function(target, attachment, textarget, texture, level) { },
 | |
|         glGenFramebuffers: function(n, framebuffers) { },
 | |
|         glGenRenderbuffers: function(n, renderbuffers) { },
 | |
|         glBindRenderbuffer: function(target, renderbuffer) { },
 | |
|         glRenderbufferStorage: function(target, internalformat, width, height) { },
 | |
|         glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) { },
 | |
|         glReadPixels: function(x, y, width, height, format, type, data) { },
 | |
|         glTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, type, pixels) { },
 | |
|         glEnable: function(cap) { },
 | |
|         glDisable: function(cap) { },
 | |
|         glColorMask: function(red, green, blue, alpha) { },
 | |
|         glClearColor: function(red, green, blue, alpha) { },
 | |
|         glDepthMask: function(flag) { },
 | |
|         glClearDepthf: function(depth) { },
 | |
|         glStencilMask: function(mask) { },
 | |
|         glClearStencil: function(s) { },
 | |
|         glClear: function(mask) { },
 | |
|         glBindBuffer: function(target, buffer) { },
 | |
|         glUseProgram: function(program) { },
 | |
|         glStencilMaskSeparate: function(face, mask) { },
 | |
|         glStencilOpSeparate: function(face, fail, zfail, zpass) { },
 | |
|         glStencilFuncSeparate: function(face, func, ref, mask) { },
 | |
|         glDepthFunc: function(func) { },
 | |
|         glCullFace: function(mode) { },
 | |
|         glBlendFuncSeparate: function(src_rgb, dst_rgb, src_alpha, dst_alpha) { },
 | |
|         glBlendEquationSeparate: function(mode_rgb, mode_alpha) { },
 | |
|         glGenBuffers: function(n, buffers) { },
 | |
|         glBufferData: function(target, size, data, usage) { },
 | |
|         glCreateProgram: function() { },
 | |
|         glAttachShader: function(program, shader) { },
 | |
|         glBindAttribLocation: function(program, index, name) { },
 | |
|         glLinkProgram: function(program) { },
 | |
|         glGetProgramiv: function(program, pname, params) { },
 | |
|         glGetProgramInfoLog: function(program) { },
 | |
|         glCreateShader: function(type) { },
 | |
|         glShaderSource: function(shader, count, source, length) { },
 | |
|         glCompileShader: function(shader) { },
 | |
|         glGetShaderiv: function(shader, pname, params) { },
 | |
|         glGetShaderInfoLog: function(shader) { },
 | |
|         glBufferSubData: function(target, offset, size, data) { },
 | |
|         glEnableVertexAttribArray: function(index) { },
 | |
|         glVertexAttribPointer: function(index, size, type, normalized, stride, offset) { },
 | |
|         glDisableVertexAttribArray: function(index) { },
 | |
|         glGetUniformLocation: function(program, name) { },
 | |
|         glUniform1i: function(location, v0) { },
 | |
|         glUniform2i: function(location, v0, v1) { },
 | |
|         glUniform3i: function(location, v0, v1, v2) { },
 | |
|         glUniform4i: function(location, v0, v1, v2, v3) { },
 | |
|         glUniform1iv: function(location, count, value) { },
 | |
|         glUniform2iv: function(location, count, value) { },
 | |
|         glUniform3iv: function(location, count, value) { },
 | |
|         glUniform4iv: function(location, count, value) { },
 | |
|         glUniform1f: function(location, v0) { },
 | |
|         glUniform2f: function(location, v0, v1) { },
 | |
|         glUniform3f: function(location, v0, v1, v2) { },
 | |
|         glUniform4f: function(location, v0, v1, v2, v3) { },
 | |
|         glUniform1fv: function(location, count, value) { },
 | |
|         glUniform2fv: function(location, count, value) { },
 | |
|         glUniform3fv: function(location, count, value) { },
 | |
|         glUniform4fv: function(location, count, value) { },
 | |
|         glUniformMatrix3fv: function(location, count, transpose, value) { },
 | |
|         glUniformMatrix4fv: function(location, count, transpose, value) { },
 | |
|         glTexParameterf: function(target, pname, param) { },
 | |
|         glActiveTexture: function(texture) { },
 | |
|         glBindTexture: function(target, texture) { },
 | |
|         glTexParameteri: function(target, pname, param) { },
 | |
|         glGetActiveUniform: function(program, index, bufSize, length, size, type, name) { },
 | |
|         glGenTextures: function(n, textures) { },
 | |
|         glTexImage2D: function(target, level, internalformat, width, height, border, format, type, data) { },
 | |
|         glPixelStorei: function(pname, param) { },
 | |
|         glCompressedTexImage2D: function(target, level, internalformat, width, height, border, imageSize, data) { },
 | |
|         glDrawBuffers: function(n, bufs) { },
 | |
|         glGenerateMipmap: function(target) { },
 | |
|         glFlush: function() { },
 | |
|         glDeleteBuffers: function(n, buffers) { },
 | |
|         glDeleteTextures: function(n, textures) { },
 | |
|         glDeleteFramebuffers: function(n, framebuffers) { },
 | |
|         glDeleteProgram: function(program) { },
 | |
|         glDeleteShader: function(shader) { },
 | |
|         js_fprintf: function(format) {
 | |
|           console.log(read_string(format));
 | |
|         },
 | |
|         js_fopen: function(filename) {
 | |
|           return 0;
 | |
|         },
 | |
|         js_ftell: function(stream) {
 | |
|           return 0;
 | |
|         },
 | |
|         js_fseek: function(stream, offset, origin) {
 | |
|           return 0;
 | |
|         },
 | |
|         js_fread: function(ptr, size, count, stream) {
 | |
|           return 0;
 | |
|         },
 | |
|         js_time: function() {
 | |
|           return window.performance.now();
 | |
|         },
 | |
|         js_pow: function(x) {
 | |
|           return Math.pow(x);
 | |
|         },
 | |
|         js_floor: function(x) {
 | |
|           return Math.floor(x);
 | |
|         },
 | |
|         js_sin: function(x) {
 | |
|           return Math.sin(x);
 | |
|         },
 | |
|         js_cos: function(x) {
 | |
|           return Math.cos(x);
 | |
|         },
 | |
|         js_tan: function(x) {
 | |
|           return Math.tan(x);
 | |
|         },
 | |
|         js_log: function(base, exponent) {
 | |
|           return Math.log(base, exponent);
 | |
|         },
 | |
|         js_exp: function(x) {
 | |
|           return Math.exp(x);
 | |
|         },
 | |
|         js_sqrt: function(x) {
 | |
|           return Math.sqrt(x);
 | |
|         },
 | |
|         js_eval: function(str) { }
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     WebAssembly.instantiate(mod, importObject).then((instance) => {
 | |
|       this.port.postMessage('Running audio thread');
 | |
|       self.audio_func = instance.exports.audio_func;
 | |
|       self.audio_pointer = instance.exports.malloc(16 * 1024);
 | |
|       this.port.postMessage('Audio pointer: ' + self.audio_pointer);
 | |
|       this.port.postMessage('Memory byteLength: ' + memory.buffer.byteLength);
 | |
|       self.audio_data = new Float32Array(
 | |
|         memory.buffer,
 | |
|         self.audio_pointer,
 | |
|         16 * 256
 | |
|       );
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   process(inputs, outputs, parameters) {
 | |
|     const output = outputs[0];
 | |
| 
 | |
|     const data = output[0];
 | |
| 
 | |
|     //for (let i = 0; i < data.length; ++i) {
 | |
|     //  data[i] = Math.random() * 2 - 1;
 | |
|     //}
 | |
| 
 | |
|     if (this.audio_func) {
 | |
|       let offset = 0;
 | |
|       for (;;) {
 | |
|         const length = Math.min(data.length - offset, this.audio_data.length);
 | |
|         this.audio_func(this.audio_pointer + offset, length);
 | |
|         for (let i = 0; i < length; ++i) {
 | |
|           data[offset + i] = this.audio_data[i];
 | |
|         }
 | |
| 
 | |
|         if (offset + this.audio_data.length >= data.length) {
 | |
|           break;
 | |
|         }
 | |
|         offset += this.audio_data.length;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| }
 | |
| 
 | |
| registerProcessor('audio-thread', AudioThread);
 |