├── 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 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/SoundTouchDemo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SoundTouchDemo
3 |
4 |
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SoundTouchDemo/app/src/test/java/ywl5320/com/soundtouchdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package ywl5320.com.soundtouchdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/SoundTouchDemo/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/SoundTouchDemo/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/SoundTouchDemo/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/SoundTouchDemo/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/SoundTouchDemo/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/pcm sounds/mydream.pcm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ywl5320/SoundTouch_OpenSL_Android/80c015b37c5fc214ce0103aa401a91237d1a4d48/pcm sounds/mydream.pcm
--------------------------------------------------------------------------------