├── app ├── test.d.ts ├── speex_wasm.d.ts ├── index.d.ts ├── test.js └── index.js ├── deps └── speex │ ├── readme.md │ ├── AUTHORS │ ├── COPYING │ ├── stack_alloc.h │ ├── resample_sse.h │ ├── fixed_generic.h │ ├── os_support.h │ ├── arch.h │ ├── resample_neon.h │ ├── speex_resampler.h │ └── resample.c ├── .npmignore ├── resources ├── 24000hz_test.pcm ├── 44100hz_test.pcm └── 24000hz_mono_test.pcm ├── .gitignore ├── tsconfig.json ├── package.json ├── scripts └── build_emscripten.sh ├── LICENSE ├── Readme.md └── src ├── test.ts ├── index.ts └── speex_wasm.js /app/test.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /deps/speex/readme.md: -------------------------------------------------------------------------------- 1 | This was copied from https://git.xiph.org/speexdsp.git. 2 | -------------------------------------------------------------------------------- /app/speex_wasm.d.ts: -------------------------------------------------------------------------------- 1 | export default Speex; 2 | declare function Speex(Speex: any): any; 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | resources/* 2 | build/* 3 | prebuilds/* 4 | .vscode 5 | .github 6 | deps 7 | scripts 8 | .envrc 9 | -------------------------------------------------------------------------------- /resources/24000hz_test.pcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekuillaume/node-speex-resampler/HEAD/resources/24000hz_test.pcm -------------------------------------------------------------------------------- /resources/44100hz_test.pcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekuillaume/node-speex-resampler/HEAD/resources/44100hz_test.pcm -------------------------------------------------------------------------------- /resources/24000hz_mono_test.pcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekuillaume/node-speex-resampler/HEAD/resources/24000hz_mono_test.pcm -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | prebuilds 3 | resources/*_output.pcm 4 | node_modules 5 | .vscode 6 | CMakeCache.txt 7 | cmake_install.cmake 8 | CMakeFiles 9 | scripts/dockcross* 10 | .envrc 11 | -------------------------------------------------------------------------------- /deps/speex/AUTHORS: -------------------------------------------------------------------------------- 1 | Jean-Marc Valin 2 | All the code except the following 3 | 4 | David Rowe 5 | lsp.c lsp.h 6 | Also ideas and feedback 7 | 8 | John Francis Edwards 9 | wave_out.[ch], some #ifdefs for windows port and MSVC project files 10 | 11 | Segher Boessenkool 12 | Misc. optimizations (for QMF in particular) 13 | 14 | Atsuhiko Yamanaka : 15 | Patch to speexenc.c to add Vorbis comment format 16 | 17 | Radim Kolar : 18 | Patch to speexenc.c for supporting more input formats 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "esModuleInterop": true, 5 | "allowSyntheticDefaultImports": true, 6 | "target": "ES2019", 7 | "noImplicitAny": false, 8 | "moduleResolution": "node", 9 | "allowJs": true, 10 | "outDir": "app", 11 | "baseUrl": "src", 12 | "resolveJsonModule": true, 13 | "skipLibCheck": true, 14 | "declaration": true, 15 | 16 | "sourceRoot": "/", 17 | "inlineSources": true, 18 | "inlineSourceMap": true 19 | }, 20 | "include": [ 21 | "src/**/*" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "speex-resampler", 3 | "version": "3.0.1", 4 | "description": "An WebAssembly implementation of Speex audio resampler", 5 | "main": "app/index.js", 6 | "types": "app/index.d.ts", 7 | "scripts": { 8 | "build": "tsc -b", 9 | "build:watch": "tsc -w", 10 | "deploy": "np --no-tests", 11 | "test": "node app/test.js" 12 | }, 13 | "author": "Guillaume Besson ", 14 | "repository": "https://github.com/geekuillaume/node-speex-resampler", 15 | "keywords": [ 16 | "audio", 17 | "resampling", 18 | "pcm", 19 | "speex", 20 | "wasm" 21 | ], 22 | "license": "MIT", 23 | "devDependencies": { 24 | "@types/emscripten": "^1.39.4", 25 | "np": "^6.2.1", 26 | "typescript": "^3.9.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /scripts/build_emscripten.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | emcc \ 5 | -s INITIAL_MEMORY=20MB \ 6 | -s ALLOW_MEMORY_GROWTH=1 \ 7 | -O3 -o src/speex_wasm.js \ 8 | -s EXPORT_ES6=1 \ 9 | -s MODULARIZE=1 \ 10 | -s SINGLE_FILE=1 \ 11 | -s EXPORT_NAME="Speex" \ 12 | -s NO_DYNAMIC_EXECUTION=1 \ 13 | -s USE_ES6_IMPORT_META=0 \ 14 | -s FILESYSTEM=0 \ 15 | -s ASSERTIONS=0 \ 16 | -s EXPORTED_RUNTIME_METHODS="['setValue', 'getValue', 'AsciiToString']" \ 17 | -s ENVIRONMENT=node,web \ 18 | -D FLOATING_POINT=true \ 19 | -D OUTSIDE_SPEEX=true \ 20 | -s EXPORTED_FUNCTIONS="['_malloc', '_free', '_speex_resampler_destroy','_speex_resampler_init','_speex_resampler_get_rate','_speex_resampler_process_interleaved_int','_speex_resampler_strerror']" \ 21 | --llvm-lto 1 \ 22 | ./deps/speex/resample.c 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Guillaume Besson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Speex Resampler 2 | 3 | This lib exposes the [Speex resampler](https://speex.org/docs/manual/speex-manual/node7.html) to Javascript with WebAssembly. It doesn't have any dependancy and support NodeJS or a WebContext. Typescript typings are also provided. 4 | 5 | From speex creator, the design goals of the resampler are: 6 | - Very fast algorithm 7 | - SIMD-friendly algorithm 8 | - Low memory requirement 9 | - Good *perceptual* quality (and not best SNR) 10 | 11 | ## How to use 12 | 13 | ```js 14 | await SpeexResampler.initPromise; // will be resolved once the WASM module has been compiled, before this you cannot call the SpeexResampler processChunk method 15 | 16 | const channels = 2; // minimum is 1, no maximum 17 | const inRate = 44100; // frequency in Hz for the input chunk 18 | const outRate = 44000; // frequency in Hz for the target chunk 19 | const quality = 7; // number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 20 | // you need a new resampler for every audio stream you want to resample 21 | // it keeps data from previous calls to improve the resampling 22 | const resampler = new SpeexResampler( 23 | channels, 24 | audioTest.inRate, 25 | audioTest.outRate, 26 | audioTest.quality // optionnal 27 | ); 28 | 29 | const pcmData = Buffer.from(/* interleaved PCM data in signed 16bits int */); 30 | const res = await resampler.processChunk(pcmData); 31 | // res is also a buffer with interleaved signed 16 bits PCM data 32 | ``` 33 | 34 | You can look at the `src/test.ts` for more information. 35 | 36 | Test music by https://www.bensound.com 37 | -------------------------------------------------------------------------------- /deps/speex/COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2002-2008 Xiph.org Foundation 2 | Copyright 2002-2008 Jean-Marc Valin 3 | Copyright 2005-2007 Analog Devices Inc. 4 | Copyright 2005-2008 Commonwealth Scientific and Industrial Research 5 | Organisation (CSIRO) 6 | Copyright 1993, 2002, 2006 David Rowe 7 | Copyright 2003 EpicGames 8 | Copyright 1992-1994 Jutta Degener, Carsten Bormann 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions 12 | are met: 13 | 14 | - Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 17 | - Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | - Neither the name of the Xiph.org Foundation nor the names of its 22 | contributors may be used to endorse or promote products derived from 23 | this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 29 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | -------------------------------------------------------------------------------- /app/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Transform } from 'stream'; 3 | declare class SpeexResampler { 4 | channels: any; 5 | inRate: any; 6 | outRate: any; 7 | quality: number; 8 | _resamplerPtr: number; 9 | _inBufferPtr: number; 10 | _inBufferSize: number; 11 | _outBufferPtr: number; 12 | _outBufferSize: number; 13 | _inLengthPtr: number; 14 | _outLengthPtr: number; 15 | static initPromise: Promise; 16 | /** 17 | * Create an SpeexResampler tranform stream. 18 | * @param channels Number of channels, minimum is 1, no maximum 19 | * @param inRate frequency in Hz for the input chunk 20 | * @param outRate frequency in Hz for the target chunk 21 | * @param quality number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 22 | */ 23 | constructor(channels: any, inRate: any, outRate: any, quality?: number); 24 | /** 25 | * Resample a chunk of audio. 26 | * @param chunk interleaved PCM data in signed 16bits int 27 | */ 28 | processChunk(chunk: Buffer): Buffer; 29 | } 30 | export declare class SpeexResamplerTransform extends Transform { 31 | channels: any; 32 | inRate: any; 33 | outRate: any; 34 | quality: number; 35 | resampler: SpeexResampler; 36 | _alignementBuffer: Buffer; 37 | /** 38 | * Create an SpeexResampler instance. 39 | * @param channels Number of channels, minimum is 1, no maximum 40 | * @param inRate frequency in Hz for the input chunk 41 | * @param outRate frequency in Hz for the target chunk 42 | * @param quality number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 43 | */ 44 | constructor(channels: any, inRate: any, outRate: any, quality?: number); 45 | _transform(chunk: any, encoding: any, callback: any): void; 46 | } 47 | export default SpeexResampler; 48 | -------------------------------------------------------------------------------- /deps/speex/stack_alloc.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002 Jean-Marc Valin */ 2 | /** 3 | @file stack_alloc.h 4 | @brief Temporary memory allocation on stack 5 | */ 6 | /* 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | - Neither the name of the Xiph.org Foundation nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef STACK_ALLOC_H 36 | #define STACK_ALLOC_H 37 | 38 | #ifdef USE_ALLOCA 39 | # ifdef WIN32 40 | # include 41 | # else 42 | # ifdef HAVE_ALLOCA_H 43 | # include 44 | # else 45 | # include 46 | # endif 47 | # endif 48 | #endif 49 | 50 | /** 51 | * @def ALIGN(stack, size) 52 | * 53 | * Aligns the stack to a 'size' boundary 54 | * 55 | * @param stack Stack 56 | * @param size New size boundary 57 | */ 58 | 59 | /** 60 | * @def PUSH(stack, size, type) 61 | * 62 | * Allocates 'size' elements of type 'type' on the stack 63 | * 64 | * @param stack Stack 65 | * @param size Number of elements 66 | * @param type Type of element 67 | */ 68 | 69 | /** 70 | * @def VARDECL(var) 71 | * 72 | * Declare variable on stack 73 | * 74 | * @param var Variable to declare 75 | */ 76 | 77 | /** 78 | * @def ALLOC(var, size, type) 79 | * 80 | * Allocate 'size' elements of 'type' on stack 81 | * 82 | * @param var Name of variable to allocate 83 | * @param size Number of elements 84 | * @param type Type of element 85 | */ 86 | 87 | #ifdef ENABLE_VALGRIND 88 | 89 | #include 90 | 91 | #define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) 92 | 93 | #define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) 94 | 95 | #else 96 | 97 | #define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) 98 | 99 | #define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) 100 | 101 | #endif 102 | 103 | #if defined(VAR_ARRAYS) 104 | #define VARDECL(var) 105 | #define ALLOC(var, size, type) type var[size] 106 | #elif defined(USE_ALLOCA) 107 | #define VARDECL(var) var 108 | #define ALLOC(var, size, type) var = alloca(sizeof(type)*(size)) 109 | #else 110 | #define VARDECL(var) var 111 | #define ALLOC(var, size, type) var = PUSH(stack, size, type) 112 | #endif 113 | 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | import {readFileSync, writeFileSync,createReadStream} from 'fs'; 2 | // const {promisify} = require('util'); 3 | import { performance } from 'perf_hooks' 4 | import path from 'path'; 5 | 6 | import SpeexResampler, {SpeexResamplerTransform} from './index'; 7 | 8 | const assert = (condition, message) => { 9 | if (!condition) { 10 | throw new Error(message); 11 | } 12 | } 13 | 14 | const audioTests = [ 15 | {inFile: path.resolve(__dirname, `../resources/24000hz_mono_test.pcm`), inRate: 24000, outRate: 48000, channels: 1, quality: 5}, 16 | {inFile: path.resolve(__dirname, `../resources/24000hz_test.pcm`), inRate: 24000, outRate: 24000, channels: 2, quality: 5}, 17 | {inFile: path.resolve(__dirname, `../resources/24000hz_test.pcm`), inRate: 24000, outRate: 48000, channels: 2, quality: 10}, 18 | {inFile: path.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 48000, channels: 2}, 19 | {inFile: path.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 48000, channels: 2, quality: 10}, 20 | {inFile: path.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 48000, channels: 2, quality: 1}, 21 | {inFile: path.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 24000, channels: 2, quality: 5}, 22 | ]; 23 | 24 | const promiseBasedTest = async () => { 25 | for (const audioTest of audioTests) { 26 | console.log(`Resampling file ${audioTest.inFile} with ${audioTest.channels} channel(s) from ${audioTest.inRate}Hz to ${audioTest.outRate}Hz (quality: ${audioTest.quality || 7})`); 27 | const resampler = new SpeexResampler(audioTest.channels, audioTest.inRate, audioTest.outRate, audioTest.quality); 28 | const filename = path.parse(audioTest.inFile).name; 29 | const pcmData = readFileSync(audioTest.inFile); 30 | 31 | const start = performance.now(); 32 | const res = await resampler.processChunk(pcmData); 33 | const end = performance.now(); 34 | console.log(`Resampled in ${Math.floor(end - start)}ms`); 35 | console.log(`Input stream: ${pcmData.length} bytes, ${pcmData.length / audioTest.inRate / 2 / audioTest.channels}s`); 36 | console.log(`Output stream: ${res.length} bytes, ${res.length / audioTest.outRate / 2 / audioTest.channels}s`); 37 | 38 | const inputDuration = pcmData.length / audioTest.inRate / 2 / audioTest.channels; 39 | const outputDuration = res.length / audioTest.outRate / 2 / audioTest.channels; 40 | assert(Math.abs(inputDuration - outputDuration) < 0.01, `Stream duration not matching target, in: ${inputDuration}s != out:${outputDuration}`); 41 | console.log(); 42 | // writeFileSync(path.resolve(__dirname, `../resources/${filename}_${audioTest.outRate}_${audioTest.quality || 7}_output.pcm`), res); 43 | } 44 | } 45 | 46 | const streamBasedTest = async () => { 47 | console.log('================='); 48 | console.log('Tranform Stream Test'); 49 | console.log('================='); 50 | 51 | for (const audioTest of audioTests) { 52 | console.log(`Resampling file ${audioTest.inFile} with ${audioTest.channels} channel(s) from ${audioTest.inRate}Hz to ${audioTest.outRate}Hz (quality: ${audioTest.quality || 7})`); 53 | const readFileStream = createReadStream(audioTest.inFile); 54 | const transformStream = new SpeexResamplerTransform(audioTest.channels, audioTest.inRate, audioTest.outRate, audioTest.quality); 55 | let pcmData = Buffer.alloc(0); 56 | readFileStream.on('data', (d) => { 57 | pcmData = Buffer.concat([ pcmData, d as Buffer ]); 58 | }); 59 | let res = Buffer.alloc(0); 60 | transformStream.on('data', (d) => { 61 | res = Buffer.concat([ res, d as Buffer ]); 62 | }); 63 | 64 | const start = performance.now(); 65 | readFileStream.pipe(transformStream); 66 | await new Promise((r) => transformStream.on('end', r)); 67 | const end = performance.now(); 68 | console.log(`Resampled in ${Math.floor(end - start)}ms`); 69 | console.log(`Input stream: ${pcmData.length} bytes, ${pcmData.length / audioTest.inRate / 2 / audioTest.channels}s`); 70 | console.log(`Output stream: ${res.length} bytes, ${res.length / audioTest.outRate / 2 / audioTest.channels}s`); 71 | 72 | const inputDuration = pcmData.length / audioTest.inRate / 2 / audioTest.channels; 73 | const outputDuration = res.length / audioTest.outRate / 2 / audioTest.channels; 74 | assert(Math.abs(inputDuration - outputDuration) < 0.01, `Stream duration not matching target, in: ${inputDuration}s != out:${outputDuration}`); 75 | console.log(); 76 | } 77 | } 78 | 79 | promiseBasedTest() 80 | .then(() => streamBasedTest()).catch((e) => { 81 | console.error(e); 82 | process.exit(1); 83 | }) 84 | -------------------------------------------------------------------------------- /deps/speex/resample_sse.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin 2 | * Copyright (C) 2008 Thorvald Natvig 3 | */ 4 | /** 5 | @file resample_sse.h 6 | @brief Resampler functions (SSE version) 7 | */ 8 | /* 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions 11 | are met: 12 | 13 | - Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | 16 | - Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | 20 | - Neither the name of the Xiph.org Foundation nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 28 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #include 38 | 39 | #define OVERRIDE_INNER_PRODUCT_SINGLE 40 | static inline float inner_product_single(const float *a, const float *b, unsigned int len) 41 | { 42 | int i; 43 | float ret; 44 | __m128 sum = _mm_setzero_ps(); 45 | for (i=0;i 76 | #define OVERRIDE_INNER_PRODUCT_DOUBLE 77 | 78 | static inline double inner_product_double(const float *a, const float *b, unsigned int len) 79 | { 80 | int i; 81 | double ret; 82 | __m128d sum = _mm_setzero_pd(); 83 | __m128 t; 84 | for (i=0;i> (shift)) 46 | #define SHL16(a,shift) ((a) << (shift)) 47 | #define SHR32(a,shift) ((a) >> (shift)) 48 | #define SHL32(a,shift) ((a) << (shift)) 49 | #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) 50 | #define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) 51 | #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) 52 | #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) 53 | #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) 54 | 55 | #define SATURATE32PSHR(x,shift,a) (((x)>=(SHL32(a,shift))) ? (a) : \ 56 | (x)<=-(SHL32(a,shift)) ? -(a) : \ 57 | (PSHR32(x, shift))) 58 | 59 | #define SHR(a,shift) ((a) >> (shift)) 60 | #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) 61 | #define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) 62 | #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) 63 | 64 | 65 | #define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) 66 | #define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) 67 | #define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) 68 | #define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b)) 69 | 70 | 71 | /* result fits in 16 bits */ 72 | #define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) 73 | 74 | /* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ 75 | #define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) 76 | 77 | #define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) 78 | #define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) 79 | #define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) 80 | #define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) 81 | 82 | #define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) 83 | #define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) 84 | 85 | #define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) 86 | #define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) 87 | #define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) 88 | 89 | 90 | #define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) 91 | #define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) 92 | #define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) 93 | 94 | #define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) 95 | #define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) 96 | #define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) 97 | #define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) 98 | 99 | #define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) 100 | #define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) 101 | #define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) 102 | 103 | #define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15)) 104 | 105 | #define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) 106 | #define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) 107 | #define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) 108 | #define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b))) 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /deps/speex/os_support.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 Jean-Marc Valin 2 | 3 | File: os_support.h 4 | This is the (tiny) OS abstraction layer. Aside from math.h, this is the 5 | only place where system headers are allowed. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | 3. The name of the author may not be used to endorse or promote products 19 | derived from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef OS_SUPPORT_H 35 | #define OS_SUPPORT_H 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #ifdef HAVE_CONFIG_H 42 | #include "config.h" 43 | #endif 44 | #ifdef OS_SUPPORT_CUSTOM 45 | #include "os_support_custom.h" 46 | #endif 47 | 48 | /** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free 49 | NOTE: speex_alloc needs to CLEAR THE MEMORY */ 50 | #ifndef OVERRIDE_SPEEX_ALLOC 51 | static inline void *speex_alloc (int size) 52 | { 53 | /* WARNING: this is not equivalent to malloc(). If you want to use malloc() 54 | or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise 55 | you will experience strange bugs */ 56 | return calloc(size,1); 57 | } 58 | #endif 59 | 60 | /** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ 61 | #ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH 62 | static inline void *speex_alloc_scratch (int size) 63 | { 64 | /* Scratch space doesn't need to be cleared */ 65 | return calloc(size,1); 66 | } 67 | #endif 68 | 69 | /** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */ 70 | #ifndef OVERRIDE_SPEEX_REALLOC 71 | static inline void *speex_realloc (void *ptr, int size) 72 | { 73 | return realloc(ptr, size); 74 | } 75 | #endif 76 | 77 | /** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */ 78 | #ifndef OVERRIDE_SPEEX_FREE 79 | static inline void speex_free (void *ptr) 80 | { 81 | free(ptr); 82 | } 83 | #endif 84 | 85 | /** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ 86 | #ifndef OVERRIDE_SPEEX_FREE_SCRATCH 87 | static inline void speex_free_scratch (void *ptr) 88 | { 89 | free(ptr); 90 | } 91 | #endif 92 | 93 | /** Copy n elements from src to dst. The 0* term provides compile-time type checking */ 94 | #ifndef OVERRIDE_SPEEX_COPY 95 | #define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) 96 | #endif 97 | 98 | /** Copy n elements from src to dst, allowing overlapping regions. The 0* term 99 | provides compile-time type checking */ 100 | #ifndef OVERRIDE_SPEEX_MOVE 101 | #define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) 102 | #endif 103 | 104 | /** For n elements worth of memory, set every byte to the value of c, starting at address dst */ 105 | #ifndef OVERRIDE_SPEEX_MEMSET 106 | #define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) 107 | #endif 108 | 109 | 110 | #ifndef OVERRIDE_SPEEX_FATAL 111 | static inline void _speex_fatal(const char *str, const char *file, int line) 112 | { 113 | fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); 114 | exit(1); 115 | } 116 | #endif 117 | 118 | #ifndef OVERRIDE_SPEEX_WARNING 119 | static inline void speex_warning(const char *str) 120 | { 121 | #ifndef DISABLE_WARNINGS 122 | fprintf (stderr, "warning: %s\n", str); 123 | #endif 124 | } 125 | #endif 126 | 127 | #ifndef OVERRIDE_SPEEX_WARNING_INT 128 | static inline void speex_warning_int(const char *str, int val) 129 | { 130 | #ifndef DISABLE_WARNINGS 131 | fprintf (stderr, "warning: %s %d\n", str, val); 132 | #endif 133 | } 134 | #endif 135 | 136 | #ifndef OVERRIDE_SPEEX_NOTIFY 137 | static inline void speex_notify(const char *str) 138 | { 139 | #ifndef DISABLE_NOTIFICATIONS 140 | fprintf (stderr, "notification: %s\n", str); 141 | #endif 142 | } 143 | #endif 144 | 145 | #ifndef OVERRIDE_SPEEX_PUTC 146 | /** Speex wrapper for putc */ 147 | static inline void _speex_putc(int ch, void *file) 148 | { 149 | FILE *f = (FILE *)file; 150 | fprintf(f, "%c", ch); 151 | } 152 | #endif 153 | 154 | #define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__); 155 | #define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}} 156 | 157 | #ifndef RELEASE 158 | static inline void print_vec(float *vec, int len, char *name) 159 | { 160 | int i; 161 | printf ("%s ", name); 162 | for (i=0;i 2 | 3 | import { Transform } from 'stream'; 4 | import SpeexWasm from './speex_wasm'; 5 | 6 | interface EmscriptenModuleOpusEncoder extends EmscriptenModule { 7 | _speex_resampler_init(nbChannels: number, inRate: number, outRate: number, quality: number, errPointer: number): number; 8 | _speex_resampler_destroy(resamplerPtr: number): void; 9 | _speex_resampler_get_rate(resamplerPtr: number, inRatePtr: number, outRatePtr: number); 10 | _speex_resampler_process_interleaved_int(resamplerPtr: number, inBufferPtr: number, inLenPtr: number, outBufferPtr: number, outLenPtr: number): number; 11 | _speex_resampler_strerror(err: number): number; 12 | 13 | getValue(ptr: number, type: string): any; 14 | setValue(ptr: number, value: any, type: string): any; 15 | AsciiToString(ptr: number): string; 16 | } 17 | 18 | let speexModule: EmscriptenModuleOpusEncoder; 19 | let globalModulePromise = SpeexWasm().then((s) => speexModule = s); 20 | 21 | class SpeexResampler { 22 | _resamplerPtr: number; 23 | _inBufferPtr = -1; 24 | _inBufferSize = -1; 25 | _outBufferPtr = -1; 26 | _outBufferSize = -1; 27 | 28 | _inLengthPtr = -1; 29 | _outLengthPtr = -1; 30 | 31 | static initPromise = globalModulePromise as Promise; 32 | 33 | /** 34 | * Create an SpeexResampler tranform stream. 35 | * @param channels Number of channels, minimum is 1, no maximum 36 | * @param inRate frequency in Hz for the input chunk 37 | * @param outRate frequency in Hz for the target chunk 38 | * @param quality number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 39 | */ 40 | constructor( 41 | public channels, 42 | public inRate, 43 | public outRate, 44 | public quality = 7) {} 45 | 46 | /** 47 | * Resample a chunk of audio. 48 | * @param chunk interleaved PCM data in signed 16bits int 49 | */ 50 | processChunk(chunk: Buffer) { 51 | if (!speexModule) { 52 | throw new Error('You need to wait for SpeexResampler.initPromise before calling this method'); 53 | } 54 | // We check that we have as many chunks for each channel and that the last chunk is full (2 bytes) 55 | if (chunk.length % (this.channels * Uint16Array.BYTES_PER_ELEMENT) !== 0) { 56 | throw new Error('Chunk length should be a multiple of channels * 2 bytes'); 57 | } 58 | 59 | if (!this._resamplerPtr) { 60 | const errPtr = speexModule._malloc(4); 61 | this._resamplerPtr = speexModule._speex_resampler_init(this.channels, this.inRate, this.outRate, this.quality, errPtr); 62 | const errNum = speexModule.getValue(errPtr, 'i32'); 63 | if (errNum !== 0) { 64 | throw new Error(speexModule.AsciiToString(speexModule._speex_resampler_strerror(errNum))); 65 | } 66 | this._inLengthPtr = speexModule._malloc(Uint32Array.BYTES_PER_ELEMENT); 67 | this._outLengthPtr = speexModule._malloc(Uint32Array.BYTES_PER_ELEMENT); 68 | } 69 | 70 | // Resizing the input buffer in the WASM memory space to match what we need 71 | if (this._inBufferSize < chunk.length) { 72 | if (this._inBufferPtr !== -1) { 73 | speexModule._free(this._inBufferPtr); 74 | } 75 | this._inBufferPtr = speexModule._malloc(chunk.length); 76 | this._inBufferSize = chunk.length; 77 | } 78 | 79 | // Resizing the output buffer in the WASM memory space to match what we need 80 | const outBufferLengthTarget = Math.ceil(chunk.length * this.outRate / this.inRate); 81 | if (this._outBufferSize < outBufferLengthTarget) { 82 | if (this._outBufferPtr !== -1) { 83 | speexModule._free(this._outBufferPtr); 84 | } 85 | this._outBufferPtr = speexModule._malloc(outBufferLengthTarget); 86 | this._outBufferSize = outBufferLengthTarget; 87 | } 88 | 89 | // number of samples per channel in input buffer 90 | speexModule.setValue(this._inLengthPtr, chunk.length / this.channels / Uint16Array.BYTES_PER_ELEMENT, 'i32'); 91 | // Copying the info from the input Buffer in the WASM memory space 92 | speexModule.HEAPU8.set(chunk, this._inBufferPtr); 93 | 94 | // number of samples per channels available in output buffer 95 | speexModule.setValue(this._outLengthPtr, this._outBufferSize / this.channels / Uint16Array.BYTES_PER_ELEMENT, 'i32'); 96 | const errNum = speexModule._speex_resampler_process_interleaved_int( 97 | this._resamplerPtr, 98 | this._inBufferPtr, 99 | this._inLengthPtr, 100 | this._outBufferPtr, 101 | this._outLengthPtr, 102 | ); 103 | 104 | if (errNum !== 0) { 105 | throw new Error(speexModule.AsciiToString(speexModule._speex_resampler_strerror(errNum))); 106 | } 107 | 108 | const outSamplesPerChannelsWritten = speexModule.getValue(this._outLengthPtr, 'i32'); 109 | 110 | // we are copying the info in a new buffer here, we could just pass a buffer pointing to the same memory space if needed 111 | return Buffer.from( 112 | speexModule.HEAPU8.slice( 113 | this._outBufferPtr, 114 | this._outBufferPtr + outSamplesPerChannelsWritten * this.channels * Uint16Array.BYTES_PER_ELEMENT 115 | ).buffer); 116 | } 117 | } 118 | 119 | const EMPTY_BUFFER = Buffer.alloc(0); 120 | 121 | export class SpeexResamplerTransform extends Transform { 122 | resampler: SpeexResampler; 123 | _alignementBuffer: Buffer; 124 | 125 | /** 126 | * Create an SpeexResampler instance. 127 | * @param channels Number of channels, minimum is 1, no maximum 128 | * @param inRate frequency in Hz for the input chunk 129 | * @param outRate frequency in Hz for the target chunk 130 | * @param quality number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 131 | */ 132 | constructor(public channels, public inRate, public outRate, public quality = 7) { 133 | super(); 134 | this.resampler = new SpeexResampler(channels, inRate, outRate, quality); 135 | this.channels = channels; 136 | this._alignementBuffer = EMPTY_BUFFER; 137 | } 138 | 139 | _transform(chunk, encoding, callback) { 140 | let chunkToProcess: Buffer = chunk; 141 | if (this._alignementBuffer.length > 0) { 142 | chunkToProcess = Buffer.concat([ 143 | this._alignementBuffer, 144 | chunk, 145 | ]); 146 | this._alignementBuffer = EMPTY_BUFFER; 147 | } 148 | // Speex needs a buffer aligned to 16bits times the number of channels 149 | // so we keep the extraneous bytes in a buffer for next chunk 150 | const extraneousBytesCount = chunkToProcess.length % (this.channels * Uint16Array.BYTES_PER_ELEMENT); 151 | if (extraneousBytesCount !== 0) { 152 | this._alignementBuffer = Buffer.from(chunkToProcess.slice(chunkToProcess.length - extraneousBytesCount)); 153 | chunkToProcess = chunkToProcess.slice(0, chunkToProcess.length - extraneousBytesCount); 154 | } 155 | try { 156 | const res = this.resampler.processChunk(chunkToProcess); 157 | callback(null, res); 158 | } catch (e) { 159 | callback(e); 160 | } 161 | } 162 | } 163 | 164 | export default SpeexResampler; 165 | -------------------------------------------------------------------------------- /deps/speex/arch.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2003 Jean-Marc Valin */ 2 | /** 3 | @file arch.h 4 | @brief Various architecture definitions Speex 5 | */ 6 | /* 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | - Neither the name of the Xiph.org Foundation nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef ARCH_H 36 | #define ARCH_H 37 | 38 | /* A couple test to catch stupid option combinations */ 39 | #ifdef FIXED_POINT 40 | 41 | #ifdef FLOATING_POINT 42 | #error You cannot compile as floating point and fixed point at the same time 43 | #endif 44 | #ifdef USE_SSE 45 | #error SSE is only for floating-point 46 | #endif 47 | #if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) 48 | #error Make up your mind. What CPU do you have? 49 | #endif 50 | #ifdef VORBIS_PSYCHO 51 | #error Vorbis-psy model currently not implemented in fixed-point 52 | #endif 53 | 54 | #else 55 | 56 | #ifndef FLOATING_POINT 57 | #error You now need to define either FIXED_POINT or FLOATING_POINT 58 | #endif 59 | #if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) 60 | #error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? 61 | #endif 62 | #ifdef FIXED_POINT_DEBUG 63 | #error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" 64 | #endif 65 | 66 | 67 | #endif 68 | 69 | #ifndef OUTSIDE_SPEEX 70 | #include "speex/speexdsp_types.h" 71 | #endif 72 | 73 | #define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ 74 | #define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ 75 | #define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 76 | #define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 77 | #define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ 78 | #define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 79 | #define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 80 | 81 | #ifdef FIXED_POINT 82 | 83 | typedef spx_int16_t spx_word16_t; 84 | typedef spx_int32_t spx_word32_t; 85 | typedef spx_word32_t spx_mem_t; 86 | typedef spx_word16_t spx_coef_t; 87 | typedef spx_word16_t spx_lsp_t; 88 | typedef spx_word32_t spx_sig_t; 89 | 90 | #define Q15ONE 32767 91 | 92 | #define LPC_SCALING 8192 93 | #define SIG_SCALING 16384 94 | #define LSP_SCALING 8192. 95 | #define GAMMA_SCALING 32768. 96 | #define GAIN_SCALING 64 97 | #define GAIN_SCALING_1 0.015625 98 | 99 | #define LPC_SHIFT 13 100 | #define LSP_SHIFT 13 101 | #define SIG_SHIFT 14 102 | #define GAIN_SHIFT 6 103 | 104 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) 105 | 106 | #define VERY_SMALL 0 107 | #define VERY_LARGE32 ((spx_word32_t)2147483647) 108 | #define VERY_LARGE16 ((spx_word16_t)32767) 109 | #define Q15_ONE ((spx_word16_t)32767) 110 | 111 | 112 | #ifdef FIXED_DEBUG 113 | #include "fixed_debug.h" 114 | #else 115 | 116 | #include "fixed_generic.h" 117 | 118 | #ifdef ARM5E_ASM 119 | #include "fixed_arm5e.h" 120 | #elif defined (ARM4_ASM) 121 | #include "fixed_arm4.h" 122 | #elif defined (BFIN_ASM) 123 | #include "fixed_bfin.h" 124 | #endif 125 | 126 | #endif 127 | 128 | 129 | #else 130 | 131 | typedef float spx_mem_t; 132 | typedef float spx_coef_t; 133 | typedef float spx_lsp_t; 134 | typedef float spx_sig_t; 135 | typedef float spx_word16_t; 136 | typedef float spx_word32_t; 137 | 138 | #define Q15ONE 1.0f 139 | #define LPC_SCALING 1.f 140 | #define SIG_SCALING 1.f 141 | #define LSP_SCALING 1.f 142 | #define GAMMA_SCALING 1.f 143 | #define GAIN_SCALING 1.f 144 | #define GAIN_SCALING_1 1.f 145 | 146 | 147 | #define VERY_SMALL 1e-15f 148 | #define VERY_LARGE32 1e15f 149 | #define VERY_LARGE16 1e15f 150 | #define Q15_ONE ((spx_word16_t)1.f) 151 | 152 | #define QCONST16(x,bits) (x) 153 | #define QCONST32(x,bits) (x) 154 | 155 | #define NEG16(x) (-(x)) 156 | #define NEG32(x) (-(x)) 157 | #define EXTRACT16(x) (x) 158 | #define EXTEND32(x) (x) 159 | #define SHR16(a,shift) (a) 160 | #define SHL16(a,shift) (a) 161 | #define SHR32(a,shift) (a) 162 | #define SHL32(a,shift) (a) 163 | #define PSHR16(a,shift) (a) 164 | #define PSHR32(a,shift) (a) 165 | #define VSHR32(a,shift) (a) 166 | #define SATURATE16(x,a) (x) 167 | #define SATURATE32(x,a) (x) 168 | #define SATURATE32PSHR(x,shift,a) (x) 169 | 170 | #define PSHR(a,shift) (a) 171 | #define SHR(a,shift) (a) 172 | #define SHL(a,shift) (a) 173 | #define SATURATE(x,a) (x) 174 | 175 | #define ADD16(a,b) ((a)+(b)) 176 | #define SUB16(a,b) ((a)-(b)) 177 | #define ADD32(a,b) ((a)+(b)) 178 | #define SUB32(a,b) ((a)-(b)) 179 | #define MULT16_16_16(a,b) ((a)*(b)) 180 | #define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) 181 | #define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) 182 | 183 | #define MULT16_32_Q11(a,b) ((a)*(b)) 184 | #define MULT16_32_Q13(a,b) ((a)*(b)) 185 | #define MULT16_32_Q14(a,b) ((a)*(b)) 186 | #define MULT16_32_Q15(a,b) ((a)*(b)) 187 | #define MULT16_32_P15(a,b) ((a)*(b)) 188 | 189 | #define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) 190 | #define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) 191 | 192 | #define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) 193 | #define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) 194 | #define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) 195 | #define MULT16_16_Q11_32(a,b) ((a)*(b)) 196 | #define MULT16_16_Q13(a,b) ((a)*(b)) 197 | #define MULT16_16_Q14(a,b) ((a)*(b)) 198 | #define MULT16_16_Q15(a,b) ((a)*(b)) 199 | #define MULT16_16_P15(a,b) ((a)*(b)) 200 | #define MULT16_16_P13(a,b) ((a)*(b)) 201 | #define MULT16_16_P14(a,b) ((a)*(b)) 202 | 203 | #define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) 204 | #define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) 205 | #define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) 206 | #define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) 207 | 208 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : \ 209 | ((x) > 32766.5f ? 32767 : (spx_int16_t)floor(.5 + (x)))) 210 | #endif 211 | 212 | 213 | #if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) 214 | 215 | /* 2 on TI C5x DSP */ 216 | #define BYTES_PER_CHAR 2 217 | #define BITS_PER_CHAR 16 218 | #define LOG2_BITS_PER_CHAR 4 219 | 220 | #else 221 | 222 | #define BYTES_PER_CHAR 1 223 | #define BITS_PER_CHAR 8 224 | #define LOG2_BITS_PER_CHAR 3 225 | 226 | #endif 227 | 228 | 229 | 230 | #ifdef FIXED_DEBUG 231 | extern long long spx_mips; 232 | #endif 233 | 234 | 235 | #endif 236 | -------------------------------------------------------------------------------- /deps/speex/resample_neon.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin 2 | * Copyright (C) 2008 Thorvald Natvig 3 | * Copyright (C) 2011 Texas Instruments 4 | * author Jyri Sarha 5 | */ 6 | /** 7 | @file resample_neon.h 8 | @brief Resampler functions (NEON version) 9 | */ 10 | /* 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions 13 | are met: 14 | 15 | - Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 18 | - Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | - Neither the name of the Xiph.org Foundation nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 30 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 31 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 32 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 33 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 34 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | #ifdef FIXED_POINT 40 | #if defined(__aarch64__) 41 | static inline int32_t saturate_32bit_to_16bit(int32_t a) { 42 | int32_t ret; 43 | asm ("fmov s0, %w[a]\n" 44 | "sqxtn h0, s0\n" 45 | "sxtl v0.4s, v0.4h\n" 46 | "fmov %w[ret], s0\n" 47 | : [ret] "=r" (ret) 48 | : [a] "r" (a) 49 | : "v0" ); 50 | return ret; 51 | } 52 | #elif defined(__thumb2__) 53 | static inline int32_t saturate_32bit_to_16bit(int32_t a) { 54 | int32_t ret; 55 | asm ("ssat %[ret], #16, %[a]" 56 | : [ret] "=r" (ret) 57 | : [a] "r" (a) 58 | : ); 59 | return ret; 60 | } 61 | #else 62 | static inline int32_t saturate_32bit_to_16bit(int32_t a) { 63 | int32_t ret; 64 | asm ("vmov.s32 d0[0], %[a]\n" 65 | "vqmovn.s32 d0, q0\n" 66 | "vmov.s16 %[ret], d0[0]\n" 67 | : [ret] "=r" (ret) 68 | : [a] "r" (a) 69 | : "q0"); 70 | return ret; 71 | } 72 | #endif 73 | #undef WORD2INT 74 | #define WORD2INT(x) (saturate_32bit_to_16bit(x)) 75 | 76 | #define OVERRIDE_INNER_PRODUCT_SINGLE 77 | /* Only works when len % 4 == 0 and len >= 4 */ 78 | #if defined(__aarch64__) 79 | static inline int32_t inner_product_single(const int16_t *a, const int16_t *b, unsigned int len) 80 | { 81 | int32_t ret; 82 | u_int32_t remainder = len % 16; 83 | len = len - remainder; 84 | 85 | asm volatile (" cmp %w[len], #0\n" 86 | " b.ne 1f\n" 87 | " ld1 {v16.4h}, [%[b]], #8\n" 88 | " ld1 {v20.4h}, [%[a]], #8\n" 89 | " subs %w[remainder], %w[remainder], #4\n" 90 | " smull v0.4s, v16.4h, v20.4h\n" 91 | " b.ne 4f\n" 92 | " b 5f\n" 93 | "1:" 94 | " ld1 {v16.4h, v17.4h, v18.4h, v19.4h}, [%[b]], #32\n" 95 | " ld1 {v20.4h, v21.4h, v22.4h, v23.4h}, [%[a]], #32\n" 96 | " subs %w[len], %w[len], #16\n" 97 | " smull v0.4s, v16.4h, v20.4h\n" 98 | " smlal v0.4s, v17.4h, v21.4h\n" 99 | " smlal v0.4s, v18.4h, v22.4h\n" 100 | " smlal v0.4s, v19.4h, v23.4h\n" 101 | " b.eq 3f\n" 102 | "2:" 103 | " ld1 {v16.4h, v17.4h, v18.4h, v19.4h}, [%[b]], #32\n" 104 | " ld1 {v20.4h, v21.4h, v22.4h, v23.4h}, [%[a]], #32\n" 105 | " subs %w[len], %w[len], #16\n" 106 | " smlal v0.4s, v16.4h, v20.4h\n" 107 | " smlal v0.4s, v17.4h, v21.4h\n" 108 | " smlal v0.4s, v18.4h, v22.4h\n" 109 | " smlal v0.4s, v19.4h, v23.4h\n" 110 | " b.ne 2b\n" 111 | "3:" 112 | " cmp %w[remainder], #0\n" 113 | " b.eq 5f\n" 114 | "4:" 115 | " ld1 {v18.4h}, [%[b]], #8\n" 116 | " ld1 {v22.4h}, [%[a]], #8\n" 117 | " subs %w[remainder], %w[remainder], #4\n" 118 | " smlal v0.4s, v18.4h, v22.4h\n" 119 | " b.ne 4b\n" 120 | "5:" 121 | " saddlv d0, v0.4s\n" 122 | " sqxtn s0, d0\n" 123 | " sqrshrn h0, s0, #15\n" 124 | " sxtl v0.4s, v0.4h\n" 125 | " fmov %w[ret], s0\n" 126 | : [ret] "=r" (ret), [a] "+r" (a), [b] "+r" (b), 127 | [len] "+r" (len), [remainder] "+r" (remainder) 128 | : 129 | : "cc", "v0", 130 | "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); 131 | return ret; 132 | } 133 | #else 134 | static inline int32_t inner_product_single(const int16_t *a, const int16_t *b, unsigned int len) 135 | { 136 | int32_t ret; 137 | u_int32_t remainder = len % 16; 138 | len = len - remainder; 139 | 140 | asm volatile (" cmp %[len], #0\n" 141 | " bne 1f\n" 142 | " vld1.16 {d16}, [%[b]]!\n" 143 | " vld1.16 {d20}, [%[a]]!\n" 144 | " subs %[remainder], %[remainder], #4\n" 145 | " vmull.s16 q0, d16, d20\n" 146 | " beq 5f\n" 147 | " b 4f\n" 148 | "1:" 149 | " vld1.16 {d16, d17, d18, d19}, [%[b]]!\n" 150 | " vld1.16 {d20, d21, d22, d23}, [%[a]]!\n" 151 | " subs %[len], %[len], #16\n" 152 | " vmull.s16 q0, d16, d20\n" 153 | " vmlal.s16 q0, d17, d21\n" 154 | " vmlal.s16 q0, d18, d22\n" 155 | " vmlal.s16 q0, d19, d23\n" 156 | " beq 3f\n" 157 | "2:" 158 | " vld1.16 {d16, d17, d18, d19}, [%[b]]!\n" 159 | " vld1.16 {d20, d21, d22, d23}, [%[a]]!\n" 160 | " subs %[len], %[len], #16\n" 161 | " vmlal.s16 q0, d16, d20\n" 162 | " vmlal.s16 q0, d17, d21\n" 163 | " vmlal.s16 q0, d18, d22\n" 164 | " vmlal.s16 q0, d19, d23\n" 165 | " bne 2b\n" 166 | "3:" 167 | " cmp %[remainder], #0\n" 168 | " beq 5f\n" 169 | "4:" 170 | " vld1.16 {d16}, [%[b]]!\n" 171 | " vld1.16 {d20}, [%[a]]!\n" 172 | " subs %[remainder], %[remainder], #4\n" 173 | " vmlal.s16 q0, d16, d20\n" 174 | " bne 4b\n" 175 | "5:" 176 | " vaddl.s32 q0, d0, d1\n" 177 | " vadd.s64 d0, d0, d1\n" 178 | " vqmovn.s64 d0, q0\n" 179 | " vqrshrn.s32 d0, q0, #15\n" 180 | " vmov.s16 %[ret], d0[0]\n" 181 | : [ret] "=r" (ret), [a] "+r" (a), [b] "+r" (b), 182 | [len] "+r" (len), [remainder] "+r" (remainder) 183 | : 184 | : "cc", "q0", 185 | "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23"); 186 | 187 | return ret; 188 | } 189 | #endif // !defined(__aarch64__) 190 | 191 | #elif defined(FLOATING_POINT) 192 | #if defined(__aarch64__) 193 | static inline int32_t saturate_float_to_16bit(float a) { 194 | int32_t ret; 195 | asm ("fcvtas s1, %s[a]\n" 196 | "sqxtn h1, s1\n" 197 | "sxtl v1.4s, v1.4h\n" 198 | "fmov %w[ret], s1\n" 199 | : [ret] "=r" (ret) 200 | : [a] "w" (a) 201 | : "v1"); 202 | return ret; 203 | } 204 | #else 205 | static inline int32_t saturate_float_to_16bit(float a) { 206 | int32_t ret; 207 | asm ("vmov.f32 d0[0], %[a]\n" 208 | "vcvt.s32.f32 d0, d0, #15\n" 209 | "vqrshrn.s32 d0, q0, #15\n" 210 | "vmov.s16 %[ret], d0[0]\n" 211 | : [ret] "=r" (ret) 212 | : [a] "r" (a) 213 | : "q0"); 214 | return ret; 215 | } 216 | #endif 217 | 218 | #undef WORD2INT 219 | #define WORD2INT(x) (saturate_float_to_16bit(x)) 220 | 221 | #define OVERRIDE_INNER_PRODUCT_SINGLE 222 | /* Only works when len % 4 == 0 and len >= 4 */ 223 | #if defined(__aarch64__) 224 | static inline float inner_product_single(const float *a, const float *b, unsigned int len) 225 | { 226 | float ret; 227 | u_int32_t remainder = len % 16; 228 | len = len - remainder; 229 | 230 | asm volatile (" cmp %w[len], #0\n" 231 | " b.ne 1f\n" 232 | " ld1 {v16.4s}, [%[b]], #16\n" 233 | " ld1 {v20.4s}, [%[a]], #16\n" 234 | " subs %w[remainder], %w[remainder], #4\n" 235 | " fmul v1.4s, v16.4s, v20.4s\n" 236 | " b.ne 4f\n" 237 | " b 5f\n" 238 | "1:" 239 | " ld1 {v16.4s, v17.4s, v18.4s, v19.4s}, [%[b]], #64\n" 240 | " ld1 {v20.4s, v21.4s, v22.4s, v23.4s}, [%[a]], #64\n" 241 | " subs %w[len], %w[len], #16\n" 242 | " fmul v1.4s, v16.4s, v20.4s\n" 243 | " fmul v2.4s, v17.4s, v21.4s\n" 244 | " fmul v3.4s, v18.4s, v22.4s\n" 245 | " fmul v4.4s, v19.4s, v23.4s\n" 246 | " b.eq 3f\n" 247 | "2:" 248 | " ld1 {v16.4s, v17.4s, v18.4s, v19.4s}, [%[b]], #64\n" 249 | " ld1 {v20.4s, v21.4s, v22.4s, v23.4s}, [%[a]], #64\n" 250 | " subs %w[len], %w[len], #16\n" 251 | " fmla v1.4s, v16.4s, v20.4s\n" 252 | " fmla v2.4s, v17.4s, v21.4s\n" 253 | " fmla v3.4s, v18.4s, v22.4s\n" 254 | " fmla v4.4s, v19.4s, v23.4s\n" 255 | " b.ne 2b\n" 256 | "3:" 257 | " fadd v16.4s, v1.4s, v2.4s\n" 258 | " fadd v17.4s, v3.4s, v4.4s\n" 259 | " cmp %w[remainder], #0\n" 260 | " fadd v1.4s, v16.4s, v17.4s\n" 261 | " b.eq 5f\n" 262 | "4:" 263 | " ld1 {v18.4s}, [%[b]], #16\n" 264 | " ld1 {v22.4s}, [%[a]], #16\n" 265 | " subs %w[remainder], %w[remainder], #4\n" 266 | " fmla v1.4s, v18.4s, v22.4s\n" 267 | " b.ne 4b\n" 268 | "5:" 269 | " faddp v1.4s, v1.4s, v1.4s\n" 270 | " faddp %[ret].4s, v1.4s, v1.4s\n" 271 | : [ret] "=w" (ret), [a] "+r" (a), [b] "+r" (b), 272 | [len] "+r" (len), [remainder] "+r" (remainder) 273 | : 274 | : "cc", "v1", "v2", "v3", "v4", 275 | "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); 276 | return ret; 277 | } 278 | #else 279 | static inline float inner_product_single(const float *a, const float *b, unsigned int len) 280 | { 281 | float ret; 282 | u_int32_t remainder = len % 16; 283 | len = len - remainder; 284 | 285 | asm volatile (" cmp %[len], #0\n" 286 | " bne 1f\n" 287 | " vld1.32 {q4}, [%[b]]!\n" 288 | " vld1.32 {q8}, [%[a]]!\n" 289 | " subs %[remainder], %[remainder], #4\n" 290 | " vmul.f32 q0, q4, q8\n" 291 | " bne 4f\n" 292 | " b 5f\n" 293 | "1:" 294 | " vld1.32 {q4, q5}, [%[b]]!\n" 295 | " vld1.32 {q8, q9}, [%[a]]!\n" 296 | " vld1.32 {q6, q7}, [%[b]]!\n" 297 | " vld1.32 {q10, q11}, [%[a]]!\n" 298 | " subs %[len], %[len], #16\n" 299 | " vmul.f32 q0, q4, q8\n" 300 | " vmul.f32 q1, q5, q9\n" 301 | " vmul.f32 q2, q6, q10\n" 302 | " vmul.f32 q3, q7, q11\n" 303 | " beq 3f\n" 304 | "2:" 305 | " vld1.32 {q4, q5}, [%[b]]!\n" 306 | " vld1.32 {q8, q9}, [%[a]]!\n" 307 | " vld1.32 {q6, q7}, [%[b]]!\n" 308 | " vld1.32 {q10, q11}, [%[a]]!\n" 309 | " subs %[len], %[len], #16\n" 310 | " vmla.f32 q0, q4, q8\n" 311 | " vmla.f32 q1, q5, q9\n" 312 | " vmla.f32 q2, q6, q10\n" 313 | " vmla.f32 q3, q7, q11\n" 314 | " bne 2b\n" 315 | "3:" 316 | " vadd.f32 q4, q0, q1\n" 317 | " vadd.f32 q5, q2, q3\n" 318 | " cmp %[remainder], #0\n" 319 | " vadd.f32 q0, q4, q5\n" 320 | " beq 5f\n" 321 | "4:" 322 | " vld1.32 {q6}, [%[b]]!\n" 323 | " vld1.32 {q10}, [%[a]]!\n" 324 | " subs %[remainder], %[remainder], #4\n" 325 | " vmla.f32 q0, q6, q10\n" 326 | " bne 4b\n" 327 | "5:" 328 | " vadd.f32 d0, d0, d1\n" 329 | " vpadd.f32 d0, d0, d0\n" 330 | " vmov.f32 %[ret], d0[0]\n" 331 | : [ret] "=r" (ret), [a] "+r" (a), [b] "+r" (b), 332 | [len] "+l" (len), [remainder] "+l" (remainder) 333 | : 334 | : "cc", "q0", "q1", "q2", "q3", 335 | "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11"); 336 | return ret; 337 | } 338 | #endif // defined(__aarch64__) 339 | #endif 340 | -------------------------------------------------------------------------------- /deps/speex/speex_resampler.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 Jean-Marc Valin 2 | 3 | File: speex_resampler.h 4 | Resampling code 5 | 6 | The design goals of this code are: 7 | - Very fast algorithm 8 | - Low memory requirement 9 | - Good *perceptual* quality (and not best SNR) 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are 13 | met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, 16 | this list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | 3. The name of the author may not be used to endorse or promote products 23 | derived from this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 29 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #ifndef SPEEX_RESAMPLER_H 40 | #define SPEEX_RESAMPLER_H 41 | 42 | #if 1 43 | 44 | /********* WARNING: MENTAL SANITY ENDS HERE *************/ 45 | 46 | /* If the resampler is defined outside of Speex, we change the symbol names so that 47 | there won't be any clash if linking with Speex later on. */ 48 | 49 | /* #define RANDOM_PREFIX your software name here */ 50 | #define RANDOM_PREFIX speex 51 | #ifndef RANDOM_PREFIX 52 | #error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" 53 | #endif 54 | 55 | #define CAT_PREFIX2(a,b) a ## b 56 | #define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) 57 | 58 | #define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) 59 | #define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) 60 | #define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) 61 | #define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) 62 | #define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) 63 | #define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) 64 | #define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) 65 | #define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) 66 | #define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) 67 | #define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) 68 | #define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) 69 | #define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) 70 | #define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) 71 | #define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) 72 | #define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) 73 | #define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) 74 | #define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) 75 | #define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency) 76 | #define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency) 77 | #define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) 78 | #define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) 79 | #define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) 80 | 81 | #define spx_int16_t short 82 | #define spx_int32_t int 83 | #define spx_uint16_t unsigned short 84 | #define spx_uint32_t unsigned int 85 | 86 | #define speex_assert(cond) 87 | 88 | #else /* OUTSIDE_SPEEX */ 89 | 90 | #include "speexdsp_types.h" 91 | 92 | #endif /* OUTSIDE_SPEEX */ 93 | 94 | #ifdef __cplusplus 95 | extern "C" { 96 | #endif 97 | 98 | #define SPEEX_RESAMPLER_QUALITY_MAX 10 99 | #define SPEEX_RESAMPLER_QUALITY_MIN 0 100 | #define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 101 | #define SPEEX_RESAMPLER_QUALITY_VOIP 3 102 | #define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 103 | 104 | enum { 105 | RESAMPLER_ERR_SUCCESS = 0, 106 | RESAMPLER_ERR_ALLOC_FAILED = 1, 107 | RESAMPLER_ERR_BAD_STATE = 2, 108 | RESAMPLER_ERR_INVALID_ARG = 3, 109 | RESAMPLER_ERR_PTR_OVERLAP = 4, 110 | RESAMPLER_ERR_OVERFLOW = 5, 111 | 112 | RESAMPLER_ERR_MAX_ERROR 113 | }; 114 | 115 | struct SpeexResamplerState_; 116 | typedef struct SpeexResamplerState_ SpeexResamplerState; 117 | 118 | /** Create a new resampler with integer input and output rates. 119 | * @param nb_channels Number of channels to be processed 120 | * @param in_rate Input sampling rate (integer number of Hz). 121 | * @param out_rate Output sampling rate (integer number of Hz). 122 | * @param quality Resampling quality between 0 and 10, where 0 has poor quality 123 | * and 10 has very high quality. 124 | * @return Newly created resampler state 125 | * @retval NULL Error: not enough memory 126 | */ 127 | SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, 128 | spx_uint32_t in_rate, 129 | spx_uint32_t out_rate, 130 | int quality, 131 | int *err); 132 | 133 | /** Create a new resampler with fractional input/output rates. The sampling 134 | * rate ratio is an arbitrary rational number with both the numerator and 135 | * denominator being 32-bit integers. 136 | * @param nb_channels Number of channels to be processed 137 | * @param ratio_num Numerator of the sampling rate ratio 138 | * @param ratio_den Denominator of the sampling rate ratio 139 | * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). 140 | * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). 141 | * @param quality Resampling quality between 0 and 10, where 0 has poor quality 142 | * and 10 has very high quality. 143 | * @return Newly created resampler state 144 | * @retval NULL Error: not enough memory 145 | */ 146 | SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, 147 | spx_uint32_t ratio_num, 148 | spx_uint32_t ratio_den, 149 | spx_uint32_t in_rate, 150 | spx_uint32_t out_rate, 151 | int quality, 152 | int *err); 153 | 154 | /** Destroy a resampler state. 155 | * @param st Resampler state 156 | */ 157 | void speex_resampler_destroy(SpeexResamplerState *st); 158 | 159 | /** Resample a float array. The input and output buffers must *not* overlap. 160 | * @param st Resampler state 161 | * @param channel_index Index of the channel to process for the multi-channel 162 | * base (0 otherwise) 163 | * @param in Input buffer 164 | * @param in_len Number of input samples in the input buffer. Returns the 165 | * number of samples processed 166 | * @param out Output buffer 167 | * @param out_len Size of the output buffer. Returns the number of samples written 168 | */ 169 | int speex_resampler_process_float(SpeexResamplerState *st, 170 | spx_uint32_t channel_index, 171 | const float *in, 172 | spx_uint32_t *in_len, 173 | float *out, 174 | spx_uint32_t *out_len); 175 | 176 | /** Resample an int array. The input and output buffers must *not* overlap. 177 | * @param st Resampler state 178 | * @param channel_index Index of the channel to process for the multi-channel 179 | * base (0 otherwise) 180 | * @param in Input buffer 181 | * @param in_len Number of input samples in the input buffer. Returns the number 182 | * of samples processed 183 | * @param out Output buffer 184 | * @param out_len Size of the output buffer. Returns the number of samples written 185 | */ 186 | int speex_resampler_process_int(SpeexResamplerState *st, 187 | spx_uint32_t channel_index, 188 | const spx_int16_t *in, 189 | spx_uint32_t *in_len, 190 | spx_int16_t *out, 191 | spx_uint32_t *out_len); 192 | 193 | /** Resample an interleaved float array. The input and output buffers must *not* overlap. 194 | * @param st Resampler state 195 | * @param in Input buffer 196 | * @param in_len Number of input samples in the input buffer. Returns the number 197 | * of samples processed. This is all per-channel. 198 | * @param out Output buffer 199 | * @param out_len Size of the output buffer. Returns the number of samples written. 200 | * This is all per-channel. 201 | */ 202 | int speex_resampler_process_interleaved_float(SpeexResamplerState *st, 203 | const float *in, 204 | spx_uint32_t *in_len, 205 | float *out, 206 | spx_uint32_t *out_len); 207 | 208 | /** Resample an interleaved int array. The input and output buffers must *not* overlap. 209 | * @param st Resampler state 210 | * @param in Input buffer 211 | * @param in_len Number of input samples in the input buffer. Returns the number 212 | * of samples processed. This is all per-channel. 213 | * @param out Output buffer 214 | * @param out_len Size of the output buffer. Returns the number of samples written. 215 | * This is all per-channel. 216 | */ 217 | int speex_resampler_process_interleaved_int(SpeexResamplerState *st, 218 | const spx_int16_t *in, 219 | spx_uint32_t *in_len, 220 | spx_int16_t *out, 221 | spx_uint32_t *out_len); 222 | 223 | /** Set (change) the input/output sampling rates (integer value). 224 | * @param st Resampler state 225 | * @param in_rate Input sampling rate (integer number of Hz). 226 | * @param out_rate Output sampling rate (integer number of Hz). 227 | */ 228 | int speex_resampler_set_rate(SpeexResamplerState *st, 229 | spx_uint32_t in_rate, 230 | spx_uint32_t out_rate); 231 | 232 | /** Get the current input/output sampling rates (integer value). 233 | * @param st Resampler state 234 | * @param in_rate Input sampling rate (integer number of Hz) copied. 235 | * @param out_rate Output sampling rate (integer number of Hz) copied. 236 | */ 237 | void speex_resampler_get_rate(SpeexResamplerState *st, 238 | spx_uint32_t *in_rate, 239 | spx_uint32_t *out_rate); 240 | 241 | /** Set (change) the input/output sampling rates and resampling ratio 242 | * (fractional values in Hz supported). 243 | * @param st Resampler state 244 | * @param ratio_num Numerator of the sampling rate ratio 245 | * @param ratio_den Denominator of the sampling rate ratio 246 | * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). 247 | * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). 248 | */ 249 | int speex_resampler_set_rate_frac(SpeexResamplerState *st, 250 | spx_uint32_t ratio_num, 251 | spx_uint32_t ratio_den, 252 | spx_uint32_t in_rate, 253 | spx_uint32_t out_rate); 254 | 255 | /** Get the current resampling ratio. This will be reduced to the least 256 | * common denominator. 257 | * @param st Resampler state 258 | * @param ratio_num Numerator of the sampling rate ratio copied 259 | * @param ratio_den Denominator of the sampling rate ratio copied 260 | */ 261 | void speex_resampler_get_ratio(SpeexResamplerState *st, 262 | spx_uint32_t *ratio_num, 263 | spx_uint32_t *ratio_den); 264 | 265 | /** Set (change) the conversion quality. 266 | * @param st Resampler state 267 | * @param quality Resampling quality between 0 and 10, where 0 has poor 268 | * quality and 10 has very high quality. 269 | */ 270 | int speex_resampler_set_quality(SpeexResamplerState *st, 271 | int quality); 272 | 273 | /** Get the conversion quality. 274 | * @param st Resampler state 275 | * @param quality Resampling quality between 0 and 10, where 0 has poor 276 | * quality and 10 has very high quality. 277 | */ 278 | void speex_resampler_get_quality(SpeexResamplerState *st, 279 | int *quality); 280 | 281 | /** Set (change) the input stride. 282 | * @param st Resampler state 283 | * @param stride Input stride 284 | */ 285 | void speex_resampler_set_input_stride(SpeexResamplerState *st, 286 | spx_uint32_t stride); 287 | 288 | /** Get the input stride. 289 | * @param st Resampler state 290 | * @param stride Input stride copied 291 | */ 292 | void speex_resampler_get_input_stride(SpeexResamplerState *st, 293 | spx_uint32_t *stride); 294 | 295 | /** Set (change) the output stride. 296 | * @param st Resampler state 297 | * @param stride Output stride 298 | */ 299 | void speex_resampler_set_output_stride(SpeexResamplerState *st, 300 | spx_uint32_t stride); 301 | 302 | /** Get the output stride. 303 | * @param st Resampler state copied 304 | * @param stride Output stride 305 | */ 306 | void speex_resampler_get_output_stride(SpeexResamplerState *st, 307 | spx_uint32_t *stride); 308 | 309 | /** Get the latency introduced by the resampler measured in input samples. 310 | * @param st Resampler state 311 | */ 312 | int speex_resampler_get_input_latency(SpeexResamplerState *st); 313 | 314 | /** Get the latency introduced by the resampler measured in output samples. 315 | * @param st Resampler state 316 | */ 317 | int speex_resampler_get_output_latency(SpeexResamplerState *st); 318 | 319 | /** Make sure that the first samples to go out of the resamplers don't have 320 | * leading zeros. This is only useful before starting to use a newly created 321 | * resampler. It is recommended to use that when resampling an audio file, as 322 | * it will generate a file with the same length. For real-time processing, 323 | * it is probably easier not to use this call (so that the output duration 324 | * is the same for the first frame). 325 | * @param st Resampler state 326 | */ 327 | int speex_resampler_skip_zeros(SpeexResamplerState *st); 328 | 329 | /** Reset a resampler so a new (unrelated) stream can be processed. 330 | * @param st Resampler state 331 | */ 332 | int speex_resampler_reset_mem(SpeexResamplerState *st); 333 | 334 | /** Returns the English meaning for an error code 335 | * @param err Error code 336 | * @return English string 337 | */ 338 | const char *speex_resampler_strerror(int err); 339 | 340 | #ifdef __cplusplus 341 | } 342 | #endif 343 | 344 | #endif 345 | -------------------------------------------------------------------------------- /app/test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 5 | }) : (function(o, m, k, k2) { 6 | if (k2 === undefined) k2 = k; 7 | o[k2] = m[k]; 8 | })); 9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 10 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 11 | }) : function(o, v) { 12 | o["default"] = v; 13 | }); 14 | var __importStar = (this && this.__importStar) || function (mod) { 15 | if (mod && mod.__esModule) return mod; 16 | var result = {}; 17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 18 | __setModuleDefault(result, mod); 19 | return result; 20 | }; 21 | var __importDefault = (this && this.__importDefault) || function (mod) { 22 | return (mod && mod.__esModule) ? mod : { "default": mod }; 23 | }; 24 | Object.defineProperty(exports, "__esModule", { value: true }); 25 | const fs_1 = require("fs"); 26 | // const {promisify} = require('util'); 27 | const perf_hooks_1 = require("perf_hooks"); 28 | const path_1 = __importDefault(require("path")); 29 | const index_1 = __importStar(require("./index")); 30 | const assert = (condition, message) => { 31 | if (!condition) { 32 | throw new Error(message); 33 | } 34 | }; 35 | const audioTests = [ 36 | { inFile: path_1.default.resolve(__dirname, `../resources/24000hz_mono_test.pcm`), inRate: 24000, outRate: 48000, channels: 1, quality: 5 }, 37 | { inFile: path_1.default.resolve(__dirname, `../resources/24000hz_test.pcm`), inRate: 24000, outRate: 24000, channels: 2, quality: 5 }, 38 | { inFile: path_1.default.resolve(__dirname, `../resources/24000hz_test.pcm`), inRate: 24000, outRate: 48000, channels: 2, quality: 10 }, 39 | { inFile: path_1.default.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 48000, channels: 2 }, 40 | { inFile: path_1.default.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 48000, channels: 2, quality: 10 }, 41 | { inFile: path_1.default.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 48000, channels: 2, quality: 1 }, 42 | { inFile: path_1.default.resolve(__dirname, `../resources/44100hz_test.pcm`), inRate: 44100, outRate: 24000, channels: 2, quality: 5 }, 43 | ]; 44 | const promiseBasedTest = async () => { 45 | for (const audioTest of audioTests) { 46 | console.log(`Resampling file ${audioTest.inFile} with ${audioTest.channels} channel(s) from ${audioTest.inRate}Hz to ${audioTest.outRate}Hz (quality: ${audioTest.quality || 7})`); 47 | const resampler = new index_1.default(audioTest.channels, audioTest.inRate, audioTest.outRate, audioTest.quality); 48 | const filename = path_1.default.parse(audioTest.inFile).name; 49 | const pcmData = fs_1.readFileSync(audioTest.inFile); 50 | const start = perf_hooks_1.performance.now(); 51 | const res = await resampler.processChunk(pcmData); 52 | const end = perf_hooks_1.performance.now(); 53 | console.log(`Resampled in ${Math.floor(end - start)}ms`); 54 | console.log(`Input stream: ${pcmData.length} bytes, ${pcmData.length / audioTest.inRate / 2 / audioTest.channels}s`); 55 | console.log(`Output stream: ${res.length} bytes, ${res.length / audioTest.outRate / 2 / audioTest.channels}s`); 56 | const inputDuration = pcmData.length / audioTest.inRate / 2 / audioTest.channels; 57 | const outputDuration = res.length / audioTest.outRate / 2 / audioTest.channels; 58 | assert(Math.abs(inputDuration - outputDuration) < 0.01, `Stream duration not matching target, in: ${inputDuration}s != out:${outputDuration}`); 59 | console.log(); 60 | // writeFileSync(path.resolve(__dirname, `../resources/${filename}_${audioTest.outRate}_${audioTest.quality || 7}_output.pcm`), res); 61 | } 62 | }; 63 | const streamBasedTest = async () => { 64 | console.log('================='); 65 | console.log('Tranform Stream Test'); 66 | console.log('================='); 67 | for (const audioTest of audioTests) { 68 | console.log(`Resampling file ${audioTest.inFile} with ${audioTest.channels} channel(s) from ${audioTest.inRate}Hz to ${audioTest.outRate}Hz (quality: ${audioTest.quality || 7})`); 69 | const readFileStream = fs_1.createReadStream(audioTest.inFile); 70 | const transformStream = new index_1.SpeexResamplerTransform(audioTest.channels, audioTest.inRate, audioTest.outRate, audioTest.quality); 71 | let pcmData = Buffer.alloc(0); 72 | readFileStream.on('data', (d) => { 73 | pcmData = Buffer.concat([pcmData, d]); 74 | }); 75 | let res = Buffer.alloc(0); 76 | transformStream.on('data', (d) => { 77 | res = Buffer.concat([res, d]); 78 | }); 79 | const start = perf_hooks_1.performance.now(); 80 | readFileStream.pipe(transformStream); 81 | await new Promise((r) => transformStream.on('end', r)); 82 | const end = perf_hooks_1.performance.now(); 83 | console.log(`Resampled in ${Math.floor(end - start)}ms`); 84 | console.log(`Input stream: ${pcmData.length} bytes, ${pcmData.length / audioTest.inRate / 2 / audioTest.channels}s`); 85 | console.log(`Output stream: ${res.length} bytes, ${res.length / audioTest.outRate / 2 / audioTest.channels}s`); 86 | const inputDuration = pcmData.length / audioTest.inRate / 2 / audioTest.channels; 87 | const outputDuration = res.length / audioTest.outRate / 2 / audioTest.channels; 88 | assert(Math.abs(inputDuration - outputDuration) < 0.01, `Stream duration not matching target, in: ${inputDuration}s != out:${outputDuration}`); 89 | console.log(); 90 | } 91 | }; 92 | promiseBasedTest() 93 | .then(() => streamBasedTest()).catch((e) => { 94 | console.error(e); 95 | process.exit(1); 96 | }); 97 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIvIiwic291cmNlcyI6WyJ0ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDJCQUFnRTtBQUNoRSx1Q0FBdUM7QUFDdkMsMkNBQXdDO0FBQ3hDLGdEQUF3QjtBQUV4QixpREFBZ0U7QUFFaEUsTUFBTSxNQUFNLEdBQUcsQ0FBQyxTQUFTLEVBQUUsT0FBTyxFQUFFLEVBQUU7SUFDcEMsSUFBSSxDQUFDLFNBQVMsRUFBRTtRQUNkLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7S0FDMUI7QUFDSCxDQUFDLENBQUE7QUFFRCxNQUFNLFVBQVUsR0FBRztJQUNqQixFQUFDLE1BQU0sRUFBRSxjQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxvQ0FBb0MsQ0FBQyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUM7SUFDL0gsRUFBQyxNQUFNLEVBQUUsY0FBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsK0JBQStCLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFDO0lBQzFILEVBQUMsTUFBTSxFQUFFLGNBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLCtCQUErQixDQUFDLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBQztJQUMzSCxFQUFDLE1BQU0sRUFBRSxjQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSwrQkFBK0IsQ0FBQyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUs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Q0FBNEMsYUFBYSxZQUFZLGNBQWMsRUFBRSxDQUFDLENBQUM7UUFDL0ksT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO0tBQ2Y7QUFDSCxDQUFDLENBQUE7QUFFRCxnQkFBZ0IsRUFBRTtLQUNqQixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtJQUN6QyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDbEIsQ0FBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge3JlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyxjcmVhdGVSZWFkU3RyZWFtfSBmcm9tICdmcyc7XG4vLyBjb25zdCB7cHJvbWlzaWZ5fSA9IHJlcXVpcmUoJ3V0aWwnKTtcbmltcG9ydCB7IHBlcmZvcm1hbmNlIH0gZnJvbSAncGVyZl9ob29rcydcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgU3BlZXhSZXNhbXBsZXIsIHtTcGVleFJlc2FtcGxlclRyYW5zZm9ybX0gZnJvbSAnLi9pbmRleCc7XG5cbmNvbnN0IGFzc2VydCA9IChjb25kaXRpb24sIG1lc3NhZ2UpID0+IHtcbiAgaWYgKCFjb25kaXRpb24pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSk7XG4gIH1cbn1cblxuY29uc3QgYXVkaW9UZXN0cyA9IFtcbiAge2luRmlsZTogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYC4uL3Jlc291cmNlcy8yNDAwMGh6X21vbm9fdGVzdC5wY21gKSwgaW5SYXRlOiAyNDAwMCwgb3V0UmF0ZTogNDgwMDAsIGNoYW5uZWxzOiAxLCBxdWFsaXR5OiA1fSxcbiAge2luRmlsZTogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYC4uL3Jlc291cmNlcy8yNDAwMGh6X3Rlc3QucGNtYCksIGluUmF0ZTogMjQwMDAsIG91dFJhdGU6IDI0MDAwLCBjaGFubmVsczogMiwgcXVhbGl0eTogNX0sXG4gIHtpbkZpbGU6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsIGAuLi9yZXNvdXJjZXMvMjQwMDBoel90ZXN0LnBjbWApLCBpblJhdGU6IDI0MDAwLCBvdXRSYXRlOiA0ODAwMCwgY2hhbm5lbHM6IDIsIHF1YWxpdHk6IDEwfSxcbiAge2luRmlsZTogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYC4uL3Jlc291cmNlcy80NDEwMGh6X3Rlc3QucGNtYCksIGluUmF0ZTogNDQxMDAsIG91dFJhdGU6IDQ4MDAwLCBjaGFubmVsczogMn0sXG4gIHtpbkZpbGU6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsIGAuLi9yZXNvdXJjZXMvNDQxMDBoel90ZXN0LnBjbWApLCBpblJhdGU6IDQ0MTAwLCBvdXRSYXRlOiA0ODAwMCwgY2hhbm5lbHM6IDIsIHF1YWxpdHk6IDEwfSxcbiAge2luRmlsZTogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgYC4uL3Jlc291cmNlcy80NDEwMGh6X3Rlc3QucGNtYCksIGluUmF0ZTogNDQxMDAsIG91dFJhdGU6IDQ4MDAwLCBjaGFubmVsczogMiwgcXVhbGl0eTogMX0sXG4gIHtpbkZpbGU6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsIGAuLi9yZXNvdXJjZXMvNDQxMDBoel90ZXN0LnBjbWApLCBpblJhdGU6IDQ0MTAwLCBvdXRSYXRlOiAyNDAwMCwgY2hhbm5lbHM6IDIsIHF1YWxpdHk6IDV9LFxuXTtcblxuY29uc3QgcHJvbWlzZUJhc2VkVGVzdCA9IGFzeW5jICgpID0+IHtcbiAgZm9yIChjb25zdCBhdWRpb1Rlc3Qgb2YgYXVkaW9UZXN0cykge1xuICAgIGNvbnNvbGUubG9nKGBSZXNhbXBsaW5nIGZpbGUgJHthdWRpb1Rlc3QuaW5GaWxlfSB3aXRoICR7YXVkaW9UZXN0LmNoYW5uZWxzfSBjaGFubmVsKHMpIGZyb20gJHthdWRpb1Rlc3QuaW5SYXRlfUh6IHRvICR7YXVkaW9UZXN0Lm91dFJhdGV9SHogKHF1YWxpdHk6ICR7YXVkaW9UZXN0LnF1YWxpdHkgfHwgN30pYCk7XG4gICAgY29uc3QgcmVzYW1wbGVyID0gbmV3IFNwZWV4UmVzYW1wbGVyKGF1ZGlvVGVzdC5jaGFubmVscywgYXVkaW9UZXN0LmluUmF0ZSwgYXVkaW9UZXN0Lm91dFJhdGUsIGF1ZGlvVGVzdC5xdWFsaXR5KTtcbiAgICBjb25zdCBmaWxlbmFtZSA9IHBhdGgucGFyc2UoYXVkaW9UZXN0LmluRmlsZSkubmFtZTtcbiAgICBjb25zdCBwY21EYXRhID0gcmVhZEZpbGVTeW5jKGF1ZGlvVGVzdC5pbkZpbGUpO1xuXG4gICAgY29uc3Qgc3RhcnQgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICBjb25zdCByZXMgPSBhd2FpdCByZXNhbXBsZXIucHJvY2Vzc0NodW5rKHBjbURhdGEpO1xuICAgIGNvbnN0IGVuZCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgIGNvbnNvbGUubG9nKGBSZXNhbXBsZWQgaW4gJHtNYXRoLmZsb29yKGVuZCAtIHN0YXJ0KX1tc2ApO1xuICAgIGNvbnNvbGUubG9nKGBJbnB1dCBzdHJlYW06ICR7cGNtRGF0YS5sZW5ndGh9IGJ5dGVzLCAke3BjbURhdGEubGVuZ3RoIC8gYXVkaW9UZXN0LmluUmF0ZSAvIDIgLyBhdWRpb1Rlc3QuY2hhbm5lbHN9c2ApO1xuICAgIGNvbnNvbGUubG9nKGBPdXRwdXQgc3RyZWFtOiAke3Jlcy5sZW5ndGh9IGJ5dGVzLCAke3Jlcy5sZW5ndGggLyBhdWRpb1Rlc3Qub3V0UmF0ZSAvIDIgLyBhdWRpb1Rlc3QuY2hhbm5lbHN9c2ApO1xuXG4gICAgY29uc3QgaW5wdXREdXJhdGlvbiA9IHBjbURhdGEubGVuZ3RoIC8gYXVkaW9UZXN0LmluUmF0ZSAvIDIgLyBhdWRpb1Rlc3QuY2hhbm5lbHM7XG4gICAgY29uc3Qgb3V0cHV0RHVyYXRpb24gPSByZXMubGVuZ3RoIC8gYXVkaW9UZXN0Lm91dFJhdGUgLyAyIC8gYXVkaW9UZXN0LmNoYW5uZWxzO1xuICAgIGFzc2VydChNYXRoLmFicyhpbnB1dER1cmF0aW9uIC0gb3V0cHV0RHVyYXRpb24pIDwgMC4wMSwgYFN0cmVhbSBkdXJhdGlvbiBub3QgbWF0Y2hpbmcgdGFyZ2V0LCBpbjogJHtpbnB1dER1cmF0aW9ufXMgIT0gb3V0OiR7b3V0cHV0RHVyYXRpb259YCk7XG4gICAgY29uc29sZS5sb2coKTtcbiAgICAvLyB3cml0ZUZpbGVTeW5jKHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsIGAuLi9yZXNvdXJjZXMvJHtmaWxlbmFtZX1fJHthdWRpb1Rlc3Qub3V0UmF0ZX1fJHthdWRpb1Rlc3QucXVhbGl0eSB8fCA3fV9vdXRwdXQucGNtYCksIHJlcyk7XG4gIH1cbn1cblxuY29uc3Qgc3RyZWFtQmFzZWRUZXN0ID0gYXN5bmMgKCkgPT4ge1xuICBjb25zb2xlLmxvZygnPT09PT09PT09PT09PT09PT0nKTtcbiAgY29uc29sZS5sb2coJ1RyYW5mb3JtIFN0cmVhbSBUZXN0Jyk7XG4gIGNvbnNvbGUubG9nKCc9PT09PT09PT09PT09PT09PScpO1xuXG4gIGZvciAoY29uc3QgYXVkaW9UZXN0IG9mIGF1ZGlvVGVzdHMpIHtcbiAgICBjb25zb2xlLmxvZyhgUmVzYW1wbGluZyBmaWxlICR7YXVkaW9UZXN0LmluRmlsZX0gd2l0aCAke2F1ZGlvVGVzdC5jaGFubmVsc30gY2hhbm5lbChzKSBmcm9tICR7YXVkaW9UZXN0LmluUmF0ZX1IeiB0byAke2F1ZGlvVGVzdC5vdXRSYXRlfUh6IChxdWFsaXR5OiAke2F1ZGlvVGVzdC5xdWFsaXR5IHx8IDd9KWApO1xuICAgIGNvbnN0IHJlYWRGaWxlU3RyZWFtID0gY3JlYXRlUmVhZFN0cmVhbShhdWRpb1Rlc3QuaW5GaWxlKTtcbiAgICBjb25zdCB0cmFuc2Zvcm1TdHJlYW0gPSBuZXcgU3BlZXhSZXNhbXBsZXJUcmFuc2Zvcm0oYXVkaW9UZXN0LmNoYW5uZWxzLCBhdWRpb1Rlc3QuaW5SYXRlLCBhdWRpb1Rlc3Qub3V0UmF0ZSwgYXVkaW9UZXN0LnF1YWxpdHkpO1xuICAgIGxldCBwY21EYXRhID0gQnVmZmVyLmFsbG9jKDApO1xuICAgIHJlYWRGaWxlU3RyZWFtLm9uKCdkYXRhJywgKGQpID0+IHtcbiAgICAgIHBjbURhdGEgPSBCdWZmZXIuY29uY2F0KFsgcGNtRGF0YSwgZCBhcyBCdWZmZXIgXSk7XG4gICAgfSk7XG4gICAgbGV0IHJlcyA9IEJ1ZmZlci5hbGxvYygwKTtcbiAgICB0cmFuc2Zvcm1TdHJlYW0ub24oJ2RhdGEnLCAoZCkgPT4ge1xuICAgICAgcmVzID0gQnVmZmVyLmNvbmNhdChbIHJlcywgZCBhcyBCdWZmZXIgXSk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBzdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgIHJlYWRGaWxlU3RyZWFtLnBpcGUodHJhbnNmb3JtU3RyZWFtKTtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocikgPT4gdHJhbnNmb3JtU3RyZWFtLm9uKCdlbmQnLCByKSk7XG4gICAgY29uc3QgZW5kID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgY29uc29sZS5sb2coYFJlc2FtcGxlZCBpbiAke01hdGguZmxvb3IoZW5kIC0gc3RhcnQpfW1zYCk7XG4gICAgY29uc29sZS5sb2coYElucHV0IHN0cmVhbTogJHtwY21EYXRhLmxlbmd0aH0gYnl0ZXMsICR7cGNtRGF0YS5sZW5ndGggLyBhdWRpb1Rlc3QuaW5SYXRlIC8gMiAvIGF1ZGlvVGVzdC5jaGFubmVsc31zYCk7XG4gICAgY29uc29sZS5sb2coYE91dHB1dCBzdHJlYW06ICR7cmVzLmxlbmd0aH0gYnl0ZXMsICR7cmVzLmxlbmd0aCAvIGF1ZGlvVGVzdC5vdXRSYXRlIC8gMiAvIGF1ZGlvVGVzdC5jaGFubmVsc31zYCk7XG5cbiAgICBjb25zdCBpbnB1dER1cmF0aW9uID0gcGNtRGF0YS5sZW5ndGggLyBhdWRpb1Rlc3QuaW5SYXRlIC8gMiAvIGF1ZGlvVGVzdC5jaGFubmVscztcbiAgICBjb25zdCBvdXRwdXREdXJhdGlvbiA9IHJlcy5sZW5ndGggLyBhdWRpb1Rlc3Qub3V0UmF0ZSAvIDIgLyBhdWRpb1Rlc3QuY2hhbm5lbHM7XG4gICAgYXNzZXJ0KE1hdGguYWJzKGlucHV0RHVyYXRpb24gLSBvdXRwdXREdXJhdGlvbikgPCAwLjAxLCBgU3RyZWFtIGR1cmF0aW9uIG5vdCBtYXRjaGluZyB0YXJnZXQsIGluOiAke2lucHV0RHVyYXRpb259cyAhPSBvdXQ6JHtvdXRwdXREdXJhdGlvbn1gKTtcbiAgICBjb25zb2xlLmxvZygpO1xuICB9XG59XG5cbnByb21pc2VCYXNlZFRlc3QoKVxuLnRoZW4oKCkgPT4gc3RyZWFtQmFzZWRUZXN0KCkpLmNhdGNoKChlKSA9PiB7XG4gIGNvbnNvbGUuZXJyb3IoZSk7XG4gIHByb2Nlc3MuZXhpdCgxKTtcbn0pXG4iXX0= -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /// 3 | var __importDefault = (this && this.__importDefault) || function (mod) { 4 | return (mod && mod.__esModule) ? mod : { "default": mod }; 5 | }; 6 | Object.defineProperty(exports, "__esModule", { value: true }); 7 | exports.SpeexResamplerTransform = void 0; 8 | const stream_1 = require("stream"); 9 | const speex_wasm_1 = __importDefault(require("./speex_wasm")); 10 | let speexModule; 11 | let globalModulePromise = speex_wasm_1.default().then((s) => speexModule = s); 12 | class SpeexResampler { 13 | /** 14 | * Create an SpeexResampler tranform stream. 15 | * @param channels Number of channels, minimum is 1, no maximum 16 | * @param inRate frequency in Hz for the input chunk 17 | * @param outRate frequency in Hz for the target chunk 18 | * @param quality number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 19 | */ 20 | constructor(channels, inRate, outRate, quality = 7) { 21 | this.channels = channels; 22 | this.inRate = inRate; 23 | this.outRate = outRate; 24 | this.quality = quality; 25 | this._inBufferPtr = -1; 26 | this._inBufferSize = -1; 27 | this._outBufferPtr = -1; 28 | this._outBufferSize = -1; 29 | this._inLengthPtr = -1; 30 | this._outLengthPtr = -1; 31 | } 32 | /** 33 | * Resample a chunk of audio. 34 | * @param chunk interleaved PCM data in signed 16bits int 35 | */ 36 | processChunk(chunk) { 37 | if (!speexModule) { 38 | throw new Error('You need to wait for SpeexResampler.initPromise before calling this method'); 39 | } 40 | // We check that we have as many chunks for each channel and that the last chunk is full (2 bytes) 41 | if (chunk.length % (this.channels * Uint16Array.BYTES_PER_ELEMENT) !== 0) { 42 | throw new Error('Chunk length should be a multiple of channels * 2 bytes'); 43 | } 44 | if (!this._resamplerPtr) { 45 | const errPtr = speexModule._malloc(4); 46 | this._resamplerPtr = speexModule._speex_resampler_init(this.channels, this.inRate, this.outRate, this.quality, errPtr); 47 | const errNum = speexModule.getValue(errPtr, 'i32'); 48 | if (errNum !== 0) { 49 | throw new Error(speexModule.AsciiToString(speexModule._speex_resampler_strerror(errNum))); 50 | } 51 | this._inLengthPtr = speexModule._malloc(Uint32Array.BYTES_PER_ELEMENT); 52 | this._outLengthPtr = speexModule._malloc(Uint32Array.BYTES_PER_ELEMENT); 53 | } 54 | // Resizing the input buffer in the WASM memory space to match what we need 55 | if (this._inBufferSize < chunk.length) { 56 | if (this._inBufferPtr !== -1) { 57 | speexModule._free(this._inBufferPtr); 58 | } 59 | this._inBufferPtr = speexModule._malloc(chunk.length); 60 | this._inBufferSize = chunk.length; 61 | } 62 | // Resizing the output buffer in the WASM memory space to match what we need 63 | const outBufferLengthTarget = Math.ceil(chunk.length * this.outRate / this.inRate); 64 | if (this._outBufferSize < outBufferLengthTarget) { 65 | if (this._outBufferPtr !== -1) { 66 | speexModule._free(this._outBufferPtr); 67 | } 68 | this._outBufferPtr = speexModule._malloc(outBufferLengthTarget); 69 | this._outBufferSize = outBufferLengthTarget; 70 | } 71 | // number of samples per channel in input buffer 72 | speexModule.setValue(this._inLengthPtr, chunk.length / this.channels / Uint16Array.BYTES_PER_ELEMENT, 'i32'); 73 | // Copying the info from the input Buffer in the WASM memory space 74 | speexModule.HEAPU8.set(chunk, this._inBufferPtr); 75 | // number of samples per channels available in output buffer 76 | speexModule.setValue(this._outLengthPtr, this._outBufferSize / this.channels / Uint16Array.BYTES_PER_ELEMENT, 'i32'); 77 | const errNum = speexModule._speex_resampler_process_interleaved_int(this._resamplerPtr, this._inBufferPtr, this._inLengthPtr, this._outBufferPtr, this._outLengthPtr); 78 | if (errNum !== 0) { 79 | throw new Error(speexModule.AsciiToString(speexModule._speex_resampler_strerror(errNum))); 80 | } 81 | const outSamplesPerChannelsWritten = speexModule.getValue(this._outLengthPtr, 'i32'); 82 | // we are copying the info in a new buffer here, we could just pass a buffer pointing to the same memory space if needed 83 | return Buffer.from(speexModule.HEAPU8.slice(this._outBufferPtr, this._outBufferPtr + outSamplesPerChannelsWritten * this.channels * Uint16Array.BYTES_PER_ELEMENT).buffer); 84 | } 85 | } 86 | SpeexResampler.initPromise = globalModulePromise; 87 | const EMPTY_BUFFER = Buffer.alloc(0); 88 | class SpeexResamplerTransform extends stream_1.Transform { 89 | /** 90 | * Create an SpeexResampler instance. 91 | * @param channels Number of channels, minimum is 1, no maximum 92 | * @param inRate frequency in Hz for the input chunk 93 | * @param outRate frequency in Hz for the target chunk 94 | * @param quality number from 1 to 10, default to 7, 1 is fast but of bad quality, 10 is slow but best quality 95 | */ 96 | constructor(channels, inRate, outRate, quality = 7) { 97 | super(); 98 | this.channels = channels; 99 | this.inRate = inRate; 100 | this.outRate = outRate; 101 | this.quality = quality; 102 | this.resampler = new SpeexResampler(channels, inRate, outRate, quality); 103 | this.channels = channels; 104 | this._alignementBuffer = EMPTY_BUFFER; 105 | } 106 | _transform(chunk, encoding, callback) { 107 | let chunkToProcess = chunk; 108 | if (this._alignementBuffer.length > 0) { 109 | chunkToProcess = Buffer.concat([ 110 | this._alignementBuffer, 111 | chunk, 112 | ]); 113 | this._alignementBuffer = EMPTY_BUFFER; 114 | } 115 | // Speex needs a buffer aligned to 16bits times the number of channels 116 | // so we keep the extraneous bytes in a buffer for next chunk 117 | const extraneousBytesCount = chunkToProcess.length % (this.channels * Uint16Array.BYTES_PER_ELEMENT); 118 | if (extraneousBytesCount !== 0) { 119 | this._alignementBuffer = Buffer.from(chunkToProcess.slice(chunkToProcess.length - extraneousBytesCount)); 120 | chunkToProcess = chunkToProcess.slice(0, chunkToProcess.length - extraneousBytesCount); 121 | } 122 | try { 123 | const res = this.resampler.processChunk(chunkToProcess); 124 | callback(null, res); 125 | } 126 | catch (e) { 127 | callback(e); 128 | } 129 | } 130 | } 131 | exports.SpeexResamplerTransform = SpeexResamplerTransform; 132 | exports.default = SpeexResampler; 133 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiLyIsInNvdXJjZXMiOlsiaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLG9DQUFvQzs7Ozs7O0FBRXBDLG1DQUFtQztBQUNuQyw4REFBcUM7QUFjckMsSUFBSSxXQUF3QyxDQUFDO0FBQzdDLElBQUksbUJBQW1CLEdBQUcsb0JBQVMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBRW5FLE1BQU0sY0FBYztJQVlsQjs7Ozs7O1FBTUk7SUFDSixZQUNTLFFBQVEsRUFDUixNQUFNLEVBQ04sT0FBTyxFQUNQLFVBQVUsQ0FBQztRQUhYLGFBQVEsR0FBUixRQUFRLENBQUE7UUFDUixXQUFNLEdBQU4sTUFBTSxDQUFBO1FBQ04sWUFBTyxHQUFQLE9BQU8sQ0FBQTtRQUNQLFlBQU8sR0FBUCxPQUFPLENBQUk7UUFyQnBCLGlCQUFZLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDbEIsa0JBQWEsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNuQixrQkFBYSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ25CLG1CQUFjLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFcEIsaUJBQVksR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNsQixrQkFBYSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBZUksQ0FBQztJQUV4Qjs7O1FBR0k7SUFDSixZQUFZLENBQUMsS0FBYTtRQUN4QixJQUFJLENBQUMsV0FBVyxFQUFFO1lBQ2hCLE1BQU0sSUFBSSxLQUFLLENBQUMsNEVBQTRFLENBQUMsQ0FBQztTQUMvRjtRQUNELGtHQUFrRztRQUNsRyxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUN4RSxNQUFNLElBQUksS0FBSyxDQUFDLHlEQUF5RCxDQUFDLENBQUM7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QVcsS0FBSyxDQUFDO1FBQ25DLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDckMsY0FBYyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7Z0JBQzdCLElBQUksQ0FBQyxpQkFBaUI7Z0JBQ3RCLEtBQUs7YUFDTixDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsWUFBWSxDQUFDO1NBQ3ZDO1FBQ0Qsc0VBQXNFO1FBQ3RFLDZEQUE2RDtRQUM3RCxNQUFNLG9CQUFvQixHQUFHLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3JHLElBQUksb0JBQW9CLEtBQUssQ0FBQyxFQUFFO1lBQzlCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxvQkFBb0IsQ0FBQyxDQUFDLENBQUM7WUFDekcsY0FBYyxHQUFHLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLGNBQWMsQ0FBQyxNQUFNLEdBQUcsb0JBQW9CLENBQUMsQ0FBQztTQUN4RjtRQUNELElBQUk7WUFDRixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN4RCxRQUFRLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1NBQ3JCO1FBQUMsT0FBTyxDQUFDLEVBQUU7WUFDVixRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDYjtJQUNILENBQUM7Q0FDRjtBQXpDRCwwREF5Q0M7QUFFRCxrQkFBZSxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLy8gPHJlZmVyZW5jZSB0eXBlcz1cImVtc2NyaXB0ZW5cIiAvPlxuXG5pbXBvcnQgeyBUcmFuc2Zvcm0gfSBmcm9tICdzdHJlYW0nO1xuaW1wb3J0IFNwZWV4V2FzbSBmcm9tICcuL3NwZWV4X3dhc20nO1xuXG5pbnRlcmZhY2UgRW1zY3JpcHRlbk1vZHVsZU9wdXNFbmNvZGVyIGV4dGVuZHMgRW1zY3JpcHRlbk1vZHVsZSB7XG4gIF9zcGVleF9yZXNhbXBsZXJfaW5pdChuYkNoYW5uZWxzOiBudW1iZXIsIGluUmF0ZTogbnVtYmVyLCBvdXRSYXRlOiBudW1iZXIsIHF1YWxpdHk6IG51bWJlciwgZXJyUG9pbnRlcjogbnVtYmVyKTogbnVtYmVyO1xuICBfc3BlZXhfcmVzYW1wbGVyX2Rlc3Ryb3kocmVzYW1wbGVyUHRyOiBudW1iZXIpOiB2b2lkO1xuICBfc3BlZXhfcmVzYW1wbGVyX2dldF9yYXRlKHJlc2FtcGxlclB0cjogbnVtYmVyLCBpblJhdGVQdHI6IG51bWJlciwgb3V0UmF0ZVB0cjogbnVtYmVyKTtcbiAgX3NwZWV4X3Jlc2FtcGxlcl9wcm9jZXNzX2ludGVybGVhdmVkX2ludChyZXNhbXBsZXJQdHI6IG51bWJlciwgaW5CdWZmZXJQdHI6IG51bWJlciwgaW5MZW5QdHI6IG51bWJlciwgb3V0QnVmZmVyUHRyOiBudW1iZXIsIG91dExlblB0cjogbnVtYmVyKTogbnVtYmVyO1xuICBfc3BlZXhfcmVzYW1wbGVyX3N0cmVycm9yKGVycjogbnVtYmVyKTogbnVtYmVyO1xuXG4gIGdldFZhbHVlKHB0cjogbnVtYmVyLCB0eXBlOiBzdHJpbmcpOiBhbnk7XG4gIHNldFZhbHVlKHB0cjogbnVtYmVyLCB2YWx1ZTogYW55LCB0eXBlOiBzdHJpbmcpOiBhbnk7XG4gIEFzY2lpVG9TdHJpbmcocHRyOiBudW1iZXIpOiBzdHJpbmc7XG59XG5cbmxldCBzcGVleE1vZHVsZTogRW1zY3JpcHRlbk1vZHVsZU9wdXNFbmNvZGVyO1xubGV0IGdsb2JhbE1vZHVsZVByb21pc2UgPSBTcGVleFdhc20oKS50aGVuKChzKSA9PiBzcGVleE1vZHVsZSA9IHMpO1xuXG5jbGFzcyBTcGVleFJlc2FtcGxlciB7XG4gIF9yZXNhbXBsZXJQdHI6IG51bWJlcjtcbiAgX2luQnVmZmVyUHRyID0gLTE7XG4gIF9pbkJ1ZmZlclNpemUgPSAtMTtcbiAgX291dEJ1ZmZlclB0ciA9IC0xO1xuICBfb3V0QnVmZmVyU2l6ZSA9IC0xO1xuXG4gIF9pbkxlbmd0aFB0ciA9IC0xO1xuICBfb3V0TGVuZ3RoUHRyID0gLTE7XG5cbiAgc3RhdGljIGluaXRQcm9taXNlID0gZ2xvYmFsTW9kdWxlUHJvbWlzZSBhcyBQcm9taXNlPGFueT47XG5cbiAgLyoqXG4gICAgKiBDcmVhdGUgYW4gU3BlZXhSZXNhbXBsZXIgdHJhbmZvcm0gc3RyZWFtLlxuICAgICogQHBhcmFtIGNoYW5uZWxzIE51bWJlciBvZiBjaGFubmVscywgbWluaW11bSBpcyAxLCBubyBtYXhpbXVtXG4gICAgKiBAcGFyYW0gaW5SYXRlIGZyZXF1ZW5jeSBpbiBIeiBmb3IgdGhlIGlucHV0IGNodW5rXG4gICAgKiBAcGFyYW0gb3V0UmF0ZSBmcmVxdWVuY3kgaW4gSHogZm9yIHRoZSB0YXJnZXQgY2h1bmtcbiAgICAqIEBwYXJhbSBxdWFsaXR5IG51bWJlciBmcm9tIDEgdG8gMTAsIGRlZmF1bHQgdG8gNywgMSBpcyBmYXN0IGJ1dCBvZiBiYWQgcXVhbGl0eSwgMTAgaXMgc2xvdyBidXQgYmVzdCBxdWFsaXR5XG4gICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGNoYW5uZWxzLFxuICAgIHB1YmxpYyBpblJhdGUsXG4gICAgcHVibGljIG91dFJhdGUsXG4gICAgcHVibGljIHF1YWxpdHkgPSA3KSB7fVxuXG4gIC8qKlxuICAgICogUmVzYW1wbGUgYSBjaHVuayBvZiBhdWRpby5cbiAgICAqIEBwYXJhbSBjaHVuayBpbnRlcmxlYXZlZCBQQ00gZGF0YSBpbiBzaWduZWQgMTZiaXRzIGludFxuICAgICovXG4gIHByb2Nlc3NDaHVuayhjaHVuazogQnVmZmVyKSB7XG4gICAgaWYgKCFzcGVleE1vZHVsZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byB3YWl0IGZvciBTcGVleFJlc2FtcGxlci5pbml0UHJvbWlzZSBiZWZvcmUgY2FsbGluZyB0aGlzIG1ldGhvZCcpO1xuICAgIH1cbiAgICAvLyBXZSBjaGVjayB0aGF0IHdlIGhhdmUgYXMgbWFueSBjaHVua3MgZm9yIGVhY2ggY2hhbm5lbCBhbmQgdGhhdCB0aGUgbGFzdCBjaHVuayBpcyBmdWxsICgyIGJ5dGVzKVxuICAgIGlmIChjaHVuay5sZW5ndGggJSAodGhpcy5jaGFubmVscyAqIFVpbnQxNkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UKSAhPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDaHVuayBsZW5ndGggc2hvdWxkIGJlIGEgbXVsdGlwbGUgb2YgY2hhbm5lbHMgKiAyIGJ5dGVzJyk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLl9yZXNhbXBsZXJQdHIpIHtcbiAgICAgIGNvbnN0IGVyclB0ciA9IHNwZWV4TW9kdWxlLl9tYWxsb2MoNCk7XG4gICAgICB0aGlzLl9yZXNhbXBsZXJQdHIgPSBzcGVleE1vZHVsZS5fc3BlZXhfcmVzYW1wbGVyX2luaXQodGhpcy5jaGFubmVscywgdGhpcy5pblJhdGUsIHRoaXMub3V0UmF0ZSwgdGhpcy5xdWFsaXR5LCBlcnJQdHIpO1xuICAgICAgY29uc3QgZXJyTnVtID0gc3BlZXhNb2R1bGUuZ2V0VmFsdWUoZXJyUHRyLCAnaTMyJyk7XG4gICAgICBpZiAoZXJyTnVtICE9PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihzcGVleE1vZHVsZS5Bc2NpaVRvU3RyaW5nKHNwZWV4TW9kdWxlLl9zcGVleF9yZXNhbXBsZXJfc3RyZXJyb3IoZXJyTnVtKSkpO1xuICAgICAgfVxuICAgICAgdGhpcy5faW5MZW5ndGhQdHIgPSBzcGVleE1vZHVsZS5fbWFsbG9jKFVpbnQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UKTtcbiAgICAgIHRoaXMuX291dExlbmd0aFB0ciA9IHNwZWV4TW9kdWxlLl9tYWxsb2MoVWludDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQpO1xuICAgIH1cblxuICAgIC8vIFJlc2l6aW5nIHRoZSBpbnB1dCBidWZmZXIgaW4gdGhlIFdBU00gbWVtb3J5IHNwYWNlIHRvIG1hdGNoIHdoYXQgd2UgbmVlZFxuICAgIGlmICh0aGlzLl9pbkJ1ZmZlclNpemUgPCBjaHVuay5sZW5ndGgpIHtcbiAgICAgIGlmICh0aGlzLl9pbkJ1ZmZlclB0ciAhPT0gLTEpIHtcbiAgICAgICAgc3BlZXhNb2R1bGUuX2ZyZWUodGhpcy5faW5CdWZmZXJQdHIpO1xuICAgICAgfVxuICAgICAgdGhpcy5faW5CdWZmZXJQdHIgPSBzcGVleE1vZHVsZS5fbWFsbG9jKGNodW5rLmxlbmd0aCk7XG4gICAgICB0aGlzLl9pbkJ1ZmZlclNpemUgPSBjaHVuay5sZW5ndGg7XG4gICAgfVxuXG4gICAgLy8gUmVzaXppbmcgdGhlIG91dHB1dCBidWZmZXIgaW4gdGhlIFdBU00gbWVtb3J5IHNwYWNlIHRvIG1hdGNoIHdoYXQgd2UgbmVlZFxuICAgIGNvbnN0IG91dEJ1ZmZlckxlbmd0aFRhcmdldCA9IE1hdGguY2VpbChjaHVuay5sZW5ndGggKiB0aGlzLm91dFJhdGUgLyB0aGlzLmluUmF0ZSk7XG4gICAgaWYgKHRoaXMuX291dEJ1ZmZlclNpemUgPCBvdXRCdWZmZXJMZW5ndGhUYXJnZXQpIHtcbiAgICAgIGlmICh0aGlzLl9vdXRCdWZmZXJQdHIgIT09IC0xKSB7XG4gICAgICAgIHNwZWV4TW9kdWxlLl9mcmVlKHRoaXMuX291dEJ1ZmZlclB0cik7XG4gICAgICB9XG4gICAgICB0aGlzLl9vdXRCdWZmZXJQdHIgPSBzcGVleE1vZHVsZS5fbWFsbG9jKG91dEJ1ZmZlckxlbmd0aFRhcmdldCk7XG4gICAgICB0aGlzLl9vdXRCdWZmZXJTaXplID0gb3V0QnVmZmVyTGVuZ3RoVGFyZ2V0O1xuICAgIH1cblxuICAgIC8vIG51bWJlciBvZiBzYW1wbGVzIHBlciBjaGFubmVsIGluIGlucHV0IGJ1ZmZlclxuICAgIHNwZWV4TW9kdWxlLnNldFZhbHVlKHRoaXMuX2luTGVuZ3RoUHRyLCBjaHVuay5sZW5ndGggLyB0aGlzLmNoYW5uZWxzIC8gVWludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlQsICdpMzInKTtcbiAgICAvLyBDb3B5aW5nIHRoZSBpbmZvIGZyb20gdGhlIGlucHV0IEJ1ZmZlciBpbiB0aGUgV0FTTSBtZW1vcnkgc3BhY2VcbiAgICBzcGVleE1vZHVsZS5IRUFQVTguc2V0KGNodW5rLCB0aGlzLl9pbkJ1ZmZlclB0cik7XG5cbiAgICAvLyBudW1iZXIgb2Ygc2FtcGxlcyBwZXIgY2hhbm5lbHMgYXZhaWxhYmxlIGluIG91dHB1dCBidWZmZXJcbiAgICBzcGVleE1vZHVsZS5zZXRWYWx1ZSh0aGlzLl9vdXRMZW5ndGhQdHIsIHRoaXMuX291dEJ1ZmZlclNpemUgLyB0aGlzLmNoYW5uZWxzIC8gVWludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlQsICdpMzInKTtcbiAgICBjb25zdCBlcnJOdW0gPSBzcGVleE1vZHVsZS5fc3BlZXhfcmVzYW1wbGVyX3Byb2Nlc3NfaW50ZXJsZWF2ZWRfaW50KFxuICAgICAgdGhpcy5fcmVzYW1wbGVyUHRyLFxuICAgICAgdGhpcy5faW5CdWZmZXJQdHIsXG4gICAgICB0aGlzLl9pbkxlbmd0aFB0cixcbiAgICAgIHRoaXMuX291dEJ1ZmZlclB0cixcbiAgICAgIHRoaXMuX291dExlbmd0aFB0cixcbiAgICApO1xuXG4gICAgaWYgKGVyck51bSAhPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKHNwZWV4TW9kdWxlLkFzY2lpVG9TdHJpbmcoc3BlZXhNb2R1bGUuX3NwZWV4X3Jlc2FtcGxlcl9zdHJlcnJvcihlcnJOdW0pKSk7XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0U2FtcGxlc1BlckNoYW5uZWxzV3JpdHRlbiA9IHNwZWV4TW9kdWxlLmdldFZhbHVlKHRoaXMuX291dExlbmd0aFB0ciwgJ2kzMicpO1xuXG4gICAgLy8gd2UgYXJlIGNvcHlpbmcgdGhlIGluZm8gaW4gYSBuZXcgYnVmZmVyIGhlcmUsIHdlIGNvdWxkIGp1c3QgcGFzcyBhIGJ1ZmZlciBwb2ludGluZyB0byB0aGUgc2FtZSBtZW1vcnkgc3BhY2UgaWYgbmVlZGVkXG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKFxuICAgICAgc3BlZXhNb2R1bGUuSEVBUFU4LnNsaWNlKFxuICAgICAgICB0aGlzLl9vdXRCdWZmZXJQdHIsXG4gICAgICAgIHRoaXMuX291dEJ1ZmZlclB0ciArIG91dFNhbXBsZXNQZXJDaGFubmVsc1dyaXR0ZW4gKiB0aGlzLmNoYW5uZWxzICogVWludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlRcbiAgICAgICkuYnVmZmVyKTtcbiAgfVxufVxuXG5jb25zdCBFTVBUWV9CVUZGRVIgPSBCdWZmZXIuYWxsb2MoMCk7XG5cbmV4cG9ydCBjbGFzcyBTcGVleFJlc2FtcGxlclRyYW5zZm9ybSBleHRlbmRzIFRyYW5zZm9ybSB7XG4gIHJlc2FtcGxlcjogU3BlZXhSZXNhbXBsZXI7XG4gIF9hbGlnbmVtZW50QnVmZmVyOiBCdWZmZXI7XG5cbiAgLyoqXG4gICAgKiBDcmVhdGUgYW4gU3BlZXhSZXNhbXBsZXIgaW5zdGFuY2UuXG4gICAgKiBAcGFyYW0gY2hhbm5lbHMgTnVtYmVyIG9mIGNoYW5uZWxzLCBtaW5pbXVtIGlzIDEsIG5vIG1heGltdW1cbiAgICAqIEBwYXJhbSBpblJhdGUgZnJlcXVlbmN5IGluIEh6IGZvciB0aGUgaW5wdXQgY2h1bmtcbiAgICAqIEBwYXJhbSBvdXRSYXRlIGZyZXF1ZW5jeSBpbiBIeiBmb3IgdGhlIHRhcmdldCBjaHVua1xuICAgICogQHBhcmFtIHF1YWxpdHkgbnVtYmVyIGZyb20gMSB0byAxMCwgZGVmYXVsdCB0byA3LCAxIGlzIGZhc3QgYnV0IG9mIGJhZCBxdWFsaXR5LCAxMCBpcyBzbG93IGJ1dCBiZXN0IHF1YWxpdHlcbiAgICAqL1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgY2hhbm5lbHMsIHB1YmxpYyBpblJhdGUsIHB1YmxpYyBvdXRSYXRlLCBwdWJsaWMgcXVhbGl0eSA9IDcpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMucmVzYW1wbGVyID0gbmV3IFNwZWV4UmVzYW1wbGVyKGNoYW5uZWxzLCBpblJhdGUsIG91dFJhdGUsIHF1YWxpdHkpO1xuICAgIHRoaXMuY2hhbm5lbHMgPSBjaGFubmVscztcbiAgICB0aGlzLl9hbGlnbmVtZW50QnVmZmVyID0gRU1QVFlfQlVGRkVSO1xuICB9XG5cbiAgX3RyYW5zZm9ybShjaHVuaywgZW5jb2RpbmcsIGNhbGxiYWNrKSB7XG4gICAgbGV0IGNodW5rVG9Qcm9jZXNzOiBCdWZmZXIgPSBjaHVuaztcbiAgICBpZiAodGhpcy5fYWxpZ25lbWVudEJ1ZmZlci5sZW5ndGggPiAwKSB7XG4gICAgICBjaHVua1RvUHJvY2VzcyA9IEJ1ZmZlci5jb25jYXQoW1xuICAgICAgICB0aGlzLl9hbGlnbmVtZW50QnVmZmVyLFxuICAgICAgICBjaHVuayxcbiAgICAgIF0pO1xuICAgICAgdGhpcy5fYWxpZ25lbWVudEJ1ZmZlciA9IEVNUFRZX0JVRkZFUjtcbiAgICB9XG4gICAgLy8gU3BlZXggbmVlZHMgYSBidWZmZXIgYWxpZ25lZCB0byAxNmJpdHMgdGltZXMgdGhlIG51bWJlciBvZiBjaGFubmVsc1xuICAgIC8vIHNvIHdlIGtlZXAgdGhlIGV4dHJhbmVvdXMgYnl0ZXMgaW4gYSBidWZmZXIgZm9yIG5leHQgY2h1bmtcbiAgICBjb25zdCBleHRyYW5lb3VzQnl0ZXNDb3VudCA9IGNodW5rVG9Qcm9jZXNzLmxlbmd0aCAlICh0aGlzLmNoYW5uZWxzICogVWludDE2QXJyYXkuQllURVNfUEVSX0VMRU1FTlQpO1xuICAgIGlmIChleHRyYW5lb3VzQnl0ZXNDb3VudCAhPT0gMCkge1xuICAgICAgdGhpcy5fYWxpZ25lbWVudEJ1ZmZlciA9IEJ1ZmZlci5mcm9tKGNodW5rVG9Qcm9jZXNzLnNsaWNlKGNodW5rVG9Qcm9jZXNzLmxlbmd0aCAtIGV4dHJhbmVvdXNCeXRlc0NvdW50KSk7XG4gICAgICBjaHVua1RvUHJvY2VzcyA9IGNodW5rVG9Qcm9jZXNzLnNsaWNlKDAsIGNodW5rVG9Qcm9jZXNzLmxlbmd0aCAtIGV4dHJhbmVvdXNCeXRlc0NvdW50KTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcyA9IHRoaXMucmVzYW1wbGVyLnByb2Nlc3NDaHVuayhjaHVua1RvUHJvY2Vzcyk7XG4gICAgICBjYWxsYmFjayhudWxsLCByZXMpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNhbGxiYWNrKGUpO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBTcGVleFJlc2FtcGxlcjtcbiJdfQ== -------------------------------------------------------------------------------- /src/speex_wasm.js: -------------------------------------------------------------------------------- 1 | 2 | var Speex = (function() { 3 | var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; 4 | if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; 5 | return ( 6 | function(Speex) { 7 | Speex = Speex || {}; 8 | 9 | var Module=typeof Speex!=="undefined"?Speex:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){var ret=tryParseAsDataURI(filename);if(ret){return binary?ret:ret.toString()}if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for getValue: "+type)}return null}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":6,"maximum":6+0,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function AsciiToString(ptr){var str="";while(1){var ch=HEAPU8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5249296,DYNAMICTOP_PTR=6256;var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||20971520;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":2147483648/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var wasmBinaryFile="data:application/octet-stream;base64,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";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(wasmBinaryFile);if(binary){return binary}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_size(){return HEAPU8.length}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){return false}var minHeapSize=16777216;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),PAGE_MULTIPLE));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ASSERTIONS=false;function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); 10 | 11 | 12 | return Speex.ready 13 | } 14 | ); 15 | })(); 16 | export default Speex; -------------------------------------------------------------------------------- /deps/speex/resample.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin 2 | Copyright (C) 2008 Thorvald Natvig 3 | 4 | File: resample.c 5 | Arbitrary resampling code 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | 3. The name of the author may not be used to endorse or promote products 19 | derived from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | /* 35 | The design goals of this code are: 36 | - Very fast algorithm 37 | - SIMD-friendly algorithm 38 | - Low memory requirement 39 | - Good *perceptual* quality (and not best SNR) 40 | 41 | Warning: This resampler is relatively new. Although I think I got rid of 42 | all the major bugs and I don't expect the API to change anymore, there 43 | may be something I've missed. So use with caution. 44 | 45 | This algorithm is based on this original resampling algorithm: 46 | Smith, Julius O. Digital Audio Resampling Home Page 47 | Center for Computer Research in Music and Acoustics (CCRMA), 48 | Stanford University, 2007. 49 | Web published at https://ccrma.stanford.edu/~jos/resample/. 50 | 51 | There is one main difference, though. This resampler uses cubic 52 | interpolation instead of linear interpolation in the above paper. This 53 | makes the table much smaller and makes it possible to compute that table 54 | on a per-stream basis. In turn, being able to tweak the table for each 55 | stream makes it possible to both reduce complexity on simple ratios 56 | (e.g. 2/3), and get rid of the rounding operations in the inner loop. 57 | The latter both reduces CPU time and makes the algorithm more SIMD-friendly. 58 | */ 59 | 60 | #ifdef HAVE_CONFIG_H 61 | #include "config.h" 62 | #endif 63 | 64 | #ifdef OUTSIDE_SPEEX 65 | #include 66 | static void *speex_alloc(int size) {return calloc(size,1);} 67 | static void *speex_realloc(void *ptr, int size) {return realloc(ptr, size);} 68 | static void speex_free(void *ptr) {free(ptr);} 69 | #ifndef EXPORT 70 | #define EXPORT 71 | #endif 72 | #include "speex_resampler.h" 73 | #include "arch.h" 74 | #else /* OUTSIDE_SPEEX */ 75 | 76 | #include "speex/speex_resampler.h" 77 | #include "arch.h" 78 | #include "os_support.h" 79 | #endif /* OUTSIDE_SPEEX */ 80 | 81 | #include 82 | #include 83 | 84 | #ifndef M_PI 85 | #define M_PI 3.14159265358979323846 86 | #endif 87 | 88 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) 89 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) 90 | 91 | #ifndef NULL 92 | #define NULL 0 93 | #endif 94 | 95 | #ifndef UINT32_MAX 96 | #define UINT32_MAX 4294967295U 97 | #endif 98 | 99 | #ifdef USE_SSE 100 | #include "resample_sse.h" 101 | #endif 102 | 103 | #ifdef USE_NEON 104 | #include "resample_neon.h" 105 | #endif 106 | 107 | /* Numer of elements to allocate on the stack */ 108 | #ifdef VAR_ARRAYS 109 | #define FIXED_STACK_ALLOC 8192 110 | #else 111 | #define FIXED_STACK_ALLOC 1024 112 | #endif 113 | 114 | typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); 115 | 116 | struct SpeexResamplerState_ { 117 | spx_uint32_t in_rate; 118 | spx_uint32_t out_rate; 119 | spx_uint32_t num_rate; 120 | spx_uint32_t den_rate; 121 | 122 | int quality; 123 | spx_uint32_t nb_channels; 124 | spx_uint32_t filt_len; 125 | spx_uint32_t mem_alloc_size; 126 | spx_uint32_t buffer_size; 127 | int int_advance; 128 | int frac_advance; 129 | float cutoff; 130 | spx_uint32_t oversample; 131 | int initialised; 132 | int started; 133 | 134 | /* These are per-channel */ 135 | spx_int32_t *last_sample; 136 | spx_uint32_t *samp_frac_num; 137 | spx_uint32_t *magic_samples; 138 | 139 | spx_word16_t *mem; 140 | spx_word16_t *sinc_table; 141 | spx_uint32_t sinc_table_length; 142 | resampler_basic_func resampler_ptr; 143 | 144 | int in_stride; 145 | int out_stride; 146 | } ; 147 | 148 | static const double kaiser12_table[68] = { 149 | 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, 150 | 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, 151 | 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, 152 | 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, 153 | 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, 154 | 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, 155 | 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, 156 | 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, 157 | 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, 158 | 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, 159 | 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, 160 | 0.00001000, 0.00000000}; 161 | /* 162 | static const double kaiser12_table[36] = { 163 | 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, 164 | 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, 165 | 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, 166 | 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, 167 | 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, 168 | 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; 169 | */ 170 | static const double kaiser10_table[36] = { 171 | 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, 172 | 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, 173 | 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, 174 | 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, 175 | 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, 176 | 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; 177 | 178 | static const double kaiser8_table[36] = { 179 | 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, 180 | 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, 181 | 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, 182 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, 183 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, 184 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; 185 | 186 | static const double kaiser6_table[36] = { 187 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, 188 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, 189 | 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, 190 | 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, 191 | 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, 192 | 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; 193 | 194 | struct FuncDef { 195 | const double *table; 196 | int oversample; 197 | }; 198 | 199 | static const struct FuncDef kaiser12_funcdef = {kaiser12_table, 64}; 200 | #define KAISER12 (&kaiser12_funcdef) 201 | static const struct FuncDef kaiser10_funcdef = {kaiser10_table, 32}; 202 | #define KAISER10 (&kaiser10_funcdef) 203 | static const struct FuncDef kaiser8_funcdef = {kaiser8_table, 32}; 204 | #define KAISER8 (&kaiser8_funcdef) 205 | static const struct FuncDef kaiser6_funcdef = {kaiser6_table, 32}; 206 | #define KAISER6 (&kaiser6_funcdef) 207 | 208 | struct QualityMapping { 209 | int base_length; 210 | int oversample; 211 | float downsample_bandwidth; 212 | float upsample_bandwidth; 213 | const struct FuncDef *window_func; 214 | }; 215 | 216 | 217 | /* This table maps conversion quality to internal parameters. There are two 218 | reasons that explain why the up-sampling bandwidth is larger than the 219 | down-sampling bandwidth: 220 | 1) When up-sampling, we can assume that the spectrum is already attenuated 221 | close to the Nyquist rate (from an A/D or a previous resampling filter) 222 | 2) Any aliasing that occurs very close to the Nyquist rate will be masked 223 | by the sinusoids/noise just below the Nyquist rate (guaranteed only for 224 | up-sampling). 225 | */ 226 | static const struct QualityMapping quality_map[11] = { 227 | { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ 228 | { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ 229 | { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ 230 | { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ 231 | { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ 232 | { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ 233 | { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ 234 | {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ 235 | {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ 236 | {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ 237 | {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ 238 | }; 239 | /*8,24,40,56,80,104,128,160,200,256,320*/ 240 | static double compute_func(float x, const struct FuncDef *func) 241 | { 242 | float y, frac; 243 | double interp[4]; 244 | int ind; 245 | y = x*func->oversample; 246 | ind = (int)floor(y); 247 | frac = (y-ind); 248 | /* CSE with handle the repeated powers */ 249 | interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); 250 | interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); 251 | /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ 252 | interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); 253 | /* Just to make sure we don't have rounding problems */ 254 | interp[1] = 1.f-interp[3]-interp[2]-interp[0]; 255 | 256 | /*sum = frac*accum[1] + (1-frac)*accum[2];*/ 257 | return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; 258 | } 259 | 260 | #if 0 261 | #include 262 | int main(int argc, char **argv) 263 | { 264 | int i; 265 | for (i=0;i<256;i++) 266 | { 267 | printf ("%f\n", compute_func(i/256., KAISER12)); 268 | } 269 | return 0; 270 | } 271 | #endif 272 | 273 | #ifdef FIXED_POINT 274 | /* The slow way of computing a sinc for the table. Should improve that some day */ 275 | static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func) 276 | { 277 | /*fprintf (stderr, "%f ", x);*/ 278 | float xx = x * cutoff; 279 | if (fabs(x)<1e-6f) 280 | return WORD2INT(32768.*cutoff); 281 | else if (fabs(x) > .5f*N) 282 | return 0; 283 | /*FIXME: Can it really be any slower than this? */ 284 | return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); 285 | } 286 | #else 287 | /* The slow way of computing a sinc for the table. Should improve that some day */ 288 | static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func) 289 | { 290 | /*fprintf (stderr, "%f ", x);*/ 291 | float xx = x * cutoff; 292 | if (fabs(x)<1e-6) 293 | return cutoff; 294 | else if (fabs(x) > .5*N) 295 | return 0; 296 | /*FIXME: Can it really be any slower than this? */ 297 | return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); 298 | } 299 | #endif 300 | 301 | #ifdef FIXED_POINT 302 | static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) 303 | { 304 | /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation 305 | but I know it's MMSE-optimal on a sinc */ 306 | spx_word16_t x2, x3; 307 | x2 = MULT16_16_P15(x, x); 308 | x3 = MULT16_16_P15(x, x2); 309 | interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); 310 | interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); 311 | interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); 312 | /* Just to make sure we don't have rounding problems */ 313 | interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; 314 | if (interp[2]<32767) 315 | interp[2]+=1; 316 | } 317 | #else 318 | static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) 319 | { 320 | /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation 321 | but I know it's MMSE-optimal on a sinc */ 322 | interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; 323 | interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; 324 | /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ 325 | interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; 326 | /* Just to make sure we don't have rounding problems */ 327 | interp[2] = 1.-interp[0]-interp[1]-interp[3]; 328 | } 329 | #endif 330 | 331 | static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 332 | { 333 | const int N = st->filt_len; 334 | int out_sample = 0; 335 | int last_sample = st->last_sample[channel_index]; 336 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 337 | const spx_word16_t *sinc_table = st->sinc_table; 338 | const int out_stride = st->out_stride; 339 | const int int_advance = st->int_advance; 340 | const int frac_advance = st->frac_advance; 341 | const spx_uint32_t den_rate = st->den_rate; 342 | spx_word32_t sum; 343 | 344 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 345 | { 346 | const spx_word16_t *sinct = & sinc_table[samp_frac_num*N]; 347 | const spx_word16_t *iptr = & in[last_sample]; 348 | 349 | #ifndef OVERRIDE_INNER_PRODUCT_SINGLE 350 | int j; 351 | sum = 0; 352 | for(j=0;j= den_rate) 375 | { 376 | samp_frac_num -= den_rate; 377 | last_sample++; 378 | } 379 | } 380 | 381 | st->last_sample[channel_index] = last_sample; 382 | st->samp_frac_num[channel_index] = samp_frac_num; 383 | return out_sample; 384 | } 385 | 386 | #ifdef FIXED_POINT 387 | #else 388 | /* This is the same as the previous function, except with a double-precision accumulator */ 389 | static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 390 | { 391 | const int N = st->filt_len; 392 | int out_sample = 0; 393 | int last_sample = st->last_sample[channel_index]; 394 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 395 | const spx_word16_t *sinc_table = st->sinc_table; 396 | const int out_stride = st->out_stride; 397 | const int int_advance = st->int_advance; 398 | const int frac_advance = st->frac_advance; 399 | const spx_uint32_t den_rate = st->den_rate; 400 | double sum; 401 | 402 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 403 | { 404 | const spx_word16_t *sinct = & sinc_table[samp_frac_num*N]; 405 | const spx_word16_t *iptr = & in[last_sample]; 406 | 407 | #ifndef OVERRIDE_INNER_PRODUCT_DOUBLE 408 | int j; 409 | double accum[4] = {0,0,0,0}; 410 | 411 | for(j=0;j= den_rate) 426 | { 427 | samp_frac_num -= den_rate; 428 | last_sample++; 429 | } 430 | } 431 | 432 | st->last_sample[channel_index] = last_sample; 433 | st->samp_frac_num[channel_index] = samp_frac_num; 434 | return out_sample; 435 | } 436 | #endif 437 | 438 | static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 439 | { 440 | const int N = st->filt_len; 441 | int out_sample = 0; 442 | int last_sample = st->last_sample[channel_index]; 443 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 444 | const int out_stride = st->out_stride; 445 | const int int_advance = st->int_advance; 446 | const int frac_advance = st->frac_advance; 447 | const spx_uint32_t den_rate = st->den_rate; 448 | spx_word32_t sum; 449 | 450 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 451 | { 452 | const spx_word16_t *iptr = & in[last_sample]; 453 | 454 | const int offset = samp_frac_num*st->oversample/st->den_rate; 455 | #ifdef FIXED_POINT 456 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); 457 | #else 458 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; 459 | #endif 460 | spx_word16_t interp[4]; 461 | 462 | 463 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE 464 | int j; 465 | spx_word32_t accum[4] = {0,0,0,0}; 466 | 467 | for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); 470 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); 471 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); 472 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); 473 | } 474 | 475 | cubic_coef(frac, interp); 476 | sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1)); 477 | sum = SATURATE32PSHR(sum, 15, 32767); 478 | #else 479 | cubic_coef(frac, interp); 480 | sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); 481 | #endif 482 | 483 | out[out_stride * out_sample++] = sum; 484 | last_sample += int_advance; 485 | samp_frac_num += frac_advance; 486 | if (samp_frac_num >= den_rate) 487 | { 488 | samp_frac_num -= den_rate; 489 | last_sample++; 490 | } 491 | } 492 | 493 | st->last_sample[channel_index] = last_sample; 494 | st->samp_frac_num[channel_index] = samp_frac_num; 495 | return out_sample; 496 | } 497 | 498 | #ifdef FIXED_POINT 499 | #else 500 | /* This is the same as the previous function, except with a double-precision accumulator */ 501 | static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 502 | { 503 | const int N = st->filt_len; 504 | int out_sample = 0; 505 | int last_sample = st->last_sample[channel_index]; 506 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 507 | const int out_stride = st->out_stride; 508 | const int int_advance = st->int_advance; 509 | const int frac_advance = st->frac_advance; 510 | const spx_uint32_t den_rate = st->den_rate; 511 | spx_word32_t sum; 512 | 513 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 514 | { 515 | const spx_word16_t *iptr = & in[last_sample]; 516 | 517 | const int offset = samp_frac_num*st->oversample/st->den_rate; 518 | #ifdef FIXED_POINT 519 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); 520 | #else 521 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; 522 | #endif 523 | spx_word16_t interp[4]; 524 | 525 | 526 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE 527 | int j; 528 | double accum[4] = {0,0,0,0}; 529 | 530 | for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); 533 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); 534 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); 535 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); 536 | } 537 | 538 | cubic_coef(frac, interp); 539 | sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); 540 | #else 541 | cubic_coef(frac, interp); 542 | sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); 543 | #endif 544 | 545 | out[out_stride * out_sample++] = PSHR32(sum,15); 546 | last_sample += int_advance; 547 | samp_frac_num += frac_advance; 548 | if (samp_frac_num >= den_rate) 549 | { 550 | samp_frac_num -= den_rate; 551 | last_sample++; 552 | } 553 | } 554 | 555 | st->last_sample[channel_index] = last_sample; 556 | st->samp_frac_num[channel_index] = samp_frac_num; 557 | return out_sample; 558 | } 559 | #endif 560 | 561 | /* This resampler is used to produce zero output in situations where memory 562 | for the filter could not be allocated. The expected numbers of input and 563 | output samples are still processed so that callers failing to check error 564 | codes are not surprised, possibly getting into infinite loops. */ 565 | static int resampler_basic_zero(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 566 | { 567 | int out_sample = 0; 568 | int last_sample = st->last_sample[channel_index]; 569 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 570 | const int out_stride = st->out_stride; 571 | const int int_advance = st->int_advance; 572 | const int frac_advance = st->frac_advance; 573 | const spx_uint32_t den_rate = st->den_rate; 574 | 575 | (void)in; 576 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 577 | { 578 | out[out_stride * out_sample++] = 0; 579 | last_sample += int_advance; 580 | samp_frac_num += frac_advance; 581 | if (samp_frac_num >= den_rate) 582 | { 583 | samp_frac_num -= den_rate; 584 | last_sample++; 585 | } 586 | } 587 | 588 | st->last_sample[channel_index] = last_sample; 589 | st->samp_frac_num[channel_index] = samp_frac_num; 590 | return out_sample; 591 | } 592 | 593 | static int multiply_frac(spx_uint32_t *result, spx_uint32_t value, spx_uint32_t num, spx_uint32_t den) 594 | { 595 | spx_uint32_t major = value / den; 596 | spx_uint32_t remain = value % den; 597 | /* TODO: Could use 64 bits operation to check for overflow. But only guaranteed in C99+ */ 598 | if (remain > UINT32_MAX / num || major > UINT32_MAX / num 599 | || major * num > UINT32_MAX - remain * num / den) 600 | return RESAMPLER_ERR_OVERFLOW; 601 | *result = remain * num / den + major * num; 602 | return RESAMPLER_ERR_SUCCESS; 603 | } 604 | 605 | static int update_filter(SpeexResamplerState *st) 606 | { 607 | spx_uint32_t old_length = st->filt_len; 608 | spx_uint32_t old_alloc_size = st->mem_alloc_size; 609 | int use_direct; 610 | spx_uint32_t min_sinc_table_length; 611 | spx_uint32_t min_alloc_size; 612 | 613 | st->int_advance = st->num_rate/st->den_rate; 614 | st->frac_advance = st->num_rate%st->den_rate; 615 | st->oversample = quality_map[st->quality].oversample; 616 | st->filt_len = quality_map[st->quality].base_length; 617 | 618 | if (st->num_rate > st->den_rate) 619 | { 620 | /* down-sampling */ 621 | st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; 622 | if (multiply_frac(&st->filt_len,st->filt_len,st->num_rate,st->den_rate) != RESAMPLER_ERR_SUCCESS) 623 | goto fail; 624 | /* Round up to make sure we have a multiple of 8 for SSE */ 625 | st->filt_len = ((st->filt_len-1)&(~0x7))+8; 626 | if (2*st->den_rate < st->num_rate) 627 | st->oversample >>= 1; 628 | if (4*st->den_rate < st->num_rate) 629 | st->oversample >>= 1; 630 | if (8*st->den_rate < st->num_rate) 631 | st->oversample >>= 1; 632 | if (16*st->den_rate < st->num_rate) 633 | st->oversample >>= 1; 634 | if (st->oversample < 1) 635 | st->oversample = 1; 636 | } else { 637 | /* up-sampling */ 638 | st->cutoff = quality_map[st->quality].upsample_bandwidth; 639 | } 640 | 641 | #ifdef RESAMPLE_FULL_SINC_TABLE 642 | use_direct = 1; 643 | if (INT_MAX/sizeof(spx_word16_t)/st->den_rate < st->filt_len) 644 | goto fail; 645 | #else 646 | /* Choose the resampling type that requires the least amount of memory */ 647 | use_direct = st->filt_len*st->den_rate <= st->filt_len*st->oversample+8 648 | && INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len; 649 | #endif 650 | if (use_direct) 651 | { 652 | min_sinc_table_length = st->filt_len*st->den_rate; 653 | } else { 654 | if ((INT_MAX/sizeof(spx_word16_t)-8)/st->oversample < st->filt_len) 655 | goto fail; 656 | 657 | min_sinc_table_length = st->filt_len*st->oversample+8; 658 | } 659 | if (st->sinc_table_length < min_sinc_table_length) 660 | { 661 | spx_word16_t *sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,min_sinc_table_length*sizeof(spx_word16_t)); 662 | if (!sinc_table) 663 | goto fail; 664 | 665 | st->sinc_table = sinc_table; 666 | st->sinc_table_length = min_sinc_table_length; 667 | } 668 | if (use_direct) 669 | { 670 | spx_uint32_t i; 671 | for (i=0;iden_rate;i++) 672 | { 673 | spx_int32_t j; 674 | for (j=0;jfilt_len;j++) 675 | { 676 | st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); 677 | } 678 | } 679 | #ifdef FIXED_POINT 680 | st->resampler_ptr = resampler_basic_direct_single; 681 | #else 682 | if (st->quality>8) 683 | st->resampler_ptr = resampler_basic_direct_double; 684 | else 685 | st->resampler_ptr = resampler_basic_direct_single; 686 | #endif 687 | /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ 688 | } else { 689 | spx_int32_t i; 690 | for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) 691 | st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); 692 | #ifdef FIXED_POINT 693 | st->resampler_ptr = resampler_basic_interpolate_single; 694 | #else 695 | if (st->quality>8) 696 | st->resampler_ptr = resampler_basic_interpolate_double; 697 | else 698 | st->resampler_ptr = resampler_basic_interpolate_single; 699 | #endif 700 | /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ 701 | } 702 | 703 | /* Here's the place where we update the filter memory to take into account 704 | the change in filter length. It's probably the messiest part of the code 705 | due to handling of lots of corner cases. */ 706 | 707 | /* Adding buffer_size to filt_len won't overflow here because filt_len 708 | could be multiplied by sizeof(spx_word16_t) above. */ 709 | min_alloc_size = st->filt_len-1 + st->buffer_size; 710 | if (min_alloc_size > st->mem_alloc_size) 711 | { 712 | spx_word16_t *mem; 713 | if (INT_MAX/sizeof(spx_word16_t)/st->nb_channels < min_alloc_size) 714 | goto fail; 715 | else if (!(mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*min_alloc_size * sizeof(*mem)))) 716 | goto fail; 717 | 718 | st->mem = mem; 719 | st->mem_alloc_size = min_alloc_size; 720 | } 721 | if (!st->started) 722 | { 723 | spx_uint32_t i; 724 | for (i=0;inb_channels*st->mem_alloc_size;i++) 725 | st->mem[i] = 0; 726 | /*speex_warning("reinit filter");*/ 727 | } else if (st->filt_len > old_length) 728 | { 729 | spx_uint32_t i; 730 | /* Increase the filter length */ 731 | /*speex_warning("increase filter size");*/ 732 | for (i=st->nb_channels;i--;) 733 | { 734 | spx_uint32_t j; 735 | spx_uint32_t olen = old_length; 736 | /*if (st->magic_samples[i])*/ 737 | { 738 | /* Try and remove the magic samples as if nothing had happened */ 739 | 740 | /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ 741 | olen = old_length + 2*st->magic_samples[i]; 742 | for (j=old_length-1+st->magic_samples[i];j--;) 743 | st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; 744 | for (j=0;jmagic_samples[i];j++) 745 | st->mem[i*st->mem_alloc_size+j] = 0; 746 | st->magic_samples[i] = 0; 747 | } 748 | if (st->filt_len > olen) 749 | { 750 | /* If the new filter length is still bigger than the "augmented" length */ 751 | /* Copy data going backward */ 752 | for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; 754 | /* Then put zeros for lack of anything better */ 755 | for (;jfilt_len-1;j++) 756 | st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; 757 | /* Adjust last_sample */ 758 | st->last_sample[i] += (st->filt_len - olen)/2; 759 | } else { 760 | /* Put back some of the magic! */ 761 | st->magic_samples[i] = (olen - st->filt_len)/2; 762 | for (j=0;jfilt_len-1+st->magic_samples[i];j++) 763 | st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; 764 | } 765 | } 766 | } else if (st->filt_len < old_length) 767 | { 768 | spx_uint32_t i; 769 | /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" 770 | samples so they can be used directly as input the next time(s) */ 771 | for (i=0;inb_channels;i++) 772 | { 773 | spx_uint32_t j; 774 | spx_uint32_t old_magic = st->magic_samples[i]; 775 | st->magic_samples[i] = (old_length - st->filt_len)/2; 776 | /* We must copy some of the memory that's no longer used */ 777 | /* Copy data going backward */ 778 | for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) 779 | st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; 780 | st->magic_samples[i] += old_magic; 781 | } 782 | } 783 | return RESAMPLER_ERR_SUCCESS; 784 | 785 | fail: 786 | st->resampler_ptr = resampler_basic_zero; 787 | /* st->mem may still contain consumed input samples for the filter. 788 | Restore filt_len so that filt_len - 1 still points to the position after 789 | the last of these samples. */ 790 | st->filt_len = old_length; 791 | return RESAMPLER_ERR_ALLOC_FAILED; 792 | } 793 | 794 | EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) 795 | { 796 | return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); 797 | } 798 | 799 | EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) 800 | { 801 | SpeexResamplerState *st; 802 | int filter_err; 803 | 804 | if (nb_channels == 0 || ratio_num == 0 || ratio_den == 0 || quality > 10 || quality < 0) 805 | { 806 | if (err) 807 | *err = RESAMPLER_ERR_INVALID_ARG; 808 | return NULL; 809 | } 810 | st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); 811 | if (!st) 812 | { 813 | if (err) 814 | *err = RESAMPLER_ERR_ALLOC_FAILED; 815 | return NULL; 816 | } 817 | st->initialised = 0; 818 | st->started = 0; 819 | st->in_rate = 0; 820 | st->out_rate = 0; 821 | st->num_rate = 0; 822 | st->den_rate = 0; 823 | st->quality = -1; 824 | st->sinc_table_length = 0; 825 | st->mem_alloc_size = 0; 826 | st->filt_len = 0; 827 | st->mem = 0; 828 | st->resampler_ptr = 0; 829 | 830 | st->cutoff = 1.f; 831 | st->nb_channels = nb_channels; 832 | st->in_stride = 1; 833 | st->out_stride = 1; 834 | 835 | st->buffer_size = 160; 836 | 837 | /* Per channel data */ 838 | if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t)))) 839 | goto fail; 840 | if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) 841 | goto fail; 842 | if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) 843 | goto fail; 844 | 845 | speex_resampler_set_quality(st, quality); 846 | speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); 847 | 848 | filter_err = update_filter(st); 849 | if (filter_err == RESAMPLER_ERR_SUCCESS) 850 | { 851 | st->initialised = 1; 852 | } else { 853 | speex_resampler_destroy(st); 854 | st = NULL; 855 | } 856 | if (err) 857 | *err = filter_err; 858 | 859 | return st; 860 | 861 | fail: 862 | if (err) 863 | *err = RESAMPLER_ERR_ALLOC_FAILED; 864 | speex_resampler_destroy(st); 865 | return NULL; 866 | } 867 | 868 | EXPORT void speex_resampler_destroy(SpeexResamplerState *st) 869 | { 870 | speex_free(st->mem); 871 | speex_free(st->sinc_table); 872 | speex_free(st->last_sample); 873 | speex_free(st->magic_samples); 874 | speex_free(st->samp_frac_num); 875 | speex_free(st); 876 | } 877 | 878 | static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 879 | { 880 | int j=0; 881 | const int N = st->filt_len; 882 | int out_sample = 0; 883 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; 884 | spx_uint32_t ilen; 885 | 886 | st->started = 1; 887 | 888 | /* Call the right resampler through the function ptr */ 889 | out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); 890 | 891 | if (st->last_sample[channel_index] < (spx_int32_t)*in_len) 892 | *in_len = st->last_sample[channel_index]; 893 | *out_len = out_sample; 894 | st->last_sample[channel_index] -= *in_len; 895 | 896 | ilen = *in_len; 897 | 898 | for(j=0;jmagic_samples[channel_index]; 906 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; 907 | const int N = st->filt_len; 908 | 909 | speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); 910 | 911 | st->magic_samples[channel_index] -= tmp_in_len; 912 | 913 | /* If we couldn't process all "magic" input samples, save the rest for next time */ 914 | if (st->magic_samples[channel_index]) 915 | { 916 | spx_uint32_t i; 917 | for (i=0;imagic_samples[channel_index];i++) 918 | mem[N-1+i]=mem[N-1+i+tmp_in_len]; 919 | } 920 | *out += out_len*st->out_stride; 921 | return out_len; 922 | } 923 | 924 | #ifdef FIXED_POINT 925 | EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) 926 | #else 927 | EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) 928 | #endif 929 | { 930 | int j; 931 | spx_uint32_t ilen = *in_len; 932 | spx_uint32_t olen = *out_len; 933 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; 934 | const int filt_offs = st->filt_len - 1; 935 | const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; 936 | const int istride = st->in_stride; 937 | 938 | if (st->magic_samples[channel_index]) 939 | olen -= speex_resampler_magic(st, channel_index, &out, olen); 940 | if (! st->magic_samples[channel_index]) { 941 | while (ilen && olen) { 942 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; 943 | spx_uint32_t ochunk = olen; 944 | 945 | if (in) { 946 | for(j=0;jout_stride; 956 | if (in) 957 | in += ichunk * istride; 958 | } 959 | } 960 | *in_len -= ilen; 961 | *out_len -= olen; 962 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 963 | } 964 | 965 | #ifdef FIXED_POINT 966 | EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) 967 | #else 968 | EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) 969 | #endif 970 | { 971 | int j; 972 | const int istride_save = st->in_stride; 973 | const int ostride_save = st->out_stride; 974 | spx_uint32_t ilen = *in_len; 975 | spx_uint32_t olen = *out_len; 976 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; 977 | const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); 978 | #ifdef VAR_ARRAYS 979 | const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; 980 | spx_word16_t ystack[ylen]; 981 | #else 982 | const unsigned int ylen = FIXED_STACK_ALLOC; 983 | spx_word16_t ystack[FIXED_STACK_ALLOC]; 984 | #endif 985 | 986 | st->out_stride = 1; 987 | 988 | while (ilen && olen) { 989 | spx_word16_t *y = ystack; 990 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; 991 | spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; 992 | spx_uint32_t omagic = 0; 993 | 994 | if (st->magic_samples[channel_index]) { 995 | omagic = speex_resampler_magic(st, channel_index, &y, ochunk); 996 | ochunk -= omagic; 997 | olen -= omagic; 998 | } 999 | if (! st->magic_samples[channel_index]) { 1000 | if (in) { 1001 | for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); 1004 | #else 1005 | x[j+st->filt_len-1]=in[j*istride_save]; 1006 | #endif 1007 | } else { 1008 | for(j=0;jfilt_len-1]=0; 1010 | } 1011 | 1012 | speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); 1013 | } else { 1014 | ichunk = 0; 1015 | ochunk = 0; 1016 | } 1017 | 1018 | for (j=0;jout_stride = ostride_save; 1032 | *in_len -= ilen; 1033 | *out_len -= olen; 1034 | 1035 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 1036 | } 1037 | 1038 | EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) 1039 | { 1040 | spx_uint32_t i; 1041 | int istride_save, ostride_save; 1042 | spx_uint32_t bak_out_len = *out_len; 1043 | spx_uint32_t bak_in_len = *in_len; 1044 | istride_save = st->in_stride; 1045 | ostride_save = st->out_stride; 1046 | st->in_stride = st->out_stride = st->nb_channels; 1047 | for (i=0;inb_channels;i++) 1048 | { 1049 | *out_len = bak_out_len; 1050 | *in_len = bak_in_len; 1051 | if (in != NULL) 1052 | speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); 1053 | else 1054 | speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len); 1055 | } 1056 | st->in_stride = istride_save; 1057 | st->out_stride = ostride_save; 1058 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 1059 | } 1060 | 1061 | EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) 1062 | { 1063 | spx_uint32_t i; 1064 | int istride_save, ostride_save; 1065 | spx_uint32_t bak_out_len = *out_len; 1066 | spx_uint32_t bak_in_len = *in_len; 1067 | istride_save = st->in_stride; 1068 | ostride_save = st->out_stride; 1069 | st->in_stride = st->out_stride = st->nb_channels; 1070 | for (i=0;inb_channels;i++) 1071 | { 1072 | *out_len = bak_out_len; 1073 | *in_len = bak_in_len; 1074 | if (in != NULL) 1075 | speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); 1076 | else 1077 | speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len); 1078 | } 1079 | st->in_stride = istride_save; 1080 | st->out_stride = ostride_save; 1081 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 1082 | } 1083 | 1084 | EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) 1085 | { 1086 | return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); 1087 | } 1088 | 1089 | EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) 1090 | { 1091 | *in_rate = st->in_rate; 1092 | *out_rate = st->out_rate; 1093 | } 1094 | 1095 | static inline spx_uint32_t compute_gcd(spx_uint32_t a, spx_uint32_t b) 1096 | { 1097 | while (b != 0) 1098 | { 1099 | spx_uint32_t temp = a; 1100 | 1101 | a = b; 1102 | b = temp % b; 1103 | } 1104 | return a; 1105 | } 1106 | 1107 | EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) 1108 | { 1109 | spx_uint32_t fact; 1110 | spx_uint32_t old_den; 1111 | spx_uint32_t i; 1112 | 1113 | if (ratio_num == 0 || ratio_den == 0) 1114 | return RESAMPLER_ERR_INVALID_ARG; 1115 | 1116 | if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) 1117 | return RESAMPLER_ERR_SUCCESS; 1118 | 1119 | old_den = st->den_rate; 1120 | st->in_rate = in_rate; 1121 | st->out_rate = out_rate; 1122 | st->num_rate = ratio_num; 1123 | st->den_rate = ratio_den; 1124 | 1125 | fact = compute_gcd(st->num_rate, st->den_rate); 1126 | 1127 | st->num_rate /= fact; 1128 | st->den_rate /= fact; 1129 | 1130 | if (old_den > 0) 1131 | { 1132 | for (i=0;inb_channels;i++) 1133 | { 1134 | if (multiply_frac(&st->samp_frac_num[i],st->samp_frac_num[i],st->den_rate,old_den) != RESAMPLER_ERR_SUCCESS) 1135 | return RESAMPLER_ERR_OVERFLOW; 1136 | /* Safety net */ 1137 | if (st->samp_frac_num[i] >= st->den_rate) 1138 | st->samp_frac_num[i] = st->den_rate-1; 1139 | } 1140 | } 1141 | 1142 | if (st->initialised) 1143 | return update_filter(st); 1144 | return RESAMPLER_ERR_SUCCESS; 1145 | } 1146 | 1147 | EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) 1148 | { 1149 | *ratio_num = st->num_rate; 1150 | *ratio_den = st->den_rate; 1151 | } 1152 | 1153 | EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) 1154 | { 1155 | if (quality > 10 || quality < 0) 1156 | return RESAMPLER_ERR_INVALID_ARG; 1157 | if (st->quality == quality) 1158 | return RESAMPLER_ERR_SUCCESS; 1159 | st->quality = quality; 1160 | if (st->initialised) 1161 | return update_filter(st); 1162 | return RESAMPLER_ERR_SUCCESS; 1163 | } 1164 | 1165 | EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) 1166 | { 1167 | *quality = st->quality; 1168 | } 1169 | 1170 | EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) 1171 | { 1172 | st->in_stride = stride; 1173 | } 1174 | 1175 | EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) 1176 | { 1177 | *stride = st->in_stride; 1178 | } 1179 | 1180 | EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) 1181 | { 1182 | st->out_stride = stride; 1183 | } 1184 | 1185 | EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) 1186 | { 1187 | *stride = st->out_stride; 1188 | } 1189 | 1190 | EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) 1191 | { 1192 | return st->filt_len / 2; 1193 | } 1194 | 1195 | EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) 1196 | { 1197 | return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; 1198 | } 1199 | 1200 | EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) 1201 | { 1202 | spx_uint32_t i; 1203 | for (i=0;inb_channels;i++) 1204 | st->last_sample[i] = st->filt_len/2; 1205 | return RESAMPLER_ERR_SUCCESS; 1206 | } 1207 | 1208 | EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) 1209 | { 1210 | spx_uint32_t i; 1211 | for (i=0;inb_channels;i++) 1212 | { 1213 | st->last_sample[i] = 0; 1214 | st->magic_samples[i] = 0; 1215 | st->samp_frac_num[i] = 0; 1216 | } 1217 | for (i=0;inb_channels*(st->filt_len-1);i++) 1218 | st->mem[i] = 0; 1219 | return RESAMPLER_ERR_SUCCESS; 1220 | } 1221 | 1222 | EXPORT const char *speex_resampler_strerror(int err) 1223 | { 1224 | switch (err) 1225 | { 1226 | case RESAMPLER_ERR_SUCCESS: 1227 | return "Success."; 1228 | case RESAMPLER_ERR_ALLOC_FAILED: 1229 | return "Memory allocation failed."; 1230 | case RESAMPLER_ERR_BAD_STATE: 1231 | return "Bad resampler state."; 1232 | case RESAMPLER_ERR_INVALID_ARG: 1233 | return "Invalid argument."; 1234 | case RESAMPLER_ERR_PTR_OVERLAP: 1235 | return "Input and output buffers overlap."; 1236 | default: 1237 | return "Unknown error. Bad error code or strange version mismatch."; 1238 | } 1239 | } 1240 | --------------------------------------------------------------------------------