mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
audio/vorbis/internal/stb: Use float32 version of decoder for efficiency
This commit is contained in:
parent
9bf2eaff58
commit
de7065bbf7
@ -1,2 +1,2 @@
|
||||
emcc -Os -o stbvorbis.js -g -DSTB_VORBIS_NO_STDIO -s WASM=1 -s EXPORTED_FUNCTIONS='["_stb_vorbis_decode_memory"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]' -s ALLOW_MEMORY_GROWTH=1 stb_vorbis.c
|
||||
emcc -Os -o stbvorbis.js -g -DSTB_VORBIS_NO_INTEGER_CONVERSION -DSTB_VORBIS_NO_STDIO -s WASM=1 -s EXPORTED_FUNCTIONS='["_stb_vorbis_decode_memory_float"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]' -s ALLOW_MEMORY_GROWTH=1 stb_vorbis.c
|
||||
go run genwasmjs.go < stbvorbis.wasm > wasm.js
|
||||
|
@ -34,12 +34,12 @@ func init() {
|
||||
<-ch
|
||||
}
|
||||
|
||||
func DecodeVorbis(buf []byte) ([]int16, int, int, error) {
|
||||
func DecodeVorbis(buf []byte) ([]float32, int, int, error) {
|
||||
r := js.Global().Get("_ebiten").Call("decodeVorbis", buf)
|
||||
if r == js.Null() {
|
||||
return nil, 0, 0, fmt.Errorf("audio/vorbis/internal/stb: decode failed")
|
||||
}
|
||||
data := make([]int16, r.Get("data").Get("length").Int())
|
||||
data := make([]float32, r.Get("data").Get("length").Int())
|
||||
// TODO: Use js.TypeArrayOf
|
||||
arr := js.ValueOf(data)
|
||||
arr.Call("set", r.Get("data"))
|
||||
|
@ -24,7 +24,7 @@ var _ebiten = {};
|
||||
};
|
||||
|
||||
Module.onRuntimeInitialized = () => {
|
||||
decodeMemory = Module.cwrap('stb_vorbis_decode_memory', 'number', ['number', 'number', 'number', 'number', 'number']);
|
||||
decodeMemory = Module.cwrap('stb_vorbis_decode_memory_float', 'number', ['number', 'number', 'number', 'number', 'number']);
|
||||
if (vorbisDecoderInitialized) {
|
||||
vorbisDecoderInitialized();
|
||||
}
|
||||
@ -47,10 +47,10 @@ var _ebiten = {};
|
||||
return a[0];
|
||||
}
|
||||
|
||||
function ptrToInt16s(ptr, length) {
|
||||
const buf = new ArrayBuffer(length * Int16Array.BYTES_PER_ELEMENT);
|
||||
const copied = new Int16Array(buf);
|
||||
copied.set(new Int16Array(Module.HEAPU8.buffer, ptr, length));
|
||||
function ptrToFloat32s(ptr, length) {
|
||||
const buf = new ArrayBuffer(length * Float32Array.BYTES_PER_ELEMENT);
|
||||
const copied = new Float32Array(buf);
|
||||
copied.set(new Float32Array(Module.HEAPU8.buffer, ptr, length));
|
||||
return copied;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ var _ebiten = {};
|
||||
}
|
||||
const channels = ptrToInt32(channelsPtr);
|
||||
const result = {
|
||||
data: ptrToInt16s(ptrToInt32(outputPtr), length * channels),
|
||||
data: ptrToFloat32s(ptrToInt32(outputPtr), length * channels),
|
||||
channels: channels,
|
||||
sampleRate: ptrToInt32(sampleRatePtr),
|
||||
};
|
||||
|
@ -3,4 +3,4 @@
|
||||
|
||||
package stb
|
||||
|
||||
var decode_js = []byte("// Copyright 2018 The Ebiten Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nvar _ebiten = {};\n\n(() => {\n var decodeMemory = null;\n var vorbisDecoderInitialized = null;\n\n _ebiten.initializeVorbisDecoder = (callback) => {\n Module.run();\n vorbisDecoderInitialized = callback;\n };\n\n Module.onRuntimeInitialized = () => {\n decodeMemory = Module.cwrap('stb_vorbis_decode_memory', 'number', ['number', 'number', 'number', 'number', 'number']);\n if (vorbisDecoderInitialized) {\n vorbisDecoderInitialized();\n }\n }\n\n function arrayToHeap(typedArray){\n const ptr = Module._malloc(typedArray.byteLength);\n const heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, typedArray.byteLength);\n heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength));\n return heapBytes;\n }\n\n function ptrToInt32(ptr) {\n const a = new Int32Array(Module.HEAPU8.buffer, ptr, 1);\n return a[0];\n }\n\n function ptrToFloat32(ptr) {\n const a = new Float32Array(Module.HEAPU8.buffer, ptr, 1);\n return a[0];\n }\n\n function ptrToInt16s(ptr, length) {\n const buf = new ArrayBuffer(length * Int16Array.BYTES_PER_ELEMENT);\n const copied = new Int16Array(buf);\n copied.set(new Int16Array(Module.HEAPU8.buffer, ptr, length));\n return copied;\n }\n\n _ebiten.decodeVorbis = (buf) => {\n const copiedBuf = arrayToHeap(buf);\n const channelsPtr = Module._malloc(4);\n const sampleRatePtr = Module._malloc(4);\n const outputPtr = Module._malloc(4);\n const length = decodeMemory(copiedBuf.byteOffset, copiedBuf.length, channelsPtr, sampleRatePtr, outputPtr);\n if (length < 0) {\n return null;\n }\n const channels = ptrToInt32(channelsPtr);\n const result = {\n data: ptrToInt16s(ptrToInt32(outputPtr), length * channels),\n channels: channels,\n sampleRate: ptrToInt32(sampleRatePtr),\n };\n\n Module._free(copiedBuf.byteOffset);\n Module._free(channelsPtr);\n Module._free(sampleRatePtr);\n Module._free(ptrToInt32(outputPtr));\n Module._free(outputPtr);\n return result;\n };\n})();\n")
|
||||
var decode_js = []byte("// Copyright 2018 The Ebiten Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nvar _ebiten = {};\n\n(() => {\n var decodeMemory = null;\n var vorbisDecoderInitialized = null;\n\n _ebiten.initializeVorbisDecoder = (callback) => {\n Module.run();\n vorbisDecoderInitialized = callback;\n };\n\n Module.onRuntimeInitialized = () => {\n decodeMemory = Module.cwrap('stb_vorbis_decode_memory_float', 'number', ['number', 'number', 'number', 'number', 'number']);\n if (vorbisDecoderInitialized) {\n vorbisDecoderInitialized();\n }\n }\n\n function arrayToHeap(typedArray){\n const ptr = Module._malloc(typedArray.byteLength);\n const heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, typedArray.byteLength);\n heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength));\n return heapBytes;\n }\n\n function ptrToInt32(ptr) {\n const a = new Int32Array(Module.HEAPU8.buffer, ptr, 1);\n return a[0];\n }\n\n function ptrToFloat32(ptr) {\n const a = new Float32Array(Module.HEAPU8.buffer, ptr, 1);\n return a[0];\n }\n\n function ptrToFloat32s(ptr, length) {\n const buf = new ArrayBuffer(length * Float32Array.BYTES_PER_ELEMENT);\n const copied = new Float32Array(buf);\n copied.set(new Float32Array(Module.HEAPU8.buffer, ptr, length));\n return copied;\n }\n\n _ebiten.decodeVorbis = (buf) => {\n const copiedBuf = arrayToHeap(buf);\n const channelsPtr = Module._malloc(4);\n const sampleRatePtr = Module._malloc(4);\n const outputPtr = Module._malloc(4);\n const length = decodeMemory(copiedBuf.byteOffset, copiedBuf.length, channelsPtr, sampleRatePtr, outputPtr);\n if (length < 0) {\n return null;\n }\n const channels = ptrToInt32(channelsPtr);\n const result = {\n data: ptrToFloat32s(ptrToInt32(outputPtr), length * channels),\n channels: channels,\n sampleRate: ptrToInt32(sampleRatePtr),\n };\n\n Module._free(copiedBuf.byteOffset);\n Module._free(channelsPtr);\n Module._free(sampleRatePtr);\n Module._free(ptrToInt32(outputPtr));\n Module._free(outputPtr);\n return result;\n };\n})();\n")
|
||||
|
@ -5462,3 +5462,48 @@ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Added by Hajime Hoshi
|
||||
|
||||
int stb_vorbis_decode_memory_float(const uint8 *mem, int len, int *channels, int *sample_rate, float **output) {
|
||||
int data_len, offset, total, limit, error;
|
||||
float* data;
|
||||
stb_vorbis* v = stb_vorbis_open_memory(mem, len, &error, NULL);
|
||||
if (v == NULL) {
|
||||
return -1;
|
||||
}
|
||||
limit = v->channels * 4096;
|
||||
*channels = v->channels;
|
||||
if (sample_rate) {
|
||||
*sample_rate = v->sample_rate;
|
||||
}
|
||||
offset = data_len = 0;
|
||||
total = limit;
|
||||
data = (float*)malloc(total * sizeof(*data));
|
||||
if (data == NULL) {
|
||||
stb_vorbis_close(v);
|
||||
return -2;
|
||||
}
|
||||
for (;;) {
|
||||
int n = stb_vorbis_get_samples_float_interleaved(v, v->channels, data+offset, total-offset);
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
data_len += n;
|
||||
offset += n * v->channels;
|
||||
if (offset + limit > total) {
|
||||
float* data2;
|
||||
total *= 2;
|
||||
data2 = (float*)realloc(data, total * sizeof(*data));
|
||||
if (data2 == NULL) {
|
||||
free(data);
|
||||
stb_vorbis_close(v);
|
||||
return -2;
|
||||
}
|
||||
data = data2;
|
||||
}
|
||||
}
|
||||
*output = data;
|
||||
stb_vorbis_close(v);
|
||||
return data_len;
|
||||
}
|
||||
|
@ -1663,7 +1663,7 @@ var ASM_CONSTS = [];
|
||||
|
||||
STATIC_BASE = GLOBAL_BASE;
|
||||
|
||||
STATICTOP = STATIC_BASE + 3888;
|
||||
STATICTOP = STATIC_BASE + 3776;
|
||||
/* global initializers */ __ATINIT__.push();
|
||||
|
||||
|
||||
@ -1672,7 +1672,7 @@ STATICTOP = STATIC_BASE + 3888;
|
||||
|
||||
|
||||
|
||||
var STATIC_BUMP = 3888;
|
||||
var STATIC_BUMP = 3776;
|
||||
Module["STATIC_BASE"] = STATIC_BASE;
|
||||
Module["STATIC_BUMP"] = STATIC_BUMP;
|
||||
|
||||
@ -1805,7 +1805,7 @@ var _malloc = Module["_malloc"] = function() { return Module["asm"]["_malloc"].
|
||||
var _memcpy = Module["_memcpy"] = function() { return Module["asm"]["_memcpy"].apply(null, arguments) };
|
||||
var _memset = Module["_memset"] = function() { return Module["asm"]["_memset"].apply(null, arguments) };
|
||||
var _sbrk = Module["_sbrk"] = function() { return Module["asm"]["_sbrk"].apply(null, arguments) };
|
||||
var _stb_vorbis_decode_memory = Module["_stb_vorbis_decode_memory"] = function() { return Module["asm"]["_stb_vorbis_decode_memory"].apply(null, arguments) };
|
||||
var _stb_vorbis_decode_memory_float = Module["_stb_vorbis_decode_memory_float"] = function() { return Module["asm"]["_stb_vorbis_decode_memory_float"].apply(null, arguments) };
|
||||
var establishStackSpace = Module["establishStackSpace"] = function() { return Module["asm"]["establishStackSpace"].apply(null, arguments) };
|
||||
var getTempRet0 = Module["getTempRet0"] = function() { return Module["asm"]["getTempRet0"].apply(null, arguments) };
|
||||
var runPostSets = Module["runPostSets"] = function() { return Module["asm"]["runPostSets"].apply(null, arguments) };
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -25,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
type decoderImpl struct {
|
||||
data []int16
|
||||
data []float32
|
||||
channels int
|
||||
sampleRate int
|
||||
}
|
||||
@ -35,13 +35,7 @@ func (d *decoderImpl) Read(buf []float32) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n := len(buf)
|
||||
if n > len(d.data) {
|
||||
n = len(d.data)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
buf[i] = float32(d.data[i]) / 32768
|
||||
}
|
||||
n := copy(buf, d.data)
|
||||
d.data = d.data[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user