├── README.md ├── SoundTouchDemo ├── .gitignore ├── app │ ├── .gitignore │ ├── CMakeLists.txt │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── ywl5320 │ │ │ └── com │ │ │ └── soundtouchdemo │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── cpp │ │ │ ├── SoundTouch │ │ │ │ ├── AAFilter.cpp │ │ │ │ ├── AAFilter.h │ │ │ │ ├── BPMDetect.cpp │ │ │ │ ├── FIFOSampleBuffer.cpp │ │ │ │ ├── FIRFilter.cpp │ │ │ │ ├── FIRFilter.h │ │ │ │ ├── InterpolateCubic.cpp │ │ │ │ ├── InterpolateCubic.h │ │ │ │ ├── InterpolateLinear.cpp │ │ │ │ ├── InterpolateLinear.h │ │ │ │ ├── InterpolateShannon.cpp │ │ │ │ ├── InterpolateShannon.h │ │ │ │ ├── PeakFinder.cpp │ │ │ │ ├── PeakFinder.h │ │ │ │ ├── RateTransposer.cpp │ │ │ │ ├── RateTransposer.h │ │ │ │ ├── SoundTouch.cpp │ │ │ │ ├── TDStretch.cpp │ │ │ │ ├── TDStretch.h │ │ │ │ ├── cpu_detect.h │ │ │ │ ├── cpu_detect_x86.cpp │ │ │ │ └── sse_optimized.cpp │ │ │ ├── include │ │ │ │ ├── BPMDetect.h │ │ │ │ ├── FIFOSampleBuffer.h │ │ │ │ ├── FIFOSamplePipe.h │ │ │ │ ├── STTypes.h │ │ │ │ ├── SoundTouch.h │ │ │ │ └── soundtouch_config.h.in │ │ │ └── native-lib.cpp │ │ ├── java │ │ │ └── ywl5320 │ │ │ │ └── com │ │ │ │ └── soundtouchdemo │ │ │ │ ├── MainActivity.java │ │ │ │ └── SoundTouch.java │ │ └── res │ │ │ ├── drawable │ │ │ └── ic_launcher_background.xml │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── ywl5320 │ │ └── com │ │ └── soundtouchdemo │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle └── pcm sounds └── mydream.pcm /README.md: -------------------------------------------------------------------------------- 1 | # SoundTouch_OpenSL_Android 2 | ## [我的视频课程(基础):《(NDK)FFmpeg打造Android万能音频播放器》](https://edu.csdn.net/course/detail/6842) 3 | ## [我的视频课程(进阶):《(NDK)FFmpeg打造Android视频播放器》](https://edu.csdn.net/course/detail/8036) 4 | ## [我的视频课程(编码直播推流):《Android视频编码和直播推流》](https://edu.csdn.net/course/detail/8942) 5 | Android中用OpenSL ES来播放SoundTouch转换后的PCM数据 6 | ## 博客[《OpenSL ES利用SoundTouch实现PCM音频的变速和变调》](https://blog.csdn.net/ywl5320/article/details/79735943) 7 | #### 实例中使用的PCM数据在文件夹pcm sounds里面,格式是:44100Hz 2声道 16bit 8 | 9 | create by ywl5320 10 | -------------------------------------------------------------------------------- /SoundTouchDemo/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | include_directories(src/main/cpp/SoundTouch) 9 | include_directories(src/main/cpp/include) 10 | 11 | # Creates and names a library, sets it as either STATIC 12 | # or SHARED, and provides the relative paths to its source code. 13 | # You can define multiple libraries, and CMake builds them for you. 14 | # Gradle automatically packages shared libraries with your APK. 15 | 16 | add_library( # Sets the name of the library. 17 | native-lib 18 | # Sets the library as a shared library. 19 | SHARED 20 | # Provides a relative path to your source file(s). 21 | src/main/cpp/native-lib.cpp 22 | src/main/cpp/SoundTouch/AAFilter.cpp 23 | src/main/cpp/SoundTouch/FIFOSampleBuffer.cpp 24 | src/main/cpp/SoundTouch/FIRFilter.cpp 25 | src/main/cpp/SoundTouch/cpu_detect_x86.cpp 26 | src/main/cpp/SoundTouch/sse_optimized.cpp 27 | src/main/cpp/SoundTouch/RateTransposer.cpp 28 | src/main/cpp/SoundTouch/SoundTouch.cpp 29 | src/main/cpp/SoundTouch/InterpolateCubic.cpp 30 | src/main/cpp/SoundTouch/InterpolateLinear.cpp 31 | src/main/cpp/SoundTouch/InterpolateShannon.cpp 32 | src/main/cpp/SoundTouch/TDStretch.cpp 33 | src/main/cpp/SoundTouch/BPMDetect.cpp 34 | src/main/cpp/SoundTouch/PeakFinder.cpp 35 | ) 36 | 37 | # Searches for a specified prebuilt library and stores the path as a 38 | # variable. Because CMake includes system libraries in the search path by 39 | # default, you only need to specify the name of the public NDK library 40 | # you want to add. CMake verifies that the library exists before 41 | # completing its build. 42 | 43 | find_library( # Sets the name of the path variable. 44 | log-lib 45 | 46 | # Specifies the name of the NDK library that 47 | # you want CMake to locate. 48 | log ) 49 | 50 | # Specifies libraries CMake should link to your target library. You 51 | # can link multiple libraries, such as libraries you define in this 52 | # build script, prebuilt third-party libraries, or system libraries. 53 | 54 | target_link_libraries( # Specifies the target library. 55 | native-lib 56 | android 57 | OpenSLES 58 | 59 | # Links the target library to the log library 60 | # included in the NDK. 61 | ${log-lib} ) -------------------------------------------------------------------------------- /SoundTouchDemo/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "26.0.2" 6 | defaultConfig { 7 | applicationId "ywl5320.com.soundtouchdemo" 8 | minSdkVersion 16 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | externalNativeBuild { 14 | cmake { 15 | cppFlags "-frtti -fexceptions" 16 | } 17 | } 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | externalNativeBuild { 26 | cmake { 27 | path "CMakeLists.txt" 28 | } 29 | } 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | implementation 'com.android.support:appcompat-v7:26.0.0-beta1' 35 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 36 | testImplementation 'junit:junit:4.12' 37 | androidTestImplementation 'com.android.support.test:runner:0.5' 38 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2' 39 | } 40 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Android\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/androidTest/java/ywl5320/com/soundtouchdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package ywl5320.com.soundtouchdemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("ywl5320.com.soundtouchdemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/AAFilter.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// FIR low-pass (anti-alias) filter with filter coefficient design routine and 4 | /// MMX optimization. 5 | /// 6 | /// Anti-alias filter is used to prevent folding of high frequencies when 7 | /// transposing the sample rate with interpolation. 8 | /// 9 | /// Author : Copyright (c) Olli Parviainen 10 | /// Author e-mail : oparviai 'at' iki.fi 11 | /// SoundTouch WWW: http://www.surina.net/soundtouch 12 | /// 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $ 16 | // File revision : $Revision: 4 $ 17 | // 18 | // $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $ 19 | // 20 | //////////////////////////////////////////////////////////////////////////////// 21 | // 22 | // License : 23 | // 24 | // SoundTouch audio processing library 25 | // Copyright (c) Olli Parviainen 26 | // 27 | // This library is free software; you can redistribute it and/or 28 | // modify it under the terms of the GNU Lesser General Public 29 | // License as published by the Free Software Foundation; either 30 | // version 2.1 of the License, or (at your option) any later version. 31 | // 32 | // This library is distributed in the hope that it will be useful, 33 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 34 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 35 | // Lesser General Public License for more details. 36 | // 37 | // You should have received a copy of the GNU Lesser General Public 38 | // License along with this library; if not, write to the Free Software 39 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 40 | // 41 | //////////////////////////////////////////////////////////////////////////////// 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include "AAFilter.h" 48 | #include "FIRFilter.h" 49 | 50 | using namespace soundtouch; 51 | 52 | #define PI 3.141592655357989 53 | #define TWOPI (2 * PI) 54 | 55 | // define this to save AA filter coefficients to a file 56 | // #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 57 | 58 | #ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS 59 | #include 60 | 61 | static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) 62 | { 63 | FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); 64 | if (fptr == NULL) return; 65 | 66 | for (int i = 0; i < len; i ++) 67 | { 68 | double temp = coeffs[i]; 69 | fprintf(fptr, "%lf\n", temp); 70 | } 71 | fclose(fptr); 72 | } 73 | 74 | #else 75 | #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) 76 | #endif 77 | 78 | 79 | /***************************************************************************** 80 | * 81 | * Implementation of the class 'AAFilter' 82 | * 83 | *****************************************************************************/ 84 | 85 | AAFilter::AAFilter(uint len) 86 | { 87 | pFIR = FIRFilter::newInstance(); 88 | cutoffFreq = 0.5; 89 | setLength(len); 90 | } 91 | 92 | 93 | 94 | AAFilter::~AAFilter() 95 | { 96 | delete pFIR; 97 | } 98 | 99 | 100 | 101 | // Sets new anti-alias filter cut-off edge frequency, scaled to 102 | // sampling frequency (nyquist frequency = 0.5). 103 | // The filter will cut frequencies higher than the given frequency. 104 | void AAFilter::setCutoffFreq(double newCutoffFreq) 105 | { 106 | cutoffFreq = newCutoffFreq; 107 | calculateCoeffs(); 108 | } 109 | 110 | 111 | 112 | // Sets number of FIR filter taps 113 | void AAFilter::setLength(uint newLength) 114 | { 115 | length = newLength; 116 | calculateCoeffs(); 117 | } 118 | 119 | 120 | 121 | // Calculates coefficients for a low-pass FIR filter using Hamming window 122 | void AAFilter::calculateCoeffs() 123 | { 124 | uint i; 125 | double cntTemp, temp, tempCoeff,h, w; 126 | double wc; 127 | double scaleCoeff, sum; 128 | double *work; 129 | SAMPLETYPE *coeffs; 130 | 131 | assert(length >= 2); 132 | assert(length % 4 == 0); 133 | assert(cutoffFreq >= 0); 134 | assert(cutoffFreq <= 0.5); 135 | 136 | work = new double[length]; 137 | coeffs = new SAMPLETYPE[length]; 138 | 139 | wc = 2.0 * PI * cutoffFreq; 140 | tempCoeff = TWOPI / (double)length; 141 | 142 | sum = 0; 143 | for (i = 0; i < length; i ++) 144 | { 145 | cntTemp = (double)i - (double)(length / 2); 146 | 147 | temp = cntTemp * wc; 148 | if (temp != 0) 149 | { 150 | h = sin(temp) / temp; // sinc function 151 | } 152 | else 153 | { 154 | h = 1.0; 155 | } 156 | w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window 157 | 158 | temp = w * h; 159 | work[i] = temp; 160 | 161 | // calc net sum of coefficients 162 | sum += temp; 163 | } 164 | 165 | // ensure the sum of coefficients is larger than zero 166 | assert(sum > 0); 167 | 168 | // ensure we've really designed a lowpass filter... 169 | assert(work[length/2] > 0); 170 | assert(work[length/2 + 1] > -1e-6); 171 | assert(work[length/2 - 1] > -1e-6); 172 | 173 | // Calculate a scaling coefficient in such a way that the result can be 174 | // divided by 16384 175 | scaleCoeff = 16384.0f / sum; 176 | 177 | for (i = 0; i < length; i ++) 178 | { 179 | temp = work[i] * scaleCoeff; 180 | //#if SOUNDTOUCH_INTEGER_SAMPLES 181 | // scale & round to nearest integer 182 | temp += (temp >= 0) ? 0.5 : -0.5; 183 | // ensure no overfloods 184 | assert(temp >= -32768 && temp <= 32767); 185 | //#endif 186 | coeffs[i] = (SAMPLETYPE)temp; 187 | } 188 | 189 | // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 190 | pFIR->setCoefficients(coeffs, length, 14); 191 | 192 | _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); 193 | 194 | delete[] work; 195 | delete[] coeffs; 196 | } 197 | 198 | 199 | // Applies the filter to the given sequence of samples. 200 | // Note : The amount of outputted samples is by value of 'filter length' 201 | // smaller than the amount of input samples. 202 | uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const 203 | { 204 | return pFIR->evaluate(dest, src, numSamples, numChannels); 205 | } 206 | 207 | 208 | /// Applies the filter to the given src & dest pipes, so that processed amount of 209 | /// samples get removed from src, and produced amount added to dest 210 | /// Note : The amount of outputted samples is by value of 'filter length' 211 | /// smaller than the amount of input samples. 212 | uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const 213 | { 214 | SAMPLETYPE *pdest; 215 | const SAMPLETYPE *psrc; 216 | uint numSrcSamples; 217 | uint result; 218 | int numChannels = src.getChannels(); 219 | 220 | assert(numChannels == dest.getChannels()); 221 | 222 | numSrcSamples = src.numSamples(); 223 | psrc = src.ptrBegin(); 224 | pdest = dest.ptrEnd(numSrcSamples); 225 | result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); 226 | src.receiveSamples(result); 227 | dest.putSamples(result); 228 | 229 | return result; 230 | } 231 | 232 | 233 | uint AAFilter::getLength() const 234 | { 235 | return pFIR->getLength(); 236 | } 237 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/AAFilter.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo 4 | /// while maintaining the original pitch by using a time domain WSOLA-like method 5 | /// with several performance-increasing tweaks. 6 | /// 7 | /// Anti-alias filter is used to prevent folding of high frequencies when 8 | /// transposing the sample rate with interpolation. 9 | /// 10 | /// Author : Copyright (c) Olli Parviainen 11 | /// Author e-mail : oparviai 'at' iki.fi 12 | /// SoundTouch WWW: http://www.surina.net/soundtouch 13 | /// 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // Last changed : $Date: 2014-01-07 21:41:23 +0200 (Tue, 07 Jan 2014) $ 17 | // File revision : $Revision: 4 $ 18 | // 19 | // $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $ 20 | // 21 | //////////////////////////////////////////////////////////////////////////////// 22 | // 23 | // License : 24 | // 25 | // SoundTouch audio processing library 26 | // Copyright (c) Olli Parviainen 27 | // 28 | // This library is free software; you can redistribute it and/or 29 | // modify it under the terms of the GNU Lesser General Public 30 | // License as published by the Free Software Foundation; either 31 | // version 2.1 of the License, or (at your option) any later version. 32 | // 33 | // This library is distributed in the hope that it will be useful, 34 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 36 | // Lesser General Public License for more details. 37 | // 38 | // You should have received a copy of the GNU Lesser General Public 39 | // License along with this library; if not, write to the Free Software 40 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 41 | // 42 | //////////////////////////////////////////////////////////////////////////////// 43 | 44 | #ifndef AAFilter_H 45 | #define AAFilter_H 46 | 47 | #include "STTypes.h" 48 | #include "FIFOSampleBuffer.h" 49 | 50 | namespace soundtouch 51 | { 52 | 53 | class AAFilter 54 | { 55 | protected: 56 | class FIRFilter *pFIR; 57 | 58 | /// Low-pass filter cut-off frequency, negative = invalid 59 | double cutoffFreq; 60 | 61 | /// num of filter taps 62 | uint length; 63 | 64 | /// Calculate the FIR coefficients realizing the given cutoff-frequency 65 | void calculateCoeffs(); 66 | public: 67 | AAFilter(uint length); 68 | 69 | ~AAFilter(); 70 | 71 | /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling 72 | /// frequency (nyquist frequency = 0.5). The filter will cut off the 73 | /// frequencies than that. 74 | void setCutoffFreq(double newCutoffFreq); 75 | 76 | /// Sets number of FIR filter taps, i.e. ~filter complexity 77 | void setLength(uint newLength); 78 | 79 | uint getLength() const; 80 | 81 | /// Applies the filter to the given sequence of samples. 82 | /// Note : The amount of outputted samples is by value of 'filter length' 83 | /// smaller than the amount of input samples. 84 | uint evaluate(SAMPLETYPE *dest, 85 | const SAMPLETYPE *src, 86 | uint numSamples, 87 | uint numChannels) const; 88 | 89 | /// Applies the filter to the given src & dest pipes, so that processed amount of 90 | /// samples get removed from src, and produced amount added to dest 91 | /// Note : The amount of outputted samples is by value of 'filter length' 92 | /// smaller than the amount of input samples. 93 | uint evaluate(FIFOSampleBuffer &dest, 94 | FIFOSampleBuffer &src) const; 95 | 96 | }; 97 | 98 | } 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/BPMDetect.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Beats-per-minute (BPM) detection routine. 4 | /// 5 | /// The beat detection algorithm works as follows: 6 | /// - Use function 'inputSamples' to input a chunks of samples to the class for 7 | /// analysis. It's a good idea to enter a large sound file or stream in smallish 8 | /// chunks of around few kilosamples in order not to extinguish too much RAM memory. 9 | /// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden, 10 | /// which is basically ok as low (bass) frequencies mostly determine the beat rate. 11 | /// Simple averaging is used for anti-alias filtering because the resulting signal 12 | /// quality isn't of that high importance. 13 | /// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by 14 | /// taking absolute value that's smoothed by sliding average. Signal levels that 15 | /// are below a couple of times the general RMS amplitude level are cut away to 16 | /// leave only notable peaks there. 17 | /// - Repeating sound patterns (e.g. beats) are detected by calculating short-term 18 | /// autocorrelation function of the enveloped signal. 19 | /// - After whole sound data file has been analyzed as above, the bpm level is 20 | /// detected by function 'getBpm' that finds the highest peak of the autocorrelation 21 | /// function, calculates it's precise location and converts this reading to bpm's. 22 | /// 23 | /// Author : Copyright (c) Olli Parviainen 24 | /// Author e-mail : oparviai 'at' iki.fi 25 | /// SoundTouch WWW: http://www.surina.net/soundtouch 26 | /// 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ 30 | // File revision : $Revision: 4 $ 31 | // 32 | // $Id: BPMDetect.cpp 202 2015-02-21 21:24:29Z oparviai $ 33 | // 34 | //////////////////////////////////////////////////////////////////////////////// 35 | // 36 | // License : 37 | // 38 | // SoundTouch audio processing library 39 | // Copyright (c) Olli Parviainen 40 | // 41 | // This library is free software; you can redistribute it and/or 42 | // modify it under the terms of the GNU Lesser General Public 43 | // License as published by the Free Software Foundation; either 44 | // version 2.1 of the License, or (at your option) any later version. 45 | // 46 | // This library is distributed in the hope that it will be useful, 47 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 48 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 49 | // Lesser General Public License for more details. 50 | // 51 | // You should have received a copy of the GNU Lesser General Public 52 | // License along with this library; if not, write to the Free Software 53 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 54 | // 55 | //////////////////////////////////////////////////////////////////////////////// 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include "FIFOSampleBuffer.h" 62 | #include "PeakFinder.h" 63 | #include "BPMDetect.h" 64 | 65 | using namespace soundtouch; 66 | 67 | #define INPUT_BLOCK_SAMPLES 2048 68 | #define DECIMATED_BLOCK_SAMPLES 256 69 | 70 | /// decay constant for calculating RMS volume sliding average approximation 71 | /// (time constant is about 10 sec) 72 | const float avgdecay = 0.99986f; 73 | 74 | /// Normalization coefficient for calculating RMS sliding average approximation. 75 | const float avgnorm = (1 - avgdecay); 76 | 77 | 78 | //////////////////////////////////////////////////////////////////////////////// 79 | 80 | // Enable following define to create bpm analysis file: 81 | 82 | // #define _CREATE_BPM_DEBUG_FILE 83 | 84 | #ifdef _CREATE_BPM_DEBUG_FILE 85 | 86 | #define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt" 87 | 88 | static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff) 89 | { 90 | FILE *fptr = fopen(DEBUGFILE_NAME, "wt"); 91 | int i; 92 | 93 | if (fptr) 94 | { 95 | printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n"); 96 | for (i = minpos; i < maxpos; i ++) 97 | { 98 | fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]); 99 | } 100 | fclose(fptr); 101 | } 102 | } 103 | #else 104 | #define _SaveDebugData(a,b,c,d) 105 | #endif 106 | 107 | //////////////////////////////////////////////////////////////////////////////// 108 | 109 | 110 | BPMDetect::BPMDetect(int numChannels, int aSampleRate) 111 | { 112 | this->sampleRate = aSampleRate; 113 | this->channels = numChannels; 114 | 115 | decimateSum = 0; 116 | decimateCount = 0; 117 | 118 | envelopeAccu = 0; 119 | 120 | // Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's 121 | // safe initial RMS signal level value for song data. This value is then adapted 122 | // to the actual level during processing. 123 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 124 | // integer samples 125 | RMSVolumeAccu = (1500 * 1500) / avgnorm; 126 | #else 127 | // float samples, scaled to range [-1..+1[ 128 | RMSVolumeAccu = (0.045f * 0.045f) / avgnorm; 129 | #endif 130 | 131 | // choose decimation factor so that result is approx. 1000 Hz 132 | decimateBy = sampleRate / 1000; 133 | assert(decimateBy > 0); 134 | assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); 135 | 136 | // Calculate window length & starting item according to desired min & max bpms 137 | windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); 138 | windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM); 139 | 140 | assert(windowLen > windowStart); 141 | 142 | // allocate new working objects 143 | xcorr = new float[windowLen]; 144 | memset(xcorr, 0, windowLen * sizeof(float)); 145 | 146 | // allocate processing buffer 147 | buffer = new FIFOSampleBuffer(); 148 | // we do processing in mono mode 149 | buffer->setChannels(1); 150 | buffer->clear(); 151 | } 152 | 153 | 154 | 155 | BPMDetect::~BPMDetect() 156 | { 157 | delete[] xcorr; 158 | delete buffer; 159 | } 160 | 161 | 162 | 163 | /// convert to mono, low-pass filter & decimate to about 500 Hz. 164 | /// return number of outputted samples. 165 | /// 166 | /// Decimation is used to remove the unnecessary frequencies and thus to reduce 167 | /// the amount of data needed to be processed as calculating autocorrelation 168 | /// function is a very-very heavy operation. 169 | /// 170 | /// Anti-alias filtering is done simply by averaging the samples. This is really a 171 | /// poor-man's anti-alias filtering, but it's not so critical in this kind of application 172 | /// (it'd also be difficult to design a high-quality filter with steep cut-off at very 173 | /// narrow band) 174 | int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) 175 | { 176 | int count, outcount; 177 | LONG_SAMPLETYPE out; 178 | 179 | assert(channels > 0); 180 | assert(decimateBy > 0); 181 | outcount = 0; 182 | for (count = 0; count < numsamples; count ++) 183 | { 184 | int j; 185 | 186 | // convert to mono and accumulate 187 | for (j = 0; j < channels; j ++) 188 | { 189 | decimateSum += src[j]; 190 | } 191 | src += j; 192 | 193 | decimateCount ++; 194 | if (decimateCount >= decimateBy) 195 | { 196 | // Store every Nth sample only 197 | out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels)); 198 | decimateSum = 0; 199 | decimateCount = 0; 200 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 201 | // check ranges for sure (shouldn't actually be necessary) 202 | if (out > 32767) 203 | { 204 | out = 32767; 205 | } 206 | else if (out < -32768) 207 | { 208 | out = -32768; 209 | } 210 | #endif // SOUNDTOUCH_INTEGER_SAMPLES 211 | dest[outcount] = (SAMPLETYPE)out; 212 | outcount ++; 213 | } 214 | } 215 | return outcount; 216 | } 217 | 218 | 219 | 220 | // Calculates autocorrelation function of the sample history buffer 221 | void BPMDetect::updateXCorr(int process_samples) 222 | { 223 | int offs; 224 | SAMPLETYPE *pBuffer; 225 | 226 | assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); 227 | 228 | pBuffer = buffer->ptrBegin(); 229 | #pragma omp parallel for 230 | for (offs = windowStart; offs < windowLen; offs ++) 231 | { 232 | LONG_SAMPLETYPE sum; 233 | int i; 234 | 235 | sum = 0; 236 | for (i = 0; i < process_samples; i ++) 237 | { 238 | sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary 239 | } 240 | // xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients 241 | // if it's desired that the system adapts automatically to 242 | // various bpms, e.g. in processing continouos music stream. 243 | // The 'xcorr_decay' should be a value that's smaller than but 244 | // close to one, and should also depend on 'process_samples' value. 245 | 246 | xcorr[offs] += (float)sum; 247 | } 248 | } 249 | 250 | 251 | // Calculates envelope of the sample data 252 | void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) 253 | { 254 | const static double decay = 0.7f; // decay constant for smoothing the envelope 255 | const static double norm = (1 - decay); 256 | 257 | int i; 258 | LONG_SAMPLETYPE out; 259 | double val; 260 | 261 | for (i = 0; i < numsamples; i ++) 262 | { 263 | // calc average RMS volume 264 | RMSVolumeAccu *= avgdecay; 265 | val = (float)fabs((float)samples[i]); 266 | RMSVolumeAccu += val * val; 267 | 268 | // cut amplitudes that are below cutoff ~2 times RMS volume 269 | // (we're interested in peak values, not the silent moments) 270 | if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm)) 271 | { 272 | val = 0; 273 | } 274 | 275 | // smooth amplitude envelope 276 | envelopeAccu *= decay; 277 | envelopeAccu += val; 278 | out = (LONG_SAMPLETYPE)(envelopeAccu * norm); 279 | 280 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 281 | // cut peaks (shouldn't be necessary though) 282 | if (out > 32767) out = 32767; 283 | #endif // SOUNDTOUCH_INTEGER_SAMPLES 284 | samples[i] = (SAMPLETYPE)out; 285 | } 286 | } 287 | 288 | 289 | 290 | void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) 291 | { 292 | SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; 293 | 294 | // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration 295 | while (numSamples > 0) 296 | { 297 | int block; 298 | int decSamples; 299 | 300 | block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples; 301 | 302 | // decimate. note that converts to mono at the same time 303 | decSamples = decimate(decimated, samples, block); 304 | samples += block * channels; 305 | numSamples -= block; 306 | 307 | // envelope new samples and add them to buffer 308 | calcEnvelope(decimated, decSamples); 309 | buffer->putSamples(decimated, decSamples); 310 | } 311 | 312 | // when the buffer has enought samples for processing... 313 | if ((int)buffer->numSamples() > windowLen) 314 | { 315 | int processLength; 316 | 317 | // how many samples are processed 318 | processLength = (int)buffer->numSamples() - windowLen; 319 | 320 | // ... calculate autocorrelations for oldest samples... 321 | updateXCorr(processLength); 322 | // ... and remove them from the buffer 323 | buffer->receiveSamples(processLength); 324 | } 325 | } 326 | 327 | 328 | 329 | void BPMDetect::removeBias() 330 | { 331 | int i; 332 | float minval = 1e12f; // arbitrary large number 333 | 334 | for (i = windowStart; i < windowLen; i ++) 335 | { 336 | if (xcorr[i] < minval) 337 | { 338 | minval = xcorr[i]; 339 | } 340 | } 341 | 342 | for (i = windowStart; i < windowLen; i ++) 343 | { 344 | xcorr[i] -= minval; 345 | } 346 | } 347 | 348 | 349 | float BPMDetect::getBpm() 350 | { 351 | double peakPos; 352 | double coeff; 353 | PeakFinder peakFinder; 354 | 355 | coeff = 60.0 * ((double)sampleRate / (double)decimateBy); 356 | 357 | // save bpm debug analysis data if debug data enabled 358 | _SaveDebugData(xcorr, windowStart, windowLen, coeff); 359 | 360 | // remove bias from xcorr data 361 | removeBias(); 362 | 363 | // find peak position 364 | peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); 365 | 366 | assert(decimateBy != 0); 367 | if (peakPos < 1e-9) return 0.0; // detection failed. 368 | 369 | // calculate BPM 370 | return (float) (coeff / peakPos); 371 | } 372 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/FIFOSampleBuffer.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// A buffer class for temporarily storaging sound samples, operates as a 4 | /// first-in-first-out pipe. 5 | /// 6 | /// Samples are added to the end of the sample buffer with the 'putSamples' 7 | /// function, and are received from the beginning of the buffer by calling 8 | /// the 'receiveSamples' function. The class automatically removes the 9 | /// outputted samples from the buffer, as well as grows the buffer size 10 | /// whenever necessary. 11 | /// 12 | /// Author : Copyright (c) Olli Parviainen 13 | /// Author e-mail : oparviai 'at' iki.fi 14 | /// SoundTouch WWW: http://www.surina.net/soundtouch 15 | /// 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // 18 | // Last changed : $Date: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $ 19 | // File revision : $Revision: 4 $ 20 | // 21 | // $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $ 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // License : 26 | // 27 | // SoundTouch audio processing library 28 | // Copyright (c) Olli Parviainen 29 | // 30 | // This library is free software; you can redistribute it and/or 31 | // modify it under the terms of the GNU Lesser General Public 32 | // License as published by the Free Software Foundation; either 33 | // version 2.1 of the License, or (at your option) any later version. 34 | // 35 | // This library is distributed in the hope that it will be useful, 36 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 38 | // Lesser General Public License for more details. 39 | // 40 | // You should have received a copy of the GNU Lesser General Public 41 | // License along with this library; if not, write to the Free Software 42 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 43 | // 44 | //////////////////////////////////////////////////////////////////////////////// 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include "FIFOSampleBuffer.h" 52 | 53 | using namespace soundtouch; 54 | 55 | // Constructor 56 | FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) 57 | { 58 | assert(numChannels > 0); 59 | sizeInBytes = 0; // reasonable initial value 60 | buffer = NULL; 61 | bufferUnaligned = NULL; 62 | samplesInBuffer = 0; 63 | bufferPos = 0; 64 | channels = (uint)numChannels; 65 | ensureCapacity(32); // allocate initial capacity 66 | } 67 | 68 | 69 | // destructor 70 | FIFOSampleBuffer::~FIFOSampleBuffer() 71 | { 72 | delete[] bufferUnaligned; 73 | bufferUnaligned = NULL; 74 | buffer = NULL; 75 | } 76 | 77 | 78 | // Sets number of channels, 1 = mono, 2 = stereo 79 | void FIFOSampleBuffer::setChannels(int numChannels) 80 | { 81 | uint usedBytes; 82 | 83 | assert(numChannels > 0); 84 | usedBytes = channels * samplesInBuffer; 85 | channels = (uint)numChannels; 86 | samplesInBuffer = usedBytes / channels; 87 | } 88 | 89 | 90 | // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and 91 | // zeroes this pointer by copying samples from the 'bufferPos' pointer 92 | // location on to the beginning of the buffer. 93 | void FIFOSampleBuffer::rewind() 94 | { 95 | if (buffer && bufferPos) 96 | { 97 | memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); 98 | bufferPos = 0; 99 | } 100 | } 101 | 102 | 103 | // Adds 'numSamples' pcs of samples from the 'samples' memory position to 104 | // the sample buffer. 105 | void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) 106 | { 107 | memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); 108 | samplesInBuffer += nSamples; 109 | } 110 | 111 | 112 | // Increases the number of samples in the buffer without copying any actual 113 | // samples. 114 | // 115 | // This function is used to update the number of samples in the sample buffer 116 | // when accessing the buffer directly with 'ptrEnd' function. Please be 117 | // careful though! 118 | void FIFOSampleBuffer::putSamples(uint nSamples) 119 | { 120 | uint req; 121 | 122 | req = samplesInBuffer + nSamples; 123 | ensureCapacity(req); 124 | samplesInBuffer += nSamples; 125 | } 126 | 127 | 128 | // Returns a pointer to the end of the used part of the sample buffer (i.e. 129 | // where the new samples are to be inserted). This function may be used for 130 | // inserting new samples into the sample buffer directly. Please be careful! 131 | // 132 | // Parameter 'slackCapacity' tells the function how much free capacity (in 133 | // terms of samples) there _at least_ should be, in order to the caller to 134 | // succesfully insert all the required samples to the buffer. When necessary, 135 | // the function grows the buffer size to comply with this requirement. 136 | // 137 | // When using this function as means for inserting new samples, also remember 138 | // to increase the sample count afterwards, by calling the 139 | // 'putSamples(numSamples)' function. 140 | SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) 141 | { 142 | ensureCapacity(samplesInBuffer + slackCapacity); 143 | return buffer + samplesInBuffer * channels; 144 | } 145 | 146 | 147 | // Returns a pointer to the beginning of the currently non-outputted samples. 148 | // This function is provided for accessing the output samples directly. 149 | // Please be careful! 150 | // 151 | // When using this function to output samples, also remember to 'remove' the 152 | // outputted samples from the buffer by calling the 153 | // 'receiveSamples(numSamples)' function 154 | SAMPLETYPE *FIFOSampleBuffer::ptrBegin() 155 | { 156 | assert(buffer); 157 | return buffer + bufferPos * channels; 158 | } 159 | 160 | 161 | // Ensures that the buffer has enought capacity, i.e. space for _at least_ 162 | // 'capacityRequirement' number of samples. The buffer is grown in steps of 163 | // 4 kilobytes to eliminate the need for frequently growing up the buffer, 164 | // as well as to round the buffer size up to the virtual memory page size. 165 | void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) 166 | { 167 | SAMPLETYPE *tempUnaligned, *temp; 168 | 169 | if (capacityRequirement > getCapacity()) 170 | { 171 | // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) 172 | sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; 173 | assert(sizeInBytes % 2 == 0); 174 | tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; 175 | if (tempUnaligned == NULL) 176 | { 177 | ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); 178 | } 179 | // Align the buffer to begin at 16byte cache line boundary for optimal performance 180 | temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); 181 | if (samplesInBuffer) 182 | { 183 | memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); 184 | } 185 | delete[] bufferUnaligned; 186 | buffer = temp; 187 | bufferUnaligned = tempUnaligned; 188 | bufferPos = 0; 189 | } 190 | else 191 | { 192 | // simply rewind the buffer (if necessary) 193 | rewind(); 194 | } 195 | } 196 | 197 | 198 | // Returns the current buffer capacity in terms of samples 199 | uint FIFOSampleBuffer::getCapacity() const 200 | { 201 | return sizeInBytes / (channels * sizeof(SAMPLETYPE)); 202 | } 203 | 204 | 205 | // Returns the number of samples currently in the buffer 206 | uint FIFOSampleBuffer::numSamples() const 207 | { 208 | return samplesInBuffer; 209 | } 210 | 211 | 212 | // Output samples from beginning of the sample buffer. Copies demanded number 213 | // of samples to output and removes them from the sample buffer. If there 214 | // are less than 'numsample' samples in the buffer, returns all available. 215 | // 216 | // Returns number of samples copied. 217 | uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) 218 | { 219 | uint num; 220 | 221 | num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; 222 | 223 | memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); 224 | return receiveSamples(num); 225 | } 226 | 227 | 228 | // Removes samples from the beginning of the sample buffer without copying them 229 | // anywhere. Used to reduce the number of samples in the buffer, when accessing 230 | // the sample buffer with the 'ptrBegin' function. 231 | uint FIFOSampleBuffer::receiveSamples(uint maxSamples) 232 | { 233 | if (maxSamples >= samplesInBuffer) 234 | { 235 | uint temp; 236 | 237 | temp = samplesInBuffer; 238 | samplesInBuffer = 0; 239 | return temp; 240 | } 241 | 242 | samplesInBuffer -= maxSamples; 243 | bufferPos += maxSamples; 244 | 245 | return maxSamples; 246 | } 247 | 248 | 249 | // Returns nonzero if the sample buffer is empty 250 | int FIFOSampleBuffer::isEmpty() const 251 | { 252 | return (samplesInBuffer == 0) ? 1 : 0; 253 | } 254 | 255 | 256 | // Clears the sample buffer 257 | void FIFOSampleBuffer::clear() 258 | { 259 | samplesInBuffer = 0; 260 | bufferPos = 0; 261 | } 262 | 263 | 264 | /// allow trimming (downwards) amount of samples in pipeline. 265 | /// Returns adjusted amount of samples 266 | uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) 267 | { 268 | if (numSamples < samplesInBuffer) 269 | { 270 | samplesInBuffer = numSamples; 271 | } 272 | return samplesInBuffer; 273 | } 274 | 275 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/FIRFilter.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// General FIR digital filter routines with MMX optimization. 4 | /// 5 | /// Note : MMX optimized functions reside in a separate, platform-specific file, 6 | /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' 7 | /// 8 | /// Author : Copyright (c) Olli Parviainen 9 | /// Author e-mail : oparviai 'at' iki.fi 10 | /// SoundTouch WWW: http://www.surina.net/soundtouch 11 | /// 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // 14 | // Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ 15 | // File revision : $Revision: 4 $ 16 | // 17 | // $Id: FIRFilter.cpp 202 2015-02-21 21:24:29Z oparviai $ 18 | // 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // License : 22 | // 23 | // SoundTouch audio processing library 24 | // Copyright (c) Olli Parviainen 25 | // 26 | // This library is free software; you can redistribute it and/or 27 | // modify it under the terms of the GNU Lesser General Public 28 | // License as published by the Free Software Foundation; either 29 | // version 2.1 of the License, or (at your option) any later version. 30 | // 31 | // This library is distributed in the hope that it will be useful, 32 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 34 | // Lesser General Public License for more details. 35 | // 36 | // You should have received a copy of the GNU Lesser General Public 37 | // License along with this library; if not, write to the Free Software 38 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 39 | // 40 | //////////////////////////////////////////////////////////////////////////////// 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include "FIRFilter.h" 47 | #include "cpu_detect.h" 48 | 49 | using namespace soundtouch; 50 | 51 | /***************************************************************************** 52 | * 53 | * Implementation of the class 'FIRFilter' 54 | * 55 | *****************************************************************************/ 56 | 57 | FIRFilter::FIRFilter() 58 | { 59 | resultDivFactor = 0; 60 | resultDivider = 0; 61 | length = 0; 62 | lengthDiv8 = 0; 63 | filterCoeffs = NULL; 64 | } 65 | 66 | 67 | FIRFilter::~FIRFilter() 68 | { 69 | delete[] filterCoeffs; 70 | } 71 | 72 | // Usual C-version of the filter routine for stereo sound 73 | uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const 74 | { 75 | int j, end; 76 | #ifdef SOUNDTOUCH_FLOAT_SAMPLES 77 | // when using floating point samples, use a scaler instead of a divider 78 | // because division is much slower operation than multiplying. 79 | double dScaler = 1.0 / (double)resultDivider; 80 | #endif 81 | 82 | assert(length != 0); 83 | assert(src != NULL); 84 | assert(dest != NULL); 85 | assert(filterCoeffs != NULL); 86 | 87 | end = 2 * (numSamples - length); 88 | 89 | #pragma omp parallel for 90 | for (j = 0; j < end; j += 2) 91 | { 92 | const SAMPLETYPE *ptr; 93 | LONG_SAMPLETYPE suml, sumr; 94 | uint i; 95 | 96 | suml = sumr = 0; 97 | ptr = src + j; 98 | 99 | for (i = 0; i < length; i += 4) 100 | { 101 | // loop is unrolled by factor of 4 here for efficiency 102 | suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + 103 | ptr[2 * i + 2] * filterCoeffs[i + 1] + 104 | ptr[2 * i + 4] * filterCoeffs[i + 2] + 105 | ptr[2 * i + 6] * filterCoeffs[i + 3]; 106 | sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + 107 | ptr[2 * i + 3] * filterCoeffs[i + 1] + 108 | ptr[2 * i + 5] * filterCoeffs[i + 2] + 109 | ptr[2 * i + 7] * filterCoeffs[i + 3]; 110 | } 111 | 112 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 113 | suml >>= resultDivFactor; 114 | sumr >>= resultDivFactor; 115 | // saturate to 16 bit integer limits 116 | suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; 117 | // saturate to 16 bit integer limits 118 | sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; 119 | #else 120 | suml *= dScaler; 121 | sumr *= dScaler; 122 | #endif // SOUNDTOUCH_INTEGER_SAMPLES 123 | dest[j] = (SAMPLETYPE)suml; 124 | dest[j + 1] = (SAMPLETYPE)sumr; 125 | } 126 | return numSamples - length; 127 | } 128 | 129 | 130 | 131 | 132 | // Usual C-version of the filter routine for mono sound 133 | uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const 134 | { 135 | int j, end; 136 | #ifdef SOUNDTOUCH_FLOAT_SAMPLES 137 | // when using floating point samples, use a scaler instead of a divider 138 | // because division is much slower operation than multiplying. 139 | double dScaler = 1.0 / (double)resultDivider; 140 | #endif 141 | 142 | assert(length != 0); 143 | 144 | end = numSamples - length; 145 | #pragma omp parallel for 146 | for (j = 0; j < end; j ++) 147 | { 148 | const SAMPLETYPE *pSrc = src + j; 149 | LONG_SAMPLETYPE sum; 150 | uint i; 151 | 152 | sum = 0; 153 | for (i = 0; i < length; i += 4) 154 | { 155 | // loop is unrolled by factor of 4 here for efficiency 156 | sum += pSrc[i + 0] * filterCoeffs[i + 0] + 157 | pSrc[i + 1] * filterCoeffs[i + 1] + 158 | pSrc[i + 2] * filterCoeffs[i + 2] + 159 | pSrc[i + 3] * filterCoeffs[i + 3]; 160 | } 161 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 162 | sum >>= resultDivFactor; 163 | // saturate to 16 bit integer limits 164 | sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; 165 | #else 166 | sum *= dScaler; 167 | #endif // SOUNDTOUCH_INTEGER_SAMPLES 168 | dest[j] = (SAMPLETYPE)sum; 169 | } 170 | return end; 171 | } 172 | 173 | 174 | uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) 175 | { 176 | int j, end; 177 | 178 | #ifdef SOUNDTOUCH_FLOAT_SAMPLES 179 | // when using floating point samples, use a scaler instead of a divider 180 | // because division is much slower operation than multiplying. 181 | double dScaler = 1.0 / (double)resultDivider; 182 | #endif 183 | 184 | assert(length != 0); 185 | assert(src != NULL); 186 | assert(dest != NULL); 187 | assert(filterCoeffs != NULL); 188 | assert(numChannels < 16); 189 | 190 | end = numChannels * (numSamples - length); 191 | 192 | #pragma omp parallel for 193 | for (j = 0; j < end; j += numChannels) 194 | { 195 | const SAMPLETYPE *ptr; 196 | LONG_SAMPLETYPE sums[16]; 197 | uint c, i; 198 | 199 | for (c = 0; c < numChannels; c ++) 200 | { 201 | sums[c] = 0; 202 | } 203 | 204 | ptr = src + j; 205 | 206 | for (i = 0; i < length; i ++) 207 | { 208 | SAMPLETYPE coef=filterCoeffs[i]; 209 | for (c = 0; c < numChannels; c ++) 210 | { 211 | sums[c] += ptr[0] * coef; 212 | ptr ++; 213 | } 214 | } 215 | 216 | for (c = 0; c < numChannels; c ++) 217 | { 218 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 219 | sums[c] >>= resultDivFactor; 220 | #else 221 | sums[c] *= dScaler; 222 | #endif // SOUNDTOUCH_INTEGER_SAMPLES 223 | dest[j+c] = (SAMPLETYPE)sums[c]; 224 | } 225 | } 226 | return numSamples - length; 227 | } 228 | 229 | 230 | // Set filter coeffiecients and length. 231 | // 232 | // Throws an exception if filter length isn't divisible by 8 233 | void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) 234 | { 235 | assert(newLength > 0); 236 | if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); 237 | 238 | lengthDiv8 = newLength / 8; 239 | length = lengthDiv8 * 8; 240 | assert(length == newLength); 241 | 242 | resultDivFactor = uResultDivFactor; 243 | resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); 244 | 245 | delete[] filterCoeffs; 246 | filterCoeffs = new SAMPLETYPE[length]; 247 | memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); 248 | } 249 | 250 | 251 | uint FIRFilter::getLength() const 252 | { 253 | return length; 254 | } 255 | 256 | 257 | 258 | // Applies the filter to the given sequence of samples. 259 | // 260 | // Note : The amount of outputted samples is by value of 'filter_length' 261 | // smaller than the amount of input samples. 262 | uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) 263 | { 264 | assert(length > 0); 265 | assert(lengthDiv8 * 8 == length); 266 | 267 | if (numSamples < length) return 0; 268 | 269 | #ifndef USE_MULTICH_ALWAYS 270 | if (numChannels == 1) 271 | { 272 | return evaluateFilterMono(dest, src, numSamples); 273 | } 274 | else if (numChannels == 2) 275 | { 276 | return evaluateFilterStereo(dest, src, numSamples); 277 | } 278 | else 279 | #endif // USE_MULTICH_ALWAYS 280 | { 281 | assert(numChannels > 0); 282 | return evaluateFilterMulti(dest, src, numSamples, numChannels); 283 | } 284 | } 285 | 286 | 287 | 288 | // Operator 'new' is overloaded so that it automatically creates a suitable instance 289 | // depending on if we've a MMX-capable CPU available or not. 290 | void * FIRFilter::operator new(size_t s) 291 | { 292 | // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! 293 | ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); 294 | return newInstance(); 295 | } 296 | 297 | 298 | FIRFilter * FIRFilter::newInstance() 299 | { 300 | uint uExtensions; 301 | 302 | uExtensions = detectCPUextensions(); 303 | 304 | // Check if MMX/SSE instruction set extensions supported by CPU 305 | 306 | #ifdef SOUNDTOUCH_ALLOW_MMX 307 | // MMX routines available only with integer sample types 308 | if (uExtensions & SUPPORT_MMX) 309 | { 310 | return ::new FIRFilterMMX; 311 | } 312 | else 313 | #endif // SOUNDTOUCH_ALLOW_MMX 314 | 315 | #ifdef SOUNDTOUCH_ALLOW_SSE 316 | if (uExtensions & SUPPORT_SSE) 317 | { 318 | // SSE support 319 | return ::new FIRFilterSSE; 320 | } 321 | else 322 | #endif // SOUNDTOUCH_ALLOW_SSE 323 | 324 | { 325 | // ISA optimizations not supported, use plain C version 326 | return ::new FIRFilter; 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/FIRFilter.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// General FIR digital filter routines with MMX optimization. 4 | /// 5 | /// Note : MMX optimized functions reside in a separate, platform-specific file, 6 | /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' 7 | /// 8 | /// Author : Copyright (c) Olli Parviainen 9 | /// Author e-mail : oparviai 'at' iki.fi 10 | /// SoundTouch WWW: http://www.surina.net/soundtouch 11 | /// 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // 14 | // Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ 15 | // File revision : $Revision: 4 $ 16 | // 17 | // $Id: FIRFilter.h 202 2015-02-21 21:24:29Z oparviai $ 18 | // 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // License : 22 | // 23 | // SoundTouch audio processing library 24 | // Copyright (c) Olli Parviainen 25 | // 26 | // This library is free software; you can redistribute it and/or 27 | // modify it under the terms of the GNU Lesser General Public 28 | // License as published by the Free Software Foundation; either 29 | // version 2.1 of the License, or (at your option) any later version. 30 | // 31 | // This library is distributed in the hope that it will be useful, 32 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 34 | // Lesser General Public License for more details. 35 | // 36 | // You should have received a copy of the GNU Lesser General Public 37 | // License along with this library; if not, write to the Free Software 38 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 39 | // 40 | //////////////////////////////////////////////////////////////////////////////// 41 | 42 | #ifndef FIRFilter_H 43 | #define FIRFilter_H 44 | 45 | #include 46 | #include "STTypes.h" 47 | 48 | namespace soundtouch 49 | { 50 | 51 | class FIRFilter 52 | { 53 | protected: 54 | // Number of FIR filter taps 55 | uint length; 56 | // Number of FIR filter taps divided by 8 57 | uint lengthDiv8; 58 | 59 | // Result divider factor in 2^k format 60 | uint resultDivFactor; 61 | 62 | // Result divider value. 63 | SAMPLETYPE resultDivider; 64 | 65 | // Memory for filter coefficients 66 | SAMPLETYPE *filterCoeffs; 67 | 68 | virtual uint evaluateFilterStereo(SAMPLETYPE *dest, 69 | const SAMPLETYPE *src, 70 | uint numSamples) const; 71 | virtual uint evaluateFilterMono(SAMPLETYPE *dest, 72 | const SAMPLETYPE *src, 73 | uint numSamples) const; 74 | virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels); 75 | 76 | public: 77 | FIRFilter(); 78 | virtual ~FIRFilter(); 79 | 80 | /// Operator 'new' is overloaded so that it automatically creates a suitable instance 81 | /// depending on if we've a MMX-capable CPU available or not. 82 | static void * operator new(size_t s); 83 | 84 | static FIRFilter *newInstance(); 85 | 86 | /// Applies the filter to the given sequence of samples. 87 | /// Note : The amount of outputted samples is by value of 'filter_length' 88 | /// smaller than the amount of input samples. 89 | /// 90 | /// \return Number of samples copied to 'dest'. 91 | uint evaluate(SAMPLETYPE *dest, 92 | const SAMPLETYPE *src, 93 | uint numSamples, 94 | uint numChannels); 95 | 96 | uint getLength() const; 97 | 98 | virtual void setCoefficients(const SAMPLETYPE *coeffs, 99 | uint newLength, 100 | uint uResultDivFactor); 101 | }; 102 | 103 | 104 | // Optional subclasses that implement CPU-specific optimizations: 105 | 106 | #ifdef SOUNDTOUCH_ALLOW_MMX 107 | 108 | /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. 109 | class FIRFilterMMX : public FIRFilter 110 | { 111 | protected: 112 | short *filterCoeffsUnalign; 113 | short *filterCoeffsAlign; 114 | 115 | virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; 116 | public: 117 | FIRFilterMMX(); 118 | ~FIRFilterMMX(); 119 | 120 | virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); 121 | }; 122 | 123 | #endif // SOUNDTOUCH_ALLOW_MMX 124 | 125 | 126 | #ifdef SOUNDTOUCH_ALLOW_SSE 127 | /// Class that implements SSE optimized functions exclusive for floating point samples type. 128 | class FIRFilterSSE : public FIRFilter 129 | { 130 | protected: 131 | float *filterCoeffsUnalign; 132 | float *filterCoeffsAlign; 133 | 134 | virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; 135 | public: 136 | FIRFilterSSE(); 137 | ~FIRFilterSSE(); 138 | 139 | virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); 140 | }; 141 | 142 | #endif // SOUNDTOUCH_ALLOW_SSE 143 | 144 | } 145 | 146 | #endif // FIRFilter_H 147 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/InterpolateCubic.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Cubic interpolation routine. 4 | /// 5 | /// Author : Copyright (c) Olli Parviainen 6 | /// Author e-mail : oparviai 'at' iki.fi 7 | /// SoundTouch WWW: http://www.surina.net/soundtouch 8 | /// 9 | //////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // $Id: InterpolateCubic.cpp 179 2014-01-06 18:41:42Z oparviai $ 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // License : 16 | // 17 | // SoundTouch audio processing library 18 | // Copyright (c) Olli Parviainen 19 | // 20 | // This library is free software; you can redistribute it and/or 21 | // modify it under the terms of the GNU Lesser General Public 22 | // License as published by the Free Software Foundation; either 23 | // version 2.1 of the License, or (at your option) any later version. 24 | // 25 | // This library is distributed in the hope that it will be useful, 26 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 28 | // Lesser General Public License for more details. 29 | // 30 | // You should have received a copy of the GNU Lesser General Public 31 | // License along with this library; if not, write to the Free Software 32 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33 | // 34 | //////////////////////////////////////////////////////////////////////////////// 35 | 36 | #include 37 | #include 38 | #include "InterpolateCubic.h" 39 | #include "STTypes.h" 40 | 41 | using namespace soundtouch; 42 | 43 | // cubic interpolation coefficients 44 | static const float _coeffs[]= 45 | { -0.5f, 1.0f, -0.5f, 0.0f, 46 | 1.5f, -2.5f, 0.0f, 1.0f, 47 | -1.5f, 2.0f, 0.5f, 0.0f, 48 | 0.5f, -0.5f, 0.0f, 0.0f}; 49 | 50 | 51 | InterpolateCubic::InterpolateCubic() 52 | { 53 | fract = 0; 54 | } 55 | 56 | 57 | void InterpolateCubic::resetRegisters() 58 | { 59 | fract = 0; 60 | } 61 | 62 | 63 | /// Transpose mono audio. Returns number of produced output samples, and 64 | /// updates "srcSamples" to amount of consumed source samples 65 | int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, 66 | const SAMPLETYPE *psrc, 67 | int &srcSamples) 68 | { 69 | int i; 70 | int srcSampleEnd = srcSamples - 4; 71 | int srcCount = 0; 72 | 73 | i = 0; 74 | while (srcCount < srcSampleEnd) 75 | { 76 | float out; 77 | const float x3 = 1.0f; 78 | const float x2 = (float)fract; // x 79 | const float x1 = x2*x2; // x^2 80 | const float x0 = x1*x2; // x^3 81 | float y0, y1, y2, y3; 82 | 83 | assert(fract < 1.0); 84 | 85 | y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; 86 | y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; 87 | y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; 88 | y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; 89 | 90 | out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3]; 91 | 92 | pdest[i] = (SAMPLETYPE)out; 93 | i ++; 94 | 95 | // update position fraction 96 | fract += rate; 97 | // update whole positions 98 | int whole = (int)fract; 99 | fract -= whole; 100 | psrc += whole; 101 | srcCount += whole; 102 | } 103 | srcSamples = srcCount; 104 | return i; 105 | } 106 | 107 | 108 | /// Transpose stereo audio. Returns number of produced output samples, and 109 | /// updates "srcSamples" to amount of consumed source samples 110 | int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, 111 | const SAMPLETYPE *psrc, 112 | int &srcSamples) 113 | { 114 | int i; 115 | int srcSampleEnd = srcSamples - 4; 116 | int srcCount = 0; 117 | 118 | i = 0; 119 | while (srcCount < srcSampleEnd) 120 | { 121 | const float x3 = 1.0f; 122 | const float x2 = (float)fract; // x 123 | const float x1 = x2*x2; // x^2 124 | const float x0 = x1*x2; // x^3 125 | float y0, y1, y2, y3; 126 | float out0, out1; 127 | 128 | assert(fract < 1.0); 129 | 130 | y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; 131 | y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; 132 | y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; 133 | y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; 134 | 135 | out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6]; 136 | out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7]; 137 | 138 | pdest[2*i] = (SAMPLETYPE)out0; 139 | pdest[2*i+1] = (SAMPLETYPE)out1; 140 | i ++; 141 | 142 | // update position fraction 143 | fract += rate; 144 | // update whole positions 145 | int whole = (int)fract; 146 | fract -= whole; 147 | psrc += 2*whole; 148 | srcCount += whole; 149 | } 150 | srcSamples = srcCount; 151 | return i; 152 | } 153 | 154 | 155 | /// Transpose multi-channel audio. Returns number of produced output samples, and 156 | /// updates "srcSamples" to amount of consumed source samples 157 | int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, 158 | const SAMPLETYPE *psrc, 159 | int &srcSamples) 160 | { 161 | int i; 162 | int srcSampleEnd = srcSamples - 4; 163 | int srcCount = 0; 164 | 165 | i = 0; 166 | while (srcCount < srcSampleEnd) 167 | { 168 | const float x3 = 1.0f; 169 | const float x2 = (float)fract; // x 170 | const float x1 = x2*x2; // x^2 171 | const float x0 = x1*x2; // x^3 172 | float y0, y1, y2, y3; 173 | 174 | assert(fract < 1.0); 175 | 176 | y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; 177 | y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; 178 | y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; 179 | y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; 180 | 181 | for (int c = 0; c < numChannels; c ++) 182 | { 183 | float out; 184 | out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; 185 | pdest[0] = (SAMPLETYPE)out; 186 | pdest ++; 187 | } 188 | i ++; 189 | 190 | // update position fraction 191 | fract += rate; 192 | // update whole positions 193 | int whole = (int)fract; 194 | fract -= whole; 195 | psrc += numChannels*whole; 196 | srcCount += whole; 197 | } 198 | srcSamples = srcCount; 199 | return i; 200 | } 201 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/InterpolateCubic.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Cubic interpolation routine. 4 | /// 5 | /// Author : Copyright (c) Olli Parviainen 6 | /// Author e-mail : oparviai 'at' iki.fi 7 | /// SoundTouch WWW: http://www.surina.net/soundtouch 8 | /// 9 | //////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // $Id: InterpolateCubic.h 225 2015-07-26 14:45:48Z oparviai $ 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // License : 16 | // 17 | // SoundTouch audio processing library 18 | // Copyright (c) Olli Parviainen 19 | // 20 | // This library is free software; you can redistribute it and/or 21 | // modify it under the terms of the GNU Lesser General Public 22 | // License as published by the Free Software Foundation; either 23 | // version 2.1 of the License, or (at your option) any later version. 24 | // 25 | // This library is distributed in the hope that it will be useful, 26 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 28 | // Lesser General Public License for more details. 29 | // 30 | // You should have received a copy of the GNU Lesser General Public 31 | // License along with this library; if not, write to the Free Software 32 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33 | // 34 | //////////////////////////////////////////////////////////////////////////////// 35 | 36 | #ifndef _InterpolateCubic_H_ 37 | #define _InterpolateCubic_H_ 38 | 39 | #include "RateTransposer.h" 40 | #include "STTypes.h" 41 | 42 | namespace soundtouch 43 | { 44 | 45 | class InterpolateCubic : public TransposerBase 46 | { 47 | protected: 48 | virtual void resetRegisters(); 49 | virtual int transposeMono(SAMPLETYPE *dest, 50 | const SAMPLETYPE *src, 51 | int &srcSamples); 52 | virtual int transposeStereo(SAMPLETYPE *dest, 53 | const SAMPLETYPE *src, 54 | int &srcSamples); 55 | virtual int transposeMulti(SAMPLETYPE *dest, 56 | const SAMPLETYPE *src, 57 | int &srcSamples); 58 | 59 | double fract; 60 | 61 | public: 62 | InterpolateCubic(); 63 | }; 64 | 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/InterpolateLinear.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Linear interpolation algorithm. 4 | /// 5 | /// Author : Copyright (c) Olli Parviainen 6 | /// Author e-mail : oparviai 'at' iki.fi 7 | /// SoundTouch WWW: http://www.surina.net/soundtouch 8 | /// 9 | //////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // $Id: InterpolateLinear.cpp 225 2015-07-26 14:45:48Z oparviai $ 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // License : 16 | // 17 | // SoundTouch audio processing library 18 | // Copyright (c) Olli Parviainen 19 | // 20 | // This library is free software; you can redistribute it and/or 21 | // modify it under the terms of the GNU Lesser General Public 22 | // License as published by the Free Software Foundation; either 23 | // version 2.1 of the License, or (at your option) any later version. 24 | // 25 | // This library is distributed in the hope that it will be useful, 26 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 28 | // Lesser General Public License for more details. 29 | // 30 | // You should have received a copy of the GNU Lesser General Public 31 | // License along with this library; if not, write to the Free Software 32 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33 | // 34 | //////////////////////////////////////////////////////////////////////////////// 35 | 36 | #include 37 | #include 38 | #include "InterpolateLinear.h" 39 | 40 | using namespace soundtouch; 41 | 42 | ////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // InterpolateLinearInteger - integer arithmetic implementation 45 | // 46 | 47 | /// fixed-point interpolation routine precision 48 | #define SCALE 65536 49 | 50 | 51 | // Constructor 52 | InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() 53 | { 54 | // Notice: use local function calling syntax for sake of clarity, 55 | // to indicate the fact that C++ constructor can't call virtual functions. 56 | resetRegisters(); 57 | setRate(1.0f); 58 | } 59 | 60 | 61 | void InterpolateLinearInteger::resetRegisters() 62 | { 63 | iFract = 0; 64 | } 65 | 66 | 67 | // Transposes the sample rate of the given samples using linear interpolation. 68 | // 'Mono' version of the routine. Returns the number of samples returned in 69 | // the "dest" buffer 70 | int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) 71 | { 72 | int i; 73 | int srcSampleEnd = srcSamples - 1; 74 | int srcCount = 0; 75 | 76 | i = 0; 77 | while (srcCount < srcSampleEnd) 78 | { 79 | LONG_SAMPLETYPE temp; 80 | 81 | assert(iFract < SCALE); 82 | 83 | temp = (SCALE - iFract) * src[0] + iFract * src[1]; 84 | dest[i] = (SAMPLETYPE)(temp / SCALE); 85 | i++; 86 | 87 | iFract += iRate; 88 | 89 | int iWhole = iFract / SCALE; 90 | iFract -= iWhole * SCALE; 91 | srcCount += iWhole; 92 | src += iWhole; 93 | } 94 | srcSamples = srcCount; 95 | 96 | return i; 97 | } 98 | 99 | 100 | // Transposes the sample rate of the given samples using linear interpolation. 101 | // 'Stereo' version of the routine. Returns the number of samples returned in 102 | // the "dest" buffer 103 | int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) 104 | { 105 | int i; 106 | int srcSampleEnd = srcSamples - 1; 107 | int srcCount = 0; 108 | 109 | i = 0; 110 | while (srcCount < srcSampleEnd) 111 | { 112 | LONG_SAMPLETYPE temp0; 113 | LONG_SAMPLETYPE temp1; 114 | 115 | assert(iFract < SCALE); 116 | 117 | temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; 118 | temp1 = (SCALE - iFract) * src[1] + iFract * src[3]; 119 | dest[0] = (SAMPLETYPE)(temp0 / SCALE); 120 | dest[1] = (SAMPLETYPE)(temp1 / SCALE); 121 | dest += 2; 122 | i++; 123 | 124 | iFract += iRate; 125 | 126 | int iWhole = iFract / SCALE; 127 | iFract -= iWhole * SCALE; 128 | srcCount += iWhole; 129 | src += 2*iWhole; 130 | } 131 | srcSamples = srcCount; 132 | 133 | return i; 134 | } 135 | 136 | 137 | int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) 138 | { 139 | int i; 140 | int srcSampleEnd = srcSamples - 1; 141 | int srcCount = 0; 142 | 143 | i = 0; 144 | while (srcCount < srcSampleEnd) 145 | { 146 | LONG_SAMPLETYPE temp, vol1; 147 | 148 | assert(iFract < SCALE); 149 | vol1 = (SCALE - iFract); 150 | for (int c = 0; c < numChannels; c ++) 151 | { 152 | temp = vol1 * src[c] + iFract * src[c + numChannels]; 153 | dest[0] = (SAMPLETYPE)(temp / SCALE); 154 | dest ++; 155 | } 156 | i++; 157 | 158 | iFract += iRate; 159 | 160 | int iWhole = iFract / SCALE; 161 | iFract -= iWhole * SCALE; 162 | srcCount += iWhole; 163 | src += iWhole * numChannels; 164 | } 165 | srcSamples = srcCount; 166 | 167 | return i; 168 | } 169 | 170 | 171 | // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower 172 | // iRate, larger faster iRates. 173 | void InterpolateLinearInteger::setRate(double newRate) 174 | { 175 | iRate = (int)(newRate * SCALE + 0.5); 176 | TransposerBase::setRate(newRate); 177 | } 178 | 179 | 180 | ////////////////////////////////////////////////////////////////////////////// 181 | // 182 | // InterpolateLinearFloat - floating point arithmetic implementation 183 | // 184 | ////////////////////////////////////////////////////////////////////////////// 185 | 186 | 187 | // Constructor 188 | InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() 189 | { 190 | // Notice: use local function calling syntax for sake of clarity, 191 | // to indicate the fact that C++ constructor can't call virtual functions. 192 | resetRegisters(); 193 | setRate(1.0); 194 | } 195 | 196 | 197 | void InterpolateLinearFloat::resetRegisters() 198 | { 199 | fract = 0; 200 | } 201 | 202 | 203 | // Transposes the sample rate of the given samples using linear interpolation. 204 | // 'Mono' version of the routine. Returns the number of samples returned in 205 | // the "dest" buffer 206 | int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) 207 | { 208 | int i; 209 | int srcSampleEnd = srcSamples - 1; 210 | int srcCount = 0; 211 | 212 | i = 0; 213 | while (srcCount < srcSampleEnd) 214 | { 215 | double out; 216 | assert(fract < 1.0); 217 | 218 | out = (1.0 - fract) * src[0] + fract * src[1]; 219 | dest[i] = (SAMPLETYPE)out; 220 | i ++; 221 | 222 | // update position fraction 223 | fract += rate; 224 | // update whole positions 225 | int whole = (int)fract; 226 | fract -= whole; 227 | src += whole; 228 | srcCount += whole; 229 | } 230 | srcSamples = srcCount; 231 | return i; 232 | } 233 | 234 | 235 | // Transposes the sample rate of the given samples using linear interpolation. 236 | // 'Mono' version of the routine. Returns the number of samples returned in 237 | // the "dest" buffer 238 | int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) 239 | { 240 | int i; 241 | int srcSampleEnd = srcSamples - 1; 242 | int srcCount = 0; 243 | 244 | i = 0; 245 | while (srcCount < srcSampleEnd) 246 | { 247 | double out0, out1; 248 | assert(fract < 1.0); 249 | 250 | out0 = (1.0 - fract) * src[0] + fract * src[2]; 251 | out1 = (1.0 - fract) * src[1] + fract * src[3]; 252 | dest[2*i] = (SAMPLETYPE)out0; 253 | dest[2*i+1] = (SAMPLETYPE)out1; 254 | i ++; 255 | 256 | // update position fraction 257 | fract += rate; 258 | // update whole positions 259 | int whole = (int)fract; 260 | fract -= whole; 261 | src += 2*whole; 262 | srcCount += whole; 263 | } 264 | srcSamples = srcCount; 265 | return i; 266 | } 267 | 268 | 269 | int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) 270 | { 271 | int i; 272 | int srcSampleEnd = srcSamples - 1; 273 | int srcCount = 0; 274 | 275 | i = 0; 276 | while (srcCount < srcSampleEnd) 277 | { 278 | float temp, vol1, fract_float; 279 | 280 | vol1 = (float)(1.0 - fract); 281 | fract_float = (float)fract; 282 | for (int c = 0; c < numChannels; c ++) 283 | { 284 | temp = vol1 * src[c] + fract_float * src[c + numChannels]; 285 | *dest = (SAMPLETYPE)temp; 286 | dest ++; 287 | } 288 | i++; 289 | 290 | fract += rate; 291 | 292 | int iWhole = (int)fract; 293 | fract -= iWhole; 294 | srcCount += iWhole; 295 | src += iWhole * numChannels; 296 | } 297 | srcSamples = srcCount; 298 | 299 | return i; 300 | } 301 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/InterpolateLinear.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Linear interpolation routine. 4 | /// 5 | /// Author : Copyright (c) Olli Parviainen 6 | /// Author e-mail : oparviai 'at' iki.fi 7 | /// SoundTouch WWW: http://www.surina.net/soundtouch 8 | /// 9 | //////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // $Id: InterpolateLinear.h 225 2015-07-26 14:45:48Z oparviai $ 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // License : 16 | // 17 | // SoundTouch audio processing library 18 | // Copyright (c) Olli Parviainen 19 | // 20 | // This library is free software; you can redistribute it and/or 21 | // modify it under the terms of the GNU Lesser General Public 22 | // License as published by the Free Software Foundation; either 23 | // version 2.1 of the License, or (at your option) any later version. 24 | // 25 | // This library is distributed in the hope that it will be useful, 26 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 28 | // Lesser General Public License for more details. 29 | // 30 | // You should have received a copy of the GNU Lesser General Public 31 | // License along with this library; if not, write to the Free Software 32 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33 | // 34 | //////////////////////////////////////////////////////////////////////////////// 35 | 36 | #ifndef _InterpolateLinear_H_ 37 | #define _InterpolateLinear_H_ 38 | 39 | #include "RateTransposer.h" 40 | #include "STTypes.h" 41 | 42 | namespace soundtouch 43 | { 44 | 45 | /// Linear transposer class that uses integer arithmetics 46 | class InterpolateLinearInteger : public TransposerBase 47 | { 48 | protected: 49 | int iFract; 50 | int iRate; 51 | 52 | virtual void resetRegisters(); 53 | 54 | virtual int transposeMono(SAMPLETYPE *dest, 55 | const SAMPLETYPE *src, 56 | int &srcSamples); 57 | virtual int transposeStereo(SAMPLETYPE *dest, 58 | const SAMPLETYPE *src, 59 | int &srcSamples); 60 | virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); 61 | public: 62 | InterpolateLinearInteger(); 63 | 64 | /// Sets new target rate. Normal rate = 1.0, smaller values represent slower 65 | /// rate, larger faster rates. 66 | virtual void setRate(double newRate); 67 | }; 68 | 69 | 70 | /// Linear transposer class that uses floating point arithmetics 71 | class InterpolateLinearFloat : public TransposerBase 72 | { 73 | protected: 74 | double fract; 75 | 76 | virtual void resetRegisters(); 77 | 78 | virtual int transposeMono(SAMPLETYPE *dest, 79 | const SAMPLETYPE *src, 80 | int &srcSamples); 81 | virtual int transposeStereo(SAMPLETYPE *dest, 82 | const SAMPLETYPE *src, 83 | int &srcSamples); 84 | virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); 85 | 86 | public: 87 | InterpolateLinearFloat(); 88 | }; 89 | 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/InterpolateShannon.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Sample interpolation routine using 8-tap band-limited Shannon interpolation 4 | /// with kaiser window. 5 | /// 6 | /// Notice. This algorithm is remarkably much heavier than linear or cubic 7 | /// interpolation, and not remarkably better than cubic algorithm. Thus mostly 8 | /// for experimental purposes 9 | /// 10 | /// Author : Copyright (c) Olli Parviainen 11 | /// Author e-mail : oparviai 'at' iki.fi 12 | /// SoundTouch WWW: http://www.surina.net/soundtouch 13 | /// 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // $Id: InterpolateShannon.cpp 195 2014-04-06 15:57:21Z oparviai $ 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // License : 21 | // 22 | // SoundTouch audio processing library 23 | // Copyright (c) Olli Parviainen 24 | // 25 | // This library is free software; you can redistribute it and/or 26 | // modify it under the terms of the GNU Lesser General Public 27 | // License as published by the Free Software Foundation; either 28 | // version 2.1 of the License, or (at your option) any later version. 29 | // 30 | // This library is distributed in the hope that it will be useful, 31 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 33 | // Lesser General Public License for more details. 34 | // 35 | // You should have received a copy of the GNU Lesser General Public 36 | // License along with this library; if not, write to the Free Software 37 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | 41 | #include 42 | #include "InterpolateShannon.h" 43 | #include "STTypes.h" 44 | 45 | using namespace soundtouch; 46 | 47 | 48 | /// Kaiser window with beta = 2.0 49 | /// Values scaled down by 5% to avoid overflows 50 | static const double _kaiser8[8] = 51 | { 52 | 0.41778693317814, 53 | 0.64888025049173, 54 | 0.83508562409944, 55 | 0.93887857733412, 56 | 0.93887857733412, 57 | 0.83508562409944, 58 | 0.64888025049173, 59 | 0.41778693317814 60 | }; 61 | 62 | 63 | InterpolateShannon::InterpolateShannon() 64 | { 65 | fract = 0; 66 | } 67 | 68 | 69 | void InterpolateShannon::resetRegisters() 70 | { 71 | fract = 0; 72 | } 73 | 74 | 75 | #define PI 3.1415926536 76 | #define sinc(x) (sin(PI * (x)) / (PI * (x))) 77 | 78 | /// Transpose mono audio. Returns number of produced output samples, and 79 | /// updates "srcSamples" to amount of consumed source samples 80 | int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, 81 | const SAMPLETYPE *psrc, 82 | int &srcSamples) 83 | { 84 | int i; 85 | int srcSampleEnd = srcSamples - 8; 86 | int srcCount = 0; 87 | 88 | i = 0; 89 | while (srcCount < srcSampleEnd) 90 | { 91 | double out; 92 | assert(fract < 1.0); 93 | 94 | out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0]; 95 | out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1]; 96 | out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2]; 97 | if (fract < 1e-6) 98 | { 99 | out += psrc[3] * _kaiser8[3]; // sinc(0) = 1 100 | } 101 | else 102 | { 103 | out += psrc[3] * sinc(- fract) * _kaiser8[3]; 104 | } 105 | out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4]; 106 | out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5]; 107 | out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6]; 108 | out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7]; 109 | 110 | pdest[i] = (SAMPLETYPE)out; 111 | i ++; 112 | 113 | // update position fraction 114 | fract += rate; 115 | // update whole positions 116 | int whole = (int)fract; 117 | fract -= whole; 118 | psrc += whole; 119 | srcCount += whole; 120 | } 121 | srcSamples = srcCount; 122 | return i; 123 | } 124 | 125 | 126 | /// Transpose stereo audio. Returns number of produced output samples, and 127 | /// updates "srcSamples" to amount of consumed source samples 128 | int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, 129 | const SAMPLETYPE *psrc, 130 | int &srcSamples) 131 | { 132 | int i; 133 | int srcSampleEnd = srcSamples - 8; 134 | int srcCount = 0; 135 | 136 | i = 0; 137 | while (srcCount < srcSampleEnd) 138 | { 139 | double out0, out1, w; 140 | assert(fract < 1.0); 141 | 142 | w = sinc(-3.0 - fract) * _kaiser8[0]; 143 | out0 = psrc[0] * w; out1 = psrc[1] * w; 144 | w = sinc(-2.0 - fract) * _kaiser8[1]; 145 | out0 += psrc[2] * w; out1 += psrc[3] * w; 146 | w = sinc(-1.0 - fract) * _kaiser8[2]; 147 | out0 += psrc[4] * w; out1 += psrc[5] * w; 148 | w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1 149 | out0 += psrc[6] * w; out1 += psrc[7] * w; 150 | w = sinc( 1.0 - fract) * _kaiser8[4]; 151 | out0 += psrc[8] * w; out1 += psrc[9] * w; 152 | w = sinc( 2.0 - fract) * _kaiser8[5]; 153 | out0 += psrc[10] * w; out1 += psrc[11] * w; 154 | w = sinc( 3.0 - fract) * _kaiser8[6]; 155 | out0 += psrc[12] * w; out1 += psrc[13] * w; 156 | w = sinc( 4.0 - fract) * _kaiser8[7]; 157 | out0 += psrc[14] * w; out1 += psrc[15] * w; 158 | 159 | pdest[2*i] = (SAMPLETYPE)out0; 160 | pdest[2*i+1] = (SAMPLETYPE)out1; 161 | i ++; 162 | 163 | // update position fraction 164 | fract += rate; 165 | // update whole positions 166 | int whole = (int)fract; 167 | fract -= whole; 168 | psrc += 2*whole; 169 | srcCount += whole; 170 | } 171 | srcSamples = srcCount; 172 | return i; 173 | } 174 | 175 | 176 | /// Transpose stereo audio. Returns number of produced output samples, and 177 | /// updates "srcSamples" to amount of consumed source samples 178 | int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, 179 | const SAMPLETYPE *psrc, 180 | int &srcSamples) 181 | { 182 | // not implemented 183 | assert(false); 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/InterpolateShannon.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Sample interpolation routine using 8-tap band-limited Shannon interpolation 4 | /// with kaiser window. 5 | /// 6 | /// Notice. This algorithm is remarkably much heavier than linear or cubic 7 | /// interpolation, and not remarkably better than cubic algorithm. Thus mostly 8 | /// for experimental purposes 9 | /// 10 | /// Author : Copyright (c) Olli Parviainen 11 | /// Author e-mail : oparviai 'at' iki.fi 12 | /// SoundTouch WWW: http://www.surina.net/soundtouch 13 | /// 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // $Id: InterpolateShannon.h 225 2015-07-26 14:45:48Z oparviai $ 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // License : 21 | // 22 | // SoundTouch audio processing library 23 | // Copyright (c) Olli Parviainen 24 | // 25 | // This library is free software; you can redistribute it and/or 26 | // modify it under the terms of the GNU Lesser General Public 27 | // License as published by the Free Software Foundation; either 28 | // version 2.1 of the License, or (at your option) any later version. 29 | // 30 | // This library is distributed in the hope that it will be useful, 31 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 33 | // Lesser General Public License for more details. 34 | // 35 | // You should have received a copy of the GNU Lesser General Public 36 | // License along with this library; if not, write to the Free Software 37 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | 41 | #ifndef _InterpolateShannon_H_ 42 | #define _InterpolateShannon_H_ 43 | 44 | #include "RateTransposer.h" 45 | #include "STTypes.h" 46 | 47 | namespace soundtouch 48 | { 49 | 50 | class InterpolateShannon : public TransposerBase 51 | { 52 | protected: 53 | void resetRegisters(); 54 | int transposeMono(SAMPLETYPE *dest, 55 | const SAMPLETYPE *src, 56 | int &srcSamples); 57 | int transposeStereo(SAMPLETYPE *dest, 58 | const SAMPLETYPE *src, 59 | int &srcSamples); 60 | int transposeMulti(SAMPLETYPE *dest, 61 | const SAMPLETYPE *src, 62 | int &srcSamples); 63 | 64 | double fract; 65 | 66 | public: 67 | InterpolateShannon(); 68 | }; 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/PeakFinder.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/cpp/SoundTouch/PeakFinder.cpp -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/PeakFinder.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// The routine detects highest value on an array of values and calculates the 4 | /// precise peak location as a mass-center of the 'hump' around the peak value. 5 | /// 6 | /// Author : Copyright (c) Olli Parviainen 7 | /// Author e-mail : oparviai 'at' iki.fi 8 | /// SoundTouch WWW: http://www.surina.net/soundtouch 9 | /// 10 | //////////////////////////////////////////////////////////////////////////////// 11 | // 12 | // Last changed : $Date: 2011-12-30 22:33:46 +0200 (Fri, 30 Dec 2011) $ 13 | // File revision : $Revision: 4 $ 14 | // 15 | // $Id: PeakFinder.h 132 2011-12-30 20:33:46Z oparviai $ 16 | // 17 | //////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // License : 20 | // 21 | // SoundTouch audio processing library 22 | // Copyright (c) Olli Parviainen 23 | // 24 | // This library is free software; you can redistribute it and/or 25 | // modify it under the terms of the GNU Lesser General Public 26 | // License as published by the Free Software Foundation; either 27 | // version 2.1 of the License, or (at your option) any later version. 28 | // 29 | // This library is distributed in the hope that it will be useful, 30 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 31 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 | // Lesser General Public License for more details. 33 | // 34 | // You should have received a copy of the GNU Lesser General Public 35 | // License along with this library; if not, write to the Free Software 36 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 37 | // 38 | //////////////////////////////////////////////////////////////////////////////// 39 | 40 | #ifndef _PeakFinder_H_ 41 | #define _PeakFinder_H_ 42 | 43 | namespace soundtouch 44 | { 45 | 46 | class PeakFinder 47 | { 48 | protected: 49 | /// Min, max allowed peak positions within the data vector 50 | int minPos, maxPos; 51 | 52 | /// Calculates the mass center between given vector items. 53 | double calcMassCenter(const float *data, ///< Data vector. 54 | int firstPos, ///< Index of first vector item beloging to the peak. 55 | int lastPos ///< Index of last vector item beloging to the peak. 56 | ) const; 57 | 58 | /// Finds the data vector index where the monotoniously decreasing signal crosses the 59 | /// given level. 60 | int findCrossingLevel(const float *data, ///< Data vector. 61 | float level, ///< Goal crossing level. 62 | int peakpos, ///< Peak position index within the data vector. 63 | int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. 64 | ) const; 65 | 66 | // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. 67 | int findTop(const float *data, int peakpos) const; 68 | 69 | 70 | /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- 71 | /// or left-hand side of the given peak position. 72 | int findGround(const float *data, /// Data vector. 73 | int peakpos, /// Peak position index within the data vector. 74 | int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. 75 | ) const; 76 | 77 | /// get exact center of peak near given position by calculating local mass of center 78 | double getPeakCenter(const float *data, int peakpos) const; 79 | 80 | public: 81 | /// Constructor. 82 | PeakFinder(); 83 | 84 | /// Detect exact peak position of the data vector by finding the largest peak 'hump' 85 | /// and calculating the mass-center location of the peak hump. 86 | /// 87 | /// \return The location of the largest base harmonic peak hump. 88 | double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has 89 | /// to be at least 'maxPos' items long. 90 | int minPos, ///< Min allowed peak location within the vector data. 91 | int maxPos ///< Max allowed peak location within the vector data. 92 | ); 93 | }; 94 | 95 | } 96 | 97 | #endif // _PeakFinder_H_ 98 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/RateTransposer.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Sample rate transposer. Changes sample rate by using linear interpolation 4 | /// together with anti-alias filtering (first order interpolation with anti- 5 | /// alias filtering should be quite adequate for this application) 6 | /// 7 | /// Author : Copyright (c) Olli Parviainen 8 | /// Author e-mail : oparviai 'at' iki.fi 9 | /// SoundTouch WWW: http://www.surina.net/soundtouch 10 | /// 11 | //////////////////////////////////////////////////////////////////////////////// 12 | // 13 | // Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ 14 | // File revision : $Revision: 4 $ 15 | // 16 | // $Id: RateTransposer.cpp 225 2015-07-26 14:45:48Z oparviai $ 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // License : 21 | // 22 | // SoundTouch audio processing library 23 | // Copyright (c) Olli Parviainen 24 | // 25 | // This library is free software; you can redistribute it and/or 26 | // modify it under the terms of the GNU Lesser General Public 27 | // License as published by the Free Software Foundation; either 28 | // version 2.1 of the License, or (at your option) any later version. 29 | // 30 | // This library is distributed in the hope that it will be useful, 31 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 32 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 33 | // Lesser General Public License for more details. 34 | // 35 | // You should have received a copy of the GNU Lesser General Public 36 | // License along with this library; if not, write to the Free Software 37 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 38 | // 39 | //////////////////////////////////////////////////////////////////////////////// 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include "RateTransposer.h" 46 | #include "InterpolateLinear.h" 47 | #include "InterpolateCubic.h" 48 | #include "InterpolateShannon.h" 49 | #include "AAFilter.h" 50 | 51 | using namespace soundtouch; 52 | 53 | // Define default interpolation algorithm here 54 | TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC; 55 | 56 | 57 | // Constructor 58 | RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) 59 | { 60 | bUseAAFilter = true; 61 | 62 | // Instantiates the anti-alias filter 63 | pAAFilter = new AAFilter(64); 64 | pTransposer = TransposerBase::newInstance(); 65 | } 66 | 67 | 68 | 69 | RateTransposer::~RateTransposer() 70 | { 71 | delete pAAFilter; 72 | delete pTransposer; 73 | } 74 | 75 | 76 | 77 | /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable 78 | void RateTransposer::enableAAFilter(bool newMode) 79 | { 80 | bUseAAFilter = newMode; 81 | } 82 | 83 | 84 | /// Returns nonzero if anti-alias filter is enabled. 85 | bool RateTransposer::isAAFilterEnabled() const 86 | { 87 | return bUseAAFilter; 88 | } 89 | 90 | 91 | AAFilter *RateTransposer::getAAFilter() 92 | { 93 | return pAAFilter; 94 | } 95 | 96 | 97 | 98 | // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower 99 | // iRate, larger faster iRates. 100 | void RateTransposer::setRate(double newRate) 101 | { 102 | double fCutoff; 103 | 104 | pTransposer->setRate(newRate); 105 | 106 | // design a new anti-alias filter 107 | if (newRate > 1.0) 108 | { 109 | fCutoff = 0.5 / newRate; 110 | } 111 | else 112 | { 113 | fCutoff = 0.5 * newRate; 114 | } 115 | pAAFilter->setCutoffFreq(fCutoff); 116 | } 117 | 118 | 119 | // Adds 'nSamples' pcs of samples from the 'samples' memory position into 120 | // the input of the object. 121 | void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples) 122 | { 123 | processSamples(samples, nSamples); 124 | } 125 | 126 | 127 | // Transposes sample rate by applying anti-alias filter to prevent folding. 128 | // Returns amount of samples returned in the "dest" buffer. 129 | // The maximum amount of samples that can be returned at a time is set by 130 | // the 'set_returnBuffer_size' function. 131 | void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) 132 | { 133 | uint count; 134 | 135 | if (nSamples == 0) return; 136 | 137 | // Store samples to input buffer 138 | inputBuffer.putSamples(src, nSamples); 139 | 140 | // If anti-alias filter is turned off, simply transpose without applying 141 | // the filter 142 | if (bUseAAFilter == false) 143 | { 144 | count = pTransposer->transpose(outputBuffer, inputBuffer); 145 | return; 146 | } 147 | 148 | assert(pAAFilter); 149 | 150 | // Transpose with anti-alias filter 151 | if (pTransposer->rate < 1.0f) 152 | { 153 | // If the parameter 'Rate' value is smaller than 1, first transpose 154 | // the samples and then apply the anti-alias filter to remove aliasing. 155 | 156 | // Transpose the samples, store the result to end of "midBuffer" 157 | pTransposer->transpose(midBuffer, inputBuffer); 158 | 159 | // Apply the anti-alias filter for transposed samples in midBuffer 160 | pAAFilter->evaluate(outputBuffer, midBuffer); 161 | } 162 | else 163 | { 164 | // If the parameter 'Rate' value is larger than 1, first apply the 165 | // anti-alias filter to remove high frequencies (prevent them from folding 166 | // over the lover frequencies), then transpose. 167 | 168 | // Apply the anti-alias filter for samples in inputBuffer 169 | pAAFilter->evaluate(midBuffer, inputBuffer); 170 | 171 | // Transpose the AA-filtered samples in "midBuffer" 172 | pTransposer->transpose(outputBuffer, midBuffer); 173 | } 174 | } 175 | 176 | 177 | // Sets the number of channels, 1 = mono, 2 = stereo 178 | void RateTransposer::setChannels(int nChannels) 179 | { 180 | assert(nChannels > 0); 181 | 182 | if (pTransposer->numChannels == nChannels) return; 183 | pTransposer->setChannels(nChannels); 184 | 185 | inputBuffer.setChannels(nChannels); 186 | midBuffer.setChannels(nChannels); 187 | outputBuffer.setChannels(nChannels); 188 | } 189 | 190 | 191 | // Clears all the samples in the object 192 | void RateTransposer::clear() 193 | { 194 | outputBuffer.clear(); 195 | midBuffer.clear(); 196 | inputBuffer.clear(); 197 | } 198 | 199 | 200 | // Returns nonzero if there aren't any samples available for outputting. 201 | int RateTransposer::isEmpty() const 202 | { 203 | int res; 204 | 205 | res = FIFOProcessor::isEmpty(); 206 | if (res == 0) return 0; 207 | return inputBuffer.isEmpty(); 208 | } 209 | 210 | 211 | ////////////////////////////////////////////////////////////////////////////// 212 | // 213 | // TransposerBase - Base class for interpolation 214 | // 215 | 216 | // static function to set interpolation algorithm 217 | void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a) 218 | { 219 | TransposerBase::algorithm = a; 220 | } 221 | 222 | 223 | // Transposes the sample rate of the given samples using linear interpolation. 224 | // Returns the number of samples returned in the "dest" buffer 225 | int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) 226 | { 227 | int numSrcSamples = src.numSamples(); 228 | int sizeDemand = (int)((double)numSrcSamples / rate) + 8; 229 | int numOutput; 230 | SAMPLETYPE *psrc = src.ptrBegin(); 231 | SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand); 232 | 233 | #ifndef USE_MULTICH_ALWAYS 234 | if (numChannels == 1) 235 | { 236 | numOutput = transposeMono(pdest, psrc, numSrcSamples); 237 | } 238 | else if (numChannels == 2) 239 | { 240 | numOutput = transposeStereo(pdest, psrc, numSrcSamples); 241 | } 242 | else 243 | #endif // USE_MULTICH_ALWAYS 244 | { 245 | assert(numChannels > 0); 246 | numOutput = transposeMulti(pdest, psrc, numSrcSamples); 247 | } 248 | dest.putSamples(numOutput); 249 | src.receiveSamples(numSrcSamples); 250 | return numOutput; 251 | } 252 | 253 | 254 | TransposerBase::TransposerBase() 255 | { 256 | numChannels = 0; 257 | rate = 1.0f; 258 | } 259 | 260 | 261 | TransposerBase::~TransposerBase() 262 | { 263 | } 264 | 265 | 266 | void TransposerBase::setChannels(int channels) 267 | { 268 | numChannels = channels; 269 | resetRegisters(); 270 | } 271 | 272 | 273 | void TransposerBase::setRate(double newRate) 274 | { 275 | rate = newRate; 276 | } 277 | 278 | 279 | // static factory function 280 | TransposerBase *TransposerBase::newInstance() 281 | { 282 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 283 | // Notice: For integer arithmetics support only linear algorithm (due to simplest calculus) 284 | return ::new InterpolateLinearInteger; 285 | #else 286 | switch (algorithm) 287 | { 288 | case LINEAR: 289 | return new InterpolateLinearFloat; 290 | 291 | case CUBIC: 292 | return new InterpolateCubic; 293 | 294 | case SHANNON: 295 | return new InterpolateShannon; 296 | 297 | default: 298 | assert(false); 299 | return NULL; 300 | } 301 | #endif 302 | } 303 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/RateTransposer.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Sample rate transposer. Changes sample rate by using linear interpolation 4 | /// together with anti-alias filtering (first order interpolation with anti- 5 | /// alias filtering should be quite adequate for this application). 6 | /// 7 | /// Use either of the derived classes of 'RateTransposerInteger' or 8 | /// 'RateTransposerFloat' for corresponding integer/floating point tranposing 9 | /// algorithm implementation. 10 | /// 11 | /// Author : Copyright (c) Olli Parviainen 12 | /// Author e-mail : oparviai 'at' iki.fi 13 | /// SoundTouch WWW: http://www.surina.net/soundtouch 14 | /// 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // 17 | // Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ 18 | // File revision : $Revision: 4 $ 19 | // 20 | // $Id: RateTransposer.h 225 2015-07-26 14:45:48Z oparviai $ 21 | // 22 | //////////////////////////////////////////////////////////////////////////////// 23 | // 24 | // License : 25 | // 26 | // SoundTouch audio processing library 27 | // Copyright (c) Olli Parviainen 28 | // 29 | // This library is free software; you can redistribute it and/or 30 | // modify it under the terms of the GNU Lesser General Public 31 | // License as published by the Free Software Foundation; either 32 | // version 2.1 of the License, or (at your option) any later version. 33 | // 34 | // This library is distributed in the hope that it will be useful, 35 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 37 | // Lesser General Public License for more details. 38 | // 39 | // You should have received a copy of the GNU Lesser General Public 40 | // License along with this library; if not, write to the Free Software 41 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 42 | // 43 | //////////////////////////////////////////////////////////////////////////////// 44 | 45 | #ifndef RateTransposer_H 46 | #define RateTransposer_H 47 | 48 | #include 49 | #include "AAFilter.h" 50 | #include "FIFOSamplePipe.h" 51 | #include "FIFOSampleBuffer.h" 52 | 53 | #include "STTypes.h" 54 | 55 | namespace soundtouch 56 | { 57 | 58 | /// Abstract base class for transposer implementations (linear, advanced vs integer, float etc) 59 | class TransposerBase 60 | { 61 | public: 62 | enum ALGORITHM { 63 | LINEAR = 0, 64 | CUBIC, 65 | SHANNON 66 | }; 67 | 68 | protected: 69 | virtual void resetRegisters() = 0; 70 | 71 | virtual int transposeMono(SAMPLETYPE *dest, 72 | const SAMPLETYPE *src, 73 | int &srcSamples) = 0; 74 | virtual int transposeStereo(SAMPLETYPE *dest, 75 | const SAMPLETYPE *src, 76 | int &srcSamples) = 0; 77 | virtual int transposeMulti(SAMPLETYPE *dest, 78 | const SAMPLETYPE *src, 79 | int &srcSamples) = 0; 80 | 81 | static ALGORITHM algorithm; 82 | 83 | public: 84 | double rate; 85 | int numChannels; 86 | 87 | TransposerBase(); 88 | virtual ~TransposerBase(); 89 | 90 | virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src); 91 | virtual void setRate(double newRate); 92 | virtual void setChannels(int channels); 93 | 94 | // static factory function 95 | static TransposerBase *newInstance(); 96 | 97 | // static function to set interpolation algorithm 98 | static void setAlgorithm(ALGORITHM a); 99 | }; 100 | 101 | 102 | /// A common linear samplerate transposer class. 103 | /// 104 | class RateTransposer : public FIFOProcessor 105 | { 106 | protected: 107 | /// Anti-alias filter object 108 | AAFilter *pAAFilter; 109 | TransposerBase *pTransposer; 110 | 111 | /// Buffer for collecting samples to feed the anti-alias filter between 112 | /// two batches 113 | FIFOSampleBuffer inputBuffer; 114 | 115 | /// Buffer for keeping samples between transposing & anti-alias filter 116 | FIFOSampleBuffer midBuffer; 117 | 118 | /// Output sample buffer 119 | FIFOSampleBuffer outputBuffer; 120 | 121 | bool bUseAAFilter; 122 | 123 | 124 | /// Transposes sample rate by applying anti-alias filter to prevent folding. 125 | /// Returns amount of samples returned in the "dest" buffer. 126 | /// The maximum amount of samples that can be returned at a time is set by 127 | /// the 'set_returnBuffer_size' function. 128 | void processSamples(const SAMPLETYPE *src, 129 | uint numSamples); 130 | 131 | public: 132 | RateTransposer(); 133 | virtual ~RateTransposer(); 134 | 135 | /// Operator 'new' is overloaded so that it automatically creates a suitable instance 136 | /// depending on if we're to use integer or floating point arithmetics. 137 | // static void *operator new(size_t s); 138 | 139 | /// Use this function instead of "new" operator to create a new instance of this class. 140 | /// This function automatically chooses a correct implementation, depending on if 141 | /// integer ot floating point arithmetics are to be used. 142 | // static RateTransposer *newInstance(); 143 | 144 | /// Returns the output buffer object 145 | FIFOSamplePipe *getOutput() { return &outputBuffer; }; 146 | 147 | /// Returns the store buffer object 148 | // FIFOSamplePipe *getStore() { return &storeBuffer; }; 149 | 150 | /// Return anti-alias filter object 151 | AAFilter *getAAFilter(); 152 | 153 | /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable 154 | void enableAAFilter(bool newMode); 155 | 156 | /// Returns nonzero if anti-alias filter is enabled. 157 | bool isAAFilterEnabled() const; 158 | 159 | /// Sets new target rate. Normal rate = 1.0, smaller values represent slower 160 | /// rate, larger faster rates. 161 | virtual void setRate(double newRate); 162 | 163 | /// Sets the number of channels, 1 = mono, 2 = stereo 164 | void setChannels(int channels); 165 | 166 | /// Adds 'numSamples' pcs of samples from the 'samples' memory position into 167 | /// the input of the object. 168 | void putSamples(const SAMPLETYPE *samples, uint numSamples); 169 | 170 | /// Clears all the samples in the object 171 | void clear(); 172 | 173 | /// Returns nonzero if there aren't any samples available for outputting. 174 | int isEmpty() const; 175 | }; 176 | 177 | } 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/TDStretch.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo 4 | /// while maintaining the original pitch by using a time domain WSOLA-like method 5 | /// with several performance-increasing tweaks. 6 | /// 7 | /// Note : MMX/SSE optimized functions reside in separate, platform-specific files 8 | /// 'mmx_optimized.cpp' and 'sse_optimized.cpp' 9 | /// 10 | /// Author : Copyright (c) Olli Parviainen 11 | /// Author e-mail : oparviai 'at' iki.fi 12 | /// SoundTouch WWW: http://www.surina.net/soundtouch 13 | /// 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ 17 | // File revision : $Revision: 4 $ 18 | // 19 | // $Id: TDStretch.h 226 2015-08-08 21:00:15Z oparviai $ 20 | // 21 | //////////////////////////////////////////////////////////////////////////////// 22 | // 23 | // License : 24 | // 25 | // SoundTouch audio processing library 26 | // Copyright (c) Olli Parviainen 27 | // 28 | // This library is free software; you can redistribute it and/or 29 | // modify it under the terms of the GNU Lesser General Public 30 | // License as published by the Free Software Foundation; either 31 | // version 2.1 of the License, or (at your option) any later version. 32 | // 33 | // This library is distributed in the hope that it will be useful, 34 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 36 | // Lesser General Public License for more details. 37 | // 38 | // You should have received a copy of the GNU Lesser General Public 39 | // License along with this library; if not, write to the Free Software 40 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 41 | // 42 | //////////////////////////////////////////////////////////////////////////////// 43 | 44 | #ifndef TDStretch_H 45 | #define TDStretch_H 46 | 47 | #include 48 | #include "STTypes.h" 49 | #include "RateTransposer.h" 50 | #include "FIFOSamplePipe.h" 51 | 52 | namespace soundtouch 53 | { 54 | 55 | /// Default values for sound processing parameters: 56 | /// Notice that the default parameters are tuned for contemporary popular music 57 | /// processing. For speech processing applications these parameters suit better: 58 | /// #define DEFAULT_SEQUENCE_MS 40 59 | /// #define DEFAULT_SEEKWINDOW_MS 15 60 | /// #define DEFAULT_OVERLAP_MS 8 61 | /// 62 | 63 | /// Default length of a single processing sequence, in milliseconds. This determines to how 64 | /// long sequences the original sound is chopped in the time-stretch algorithm. 65 | /// 66 | /// The larger this value is, the lesser sequences are used in processing. In principle 67 | /// a bigger value sounds better when slowing down tempo, but worse when increasing tempo 68 | /// and vice versa. 69 | /// 70 | /// Increasing this value reduces computational burden & vice versa. 71 | //#define DEFAULT_SEQUENCE_MS 40 72 | #define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN 73 | 74 | /// Giving this value for the sequence length sets automatic parameter value 75 | /// according to tempo setting (recommended) 76 | #define USE_AUTO_SEQUENCE_LEN 0 77 | 78 | /// Seeking window default length in milliseconds for algorithm that finds the best possible 79 | /// overlapping location. This determines from how wide window the algorithm may look for an 80 | /// optimal joining location when mixing the sound sequences back together. 81 | /// 82 | /// The bigger this window setting is, the higher the possibility to find a better mixing 83 | /// position will become, but at the same time large values may cause a "drifting" artifact 84 | /// because consequent sequences will be taken at more uneven intervals. 85 | /// 86 | /// If there's a disturbing artifact that sounds as if a constant frequency was drifting 87 | /// around, try reducing this setting. 88 | /// 89 | /// Increasing this value increases computational burden & vice versa. 90 | //#define DEFAULT_SEEKWINDOW_MS 15 91 | #define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN 92 | 93 | /// Giving this value for the seek window length sets automatic parameter value 94 | /// according to tempo setting (recommended) 95 | #define USE_AUTO_SEEKWINDOW_LEN 0 96 | 97 | /// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, 98 | /// to form a continuous sound stream, this parameter defines over how long period the two 99 | /// consecutive sequences are let to overlap each other. 100 | /// 101 | /// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting 102 | /// by a large amount, you might wish to try a smaller value on this. 103 | /// 104 | /// Increasing this value increases computational burden & vice versa. 105 | #define DEFAULT_OVERLAP_MS 8 106 | 107 | 108 | /// Class that does the time-stretch (tempo change) effect for the processed 109 | /// sound. 110 | class TDStretch : public FIFOProcessor 111 | { 112 | protected: 113 | int channels; 114 | int sampleReq; 115 | 116 | int overlapLength; 117 | int seekLength; 118 | int seekWindowLength; 119 | int overlapDividerBitsNorm; 120 | int overlapDividerBitsPure; 121 | int slopingDivider; 122 | int sampleRate; 123 | int sequenceMs; 124 | int seekWindowMs; 125 | int overlapMs; 126 | 127 | unsigned long maxnorm; 128 | float maxnormf; 129 | 130 | double tempo; 131 | double nominalSkip; 132 | double skipFract; 133 | 134 | bool bQuickSeek; 135 | bool bAutoSeqSetting; 136 | bool bAutoSeekSetting; 137 | 138 | SAMPLETYPE *pMidBuffer; 139 | SAMPLETYPE *pMidBufferUnaligned; 140 | 141 | FIFOSampleBuffer outputBuffer; 142 | FIFOSampleBuffer inputBuffer; 143 | 144 | void acceptNewOverlapLength(int newOverlapLength); 145 | 146 | virtual void clearCrossCorrState(); 147 | void calculateOverlapLength(int overlapMs); 148 | 149 | virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); 150 | virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); 151 | 152 | virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos); 153 | virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); 154 | virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos); 155 | 156 | virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; 157 | virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; 158 | virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const; 159 | 160 | void clearMidBuffer(); 161 | void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; 162 | 163 | void calcSeqParameters(); 164 | void adaptNormalizer(); 165 | 166 | 167 | /// Changes the tempo of the given sound samples. 168 | /// Returns amount of samples returned in the "output" buffer. 169 | /// The maximum amount of samples that can be returned at a time is set by 170 | /// the 'set_returnBuffer_size' function. 171 | void processSamples(); 172 | 173 | public: 174 | TDStretch(); 175 | virtual ~TDStretch(); 176 | 177 | /// Operator 'new' is overloaded so that it automatically creates a suitable instance 178 | /// depending on if we've a MMX/SSE/etc-capable CPU available or not. 179 | static void *operator new(size_t s); 180 | 181 | /// Use this function instead of "new" operator to create a new instance of this class. 182 | /// This function automatically chooses a correct feature set depending on if the CPU 183 | /// supports MMX/SSE/etc extensions. 184 | static TDStretch *newInstance(); 185 | 186 | /// Returns the output buffer object 187 | FIFOSamplePipe *getOutput() { return &outputBuffer; }; 188 | 189 | /// Returns the input buffer object 190 | FIFOSamplePipe *getInput() { return &inputBuffer; }; 191 | 192 | /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower 193 | /// tempo, larger faster tempo. 194 | void setTempo(double newTempo); 195 | 196 | /// Returns nonzero if there aren't any samples available for outputting. 197 | virtual void clear(); 198 | 199 | /// Clears the input buffer 200 | void clearInput(); 201 | 202 | /// Sets the number of channels, 1 = mono, 2 = stereo 203 | void setChannels(int numChannels); 204 | 205 | /// Enables/disables the quick position seeking algorithm. Zero to disable, 206 | /// nonzero to enable 207 | void enableQuickSeek(bool enable); 208 | 209 | /// Returns nonzero if the quick seeking algorithm is enabled. 210 | bool isQuickSeekEnabled() const; 211 | 212 | /// Sets routine control parameters. These control are certain time constants 213 | /// defining how the sound is stretched to the desired duration. 214 | // 215 | /// 'sampleRate' = sample rate of the sound 216 | /// 'sequenceMS' = one processing sequence length in milliseconds 217 | /// 'seekwindowMS' = seeking window length for scanning the best overlapping 218 | /// position 219 | /// 'overlapMS' = overlapping length 220 | void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz) 221 | int sequenceMS = -1, ///< Single processing sequence length (ms) 222 | int seekwindowMS = -1, ///< Offset seeking window length (ms) 223 | int overlapMS = -1 ///< Sequence overlapping length (ms) 224 | ); 225 | 226 | /// Get routine control parameters, see setParameters() function. 227 | /// Any of the parameters to this function can be NULL, in such case corresponding parameter 228 | /// value isn't returned. 229 | void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const; 230 | 231 | /// Adds 'numsamples' pcs of samples from the 'samples' memory position into 232 | /// the input of the object. 233 | virtual void putSamples( 234 | const SAMPLETYPE *samples, ///< Input sample data 235 | uint numSamples ///< Number of samples in 'samples' so that one sample 236 | ///< contains both channels if stereo 237 | ); 238 | 239 | /// return nominal input sample requirement for triggering a processing batch 240 | int getInputSampleReq() const 241 | { 242 | return (int)(nominalSkip + 0.5); 243 | } 244 | 245 | /// return nominal output sample amount when running a processing batch 246 | int getOutputBatchSize() const 247 | { 248 | return seekWindowLength - overlapLength; 249 | } 250 | }; 251 | 252 | 253 | 254 | // Implementation-specific class declarations: 255 | 256 | #ifdef SOUNDTOUCH_ALLOW_MMX 257 | /// Class that implements MMX optimized routines for 16bit integer samples type. 258 | class TDStretchMMX : public TDStretch 259 | { 260 | protected: 261 | double calcCrossCorr(const short *mixingPos, const short *compare, double &norm); 262 | double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm); 263 | virtual void overlapStereo(short *output, const short *input) const; 264 | virtual void clearCrossCorrState(); 265 | }; 266 | #endif /// SOUNDTOUCH_ALLOW_MMX 267 | 268 | 269 | #ifdef SOUNDTOUCH_ALLOW_SSE 270 | /// Class that implements SSE optimized routines for floating point samples type. 271 | class TDStretchSSE : public TDStretch 272 | { 273 | protected: 274 | double calcCrossCorr(const float *mixingPos, const float *compare, double &norm); 275 | double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm); 276 | }; 277 | 278 | #endif /// SOUNDTOUCH_ALLOW_SSE 279 | 280 | } 281 | #endif /// TDStretch_H 282 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/cpu_detect.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// A header file for detecting the Intel MMX instructions set extension. 4 | /// 5 | /// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the 6 | /// routine implementations for x86 Windows, x86 gnu version and non-x86 7 | /// platforms, respectively. 8 | /// 9 | /// Author : Copyright (c) Olli Parviainen 10 | /// Author e-mail : oparviai 'at' iki.fi 11 | /// SoundTouch WWW: http://www.surina.net/soundtouch 12 | /// 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ 16 | // File revision : $Revision: 4 $ 17 | // 18 | // $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $ 19 | // 20 | //////////////////////////////////////////////////////////////////////////////// 21 | // 22 | // License : 23 | // 24 | // SoundTouch audio processing library 25 | // Copyright (c) Olli Parviainen 26 | // 27 | // This library is free software; you can redistribute it and/or 28 | // modify it under the terms of the GNU Lesser General Public 29 | // License as published by the Free Software Foundation; either 30 | // version 2.1 of the License, or (at your option) any later version. 31 | // 32 | // This library is distributed in the hope that it will be useful, 33 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 34 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 35 | // Lesser General Public License for more details. 36 | // 37 | // You should have received a copy of the GNU Lesser General Public 38 | // License along with this library; if not, write to the Free Software 39 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 40 | // 41 | //////////////////////////////////////////////////////////////////////////////// 42 | 43 | #ifndef _CPU_DETECT_H_ 44 | #define _CPU_DETECT_H_ 45 | 46 | #include "STTypes.h" 47 | 48 | #define SUPPORT_MMX 0x0001 49 | #define SUPPORT_3DNOW 0x0002 50 | #define SUPPORT_ALTIVEC 0x0004 51 | #define SUPPORT_SSE 0x0008 52 | #define SUPPORT_SSE2 0x0010 53 | 54 | /// Checks which instruction set extensions are supported by the CPU. 55 | /// 56 | /// \return A bitmask of supported extensions, see SUPPORT_... defines. 57 | uint detectCPUextensions(void); 58 | 59 | /// Disables given set of instruction extensions. See SUPPORT_... defines. 60 | void disableExtensions(uint wDisableMask); 61 | 62 | #endif // _CPU_DETECT_H_ 63 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/cpu_detect_x86.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Generic version of the x86 CPU extension detection routine. 4 | /// 5 | /// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' 6 | /// for the Microsoft compiler version. 7 | /// 8 | /// Author : Copyright (c) Olli Parviainen 9 | /// Author e-mail : oparviai 'at' iki.fi 10 | /// SoundTouch WWW: http://www.surina.net/soundtouch 11 | /// 12 | //////////////////////////////////////////////////////////////////////////////// 13 | // 14 | // Last changed : $Date: 2014-01-07 20:24:28 +0200 (Tue, 07 Jan 2014) $ 15 | // File revision : $Revision: 4 $ 16 | // 17 | // $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $ 18 | // 19 | //////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // License : 22 | // 23 | // SoundTouch audio processing library 24 | // Copyright (c) Olli Parviainen 25 | // 26 | // This library is free software; you can redistribute it and/or 27 | // modify it under the terms of the GNU Lesser General Public 28 | // License as published by the Free Software Foundation; either 29 | // version 2.1 of the License, or (at your option) any later version. 30 | // 31 | // This library is distributed in the hope that it will be useful, 32 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 34 | // Lesser General Public License for more details. 35 | // 36 | // You should have received a copy of the GNU Lesser General Public 37 | // License along with this library; if not, write to the Free Software 38 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 39 | // 40 | //////////////////////////////////////////////////////////////////////////////// 41 | 42 | #include "cpu_detect.h" 43 | #include "STTypes.h" 44 | 45 | 46 | #if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) 47 | 48 | #if defined(__GNUC__) && defined(__i386__) 49 | // gcc 50 | #include "cpuid.h" 51 | #elif defined(_M_IX86) 52 | // windows non-gcc 53 | #include 54 | #endif 55 | 56 | #define bit_MMX (1 << 23) 57 | #define bit_SSE (1 << 25) 58 | #define bit_SSE2 (1 << 26) 59 | #endif 60 | 61 | 62 | ////////////////////////////////////////////////////////////////////////////// 63 | // 64 | // processor instructions extension detection routines 65 | // 66 | ////////////////////////////////////////////////////////////////////////////// 67 | 68 | // Flag variable indicating whick ISA extensions are disabled (for debugging) 69 | static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions 70 | 71 | // Disables given set of instruction extensions. See SUPPORT_... defines. 72 | void disableExtensions(uint dwDisableMask) 73 | { 74 | _dwDisabledISA = dwDisableMask; 75 | } 76 | 77 | 78 | 79 | /// Checks which instruction set extensions are supported by the CPU. 80 | uint detectCPUextensions(void) 81 | { 82 | /// If building for a 64bit system (no Itanium) and the user wants optimizations. 83 | /// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19. 84 | /// Keep the _dwDisabledISA test (2 more operations, could be eliminated). 85 | #if ((defined(__GNUC__) && defined(__x86_64__)) \ 86 | || defined(_M_X64)) \ 87 | && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) 88 | return 0x19 & ~_dwDisabledISA; 89 | 90 | /// If building for a 32bit system and the user wants optimizations. 91 | /// Keep the _dwDisabledISA test (2 more operations, could be eliminated). 92 | #elif ((defined(__GNUC__) && defined(__i386__)) \ 93 | || defined(_M_IX86)) \ 94 | && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) 95 | 96 | if (_dwDisabledISA == 0xffffffff) return 0; 97 | 98 | uint res = 0; 99 | 100 | #if defined(__GNUC__) 101 | // GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support. 102 | uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable. 103 | 104 | // Check if no cpuid support. 105 | if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions. 106 | 107 | if (edx & bit_MMX) res = res | SUPPORT_MMX; 108 | if (edx & bit_SSE) res = res | SUPPORT_SSE; 109 | if (edx & bit_SSE2) res = res | SUPPORT_SSE2; 110 | 111 | #else 112 | // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required 113 | // for __cpuid intrinsic support. 114 | int reg[4] = {-1}; 115 | 116 | // Check if no cpuid support. 117 | __cpuid(reg,0); 118 | if ((unsigned int)reg[0] == 0) return 0; // always disable extensions. 119 | 120 | __cpuid(reg,1); 121 | if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX; 122 | if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE; 123 | if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2; 124 | 125 | #endif 126 | 127 | return res & ~_dwDisabledISA; 128 | 129 | #else 130 | 131 | /// One of these is true: 132 | /// 1) We don't want optimizations. 133 | /// 2) Using an unsupported compiler. 134 | /// 3) Running on a non-x86 platform. 135 | return 0; 136 | 137 | #endif 138 | } 139 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/SoundTouch/sse_optimized.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE 4 | /// optimized functions have been gathered into this single source 5 | /// code file, regardless to their class or original source code file, in order 6 | /// to ease porting the library to other compiler and processor platforms. 7 | /// 8 | /// The SSE-optimizations are programmed using SSE compiler intrinsics that 9 | /// are supported both by Microsoft Visual C++ and GCC compilers, so this file 10 | /// should compile with both toolsets. 11 | /// 12 | /// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ 13 | /// 6.0 processor pack" update to support SSE instruction set. The update is 14 | /// available for download at Microsoft Developers Network, see here: 15 | /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx 16 | /// 17 | /// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and 18 | /// perform a search with keywords "processor pack". 19 | /// 20 | /// Author : Copyright (c) Olli Parviainen 21 | /// Author e-mail : oparviai 'at' iki.fi 22 | /// SoundTouch WWW: http://www.surina.net/soundtouch 23 | /// 24 | //////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ 27 | // File revision : $Revision: 4 $ 28 | // 29 | // $Id: sse_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $ 30 | // 31 | //////////////////////////////////////////////////////////////////////////////// 32 | // 33 | // License : 34 | // 35 | // SoundTouch audio processing library 36 | // Copyright (c) Olli Parviainen 37 | // 38 | // This library is free software; you can redistribute it and/or 39 | // modify it under the terms of the GNU Lesser General Public 40 | // License as published by the Free Software Foundation; either 41 | // version 2.1 of the License, or (at your option) any later version. 42 | // 43 | // This library is distributed in the hope that it will be useful, 44 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 45 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 46 | // Lesser General Public License for more details. 47 | // 48 | // You should have received a copy of the GNU Lesser General Public 49 | // License along with this library; if not, write to the Free Software 50 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 51 | // 52 | //////////////////////////////////////////////////////////////////////////////// 53 | 54 | #include "cpu_detect.h" 55 | #include "STTypes.h" 56 | 57 | using namespace soundtouch; 58 | 59 | #ifdef SOUNDTOUCH_ALLOW_SSE 60 | 61 | // SSE routines available only with float sample type 62 | 63 | ////////////////////////////////////////////////////////////////////////////// 64 | // 65 | // implementation of SSE optimized functions of class 'TDStretchSSE' 66 | // 67 | ////////////////////////////////////////////////////////////////////////////// 68 | 69 | #include "TDStretch.h" 70 | #include 71 | #include 72 | 73 | // Calculates cross correlation of two buffers 74 | double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm) 75 | { 76 | int i; 77 | const float *pVec1; 78 | const __m128 *pVec2; 79 | __m128 vSum, vNorm; 80 | 81 | // Note. It means a major slow-down if the routine needs to tolerate 82 | // unaligned __m128 memory accesses. It's way faster if we can skip 83 | // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. 84 | // This can mean up to ~ 10-fold difference (incl. part of which is 85 | // due to skipping every second round for stereo sound though). 86 | // 87 | // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided 88 | // for choosing if this little cheating is allowed. 89 | 90 | #ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 91 | // Little cheating allowed, return valid correlation only for 92 | // aligned locations, meaning every second round for stereo sound. 93 | 94 | #define _MM_LOAD _mm_load_ps 95 | 96 | if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations 97 | 98 | #else 99 | // No cheating allowed, use unaligned load & take the resulting 100 | // performance hit. 101 | #define _MM_LOAD _mm_loadu_ps 102 | #endif 103 | 104 | // ensure overlapLength is divisible by 8 105 | assert((overlapLength % 8) == 0); 106 | 107 | // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors 108 | // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. 109 | pVec1 = (const float*)pV1; 110 | pVec2 = (const __m128*)pV2; 111 | vSum = vNorm = _mm_setzero_ps(); 112 | 113 | // Unroll the loop by factor of 4 * 4 operations. Use same routine for 114 | // stereo & mono, for mono it just means twice the amount of unrolling. 115 | for (i = 0; i < channels * overlapLength / 16; i ++) 116 | { 117 | __m128 vTemp; 118 | // vSum += pV1[0..3] * pV2[0..3] 119 | vTemp = _MM_LOAD(pVec1); 120 | vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0])); 121 | vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); 122 | 123 | // vSum += pV1[4..7] * pV2[4..7] 124 | vTemp = _MM_LOAD(pVec1 + 4); 125 | vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1])); 126 | vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); 127 | 128 | // vSum += pV1[8..11] * pV2[8..11] 129 | vTemp = _MM_LOAD(pVec1 + 8); 130 | vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2])); 131 | vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); 132 | 133 | // vSum += pV1[12..15] * pV2[12..15] 134 | vTemp = _MM_LOAD(pVec1 + 12); 135 | vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3])); 136 | vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); 137 | 138 | pVec1 += 16; 139 | pVec2 += 4; 140 | } 141 | 142 | // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] 143 | float *pvNorm = (float*)&vNorm; 144 | float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); 145 | anorm = norm; 146 | 147 | float *pvSum = (float*)&vSum; 148 | return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm); 149 | 150 | /* This is approximately corresponding routine in C-language yet without normalization: 151 | double corr, norm; 152 | uint i; 153 | 154 | // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors 155 | corr = norm = 0.0; 156 | for (i = 0; i < channels * overlapLength / 16; i ++) 157 | { 158 | corr += pV1[0] * pV2[0] + 159 | pV1[1] * pV2[1] + 160 | pV1[2] * pV2[2] + 161 | pV1[3] * pV2[3] + 162 | pV1[4] * pV2[4] + 163 | pV1[5] * pV2[5] + 164 | pV1[6] * pV2[6] + 165 | pV1[7] * pV2[7] + 166 | pV1[8] * pV2[8] + 167 | pV1[9] * pV2[9] + 168 | pV1[10] * pV2[10] + 169 | pV1[11] * pV2[11] + 170 | pV1[12] * pV2[12] + 171 | pV1[13] * pV2[13] + 172 | pV1[14] * pV2[14] + 173 | pV1[15] * pV2[15]; 174 | 175 | for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j]; 176 | 177 | pV1 += 16; 178 | pV2 += 16; 179 | } 180 | return corr / sqrt(norm); 181 | */ 182 | } 183 | 184 | 185 | 186 | double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm) 187 | { 188 | // call usual calcCrossCorr function because SSE does not show big benefit of 189 | // accumulating "norm" value, and also the "norm" rolling algorithm would get 190 | // complicated due to SSE-specific alignment-vs-nonexact correlation rules. 191 | return calcCrossCorr(pV1, pV2, norm); 192 | } 193 | 194 | 195 | ////////////////////////////////////////////////////////////////////////////// 196 | // 197 | // implementation of SSE optimized functions of class 'FIRFilter' 198 | // 199 | ////////////////////////////////////////////////////////////////////////////// 200 | 201 | #include "FIRFilter.h" 202 | 203 | FIRFilterSSE::FIRFilterSSE() : FIRFilter() 204 | { 205 | filterCoeffsAlign = NULL; 206 | filterCoeffsUnalign = NULL; 207 | } 208 | 209 | 210 | FIRFilterSSE::~FIRFilterSSE() 211 | { 212 | delete[] filterCoeffsUnalign; 213 | filterCoeffsAlign = NULL; 214 | filterCoeffsUnalign = NULL; 215 | } 216 | 217 | 218 | // (overloaded) Calculates filter coefficients for SSE routine 219 | void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) 220 | { 221 | uint i; 222 | float fDivider; 223 | 224 | FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); 225 | 226 | // Scale the filter coefficients so that it won't be necessary to scale the filtering result 227 | // also rearrange coefficients suitably for SSE 228 | // Ensure that filter coeffs array is aligned to 16-byte boundary 229 | delete[] filterCoeffsUnalign; 230 | filterCoeffsUnalign = new float[2 * newLength + 4]; 231 | filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); 232 | 233 | fDivider = (float)resultDivider; 234 | 235 | // rearrange the filter coefficients for mmx routines 236 | for (i = 0; i < newLength; i ++) 237 | { 238 | filterCoeffsAlign[2 * i + 0] = 239 | filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; 240 | } 241 | } 242 | 243 | 244 | 245 | // SSE-optimized version of the filter routine for stereo sound 246 | uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const 247 | { 248 | int count = (int)((numSamples - length) & (uint)-2); 249 | int j; 250 | 251 | assert(count % 2 == 0); 252 | 253 | if (count < 2) return 0; 254 | 255 | assert(source != NULL); 256 | assert(dest != NULL); 257 | assert((length % 8) == 0); 258 | assert(filterCoeffsAlign != NULL); 259 | assert(((ulongptr)filterCoeffsAlign) % 16 == 0); 260 | 261 | // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' 262 | #pragma omp parallel for 263 | for (j = 0; j < count; j += 2) 264 | { 265 | const float *pSrc; 266 | float *pDest; 267 | const __m128 *pFil; 268 | __m128 sum1, sum2; 269 | uint i; 270 | 271 | pSrc = (const float*)source + j * 2; // source audio data 272 | pDest = dest + j * 2; // destination audio data 273 | pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients 274 | // are aligned to 16-byte boundary 275 | sum1 = sum2 = _mm_setzero_ps(); 276 | 277 | for (i = 0; i < length / 8; i ++) 278 | { 279 | // Unroll loop for efficiency & calculate filter for 2*2 stereo samples 280 | // at each pass 281 | 282 | // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset 283 | // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. 284 | 285 | sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); 286 | sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); 287 | 288 | sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); 289 | sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); 290 | 291 | sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); 292 | sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); 293 | 294 | sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); 295 | sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); 296 | 297 | pSrc += 16; 298 | pFil += 4; 299 | } 300 | 301 | // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need 302 | // to sum the two hi- and lo-floats of these registers together. 303 | 304 | // post-shuffle & add the filtered values and store to dest. 305 | _mm_storeu_ps(pDest, _mm_add_ps( 306 | _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 307 | _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 308 | )); 309 | } 310 | 311 | // Ideas for further improvement: 312 | // 1. If it could be guaranteed that 'source' were always aligned to 16-byte 313 | // boundary, a faster aligned '_mm_load_ps' instruction could be used. 314 | // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte 315 | // boundary, a faster '_mm_store_ps' instruction could be used. 316 | 317 | return (uint)count; 318 | 319 | /* original routine in C-language. please notice the C-version has differently 320 | organized coefficients though. 321 | double suml1, suml2; 322 | double sumr1, sumr2; 323 | uint i, j; 324 | 325 | for (j = 0; j < count; j += 2) 326 | { 327 | const float *ptr; 328 | const float *pFil; 329 | 330 | suml1 = sumr1 = 0.0; 331 | suml2 = sumr2 = 0.0; 332 | ptr = src; 333 | pFil = filterCoeffs; 334 | for (i = 0; i < lengthLocal; i ++) 335 | { 336 | // unroll loop for efficiency. 337 | 338 | suml1 += ptr[0] * pFil[0] + 339 | ptr[2] * pFil[2] + 340 | ptr[4] * pFil[4] + 341 | ptr[6] * pFil[6]; 342 | 343 | sumr1 += ptr[1] * pFil[1] + 344 | ptr[3] * pFil[3] + 345 | ptr[5] * pFil[5] + 346 | ptr[7] * pFil[7]; 347 | 348 | suml2 += ptr[8] * pFil[0] + 349 | ptr[10] * pFil[2] + 350 | ptr[12] * pFil[4] + 351 | ptr[14] * pFil[6]; 352 | 353 | sumr2 += ptr[9] * pFil[1] + 354 | ptr[11] * pFil[3] + 355 | ptr[13] * pFil[5] + 356 | ptr[15] * pFil[7]; 357 | 358 | ptr += 16; 359 | pFil += 8; 360 | } 361 | dest[0] = (float)suml1; 362 | dest[1] = (float)sumr1; 363 | dest[2] = (float)suml2; 364 | dest[3] = (float)sumr2; 365 | 366 | src += 4; 367 | dest += 4; 368 | } 369 | */ 370 | } 371 | 372 | #endif // SOUNDTOUCH_ALLOW_SSE 373 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/include/BPMDetect.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Beats-per-minute (BPM) detection routine. 4 | /// 5 | /// The beat detection algorithm works as follows: 6 | /// - Use function 'inputSamples' to input a chunks of samples to the class for 7 | /// analysis. It's a good idea to enter a large sound file or stream in smallish 8 | /// chunks of around few kilosamples in order not to extinguish too much RAM memory. 9 | /// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, 10 | /// which is basically ok as low (bass) frequencies mostly determine the beat rate. 11 | /// Simple averaging is used for anti-alias filtering because the resulting signal 12 | /// quality isn't of that high importance. 13 | /// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by 14 | /// taking absolute value that's smoothed by sliding average. Signal levels that 15 | /// are below a couple of times the general RMS amplitude level are cut away to 16 | /// leave only notable peaks there. 17 | /// - Repeating sound patterns (e.g. beats) are detected by calculating short-term 18 | /// autocorrelation function of the enveloped signal. 19 | /// - After whole sound data file has been analyzed as above, the bpm level is 20 | /// detected by function 'getBpm' that finds the highest peak of the autocorrelation 21 | /// function, calculates it's precise location and converts this reading to bpm's. 22 | /// 23 | /// Author : Copyright (c) Olli Parviainen 24 | /// Author e-mail : oparviai 'at' iki.fi 25 | /// SoundTouch WWW: http://www.surina.net/soundtouch 26 | /// 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // Last changed : $Date: 2012-08-30 22:53:44 +0300 (Thu, 30 Aug 2012) $ 30 | // File revision : $Revision: 4 $ 31 | // 32 | // $Id: BPMDetect.h 150 2012-08-30 19:53:44Z oparviai $ 33 | // 34 | //////////////////////////////////////////////////////////////////////////////// 35 | // 36 | // License : 37 | // 38 | // SoundTouch audio processing library 39 | // Copyright (c) Olli Parviainen 40 | // 41 | // This library is free software; you can redistribute it and/or 42 | // modify it under the terms of the GNU Lesser General Public 43 | // License as published by the Free Software Foundation; either 44 | // version 2.1 of the License, or (at your option) any later version. 45 | // 46 | // This library is distributed in the hope that it will be useful, 47 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 48 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 49 | // Lesser General Public License for more details. 50 | // 51 | // You should have received a copy of the GNU Lesser General Public 52 | // License along with this library; if not, write to the Free Software 53 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 54 | // 55 | //////////////////////////////////////////////////////////////////////////////// 56 | 57 | #ifndef _BPMDetect_H_ 58 | #define _BPMDetect_H_ 59 | 60 | #include "STTypes.h" 61 | #include "FIFOSampleBuffer.h" 62 | 63 | namespace soundtouch 64 | { 65 | 66 | /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. 67 | #define MIN_BPM 29 68 | 69 | /// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. 70 | #define MAX_BPM 200 71 | 72 | 73 | /// Class for calculating BPM rate for audio data. 74 | class BPMDetect 75 | { 76 | protected: 77 | /// Auto-correlation accumulator bins. 78 | float *xcorr; 79 | 80 | /// Amplitude envelope sliding average approximation level accumulator 81 | double envelopeAccu; 82 | 83 | /// RMS volume sliding average approximation level accumulator 84 | double RMSVolumeAccu; 85 | 86 | /// Sample average counter. 87 | int decimateCount; 88 | 89 | /// Sample average accumulator for FIFO-like decimation. 90 | soundtouch::LONG_SAMPLETYPE decimateSum; 91 | 92 | /// Decimate sound by this coefficient to reach approx. 500 Hz. 93 | int decimateBy; 94 | 95 | /// Auto-correlation window length 96 | int windowLen; 97 | 98 | /// Number of channels (1 = mono, 2 = stereo) 99 | int channels; 100 | 101 | /// sample rate 102 | int sampleRate; 103 | 104 | /// Beginning of auto-correlation window: Autocorrelation isn't being updated for 105 | /// the first these many correlation bins. 106 | int windowStart; 107 | 108 | /// FIFO-buffer for decimated processing samples. 109 | soundtouch::FIFOSampleBuffer *buffer; 110 | 111 | /// Updates auto-correlation function for given number of decimated samples that 112 | /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe 113 | /// though). 114 | void updateXCorr(int process_samples /// How many samples are processed. 115 | ); 116 | 117 | /// Decimates samples to approx. 500 Hz. 118 | /// 119 | /// \return Number of output samples. 120 | int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer 121 | const soundtouch::SAMPLETYPE *src, ///< Source sample buffer 122 | int numsamples ///< Number of source samples. 123 | ); 124 | 125 | /// Calculates amplitude envelope for the buffer of samples. 126 | /// Result is output to 'samples'. 127 | void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer 128 | int numsamples ///< Number of samples in buffer 129 | ); 130 | 131 | /// remove constant bias from xcorr data 132 | void removeBias(); 133 | 134 | public: 135 | /// Constructor. 136 | BPMDetect(int numChannels, ///< Number of channels in sample data. 137 | int sampleRate ///< Sample rate in Hz. 138 | ); 139 | 140 | /// Destructor. 141 | virtual ~BPMDetect(); 142 | 143 | /// Inputs a block of samples for analyzing: Envelopes the samples and then 144 | /// updates the autocorrelation estimation. When whole song data has been input 145 | /// in smaller blocks using this function, read the resulting bpm with 'getBpm' 146 | /// function. 147 | /// 148 | /// Notice that data in 'samples' array can be disrupted in processing. 149 | void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer 150 | int numSamples ///< Number of samples in buffer 151 | ); 152 | 153 | 154 | /// Analyzes the results and returns the BPM rate. Use this function to read result 155 | /// after whole song data has been input to the class by consecutive calls of 156 | /// 'inputSamples' function. 157 | /// 158 | /// \return Beats-per-minute rate, or zero if detection failed. 159 | float getBpm(); 160 | }; 161 | 162 | } 163 | 164 | #endif // _BPMDetect_H_ 165 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/include/FIFOSampleBuffer.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// A buffer class for temporarily storaging sound samples, operates as a 4 | /// first-in-first-out pipe. 5 | /// 6 | /// Samples are added to the end of the sample buffer with the 'putSamples' 7 | /// function, and are received from the beginning of the buffer by calling 8 | /// the 'receiveSamples' function. The class automatically removes the 9 | /// output samples from the buffer as well as grows the storage size 10 | /// whenever necessary. 11 | /// 12 | /// Author : Copyright (c) Olli Parviainen 13 | /// Author e-mail : oparviai 'at' iki.fi 14 | /// SoundTouch WWW: http://www.surina.net/soundtouch 15 | /// 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // 18 | // Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $ 19 | // File revision : $Revision: 4 $ 20 | // 21 | // $Id: FIFOSampleBuffer.h 177 2014-01-05 21:40:22Z oparviai $ 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | // 25 | // License : 26 | // 27 | // SoundTouch audio processing library 28 | // Copyright (c) Olli Parviainen 29 | // 30 | // This library is free software; you can redistribute it and/or 31 | // modify it under the terms of the GNU Lesser General Public 32 | // License as published by the Free Software Foundation; either 33 | // version 2.1 of the License, or (at your option) any later version. 34 | // 35 | // This library is distributed in the hope that it will be useful, 36 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 38 | // Lesser General Public License for more details. 39 | // 40 | // You should have received a copy of the GNU Lesser General Public 41 | // License along with this library; if not, write to the Free Software 42 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 43 | // 44 | //////////////////////////////////////////////////////////////////////////////// 45 | 46 | #ifndef FIFOSampleBuffer_H 47 | #define FIFOSampleBuffer_H 48 | 49 | #include "FIFOSamplePipe.h" 50 | 51 | namespace soundtouch 52 | { 53 | 54 | /// Sample buffer working in FIFO (first-in-first-out) principle. The class takes 55 | /// care of storage size adjustment and data moving during input/output operations. 56 | /// 57 | /// Notice that in case of stereo audio, one sample is considered to consist of 58 | /// both channel data. 59 | class FIFOSampleBuffer : public FIFOSamplePipe 60 | { 61 | private: 62 | /// Sample buffer. 63 | SAMPLETYPE *buffer; 64 | 65 | // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first 66 | // 16-byte aligned location of this buffer 67 | SAMPLETYPE *bufferUnaligned; 68 | 69 | /// Sample buffer size in bytes 70 | uint sizeInBytes; 71 | 72 | /// How many samples are currently in buffer. 73 | uint samplesInBuffer; 74 | 75 | /// Channels, 1=mono, 2=stereo. 76 | uint channels; 77 | 78 | /// Current position pointer to the buffer. This pointer is increased when samples are 79 | /// removed from the pipe so that it's necessary to actually rewind buffer (move data) 80 | /// only new data when is put to the pipe. 81 | uint bufferPos; 82 | 83 | /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real 84 | /// beginning of the buffer. 85 | void rewind(); 86 | 87 | /// Ensures that the buffer has capacity for at least this many samples. 88 | void ensureCapacity(uint capacityRequirement); 89 | 90 | /// Returns current capacity. 91 | uint getCapacity() const; 92 | 93 | public: 94 | 95 | /// Constructor 96 | FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. 97 | ///< Default is stereo. 98 | ); 99 | 100 | /// destructor 101 | ~FIFOSampleBuffer(); 102 | 103 | /// Returns a pointer to the beginning of the output samples. 104 | /// This function is provided for accessing the output samples directly. 105 | /// Please be careful for not to corrupt the book-keeping! 106 | /// 107 | /// When using this function to output samples, also remember to 'remove' the 108 | /// output samples from the buffer by calling the 109 | /// 'receiveSamples(numSamples)' function 110 | virtual SAMPLETYPE *ptrBegin(); 111 | 112 | /// Returns a pointer to the end of the used part of the sample buffer (i.e. 113 | /// where the new samples are to be inserted). This function may be used for 114 | /// inserting new samples into the sample buffer directly. Please be careful 115 | /// not corrupt the book-keeping! 116 | /// 117 | /// When using this function as means for inserting new samples, also remember 118 | /// to increase the sample count afterwards, by calling the 119 | /// 'putSamples(numSamples)' function. 120 | SAMPLETYPE *ptrEnd( 121 | uint slackCapacity ///< How much free capacity (in samples) there _at least_ 122 | ///< should be so that the caller can succesfully insert the 123 | ///< desired samples to the buffer. If necessary, the function 124 | ///< grows the buffer size to comply with this requirement. 125 | ); 126 | 127 | /// Adds 'numSamples' pcs of samples from the 'samples' memory position to 128 | /// the sample buffer. 129 | virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. 130 | uint numSamples ///< Number of samples to insert. 131 | ); 132 | 133 | /// Adjusts the book-keeping to increase number of samples in the buffer without 134 | /// copying any actual samples. 135 | /// 136 | /// This function is used to update the number of samples in the sample buffer 137 | /// when accessing the buffer directly with 'ptrEnd' function. Please be 138 | /// careful though! 139 | virtual void putSamples(uint numSamples ///< Number of samples been inserted. 140 | ); 141 | 142 | /// Output samples from beginning of the sample buffer. Copies requested samples to 143 | /// output buffer and removes them from the sample buffer. If there are less than 144 | /// 'numsample' samples in the buffer, returns all that available. 145 | /// 146 | /// \return Number of samples returned. 147 | virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. 148 | uint maxSamples ///< How many samples to receive at max. 149 | ); 150 | 151 | /// Adjusts book-keeping so that given number of samples are removed from beginning of the 152 | /// sample buffer without copying them anywhere. 153 | /// 154 | /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly 155 | /// with 'ptrBegin' function. 156 | virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. 157 | ); 158 | 159 | /// Returns number of samples currently available. 160 | virtual uint numSamples() const; 161 | 162 | /// Sets number of channels, 1 = mono, 2 = stereo. 163 | void setChannels(int numChannels); 164 | 165 | /// Get number of channels 166 | int getChannels() 167 | { 168 | return channels; 169 | } 170 | 171 | /// Returns nonzero if there aren't any samples available for outputting. 172 | virtual int isEmpty() const; 173 | 174 | /// Clears all the samples. 175 | virtual void clear(); 176 | 177 | /// allow trimming (downwards) amount of samples in pipeline. 178 | /// Returns adjusted amount of samples 179 | uint adjustAmountOfSamples(uint numSamples); 180 | }; 181 | 182 | } 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/include/FIFOSamplePipe.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound 4 | /// samples by operating like a first-in-first-out pipe: New samples are fed 5 | /// into one end of the pipe with the 'putSamples' function, and the processed 6 | /// samples are received from the other end with the 'receiveSamples' function. 7 | /// 8 | /// 'FIFOProcessor' : A base class for classes the do signal processing with 9 | /// the samples while operating like a first-in-first-out pipe. When samples 10 | /// are input with the 'putSamples' function, the class processes them 11 | /// and moves the processed samples to the given 'output' pipe object, which 12 | /// may be either another processing stage, or a fifo sample buffer object. 13 | /// 14 | /// Author : Copyright (c) Olli Parviainen 15 | /// Author e-mail : oparviai 'at' iki.fi 16 | /// SoundTouch WWW: http://www.surina.net/soundtouch 17 | /// 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // Last changed : $Date: 2012-06-13 22:29:53 +0300 (Wed, 13 Jun 2012) $ 21 | // File revision : $Revision: 4 $ 22 | // 23 | // $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $ 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | // 27 | // License : 28 | // 29 | // SoundTouch audio processing library 30 | // Copyright (c) Olli Parviainen 31 | // 32 | // This library is free software; you can redistribute it and/or 33 | // modify it under the terms of the GNU Lesser General Public 34 | // License as published by the Free Software Foundation; either 35 | // version 2.1 of the License, or (at your option) any later version. 36 | // 37 | // This library is distributed in the hope that it will be useful, 38 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 39 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 40 | // Lesser General Public License for more details. 41 | // 42 | // You should have received a copy of the GNU Lesser General Public 43 | // License along with this library; if not, write to the Free Software 44 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 45 | // 46 | //////////////////////////////////////////////////////////////////////////////// 47 | 48 | #ifndef FIFOSamplePipe_H 49 | #define FIFOSamplePipe_H 50 | 51 | #include 52 | #include 53 | #include "STTypes.h" 54 | 55 | namespace soundtouch 56 | { 57 | 58 | /// Abstract base class for FIFO (first-in-first-out) sample processing classes. 59 | class FIFOSamplePipe 60 | { 61 | public: 62 | // virtual default destructor 63 | virtual ~FIFOSamplePipe() {} 64 | 65 | 66 | /// Returns a pointer to the beginning of the output samples. 67 | /// This function is provided for accessing the output samples directly. 68 | /// Please be careful for not to corrupt the book-keeping! 69 | /// 70 | /// When using this function to output samples, also remember to 'remove' the 71 | /// output samples from the buffer by calling the 72 | /// 'receiveSamples(numSamples)' function 73 | virtual SAMPLETYPE *ptrBegin() = 0; 74 | 75 | /// Adds 'numSamples' pcs of samples from the 'samples' memory position to 76 | /// the sample buffer. 77 | virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. 78 | uint numSamples ///< Number of samples to insert. 79 | ) = 0; 80 | 81 | 82 | // Moves samples from the 'other' pipe instance to this instance. 83 | void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. 84 | ) 85 | { 86 | int oNumSamples = other.numSamples(); 87 | 88 | putSamples(other.ptrBegin(), oNumSamples); 89 | other.receiveSamples(oNumSamples); 90 | }; 91 | 92 | /// Output samples from beginning of the sample buffer. Copies requested samples to 93 | /// output buffer and removes them from the sample buffer. If there are less than 94 | /// 'numsample' samples in the buffer, returns all that available. 95 | /// 96 | /// \return Number of samples returned. 97 | virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. 98 | uint maxSamples ///< How many samples to receive at max. 99 | ) = 0; 100 | 101 | /// Adjusts book-keeping so that given number of samples are removed from beginning of the 102 | /// sample buffer without copying them anywhere. 103 | /// 104 | /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly 105 | /// with 'ptrBegin' function. 106 | virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. 107 | ) = 0; 108 | 109 | /// Returns number of samples currently available. 110 | virtual uint numSamples() const = 0; 111 | 112 | // Returns nonzero if there aren't any samples available for outputting. 113 | virtual int isEmpty() const = 0; 114 | 115 | /// Clears all the samples. 116 | virtual void clear() = 0; 117 | 118 | /// allow trimming (downwards) amount of samples in pipeline. 119 | /// Returns adjusted amount of samples 120 | virtual uint adjustAmountOfSamples(uint numSamples) = 0; 121 | 122 | }; 123 | 124 | 125 | 126 | /// Base-class for sound processing routines working in FIFO principle. With this base 127 | /// class it's easy to implement sound processing stages that can be chained together, 128 | /// so that samples that are fed into beginning of the pipe automatically go through 129 | /// all the processing stages. 130 | /// 131 | /// When samples are input to this class, they're first processed and then put to 132 | /// the FIFO pipe that's defined as output of this class. This output pipe can be 133 | /// either other processing stage or a FIFO sample buffer. 134 | class FIFOProcessor :public FIFOSamplePipe 135 | { 136 | protected: 137 | /// Internal pipe where processed samples are put. 138 | FIFOSamplePipe *output; 139 | 140 | /// Sets output pipe. 141 | void setOutPipe(FIFOSamplePipe *pOutput) 142 | { 143 | assert(output == NULL); 144 | assert(pOutput != NULL); 145 | output = pOutput; 146 | } 147 | 148 | 149 | /// Constructor. Doesn't define output pipe; it has to be set be 150 | /// 'setOutPipe' function. 151 | FIFOProcessor() 152 | { 153 | output = NULL; 154 | } 155 | 156 | 157 | /// Constructor. Configures output pipe. 158 | FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. 159 | ) 160 | { 161 | output = pOutput; 162 | } 163 | 164 | 165 | /// Destructor. 166 | virtual ~FIFOProcessor() 167 | { 168 | } 169 | 170 | 171 | /// Returns a pointer to the beginning of the output samples. 172 | /// This function is provided for accessing the output samples directly. 173 | /// Please be careful for not to corrupt the book-keeping! 174 | /// 175 | /// When using this function to output samples, also remember to 'remove' the 176 | /// output samples from the buffer by calling the 177 | /// 'receiveSamples(numSamples)' function 178 | virtual SAMPLETYPE *ptrBegin() 179 | { 180 | return output->ptrBegin(); 181 | } 182 | 183 | public: 184 | 185 | /// Output samples from beginning of the sample buffer. Copies requested samples to 186 | /// output buffer and removes them from the sample buffer. If there are less than 187 | /// 'numsample' samples in the buffer, returns all that available. 188 | /// 189 | /// \return Number of samples returned. 190 | virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. 191 | uint maxSamples ///< How many samples to receive at max. 192 | ) 193 | { 194 | return output->receiveSamples(outBuffer, maxSamples); 195 | } 196 | 197 | 198 | /// Adjusts book-keeping so that given number of samples are removed from beginning of the 199 | /// sample buffer without copying them anywhere. 200 | /// 201 | /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly 202 | /// with 'ptrBegin' function. 203 | virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. 204 | ) 205 | { 206 | return output->receiveSamples(maxSamples); 207 | } 208 | 209 | 210 | /// Returns number of samples currently available. 211 | virtual uint numSamples() const 212 | { 213 | return output->numSamples(); 214 | } 215 | 216 | 217 | /// Returns nonzero if there aren't any samples available for outputting. 218 | virtual int isEmpty() const 219 | { 220 | return output->isEmpty(); 221 | } 222 | 223 | /// allow trimming (downwards) amount of samples in pipeline. 224 | /// Returns adjusted amount of samples 225 | virtual uint adjustAmountOfSamples(uint numSamples) 226 | { 227 | return output->adjustAmountOfSamples(numSamples); 228 | } 229 | 230 | }; 231 | 232 | } 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/include/STTypes.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// Common type definitions for SoundTouch audio processing library. 4 | /// 5 | /// Author : Copyright (c) Olli Parviainen 6 | /// Author e-mail : oparviai 'at' iki.fi 7 | /// SoundTouch WWW: http://www.surina.net/soundtouch 8 | /// 9 | //////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // Last changed : $Date: 2015-05-18 18:25:07 +0300 (Mon, 18 May 2015) $ 12 | // File revision : $Revision: 3 $ 13 | // 14 | // $Id: STTypes.h 215 2015-05-18 15:25:07Z oparviai $ 15 | // 16 | //////////////////////////////////////////////////////////////////////////////// 17 | // 18 | // License : 19 | // 20 | // SoundTouch audio processing library 21 | // Copyright (c) Olli Parviainen 22 | // 23 | // This library is free software; you can redistribute it and/or 24 | // modify it under the terms of the GNU Lesser General Public 25 | // License as published by the Free Software Foundation; either 26 | // version 2.1 of the License, or (at your option) any later version. 27 | // 28 | // This library is distributed in the hope that it will be useful, 29 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 31 | // Lesser General Public License for more details. 32 | // 33 | // You should have received a copy of the GNU Lesser General Public 34 | // License along with this library; if not, write to the Free Software 35 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 36 | // 37 | //////////////////////////////////////////////////////////////////////////////// 38 | 39 | #ifndef STTypes_H 40 | #define STTypes_H 41 | 42 | typedef unsigned int uint; 43 | typedef unsigned long ulong; 44 | 45 | // Patch for MinGW: on Win64 long is 32-bit 46 | #ifdef _WIN64 47 | typedef unsigned long long ulongptr; 48 | #else 49 | typedef ulong ulongptr; 50 | #endif 51 | 52 | 53 | // Helper macro for aligning pointer up to next 16-byte boundary 54 | #define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 ) 55 | 56 | 57 | #if (defined(__GNUC__) && !defined(ANDROID)) 58 | // In GCC, include soundtouch_config.h made by config scritps. 59 | // Skip this in Android compilation that uses GCC but without configure scripts. 60 | #include "soundtouch_config.h" 61 | #endif 62 | 63 | 64 | namespace soundtouch 65 | { 66 | /// Activate these undef's to overrule the possible sampletype 67 | /// setting inherited from some other header file: 68 | //#undef SOUNDTOUCH_INTEGER_SAMPLES 69 | //#undef SOUNDTOUCH_FLOAT_SAMPLES 70 | 71 | /// If following flag is defined, always uses multichannel processing 72 | /// routines also for mono and stero sound. This is for routine testing 73 | /// purposes; output should be same with either routines, yet disabling 74 | /// the dedicated mono/stereo processing routines will result in slower 75 | /// runtime performance so recommendation is to keep this off. 76 | // #define USE_MULTICH_ALWAYS 77 | 78 | #if (defined(__SOFTFP__) && defined(ANDROID)) 79 | // For Android compilation: Force use of Integer samples in case that 80 | // compilation uses soft-floating point emulation - soft-fp is way too slow 81 | #undef SOUNDTOUCH_FLOAT_SAMPLES 82 | #define SOUNDTOUCH_INTEGER_SAMPLES 1 83 | #endif 84 | 85 | #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES) 86 | 87 | /// Choose either 32bit floating point or 16bit integer sampletype 88 | /// by choosing one of the following defines, unless this selection 89 | /// has already been done in some other file. 90 | //// 91 | /// Notes: 92 | /// - In Windows environment, choose the sample format with the 93 | /// following defines. 94 | /// - In GNU environment, the floating point samples are used by 95 | /// default, but integer samples can be chosen by giving the 96 | /// following switch to the configure script: 97 | /// ./configure --enable-integer-samples 98 | /// However, if you still prefer to select the sample format here 99 | /// also in GNU environment, then please #undef the INTEGER_SAMPLE 100 | /// and FLOAT_SAMPLE defines first as in comments above. 101 | #define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples 102 | //#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples 103 | 104 | #endif 105 | 106 | #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64) 107 | /// Define this to allow X86-specific assembler/intrinsic optimizations. 108 | /// Notice that library contains also usual C++ versions of each of these 109 | /// these routines, so if you're having difficulties getting the optimized 110 | /// routines compiled for whatever reason, you may disable these optimizations 111 | /// to make the library compile. 112 | 113 | #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 114 | 115 | /// In GNU environment, allow the user to override this setting by 116 | /// giving the following switch to the configure script: 117 | /// ./configure --disable-x86-optimizations 118 | /// ./configure --enable-x86-optimizations=no 119 | #ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 120 | #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 121 | #endif 122 | #else 123 | /// Always disable optimizations when not using a x86 systems. 124 | #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 125 | 126 | #endif 127 | 128 | // If defined, allows the SIMD-optimized routines to take minor shortcuts 129 | // for improved performance. Undefine to require faithfully similar SIMD 130 | // calculations as in normal C implementation. 131 | #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 132 | 133 | 134 | #ifdef SOUNDTOUCH_INTEGER_SAMPLES 135 | // 16bit integer sample type 136 | typedef short SAMPLETYPE; 137 | // data type for sample accumulation: Use 32bit integer to prevent overflows 138 | typedef long LONG_SAMPLETYPE; 139 | 140 | #ifdef SOUNDTOUCH_FLOAT_SAMPLES 141 | // check that only one sample type is defined 142 | #error "conflicting sample types defined" 143 | #endif // SOUNDTOUCH_FLOAT_SAMPLES 144 | 145 | #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 146 | // Allow MMX optimizations 147 | // #define SOUNDTOUCH_ALLOW_MMX 1 148 | #endif 149 | 150 | #else 151 | 152 | // floating point samples 153 | typedef float SAMPLETYPE; 154 | // data type for sample accumulation: Use double to utilize full precision. 155 | typedef double LONG_SAMPLETYPE; 156 | 157 | #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 158 | // Allow SSE optimizations 159 | #define SOUNDTOUCH_ALLOW_SSE 1 160 | #endif 161 | 162 | #endif // SOUNDTOUCH_INTEGER_SAMPLES 163 | 164 | }; 165 | 166 | // define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: 167 | // #define ST_NO_EXCEPTION_HANDLING 1 168 | #ifdef ST_NO_EXCEPTION_HANDLING 169 | // Exceptions disabled. Throw asserts instead if enabled. 170 | #include 171 | #define ST_THROW_RT_ERROR(x) {assert((const char *)x);} 172 | #else 173 | // use c++ standard exceptions 174 | #include 175 | #include 176 | #define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);} 177 | #endif 178 | 179 | // When this #define is active, eliminates a clicking sound when the "rate" or "pitch" 180 | // parameter setting crosses from value <1 to >=1 or vice versa during processing. 181 | // Default is off as such crossover is untypical case and involves a slight sound 182 | // quality compromise. 183 | //#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/include/SoundTouch.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | /// 3 | /// SoundTouch - main class for tempo/pitch/rate adjusting routines. 4 | /// 5 | /// Notes: 6 | /// - Initialize the SoundTouch object instance by setting up the sound stream 7 | /// parameters with functions 'setSampleRate' and 'setChannels', then set 8 | /// desired tempo/pitch/rate settings with the corresponding functions. 9 | /// 10 | /// - The SoundTouch class behaves like a first-in-first-out pipeline: The 11 | /// samples that are to be processed are fed into one of the pipe by calling 12 | /// function 'putSamples', while the ready processed samples can be read 13 | /// from the other end of the pipeline with function 'receiveSamples'. 14 | /// 15 | /// - The SoundTouch processing classes require certain sized 'batches' of 16 | /// samples in order to process the sound. For this reason the classes buffer 17 | /// incoming samples until there are enough of samples available for 18 | /// processing, then they carry out the processing step and consequently 19 | /// make the processed samples available for outputting. 20 | /// 21 | /// - For the above reason, the processing routines introduce a certain 22 | /// 'latency' between the input and output, so that the samples input to 23 | /// SoundTouch may not be immediately available in the output, and neither 24 | /// the amount of outputtable samples may not immediately be in direct 25 | /// relationship with the amount of previously input samples. 26 | /// 27 | /// - The tempo/pitch/rate control parameters can be altered during processing. 28 | /// Please notice though that they aren't currently protected by semaphores, 29 | /// so in multi-thread application external semaphore protection may be 30 | /// required. 31 | /// 32 | /// - This class utilizes classes 'TDStretch' for tempo change (without modifying 33 | /// pitch) and 'RateTransposer' for changing the playback rate (that is, both 34 | /// tempo and pitch in the same ratio) of the sound. The third available control 35 | /// 'pitch' (change pitch but maintain tempo) is produced by a combination of 36 | /// combining the two other controls. 37 | /// 38 | /// Author : Copyright (c) Olli Parviainen 39 | /// Author e-mail : oparviai 'at' iki.fi 40 | /// SoundTouch WWW: http://www.surina.net/soundtouch 41 | /// 42 | //////////////////////////////////////////////////////////////////////////////// 43 | // 44 | // Last changed : $Date: 2015-09-20 10:38:32 +0300 (Sun, 20 Sep 2015) $ 45 | // File revision : $Revision: 4 $ 46 | // 47 | // $Id: SoundTouch.h 230 2015-09-20 07:38:32Z oparviai $ 48 | // 49 | //////////////////////////////////////////////////////////////////////////////// 50 | // 51 | // License : 52 | // 53 | // SoundTouch audio processing library 54 | // Copyright (c) Olli Parviainen 55 | // 56 | // This library is free software; you can redistribute it and/or 57 | // modify it under the terms of the GNU Lesser General Public 58 | // License as published by the Free Software Foundation; either 59 | // version 2.1 of the License, or (at your option) any later version. 60 | // 61 | // This library is distributed in the hope that it will be useful, 62 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 63 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 64 | // Lesser General Public License for more details. 65 | // 66 | // You should have received a copy of the GNU Lesser General Public 67 | // License along with this library; if not, write to the Free Software 68 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 69 | // 70 | //////////////////////////////////////////////////////////////////////////////// 71 | 72 | #ifndef SoundTouch_H 73 | #define SoundTouch_H 74 | 75 | #include "FIFOSamplePipe.h" 76 | #include "STTypes.h" 77 | 78 | namespace soundtouch 79 | { 80 | 81 | /// Soundtouch library version string 82 | #define SOUNDTOUCH_VERSION "1.9.2" 83 | 84 | /// SoundTouch library version id 85 | #define SOUNDTOUCH_VERSION_ID (10902) 86 | 87 | // 88 | // Available setting IDs for the 'setSetting' & 'get_setting' functions: 89 | 90 | /// Enable/disable anti-alias filter in pitch transposer (0 = disable) 91 | #define SETTING_USE_AA_FILTER 0 92 | 93 | /// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) 94 | #define SETTING_AA_FILTER_LENGTH 1 95 | 96 | /// Enable/disable quick seeking algorithm in tempo changer routine 97 | /// (enabling quick seeking lowers CPU utilization but causes a minor sound 98 | /// quality compromising) 99 | #define SETTING_USE_QUICKSEEK 2 100 | 101 | /// Time-stretch algorithm single processing sequence length in milliseconds. This determines 102 | /// to how long sequences the original sound is chopped in the time-stretch algorithm. 103 | /// See "STTypes.h" or README for more information. 104 | #define SETTING_SEQUENCE_MS 3 105 | 106 | /// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the 107 | /// best possible overlapping location. This determines from how wide window the algorithm 108 | /// may look for an optimal joining location when mixing the sound sequences back together. 109 | /// See "STTypes.h" or README for more information. 110 | #define SETTING_SEEKWINDOW_MS 4 111 | 112 | /// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences 113 | /// are mixed back together, to form a continuous sound stream, this parameter defines over 114 | /// how long period the two consecutive sequences are let to overlap each other. 115 | /// See "STTypes.h" or README for more information. 116 | #define SETTING_OVERLAP_MS 5 117 | 118 | 119 | /// Call "getSetting" with this ID to query nominal average processing sequence 120 | /// size in samples. This value tells approcimate value how many input samples 121 | /// SoundTouch needs to gather before it does DSP processing run for the sample batch. 122 | /// 123 | /// Notices: 124 | /// - This is read-only parameter, i.e. setSetting ignores this parameter 125 | /// - Returned value is approximate average value, exact processing batch 126 | /// size may wary from time to time 127 | /// - This parameter value is not constant but may change depending on 128 | /// tempo/pitch/rate/samplerate settings. 129 | #define SETTING_NOMINAL_INPUT_SEQUENCE 6 130 | 131 | 132 | /// Call "getSetting" with this ID to query nominal average processing output 133 | /// size in samples. This value tells approcimate value how many output samples 134 | /// SoundTouch outputs once it does DSP processing run for a batch of input samples. 135 | /// 136 | /// Notices: 137 | /// - This is read-only parameter, i.e. setSetting ignores this parameter 138 | /// - Returned value is approximate average value, exact processing batch 139 | /// size may wary from time to time 140 | /// - This parameter value is not constant but may change depending on 141 | /// tempo/pitch/rate/samplerate settings. 142 | #define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 143 | 144 | class SoundTouch : public FIFOProcessor 145 | { 146 | private: 147 | /// Rate transposer class instance 148 | class RateTransposer *pRateTransposer; 149 | 150 | /// Time-stretch class instance 151 | class TDStretch *pTDStretch; 152 | 153 | /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. 154 | double virtualRate; 155 | 156 | /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. 157 | double virtualTempo; 158 | 159 | /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. 160 | double virtualPitch; 161 | 162 | /// Flag: Has sample rate been set? 163 | bool bSrateSet; 164 | 165 | /// Accumulator for how many samples in total will be expected as output vs. samples put in, 166 | /// considering current processing settings. 167 | double samplesExpectedOut; 168 | 169 | /// Accumulator for how many samples in total have been read out from the processing so far 170 | long samplesOutput; 171 | 172 | /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and 173 | /// 'virtualPitch' parameters. 174 | void calcEffectiveRateAndTempo(); 175 | 176 | protected : 177 | /// Number of channels 178 | uint channels; 179 | 180 | /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' 181 | double rate; 182 | 183 | /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' 184 | double tempo; 185 | 186 | public: 187 | SoundTouch(); 188 | virtual ~SoundTouch(); 189 | 190 | /// Get SoundTouch library version string 191 | static const char *getVersionString(); 192 | 193 | /// Get SoundTouch library version Id 194 | static uint getVersionId(); 195 | 196 | /// Sets new rate control value. Normal rate = 1.0, smaller values 197 | /// represent slower rate, larger faster rates. 198 | void setRate(double newRate); 199 | 200 | /// Sets new tempo control value. Normal tempo = 1.0, smaller values 201 | /// represent slower tempo, larger faster tempo. 202 | void setTempo(double newTempo); 203 | 204 | /// Sets new rate control value as a difference in percents compared 205 | /// to the original rate (-50 .. +100 %) 206 | void setRateChange(double newRate); 207 | 208 | /// Sets new tempo control value as a difference in percents compared 209 | /// to the original tempo (-50 .. +100 %) 210 | void setTempoChange(double newTempo); 211 | 212 | /// Sets new pitch control value. Original pitch = 1.0, smaller values 213 | /// represent lower pitches, larger values higher pitch. 214 | void setPitch(double newPitch); 215 | 216 | /// Sets pitch change in octaves compared to the original pitch 217 | /// (-1.00 .. +1.00) 218 | void setPitchOctaves(double newPitch); 219 | 220 | /// Sets pitch change in semi-tones compared to the original pitch 221 | /// (-12 .. +12) 222 | void setPitchSemiTones(int newPitch); 223 | void setPitchSemiTones(double newPitch); 224 | 225 | /// Sets the number of channels, 1 = mono, 2 = stereo 226 | void setChannels(uint numChannels); 227 | 228 | /// Sets sample rate. 229 | void setSampleRate(uint srate); 230 | 231 | /// Flushes the last samples from the processing pipeline to the output. 232 | /// Clears also the internal processing buffers. 233 | // 234 | /// Note: This function is meant for extracting the last samples of a sound 235 | /// stream. This function may introduce additional blank samples in the end 236 | /// of the sound stream, and thus it's not recommended to call this function 237 | /// in the middle of a sound stream. 238 | void flush(); 239 | 240 | /// Adds 'numSamples' pcs of samples from the 'samples' memory position into 241 | /// the input of the object. Notice that sample rate _has_to_ be set before 242 | /// calling this function, otherwise throws a runtime_error exception. 243 | virtual void putSamples( 244 | const SAMPLETYPE *samples, ///< Pointer to sample buffer. 245 | uint numSamples ///< Number of samples in buffer. Notice 246 | ///< that in case of stereo-sound a single sample 247 | ///< contains data for both channels. 248 | ); 249 | 250 | /// Output samples from beginning of the sample buffer. Copies requested samples to 251 | /// output buffer and removes them from the sample buffer. If there are less than 252 | /// 'numsample' samples in the buffer, returns all that available. 253 | /// 254 | /// \return Number of samples returned. 255 | virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. 256 | uint maxSamples ///< How many samples to receive at max. 257 | ); 258 | 259 | /// Adjusts book-keeping so that given number of samples are removed from beginning of the 260 | /// sample buffer without copying them anywhere. 261 | /// 262 | /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly 263 | /// with 'ptrBegin' function. 264 | virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. 265 | ); 266 | 267 | /// Clears all the samples in the object's output and internal processing 268 | /// buffers. 269 | virtual void clear(); 270 | 271 | /// Changes a setting controlling the processing system behaviour. See the 272 | /// 'SETTING_...' defines for available setting ID's. 273 | /// 274 | /// \return 'true' if the setting was succesfully changed 275 | bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. 276 | int value ///< New setting value. 277 | ); 278 | 279 | /// Reads a setting controlling the processing system behaviour. See the 280 | /// 'SETTING_...' defines for available setting ID's. 281 | /// 282 | /// \return the setting value. 283 | int getSetting(int settingId ///< Setting ID number, see SETTING_... defines. 284 | ) const; 285 | 286 | /// Returns number of samples currently unprocessed. 287 | virtual uint numUnprocessedSamples() const; 288 | 289 | 290 | /// Other handy functions that are implemented in the ancestor classes (see 291 | /// classes 'FIFOProcessor' and 'FIFOSamplePipe') 292 | /// 293 | /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. 294 | /// - numSamples() : Get number of 'ready' samples that can be received with 295 | /// function 'receiveSamples()' 296 | /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. 297 | /// - clear() : Clears all samples from ready/processing buffers. 298 | }; 299 | 300 | } 301 | #endif 302 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/include/soundtouch_config.h.in: -------------------------------------------------------------------------------- 1 | /* Use Float as Sample type */ 2 | #undef SOUNDTOUCH_FLOAT_SAMPLES 3 | 4 | /* Use Integer as Sample type */ 5 | #undef SOUNDTOUCH_INTEGER_SAMPLES 6 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/cpp/native-lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | // for opensles 5 | #include 6 | #include 7 | 8 | #include "SoundTouch.h" 9 | //打印日志 10 | #include 11 | #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"ywl5320",FORMAT,##__VA_ARGS__); 12 | #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"ywl5320",FORMAT,##__VA_ARGS__); 13 | 14 | // 引擎接口 15 | SLObjectItf engineObject = NULL; 16 | SLEngineItf engineEngine = NULL; 17 | 18 | //混音器 19 | SLObjectItf outputMixObject = NULL; 20 | SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL; 21 | SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; 22 | 23 | //pcm 24 | SLObjectItf pcmPlayerObject = NULL; 25 | SLPlayItf pcmPlayerPlay = NULL; 26 | SLVolumeItf pcmPlayerVolume = NULL; 27 | 28 | //缓冲器队列接口 29 | SLAndroidSimpleBufferQueueItf pcmBufferQueue; 30 | 31 | 32 | 33 | using namespace soundtouch; 34 | SoundTouch *soundTouch; 35 | FILE *pcmFile; 36 | SAMPLETYPE *sd_buffer; 37 | uint8_t *pcm_buffer; //用8位读取PCM数据 38 | //uint16_t *pcm_buffer; //用16位读取PCM数据 39 | 40 | void release() 41 | { 42 | 43 | if (pcmPlayerObject != NULL) { 44 | (*pcmPlayerObject)->Destroy(pcmPlayerObject); 45 | pcmPlayerObject = NULL; 46 | pcmPlayerPlay = NULL; 47 | pcmPlayerVolume = NULL; 48 | pcmBufferQueue = NULL; 49 | pcmFile = NULL; 50 | pcm_buffer = NULL; 51 | sd_buffer = NULL; 52 | } 53 | 54 | if (outputMixObject != NULL) { 55 | (*outputMixObject)->Destroy(outputMixObject); 56 | outputMixObject = NULL; 57 | outputMixEnvironmentalReverb = NULL; 58 | } 59 | 60 | if (engineObject != NULL) { 61 | (*engineObject)->Destroy(engineObject); 62 | engineObject = NULL; 63 | engineEngine = NULL; 64 | } 65 | } 66 | bool isfinish = true; 67 | int num = 0; 68 | int readPcmData() 69 | { 70 | int size = 0; 71 | while(!feof(pcmFile)) 72 | { 73 | if(isfinish) 74 | { 75 | isfinish = false; 76 | size = fread(pcm_buffer, 1, 4096 * 2, pcmFile); 77 | if(size > 0) 78 | { 79 | /** 80 | * 用uint_16来存储PCM数据,就不需要下面的转换。 81 | */ 82 | for (int i = 0; i < size / 2 + 1; i++) 83 | { 84 | sd_buffer[i] = (pcm_buffer[i * 2] | (pcm_buffer[i * 2 + 1] << 8)); 85 | } 86 | soundTouch->putSamples((const SAMPLETYPE *) pcm_buffer, size / 4); 87 | } else{ 88 | num = 0; 89 | soundTouch->clear(); 90 | } 91 | } 92 | num = soundTouch->receiveSamples(sd_buffer, size / 4); 93 | if(num == 0) 94 | { 95 | isfinish = true; 96 | continue; 97 | } 98 | return num; 99 | } 100 | return size; 101 | } 102 | 103 | void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void * context) 104 | { 105 | int size = readPcmData(); 106 | if(size > 0) 107 | { 108 | (*pcmBufferQueue)->Enqueue(pcmBufferQueue, sd_buffer, size * 4); 109 | } else{ 110 | LOGI("解码完成..."); 111 | } 112 | } 113 | 114 | 115 | extern "C" 116 | JNIEXPORT void JNICALL 117 | Java_ywl5320_com_soundtouchdemo_SoundTouch_playAudioByOpenSL_1pcm(JNIEnv *env, jobject instance, 118 | jstring pamPath_) { 119 | release(); 120 | const char *pamPath = env->GetStringUTFChars(pamPath_, 0); 121 | pcmFile = fopen(pamPath, "r"); 122 | if(pcmFile == NULL) 123 | { 124 | LOGE("%s", "fopen file error"); 125 | return; 126 | } 127 | pcm_buffer = (uint8_t *) malloc(4096 * 2 * 2); 128 | sd_buffer = (SAMPLETYPE *) malloc(4096 * 2 * 2); 129 | SLresult result; 130 | 131 | soundTouch = new SoundTouch(); 132 | soundTouch->setSampleRate(44100); // 设置采样率 133 | soundTouch->setChannels(2); // 设置通道数 134 | soundTouch->setTempo(1.5); 135 | // TODO 136 | //第一步,创建引擎 137 | result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 138 | result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 139 | result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); 140 | 141 | //第二步,创建混音器 142 | const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB}; 143 | const SLboolean mreq[1] = {SL_BOOLEAN_FALSE}; 144 | result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq); 145 | (void)result; 146 | result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 147 | (void)result; 148 | result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb); 149 | if (SL_RESULT_SUCCESS == result) { 150 | result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties( 151 | outputMixEnvironmentalReverb, &reverbSettings); 152 | (void)result; 153 | } 154 | SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; 155 | SLDataSink audioSnk = {&outputMix, NULL}; 156 | 157 | 158 | // 第三步,配置PCM格式信息 159 | SLDataLocator_AndroidSimpleBufferQueue android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2}; 160 | SLDataFormat_PCM pcm={ 161 | SL_DATAFORMAT_PCM,//播放pcm格式的数据 162 | 2,//2个声道(立体声) 163 | SL_SAMPLINGRATE_44_1,//44100hz的频率 164 | SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位 165 | SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行 166 | SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声(前左前右) 167 | SL_BYTEORDER_LITTLEENDIAN//结束标志 168 | }; 169 | SLDataSource slDataSource = {&android_queue, &pcm}; 170 | 171 | 172 | const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, SL_IID_VOLUME}; 173 | const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; 174 | 175 | result = (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 3, ids, req); 176 | //初始化播放器 177 | (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE); 178 | 179 | // 得到接口后调用 获取Player接口 180 | (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay); 181 | 182 | // 注册回调缓冲区 获取缓冲队列接口 183 | (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue); 184 | //缓冲接口回调 185 | (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, NULL); 186 | // 获取音量接口 187 | (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayerVolume); 188 | 189 | // 获取播放状态接口 190 | (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING); 191 | 192 | // 主动调用回调函数开始工作 193 | pcmBufferCallBack(pcmBufferQueue, NULL); 194 | 195 | env->ReleaseStringUTFChars(pamPath_, pamPath); 196 | } -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/java/ywl5320/com/soundtouchdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package ywl5320.com.soundtouchdemo; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.TextView; 7 | 8 | public class MainActivity extends AppCompatActivity { 9 | 10 | SoundTouch soundTouch; 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_main); 16 | soundTouch = new SoundTouch(); 17 | } 18 | 19 | public void play(View view) { 20 | soundTouch.playAudioByOpenSL_pcm("/mnt/shared/Other/mydream.pcm"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/java/ywl5320/com/soundtouchdemo/SoundTouch.java: -------------------------------------------------------------------------------- 1 | package ywl5320.com.soundtouchdemo; 2 | 3 | /** 4 | * Created by hlwky001 on 2018/3/19. 5 | */ 6 | 7 | public class SoundTouch { 8 | 9 | static { 10 | System.loadLibrary("native-lib"); 11 | } 12 | 13 | public native void playAudioByOpenSL_pcm(String pamPath); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 17 | 22 | 27 | 32 | 37 | 42 | 47 | 52 | 57 | 62 | 67 | 72 | 77 | 82 | 87 | 92 | 97 | 102 | 107 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /SoundTouchDemo/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |