Complete Implementation
|
@ -0,0 +1,97 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
||||
# [Android] ========================
|
||||
# Built application files
|
||||
*.apk
|
||||
*.ap_
|
||||
|
||||
# Files for the Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
|
||||
|
||||
# [Maven] ========================
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
|
||||
|
||||
# [Gradle-Android] ========================
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Gradle Signing
|
||||
signing.properties
|
||||
trestle.keystore
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# Misc
|
||||
/.idea/workspace.xml
|
||||
.DS_Store
|
||||
/captures
|
||||
**/*.iml
|
||||
*.class
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,34 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
defaultConfig {
|
||||
applicationId "com.mozilla.speechmodule"
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 27
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':mozillaspeechlibrary')
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
||||
implementation 'com.jjoe64:graphview:4.2.2'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,26 @@
|
|||
package com.mozilla.speechmodule;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.mozilla.speechmodule", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mozilla.speechmodule">
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
|
||||
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name="com.mozilla.speechapp.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,128 @@
|
|||
package com.mozilla.speechapp;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.jjoe64.graphview.GraphView;
|
||||
import com.jjoe64.graphview.series.DataPoint;
|
||||
import com.jjoe64.graphview.series.LineGraphSeries;
|
||||
import com.mozilla.speechlibrary.ISpeechRecognitionListener;
|
||||
import com.mozilla.speechlibrary.MozillaSpeechService;
|
||||
import com.mozilla.speechlibrary.STTResult;
|
||||
import com.mozilla.speechmodule.R;
|
||||
|
||||
import static android.support.constraint.Constraints.TAG;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements ISpeechRecognitionListener {
|
||||
|
||||
private Button mButtonStart, mButtonCancel;
|
||||
private MozillaSpeechService mMozillaSpeechService;
|
||||
private GraphView mGraph;
|
||||
private long mDtstart;
|
||||
private LineGraphSeries<DataPoint> mSeries1;
|
||||
private EditText mPlain_text_input;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
mMozillaSpeechService = MozillaSpeechService.getInstance();
|
||||
mMozillaSpeechService.addListener(this);
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
|
||||
123);
|
||||
}
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
124);
|
||||
}
|
||||
mButtonStart = findViewById(R.id.button_start);
|
||||
mButtonCancel = findViewById(R.id.button_cancel);
|
||||
|
||||
mPlain_text_input = findViewById(R.id.plain_text_input);
|
||||
mButtonStart.setOnClickListener((View v) -> {
|
||||
try {
|
||||
mDtstart = System.currentTimeMillis();
|
||||
mSeries1.resetData(new DataPoint[0]);
|
||||
mMozillaSpeechService.start(getApplicationContext());
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
mButtonCancel.setOnClickListener((View v) -> {
|
||||
try {
|
||||
mMozillaSpeechService.cancel();
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
mGraph = findViewById(R.id.graph);
|
||||
mSeries1 = new LineGraphSeries<>(new DataPoint[0]);
|
||||
mGraph.addSeries(mSeries1);
|
||||
mGraph.getViewport().setXAxisBoundsManual(true);
|
||||
mGraph.getViewport().setScalable(true);
|
||||
mGraph.getViewport().setScalableY(true);
|
||||
mGraph.getViewport().setScrollable(true); // enables horizontal scrolling
|
||||
mGraph.getViewport().setScrollableY(true); // enables vertical scrolling
|
||||
}
|
||||
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
public void onSpeechStatusChanged(MozillaSpeechService.SpeechState aState, Object aPayload){
|
||||
this.runOnUiThread(() -> {
|
||||
switch (aState) {
|
||||
case DECODING:
|
||||
mPlain_text_input.append("Decoding... \n");
|
||||
break;
|
||||
case MIC_ACTIVITY:
|
||||
long mPointx = System.currentTimeMillis() - mDtstart;
|
||||
mSeries1.appendData(new DataPoint(Math.round(mPointx) + 1, (double)aPayload * -1), true, 3000);
|
||||
break;
|
||||
case STT_RESULT:
|
||||
String message = String.format("Success: %s (%s)", ((STTResult)aPayload).mTranscription, ((STTResult)aPayload).mConfidence);
|
||||
mPlain_text_input.append(message + "\n");
|
||||
break;
|
||||
case START_LISTEN:
|
||||
mPlain_text_input.append("Started to listen\n");
|
||||
break;
|
||||
case NO_VOICE:
|
||||
mPlain_text_input.append("No Voice detected\n");
|
||||
break;
|
||||
case CANCELED:
|
||||
mPlain_text_input.append("Canceled\n");
|
||||
break;
|
||||
case ERROR:
|
||||
mPlain_text_input.append("Error:" + aPayload + " \n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
</vector>
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.mozilla.speechapp.MainActivity">
|
||||
<RelativeLayout
|
||||
android:id="@+id/InnerRelativeLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true" >
|
||||
|
||||
<com.jjoe64.graphview.GraphView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="200dip"
|
||||
android:id="@+id/graph"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/graph"
|
||||
android:text="Start" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/graph"
|
||||
android:layout_toEndOf="@+id/button_start"
|
||||
android:text="Cancel" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/plain_text_input"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_below="@+id/button_start"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:singleLine="false"
|
||||
android:gravity="top"
|
||||
android:inputType="textMultiLine"
|
||||
android:enabled="false" />
|
||||
</RelativeLayout>
|
||||
</android.support.constraint.ConstraintLayout>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
После Ширина: | Высота: | Размер: 3.0 KiB |
После Ширина: | Высота: | Размер: 4.9 KiB |
После Ширина: | Высота: | Размер: 2.0 KiB |
После Ширина: | Высота: | Размер: 2.8 KiB |
После Ширина: | Высота: | Размер: 4.5 KiB |
После Ширина: | Высота: | Размер: 6.9 KiB |
После Ширина: | Высота: | Размер: 6.3 KiB |
После Ширина: | Высота: | Размер: 10 KiB |
После Ширина: | Высота: | Размер: 9.0 KiB |
После Ширина: | Высота: | Размер: 15 KiB |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">Speech Module</string>
|
||||
</resources>
|
|
@ -0,0 +1,11 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,17 @@
|
|||
package com.mozilla.speechmodule;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
|
||||
|
||||
VERSION_NAME=1.0.1
|
||||
VERSION_CODE=1
|
||||
GROUP=com.github.mozilla
|
||||
|
||||
POM_DESCRIPTION=An Android library to Mozilla's speech recognition services
|
||||
POM_URL=https://github.com/mozilla/androidspeechlibrary
|
||||
POM_SCM_URL=https://github.com/mozilla/androidspeechlibrary
|
||||
POM_SCM_CONNECTION=scm:git@github.com:mozilla/androidspeechlibrary.git
|
||||
POM_SCM_DEV_CONNECTION=scm:git@github.com:mozilla/androidspeechlibrary.git
|
||||
POM_LICENCE_NAME=The Apache Software License, Version 2.0
|
||||
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
POM_LICENCE_DIST=repo
|
||||
POM_DEVELOPER_ID=anatal@gmail.com
|
||||
POM_DEVELOPER_NAME=Andre Natal
|
|
@ -0,0 +1,6 @@
|
|||
#Thu Aug 23 21:43:36 PDT 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
|
@ -0,0 +1,84 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,49 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply from: 'maven-push.gradle'
|
||||
|
||||
def versionMajor = 1
|
||||
def versionMinor = 0
|
||||
def versionPatch = 1
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 25
|
||||
versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch
|
||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path 'src/main/cpp/Android.mk'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'com.loopj.android:android-async-http:1.4.9'
|
||||
implementation 'com.android.support:appcompat-v7:25.4.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
api 'org.gagravarr:vorbis-java-core:0.8'
|
||||
api 'com.github.axet:opus:1.0.2'
|
||||
api 'com.github.axet:jssrc:1.0.2-2'
|
||||
api 'org.apache.commons:commons-math3:3.6.1'
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
POM_NAME=mozillaspeechlibrary
|
||||
POM_ARTIFACT_ID=mozillaspeechlibrary
|
||||
POM_PACKAGING=mozillaspeechlibrary
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2013 Chris Banes
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
def isReleaseBuild() {
|
||||
return VERSION_NAME.contains("SNAPSHOT") == false
|
||||
}
|
||||
|
||||
def getReleaseRepositoryUrl() {
|
||||
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
|
||||
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||
}
|
||||
|
||||
def getSnapshotRepositoryUrl() {
|
||||
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
|
||||
: "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
|
||||
def getRepositoryUsername() {
|
||||
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
|
||||
}
|
||||
|
||||
def getRepositoryPassword() {
|
||||
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
|
||||
}
|
||||
|
||||
afterEvaluate { project ->
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
pom.groupId = GROUP
|
||||
pom.artifactId = POM_ARTIFACT_ID
|
||||
pom.version = VERSION_NAME
|
||||
|
||||
repository(url: getReleaseRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||
}
|
||||
snapshotRepository(url: getSnapshotRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||
}
|
||||
|
||||
pom.project {
|
||||
name POM_NAME
|
||||
packaging POM_PACKAGING
|
||||
description POM_DESCRIPTION
|
||||
url POM_URL
|
||||
|
||||
scm {
|
||||
url POM_SCM_URL
|
||||
connection POM_SCM_CONNECTION
|
||||
developerConnection POM_SCM_DEV_CONNECTION
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name POM_LICENCE_NAME
|
||||
url POM_LICENCE_URL
|
||||
distribution POM_LICENCE_DIST
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id POM_DEVELOPER_ID
|
||||
name POM_DEVELOPER_NAME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
//task androidJavadocs(type: Javadoc) {
|
||||
//source = android.sourceSets.main.allJava
|
||||
//}
|
||||
|
||||
//task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
|
||||
//classifier = 'javadoc'
|
||||
//from androidJavadocs.destinationDir
|
||||
//}
|
||||
|
||||
task androidSourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from android.sourceSets.main.java.sourceFiles
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives androidSourcesJar
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,26 @@
|
|||
package com.mozilla.speechlibrary;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("com.mozilla.speechlibrary.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mozilla.speechlibrary" />
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
include $(call all-subdir-makefiles)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CFLAGS := -DWEBRTC_ANDROID -D__ARMEL__
|
||||
|
||||
LOCAL_MODULE := webrtc_jni
|
||||
LOCAL_SRC_FILES := webrtc_jni.c \
|
||||
webrtc/common_audio/vad/webrtc_vad.c \
|
||||
webrtc/common_audio/vad/vad_core.c \
|
||||
webrtc/common_audio/vad/vad_filterbank.c \
|
||||
webrtc/common_audio/vad/vad_gmm.c \
|
||||
webrtc/common_audio/vad/vad_sp.c \
|
||||
webrtc/common_audio/signal_processing/spl_init.c \
|
||||
webrtc/common_audio/signal_processing/division_operations.c \
|
||||
webrtc/common_audio/signal_processing/resample_48khz.c \
|
||||
webrtc/common_audio/signal_processing/energy.c \
|
||||
webrtc/common_audio/signal_processing/resample.c \
|
||||
webrtc/common_audio/signal_processing/resample_by_2.c \
|
||||
webrtc/common_audio/signal_processing/resample_fractional.c \
|
||||
webrtc/common_audio/signal_processing/resample_by_2_internal.c \
|
||||
webrtc/common_audio/signal_processing/spl_sqrt.c \
|
||||
webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
|
||||
webrtc/common_audio/signal_processing/vector_scaling_operations.c \
|
||||
webrtc/common_audio/signal_processing/real_fft.c \
|
||||
webrtc/common_audio/signal_processing/get_scaling_square.c \
|
||||
webrtc/common_audio/signal_processing/downsample_fast.c \
|
||||
webrtc/common_audio/signal_processing/complex_fft.c \
|
||||
webrtc/common_audio/signal_processing/cross_correlation.c \
|
||||
webrtc/common_audio/signal_processing/complex_bit_reverse.c \
|
||||
webrtc/common_audio/signal_processing/min_max_operations.c
|
||||
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_
|
||||
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <typedefs.h>
|
||||
|
||||
// List of features in x86.
|
||||
typedef enum {
|
||||
kSSE2,
|
||||
kSSE3
|
||||
} CPUFeature;
|
||||
|
||||
// List of features in ARM.
|
||||
enum {
|
||||
kCPUFeatureARMv7 = (1 << 0),
|
||||
kCPUFeatureVFPv3 = (1 << 1),
|
||||
kCPUFeatureNEON = (1 << 2),
|
||||
kCPUFeatureLDREXSTREX = (1 << 3)
|
||||
};
|
||||
|
||||
typedef int (*WebRtc_CPUInfo)(CPUFeature feature);
|
||||
|
||||
// Returns true if the CPU supports the feature.
|
||||
extern WebRtc_CPUInfo WebRtc_GetCPUInfo;
|
||||
|
||||
// No CPU feature is available => straight C path.
|
||||
extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM;
|
||||
|
||||
// Return the features in an ARM device.
|
||||
// It detects the features in the hardware platform, and returns supported
|
||||
// values in the above enum definition as a bitmask.
|
||||
extern uint64_t WebRtc_GetCPUFeaturesARM(void);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This header file includes the inline functions in
|
||||
// the fix point signal processing library.
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_H_
|
||||
#define WEBRTC_SPL_SPL_INL_H_
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7A
|
||||
#include "spl_inl_armv7.h"
|
||||
#else
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_SatW32ToW16(WebRtc_Word32 value32) {
|
||||
WebRtc_Word16 out16 = (WebRtc_Word16) value32;
|
||||
|
||||
if (value32 > 32767)
|
||||
out16 = 32767;
|
||||
else if (value32 < -32768)
|
||||
out16 = -32768;
|
||||
|
||||
return out16;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a,
|
||||
WebRtc_Word16 b) {
|
||||
return WebRtcSpl_SatW32ToW16((WebRtc_Word32) a + (WebRtc_Word32) b);
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WebRtcSpl_AddSatW32(WebRtc_Word32 l_var1,
|
||||
WebRtc_Word32 l_var2) {
|
||||
WebRtc_Word32 l_sum;
|
||||
|
||||
// perform long addition
|
||||
l_sum = l_var1 + l_var2;
|
||||
|
||||
// check for under or overflow
|
||||
if (WEBRTC_SPL_IS_NEG(l_var1)) {
|
||||
if (WEBRTC_SPL_IS_NEG(l_var2) && !WEBRTC_SPL_IS_NEG(l_sum)) {
|
||||
l_sum = (WebRtc_Word32)0x80000000;
|
||||
}
|
||||
} else {
|
||||
if (!WEBRTC_SPL_IS_NEG(l_var2) && WEBRTC_SPL_IS_NEG(l_sum)) {
|
||||
l_sum = (WebRtc_Word32)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_SubSatW16(WebRtc_Word16 var1,
|
||||
WebRtc_Word16 var2) {
|
||||
return WebRtcSpl_SatW32ToW16((WebRtc_Word32) var1 - (WebRtc_Word32) var2);
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WebRtcSpl_SubSatW32(WebRtc_Word32 l_var1,
|
||||
WebRtc_Word32 l_var2) {
|
||||
WebRtc_Word32 l_diff;
|
||||
|
||||
// perform subtraction
|
||||
l_diff = l_var1 - l_var2;
|
||||
|
||||
// check for underflow
|
||||
if ((l_var1 < 0) && (l_var2 > 0) && (l_diff > 0))
|
||||
l_diff = (WebRtc_Word32)0x80000000;
|
||||
// check for overflow
|
||||
if ((l_var1 > 0) && (l_var2 < 0) && (l_diff < 0))
|
||||
l_diff = (WebRtc_Word32)0x7FFFFFFF;
|
||||
|
||||
return l_diff;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_GetSizeInBits(WebRtc_UWord32 n) {
|
||||
int bits;
|
||||
|
||||
if (0xFFFF0000 & n) {
|
||||
bits = 16;
|
||||
} else {
|
||||
bits = 0;
|
||||
}
|
||||
if (0x0000FF00 & (n >> bits)) bits += 8;
|
||||
if (0x000000F0 & (n >> bits)) bits += 4;
|
||||
if (0x0000000C & (n >> bits)) bits += 2;
|
||||
if (0x00000002 & (n >> bits)) bits += 1;
|
||||
if (0x00000001 & (n >> bits)) bits += 1;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW32(WebRtc_Word32 a) {
|
||||
int zeros;
|
||||
|
||||
if (a <= 0) a ^= 0xFFFFFFFF;
|
||||
|
||||
if (!(0xFFFF8000 & a)) {
|
||||
zeros = 16;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xFF800000 & (a << zeros))) zeros += 8;
|
||||
if (!(0xF8000000 & (a << zeros))) zeros += 4;
|
||||
if (!(0xE0000000 & (a << zeros))) zeros += 2;
|
||||
if (!(0xC0000000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormU32(WebRtc_UWord32 a) {
|
||||
int zeros;
|
||||
|
||||
if (a == 0) return 0;
|
||||
|
||||
if (!(0xFFFF0000 & a)) {
|
||||
zeros = 16;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xFF000000 & (a << zeros))) zeros += 8;
|
||||
if (!(0xF0000000 & (a << zeros))) zeros += 4;
|
||||
if (!(0xC0000000 & (a << zeros))) zeros += 2;
|
||||
if (!(0x80000000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW16(WebRtc_Word16 a) {
|
||||
int zeros;
|
||||
|
||||
if (a <= 0) a ^= 0xFFFF;
|
||||
|
||||
if (!(0xFF80 & a)) {
|
||||
zeros = 8;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xF800 & (a << zeros))) zeros += 4;
|
||||
if (!(0xE000 & (a << zeros))) zeros += 2;
|
||||
if (!(0xC000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a,
|
||||
int16_t b,
|
||||
int32_t c) {
|
||||
return (a * b + c);
|
||||
}
|
||||
|
||||
#endif // WEBRTC_ARCH_ARM_V7A
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_H_
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This header file includes the inline functions for ARM processors in
|
||||
// the fix point signal processing library.
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_ARMV7_H_
|
||||
#define WEBRTC_SPL_SPL_INL_ARMV7_H_
|
||||
|
||||
static __inline WebRtc_Word32 WEBRTC_SPL_MUL_16_32_RSFT16(WebRtc_Word16 a,
|
||||
WebRtc_Word32 b) {
|
||||
WebRtc_Word32 tmp;
|
||||
__asm__("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WEBRTC_SPL_MUL_32_32_RSFT32(WebRtc_Word16 a,
|
||||
WebRtc_Word16 b,
|
||||
WebRtc_Word32 c) {
|
||||
WebRtc_Word32 tmp;
|
||||
__asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(tmp) : "r"(b), "r"(a));
|
||||
__asm__("smmul %0, %1, %2":"=r"(tmp):"r"(tmp), "r"(c));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WEBRTC_SPL_MUL_32_32_RSFT32BI(WebRtc_Word32 a,
|
||||
WebRtc_Word32 b) {
|
||||
WebRtc_Word32 tmp;
|
||||
__asm__("smmul %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WEBRTC_SPL_MUL_16_16(WebRtc_Word16 a,
|
||||
WebRtc_Word16 b) {
|
||||
WebRtc_Word32 tmp;
|
||||
__asm__("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a,
|
||||
int16_t b,
|
||||
int32_t c) {
|
||||
int32_t tmp = 0;
|
||||
__asm__("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a,
|
||||
WebRtc_Word16 b) {
|
||||
WebRtc_Word32 s_sum;
|
||||
|
||||
__asm__("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b));
|
||||
|
||||
return (WebRtc_Word16) s_sum;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WebRtcSpl_AddSatW32(WebRtc_Word32 l_var1,
|
||||
WebRtc_Word32 l_var2) {
|
||||
WebRtc_Word32 l_sum;
|
||||
|
||||
__asm__("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2));
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_SubSatW16(WebRtc_Word16 var1,
|
||||
WebRtc_Word16 var2) {
|
||||
WebRtc_Word32 s_sub;
|
||||
|
||||
__asm__("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2));
|
||||
|
||||
return (WebRtc_Word16)s_sub;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word32 WebRtcSpl_SubSatW32(WebRtc_Word32 l_var1,
|
||||
WebRtc_Word32 l_var2) {
|
||||
WebRtc_Word32 l_sub;
|
||||
|
||||
__asm__("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2));
|
||||
|
||||
return l_sub;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_GetSizeInBits(WebRtc_UWord32 n) {
|
||||
WebRtc_Word32 tmp;
|
||||
|
||||
__asm__("clz %0, %1":"=r"(tmp):"r"(n));
|
||||
|
||||
return (WebRtc_Word16)(32 - tmp);
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW32(WebRtc_Word32 a) {
|
||||
WebRtc_Word32 tmp;
|
||||
|
||||
if (a <= 0) a ^= 0xFFFFFFFF;
|
||||
|
||||
__asm__("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return tmp - 1;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormU32(WebRtc_UWord32 a) {
|
||||
int tmp;
|
||||
|
||||
if (a == 0) return 0;
|
||||
|
||||
__asm__("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW16(WebRtc_Word16 a) {
|
||||
WebRtc_Word32 tmp;
|
||||
|
||||
if (a <= 0) a ^= 0xFFFFFFFF;
|
||||
|
||||
__asm__("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return tmp - 17;
|
||||
}
|
||||
|
||||
static __inline WebRtc_Word16 WebRtcSpl_SatW32ToW16(WebRtc_Word32 value32) {
|
||||
WebRtc_Word16 out16;
|
||||
|
||||
__asm__("ssat %0, #16, %1" : "=r"(out16) : "r"(value32));
|
||||
|
||||
return out16;
|
||||
}
|
||||
#endif // WEBRTC_SPL_SPL_INL_ARMV7_H_
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// This file contains platform-specific typedefs and defines.
|
||||
|
||||
#ifndef WEBRTC_TYPEDEFS_H_
|
||||
#define WEBRTC_TYPEDEFS_H_
|
||||
|
||||
// Reserved words definitions
|
||||
// TODO(andrew): Look at removing these.
|
||||
#define WEBRTC_EXTERN extern
|
||||
#define G_CONST const
|
||||
#define WEBRTC_INLINE extern __inline
|
||||
|
||||
// Define WebRTC preprocessor identifiers based on the current build platform.
|
||||
// TODO(andrew): Clean these up. We can probably remove everything in this
|
||||
// block.
|
||||
// - TARGET_MAC_INTEL and TARGET_MAC aren't used anywhere.
|
||||
// - In the few places where TARGET_PC is used, it should be replaced by
|
||||
// something more specific.
|
||||
// - Do we really support PowerPC? Probably not. Remove WEBRTC_MAC_INTEL
|
||||
// from build/common.gypi as well.
|
||||
#if defined(WIN32)
|
||||
// Windows & Windows Mobile.
|
||||
#if !defined(WEBRTC_TARGET_PC)
|
||||
#define WEBRTC_TARGET_PC
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
// Mac OS X.
|
||||
#if defined(__LITTLE_ENDIAN__ )
|
||||
#if !defined(WEBRTC_TARGET_MAC_INTEL)
|
||||
#define WEBRTC_TARGET_MAC_INTEL
|
||||
#endif
|
||||
#else
|
||||
#if !defined(WEBRTC_TARGET_MAC)
|
||||
#define WEBRTC_TARGET_MAC
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
// Linux etc.
|
||||
#if !defined(WEBRTC_TARGET_PC)
|
||||
#define WEBRTC_TARGET_PC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Derived from Chromium's build/build_config.h
|
||||
// Processor architecture detection. For more info on what's defined, see:
|
||||
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
|
||||
// http://www.agner.org/optimize/calling_conventions.pdf
|
||||
// or with gcc, run: "echo | gcc -E -dM -"
|
||||
// TODO(andrew): replace WEBRTC_LITTLE_ENDIAN with WEBRTC_ARCH_LITTLE_ENDIAN?
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define WEBRTC_ARCH_X86_FAMILY
|
||||
#define WEBRTC_ARCH_X86_64
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
#define WEBRTC_ARCH_X86_FAMILY
|
||||
#define WEBRTC_ARCH_X86
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__ARMEL__)
|
||||
// TODO(andrew): We'd prefer to control platform defines here, but this is
|
||||
// currently provided by the Android makefiles. Commented to avoid duplicate
|
||||
// definition warnings.
|
||||
//#define WEBRTC_ARCH_ARM
|
||||
// TODO(andrew): Chromium uses the following two defines. Should we switch?
|
||||
//#define WEBRTC_ARCH_ARM_FAMILY
|
||||
//#define WEBRTC_ARCH_ARMEL
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__mips__)
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#else
|
||||
#error Please add support for your architecture in typedefs.h
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__) || defined(_MSC_VER)
|
||||
#define WEBRTC_USE_SSE2
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_TARGET_PC)
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
// Define C99 equivalent types.
|
||||
// Since MSVC doesn't include these headers, we have to write our own
|
||||
// version to provide a compatibility layer between MSVC and the WebRTC
|
||||
// headers.
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef __int64 WebRtc_Word64;
|
||||
typedef unsigned __int64 WebRtc_UWord64;
|
||||
#else
|
||||
typedef int64_t WebRtc_Word64;
|
||||
typedef uint64_t WebRtc_UWord64;
|
||||
#endif
|
||||
typedef int32_t WebRtc_Word32;
|
||||
typedef uint32_t WebRtc_UWord32;
|
||||
typedef int16_t WebRtc_Word16;
|
||||
typedef uint16_t WebRtc_UWord16;
|
||||
typedef char WebRtc_Word8;
|
||||
typedef uint8_t WebRtc_UWord8;
|
||||
|
||||
// Define endian for the platform
|
||||
#define WEBRTC_LITTLE_ENDIAN
|
||||
|
||||
#elif defined(WEBRTC_TARGET_MAC_INTEL)
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int64_t WebRtc_Word64;
|
||||
typedef uint64_t WebRtc_UWord64;
|
||||
typedef int32_t WebRtc_Word32;
|
||||
typedef uint32_t WebRtc_UWord32;
|
||||
typedef int16_t WebRtc_Word16;
|
||||
typedef char WebRtc_Word8;
|
||||
typedef uint16_t WebRtc_UWord16;
|
||||
typedef uint8_t WebRtc_UWord8;
|
||||
|
||||
// Define endian for the platform
|
||||
#define WEBRTC_LITTLE_ENDIAN
|
||||
|
||||
#else
|
||||
#error "No platform defined for WebRTC type definitions (typedefs.h)"
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_TYPEDEFS_H_
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "include/audio_util.h"
|
||||
|
||||
#include "include/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void Deinterleave(const int16_t* interleaved, int samples_per_channel,
|
||||
int num_channels, int16_t** deinterleaved) {
|
||||
for (int i = 0; i < num_channels; i++) {
|
||||
int16_t* channel = deinterleaved[i];
|
||||
int interleaved_idx = i;
|
||||
for (int j = 0; j < samples_per_channel; j++) {
|
||||
channel[j] = interleaved[interleaved_idx];
|
||||
interleaved_idx += num_channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interleave(const int16_t* const* deinterleaved, int samples_per_channel,
|
||||
int num_channels, int16_t* interleaved) {
|
||||
for (int i = 0; i < num_channels; ++i) {
|
||||
const int16_t* channel = deinterleaved[i];
|
||||
int interleaved_idx = i;
|
||||
for (int j = 0; j < samples_per_channel; j++) {
|
||||
interleaved[interleaved_idx] = channel[j];
|
||||
interleaved_idx += num_channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
|
||||
#define WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Clamp the floating |value| to the range representable by an int16_t.
|
||||
static inline float ClampInt16(float value) {
|
||||
const float kMaxInt16 = 32767.f;
|
||||
const float kMinInt16 = -32768.f;
|
||||
return value < kMinInt16 ? kMinInt16 :
|
||||
(value > kMaxInt16 ? kMaxInt16 : value);
|
||||
}
|
||||
|
||||
// Return a rounded int16_t of the floating |value|. Doesn't handle overflow;
|
||||
// use ClampInt16 if necessary.
|
||||
static inline int16_t RoundToInt16(float value) {
|
||||
return static_cast<int16_t>(value < 0.f ? value - 0.5f : value + 0.5f);
|
||||
}
|
||||
|
||||
// Deinterleave audio from |interleaved| to the channel buffers pointed to
|
||||
// by |deinterleaved|. There must be sufficient space allocated in the
|
||||
// |deinterleaved| buffers (|num_channel| buffers with |samples_per_channel|
|
||||
// per buffer).
|
||||
void Deinterleave(const int16_t* interleaved, int samples_per_channel,
|
||||
int num_channels, int16_t** deinterleaved);
|
||||
|
||||
// Interleave audio from the channel buffers pointed to by |deinterleaved| to
|
||||
// |interleaved|. There must be sufficient space allocated in |interleaved|
|
||||
// (|samples_per_channel| * |num_channels|).
|
||||
void Interleave(const int16_t* const* deinterleaved, int samples_per_channel,
|
||||
int num_channels, int16_t* interleaved);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// This file contains platform-specific typedefs and defines.
|
||||
// Much of it is derived from Chromium's build/build_config.h.
|
||||
|
||||
#ifndef WEBRTC_TYPEDEFS_H_
|
||||
#define WEBRTC_TYPEDEFS_H_
|
||||
|
||||
// For access to standard POSIXish features, use WEBRTC_POSIX instead of a
|
||||
// more specific macro.
|
||||
#if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX) || \
|
||||
defined(WEBRTC_ANDROID)
|
||||
#define WEBRTC_POSIX
|
||||
#endif
|
||||
|
||||
// Processor architecture detection. For more info on what's defined, see:
|
||||
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
|
||||
// http://www.agner.org/optimize/calling_conventions.pdf
|
||||
// or with gcc, run: "echo | gcc -E -dM -"
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define WEBRTC_ARCH_X86_FAMILY
|
||||
#define WEBRTC_ARCH_X86_64
|
||||
#define WEBRTC_ARCH_64_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
#define WEBRTC_ARCH_X86_FAMILY
|
||||
#define WEBRTC_ARCH_X86
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__ARMEL__)
|
||||
// TODO(ajm): We'd prefer to control platform defines here, but this is
|
||||
// currently provided by the Android makefiles. Commented to avoid duplicate
|
||||
// definition warnings.
|
||||
//#define WEBRTC_ARCH_ARM
|
||||
// TODO(ajm): Chromium uses the following two defines. Should we switch?
|
||||
//#define WEBRTC_ARCH_ARM_FAMILY
|
||||
//#define WEBRTC_ARCH_ARMEL
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#elif defined(__MIPSEL__)
|
||||
#define WEBRTC_ARCH_32_BITS
|
||||
#define WEBRTC_ARCH_LITTLE_ENDIAN
|
||||
#else
|
||||
#error Please add support for your architecture in typedefs.h
|
||||
#endif
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_LITTLE_ENDIAN) ^ defined(WEBRTC_ARCH_BIG_ENDIAN))
|
||||
#error Define either WEBRTC_ARCH_LITTLE_ENDIAN or WEBRTC_ARCH_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__) || defined(_MSC_VER)
|
||||
#define WEBRTC_USE_SSE2
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
// Define C99 equivalent types, since MSVC doesn't provide stdint.h.
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
|
||||
// Borrowed from Chromium's base/compiler_specific.h.
|
||||
// Annotate a virtual method indicating it must be overriding a virtual
|
||||
// method in the parent class.
|
||||
// Use like:
|
||||
// virtual void foo() OVERRIDE;
|
||||
#if defined(_MSC_VER)
|
||||
#define OVERRIDE override
|
||||
#elif defined(__clang__)
|
||||
// Clang defaults to C++03 and warns about using override. Squelch that.
|
||||
// Intentionally no push/pop here so all users of OVERRIDE ignore the warning
|
||||
// too. This is like passing -Wno-c++11-extensions, except that GCC won't die
|
||||
// (because it won't see this pragma).
|
||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
#define OVERRIDE override
|
||||
#elif defined(__GNUC__) && __cplusplus >= 201103 && \
|
||||
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700
|
||||
// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled.
|
||||
#define OVERRIDE override
|
||||
#else
|
||||
#define OVERRIDE
|
||||
#endif
|
||||
|
||||
// Annotate a function indicating the caller must examine the return value.
|
||||
// Use like:
|
||||
// int foo() WARN_UNUSED_RESULT;
|
||||
// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
|
||||
// libjingle are merged.
|
||||
#if !defined(WARN_UNUSED_RESULT)
|
||||
#if defined(__GNUC__)
|
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define WARN_UNUSED_RESULT
|
||||
#endif
|
||||
#endif // WARN_UNUSED_RESULT
|
||||
|
||||
#endif // WEBRTC_TYPEDEFS_H_
|
|
@ -0,0 +1,126 @@
|
|||
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
include $(LOCAL_PATH)/../../../android-webrtc.mk
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
|
||||
LOCAL_MODULE := libwebrtc_spl
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_SRC_FILES := \
|
||||
auto_corr_to_refl_coef.c \
|
||||
auto_correlation.c \
|
||||
complex_fft.c \
|
||||
copy_set_operations.c \
|
||||
cross_correlation.c \
|
||||
division_operations.c \
|
||||
dot_product_with_scale.c \
|
||||
downsample_fast.c \
|
||||
energy.c \
|
||||
filter_ar.c \
|
||||
filter_ma_fast_q12.c \
|
||||
get_hanning_window.c \
|
||||
get_scaling_square.c \
|
||||
ilbc_specific_functions.c \
|
||||
levinson_durbin.c \
|
||||
lpc_to_refl_coef.c \
|
||||
min_max_operations.c \
|
||||
randomization_functions.c \
|
||||
real_fft.c \
|
||||
refl_coef_to_lpc.c \
|
||||
resample.c \
|
||||
resample_48khz.c \
|
||||
resample_by_2.c \
|
||||
resample_by_2_internal.c \
|
||||
resample_fractional.c \
|
||||
spl_init.c \
|
||||
spl_sqrt.c \
|
||||
spl_version.c \
|
||||
splitting_filter.c \
|
||||
sqrt_of_one_minus_x_squared.c \
|
||||
vector_scaling_operations.c
|
||||
|
||||
# Flags passed to both C and C++ files.
|
||||
LOCAL_CFLAGS := \
|
||||
$(MY_WEBRTC_COMMON_DEFS)
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/include \
|
||||
$(LOCAL_PATH)/../.. \
|
||||
external/webrtc
|
||||
|
||||
ifeq ($(ARCH_ARM_HAVE_ARMV7A),true)
|
||||
LOCAL_SRC_FILES += \
|
||||
filter_ar_fast_q12_armv7.S
|
||||
else
|
||||
LOCAL_SRC_FILES += \
|
||||
filter_ar_fast_q12.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
LOCAL_SRC_FILES += \
|
||||
complex_bit_reverse_arm.S \
|
||||
spl_sqrt_floor_arm.S
|
||||
else
|
||||
LOCAL_SRC_FILES += \
|
||||
complex_bit_reverse.c \
|
||||
spl_sqrt_floor.c
|
||||
endif
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := libstlport
|
||||
|
||||
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
|
||||
LOCAL_LDLIBS += -ldl -lpthread
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
endif
|
||||
|
||||
ifndef NDK_ROOT
|
||||
include external/stlport/libstlport.mk
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
#########################
|
||||
# Build the neon library.
|
||||
ifeq ($(WEBRTC_BUILD_NEON_LIBS),true)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
|
||||
LOCAL_MODULE := libwebrtc_spl_neon
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_SRC_FILES := \
|
||||
cross_correlation_neon.S \
|
||||
downsample_fast_neon.S \
|
||||
min_max_operations_neon.S \
|
||||
vector_scaling_operations_neon.S
|
||||
|
||||
# Flags passed to both C and C++ files.
|
||||
LOCAL_CFLAGS := \
|
||||
$(MY_WEBRTC_COMMON_DEFS) \
|
||||
$(MY_ARM_CFLAGS_NEON)
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/include \
|
||||
$(LOCAL_PATH)/../.. \
|
||||
external/webrtc
|
||||
|
||||
ifndef NDK_ROOT
|
||||
include external/stlport/libstlport.mk
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
endif # ifeq ($(WEBRTC_BUILD_NEON_LIBS),true)
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
/* Tables for data buffer indexes that are bit reversed and thus need to be
|
||||
* swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap
|
||||
* operations, while index_7[{1, 3, 5, ...}] are for the right side of the
|
||||
* operation. Same for index_8.
|
||||
*/
|
||||
|
||||
/* Indexes for the case of stages == 7. */
|
||||
static const int16_t index_7[112] = {
|
||||
1, 64, 2, 32, 3, 96, 4, 16, 5, 80, 6, 48, 7, 112, 9, 72, 10, 40, 11, 104,
|
||||
12, 24, 13, 88, 14, 56, 15, 120, 17, 68, 18, 36, 19, 100, 21, 84, 22, 52,
|
||||
23, 116, 25, 76, 26, 44, 27, 108, 29, 92, 30, 60, 31, 124, 33, 66, 35, 98,
|
||||
37, 82, 38, 50, 39, 114, 41, 74, 43, 106, 45, 90, 46, 58, 47, 122, 49, 70,
|
||||
51, 102, 53, 86, 55, 118, 57, 78, 59, 110, 61, 94, 63, 126, 67, 97, 69,
|
||||
81, 71, 113, 75, 105, 77, 89, 79, 121, 83, 101, 87, 117, 91, 109, 95, 125,
|
||||
103, 115, 111, 123
|
||||
};
|
||||
|
||||
/* Indexes for the case of stages == 8. */
|
||||
static const int16_t index_8[240] = {
|
||||
1, 128, 2, 64, 3, 192, 4, 32, 5, 160, 6, 96, 7, 224, 8, 16, 9, 144, 10, 80,
|
||||
11, 208, 12, 48, 13, 176, 14, 112, 15, 240, 17, 136, 18, 72, 19, 200, 20,
|
||||
40, 21, 168, 22, 104, 23, 232, 25, 152, 26, 88, 27, 216, 28, 56, 29, 184,
|
||||
30, 120, 31, 248, 33, 132, 34, 68, 35, 196, 37, 164, 38, 100, 39, 228, 41,
|
||||
148, 42, 84, 43, 212, 44, 52, 45, 180, 46, 116, 47, 244, 49, 140, 50, 76,
|
||||
51, 204, 53, 172, 54, 108, 55, 236, 57, 156, 58, 92, 59, 220, 61, 188, 62,
|
||||
124, 63, 252, 65, 130, 67, 194, 69, 162, 70, 98, 71, 226, 73, 146, 74, 82,
|
||||
75, 210, 77, 178, 78, 114, 79, 242, 81, 138, 83, 202, 85, 170, 86, 106, 87,
|
||||
234, 89, 154, 91, 218, 93, 186, 94, 122, 95, 250, 97, 134, 99, 198, 101,
|
||||
166, 103, 230, 105, 150, 107, 214, 109, 182, 110, 118, 111, 246, 113, 142,
|
||||
115, 206, 117, 174, 119, 238, 121, 158, 123, 222, 125, 190, 127, 254, 131,
|
||||
193, 133, 161, 135, 225, 137, 145, 139, 209, 141, 177, 143, 241, 147, 201,
|
||||
149, 169, 151, 233, 155, 217, 157, 185, 159, 249, 163, 197, 167, 229, 171,
|
||||
213, 173, 181, 175, 245, 179, 205, 183, 237, 187, 221, 191, 253, 199, 227,
|
||||
203, 211, 207, 243, 215, 235, 223, 251, 239, 247
|
||||
};
|
||||
|
||||
void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages) {
|
||||
/* For any specific value of stages, we know exactly the indexes that are
|
||||
* bit reversed. Currently (Feb. 2012) in WebRTC the only possible values of
|
||||
* stages are 7 and 8, so we use tables to save unnecessary iterations and
|
||||
* calculations for these two cases.
|
||||
*/
|
||||
if (stages == 7 || stages == 8) {
|
||||
int m = 0;
|
||||
int length = 112;
|
||||
const int16_t* index = index_7;
|
||||
|
||||
if (stages == 8) {
|
||||
length = 240;
|
||||
index = index_8;
|
||||
}
|
||||
|
||||
/* Decimation in time. Swap the elements with bit-reversed indexes. */
|
||||
for (m = 0; m < length; m += 2) {
|
||||
/* We declare a int32_t* type pointer, to load both the 16-bit real
|
||||
* and imaginary elements from complex_data in one instruction, reducing
|
||||
* complexity.
|
||||
*/
|
||||
int32_t* complex_data_ptr = (int32_t*)complex_data;
|
||||
int32_t temp = 0;
|
||||
|
||||
temp = complex_data_ptr[index[m]]; /* Real and imaginary */
|
||||
complex_data_ptr[index[m]] = complex_data_ptr[index[m + 1]];
|
||||
complex_data_ptr[index[m + 1]] = temp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int m = 0, mr = 0, l = 0;
|
||||
int n = 1 << stages;
|
||||
int nn = n - 1;
|
||||
|
||||
/* Decimation in time - re-order data */
|
||||
for (m = 1; m <= nn; ++m) {
|
||||
int32_t* complex_data_ptr = (int32_t*)complex_data;
|
||||
int32_t temp = 0;
|
||||
|
||||
/* Find out indexes that are bit-reversed. */
|
||||
l = n;
|
||||
do {
|
||||
l >>= 1;
|
||||
} while (l > nn - mr);
|
||||
mr = (mr & (l - 1)) + l;
|
||||
|
||||
if (mr <= m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Swap the elements with bit-reversed indexes.
|
||||
* This is similar to the loop in the stages == 7 or 8 cases.
|
||||
*/
|
||||
temp = complex_data_ptr[m]; /* Real and imaginary */
|
||||
complex_data_ptr[m] = complex_data_ptr[mr];
|
||||
complex_data_ptr[mr] = temp;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_ComplexFFT().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "complex_fft_tables.h"
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
#define CFFTSFT 14
|
||||
#define CFFTRND 1
|
||||
#define CFFTRND2 16384
|
||||
|
||||
#define CIFFTSFT 14
|
||||
#define CIFFTRND 1
|
||||
|
||||
|
||||
int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode)
|
||||
{
|
||||
int i, j, l, k, istep, n, m;
|
||||
int16_t wr, wi;
|
||||
int32_t tr32, ti32, qr32, qi32;
|
||||
|
||||
/* The 1024-value is a constant given from the size of kSinTable1024[],
|
||||
* and should not be changed depending on the input parameter 'stages'
|
||||
*/
|
||||
n = 1 << stages;
|
||||
if (n > 1024)
|
||||
return -1;
|
||||
|
||||
l = 1;
|
||||
k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
|
||||
depending on the input parameter 'stages' */
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
// mode==0: Low-complexity and Low-accuracy mode
|
||||
while (l < n)
|
||||
{
|
||||
istep = l << 1;
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = -kSinTable1024[j];
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
|
||||
- WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15);
|
||||
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
|
||||
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15);
|
||||
|
||||
qr32 = (int32_t)frfi[2 * i];
|
||||
qi32 = (int32_t)frfi[2 * i + 1];
|
||||
frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1);
|
||||
frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1);
|
||||
frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1);
|
||||
frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1);
|
||||
}
|
||||
}
|
||||
|
||||
--k;
|
||||
l = istep;
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
// mode==1: High-complexity and High-accuracy mode
|
||||
while (l < n)
|
||||
{
|
||||
istep = l << 1;
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = -kSinTable1024[j];
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
int32_t wri = 0;
|
||||
int32_t frfi_r = 0;
|
||||
__asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
|
||||
"r"((int32_t)wr), "r"((int32_t)wi));
|
||||
#endif
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
__asm __volatile(
|
||||
"pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
|
||||
"smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
|
||||
"smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t"
|
||||
:[frfi_r]"+r"(frfi_r),
|
||||
[tr32]"=r"(tr32),
|
||||
[ti32]"=r"(ti32)
|
||||
:[frfi_even]"r"((int32_t)frfi[2*j]),
|
||||
[frfi_odd]"r"((int32_t)frfi[2*j +1]),
|
||||
[wri]"r"(wri),
|
||||
[cfftrnd]"r"(CFFTRND)
|
||||
);
|
||||
|
||||
#else
|
||||
tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
|
||||
- WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CFFTRND;
|
||||
|
||||
ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
|
||||
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND;
|
||||
#endif
|
||||
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT);
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT);
|
||||
|
||||
qr32 = ((int32_t)frfi[2 * i]) << CFFTSFT;
|
||||
qi32 = ((int32_t)frfi[2 * i + 1]) << CFFTSFT;
|
||||
|
||||
frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qr32 - tr32 + CFFTRND2), 1 + CFFTSFT);
|
||||
frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 - ti32 + CFFTRND2), 1 + CFFTSFT);
|
||||
frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qr32 + tr32 + CFFTRND2), 1 + CFFTSFT);
|
||||
frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 + ti32 + CFFTRND2), 1 + CFFTSFT);
|
||||
}
|
||||
}
|
||||
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode)
|
||||
{
|
||||
int i, j, l, k, istep, n, m, scale, shift;
|
||||
int16_t wr, wi;
|
||||
int32_t tr32, ti32, qr32, qi32;
|
||||
int32_t tmp32, round2;
|
||||
|
||||
/* The 1024-value is a constant given from the size of kSinTable1024[],
|
||||
* and should not be changed depending on the input parameter 'stages'
|
||||
*/
|
||||
n = 1 << stages;
|
||||
if (n > 1024)
|
||||
return -1;
|
||||
|
||||
scale = 0;
|
||||
|
||||
l = 1;
|
||||
k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change
|
||||
depending on the input parameter 'stages' */
|
||||
|
||||
while (l < n)
|
||||
{
|
||||
// variable scaling, depending upon data
|
||||
shift = 0;
|
||||
round2 = 8192;
|
||||
|
||||
tmp32 = (int32_t)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n);
|
||||
if (tmp32 > 13573)
|
||||
{
|
||||
shift++;
|
||||
scale++;
|
||||
round2 <<= 1;
|
||||
}
|
||||
if (tmp32 > 27146)
|
||||
{
|
||||
shift++;
|
||||
scale++;
|
||||
round2 <<= 1;
|
||||
}
|
||||
|
||||
istep = l << 1;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
// mode==0: Low-complexity and Low-accuracy mode
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = kSinTable1024[j];
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0)
|
||||
- WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15);
|
||||
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32(
|
||||
(WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0)
|
||||
+ WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15);
|
||||
|
||||
qr32 = (int32_t)frfi[2 * i];
|
||||
qi32 = (int32_t)frfi[2 * i + 1];
|
||||
frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift);
|
||||
frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift);
|
||||
frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift);
|
||||
frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift);
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
// mode==1: High-complexity and High-accuracy mode
|
||||
|
||||
for (m = 0; m < l; ++m)
|
||||
{
|
||||
j = m << k;
|
||||
|
||||
/* The 256-value is a constant given as 1/4 of the size of
|
||||
* kSinTable1024[], and should not be changed depending on the input
|
||||
* parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2
|
||||
*/
|
||||
wr = kSinTable1024[j + 256];
|
||||
wi = kSinTable1024[j];
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
int32_t wri = 0;
|
||||
int32_t frfi_r = 0;
|
||||
__asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) :
|
||||
"r"((int32_t)wr), "r"((int32_t)wi));
|
||||
#endif
|
||||
|
||||
for (i = m; i < n; i += istep)
|
||||
{
|
||||
j = i + l;
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
__asm __volatile(
|
||||
"pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t"
|
||||
"smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
|
||||
"smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t"
|
||||
:[frfi_r]"+r"(frfi_r),
|
||||
[tr32]"=r"(tr32),
|
||||
[ti32]"=r"(ti32)
|
||||
:[frfi_even]"r"((int32_t)frfi[2*j]),
|
||||
[frfi_odd]"r"((int32_t)frfi[2*j +1]),
|
||||
[wri]"r"(wri),
|
||||
[cifftrnd]"r"(CIFFTRND)
|
||||
);
|
||||
#else
|
||||
|
||||
tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j])
|
||||
- WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CIFFTRND;
|
||||
|
||||
ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1])
|
||||
+ WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND;
|
||||
#endif
|
||||
tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT);
|
||||
ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT);
|
||||
|
||||
qr32 = ((int32_t)frfi[2 * i]) << CIFFTSFT;
|
||||
qi32 = ((int32_t)frfi[2 * i + 1]) << CIFFTSFT;
|
||||
|
||||
frfi[2 * j] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2),
|
||||
shift+CIFFTSFT);
|
||||
frfi[2 * j + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 - ti32 + round2), shift + CIFFTSFT);
|
||||
frfi[2 * i] = (int16_t)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2),
|
||||
shift + CIFFTSFT);
|
||||
frfi[2 * i + 1] = (int16_t)WEBRTC_SPL_RSHIFT_W32(
|
||||
(qi32 + ti32 + round2), shift + CIFFTSFT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
return scale;
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
|
||||
#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
|
||||
|
||||
|
||||
#include "../include/typedefs.h"
|
||||
static const int16_t kSinTable1024[] = {
|
||||
0, 201, 402, 603, 804, 1005, 1206, 1406,
|
||||
1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
|
||||
3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
|
||||
4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
|
||||
6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766,
|
||||
7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
|
||||
9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849,
|
||||
11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
|
||||
12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
|
||||
14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
|
||||
15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672,
|
||||
16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
|
||||
18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357,
|
||||
19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
|
||||
20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855,
|
||||
22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
|
||||
23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143,
|
||||
24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
|
||||
25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198,
|
||||
26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
|
||||
27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001,
|
||||
28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
|
||||
28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534,
|
||||
29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
|
||||
30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783,
|
||||
30851, 30918, 30984, 31049, 31113, 31175, 31236, 31297,
|
||||
31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
|
||||
31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
|
||||
32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382,
|
||||
32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
|
||||
32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717,
|
||||
32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
|
||||
32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736,
|
||||
32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
|
||||
32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441,
|
||||
32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
|
||||
32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833,
|
||||
31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
|
||||
31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918,
|
||||
30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
|
||||
30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706,
|
||||
29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
|
||||
28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208,
|
||||
28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
|
||||
27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
|
||||
26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
|
||||
25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413,
|
||||
24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
|
||||
23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153,
|
||||
22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
|
||||
20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680,
|
||||
19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
|
||||
18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017,
|
||||
16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
|
||||
15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191,
|
||||
14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
|
||||
12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227,
|
||||
11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
|
||||
9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156,
|
||||
7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
|
||||
6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006,
|
||||
4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
|
||||
3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
|
||||
1607, 1406, 1206, 1005, 804, 603, 402, 201,
|
||||
0, -201, -402, -603, -804, -1005, -1206, -1406,
|
||||
-1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
|
||||
-3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608,
|
||||
-4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
|
||||
-6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766,
|
||||
-7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
|
||||
-9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849,
|
||||
-11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
|
||||
-12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
|
||||
-14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
|
||||
-15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
|
||||
-16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
|
||||
-18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
|
||||
-19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
|
||||
-20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
|
||||
-22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
|
||||
-23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
|
||||
-24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
|
||||
-25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
|
||||
-26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
|
||||
-27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
|
||||
-28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
|
||||
-28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
|
||||
-29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
|
||||
-30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
|
||||
-30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
|
||||
-31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
|
||||
-31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
|
||||
-32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
|
||||
-32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
|
||||
-32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
|
||||
-32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
|
||||
-32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
|
||||
-32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
|
||||
-32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
|
||||
-32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
|
||||
-32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
|
||||
-31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
|
||||
-31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
|
||||
-30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
|
||||
-30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
|
||||
-29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
|
||||
-28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
|
||||
-28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
|
||||
-27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
|
||||
-26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
|
||||
-25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
|
||||
-24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
|
||||
-23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
|
||||
-22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
|
||||
-20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
|
||||
-19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
|
||||
-18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
|
||||
-16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
|
||||
-15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
|
||||
-14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
|
||||
-12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
|
||||
-11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
|
||||
-9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156,
|
||||
-7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
|
||||
-6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
|
||||
-4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
|
||||
-3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
|
||||
-1607, -1406, -1206, -1005, -804, -603, -402, -201
|
||||
};
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
/* C version of WebRtcSpl_CrossCorrelation() for generic platforms. */
|
||||
void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation,
|
||||
const int16_t* seq1,
|
||||
const int16_t* seq2,
|
||||
int16_t dim_seq,
|
||||
int16_t dim_cross_correlation,
|
||||
int16_t right_shifts,
|
||||
int16_t step_seq2) {
|
||||
int i = 0, j = 0;
|
||||
|
||||
for (i = 0; i < dim_cross_correlation; i++) {
|
||||
*cross_correlation = 0;
|
||||
/* Unrolling doesn't seem to improve performance. */
|
||||
for (j = 0; j < dim_seq; j++) {
|
||||
*cross_correlation += (seq1[j] * seq2[step_seq2 * i + j]) >> right_shifts;
|
||||
}
|
||||
cross_correlation++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the divisions
|
||||
* WebRtcSpl_DivU32U16()
|
||||
* WebRtcSpl_DivW32W16()
|
||||
* WebRtcSpl_DivW32W16ResW16()
|
||||
* WebRtcSpl_DivResultInQ31()
|
||||
* WebRtcSpl_DivW32HiLow()
|
||||
*
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (uint32_t)(num / den);
|
||||
} else
|
||||
{
|
||||
return (uint32_t)0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (int32_t)(num / den);
|
||||
} else
|
||||
{
|
||||
return (int32_t)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den)
|
||||
{
|
||||
// Guard against division with 0
|
||||
if (den != 0)
|
||||
{
|
||||
return (int16_t)(num / den);
|
||||
} else
|
||||
{
|
||||
return (int16_t)0x7FFF;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
|
||||
{
|
||||
int32_t L_num = num;
|
||||
int32_t L_den = den;
|
||||
int32_t div = 0;
|
||||
int k = 31;
|
||||
int change_sign = 0;
|
||||
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
change_sign++;
|
||||
L_num = -num;
|
||||
}
|
||||
if (den < 0)
|
||||
{
|
||||
change_sign++;
|
||||
L_den = -den;
|
||||
}
|
||||
while (k--)
|
||||
{
|
||||
div <<= 1;
|
||||
L_num <<= 1;
|
||||
if (L_num >= L_den)
|
||||
{
|
||||
L_num -= L_den;
|
||||
div++;
|
||||
}
|
||||
}
|
||||
if (change_sign == 1)
|
||||
{
|
||||
div = -div;
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
|
||||
{
|
||||
int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
|
||||
int32_t tmpW32;
|
||||
|
||||
approx = (int16_t)WebRtcSpl_DivW32W16((int32_t)0x1FFFFFFF, den_hi);
|
||||
// result in Q14 (Note: 3FFFFFFF = 0.5 in Q30)
|
||||
|
||||
// tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30)
|
||||
tmpW32 = (WEBRTC_SPL_MUL_16_16(den_hi, approx) << 1)
|
||||
+ ((WEBRTC_SPL_MUL_16_16(den_low, approx) >> 15) << 1);
|
||||
// tmpW32 = den * approx
|
||||
|
||||
tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
|
||||
|
||||
// Store tmpW32 in hi and low format
|
||||
tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
|
||||
tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32
|
||||
- WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
|
||||
|
||||
// tmpW32 = 1/den in Q29
|
||||
tmpW32 = ((WEBRTC_SPL_MUL_16_16(tmp_hi, approx) + (WEBRTC_SPL_MUL_16_16(tmp_low, approx)
|
||||
>> 15)) << 1);
|
||||
|
||||
// 1/den in hi and low format
|
||||
tmp_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
|
||||
tmp_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((tmpW32
|
||||
- WEBRTC_SPL_LSHIFT_W32((int32_t)tmp_hi, 16)), 1);
|
||||
|
||||
// Store num in hi and low format
|
||||
num_hi = (int16_t)WEBRTC_SPL_RSHIFT_W32(num, 16);
|
||||
num_low = (int16_t)WEBRTC_SPL_RSHIFT_W32((num
|
||||
- WEBRTC_SPL_LSHIFT_W32((int32_t)num_hi, 16)), 1);
|
||||
|
||||
// num * (1/den) by 32 bit multiplication (result in Q28)
|
||||
|
||||
tmpW32 = (WEBRTC_SPL_MUL_16_16(num_hi, tmp_hi) + (WEBRTC_SPL_MUL_16_16(num_hi, tmp_low)
|
||||
>> 15) + (WEBRTC_SPL_MUL_16_16(num_low, tmp_hi) >> 15));
|
||||
|
||||
// Put result in Q31 (convert from Q28)
|
||||
tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3);
|
||||
|
||||
return tmpW32;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
// TODO(Bjornv): Change the function parameter order to WebRTC code style.
|
||||
// C version of WebRtcSpl_DownsampleFast() for generic platforms.
|
||||
int WebRtcSpl_DownsampleFastC(const int16_t* data_in,
|
||||
int data_in_length,
|
||||
int16_t* data_out,
|
||||
int data_out_length,
|
||||
const int16_t* __restrict coefficients,
|
||||
int coefficients_length,
|
||||
int factor,
|
||||
int delay) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int32_t out_s32 = 0;
|
||||
int endpos = delay + factor * (data_out_length - 1) + 1;
|
||||
|
||||
// Return error if any of the running conditions doesn't meet.
|
||||
if (data_out_length <= 0 || coefficients_length <= 0
|
||||
|| data_in_length < endpos) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = delay; i < endpos; i += factor) {
|
||||
out_s32 = 2048; // Round value, 0.5 in Q12.
|
||||
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
out_s32 += coefficients[j] * data_in[i - j]; // Q12.
|
||||
}
|
||||
|
||||
out_s32 >>= 12; // Q0.
|
||||
|
||||
// Saturate and store the output.
|
||||
*data_out++ = WebRtcSpl_SatW32ToW16(out_s32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_Energy().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
int32_t WebRtcSpl_Energy(int16_t* vector, int vector_length, int* scale_factor)
|
||||
{
|
||||
int32_t en = 0;
|
||||
int i;
|
||||
int scaling = WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length);
|
||||
int looptimes = vector_length;
|
||||
int16_t *vectorptr = vector;
|
||||
|
||||
for (i = 0; i < looptimes; i++)
|
||||
{
|
||||
en += WEBRTC_SPL_MUL_16_16_RSFT(*vectorptr, *vectorptr, scaling);
|
||||
vectorptr++;
|
||||
}
|
||||
*scale_factor = scaling;
|
||||
|
||||
return en;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_GetScalingSquare().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
int WebRtcSpl_GetScalingSquare(int16_t *in_vector, int in_vector_length, int times)
|
||||
{
|
||||
int nbits = WebRtcSpl_GetSizeInBits(times);
|
||||
int i;
|
||||
int16_t smax = -1;
|
||||
int16_t sabs;
|
||||
int16_t *sptr = in_vector;
|
||||
int t;
|
||||
int looptimes = in_vector_length;
|
||||
|
||||
for (i = looptimes; i > 0; i--)
|
||||
{
|
||||
sabs = (*sptr > 0 ? *sptr++ : -*sptr++);
|
||||
smax = (sabs > smax ? sabs : smax);
|
||||
}
|
||||
t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax));
|
||||
|
||||
if (smax == 0)
|
||||
{
|
||||
return 0; // Since norm(0) returns 0
|
||||
} else
|
||||
{
|
||||
return (t > nbits) ? 0 : nbits - t;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
|
||||
#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
|
||||
|
||||
#include "../../include/typedefs.h"
|
||||
|
||||
// For ComplexFFT(), the maximum fft order is 10;
|
||||
// for OpenMax FFT in ARM, it is 12;
|
||||
// WebRTC APM uses orders of only 7 and 8.
|
||||
enum {kMaxFFTOrder = 10};
|
||||
|
||||
struct RealFFT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct RealFFT* (*CreateRealFFT)(int order);
|
||||
typedef void (*FreeRealFFT)(struct RealFFT* self);
|
||||
typedef int (*RealForwardFFT)(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out);
|
||||
typedef int (*RealInverseFFT)(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out);
|
||||
|
||||
extern CreateRealFFT WebRtcSpl_CreateRealFFT;
|
||||
extern FreeRealFFT WebRtcSpl_FreeRealFFT;
|
||||
extern RealForwardFFT WebRtcSpl_RealForwardFFT;
|
||||
extern RealInverseFFT WebRtcSpl_RealInverseFFT;
|
||||
|
||||
struct RealFFT* WebRtcSpl_CreateRealFFTC(int order);
|
||||
void WebRtcSpl_FreeRealFFTC(struct RealFFT* self);
|
||||
|
||||
#if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON)
|
||||
struct RealFFT* WebRtcSpl_CreateRealFFTNeon(int order);
|
||||
void WebRtcSpl_FreeRealFFTNeon(struct RealFFT* self);
|
||||
#endif
|
||||
|
||||
// Compute an FFT for a real-valued signal of length of 2^order,
|
||||
// where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the
|
||||
// specification structure, which must be initialized prior to calling the FFT
|
||||
// function with WebRtcSpl_CreateRealFFT().
|
||||
// The relationship between the input and output sequences can
|
||||
// be expressed in terms of the DFT, i.e.:
|
||||
// x[n] = (2^(-scalefactor)/N) . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N)
|
||||
// n=0,1,2,...N-1
|
||||
// N=2^order.
|
||||
// The conjugate-symmetric output sequence is represented using a CCS vector,
|
||||
// which is of length N+2, and is organized as follows:
|
||||
// Index: 0 1 2 3 4 5 . . . N-2 N-1 N N+1
|
||||
// Component: R0 0 R1 I1 R2 I2 . . . R[N/2-1] I[N/2-1] R[N/2] 0
|
||||
// where R[n] and I[n], respectively, denote the real and imaginary components
|
||||
// for FFT bin 'n'. Bins are numbered from 0 to N/2, where N is the FFT length.
|
||||
// Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to
|
||||
// the foldover frequency.
|
||||
//
|
||||
// Input Arguments:
|
||||
// self - pointer to preallocated and initialized FFT specification structure.
|
||||
// real_data_in - the input signal. For an ARM Neon platform, it must be
|
||||
// aligned on a 32-byte boundary.
|
||||
//
|
||||
// Output Arguments:
|
||||
// complex_data_out - the output complex signal with (2^order + 2) 16-bit
|
||||
// elements. For an ARM Neon platform, it must be different
|
||||
// from real_data_in, and aligned on a 32-byte boundary.
|
||||
//
|
||||
// Return Value:
|
||||
// 0 - FFT calculation is successful.
|
||||
// -1 - Error with bad arguments (NULL pointers).
|
||||
int WebRtcSpl_RealForwardFFTC(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out);
|
||||
|
||||
#if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON)
|
||||
int WebRtcSpl_RealForwardFFTNeon(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out);
|
||||
#endif
|
||||
|
||||
// Compute the inverse FFT for a conjugate-symmetric input sequence of length of
|
||||
// 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by
|
||||
// the specification structure, which must be initialized prior to calling the
|
||||
// FFT function with WebRtcSpl_CreateRealFFT().
|
||||
// For a transform of length M, the input sequence is represented using a packed
|
||||
// CCS vector of length M+2, which is explained in the comments for
|
||||
// WebRtcSpl_RealForwardFFTC above.
|
||||
//
|
||||
// Input Arguments:
|
||||
// self - pointer to preallocated and initialized FFT specification structure.
|
||||
// complex_data_in - the input complex signal with (2^order + 2) 16-bit
|
||||
// elements. For an ARM Neon platform, it must be aligned on
|
||||
// a 32-byte boundary.
|
||||
//
|
||||
// Output Arguments:
|
||||
// real_data_out - the output real signal. For an ARM Neon platform, it must
|
||||
// be different to complex_data_in, and aligned on a 32-byte
|
||||
// boundary.
|
||||
//
|
||||
// Return Value:
|
||||
// 0 or a positive number - a value that the elements in the |real_data_out|
|
||||
// should be shifted left with in order to get
|
||||
// correct physical values.
|
||||
// -1 - Error with bad arguments (NULL pointers).
|
||||
int WebRtcSpl_RealInverseFFTC(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out);
|
||||
|
||||
#if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON)
|
||||
int WebRtcSpl_RealInverseFFTNeon(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This header file includes the inline functions in
|
||||
// the fix point signal processing library.
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_H_
|
||||
#define WEBRTC_SPL_SPL_INL_H_
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
#include "include/spl_inl_armv7.h"
|
||||
#else
|
||||
|
||||
#if defined(MIPS32_LE)
|
||||
#include "include/spl_inl_mips.h"
|
||||
#endif
|
||||
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
|
||||
int16_t out16 = (int16_t) value32;
|
||||
|
||||
if (value32 > 32767)
|
||||
out16 = 32767;
|
||||
else if (value32 < -32768)
|
||||
out16 = -32768;
|
||||
|
||||
return out16;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
|
||||
return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b);
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
|
||||
return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2);
|
||||
}
|
||||
#endif // #if !defined(MIPS_DSP_R1_LE)
|
||||
|
||||
#if !defined(MIPS32_LE)
|
||||
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
|
||||
int bits;
|
||||
|
||||
if (0xFFFF0000 & n) {
|
||||
bits = 16;
|
||||
} else {
|
||||
bits = 0;
|
||||
}
|
||||
if (0x0000FF00 & (n >> bits)) bits += 8;
|
||||
if (0x000000F0 & (n >> bits)) bits += 4;
|
||||
if (0x0000000C & (n >> bits)) bits += 2;
|
||||
if (0x00000002 & (n >> bits)) bits += 1;
|
||||
if (0x00000001 & (n >> bits)) bits += 1;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW32(int32_t a) {
|
||||
int zeros;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a = ~a;
|
||||
}
|
||||
|
||||
if (!(0xFFFF8000 & a)) {
|
||||
zeros = 16;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xFF800000 & (a << zeros))) zeros += 8;
|
||||
if (!(0xF8000000 & (a << zeros))) zeros += 4;
|
||||
if (!(0xE0000000 & (a << zeros))) zeros += 2;
|
||||
if (!(0xC0000000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormU32(uint32_t a) {
|
||||
int zeros;
|
||||
|
||||
if (a == 0) return 0;
|
||||
|
||||
if (!(0xFFFF0000 & a)) {
|
||||
zeros = 16;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xFF000000 & (a << zeros))) zeros += 8;
|
||||
if (!(0xF0000000 & (a << zeros))) zeros += 4;
|
||||
if (!(0xC0000000 & (a << zeros))) zeros += 2;
|
||||
if (!(0x80000000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW16(int16_t a) {
|
||||
int zeros;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a = ~a;
|
||||
}
|
||||
|
||||
if (!(0xFF80 & a)) {
|
||||
zeros = 8;
|
||||
} else {
|
||||
zeros = 0;
|
||||
}
|
||||
if (!(0xF800 & (a << zeros))) zeros += 4;
|
||||
if (!(0xE000 & (a << zeros))) zeros += 2;
|
||||
if (!(0xC000 & (a << zeros))) zeros += 1;
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
|
||||
return (a * b + c);
|
||||
}
|
||||
#endif // #if !defined(MIPS32_LE)
|
||||
|
||||
#endif // WEBRTC_ARCH_ARM_V7
|
||||
|
||||
// The following functions have no optimized versions.
|
||||
// TODO(kma): Consider saturating add/sub instructions in X86 platform.
|
||||
#if !defined(MIPS_DSP_R1_LE)
|
||||
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sum;
|
||||
|
||||
// Perform long addition
|
||||
l_sum = l_var1 + l_var2;
|
||||
|
||||
if (l_var1 < 0) { // Check for underflow.
|
||||
if ((l_var2 < 0) && (l_sum >= 0)) {
|
||||
l_sum = (int32_t)0x80000000;
|
||||
}
|
||||
} else { // Check for overflow.
|
||||
if ((l_var2 > 0) && (l_sum < 0)) {
|
||||
l_sum = (int32_t)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_diff;
|
||||
|
||||
// Perform subtraction.
|
||||
l_diff = l_var1 - l_var2;
|
||||
|
||||
if (l_var1 < 0) { // Check for underflow.
|
||||
if ((l_var2 > 0) && (l_diff > 0)) {
|
||||
l_diff = (int32_t)0x80000000;
|
||||
}
|
||||
} else { // Check for overflow.
|
||||
if ((l_var2 < 0) && (l_diff < 0)) {
|
||||
l_diff = (int32_t)0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
return l_diff;
|
||||
}
|
||||
#endif // #if !defined(MIPS_DSP_R1_LE)
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_H_
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/* This header file includes the inline functions for ARM processors in
|
||||
* the fix point signal processing library.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_ARMV7_H_
|
||||
#define WEBRTC_SPL_SPL_INL_ARMV7_H_
|
||||
|
||||
/* TODO(kma): Replace some assembly code with GCC intrinsics
|
||||
* (e.g. __builtin_clz).
|
||||
*/
|
||||
|
||||
/* This function produces result that is not bit exact with that by the generic
|
||||
* C version in some cases, although the former is at least as accurate as the
|
||||
* later.
|
||||
*/
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile ("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* This function produces result that is not bit exact with that by the generic
|
||||
* C version in some cases, although the former is at least as accurate as the
|
||||
* later.
|
||||
*/
|
||||
static __inline int32_t WEBRTC_SPL_MUL_32_32_RSFT32(int16_t a,
|
||||
int16_t b,
|
||||
int32_t c) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile (
|
||||
"pkhbt %[tmp], %[b], %[a], lsl #16\n\t"
|
||||
"smmulr %[tmp], %[tmp], %[c]\n\t"
|
||||
:[tmp]"+r"(tmp)
|
||||
:[a]"r"(a),
|
||||
[b]"r"(b),
|
||||
[c]"r"(c)
|
||||
);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_32_32_RSFT32BI(int32_t a, int32_t b) {
|
||||
int32_t tmp = 0;
|
||||
__asm volatile ("smmulr %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile ("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// TODO(kma): add unit test.
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) {
|
||||
int32_t tmp = 0;
|
||||
__asm __volatile ("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
|
||||
int32_t s_sum = 0;
|
||||
|
||||
__asm __volatile ("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b));
|
||||
|
||||
return (int16_t) s_sum;
|
||||
}
|
||||
|
||||
/* TODO(kma): find the cause of unittest errors by the next two functions:
|
||||
* http://code.google.com/p/webrtc/issues/detail?id=740.
|
||||
*/
|
||||
#if 0
|
||||
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sum = 0;
|
||||
|
||||
__asm __volatile ("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2));
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sub = 0;
|
||||
|
||||
__asm __volatile ("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2));
|
||||
|
||||
return l_sub;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
|
||||
int32_t s_sub = 0;
|
||||
|
||||
__asm __volatile ("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2));
|
||||
|
||||
return (int16_t)s_sub;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
|
||||
int32_t tmp = 0;
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(n));
|
||||
|
||||
return (int16_t)(32 - tmp);
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW32(int32_t a) {
|
||||
int32_t tmp = 0;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a ^= 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return tmp - 1;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormU32(uint32_t a) {
|
||||
int tmp = 0;
|
||||
|
||||
if (a == 0) return 0;
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW16(int16_t a) {
|
||||
int32_t tmp = 0;
|
||||
|
||||
if (a == 0) {
|
||||
return 0;
|
||||
}
|
||||
else if (a < 0) {
|
||||
a ^= 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
__asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a));
|
||||
|
||||
return tmp - 17;
|
||||
}
|
||||
|
||||
// TODO(kma): add unit test.
|
||||
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
|
||||
int32_t out = 0;
|
||||
|
||||
__asm __volatile ("ssat %0, #16, %1" : "=r"(out) : "r"(value32));
|
||||
|
||||
return (int16_t)out;
|
||||
}
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_ARMV7_H_
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This header file includes the inline functions in
|
||||
// the fix point signal processing library.
|
||||
|
||||
#ifndef WEBRTC_SPL_SPL_INL_MIPS_H_
|
||||
#define WEBRTC_SPL_SPL_INL_MIPS_H_
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a,
|
||||
int32_t b) {
|
||||
int32_t value32 = 0;
|
||||
int32_t a1 = 0, b1 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a1], %[a] \n\t"
|
||||
"seh %[b1], %[b] \n\t"
|
||||
#else
|
||||
"sll %[a1], %[a], 16 \n\t"
|
||||
"sll %[b1], %[b], 16 \n\t"
|
||||
"sra %[a1], %[a1], 16 \n\t"
|
||||
"sra %[b1], %[b1], 16 \n\t"
|
||||
#endif
|
||||
"mul %[value32], %[a1], %[b1] \n\t"
|
||||
: [value32] "=r" (value32), [a1] "=&r" (a1), [b1] "=&r" (b1)
|
||||
: [a] "r" (a), [b] "r" (b)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a,
|
||||
int32_t b) {
|
||||
int32_t value32 = 0, b1 = 0, b2 = 0;
|
||||
int32_t a1 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a1], %[a] \n\t"
|
||||
#else
|
||||
"sll %[a1], %[a], 16 \n\t"
|
||||
"sra %[a1], %[a1], 16 \n\t"
|
||||
#endif
|
||||
"andi %[b2], %[b], 0xFFFF \n\t"
|
||||
"sra %[b1], %[b], 16 \n\t"
|
||||
"sra %[b2], %[b2], 1 \n\t"
|
||||
"mul %[value32], %[a1], %[b1] \n\t"
|
||||
"mul %[b2], %[a1], %[b2] \n\t"
|
||||
"addiu %[b2], %[b2], 0x4000 \n\t"
|
||||
"sra %[b2], %[b2], 15 \n\t"
|
||||
"addu %[value32], %[value32], %[b2] \n\t"
|
||||
: [value32] "=&r" (value32), [b1] "=&r" (b1), [b2] "=&r" (b2),
|
||||
[a1] "=&r" (a1)
|
||||
: [a] "r" (a), [b] "r" (b)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_32_32_RSFT32BI(int32_t a,
|
||||
int32_t b) {
|
||||
int32_t tmp = 0;
|
||||
|
||||
if ((32767 < a) || (a < 0))
|
||||
tmp = WEBRTC_SPL_MUL_16_32_RSFT16(((int16_t)(a >> 16)), b);
|
||||
tmp += WEBRTC_SPL_MUL_16_32_RSFT16(((int16_t)((a & 0x0000FFFF) >> 1)),
|
||||
b) >> 15;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static __inline int32_t WEBRTC_SPL_MUL_32_32_RSFT32(int16_t a,
|
||||
int16_t b,
|
||||
int32_t c) {
|
||||
int32_t tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
"sra %[tmp1], %[c], 16 \n\t"
|
||||
"andi %[tmp2], %[c], 0xFFFF \n\t"
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a], %[a] \n\t"
|
||||
"seh %[b], %[b] \n\t"
|
||||
#else
|
||||
"sll %[a], %[a], 16 \n\t"
|
||||
"sra %[a], %[a], 16 \n\t"
|
||||
"sll %[b], %[b], 16 \n\t"
|
||||
"sra %[b], %[b], 16 \n\t"
|
||||
#endif
|
||||
"sra %[tmp2], %[tmp2], 1 \n\t"
|
||||
"mul %[tmp3], %[a], %[tmp2] \n\t"
|
||||
"mul %[tmp4], %[b], %[tmp2] \n\t"
|
||||
"mul %[tmp2], %[a], %[tmp1] \n\t"
|
||||
"mul %[tmp1], %[b], %[tmp1] \n\t"
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
"shra_r.w %[tmp3], %[tmp3], 15 \n\t"
|
||||
"shra_r.w %[tmp4], %[tmp4], 15 \n\t"
|
||||
#else
|
||||
"addiu %[tmp3], %[tmp3], 0x4000 \n\t"
|
||||
"sra %[tmp3], %[tmp3], 15 \n\t"
|
||||
"addiu %[tmp4], %[tmp4], 0x4000 \n\t"
|
||||
"sra %[tmp4], %[tmp4], 15 \n\t"
|
||||
#endif
|
||||
"addu %[tmp3], %[tmp3], %[tmp2] \n\t"
|
||||
"addu %[tmp4], %[tmp4], %[tmp1] \n\t"
|
||||
"sra %[tmp4], %[tmp4], 16 \n\t"
|
||||
"addu %[tmp1], %[tmp3], %[tmp4] \n\t"
|
||||
: [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2),
|
||||
[tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4),
|
||||
[a] "+r" (a), [b] "+r" (b)
|
||||
: [c] "r" (c)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return tmp1;
|
||||
}
|
||||
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) {
|
||||
__asm __volatile(
|
||||
"shll_s.w %[value32], %[value32], 16 \n\t"
|
||||
"sra %[value32], %[value32], 16 \n\t"
|
||||
: [value32] "+r" (value32)
|
||||
:
|
||||
);
|
||||
int16_t out16 = (int16_t)value32;
|
||||
return out16;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) {
|
||||
int32_t value32 = 0;
|
||||
|
||||
__asm __volatile(
|
||||
"addq_s.ph %[value32], %[a], %[b] \n\t"
|
||||
: [value32] "=r" (value32)
|
||||
: [a] "r" (a), [b] "r" (b)
|
||||
);
|
||||
return (int16_t)value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_sum;
|
||||
|
||||
__asm __volatile(
|
||||
"addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t"
|
||||
: [l_sum] "=r" (l_sum)
|
||||
: [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
|
||||
);
|
||||
|
||||
return l_sum;
|
||||
}
|
||||
|
||||
static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) {
|
||||
int32_t value32;
|
||||
|
||||
__asm __volatile(
|
||||
"subq_s.ph %[value32], %[var1], %[var2] \n\t"
|
||||
: [value32] "=r" (value32)
|
||||
: [var1] "r" (var1), [var2] "r" (var2)
|
||||
);
|
||||
|
||||
return (int16_t)value32;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
|
||||
int32_t l_diff;
|
||||
|
||||
__asm __volatile(
|
||||
"subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t"
|
||||
: [l_diff] "=r" (l_diff)
|
||||
: [l_var1] "r" (l_var1), [l_var2] "r" (l_var2)
|
||||
);
|
||||
|
||||
return l_diff;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) {
|
||||
int bits = 0;
|
||||
int i32 = 32;
|
||||
|
||||
__asm __volatile(
|
||||
"clz %[bits], %[n] \n\t"
|
||||
"subu %[bits], %[i32], %[bits] \n\t"
|
||||
: [bits] "=&r" (bits)
|
||||
: [n] "r" (n), [i32] "r" (i32)
|
||||
);
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW32(int32_t a) {
|
||||
int zeros = 0;
|
||||
|
||||
__asm __volatile(
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"bnez %[a], 1f \n\t"
|
||||
" sra %[zeros], %[a], 31 \n\t"
|
||||
"b 2f \n\t"
|
||||
" move %[zeros], $zero \n\t"
|
||||
"1: \n\t"
|
||||
"xor %[zeros], %[a], %[zeros] \n\t"
|
||||
"clz %[zeros], %[zeros] \n\t"
|
||||
"addiu %[zeros], %[zeros], -1 \n\t"
|
||||
"2: \n\t"
|
||||
".set pop \n\t"
|
||||
: [zeros]"=&r"(zeros)
|
||||
: [a] "r" (a)
|
||||
);
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormU32(uint32_t a) {
|
||||
int zeros = 0;
|
||||
|
||||
__asm __volatile(
|
||||
"clz %[zeros], %[a] \n\t"
|
||||
: [zeros] "=r" (zeros)
|
||||
: [a] "r" (a)
|
||||
);
|
||||
|
||||
return (zeros & 0x1f);
|
||||
}
|
||||
|
||||
static __inline int WebRtcSpl_NormW16(int16_t a) {
|
||||
int zeros = 0;
|
||||
int a0 = a << 16;
|
||||
|
||||
__asm __volatile(
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"bnez %[a0], 1f \n\t"
|
||||
" sra %[zeros], %[a0], 31 \n\t"
|
||||
"b 2f \n\t"
|
||||
" move %[zeros], $zero \n\t"
|
||||
"1: \n\t"
|
||||
"xor %[zeros], %[a0], %[zeros] \n\t"
|
||||
"clz %[zeros], %[zeros] \n\t"
|
||||
"addiu %[zeros], %[zeros], -1 \n\t"
|
||||
"2: \n\t"
|
||||
".set pop \n\t"
|
||||
: [zeros]"=&r"(zeros)
|
||||
: [a0] "r" (a0)
|
||||
);
|
||||
|
||||
return zeros;
|
||||
}
|
||||
|
||||
static __inline int32_t WebRtc_MulAccumW16(int16_t a,
|
||||
int16_t b,
|
||||
int32_t c) {
|
||||
int32_t res = 0, c1 = 0;
|
||||
__asm __volatile(
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"seh %[a], %[a] \n\t"
|
||||
"seh %[b], %[b] \n\t"
|
||||
#else
|
||||
"sll %[a], %[a], 16 \n\t"
|
||||
"sll %[b], %[b], 16 \n\t"
|
||||
"sra %[a], %[a], 16 \n\t"
|
||||
"sra %[b], %[b], 16 \n\t"
|
||||
#endif
|
||||
"mul %[res], %[a], %[b] \n\t"
|
||||
"addu %[c1], %[c], %[res] \n\t"
|
||||
: [c1] "=r" (c1), [res] "=&r" (res)
|
||||
: [a] "r" (a), [b] "r" (b), [c] "r" (c)
|
||||
: "hi", "lo"
|
||||
);
|
||||
return (c1);
|
||||
}
|
||||
|
||||
#endif // WEBRTC_SPL_SPL_INL_MIPS_H_
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains the implementation of functions
|
||||
* WebRtcSpl_MaxAbsValueW16C()
|
||||
* WebRtcSpl_MaxAbsValueW32C()
|
||||
* WebRtcSpl_MaxValueW16C()
|
||||
* WebRtcSpl_MaxValueW32C()
|
||||
* WebRtcSpl_MinValueW16C()
|
||||
* WebRtcSpl_MinValueW32C()
|
||||
* WebRtcSpl_MaxAbsIndexW16()
|
||||
* WebRtcSpl_MaxIndexW16()
|
||||
* WebRtcSpl_MaxIndexW32()
|
||||
* WebRtcSpl_MinIndexW16()
|
||||
* WebRtcSpl_MinIndexW32()
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// TODO(bjorn/kma): Consolidate function pairs (e.g. combine
|
||||
// WebRtcSpl_MaxAbsValueW16C and WebRtcSpl_MaxAbsIndexW16 into a single one.)
|
||||
// TODO(kma): Move the next six functions into min_max_operations_c.c.
|
||||
|
||||
// Maximum absolute value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, int length) {
|
||||
int i = 0, absolute = 0, maximum = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
}
|
||||
|
||||
// Guard the case for abs(-32768).
|
||||
if (maximum > WEBRTC_SPL_WORD16_MAX) {
|
||||
maximum = WEBRTC_SPL_WORD16_MAX;
|
||||
}
|
||||
|
||||
return (int16_t)maximum;
|
||||
}
|
||||
|
||||
// Maximum absolute value of word32 vector. C version for generic platforms.
|
||||
int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, int length) {
|
||||
// Use uint32_t for the local variables, to accommodate the return value
|
||||
// of abs(0x80000000), which is 0x80000000.
|
||||
|
||||
uint32_t absolute = 0, maximum = 0;
|
||||
int i = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
}
|
||||
|
||||
maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX);
|
||||
|
||||
return (int32_t)maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, int length) {
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
int i = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return maximum;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum)
|
||||
maximum = vector[i];
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Maximum value of word32 vector. C version for generic platforms.
|
||||
int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, int length) {
|
||||
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
|
||||
int i = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return maximum;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum)
|
||||
maximum = vector[i];
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
// Minimum value of word16 vector. C version for generic platforms.
|
||||
int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, int length) {
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
int i = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return minimum;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum)
|
||||
minimum = vector[i];
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Minimum value of word32 vector. C version for generic platforms.
|
||||
int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, int length) {
|
||||
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
|
||||
int i = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return minimum;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum)
|
||||
minimum = vector[i];
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Index of maximum absolute value in a word16 vector.
|
||||
int WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, int length) {
|
||||
// Use type int for local variables, to accomodate the value of abs(-32768).
|
||||
|
||||
int i = 0, absolute = 0, maximum = 0, index = 0;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of maximum value in a word16 vector.
|
||||
int WebRtcSpl_MaxIndexW16(const int16_t* vector, int length) {
|
||||
int i = 0, index = 0;
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum) {
|
||||
maximum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of maximum value in a word32 vector.
|
||||
int WebRtcSpl_MaxIndexW32(const int32_t* vector, int length) {
|
||||
int i = 0, index = 0;
|
||||
int32_t maximum = WEBRTC_SPL_WORD32_MIN;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] > maximum) {
|
||||
maximum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of minimum value in a word16 vector.
|
||||
int WebRtcSpl_MinIndexW16(const int16_t* vector, int length) {
|
||||
int i = 0, index = 0;
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum) {
|
||||
minimum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Index of minimum value in a word32 vector.
|
||||
int WebRtcSpl_MinIndexW32(const int32_t* vector, int length) {
|
||||
int i = 0, index = 0;
|
||||
int32_t minimum = WEBRTC_SPL_WORD32_MAX;
|
||||
|
||||
if (vector == NULL || length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum) {
|
||||
minimum = vector[i];
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "include/real_fft.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
struct RealFFT {
|
||||
int order;
|
||||
};
|
||||
|
||||
struct RealFFT* WebRtcSpl_CreateRealFFTC(int order) {
|
||||
struct RealFFT* self = NULL;
|
||||
|
||||
if (order > kMaxFFTOrder || order < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = malloc(sizeof(struct RealFFT));
|
||||
if (self == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
self->order = order;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void WebRtcSpl_FreeRealFFTC(struct RealFFT* self) {
|
||||
if (self != NULL) {
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
|
||||
// The C version FFT functions (i.e. WebRtcSpl_RealForwardFFTC and
|
||||
// WebRtcSpl_RealInverseFFTC) are real-valued FFT wrappers for complex-valued
|
||||
// FFT implementation in SPL.
|
||||
|
||||
int WebRtcSpl_RealForwardFFTC(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int result = 0;
|
||||
int n = 1 << self->order;
|
||||
// The complex-value FFT implementation needs a buffer to hold 2^order
|
||||
// 16-bit COMPLEX numbers, for both time and frequency data.
|
||||
int16_t complex_buffer[2 << kMaxFFTOrder];
|
||||
|
||||
// Insert zeros to the imaginary parts for complex forward FFT input.
|
||||
for (i = 0, j = 0; i < n; i += 1, j += 2) {
|
||||
complex_buffer[j] = real_data_in[i];
|
||||
complex_buffer[j + 1] = 0;
|
||||
};
|
||||
|
||||
WebRtcSpl_ComplexBitReverse(complex_buffer, self->order);
|
||||
result = WebRtcSpl_ComplexFFT(complex_buffer, self->order, 1);
|
||||
|
||||
// For real FFT output, use only the first N + 2 elements from
|
||||
// complex forward FFT.
|
||||
memcpy(complex_data_out, complex_buffer, sizeof(int16_t) * (n + 2));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int WebRtcSpl_RealInverseFFTC(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int result = 0;
|
||||
int n = 1 << self->order;
|
||||
// Create the buffer specific to complex-valued FFT implementation.
|
||||
int16_t complex_buffer[2 << kMaxFFTOrder];
|
||||
|
||||
// For n-point FFT, first copy the first n + 2 elements into complex
|
||||
// FFT, then construct the remaining n - 2 elements by real FFT's
|
||||
// conjugate-symmetric properties.
|
||||
memcpy(complex_buffer, complex_data_in, sizeof(int16_t) * (n + 2));
|
||||
for (i = n + 2; i < 2 * n; i += 2) {
|
||||
complex_buffer[i] = complex_data_in[2 * n - i];
|
||||
complex_buffer[i + 1] = -complex_data_in[2 * n - i + 1];
|
||||
}
|
||||
|
||||
WebRtcSpl_ComplexBitReverse(complex_buffer, self->order);
|
||||
result = WebRtcSpl_ComplexIFFT(complex_buffer, self->order, 1);
|
||||
|
||||
// Strip out the imaginary parts of the complex inverse FFT output.
|
||||
for (i = 0, j = 0; i < n; i += 1, j += 2) {
|
||||
real_data_out[i] = complex_buffer[j];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_DETECT_ARM_NEON) || defined(WEBRTC_ARCH_ARM_NEON)
|
||||
// TODO(kma): Replace the following function bodies into optimized functions
|
||||
// for ARM Neon.
|
||||
struct RealFFT* WebRtcSpl_CreateRealFFTNeon(int order) {
|
||||
return WebRtcSpl_CreateRealFFTC(order);
|
||||
}
|
||||
|
||||
void WebRtcSpl_FreeRealFFTNeon(struct RealFFT* self) {
|
||||
WebRtcSpl_FreeRealFFTC(self);
|
||||
}
|
||||
|
||||
int WebRtcSpl_RealForwardFFTNeon(struct RealFFT* self,
|
||||
const int16_t* real_data_in,
|
||||
int16_t* complex_data_out) {
|
||||
return WebRtcSpl_RealForwardFFTC(self, real_data_in, complex_data_out);
|
||||
}
|
||||
|
||||
int WebRtcSpl_RealInverseFFTNeon(struct RealFFT* self,
|
||||
const int16_t* complex_data_in,
|
||||
int16_t* real_data_out) {
|
||||
return WebRtcSpl_RealInverseFFTC(self, complex_data_in, real_data_out);
|
||||
}
|
||||
#endif // WEBRTC_DETECT_ARM_NEON || WEBRTC_ARCH_ARM_NEON
|
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling functions for 22 kHz.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
#include "resample_by_2_internal.h"
|
||||
|
||||
// Declaration of internally used functions
|
||||
static void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, int16_t *Out,
|
||||
int32_t K);
|
||||
|
||||
void WebRtcSpl_32khzTo22khzIntToInt(const int32_t *In, int32_t *Out,
|
||||
int32_t K);
|
||||
|
||||
// interpolation coefficients
|
||||
static const int16_t kCoefficients32To22[5][9] = {
|
||||
{127, -712, 2359, -6333, 23456, 16775, -3695, 945, -154},
|
||||
{-39, 230, -830, 2785, 32366, -2324, 760, -218, 38},
|
||||
{117, -663, 2222, -6133, 26634, 13070, -3174, 831, -137},
|
||||
{-77, 457, -1677, 5958, 31175, -4136, 1405, -408, 71},
|
||||
{ 98, -560, 1900, -5406, 29240, 9423, -2480, 663, -110}
|
||||
};
|
||||
|
||||
//////////////////////
|
||||
// 22 kHz -> 16 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 4, 5, 10
|
||||
#define SUB_BLOCKS_22_16 5
|
||||
|
||||
// 22 -> 16 resampler
|
||||
void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State22khzTo16khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_22_16 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_22_16; k++)
|
||||
{
|
||||
///// 22 --> 44 /////
|
||||
// int16_t in[220/SUB_BLOCKS_22_16]
|
||||
// int32_t out[440/SUB_BLOCKS_22_16]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 220 / SUB_BLOCKS_22_16, tmpmem + 16, state->S_22_44);
|
||||
|
||||
///// 44 --> 32 /////
|
||||
// int32_t in[440/SUB_BLOCKS_22_16]
|
||||
// int32_t out[320/SUB_BLOCKS_22_16]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[8] = state->S_44_32[0];
|
||||
tmpmem[9] = state->S_44_32[1];
|
||||
tmpmem[10] = state->S_44_32[2];
|
||||
tmpmem[11] = state->S_44_32[3];
|
||||
tmpmem[12] = state->S_44_32[4];
|
||||
tmpmem[13] = state->S_44_32[5];
|
||||
tmpmem[14] = state->S_44_32[6];
|
||||
tmpmem[15] = state->S_44_32[7];
|
||||
state->S_44_32[0] = tmpmem[440 / SUB_BLOCKS_22_16 + 8];
|
||||
state->S_44_32[1] = tmpmem[440 / SUB_BLOCKS_22_16 + 9];
|
||||
state->S_44_32[2] = tmpmem[440 / SUB_BLOCKS_22_16 + 10];
|
||||
state->S_44_32[3] = tmpmem[440 / SUB_BLOCKS_22_16 + 11];
|
||||
state->S_44_32[4] = tmpmem[440 / SUB_BLOCKS_22_16 + 12];
|
||||
state->S_44_32[5] = tmpmem[440 / SUB_BLOCKS_22_16 + 13];
|
||||
state->S_44_32[6] = tmpmem[440 / SUB_BLOCKS_22_16 + 14];
|
||||
state->S_44_32[7] = tmpmem[440 / SUB_BLOCKS_22_16 + 15];
|
||||
|
||||
WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 40 / SUB_BLOCKS_22_16);
|
||||
|
||||
///// 32 --> 16 /////
|
||||
// int32_t in[320/SUB_BLOCKS_22_16]
|
||||
// int32_t out[160/SUB_BLOCKS_22_16]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 320 / SUB_BLOCKS_22_16, out, state->S_32_16);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_22_16 ms seconds ahead
|
||||
in += 220 / SUB_BLOCKS_22_16;
|
||||
out += 160 / SUB_BLOCKS_22_16;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 22 -> 16 resampler
|
||||
void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_22_44[k] = 0;
|
||||
state->S_44_32[k] = 0;
|
||||
state->S_32_16[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// 16 kHz -> 22 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 4, 5, 10
|
||||
#define SUB_BLOCKS_16_22 4
|
||||
|
||||
// 16 -> 22 resampler
|
||||
void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State16khzTo22khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_16_22 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_16_22; k++)
|
||||
{
|
||||
///// 16 --> 32 /////
|
||||
// int16_t in[160/SUB_BLOCKS_16_22]
|
||||
// int32_t out[320/SUB_BLOCKS_16_22]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 160 / SUB_BLOCKS_16_22, tmpmem + 8, state->S_16_32);
|
||||
|
||||
///// 32 --> 22 /////
|
||||
// int32_t in[320/SUB_BLOCKS_16_22]
|
||||
// int32_t out[220/SUB_BLOCKS_16_22]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[0] = state->S_32_22[0];
|
||||
tmpmem[1] = state->S_32_22[1];
|
||||
tmpmem[2] = state->S_32_22[2];
|
||||
tmpmem[3] = state->S_32_22[3];
|
||||
tmpmem[4] = state->S_32_22[4];
|
||||
tmpmem[5] = state->S_32_22[5];
|
||||
tmpmem[6] = state->S_32_22[6];
|
||||
tmpmem[7] = state->S_32_22[7];
|
||||
state->S_32_22[0] = tmpmem[320 / SUB_BLOCKS_16_22];
|
||||
state->S_32_22[1] = tmpmem[320 / SUB_BLOCKS_16_22 + 1];
|
||||
state->S_32_22[2] = tmpmem[320 / SUB_BLOCKS_16_22 + 2];
|
||||
state->S_32_22[3] = tmpmem[320 / SUB_BLOCKS_16_22 + 3];
|
||||
state->S_32_22[4] = tmpmem[320 / SUB_BLOCKS_16_22 + 4];
|
||||
state->S_32_22[5] = tmpmem[320 / SUB_BLOCKS_16_22 + 5];
|
||||
state->S_32_22[6] = tmpmem[320 / SUB_BLOCKS_16_22 + 6];
|
||||
state->S_32_22[7] = tmpmem[320 / SUB_BLOCKS_16_22 + 7];
|
||||
|
||||
WebRtcSpl_32khzTo22khzIntToShort(tmpmem, out, 20 / SUB_BLOCKS_16_22);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_16_22 ms seconds ahead
|
||||
in += 160 / SUB_BLOCKS_16_22;
|
||||
out += 220 / SUB_BLOCKS_16_22;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 16 -> 22 resampler
|
||||
void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_16_32[k] = 0;
|
||||
state->S_32_22[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// 22 kHz -> 8 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 5, 10
|
||||
#define SUB_BLOCKS_22_8 2
|
||||
|
||||
// 22 -> 8 resampler
|
||||
void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State22khzTo8khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_22_8 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_22_8; k++)
|
||||
{
|
||||
///// 22 --> 22 lowpass /////
|
||||
// int16_t in[220/SUB_BLOCKS_22_8]
|
||||
// int32_t out[220/SUB_BLOCKS_22_8]
|
||||
/////
|
||||
WebRtcSpl_LPBy2ShortToInt(in, 220 / SUB_BLOCKS_22_8, tmpmem + 16, state->S_22_22);
|
||||
|
||||
///// 22 --> 16 /////
|
||||
// int32_t in[220/SUB_BLOCKS_22_8]
|
||||
// int32_t out[160/SUB_BLOCKS_22_8]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[8] = state->S_22_16[0];
|
||||
tmpmem[9] = state->S_22_16[1];
|
||||
tmpmem[10] = state->S_22_16[2];
|
||||
tmpmem[11] = state->S_22_16[3];
|
||||
tmpmem[12] = state->S_22_16[4];
|
||||
tmpmem[13] = state->S_22_16[5];
|
||||
tmpmem[14] = state->S_22_16[6];
|
||||
tmpmem[15] = state->S_22_16[7];
|
||||
state->S_22_16[0] = tmpmem[220 / SUB_BLOCKS_22_8 + 8];
|
||||
state->S_22_16[1] = tmpmem[220 / SUB_BLOCKS_22_8 + 9];
|
||||
state->S_22_16[2] = tmpmem[220 / SUB_BLOCKS_22_8 + 10];
|
||||
state->S_22_16[3] = tmpmem[220 / SUB_BLOCKS_22_8 + 11];
|
||||
state->S_22_16[4] = tmpmem[220 / SUB_BLOCKS_22_8 + 12];
|
||||
state->S_22_16[5] = tmpmem[220 / SUB_BLOCKS_22_8 + 13];
|
||||
state->S_22_16[6] = tmpmem[220 / SUB_BLOCKS_22_8 + 14];
|
||||
state->S_22_16[7] = tmpmem[220 / SUB_BLOCKS_22_8 + 15];
|
||||
|
||||
WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 20 / SUB_BLOCKS_22_8);
|
||||
|
||||
///// 16 --> 8 /////
|
||||
// int32_t in[160/SUB_BLOCKS_22_8]
|
||||
// int32_t out[80/SUB_BLOCKS_22_8]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 160 / SUB_BLOCKS_22_8, out, state->S_16_8);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_22_8 ms seconds ahead
|
||||
in += 220 / SUB_BLOCKS_22_8;
|
||||
out += 80 / SUB_BLOCKS_22_8;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 22 -> 8 resampler
|
||||
void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_22_22[k] = 0;
|
||||
state->S_22_22[k + 8] = 0;
|
||||
state->S_22_16[k] = 0;
|
||||
state->S_16_8[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// 8 kHz -> 22 kHz //
|
||||
//////////////////////
|
||||
|
||||
// number of subblocks; options: 1, 2, 5, 10
|
||||
#define SUB_BLOCKS_8_22 2
|
||||
|
||||
// 8 -> 22 resampler
|
||||
void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State8khzTo22khz* state, int32_t* tmpmem)
|
||||
{
|
||||
int k;
|
||||
|
||||
// process two blocks of 10/SUB_BLOCKS_8_22 ms (to reduce temp buffer size)
|
||||
for (k = 0; k < SUB_BLOCKS_8_22; k++)
|
||||
{
|
||||
///// 8 --> 16 /////
|
||||
// int16_t in[80/SUB_BLOCKS_8_22]
|
||||
// int32_t out[160/SUB_BLOCKS_8_22]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 80 / SUB_BLOCKS_8_22, tmpmem + 18, state->S_8_16);
|
||||
|
||||
///// 16 --> 11 /////
|
||||
// int32_t in[160/SUB_BLOCKS_8_22]
|
||||
// int32_t out[110/SUB_BLOCKS_8_22]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
tmpmem[10] = state->S_16_11[0];
|
||||
tmpmem[11] = state->S_16_11[1];
|
||||
tmpmem[12] = state->S_16_11[2];
|
||||
tmpmem[13] = state->S_16_11[3];
|
||||
tmpmem[14] = state->S_16_11[4];
|
||||
tmpmem[15] = state->S_16_11[5];
|
||||
tmpmem[16] = state->S_16_11[6];
|
||||
tmpmem[17] = state->S_16_11[7];
|
||||
state->S_16_11[0] = tmpmem[160 / SUB_BLOCKS_8_22 + 10];
|
||||
state->S_16_11[1] = tmpmem[160 / SUB_BLOCKS_8_22 + 11];
|
||||
state->S_16_11[2] = tmpmem[160 / SUB_BLOCKS_8_22 + 12];
|
||||
state->S_16_11[3] = tmpmem[160 / SUB_BLOCKS_8_22 + 13];
|
||||
state->S_16_11[4] = tmpmem[160 / SUB_BLOCKS_8_22 + 14];
|
||||
state->S_16_11[5] = tmpmem[160 / SUB_BLOCKS_8_22 + 15];
|
||||
state->S_16_11[6] = tmpmem[160 / SUB_BLOCKS_8_22 + 16];
|
||||
state->S_16_11[7] = tmpmem[160 / SUB_BLOCKS_8_22 + 17];
|
||||
|
||||
WebRtcSpl_32khzTo22khzIntToInt(tmpmem + 10, tmpmem, 10 / SUB_BLOCKS_8_22);
|
||||
|
||||
///// 11 --> 22 /////
|
||||
// int32_t in[110/SUB_BLOCKS_8_22]
|
||||
// int16_t out[220/SUB_BLOCKS_8_22]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToShort(tmpmem, 110 / SUB_BLOCKS_8_22, out, state->S_11_22);
|
||||
|
||||
// move input/output pointers 10/SUB_BLOCKS_8_22 ms seconds ahead
|
||||
in += 80 / SUB_BLOCKS_8_22;
|
||||
out += 220 / SUB_BLOCKS_8_22;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize state of 8 -> 22 resampler
|
||||
void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
state->S_8_16[k] = 0;
|
||||
state->S_16_11[k] = 0;
|
||||
state->S_11_22[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// compute two inner-products and store them to output array
|
||||
static void WebRtcSpl_DotProdIntToInt(const int32_t* in1, const int32_t* in2,
|
||||
const int16_t* coef_ptr, int32_t* out1,
|
||||
int32_t* out2)
|
||||
{
|
||||
int32_t tmp1 = 16384;
|
||||
int32_t tmp2 = 16384;
|
||||
int16_t coef;
|
||||
|
||||
coef = coef_ptr[0];
|
||||
tmp1 += coef * in1[0];
|
||||
tmp2 += coef * in2[-0];
|
||||
|
||||
coef = coef_ptr[1];
|
||||
tmp1 += coef * in1[1];
|
||||
tmp2 += coef * in2[-1];
|
||||
|
||||
coef = coef_ptr[2];
|
||||
tmp1 += coef * in1[2];
|
||||
tmp2 += coef * in2[-2];
|
||||
|
||||
coef = coef_ptr[3];
|
||||
tmp1 += coef * in1[3];
|
||||
tmp2 += coef * in2[-3];
|
||||
|
||||
coef = coef_ptr[4];
|
||||
tmp1 += coef * in1[4];
|
||||
tmp2 += coef * in2[-4];
|
||||
|
||||
coef = coef_ptr[5];
|
||||
tmp1 += coef * in1[5];
|
||||
tmp2 += coef * in2[-5];
|
||||
|
||||
coef = coef_ptr[6];
|
||||
tmp1 += coef * in1[6];
|
||||
tmp2 += coef * in2[-6];
|
||||
|
||||
coef = coef_ptr[7];
|
||||
tmp1 += coef * in1[7];
|
||||
tmp2 += coef * in2[-7];
|
||||
|
||||
coef = coef_ptr[8];
|
||||
*out1 = tmp1 + coef * in1[8];
|
||||
*out2 = tmp2 + coef * in2[-8];
|
||||
}
|
||||
|
||||
// compute two inner-products and store them to output array
|
||||
static void WebRtcSpl_DotProdIntToShort(const int32_t* in1, const int32_t* in2,
|
||||
const int16_t* coef_ptr, int16_t* out1,
|
||||
int16_t* out2)
|
||||
{
|
||||
int32_t tmp1 = 16384;
|
||||
int32_t tmp2 = 16384;
|
||||
int16_t coef;
|
||||
|
||||
coef = coef_ptr[0];
|
||||
tmp1 += coef * in1[0];
|
||||
tmp2 += coef * in2[-0];
|
||||
|
||||
coef = coef_ptr[1];
|
||||
tmp1 += coef * in1[1];
|
||||
tmp2 += coef * in2[-1];
|
||||
|
||||
coef = coef_ptr[2];
|
||||
tmp1 += coef * in1[2];
|
||||
tmp2 += coef * in2[-2];
|
||||
|
||||
coef = coef_ptr[3];
|
||||
tmp1 += coef * in1[3];
|
||||
tmp2 += coef * in2[-3];
|
||||
|
||||
coef = coef_ptr[4];
|
||||
tmp1 += coef * in1[4];
|
||||
tmp2 += coef * in2[-4];
|
||||
|
||||
coef = coef_ptr[5];
|
||||
tmp1 += coef * in1[5];
|
||||
tmp2 += coef * in2[-5];
|
||||
|
||||
coef = coef_ptr[6];
|
||||
tmp1 += coef * in1[6];
|
||||
tmp2 += coef * in2[-6];
|
||||
|
||||
coef = coef_ptr[7];
|
||||
tmp1 += coef * in1[7];
|
||||
tmp2 += coef * in2[-7];
|
||||
|
||||
coef = coef_ptr[8];
|
||||
tmp1 += coef * in1[8];
|
||||
tmp2 += coef * in2[-8];
|
||||
|
||||
// scale down, round and saturate
|
||||
tmp1 >>= 15;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
tmp2 >>= 15;
|
||||
if (tmp2 > (int32_t)0x00007FFF)
|
||||
tmp2 = 0x00007FFF;
|
||||
if (tmp2 < (int32_t)0xFFFF8000)
|
||||
tmp2 = 0xFFFF8000;
|
||||
*out1 = (int16_t)tmp1;
|
||||
*out2 = (int16_t)tmp2;
|
||||
}
|
||||
|
||||
// Resampling ratio: 11/16
|
||||
// input: int32_t (normalized, not saturated) :: size 16 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 11 * K
|
||||
// K: Number of blocks
|
||||
|
||||
void WebRtcSpl_32khzTo22khzIntToInt(const int32_t* In,
|
||||
int32_t* Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (16 input samples -> 11 output samples);
|
||||
// process in sub blocks of size 16 samples.
|
||||
int32_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
// first output sample
|
||||
Out[0] = ((int32_t)In[3] << 15) + (1 << 14);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToInt(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]);
|
||||
|
||||
// update pointers
|
||||
In += 16;
|
||||
Out += 11;
|
||||
}
|
||||
}
|
||||
|
||||
// Resampling ratio: 11/16
|
||||
// input: int32_t (normalized, not saturated) :: size 16 * K
|
||||
// output: int16_t (saturated) :: size 11 * K
|
||||
// K: Number of blocks
|
||||
|
||||
void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In,
|
||||
int16_t *Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (16 input samples -> 11 output samples);
|
||||
// process in sub blocks of size 16 samples.
|
||||
int32_t tmp;
|
||||
int32_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
// first output sample
|
||||
tmp = In[3];
|
||||
if (tmp > (int32_t)0x00007FFF)
|
||||
tmp = 0x00007FFF;
|
||||
if (tmp < (int32_t)0xFFFF8000)
|
||||
tmp = 0xFFFF8000;
|
||||
Out[0] = (int16_t)tmp;
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_DotProdIntToShort(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]);
|
||||
|
||||
// update pointers
|
||||
In += 16;
|
||||
Out += 11;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains resampling functions between 48 kHz and nb/wb.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "include/signal_processing_library.h"
|
||||
#include "resample_by_2_internal.h"
|
||||
|
||||
////////////////////////////
|
||||
///// 48 kHz -> 16 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 48 -> 16 resampler
|
||||
void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State48khzTo16khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 48 --> 48(LP) /////
|
||||
// int16_t in[480]
|
||||
// int32_t out[480]
|
||||
/////
|
||||
WebRtcSpl_LPBy2ShortToInt(in, 480, tmpmem + 16, state->S_48_48);
|
||||
|
||||
///// 48 --> 32 /////
|
||||
// int32_t in[480]
|
||||
// int32_t out[320]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
memcpy(tmpmem + 8, state->S_48_32, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_48_32, tmpmem + 488, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 160);
|
||||
|
||||
///// 32 --> 16 /////
|
||||
// int32_t in[320]
|
||||
// int16_t out[160]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 320, out, state->S_32_16);
|
||||
}
|
||||
|
||||
// initialize state of 48 -> 16 resampler
|
||||
void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state)
|
||||
{
|
||||
memset(state->S_48_48, 0, 16 * sizeof(int32_t));
|
||||
memset(state->S_48_32, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_32_16, 0, 8 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
///// 16 kHz -> 48 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 16 -> 48 resampler
|
||||
void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State16khzTo48khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 16 --> 32 /////
|
||||
// int16_t in[160]
|
||||
// int32_t out[320]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 160, tmpmem + 16, state->S_16_32);
|
||||
|
||||
///// 32 --> 24 /////
|
||||
// int32_t in[320]
|
||||
// int32_t out[240]
|
||||
// copy state to and from input array
|
||||
/////
|
||||
memcpy(tmpmem + 8, state->S_32_24, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_32_24, tmpmem + 328, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample32khzTo24khz(tmpmem + 8, tmpmem, 80);
|
||||
|
||||
///// 24 --> 48 /////
|
||||
// int32_t in[240]
|
||||
// int16_t out[480]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48);
|
||||
}
|
||||
|
||||
// initialize state of 16 -> 48 resampler
|
||||
void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state)
|
||||
{
|
||||
memset(state->S_16_32, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_32_24, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_24_48, 0, 8 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
///// 48 kHz -> 8 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 48 -> 8 resampler
|
||||
void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State48khzTo8khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 48 --> 24 /////
|
||||
// int16_t in[480]
|
||||
// int32_t out[240]
|
||||
/////
|
||||
WebRtcSpl_DownBy2ShortToInt(in, 480, tmpmem + 256, state->S_48_24);
|
||||
|
||||
///// 24 --> 24(LP) /////
|
||||
// int32_t in[240]
|
||||
// int32_t out[240]
|
||||
/////
|
||||
WebRtcSpl_LPBy2IntToInt(tmpmem + 256, 240, tmpmem + 16, state->S_24_24);
|
||||
|
||||
///// 24 --> 16 /////
|
||||
// int32_t in[240]
|
||||
// int32_t out[160]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
memcpy(tmpmem + 8, state->S_24_16, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_24_16, tmpmem + 248, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 80);
|
||||
|
||||
///// 16 --> 8 /////
|
||||
// int32_t in[160]
|
||||
// int16_t out[80]
|
||||
/////
|
||||
WebRtcSpl_DownBy2IntToShort(tmpmem, 160, out, state->S_16_8);
|
||||
}
|
||||
|
||||
// initialize state of 48 -> 8 resampler
|
||||
void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state)
|
||||
{
|
||||
memset(state->S_48_24, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_24_24, 0, 16 * sizeof(int32_t));
|
||||
memset(state->S_24_16, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_16_8, 0, 8 * sizeof(int32_t));
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
///// 8 kHz -> 48 kHz /////
|
||||
////////////////////////////
|
||||
|
||||
// 8 -> 48 resampler
|
||||
void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out,
|
||||
WebRtcSpl_State8khzTo48khz* state, int32_t* tmpmem)
|
||||
{
|
||||
///// 8 --> 16 /////
|
||||
// int16_t in[80]
|
||||
// int32_t out[160]
|
||||
/////
|
||||
WebRtcSpl_UpBy2ShortToInt(in, 80, tmpmem + 264, state->S_8_16);
|
||||
|
||||
///// 16 --> 12 /////
|
||||
// int32_t in[160]
|
||||
// int32_t out[120]
|
||||
/////
|
||||
// copy state to and from input array
|
||||
memcpy(tmpmem + 256, state->S_16_12, 8 * sizeof(int32_t));
|
||||
memcpy(state->S_16_12, tmpmem + 416, 8 * sizeof(int32_t));
|
||||
WebRtcSpl_Resample32khzTo24khz(tmpmem + 256, tmpmem + 240, 40);
|
||||
|
||||
///// 12 --> 24 /////
|
||||
// int32_t in[120]
|
||||
// int16_t out[240]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToInt(tmpmem + 240, 120, tmpmem, state->S_12_24);
|
||||
|
||||
///// 24 --> 48 /////
|
||||
// int32_t in[240]
|
||||
// int16_t out[480]
|
||||
/////
|
||||
WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48);
|
||||
}
|
||||
|
||||
// initialize state of 8 -> 48 resampler
|
||||
void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state)
|
||||
{
|
||||
memset(state->S_8_16, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_16_12, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_12_24, 0, 8 * sizeof(int32_t));
|
||||
memset(state->S_24_48, 0, 8 * sizeof(int32_t));
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling by two functions.
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15};
|
||||
static const uint32_t kResampleAllpass2[3] =
|
||||
{12199, 37471 << 15, 60255 << 15};
|
||||
|
||||
// Multiply two 32-bit values and accumulate to another input value.
|
||||
// Return: state + ((diff * tbl_value) >> 16)
|
||||
|
||||
static __inline int32_t MUL_ACCUM_1(int32_t tbl_value,
|
||||
int32_t diff,
|
||||
int32_t state) {
|
||||
int32_t result;
|
||||
__asm __volatile ("smlawb %0, %1, %2, %3": "=r"(result): "r"(diff),
|
||||
"r"(tbl_value), "r"(state));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Multiply two 32-bit values and accumulate to another input value.
|
||||
// Return: Return: state + (((diff << 1) * tbl_value) >> 32)
|
||||
//
|
||||
// The reason to introduce this function is that, in case we can't use smlawb
|
||||
// instruction (in MUL_ACCUM_1) due to input value range, we can still use
|
||||
// smmla to save some cycles.
|
||||
|
||||
static __inline int32_t MUL_ACCUM_2(int32_t tbl_value,
|
||||
int32_t diff,
|
||||
int32_t state) {
|
||||
int32_t result;
|
||||
__asm __volatile ("smmla %0, %1, %2, %3": "=r"(result): "r"(diff << 1),
|
||||
"r"(tbl_value), "r"(state));
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528};
|
||||
static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255};
|
||||
|
||||
// Multiply a 32-bit value with a 16-bit value and accumulate to another input:
|
||||
#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
|
||||
#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c)
|
||||
|
||||
#endif // WEBRTC_ARCH_ARM_V7
|
||||
|
||||
|
||||
// decimator
|
||||
#if !defined(MIPS32_LE)
|
||||
void WebRtcSpl_DownsampleBy2(const int16_t* in, int16_t len,
|
||||
int16_t* out, int32_t* filtState) {
|
||||
int32_t tmp1, tmp2, diff, in32, out32;
|
||||
int16_t i;
|
||||
|
||||
register int32_t state0 = filtState[0];
|
||||
register int32_t state1 = filtState[1];
|
||||
register int32_t state2 = filtState[2];
|
||||
register int32_t state3 = filtState[3];
|
||||
register int32_t state4 = filtState[4];
|
||||
register int32_t state5 = filtState[5];
|
||||
register int32_t state6 = filtState[6];
|
||||
register int32_t state7 = filtState[7];
|
||||
|
||||
for (i = (len >> 1); i > 0; i--) {
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// upper allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// add two allpass outputs, divide by two and round
|
||||
out32 = (state3 + state7 + 1024) >> 11;
|
||||
|
||||
// limit amplitude to prevent wrap-around, and write to output array
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
}
|
||||
|
||||
filtState[0] = state0;
|
||||
filtState[1] = state1;
|
||||
filtState[2] = state2;
|
||||
filtState[3] = state3;
|
||||
filtState[4] = state4;
|
||||
filtState[5] = state5;
|
||||
filtState[6] = state6;
|
||||
filtState[7] = state7;
|
||||
}
|
||||
#endif // #if defined(MIPS32_LE)
|
||||
|
||||
|
||||
void WebRtcSpl_UpsampleBy2(const int16_t* in, int16_t len,
|
||||
int16_t* out, int32_t* filtState) {
|
||||
int32_t tmp1, tmp2, diff, in32, out32;
|
||||
int16_t i;
|
||||
|
||||
register int32_t state0 = filtState[0];
|
||||
register int32_t state1 = filtState[1];
|
||||
register int32_t state2 = filtState[2];
|
||||
register int32_t state3 = filtState[3];
|
||||
register int32_t state4 = filtState[4];
|
||||
register int32_t state5 = filtState[5];
|
||||
register int32_t state6 = filtState[6];
|
||||
register int32_t state7 = filtState[7];
|
||||
|
||||
for (i = len; i > 0; i--) {
|
||||
// lower allpass filter
|
||||
in32 = (int32_t)(*in++) << 10;
|
||||
diff = in32 - state1;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0);
|
||||
state0 = in32;
|
||||
diff = tmp1 - state2;
|
||||
tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1);
|
||||
state1 = tmp1;
|
||||
diff = tmp2 - state3;
|
||||
state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2);
|
||||
state2 = tmp2;
|
||||
|
||||
// round; limit amplitude to prevent wrap-around; write to output array
|
||||
out32 = (state3 + 512) >> 10;
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
|
||||
// upper allpass filter
|
||||
diff = in32 - state5;
|
||||
tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4);
|
||||
state4 = in32;
|
||||
diff = tmp1 - state6;
|
||||
tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5);
|
||||
state5 = tmp1;
|
||||
diff = tmp2 - state7;
|
||||
state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6);
|
||||
state6 = tmp2;
|
||||
|
||||
// round; limit amplitude to prevent wrap-around; write to output array
|
||||
out32 = (state7 + 512) >> 10;
|
||||
*out++ = WebRtcSpl_SatW32ToW16(out32);
|
||||
}
|
||||
|
||||
filtState[0] = state0;
|
||||
filtState[1] = state1;
|
||||
filtState[2] = state2;
|
||||
filtState[3] = state3;
|
||||
filtState[4] = state4;
|
||||
filtState[5] = state5;
|
||||
filtState[6] = state6;
|
||||
filtState[7] = state7;
|
||||
}
|
|
@ -0,0 +1,679 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file contains some internal resampling functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "resample_by_2_internal.h"
|
||||
|
||||
// allpass filter coefficients.
|
||||
static const int16_t kResampleAllpass[2][3] = {
|
||||
{821, 6110, 12382},
|
||||
{3050, 9368, 15063}
|
||||
};
|
||||
|
||||
//
|
||||
// decimator
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384) OVERWRITTEN!
|
||||
// output: int16_t (saturated) (of length len/2)
|
||||
// state: filter state array; length = 8
|
||||
|
||||
void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter (operates on even input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
in[i << 1] = (state[3] >> 1);
|
||||
}
|
||||
|
||||
in++;
|
||||
|
||||
// upper allpass filter (operates on odd input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
in[i << 1] = (state[7] >> 1);
|
||||
}
|
||||
|
||||
in--;
|
||||
|
||||
// combine allpass outputs
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
// divide by two, add both allpass outputs and round
|
||||
tmp0 = (in[i << 1] + in[(i << 1) + 1]) >> 15;
|
||||
tmp1 = (in[(i << 1) + 2] + in[(i << 1) + 3]) >> 15;
|
||||
if (tmp0 > (int32_t)0x00007FFF)
|
||||
tmp0 = 0x00007FFF;
|
||||
if (tmp0 < (int32_t)0xFFFF8000)
|
||||
tmp0 = 0xFFFF8000;
|
||||
out[i] = (int16_t)tmp0;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
out[i + 1] = (int16_t)tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// decimator
|
||||
// input: int16_t
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len/2)
|
||||
// state: filter state array; length = 8
|
||||
|
||||
void WebRtcSpl_DownBy2ShortToInt(const int16_t *in,
|
||||
int32_t len,
|
||||
int32_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter (operates on even input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
out[i] = (state[3] >> 1);
|
||||
}
|
||||
|
||||
in++;
|
||||
|
||||
// upper allpass filter (operates on odd input samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// divide by two and store temporarily
|
||||
out[i] += (state[7] >> 1);
|
||||
}
|
||||
|
||||
in--;
|
||||
}
|
||||
|
||||
//
|
||||
// interpolator
|
||||
// input: int16_t
|
||||
// output: int32_t (normalized, not saturated) (of length len*2)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len, int32_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
// upper allpass filter (generates odd output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[7] >> 15;
|
||||
}
|
||||
|
||||
out++;
|
||||
|
||||
// lower allpass filter (generates even output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3] >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// interpolator
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384)
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len*2)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
// upper allpass filter (generates odd output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[7];
|
||||
}
|
||||
|
||||
out++;
|
||||
|
||||
// lower allpass filter (generates even output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// interpolator
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384)
|
||||
// output: int16_t (saturated) (of length len*2)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len, int16_t *out,
|
||||
int32_t *state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
// upper allpass filter (generates odd output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// scale down, saturate and store
|
||||
tmp1 = state[7] >> 15;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
out[i << 1] = (int16_t)tmp1;
|
||||
}
|
||||
|
||||
out++;
|
||||
|
||||
// lower allpass filter (generates even output samples)
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i];
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, saturate and store
|
||||
tmp1 = state[3] >> 15;
|
||||
if (tmp1 > (int32_t)0x00007FFF)
|
||||
tmp1 = 0x00007FFF;
|
||||
if (tmp1 < (int32_t)0xFFFF8000)
|
||||
tmp1 = 0xFFFF8000;
|
||||
out[i << 1] = (int16_t)tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
// lowpass filter
|
||||
// input: int16_t
|
||||
// output: int32_t (normalized, not saturated)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out,
|
||||
int32_t* state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter: odd input -> even output samples
|
||||
in++;
|
||||
// initial state of polyphase delay element
|
||||
tmp0 = state[12];
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3] >> 1;
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
}
|
||||
in--;
|
||||
|
||||
// upper allpass filter: even input -> even output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15;
|
||||
}
|
||||
|
||||
// switch to odd output samples
|
||||
out++;
|
||||
|
||||
// lower allpass filter: even input -> odd output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[9];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[8] + diff * kResampleAllpass[1][0];
|
||||
state[8] = tmp0;
|
||||
diff = tmp1 - state[10];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[9] + diff * kResampleAllpass[1][1];
|
||||
state[9] = tmp1;
|
||||
diff = tmp0 - state[11];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[11] = state[10] + diff * kResampleAllpass[1][2];
|
||||
state[10] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[11] >> 1;
|
||||
}
|
||||
|
||||
// upper allpass filter: odd input -> odd output samples
|
||||
in++;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14);
|
||||
diff = tmp0 - state[13];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[12] + diff * kResampleAllpass[0][0];
|
||||
state[12] = tmp0;
|
||||
diff = tmp1 - state[14];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[13] + diff * kResampleAllpass[0][1];
|
||||
state[13] = tmp1;
|
||||
diff = tmp0 - state[15];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[15] = state[14] + diff * kResampleAllpass[0][2];
|
||||
state[14] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15;
|
||||
}
|
||||
}
|
||||
|
||||
// lowpass filter
|
||||
// input: int32_t (shifted 15 positions to the left, + offset 16384)
|
||||
// output: int32_t (normalized, not saturated)
|
||||
// state: filter state array; length = 8
|
||||
void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
|
||||
int32_t* state)
|
||||
{
|
||||
int32_t tmp0, tmp1, diff;
|
||||
int32_t i;
|
||||
|
||||
len >>= 1;
|
||||
|
||||
// lower allpass filter: odd input -> even output samples
|
||||
in++;
|
||||
// initial state of polyphase delay element
|
||||
tmp0 = state[12];
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
diff = tmp0 - state[1];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[0] + diff * kResampleAllpass[1][0];
|
||||
state[0] = tmp0;
|
||||
diff = tmp1 - state[2];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[1] + diff * kResampleAllpass[1][1];
|
||||
state[1] = tmp1;
|
||||
diff = tmp0 - state[3];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[3] = state[2] + diff * kResampleAllpass[1][2];
|
||||
state[2] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[3] >> 1;
|
||||
tmp0 = in[i << 1];
|
||||
}
|
||||
in--;
|
||||
|
||||
// upper allpass filter: even input -> even output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[5];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[4] + diff * kResampleAllpass[0][0];
|
||||
state[4] = tmp0;
|
||||
diff = tmp1 - state[6];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[5] + diff * kResampleAllpass[0][1];
|
||||
state[5] = tmp1;
|
||||
diff = tmp0 - state[7];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[7] = state[6] + diff * kResampleAllpass[0][2];
|
||||
state[6] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15;
|
||||
}
|
||||
|
||||
// switch to odd output samples
|
||||
out++;
|
||||
|
||||
// lower allpass filter: even input -> odd output samples
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[9];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[8] + diff * kResampleAllpass[1][0];
|
||||
state[8] = tmp0;
|
||||
diff = tmp1 - state[10];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[9] + diff * kResampleAllpass[1][1];
|
||||
state[9] = tmp1;
|
||||
diff = tmp0 - state[11];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[11] = state[10] + diff * kResampleAllpass[1][2];
|
||||
state[10] = tmp0;
|
||||
|
||||
// scale down, round and store
|
||||
out[i << 1] = state[11] >> 1;
|
||||
}
|
||||
|
||||
// upper allpass filter: odd input -> odd output samples
|
||||
in++;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tmp0 = in[i << 1];
|
||||
diff = tmp0 - state[13];
|
||||
// scale down and round
|
||||
diff = (diff + (1 << 13)) >> 14;
|
||||
tmp1 = state[12] + diff * kResampleAllpass[0][0];
|
||||
state[12] = tmp0;
|
||||
diff = tmp1 - state[14];
|
||||
// scale down and round
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
tmp0 = state[13] + diff * kResampleAllpass[0][1];
|
||||
state[13] = tmp1;
|
||||
diff = tmp0 - state[15];
|
||||
// scale down and truncate
|
||||
diff = diff >> 14;
|
||||
if (diff < 0)
|
||||
diff += 1;
|
||||
state[15] = state[14] + diff * kResampleAllpass[0][2];
|
||||
state[14] = tmp0;
|
||||
|
||||
// average the two allpass outputs, scale down and store
|
||||
out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file contains some internal resampling functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
|
||||
#define WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
|
||||
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
/*******************************************************************
|
||||
* resample_by_2_fast.c
|
||||
* Functions for internal use in the other resample functions
|
||||
******************************************************************/
|
||||
void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out,
|
||||
int32_t *state);
|
||||
|
||||
void WebRtcSpl_DownBy2ShortToInt(const int16_t *in, int32_t len,
|
||||
int32_t *out, int32_t *state);
|
||||
|
||||
void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len,
|
||||
int32_t *out, int32_t *state);
|
||||
|
||||
void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out,
|
||||
int32_t *state);
|
||||
|
||||
void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len,
|
||||
int16_t *out, int32_t *state);
|
||||
|
||||
void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len,
|
||||
int32_t* out, int32_t* state);
|
||||
|
||||
void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out,
|
||||
int32_t* state);
|
||||
|
||||
#endif // WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the resampling functions between 48, 44, 32 and 24 kHz.
|
||||
* The description headers can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
// interpolation coefficients
|
||||
static const int16_t kCoefficients48To32[2][8] = {
|
||||
{778, -2050, 1087, 23285, 12903, -3783, 441, 222},
|
||||
{222, 441, -3783, 12903, 23285, 1087, -2050, 778}
|
||||
};
|
||||
|
||||
static const int16_t kCoefficients32To24[3][8] = {
|
||||
{767, -2362, 2434, 24406, 10620, -3838, 721, 90},
|
||||
{386, -381, -2646, 19062, 19062, -2646, -381, 386},
|
||||
{90, 721, -3838, 10620, 24406, 2434, -2362, 767}
|
||||
};
|
||||
|
||||
static const int16_t kCoefficients44To32[4][9] = {
|
||||
{117, -669, 2245, -6183, 26267, 13529, -3245, 845, -138},
|
||||
{-101, 612, -2283, 8532, 29790, -5138, 1789, -524, 91},
|
||||
{50, -292, 1016, -3064, 32010, 3933, -1147, 315, -53},
|
||||
{-156, 974, -3863, 18603, 21691, -6246, 2353, -712, 126}
|
||||
};
|
||||
|
||||
// Resampling ratio: 2/3
|
||||
// input: int32_t (normalized, not saturated) :: size 3 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 2 * K
|
||||
// K: number of blocks
|
||||
|
||||
void WebRtcSpl_Resample48khzTo32khz(const int32_t *In, int32_t *Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (3 input samples -> 2 output samples);
|
||||
// process in sub blocks of size 3 samples.
|
||||
int32_t tmp;
|
||||
int32_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients48To32[0][0] * In[0];
|
||||
tmp += kCoefficients48To32[0][1] * In[1];
|
||||
tmp += kCoefficients48To32[0][2] * In[2];
|
||||
tmp += kCoefficients48To32[0][3] * In[3];
|
||||
tmp += kCoefficients48To32[0][4] * In[4];
|
||||
tmp += kCoefficients48To32[0][5] * In[5];
|
||||
tmp += kCoefficients48To32[0][6] * In[6];
|
||||
tmp += kCoefficients48To32[0][7] * In[7];
|
||||
Out[0] = tmp;
|
||||
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients48To32[1][0] * In[1];
|
||||
tmp += kCoefficients48To32[1][1] * In[2];
|
||||
tmp += kCoefficients48To32[1][2] * In[3];
|
||||
tmp += kCoefficients48To32[1][3] * In[4];
|
||||
tmp += kCoefficients48To32[1][4] * In[5];
|
||||
tmp += kCoefficients48To32[1][5] * In[6];
|
||||
tmp += kCoefficients48To32[1][6] * In[7];
|
||||
tmp += kCoefficients48To32[1][7] * In[8];
|
||||
Out[1] = tmp;
|
||||
|
||||
// update pointers
|
||||
In += 3;
|
||||
Out += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Resampling ratio: 3/4
|
||||
// input: int32_t (normalized, not saturated) :: size 4 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 3 * K
|
||||
// K: number of blocks
|
||||
|
||||
void WebRtcSpl_Resample32khzTo24khz(const int32_t *In, int32_t *Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (4 input samples -> 3 output samples);
|
||||
// process in sub blocks of size 4 samples.
|
||||
int32_t m;
|
||||
int32_t tmp;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients32To24[0][0] * In[0];
|
||||
tmp += kCoefficients32To24[0][1] * In[1];
|
||||
tmp += kCoefficients32To24[0][2] * In[2];
|
||||
tmp += kCoefficients32To24[0][3] * In[3];
|
||||
tmp += kCoefficients32To24[0][4] * In[4];
|
||||
tmp += kCoefficients32To24[0][5] * In[5];
|
||||
tmp += kCoefficients32To24[0][6] * In[6];
|
||||
tmp += kCoefficients32To24[0][7] * In[7];
|
||||
Out[0] = tmp;
|
||||
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients32To24[1][0] * In[1];
|
||||
tmp += kCoefficients32To24[1][1] * In[2];
|
||||
tmp += kCoefficients32To24[1][2] * In[3];
|
||||
tmp += kCoefficients32To24[1][3] * In[4];
|
||||
tmp += kCoefficients32To24[1][4] * In[5];
|
||||
tmp += kCoefficients32To24[1][5] * In[6];
|
||||
tmp += kCoefficients32To24[1][6] * In[7];
|
||||
tmp += kCoefficients32To24[1][7] * In[8];
|
||||
Out[1] = tmp;
|
||||
|
||||
tmp = 1 << 14;
|
||||
tmp += kCoefficients32To24[2][0] * In[2];
|
||||
tmp += kCoefficients32To24[2][1] * In[3];
|
||||
tmp += kCoefficients32To24[2][2] * In[4];
|
||||
tmp += kCoefficients32To24[2][3] * In[5];
|
||||
tmp += kCoefficients32To24[2][4] * In[6];
|
||||
tmp += kCoefficients32To24[2][5] * In[7];
|
||||
tmp += kCoefficients32To24[2][6] * In[8];
|
||||
tmp += kCoefficients32To24[2][7] * In[9];
|
||||
Out[2] = tmp;
|
||||
|
||||
// update pointers
|
||||
In += 4;
|
||||
Out += 3;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// fractional resampling filters
|
||||
// Fout = 11/16 * Fin
|
||||
// Fout = 8/11 * Fin
|
||||
//
|
||||
|
||||
// compute two inner-products and store them to output array
|
||||
static void WebRtcSpl_ResampDotProduct(const int32_t *in1, const int32_t *in2,
|
||||
const int16_t *coef_ptr, int32_t *out1,
|
||||
int32_t *out2)
|
||||
{
|
||||
int32_t tmp1 = 16384;
|
||||
int32_t tmp2 = 16384;
|
||||
int16_t coef;
|
||||
|
||||
coef = coef_ptr[0];
|
||||
tmp1 += coef * in1[0];
|
||||
tmp2 += coef * in2[-0];
|
||||
|
||||
coef = coef_ptr[1];
|
||||
tmp1 += coef * in1[1];
|
||||
tmp2 += coef * in2[-1];
|
||||
|
||||
coef = coef_ptr[2];
|
||||
tmp1 += coef * in1[2];
|
||||
tmp2 += coef * in2[-2];
|
||||
|
||||
coef = coef_ptr[3];
|
||||
tmp1 += coef * in1[3];
|
||||
tmp2 += coef * in2[-3];
|
||||
|
||||
coef = coef_ptr[4];
|
||||
tmp1 += coef * in1[4];
|
||||
tmp2 += coef * in2[-4];
|
||||
|
||||
coef = coef_ptr[5];
|
||||
tmp1 += coef * in1[5];
|
||||
tmp2 += coef * in2[-5];
|
||||
|
||||
coef = coef_ptr[6];
|
||||
tmp1 += coef * in1[6];
|
||||
tmp2 += coef * in2[-6];
|
||||
|
||||
coef = coef_ptr[7];
|
||||
tmp1 += coef * in1[7];
|
||||
tmp2 += coef * in2[-7];
|
||||
|
||||
coef = coef_ptr[8];
|
||||
*out1 = tmp1 + coef * in1[8];
|
||||
*out2 = tmp2 + coef * in2[-8];
|
||||
}
|
||||
|
||||
// Resampling ratio: 8/11
|
||||
// input: int32_t (normalized, not saturated) :: size 11 * K
|
||||
// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 8 * K
|
||||
// K: number of blocks
|
||||
|
||||
void WebRtcSpl_Resample44khzTo32khz(const int32_t *In, int32_t *Out,
|
||||
int32_t K)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Filter operation:
|
||||
//
|
||||
// Perform resampling (11 input samples -> 8 output samples);
|
||||
// process in sub blocks of size 11 samples.
|
||||
int32_t tmp;
|
||||
int32_t m;
|
||||
|
||||
for (m = 0; m < K; m++)
|
||||
{
|
||||
tmp = 1 << 14;
|
||||
|
||||
// first output sample
|
||||
Out[0] = ((int32_t)In[3] << 15) + tmp;
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
tmp += kCoefficients44To32[3][0] * In[5];
|
||||
tmp += kCoefficients44To32[3][1] * In[6];
|
||||
tmp += kCoefficients44To32[3][2] * In[7];
|
||||
tmp += kCoefficients44To32[3][3] * In[8];
|
||||
tmp += kCoefficients44To32[3][4] * In[9];
|
||||
tmp += kCoefficients44To32[3][5] * In[10];
|
||||
tmp += kCoefficients44To32[3][6] * In[11];
|
||||
tmp += kCoefficients44To32[3][7] * In[12];
|
||||
tmp += kCoefficients44To32[3][8] * In[13];
|
||||
Out[4] = tmp;
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_ResampDotProduct(&In[0], &In[17], kCoefficients44To32[0], &Out[1], &Out[7]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_ResampDotProduct(&In[2], &In[15], kCoefficients44To32[1], &Out[2], &Out[6]);
|
||||
|
||||
// sum and accumulate filter coefficients and input samples
|
||||
WebRtcSpl_ResampDotProduct(&In[3], &In[14], kCoefficients44To32[2], &Out[3], &Out[5]);
|
||||
|
||||
// update pointers
|
||||
In += 11;
|
||||
Out += 8;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/* The global function contained in this file initializes SPL function
|
||||
* pointers, currently only for ARM platforms.
|
||||
*
|
||||
* Some code came from common/rtcd.c in the WebM project.
|
||||
*/
|
||||
|
||||
#include "include/real_fft.h"
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
|
||||
/* Declare function pointers. */
|
||||
MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
|
||||
MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
|
||||
MaxValueW16 WebRtcSpl_MaxValueW16;
|
||||
MaxValueW32 WebRtcSpl_MaxValueW32;
|
||||
MinValueW16 WebRtcSpl_MinValueW16;
|
||||
MinValueW32 WebRtcSpl_MinValueW32;
|
||||
CrossCorrelation WebRtcSpl_CrossCorrelation;
|
||||
DownsampleFast WebRtcSpl_DownsampleFast;
|
||||
ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
|
||||
CreateRealFFT WebRtcSpl_CreateRealFFT;
|
||||
FreeRealFFT WebRtcSpl_FreeRealFFT;
|
||||
RealForwardFFT WebRtcSpl_RealForwardFFT;
|
||||
RealInverseFFT WebRtcSpl_RealInverseFFT;
|
||||
|
||||
#if (defined(WEBRTC_DETECT_ARM_NEON) || !defined(WEBRTC_ARCH_ARM_NEON)) && \
|
||||
!defined(MIPS32_LE)
|
||||
/* Initialize function pointers to the generic C version. */
|
||||
static void InitPointersToC() {
|
||||
WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C;
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
|
||||
WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C;
|
||||
WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C;
|
||||
WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C;
|
||||
WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C;
|
||||
WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC;
|
||||
WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRoundC;
|
||||
WebRtcSpl_CreateRealFFT = WebRtcSpl_CreateRealFFTC;
|
||||
WebRtcSpl_FreeRealFFT = WebRtcSpl_FreeRealFFTC;
|
||||
WebRtcSpl_RealForwardFFT = WebRtcSpl_RealForwardFFTC;
|
||||
WebRtcSpl_RealInverseFFT = WebRtcSpl_RealInverseFFTC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_DETECT_ARM_NEON) || defined(WEBRTC_ARCH_ARM_NEON)
|
||||
/* Initialize function pointers to the Neon version. */
|
||||
static void InitPointersToNeon() {
|
||||
WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon;
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon;
|
||||
WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon;
|
||||
WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon;
|
||||
WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon;
|
||||
WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon;
|
||||
WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationNeon;
|
||||
WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRoundNeon;
|
||||
WebRtcSpl_CreateRealFFT = WebRtcSpl_CreateRealFFTNeon;
|
||||
WebRtcSpl_FreeRealFFT = WebRtcSpl_FreeRealFFTNeon;
|
||||
WebRtcSpl_RealForwardFFT = WebRtcSpl_RealForwardFFTNeon;
|
||||
WebRtcSpl_RealInverseFFT = WebRtcSpl_RealInverseFFTNeon;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MIPS32_LE)
|
||||
/* Initialize function pointers to the MIPS version. */
|
||||
static void InitPointersToMIPS() {
|
||||
WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips;
|
||||
WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips;
|
||||
WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips;
|
||||
WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips;
|
||||
WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips;
|
||||
WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelation_mips;
|
||||
WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips;
|
||||
WebRtcSpl_CreateRealFFT = WebRtcSpl_CreateRealFFTC;
|
||||
WebRtcSpl_FreeRealFFT = WebRtcSpl_FreeRealFFTC;
|
||||
WebRtcSpl_RealForwardFFT = WebRtcSpl_RealForwardFFTC;
|
||||
WebRtcSpl_RealInverseFFT = WebRtcSpl_RealInverseFFTC;
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32_mips;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound_mips;
|
||||
#else
|
||||
WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRound =
|
||||
WebRtcSpl_ScaleAndAddVectorsWithRoundC;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void InitFunctionPointers(void) {
|
||||
#if defined(WEBRTC_DETECT_ARM_NEON)
|
||||
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
|
||||
InitPointersToNeon();
|
||||
} else {
|
||||
InitPointersToC();
|
||||
}
|
||||
#elif defined(WEBRTC_ARCH_ARM_NEON)
|
||||
InitPointersToNeon();
|
||||
#elif defined(MIPS32_LE)
|
||||
InitPointersToMIPS();
|
||||
#else
|
||||
InitPointersToC();
|
||||
#endif /* WEBRTC_DETECT_ARM_NEON */
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#include <pthread.h>
|
||||
|
||||
static void once(void (*func)(void)) {
|
||||
static pthread_once_t lock = PTHREAD_ONCE_INIT;
|
||||
pthread_once(&lock, func);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
static void once(void (*func)(void)) {
|
||||
/* Didn't use InitializeCriticalSection() since there's no race-free context
|
||||
* in which to execute it.
|
||||
*
|
||||
* TODO(kma): Change to different implementation (e.g.
|
||||
* InterlockedCompareExchangePointer) to avoid issues similar to
|
||||
* http://code.google.com/p/webm/issues/detail?id=467.
|
||||
*/
|
||||
static CRITICAL_SECTION lock = {(void *)((size_t)-1), -1, 0, 0, 0, 0};
|
||||
static int done = 0;
|
||||
|
||||
EnterCriticalSection(&lock);
|
||||
if (!done) {
|
||||
func();
|
||||
done = 1;
|
||||
}
|
||||
LeaveCriticalSection(&lock);
|
||||
}
|
||||
|
||||
/* There's no fallback version as an #else block here to ensure thread safety.
|
||||
* In case of neither pthread for WEBRTC_POSIX nor _WIN32 is present, build
|
||||
* system should pick it up.
|
||||
*/
|
||||
#endif /* WEBRTC_POSIX */
|
||||
|
||||
void WebRtcSpl_Init() {
|
||||
once(InitFunctionPointers);
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_Sqrt().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
int32_t WebRtcSpl_SqrtLocal(int32_t in);
|
||||
|
||||
int32_t WebRtcSpl_SqrtLocal(int32_t in)
|
||||
{
|
||||
|
||||
int16_t x_half, t16;
|
||||
int32_t A, B, x2;
|
||||
|
||||
/* The following block performs:
|
||||
y=in/2
|
||||
x=y-2^30
|
||||
x_half=x/2^31
|
||||
t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4)
|
||||
+ 0.875*((x_half)^5)
|
||||
*/
|
||||
|
||||
B = in;
|
||||
|
||||
B = WEBRTC_SPL_RSHIFT_W32(B, 1); // B = in/2
|
||||
B = B - ((int32_t)0x40000000); // B = in/2 - 1/2
|
||||
x_half = (int16_t)WEBRTC_SPL_RSHIFT_W32(B, 16);// x_half = x/2 = (in-1)/2
|
||||
B = B + ((int32_t)0x40000000); // B = 1 + x/2
|
||||
B = B + ((int32_t)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31)
|
||||
|
||||
x2 = ((int32_t)x_half) * ((int32_t)x_half) * 2; // A = (x/2)^2
|
||||
A = -x2; // A = -(x/2)^2
|
||||
B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2
|
||||
|
||||
A = WEBRTC_SPL_RSHIFT_W32(A, 16);
|
||||
A = A * A * 2; // A = (x/2)^4
|
||||
t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
|
||||
B = B + WEBRTC_SPL_MUL_16_16(-20480, t16) * 2; // B = B - 0.625*A
|
||||
// After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4
|
||||
|
||||
t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
|
||||
A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = (x/2)^5
|
||||
t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16);
|
||||
B = B + WEBRTC_SPL_MUL_16_16(28672, t16) * 2; // B = B + 0.875*A
|
||||
// After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5
|
||||
|
||||
t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(x2, 16);
|
||||
A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = x/2^3
|
||||
|
||||
B = B + (A >> 1); // B = B + 0.5*A
|
||||
// After this, B = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 - 0.625*(x/2)^4 + 0.875*(x/2)^5
|
||||
|
||||
B = B + ((int32_t)32768); // Round off bit
|
||||
|
||||
return B;
|
||||
}
|
||||
|
||||
int32_t WebRtcSpl_Sqrt(int32_t value)
|
||||
{
|
||||
/*
|
||||
Algorithm:
|
||||
|
||||
Six term Taylor Series is used here to compute the square root of a number
|
||||
y^0.5 = (1+x)^0.5 where x = y-1
|
||||
= 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5)
|
||||
0.5 <= x < 1
|
||||
|
||||
Example of how the algorithm works, with ut=sqrt(in), and
|
||||
with in=73632 and ut=271 (even shift value case):
|
||||
|
||||
in=73632
|
||||
y= in/131072
|
||||
x=y-1
|
||||
t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5)
|
||||
ut=t*(1/sqrt(2))*512
|
||||
|
||||
or:
|
||||
|
||||
in=73632
|
||||
in2=73632*2^14
|
||||
y= in2/2^31
|
||||
x=y-1
|
||||
t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5)
|
||||
ut=t*(1/sqrt(2))
|
||||
ut2=ut*2^9
|
||||
|
||||
which gives:
|
||||
|
||||
in = 73632
|
||||
in2 = 1206386688
|
||||
y = 0.56176757812500
|
||||
x = -0.43823242187500
|
||||
t = 0.74973506527313
|
||||
ut = 0.53014274874797
|
||||
ut2 = 2.714330873589594e+002
|
||||
|
||||
or:
|
||||
|
||||
in=73632
|
||||
in2=73632*2^14
|
||||
y=in2/2
|
||||
x=y-2^30
|
||||
x_half=x/2^31
|
||||
t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4)
|
||||
+ 0.875*((x_half)^5)
|
||||
ut=t*(1/sqrt(2))
|
||||
ut2=ut*2^9
|
||||
|
||||
which gives:
|
||||
|
||||
in = 73632
|
||||
in2 = 1206386688
|
||||
y = 603193344
|
||||
x = -470548480
|
||||
x_half = -0.21911621093750
|
||||
t = 0.74973506527313
|
||||
ut = 0.53014274874797
|
||||
ut2 = 2.714330873589594e+002
|
||||
|
||||
*/
|
||||
|
||||
int16_t x_norm, nshift, t16, sh;
|
||||
int32_t A;
|
||||
|
||||
int16_t k_sqrt_2 = 23170; // 1/sqrt2 (==5a82)
|
||||
|
||||
A = value;
|
||||
|
||||
if (A == 0)
|
||||
return (int32_t)0; // sqrt(0) = 0
|
||||
|
||||
sh = WebRtcSpl_NormW32(A); // # shifts to normalize A
|
||||
A = WEBRTC_SPL_LSHIFT_W32(A, sh); // Normalize A
|
||||
if (A < (WEBRTC_SPL_WORD32_MAX - 32767))
|
||||
{
|
||||
A = A + ((int32_t)32768); // Round off bit
|
||||
} else
|
||||
{
|
||||
A = WEBRTC_SPL_WORD32_MAX;
|
||||
}
|
||||
|
||||
x_norm = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16); // x_norm = AH
|
||||
|
||||
nshift = WEBRTC_SPL_RSHIFT_W16(sh, 1); // nshift = sh>>1
|
||||
nshift = -nshift; // Negate the power for later de-normalization
|
||||
|
||||
A = (int32_t)WEBRTC_SPL_LSHIFT_W32((int32_t)x_norm, 16);
|
||||
A = WEBRTC_SPL_ABS_W32(A); // A = abs(x_norm<<16)
|
||||
A = WebRtcSpl_SqrtLocal(A); // A = sqrt(A)
|
||||
|
||||
if ((-2 * nshift) == sh)
|
||||
{ // Even shift value case
|
||||
|
||||
t16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(A, 16); // t16 = AH
|
||||
|
||||
A = WEBRTC_SPL_MUL_16_16(k_sqrt_2, t16) * 2; // A = 1/sqrt(2)*t16
|
||||
A = A + ((int32_t)32768); // Round off
|
||||
A = A & ((int32_t)0x7fff0000); // Round off
|
||||
|
||||
A = WEBRTC_SPL_RSHIFT_W32(A, 15); // A = A>>16
|
||||
|
||||
} else
|
||||
{
|
||||
A = WEBRTC_SPL_RSHIFT_W32(A, 16); // A = A>>16
|
||||
}
|
||||
|
||||
A = A & ((int32_t)0x0000ffff);
|
||||
A = (int32_t)WEBRTC_SPL_SHIFT_W32(A, nshift); // De-normalize the result
|
||||
|
||||
return A;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_get_version().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
int16_t WebRtcSpl_get_version(char* version, int16_t length_in_bytes)
|
||||
{
|
||||
strncpy(version, "1.2.0", length_in_bytes);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains the function WebRtcSpl_SqrtOfOneMinusXSquared().
|
||||
* The description header can be found in signal_processing_library.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t *xQ15, int vector_length,
|
||||
int16_t *yQ15)
|
||||
{
|
||||
int32_t sq;
|
||||
int m;
|
||||
int16_t tmp;
|
||||
|
||||
for (m = 0; m < vector_length; m++)
|
||||
{
|
||||
tmp = xQ15[m];
|
||||
sq = WEBRTC_SPL_MUL_16_16(tmp, tmp); // x^2 in Q30
|
||||
sq = 1073741823 - sq; // 1-x^2, where 1 ~= 0.99999999906 is 1073741823 in Q30
|
||||
sq = WebRtcSpl_Sqrt(sq); // sqrt(1-x^2) in Q15
|
||||
yQ15[m] = (int16_t)sq;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file contains implementations of the functions
|
||||
* WebRtcSpl_VectorBitShiftW16()
|
||||
* WebRtcSpl_VectorBitShiftW32()
|
||||
* WebRtcSpl_VectorBitShiftW32ToW16()
|
||||
* WebRtcSpl_ScaleVector()
|
||||
* WebRtcSpl_ScaleVectorWithSat()
|
||||
* WebRtcSpl_ScaleAndAddVectors()
|
||||
* WebRtcSpl_ScaleAndAddVectorsWithRoundC()
|
||||
*/
|
||||
|
||||
#include "include/signal_processing_library.h"
|
||||
|
||||
void WebRtcSpl_VectorBitShiftW16(int16_t *res, int16_t length,
|
||||
const int16_t *in, int16_t right_shifts)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (right_shifts > 0)
|
||||
{
|
||||
for (i = length; i > 0; i--)
|
||||
{
|
||||
(*res++) = ((*in++) >> right_shifts);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (i = length; i > 0; i--)
|
||||
{
|
||||
(*res++) = ((*in++) << (-right_shifts));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_VectorBitShiftW32(int32_t *out_vector,
|
||||
int16_t vector_length,
|
||||
const int32_t *in_vector,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (right_shifts > 0)
|
||||
{
|
||||
for (i = vector_length; i > 0; i--)
|
||||
{
|
||||
(*out_vector++) = ((*in_vector++) >> right_shifts);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (i = vector_length; i > 0; i--)
|
||||
{
|
||||
(*out_vector++) = ((*in_vector++) << (-right_shifts));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out, int length,
|
||||
const int32_t* in, int right_shifts) {
|
||||
int i;
|
||||
int32_t tmp_w32;
|
||||
|
||||
if (right_shifts >= 0) {
|
||||
for (i = length; i > 0; i--) {
|
||||
tmp_w32 = (*in++) >> right_shifts;
|
||||
(*out++) = WebRtcSpl_SatW32ToW16(tmp_w32);
|
||||
}
|
||||
} else {
|
||||
int16_t left_shifts = -right_shifts;
|
||||
for (i = length; i > 0; i--) {
|
||||
tmp_w32 = (*in++) << left_shifts;
|
||||
(*out++) = WebRtcSpl_SatW32ToW16(tmp_w32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ScaleVector(const int16_t *in_vector, int16_t *out_vector,
|
||||
int16_t gain, int16_t in_vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
// Performs vector operation: out_vector = (gain*in_vector)>>right_shifts
|
||||
int i;
|
||||
const int16_t *inptr;
|
||||
int16_t *outptr;
|
||||
|
||||
inptr = in_vector;
|
||||
outptr = out_vector;
|
||||
|
||||
for (i = 0; i < in_vector_length; i++)
|
||||
{
|
||||
(*outptr++) = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, gain, right_shifts);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ScaleVectorWithSat(const int16_t *in_vector, int16_t *out_vector,
|
||||
int16_t gain, int16_t in_vector_length,
|
||||
int16_t right_shifts)
|
||||
{
|
||||
// Performs vector operation: out_vector = (gain*in_vector)>>right_shifts
|
||||
int i;
|
||||
int32_t tmpW32;
|
||||
const int16_t *inptr;
|
||||
int16_t *outptr;
|
||||
|
||||
inptr = in_vector;
|
||||
outptr = out_vector;
|
||||
|
||||
for (i = 0; i < in_vector_length; i++)
|
||||
{
|
||||
tmpW32 = WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, gain, right_shifts);
|
||||
(*outptr++) = WebRtcSpl_SatW32ToW16(tmpW32);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcSpl_ScaleAndAddVectors(const int16_t *in1, int16_t gain1, int shift1,
|
||||
const int16_t *in2, int16_t gain2, int shift2,
|
||||
int16_t *out, int vector_length)
|
||||
{
|
||||
// Performs vector operation: out = (gain1*in1)>>shift1 + (gain2*in2)>>shift2
|
||||
int i;
|
||||
const int16_t *in1ptr;
|
||||
const int16_t *in2ptr;
|
||||
int16_t *outptr;
|
||||
|
||||
in1ptr = in1;
|
||||
in2ptr = in2;
|
||||
outptr = out;
|
||||
|
||||
for (i = 0; i < vector_length; i++)
|
||||
{
|
||||
(*outptr++) = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(gain1, *in1ptr++, shift1)
|
||||
+ (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(gain2, *in2ptr++, shift2);
|
||||
}
|
||||
}
|
||||
|
||||
// C version of WebRtcSpl_ScaleAndAddVectorsWithRound() for generic platforms.
|
||||
int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1,
|
||||
int16_t in_vector1_scale,
|
||||
const int16_t* in_vector2,
|
||||
int16_t in_vector2_scale,
|
||||
int right_shifts,
|
||||
int16_t* out_vector,
|
||||
int length) {
|
||||
int i = 0;
|
||||
int round_value = (1 << right_shifts) >> 1;
|
||||
|
||||
if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL ||
|
||||
length <= 0 || right_shifts < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
out_vector[i] = (int16_t)((
|
||||
WEBRTC_SPL_MUL_16_16(in_vector1[i], in_vector1_scale)
|
||||
+ WEBRTC_SPL_MUL_16_16(in_vector2[i], in_vector2_scale)
|
||||
+ round_value) >> right_shifts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
include $(LOCAL_PATH)/../../../android-webrtc.mk
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
|
||||
LOCAL_MODULE := libwebrtc_vad
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_SRC_FILES := \
|
||||
webrtc_vad.c \
|
||||
vad_core.c \
|
||||
vad_filterbank.c \
|
||||
vad_gmm.c \
|
||||
vad_sp.c
|
||||
|
||||
# Flags passed to both C and C++ files.
|
||||
LOCAL_CFLAGS := \
|
||||
$(MY_WEBRTC_COMMON_DEFS)
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/include \
|
||||
$(LOCAL_PATH)/../.. \
|
||||
$(LOCAL_PATH)/../signal_processing/include \
|
||||
external/webrtc
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libdl \
|
||||
libstlport
|
||||
|
||||
ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
|
||||
LOCAL_LDLIBS += -ldl -lpthread
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
LOCAL_SHARED_LIBRARIES += libdl
|
||||
endif
|
||||
|
||||
ifndef NDK_ROOT
|
||||
include external/stlport/libstlport.mk
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the VAD API calls. Specific function calls are given below.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_
|
||||
|
||||
#include "../../include/typedefs.h"
|
||||
|
||||
|
||||
typedef struct WebRtcVadInst VadInst;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Creates an instance to the VAD structure.
|
||||
//
|
||||
// - handle [o] : Pointer to the VAD instance that should be created.
|
||||
//
|
||||
// returns : 0 - (OK), -1 - (Error)
|
||||
int WebRtcVad_Create(VadInst** handle);
|
||||
|
||||
// Frees the dynamic memory of a specified VAD instance.
|
||||
//
|
||||
// - handle [i] : Pointer to VAD instance that should be freed.
|
||||
//
|
||||
// returns : 0 - (OK), -1 - (NULL pointer in)
|
||||
int WebRtcVad_Free(VadInst* handle);
|
||||
|
||||
// Initializes a VAD instance.
|
||||
//
|
||||
// - handle [i/o] : Instance that should be initialized.
|
||||
//
|
||||
// returns : 0 - (OK),
|
||||
// -1 - (NULL pointer or Default mode could not be set).
|
||||
int WebRtcVad_Init(VadInst* handle);
|
||||
|
||||
// Sets the VAD operating mode. A more aggressive (higher mode) VAD is more
|
||||
// restrictive in reporting speech. Put in other words the probability of being
|
||||
// speech when the VAD returns 1 is increased with increasing mode. As a
|
||||
// consequence also the missed detection rate goes up.
|
||||
//
|
||||
// - handle [i/o] : VAD instance.
|
||||
// - mode [i] : Aggressiveness mode (0, 1, 2, or 3).
|
||||
//
|
||||
// returns : 0 - (OK),
|
||||
// -1 - (NULL pointer, mode could not be set or the VAD instance
|
||||
// has not been initialized).
|
||||
int WebRtcVad_set_mode(VadInst* handle, int mode);
|
||||
|
||||
// Calculates a VAD decision for the |audio_frame|. For valid sampling rates
|
||||
// frame lengths, see the description of WebRtcVad_ValidRatesAndFrameLengths().
|
||||
//
|
||||
// - handle [i/o] : VAD Instance. Needs to be initialized by
|
||||
// WebRtcVad_Init() before call.
|
||||
// - fs [i] : Sampling frequency (Hz): 8000, 16000, or 32000
|
||||
// - audio_frame [i] : Audio frame buffer.
|
||||
// - frame_length [i] : Length of audio frame buffer in number of samples.
|
||||
//
|
||||
// returns : 1 - (Active Voice),
|
||||
// 0 - (Non-active Voice),
|
||||
// -1 - (Error)
|
||||
int WebRtcVad_Process(VadInst* handle, int fs, int16_t* audio_frame,
|
||||
int frame_length);
|
||||
|
||||
// Checks for valid combinations of |rate| and |frame_length|. We support 10,
|
||||
// 20 and 30 ms frames and the rates 8000, 16000 and 32000 Hz.
|
||||
//
|
||||
// - rate [i] : Sampling frequency (Hz).
|
||||
// - frame_length [i] : Speech frame buffer length in number of samples.
|
||||
//
|
||||
// returns : 0 - (valid combination), -1 - (invalid combination)
|
||||
int WebRtcVad_ValidRateAndFrameLength(int rate, int frame_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
|
|
@ -0,0 +1,682 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "vad_core.h"
|
||||
|
||||
#include "../signal_processing/include/signal_processing_library.h"
|
||||
#include "vad_filterbank.h"
|
||||
#include "vad_gmm.h"
|
||||
#include "vad_sp.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
// Spectrum Weighting
|
||||
static const int16_t kSpectrumWeight[kNumChannels] = { 6, 8, 10, 12, 14, 16 };
|
||||
static const int16_t kNoiseUpdateConst = 655; // Q15
|
||||
static const int16_t kSpeechUpdateConst = 6554; // Q15
|
||||
static const int16_t kBackEta = 154; // Q8
|
||||
// Minimum difference between the two models, Q5
|
||||
static const int16_t kMinimumDifference[kNumChannels] = {
|
||||
544, 544, 576, 576, 576, 576 };
|
||||
// Upper limit of mean value for speech model, Q7
|
||||
static const int16_t kMaximumSpeech[kNumChannels] = {
|
||||
11392, 11392, 11520, 11520, 11520, 11520 };
|
||||
// Minimum value for mean value
|
||||
static const int16_t kMinimumMean[kNumGaussians] = { 640, 768 };
|
||||
// Upper limit of mean value for noise model, Q7
|
||||
static const int16_t kMaximumNoise[kNumChannels] = {
|
||||
9216, 9088, 8960, 8832, 8704, 8576 };
|
||||
// Start values for the Gaussian models, Q7
|
||||
// Weights for the two Gaussians for the six channels (noise)
|
||||
static const int16_t kNoiseDataWeights[kTableSize] = {
|
||||
34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103 };
|
||||
// Weights for the two Gaussians for the six channels (speech)
|
||||
static const int16_t kSpeechDataWeights[kTableSize] = {
|
||||
48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81 };
|
||||
// Means for the two Gaussians for the six channels (noise)
|
||||
static const int16_t kNoiseDataMeans[kTableSize] = {
|
||||
6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, 7820, 7266, 5020, 4362 };
|
||||
// Means for the two Gaussians for the six channels (speech)
|
||||
static const int16_t kSpeechDataMeans[kTableSize] = {
|
||||
8306, 10085, 10078, 11823, 11843, 6309, 9473, 9571, 10879, 7581, 8180, 7483
|
||||
};
|
||||
// Stds for the two Gaussians for the six channels (noise)
|
||||
static const int16_t kNoiseDataStds[kTableSize] = {
|
||||
378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, 421, 455 };
|
||||
// Stds for the two Gaussians for the six channels (speech)
|
||||
static const int16_t kSpeechDataStds[kTableSize] = {
|
||||
555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, 1079, 850 };
|
||||
|
||||
// Constants used in GmmProbability().
|
||||
//
|
||||
// Maximum number of counted speech (VAD = 1) frames in a row.
|
||||
static const int16_t kMaxSpeechFrames = 6;
|
||||
// Minimum standard deviation for both speech and noise.
|
||||
static const int16_t kMinStd = 384;
|
||||
|
||||
// Constants in WebRtcVad_InitCore().
|
||||
// Default aggressiveness mode.
|
||||
static const short kDefaultMode = 0;
|
||||
static const int kInitCheck = 42;
|
||||
|
||||
// Constants used in WebRtcVad_set_mode_core().
|
||||
//
|
||||
// Thresholds for different frame lengths (10 ms, 20 ms and 30 ms).
|
||||
//
|
||||
// Mode 0, Quality.
|
||||
static const int16_t kOverHangMax1Q[3] = { 8, 4, 3 };
|
||||
static const int16_t kOverHangMax2Q[3] = { 14, 7, 5 };
|
||||
static const int16_t kLocalThresholdQ[3] = { 24, 21, 24 };
|
||||
static const int16_t kGlobalThresholdQ[3] = { 57, 48, 57 };
|
||||
// Mode 1, Low bitrate.
|
||||
static const int16_t kOverHangMax1LBR[3] = { 8, 4, 3 };
|
||||
static const int16_t kOverHangMax2LBR[3] = { 14, 7, 5 };
|
||||
static const int16_t kLocalThresholdLBR[3] = { 37, 32, 37 };
|
||||
static const int16_t kGlobalThresholdLBR[3] = { 100, 80, 100 };
|
||||
// Mode 2, Aggressive.
|
||||
static const int16_t kOverHangMax1AGG[3] = { 6, 3, 2 };
|
||||
static const int16_t kOverHangMax2AGG[3] = { 9, 5, 3 };
|
||||
static const int16_t kLocalThresholdAGG[3] = { 82, 78, 82 };
|
||||
static const int16_t kGlobalThresholdAGG[3] = { 285, 260, 285 };
|
||||
// Mode 3, Very aggressive.
|
||||
static const int16_t kOverHangMax1VAG[3] = { 6, 3, 2 };
|
||||
static const int16_t kOverHangMax2VAG[3] = { 9, 5, 3 };
|
||||
static const int16_t kLocalThresholdVAG[3] = { 94, 94, 94 };
|
||||
static const int16_t kGlobalThresholdVAG[3] = { 1100, 1050, 1100 };
|
||||
|
||||
// Calculates the weighted average w.r.t. number of Gaussians. The |data| are
|
||||
// updated with an |offset| before averaging.
|
||||
//
|
||||
// - data [i/o] : Data to average.
|
||||
// - offset [i] : An offset added to |data|.
|
||||
// - weights [i] : Weights used for averaging.
|
||||
//
|
||||
// returns : The weighted average.
|
||||
static int32_t WeightedAverage(int16_t* data, int16_t offset,
|
||||
const int16_t* weights) {
|
||||
int k;
|
||||
int32_t weighted_average = 0;
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
data[k * kNumChannels] += offset;
|
||||
weighted_average += data[k * kNumChannels] * weights[k * kNumChannels];
|
||||
}
|
||||
return weighted_average;
|
||||
}
|
||||
|
||||
// Calculates the probabilities for both speech and background noise using
|
||||
// Gaussian Mixture Models (GMM). A hypothesis-test is performed to decide which
|
||||
// type of signal is most probable.
|
||||
//
|
||||
// - self [i/o] : Pointer to VAD instance
|
||||
// - features [i] : Feature vector of length |kNumChannels|
|
||||
// = log10(energy in frequency band)
|
||||
// - total_power [i] : Total power in audio frame.
|
||||
// - frame_length [i] : Number of input samples
|
||||
//
|
||||
// - returns : the VAD decision (0 - noise, 1 - speech).
|
||||
static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
int16_t total_power, int frame_length) {
|
||||
int channel, k;
|
||||
int16_t feature_minimum;
|
||||
int16_t h0, h1;
|
||||
int16_t log_likelihood_ratio;
|
||||
int16_t vadflag = 0;
|
||||
int16_t shifts_h0, shifts_h1;
|
||||
int16_t tmp_s16, tmp1_s16, tmp2_s16;
|
||||
int16_t diff;
|
||||
int gaussian;
|
||||
int16_t nmk, nmk2, nmk3, smk, smk2, nsk, ssk;
|
||||
int16_t delt, ndelt;
|
||||
int16_t maxspe, maxmu;
|
||||
int16_t deltaN[kTableSize], deltaS[kTableSize];
|
||||
int16_t ngprvec[kTableSize] = { 0 }; // Conditional probability = 0.
|
||||
int16_t sgprvec[kTableSize] = { 0 }; // Conditional probability = 0.
|
||||
int32_t h0_test, h1_test;
|
||||
int32_t tmp1_s32, tmp2_s32;
|
||||
int32_t sum_log_likelihood_ratios = 0;
|
||||
int32_t noise_global_mean, speech_global_mean;
|
||||
int32_t noise_probability[kNumGaussians], speech_probability[kNumGaussians];
|
||||
int16_t overhead1, overhead2, individualTest, totalTest;
|
||||
|
||||
// Set various thresholds based on frame lengths (80, 160 or 240 samples).
|
||||
if (frame_length == 80) {
|
||||
overhead1 = self->over_hang_max_1[0];
|
||||
overhead2 = self->over_hang_max_2[0];
|
||||
individualTest = self->individual[0];
|
||||
totalTest = self->total[0];
|
||||
} else if (frame_length == 160) {
|
||||
overhead1 = self->over_hang_max_1[1];
|
||||
overhead2 = self->over_hang_max_2[1];
|
||||
individualTest = self->individual[1];
|
||||
totalTest = self->total[1];
|
||||
} else {
|
||||
overhead1 = self->over_hang_max_1[2];
|
||||
overhead2 = self->over_hang_max_2[2];
|
||||
individualTest = self->individual[2];
|
||||
totalTest = self->total[2];
|
||||
}
|
||||
|
||||
if (total_power > kMinEnergy) {
|
||||
// The signal power of current frame is large enough for processing. The
|
||||
// processing consists of two parts:
|
||||
// 1) Calculating the likelihood of speech and thereby a VAD decision.
|
||||
// 2) Updating the underlying model, w.r.t., the decision made.
|
||||
|
||||
// The detection scheme is an LRT with hypothesis
|
||||
// H0: Noise
|
||||
// H1: Speech
|
||||
//
|
||||
// We combine a global LRT with local tests, for each frequency sub-band,
|
||||
// here defined as |channel|.
|
||||
for (channel = 0; channel < kNumChannels; channel++) {
|
||||
// For each channel we model the probability with a GMM consisting of
|
||||
// |kNumGaussians|, with different means and standard deviations depending
|
||||
// on H0 or H1.
|
||||
h0_test = 0;
|
||||
h1_test = 0;
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
gaussian = channel + k * kNumChannels;
|
||||
// Probability under H0, that is, probability of frame being noise.
|
||||
// Value given in Q27 = Q7 * Q20.
|
||||
tmp1_s32 = WebRtcVad_GaussianProbability(features[channel],
|
||||
self->noise_means[gaussian],
|
||||
self->noise_stds[gaussian],
|
||||
&deltaN[gaussian]);
|
||||
noise_probability[k] = kNoiseDataWeights[gaussian] * tmp1_s32;
|
||||
h0_test += noise_probability[k]; // Q27
|
||||
|
||||
// Probability under H1, that is, probability of frame being speech.
|
||||
// Value given in Q27 = Q7 * Q20.
|
||||
tmp1_s32 = WebRtcVad_GaussianProbability(features[channel],
|
||||
self->speech_means[gaussian],
|
||||
self->speech_stds[gaussian],
|
||||
&deltaS[gaussian]);
|
||||
speech_probability[k] = kSpeechDataWeights[gaussian] * tmp1_s32;
|
||||
h1_test += speech_probability[k]; // Q27
|
||||
}
|
||||
|
||||
// Calculate the log likelihood ratio: log2(Pr{X|H1} / Pr{X|H1}).
|
||||
// Approximation:
|
||||
// log2(Pr{X|H1} / Pr{X|H1}) = log2(Pr{X|H1}*2^Q) - log2(Pr{X|H1}*2^Q)
|
||||
// = log2(h1_test) - log2(h0_test)
|
||||
// = log2(2^(31-shifts_h1)*(1+b1))
|
||||
// - log2(2^(31-shifts_h0)*(1+b0))
|
||||
// = shifts_h0 - shifts_h1
|
||||
// + log2(1+b1) - log2(1+b0)
|
||||
// ~= shifts_h0 - shifts_h1
|
||||
//
|
||||
// Note that b0 and b1 are values less than 1, hence, 0 <= log2(1+b0) < 1.
|
||||
// Further, b0 and b1 are independent and on the average the two terms
|
||||
// cancel.
|
||||
shifts_h0 = WebRtcSpl_NormW32(h0_test);
|
||||
shifts_h1 = WebRtcSpl_NormW32(h1_test);
|
||||
if (h0_test == 0) {
|
||||
shifts_h0 = 31;
|
||||
}
|
||||
if (h1_test == 0) {
|
||||
shifts_h1 = 31;
|
||||
}
|
||||
log_likelihood_ratio = shifts_h0 - shifts_h1;
|
||||
|
||||
// Update |sum_log_likelihood_ratios| with spectrum weighting. This is
|
||||
// used for the global VAD decision.
|
||||
sum_log_likelihood_ratios +=
|
||||
(int32_t) (log_likelihood_ratio * kSpectrumWeight[channel]);
|
||||
|
||||
// Local VAD decision.
|
||||
if ((log_likelihood_ratio << 2) > individualTest) {
|
||||
vadflag = 1;
|
||||
}
|
||||
|
||||
// TODO(bjornv): The conditional probabilities below are applied on the
|
||||
// hard coded number of Gaussians set to two. Find a way to generalize.
|
||||
// Calculate local noise probabilities used later when updating the GMM.
|
||||
h0 = (int16_t) (h0_test >> 12); // Q15
|
||||
if (h0 > 0) {
|
||||
// High probability of noise. Assign conditional probabilities for each
|
||||
// Gaussian in the GMM.
|
||||
tmp1_s32 = (noise_probability[0] & 0xFFFFF000) << 2; // Q29
|
||||
ngprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h0); // Q14
|
||||
ngprvec[channel + kNumChannels] = 16384 - ngprvec[channel];
|
||||
} else {
|
||||
// Low noise probability. Assign conditional probability 1 to the first
|
||||
// Gaussian and 0 to the rest (which is already set at initialization).
|
||||
ngprvec[channel] = 16384;
|
||||
}
|
||||
|
||||
// Calculate local speech probabilities used later when updating the GMM.
|
||||
h1 = (int16_t) (h1_test >> 12); // Q15
|
||||
if (h1 > 0) {
|
||||
// High probability of speech. Assign conditional probabilities for each
|
||||
// Gaussian in the GMM. Otherwise use the initialized values, i.e., 0.
|
||||
tmp1_s32 = (speech_probability[0] & 0xFFFFF000) << 2; // Q29
|
||||
sgprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h1); // Q14
|
||||
sgprvec[channel + kNumChannels] = 16384 - sgprvec[channel];
|
||||
}
|
||||
}
|
||||
|
||||
// Make a global VAD decision.
|
||||
vadflag |= (sum_log_likelihood_ratios >= totalTest);
|
||||
|
||||
// Update the model parameters.
|
||||
maxspe = 12800;
|
||||
for (channel = 0; channel < kNumChannels; channel++) {
|
||||
|
||||
// Get minimum value in past which is used for long term correction in Q4.
|
||||
feature_minimum = WebRtcVad_FindMinimum(self, features[channel], channel);
|
||||
|
||||
// Compute the "global" mean, that is the sum of the two means weighted.
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel], 0,
|
||||
&kNoiseDataWeights[channel]);
|
||||
tmp1_s16 = (int16_t) (noise_global_mean >> 6); // Q8
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
gaussian = channel + k * kNumChannels;
|
||||
|
||||
nmk = self->noise_means[gaussian];
|
||||
smk = self->speech_means[gaussian];
|
||||
nsk = self->noise_stds[gaussian];
|
||||
ssk = self->speech_stds[gaussian];
|
||||
|
||||
// Update noise mean vector if the frame consists of noise only.
|
||||
nmk2 = nmk;
|
||||
if (!vadflag) {
|
||||
// deltaN = (x-mu)/sigma^2
|
||||
// ngprvec[k] = |noise_probability[k]| /
|
||||
// (|noise_probability[0]| + |noise_probability[1]|)
|
||||
|
||||
// (Q14 * Q11 >> 11) = Q14.
|
||||
delt = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(ngprvec[gaussian],
|
||||
deltaN[gaussian],
|
||||
11);
|
||||
// Q7 + (Q14 * Q15 >> 22) = Q7.
|
||||
nmk2 = nmk + (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(delt,
|
||||
kNoiseUpdateConst,
|
||||
22);
|
||||
}
|
||||
|
||||
// Long term correction of the noise mean.
|
||||
// Q8 - Q8 = Q8.
|
||||
ndelt = (feature_minimum << 4) - tmp1_s16;
|
||||
// Q7 + (Q8 * Q8) >> 9 = Q7.
|
||||
nmk3 = nmk2 + (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(ndelt, kBackEta, 9);
|
||||
|
||||
// Control that the noise mean does not drift to much.
|
||||
tmp_s16 = (int16_t) ((k + 5) << 7);
|
||||
if (nmk3 < tmp_s16) {
|
||||
nmk3 = tmp_s16;
|
||||
}
|
||||
tmp_s16 = (int16_t) ((72 + k - channel) << 7);
|
||||
if (nmk3 > tmp_s16) {
|
||||
nmk3 = tmp_s16;
|
||||
}
|
||||
self->noise_means[gaussian] = nmk3;
|
||||
|
||||
if (vadflag) {
|
||||
// Update speech mean vector:
|
||||
// |deltaS| = (x-mu)/sigma^2
|
||||
// sgprvec[k] = |speech_probability[k]| /
|
||||
// (|speech_probability[0]| + |speech_probability[1]|)
|
||||
|
||||
// (Q14 * Q11) >> 11 = Q14.
|
||||
delt = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(sgprvec[gaussian],
|
||||
deltaS[gaussian],
|
||||
11);
|
||||
// Q14 * Q15 >> 21 = Q8.
|
||||
tmp_s16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(delt,
|
||||
kSpeechUpdateConst,
|
||||
21);
|
||||
// Q7 + (Q8 >> 1) = Q7. With rounding.
|
||||
smk2 = smk + ((tmp_s16 + 1) >> 1);
|
||||
|
||||
// Control that the speech mean does not drift to much.
|
||||
maxmu = maxspe + 640;
|
||||
if (smk2 < kMinimumMean[k]) {
|
||||
smk2 = kMinimumMean[k];
|
||||
}
|
||||
if (smk2 > maxmu) {
|
||||
smk2 = maxmu;
|
||||
}
|
||||
self->speech_means[gaussian] = smk2; // Q7.
|
||||
|
||||
// (Q7 >> 3) = Q4. With rounding.
|
||||
tmp_s16 = ((smk + 4) >> 3);
|
||||
|
||||
tmp_s16 = features[channel] - tmp_s16; // Q4
|
||||
// (Q11 * Q4 >> 3) = Q12.
|
||||
tmp1_s32 = WEBRTC_SPL_MUL_16_16_RSFT(deltaS[gaussian], tmp_s16, 3);
|
||||
tmp2_s32 = tmp1_s32 - 4096;
|
||||
tmp_s16 = sgprvec[gaussian] >> 2;
|
||||
// (Q14 >> 2) * Q12 = Q24.
|
||||
tmp1_s32 = tmp_s16 * tmp2_s32;
|
||||
|
||||
tmp2_s32 = tmp1_s32 >> 4; // Q20
|
||||
|
||||
// 0.1 * Q20 / Q7 = Q13.
|
||||
if (tmp2_s32 > 0) {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp2_s32, ssk * 10);
|
||||
} else {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp2_s32, ssk * 10);
|
||||
tmp_s16 = -tmp_s16;
|
||||
}
|
||||
// Divide by 4 giving an update factor of 0.025 (= 0.1 / 4).
|
||||
// Note that division by 4 equals shift by 2, hence,
|
||||
// (Q13 >> 8) = (Q13 >> 6) / 4 = Q7.
|
||||
tmp_s16 += 128; // Rounding.
|
||||
ssk += (tmp_s16 >> 8);
|
||||
if (ssk < kMinStd) {
|
||||
ssk = kMinStd;
|
||||
}
|
||||
self->speech_stds[gaussian] = ssk;
|
||||
} else {
|
||||
// Update GMM variance vectors.
|
||||
// deltaN * (features[channel] - nmk) - 1
|
||||
// Q4 - (Q7 >> 3) = Q4.
|
||||
tmp_s16 = features[channel] - (nmk >> 3);
|
||||
// (Q11 * Q4 >> 3) = Q12.
|
||||
tmp1_s32 = WEBRTC_SPL_MUL_16_16_RSFT(deltaN[gaussian], tmp_s16, 3);
|
||||
tmp1_s32 -= 4096;
|
||||
|
||||
// (Q14 >> 2) * Q12 = Q24.
|
||||
tmp_s16 = (ngprvec[gaussian] + 2) >> 2;
|
||||
tmp2_s32 = tmp_s16 * tmp1_s32;
|
||||
// Q20 * approx 0.001 (2^-10=0.0009766), hence,
|
||||
// (Q24 >> 14) = (Q24 >> 4) / 2^10 = Q20.
|
||||
tmp1_s32 = tmp2_s32 >> 14;
|
||||
|
||||
// Q20 / Q7 = Q13.
|
||||
if (tmp1_s32 > 0) {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, nsk);
|
||||
} else {
|
||||
tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp1_s32, nsk);
|
||||
tmp_s16 = -tmp_s16;
|
||||
}
|
||||
tmp_s16 += 32; // Rounding
|
||||
nsk += tmp_s16 >> 6; // Q13 >> 6 = Q7.
|
||||
if (nsk < kMinStd) {
|
||||
nsk = kMinStd;
|
||||
}
|
||||
self->noise_stds[gaussian] = nsk;
|
||||
}
|
||||
}
|
||||
|
||||
// Separate models if they are too close.
|
||||
// |noise_global_mean| in Q14 (= Q7 * Q7).
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel], 0,
|
||||
&kNoiseDataWeights[channel]);
|
||||
|
||||
// |speech_global_mean| in Q14 (= Q7 * Q7).
|
||||
speech_global_mean = WeightedAverage(&self->speech_means[channel], 0,
|
||||
&kSpeechDataWeights[channel]);
|
||||
|
||||
// |diff| = "global" speech mean - "global" noise mean.
|
||||
// (Q14 >> 9) - (Q14 >> 9) = Q5.
|
||||
diff = (int16_t) (speech_global_mean >> 9) -
|
||||
(int16_t) (noise_global_mean >> 9);
|
||||
if (diff < kMinimumDifference[channel]) {
|
||||
tmp_s16 = kMinimumDifference[channel] - diff;
|
||||
|
||||
// |tmp1_s16| = ~0.8 * (kMinimumDifference - diff) in Q7.
|
||||
// |tmp2_s16| = ~0.2 * (kMinimumDifference - diff) in Q7.
|
||||
tmp1_s16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(13, tmp_s16, 2);
|
||||
tmp2_s16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(3, tmp_s16, 2);
|
||||
|
||||
// Move Gaussian means for speech model by |tmp1_s16| and update
|
||||
// |speech_global_mean|. Note that |self->speech_means[channel]| is
|
||||
// changed after the call.
|
||||
speech_global_mean = WeightedAverage(&self->speech_means[channel],
|
||||
tmp1_s16,
|
||||
&kSpeechDataWeights[channel]);
|
||||
|
||||
// Move Gaussian means for noise model by -|tmp2_s16| and update
|
||||
// |noise_global_mean|. Note that |self->noise_means[channel]| is
|
||||
// changed after the call.
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel],
|
||||
-tmp2_s16,
|
||||
&kNoiseDataWeights[channel]);
|
||||
}
|
||||
|
||||
// Control that the speech & noise means do not drift to much.
|
||||
maxspe = kMaximumSpeech[channel];
|
||||
tmp2_s16 = (int16_t) (speech_global_mean >> 7);
|
||||
if (tmp2_s16 > maxspe) {
|
||||
// Upper limit of speech model.
|
||||
tmp2_s16 -= maxspe;
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
self->speech_means[channel + k * kNumChannels] -= tmp2_s16;
|
||||
}
|
||||
}
|
||||
|
||||
tmp2_s16 = (int16_t) (noise_global_mean >> 7);
|
||||
if (tmp2_s16 > kMaximumNoise[channel]) {
|
||||
tmp2_s16 -= kMaximumNoise[channel];
|
||||
|
||||
for (k = 0; k < kNumGaussians; k++) {
|
||||
self->noise_means[channel + k * kNumChannels] -= tmp2_s16;
|
||||
}
|
||||
}
|
||||
}
|
||||
self->frame_counter++;
|
||||
}
|
||||
|
||||
// Smooth with respect to transition hysteresis.
|
||||
if (!vadflag) {
|
||||
if (self->over_hang > 0) {
|
||||
vadflag = 2 + self->over_hang;
|
||||
self->over_hang--;
|
||||
}
|
||||
self->num_of_speech = 0;
|
||||
} else {
|
||||
self->num_of_speech++;
|
||||
if (self->num_of_speech > kMaxSpeechFrames) {
|
||||
self->num_of_speech = kMaxSpeechFrames;
|
||||
self->over_hang = overhead2;
|
||||
} else {
|
||||
self->over_hang = overhead1;
|
||||
}
|
||||
}
|
||||
return vadflag;
|
||||
}
|
||||
|
||||
// Initialize the VAD. Set aggressiveness mode to default value.
|
||||
int WebRtcVad_InitCore(VadInstT* self) {
|
||||
int i;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialization of general struct variables.
|
||||
self->vad = 1; // Speech active (=1).
|
||||
self->frame_counter = 0;
|
||||
self->over_hang = 0;
|
||||
self->num_of_speech = 0;
|
||||
|
||||
// Initialization of downsampling filter state.
|
||||
memset(self->downsampling_filter_states, 0,
|
||||
sizeof(self->downsampling_filter_states));
|
||||
|
||||
// Initialization of 48 to 8 kHz downsampling.
|
||||
WebRtcSpl_ResetResample48khzTo8khz(&self->state_48_to_8);
|
||||
|
||||
// Read initial PDF parameters.
|
||||
for (i = 0; i < kTableSize; i++) {
|
||||
self->noise_means[i] = kNoiseDataMeans[i];
|
||||
self->speech_means[i] = kSpeechDataMeans[i];
|
||||
self->noise_stds[i] = kNoiseDataStds[i];
|
||||
self->speech_stds[i] = kSpeechDataStds[i];
|
||||
}
|
||||
|
||||
// Initialize Index and Minimum value vectors.
|
||||
for (i = 0; i < 16 * kNumChannels; i++) {
|
||||
self->low_value_vector[i] = 10000;
|
||||
self->index_vector[i] = 0;
|
||||
}
|
||||
|
||||
// Initialize splitting filter states.
|
||||
memset(self->upper_state, 0, sizeof(self->upper_state));
|
||||
memset(self->lower_state, 0, sizeof(self->lower_state));
|
||||
|
||||
// Initialize high pass filter states.
|
||||
memset(self->hp_filter_state, 0, sizeof(self->hp_filter_state));
|
||||
|
||||
// Initialize mean value memory, for WebRtcVad_FindMinimum().
|
||||
for (i = 0; i < kNumChannels; i++) {
|
||||
self->mean_value[i] = 1600;
|
||||
}
|
||||
|
||||
// Set aggressiveness mode to default (=|kDefaultMode|).
|
||||
if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->init_flag = kInitCheck;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set aggressiveness mode
|
||||
int WebRtcVad_set_mode_core(VadInstT* self, int mode) {
|
||||
int return_value = 0;
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
// Quality mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1Q,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2Q,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdQ,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdQ,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
case 1:
|
||||
// Low bitrate mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1LBR,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2LBR,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdLBR,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdLBR,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
case 2:
|
||||
// Aggressive mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1AGG,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2AGG,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdAGG,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdAGG,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
case 3:
|
||||
// Very aggressive mode.
|
||||
memcpy(self->over_hang_max_1, kOverHangMax1VAG,
|
||||
sizeof(self->over_hang_max_1));
|
||||
memcpy(self->over_hang_max_2, kOverHangMax2VAG,
|
||||
sizeof(self->over_hang_max_2));
|
||||
memcpy(self->individual, kLocalThresholdVAG,
|
||||
sizeof(self->individual));
|
||||
memcpy(self->total, kGlobalThresholdVAG,
|
||||
sizeof(self->total));
|
||||
break;
|
||||
default:
|
||||
return_value = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Calculate VAD decision by first extracting feature values and then calculate
|
||||
// probability for both speech and background noise.
|
||||
|
||||
int WebRtcVad_CalcVad48khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length) {
|
||||
int vad;
|
||||
int i;
|
||||
int16_t speech_nb[240]; // 30 ms in 8 kHz.
|
||||
// |tmp_mem| is a temporary memory used by resample function, length is
|
||||
// frame length in 10 ms (480 samples) + 256 extra.
|
||||
int32_t tmp_mem[480 + 256] = { 0 };
|
||||
const int kFrameLen10ms48khz = 480;
|
||||
const int kFrameLen10ms8khz = 80;
|
||||
int num_10ms_frames = frame_length / kFrameLen10ms48khz;
|
||||
|
||||
for (i = 0; i < num_10ms_frames; i++) {
|
||||
WebRtcSpl_Resample48khzTo8khz(speech_frame,
|
||||
&speech_nb[i * kFrameLen10ms8khz],
|
||||
&inst->state_48_to_8,
|
||||
tmp_mem);
|
||||
}
|
||||
|
||||
// Do VAD on an 8 kHz signal
|
||||
vad = WebRtcVad_CalcVad8khz(inst, speech_nb, frame_length / 6);
|
||||
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_CalcVad32khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length)
|
||||
{
|
||||
int len, vad;
|
||||
int16_t speechWB[480]; // Downsampled speech frame: 960 samples (30ms in SWB)
|
||||
int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB)
|
||||
|
||||
|
||||
// Downsample signal 32->16->8 before doing VAD
|
||||
WebRtcVad_Downsampling(speech_frame, speechWB, &(inst->downsampling_filter_states[2]),
|
||||
frame_length);
|
||||
len = WEBRTC_SPL_RSHIFT_W16(frame_length, 1);
|
||||
|
||||
WebRtcVad_Downsampling(speechWB, speechNB, inst->downsampling_filter_states, len);
|
||||
len = WEBRTC_SPL_RSHIFT_W16(len, 1);
|
||||
|
||||
// Do VAD on an 8 kHz signal
|
||||
vad = WebRtcVad_CalcVad8khz(inst, speechNB, len);
|
||||
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_CalcVad16khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length)
|
||||
{
|
||||
int len, vad;
|
||||
int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB)
|
||||
|
||||
// Wideband: Downsample signal before doing VAD
|
||||
WebRtcVad_Downsampling(speech_frame, speechNB, inst->downsampling_filter_states,
|
||||
frame_length);
|
||||
|
||||
len = WEBRTC_SPL_RSHIFT_W16(frame_length, 1);
|
||||
vad = WebRtcVad_CalcVad8khz(inst, speechNB, len);
|
||||
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_CalcVad8khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length)
|
||||
{
|
||||
int16_t feature_vector[kNumChannels], total_power;
|
||||
|
||||
// Get power in the bands
|
||||
total_power = WebRtcVad_CalculateFeatures(inst, speech_frame, frame_length,
|
||||
feature_vector);
|
||||
|
||||
// Make a VAD
|
||||
inst->vad = GmmProbability(inst, feature_vector, total_power, frame_length);
|
||||
|
||||
return inst->vad;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the descriptions of the core VAD calls.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
|
||||
|
||||
#include "../signal_processing/include/signal_processing_library.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
enum { kNumChannels = 6 }; // Number of frequency bands (named channels).
|
||||
enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM.
|
||||
enum { kTableSize = kNumChannels * kNumGaussians };
|
||||
enum { kMinEnergy = 10 }; // Minimum energy required to trigger audio signal.
|
||||
|
||||
typedef struct VadInstT_
|
||||
{
|
||||
|
||||
int vad;
|
||||
int32_t downsampling_filter_states[4];
|
||||
WebRtcSpl_State48khzTo8khz state_48_to_8;
|
||||
int16_t noise_means[kTableSize];
|
||||
int16_t speech_means[kTableSize];
|
||||
int16_t noise_stds[kTableSize];
|
||||
int16_t speech_stds[kTableSize];
|
||||
// TODO(bjornv): Change to |frame_count|.
|
||||
int32_t frame_counter;
|
||||
int16_t over_hang; // Over Hang
|
||||
int16_t num_of_speech;
|
||||
// TODO(bjornv): Change to |age_vector|.
|
||||
int16_t index_vector[16 * kNumChannels];
|
||||
int16_t low_value_vector[16 * kNumChannels];
|
||||
// TODO(bjornv): Change to |median|.
|
||||
int16_t mean_value[kNumChannels];
|
||||
int16_t upper_state[5];
|
||||
int16_t lower_state[5];
|
||||
int16_t hp_filter_state[4];
|
||||
int16_t over_hang_max_1[3];
|
||||
int16_t over_hang_max_2[3];
|
||||
int16_t individual[3];
|
||||
int16_t total[3];
|
||||
|
||||
int init_flag;
|
||||
|
||||
} VadInstT;
|
||||
|
||||
// Initializes the core VAD component. The default aggressiveness mode is
|
||||
// controlled by |kDefaultMode| in vad_core.c.
|
||||
//
|
||||
// - self [i/o] : Instance that should be initialized
|
||||
//
|
||||
// returns : 0 (OK), -1 (NULL pointer in or if the default mode can't be
|
||||
// set)
|
||||
int WebRtcVad_InitCore(VadInstT* self);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_set_mode_core(...)
|
||||
*
|
||||
* This function changes the VAD settings
|
||||
*
|
||||
* Input:
|
||||
* - inst : VAD instance
|
||||
* - mode : Aggressiveness degree
|
||||
* 0 (High quality) - 3 (Highly aggressive)
|
||||
*
|
||||
* Output:
|
||||
* - inst : Changed instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcVad_set_mode_core(VadInstT* self, int mode);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_CalcVad48khz(...)
|
||||
* WebRtcVad_CalcVad32khz(...)
|
||||
* WebRtcVad_CalcVad16khz(...)
|
||||
* WebRtcVad_CalcVad8khz(...)
|
||||
*
|
||||
* Calculate probability for active speech and make VAD decision.
|
||||
*
|
||||
* Input:
|
||||
* - inst : Instance that should be initialized
|
||||
* - speech_frame : Input speech frame
|
||||
* - frame_length : Number of input samples
|
||||
*
|
||||
* Output:
|
||||
* - inst : Updated filter states etc.
|
||||
*
|
||||
* Return value : VAD decision
|
||||
* 0 - No active speech
|
||||
* 1-6 - Active speech
|
||||
*/
|
||||
int WebRtcVad_CalcVad48khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length);
|
||||
int WebRtcVad_CalcVad32khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length);
|
||||
int WebRtcVad_CalcVad16khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length);
|
||||
int WebRtcVad_CalcVad8khz(VadInstT* inst, int16_t* speech_frame,
|
||||
int frame_length);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "vad_filterbank.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "../signal_processing/include/signal_processing_library.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
// Constants used in LogOfEnergy().
|
||||
static const int16_t kLogConst = 24660; // 160*log10(2) in Q9.
|
||||
static const int16_t kLogEnergyIntPart = 14336; // 14 in Q10
|
||||
|
||||
// Coefficients used by HighPassFilter, Q14.
|
||||
static const int16_t kHpZeroCoefs[3] = { 6631, -13262, 6631 };
|
||||
static const int16_t kHpPoleCoefs[3] = { 16384, -7756, 5620 };
|
||||
|
||||
// Allpass filter coefficients, upper and lower, in Q15.
|
||||
// Upper: 0.64, Lower: 0.17
|
||||
static const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 };
|
||||
|
||||
// Adjustment for division with two in SplitFilter.
|
||||
static const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 };
|
||||
|
||||
// High pass filtering, with a cut-off frequency at 80 Hz, if the |data_in| is
|
||||
// sampled at 500 Hz.
|
||||
//
|
||||
// - data_in [i] : Input audio data sampled at 500 Hz.
|
||||
// - data_length [i] : Length of input and output data.
|
||||
// - filter_state [i/o] : State of the filter.
|
||||
// - data_out [o] : Output audio data in the frequency interval
|
||||
// 80 - 250 Hz.
|
||||
static void HighPassFilter(const int16_t* data_in, int data_length,
|
||||
int16_t* filter_state, int16_t* data_out) {
|
||||
int i;
|
||||
const int16_t* in_ptr = data_in;
|
||||
int16_t* out_ptr = data_out;
|
||||
int32_t tmp32 = 0;
|
||||
|
||||
|
||||
// The sum of the absolute values of the impulse response:
|
||||
// The zero/pole-filter has a max amplification of a single sample of: 1.4546
|
||||
// Impulse response: 0.4047 -0.6179 -0.0266 0.1993 0.1035 -0.0194
|
||||
// The all-zero section has a max amplification of a single sample of: 1.6189
|
||||
// Impulse response: 0.4047 -0.8094 0.4047 0 0 0
|
||||
// The all-pole section has a max amplification of a single sample of: 1.9931
|
||||
// Impulse response: 1.0000 0.4734 -0.1189 -0.2187 -0.0627 0.04532
|
||||
|
||||
for (i = 0; i < data_length; i++) {
|
||||
// All-zero section (filter coefficients in Q14).
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[0], *in_ptr);
|
||||
tmp32 += WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[1], filter_state[0]);
|
||||
tmp32 += WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[2], filter_state[1]);
|
||||
filter_state[1] = filter_state[0];
|
||||
filter_state[0] = *in_ptr++;
|
||||
|
||||
// All-pole section (filter coefficients in Q14).
|
||||
tmp32 -= WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[1], filter_state[2]);
|
||||
tmp32 -= WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[2], filter_state[3]);
|
||||
filter_state[3] = filter_state[2];
|
||||
filter_state[2] = (int16_t) (tmp32 >> 14);
|
||||
*out_ptr++ = filter_state[2];
|
||||
}
|
||||
}
|
||||
|
||||
// All pass filtering of |data_in|, used before splitting the signal into two
|
||||
// frequency bands (low pass vs high pass).
|
||||
// Note that |data_in| and |data_out| can NOT correspond to the same address.
|
||||
//
|
||||
// - data_in [i] : Input audio signal given in Q0.
|
||||
// - data_length [i] : Length of input and output data.
|
||||
// - filter_coefficient [i] : Given in Q15.
|
||||
// - filter_state [i/o] : State of the filter given in Q(-1).
|
||||
// - data_out [o] : Output audio signal given in Q(-1).
|
||||
static void AllPassFilter(const int16_t* data_in, int data_length,
|
||||
int16_t filter_coefficient, int16_t* filter_state,
|
||||
int16_t* data_out) {
|
||||
// The filter can only cause overflow (in the w16 output variable)
|
||||
// if more than 4 consecutive input numbers are of maximum value and
|
||||
// has the the same sign as the impulse responses first taps.
|
||||
// First 6 taps of the impulse response:
|
||||
// 0.6399 0.5905 -0.3779 0.2418 -0.1547 0.0990
|
||||
|
||||
int i;
|
||||
int16_t tmp16 = 0;
|
||||
int32_t tmp32 = 0;
|
||||
int32_t state32 = ((int32_t) (*filter_state) << 16); // Q15
|
||||
|
||||
for (i = 0; i < data_length; i++) {
|
||||
tmp32 = state32 + WEBRTC_SPL_MUL_16_16(filter_coefficient, *data_in);
|
||||
tmp16 = (int16_t) (tmp32 >> 16); // Q(-1)
|
||||
*data_out++ = tmp16;
|
||||
state32 = (((int32_t) (*data_in)) << 14); // Q14
|
||||
state32 -= WEBRTC_SPL_MUL_16_16(filter_coefficient, tmp16); // Q14
|
||||
state32 <<= 1; // Q15.
|
||||
data_in += 2;
|
||||
}
|
||||
|
||||
*filter_state = (int16_t) (state32 >> 16); // Q(-1)
|
||||
}
|
||||
|
||||
// Splits |data_in| into |hp_data_out| and |lp_data_out| corresponding to
|
||||
// an upper (high pass) part and a lower (low pass) part respectively.
|
||||
//
|
||||
// - data_in [i] : Input audio data to be split into two frequency bands.
|
||||
// - data_length [i] : Length of |data_in|.
|
||||
// - upper_state [i/o] : State of the upper filter, given in Q(-1).
|
||||
// - lower_state [i/o] : State of the lower filter, given in Q(-1).
|
||||
// - hp_data_out [o] : Output audio data of the upper half of the spectrum.
|
||||
// The length is |data_length| / 2.
|
||||
// - lp_data_out [o] : Output audio data of the lower half of the spectrum.
|
||||
// The length is |data_length| / 2.
|
||||
static void SplitFilter(const int16_t* data_in, int data_length,
|
||||
int16_t* upper_state, int16_t* lower_state,
|
||||
int16_t* hp_data_out, int16_t* lp_data_out) {
|
||||
int i;
|
||||
int half_length = data_length >> 1; // Downsampling by 2.
|
||||
int16_t tmp_out;
|
||||
|
||||
// All-pass filtering upper branch.
|
||||
AllPassFilter(&data_in[0], half_length, kAllPassCoefsQ15[0], upper_state,
|
||||
hp_data_out);
|
||||
|
||||
// All-pass filtering lower branch.
|
||||
AllPassFilter(&data_in[1], half_length, kAllPassCoefsQ15[1], lower_state,
|
||||
lp_data_out);
|
||||
|
||||
// Make LP and HP signals.
|
||||
for (i = 0; i < half_length; i++) {
|
||||
tmp_out = *hp_data_out;
|
||||
*hp_data_out++ -= *lp_data_out;
|
||||
*lp_data_out++ += tmp_out;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates the energy of |data_in| in dB, and also updates an overall
|
||||
// |total_energy| if necessary.
|
||||
//
|
||||
// - data_in [i] : Input audio data for energy calculation.
|
||||
// - data_length [i] : Length of input data.
|
||||
// - offset [i] : Offset value added to |log_energy|.
|
||||
// - total_energy [i/o] : An external energy updated with the energy of
|
||||
// |data_in|.
|
||||
// NOTE: |total_energy| is only updated if
|
||||
// |total_energy| <= |kMinEnergy|.
|
||||
// - log_energy [o] : 10 * log10("energy of |data_in|") given in Q4.
|
||||
static void LogOfEnergy(const int16_t* data_in, int data_length,
|
||||
int16_t offset, int16_t* total_energy,
|
||||
int16_t* log_energy) {
|
||||
// |tot_rshifts| accumulates the number of right shifts performed on |energy|.
|
||||
int tot_rshifts = 0;
|
||||
// The |energy| will be normalized to 15 bits. We use unsigned integer because
|
||||
// we eventually will mask out the fractional part.
|
||||
uint32_t energy = 0;
|
||||
|
||||
assert(data_in != NULL);
|
||||
assert(data_length > 0);
|
||||
|
||||
energy = (uint32_t) WebRtcSpl_Energy((int16_t*) data_in, data_length,
|
||||
&tot_rshifts);
|
||||
|
||||
if (energy != 0) {
|
||||
// By construction, normalizing to 15 bits is equivalent with 17 leading
|
||||
// zeros of an unsigned 32 bit value.
|
||||
int normalizing_rshifts = 17 - WebRtcSpl_NormU32(energy);
|
||||
// In a 15 bit representation the leading bit is 2^14. log2(2^14) in Q10 is
|
||||
// (14 << 10), which is what we initialize |log2_energy| with. For a more
|
||||
// detailed derivations, see below.
|
||||
int16_t log2_energy = kLogEnergyIntPart;
|
||||
|
||||
tot_rshifts += normalizing_rshifts;
|
||||
// Normalize |energy| to 15 bits.
|
||||
// |tot_rshifts| is now the total number of right shifts performed on
|
||||
// |energy| after normalization. This means that |energy| is in
|
||||
// Q(-tot_rshifts).
|
||||
if (normalizing_rshifts < 0) {
|
||||
energy <<= -normalizing_rshifts;
|
||||
} else {
|
||||
energy >>= normalizing_rshifts;
|
||||
}
|
||||
|
||||
// Calculate the energy of |data_in| in dB, in Q4.
|
||||
//
|
||||
// 10 * log10("true energy") in Q4 = 2^4 * 10 * log10("true energy") =
|
||||
// 160 * log10(|energy| * 2^|tot_rshifts|) =
|
||||
// 160 * log10(2) * log2(|energy| * 2^|tot_rshifts|) =
|
||||
// 160 * log10(2) * (log2(|energy|) + log2(2^|tot_rshifts|)) =
|
||||
// (160 * log10(2)) * (log2(|energy|) + |tot_rshifts|) =
|
||||
// |kLogConst| * (|log2_energy| + |tot_rshifts|)
|
||||
//
|
||||
// We know by construction that |energy| is normalized to 15 bits. Hence,
|
||||
// |energy| = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15.
|
||||
// Further, we'd like |log2_energy| in Q10
|
||||
// log2(|energy|) in Q10 = 2^10 * log2(2^14 + frac_Q15) =
|
||||
// 2^10 * log2(2^14 * (1 + frac_Q15 * 2^-14)) =
|
||||
// 2^10 * (14 + log2(1 + frac_Q15 * 2^-14)) ~=
|
||||
// (14 << 10) + 2^10 * (frac_Q15 * 2^-14) =
|
||||
// (14 << 10) + (frac_Q15 * 2^-4) = (14 << 10) + (frac_Q15 >> 4)
|
||||
//
|
||||
// Note that frac_Q15 = (|energy| & 0x00003FFF)
|
||||
|
||||
// Calculate and add the fractional part to |log2_energy|.
|
||||
log2_energy += (int16_t) ((energy & 0x00003FFF) >> 4);
|
||||
|
||||
// |kLogConst| is in Q9, |log2_energy| in Q10 and |tot_rshifts| in Q0.
|
||||
// Note that we in our derivation above have accounted for an output in Q4.
|
||||
*log_energy = (int16_t) (WEBRTC_SPL_MUL_16_16_RSFT(
|
||||
kLogConst, log2_energy, 19) +
|
||||
WEBRTC_SPL_MUL_16_16_RSFT(tot_rshifts, kLogConst, 9));
|
||||
|
||||
if (*log_energy < 0) {
|
||||
*log_energy = 0;
|
||||
}
|
||||
} else {
|
||||
*log_energy = offset;
|
||||
return;
|
||||
}
|
||||
|
||||
*log_energy += offset;
|
||||
|
||||
// Update the approximate |total_energy| with the energy of |data_in|, if
|
||||
// |total_energy| has not exceeded |kMinEnergy|. |total_energy| is used as an
|
||||
// energy indicator in WebRtcVad_GmmProbability() in vad_core.c.
|
||||
if (*total_energy <= kMinEnergy) {
|
||||
if (tot_rshifts >= 0) {
|
||||
// We know by construction that the |energy| > |kMinEnergy| in Q0, so add
|
||||
// an arbitrary value such that |total_energy| exceeds |kMinEnergy|.
|
||||
*total_energy += kMinEnergy + 1;
|
||||
} else {
|
||||
// By construction |energy| is represented by 15 bits, hence any number of
|
||||
// right shifted |energy| will fit in an int16_t. In addition, adding the
|
||||
// value to |total_energy| is wrap around safe as long as
|
||||
// |kMinEnergy| < 8192.
|
||||
*total_energy += (int16_t) (energy >> -tot_rshifts); // Q0.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
int data_length, int16_t* features) {
|
||||
int16_t total_energy = 0;
|
||||
// We expect |data_length| to be 80, 160 or 240 samples, which corresponds to
|
||||
// 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will
|
||||
// have at most 120 samples after the first split and at most 60 samples after
|
||||
// the second split.
|
||||
int16_t hp_120[120], lp_120[120];
|
||||
int16_t hp_60[60], lp_60[60];
|
||||
const int half_data_length = data_length >> 1;
|
||||
int length = half_data_length; // |data_length| / 2, corresponds to
|
||||
// bandwidth = 2000 Hz after downsampling.
|
||||
|
||||
// Initialize variables for the first SplitFilter().
|
||||
int frequency_band = 0;
|
||||
const int16_t* in_ptr = data_in; // [0 - 4000] Hz.
|
||||
int16_t* hp_out_ptr = hp_120; // [2000 - 4000] Hz.
|
||||
int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz.
|
||||
|
||||
assert(data_length >= 0);
|
||||
assert(data_length <= 240);
|
||||
assert(4 < kNumChannels - 1); // Checking maximum |frequency_band|.
|
||||
|
||||
// Split at 2000 Hz and downsample.
|
||||
SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// For the upper band (2000 Hz - 4000 Hz) split at 3000 Hz and downsample.
|
||||
frequency_band = 1;
|
||||
in_ptr = hp_120; // [2000 - 4000] Hz.
|
||||
hp_out_ptr = hp_60; // [3000 - 4000] Hz.
|
||||
lp_out_ptr = lp_60; // [2000 - 3000] Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 3000 Hz - 4000 Hz.
|
||||
length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz.
|
||||
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[5], &total_energy, &features[5]);
|
||||
|
||||
// Energy in 2000 Hz - 3000 Hz.
|
||||
LogOfEnergy(lp_60, length, kOffsetVector[4], &total_energy, &features[4]);
|
||||
|
||||
// For the lower band (0 Hz - 2000 Hz) split at 1000 Hz and downsample.
|
||||
frequency_band = 2;
|
||||
in_ptr = lp_120; // [0 - 2000] Hz.
|
||||
hp_out_ptr = hp_60; // [1000 - 2000] Hz.
|
||||
lp_out_ptr = lp_60; // [0 - 1000] Hz.
|
||||
length = half_data_length; // |data_length| / 2 <=> bandwidth = 2000 Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 1000 Hz - 2000 Hz.
|
||||
length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz.
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[3], &total_energy, &features[3]);
|
||||
|
||||
// For the lower band (0 Hz - 1000 Hz) split at 500 Hz and downsample.
|
||||
frequency_band = 3;
|
||||
in_ptr = lp_60; // [0 - 1000] Hz.
|
||||
hp_out_ptr = hp_120; // [500 - 1000] Hz.
|
||||
lp_out_ptr = lp_120; // [0 - 500] Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 500 Hz - 1000 Hz.
|
||||
length >>= 1; // |data_length| / 8 <=> bandwidth = 500 Hz.
|
||||
LogOfEnergy(hp_120, length, kOffsetVector[2], &total_energy, &features[2]);
|
||||
|
||||
// For the lower band (0 Hz - 500 Hz) split at 250 Hz and downsample.
|
||||
frequency_band = 4;
|
||||
in_ptr = lp_120; // [0 - 500] Hz.
|
||||
hp_out_ptr = hp_60; // [250 - 500] Hz.
|
||||
lp_out_ptr = lp_60; // [0 - 250] Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 250 Hz - 500 Hz.
|
||||
length >>= 1; // |data_length| / 16 <=> bandwidth = 250 Hz.
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[1], &total_energy, &features[1]);
|
||||
|
||||
// Remove 0 Hz - 80 Hz, by high pass filtering the lower band.
|
||||
HighPassFilter(lp_60, length, self->hp_filter_state, hp_120);
|
||||
|
||||
// Energy in 80 Hz - 250 Hz.
|
||||
LogOfEnergy(hp_120, length, kOffsetVector[0], &total_energy, &features[0]);
|
||||
|
||||
return total_energy;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file includes feature calculating functionality used in vad_core.c.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
|
||||
|
||||
#include "vad_core.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
// Takes |data_length| samples of |data_in| and calculates the logarithm of the
|
||||
// energy of each of the |kNumChannels| = 6 frequency bands used by the VAD:
|
||||
// 80 Hz - 250 Hz
|
||||
// 250 Hz - 500 Hz
|
||||
// 500 Hz - 1000 Hz
|
||||
// 1000 Hz - 2000 Hz
|
||||
// 2000 Hz - 3000 Hz
|
||||
// 3000 Hz - 4000 Hz
|
||||
//
|
||||
// The values are given in Q4 and written to |features|. Further, an approximate
|
||||
// overall energy is returned. The return value is used in
|
||||
// WebRtcVad_GmmProbability() as a signal indicator, hence it is arbitrary above
|
||||
// the threshold |kMinEnergy|.
|
||||
//
|
||||
// - self [i/o] : State information of the VAD.
|
||||
// - data_in [i] : Input audio data, for feature extraction.
|
||||
// - data_length [i] : Audio data size, in number of samples.
|
||||
// - features [o] : 10 * log10(energy in each frequency band), Q4.
|
||||
// - returns : Total energy of the signal (NOTE! This value is not
|
||||
// exact. It is only used in a comparison.)
|
||||
int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
int data_length, int16_t* features);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "vad_gmm.h"
|
||||
|
||||
#include "../signal_processing/include/signal_processing_library.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
static const int32_t kCompVar = 22005;
|
||||
static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12.
|
||||
|
||||
// For a normal distribution, the probability of |input| is calculated and
|
||||
// returned (in Q20). The formula for normal distributed probability is
|
||||
//
|
||||
// 1 / s * exp(-(x - m)^2 / (2 * s^2))
|
||||
//
|
||||
// where the parameters are given in the following Q domains:
|
||||
// m = |mean| (Q7)
|
||||
// s = |std| (Q7)
|
||||
// x = |input| (Q4)
|
||||
// in addition to the probability we output |delta| (in Q11) used when updating
|
||||
// the noise/speech model.
|
||||
int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t mean,
|
||||
int16_t std,
|
||||
int16_t* delta) {
|
||||
int16_t tmp16, inv_std, inv_std2, exp_value = 0;
|
||||
int32_t tmp32;
|
||||
|
||||
// Calculate |inv_std| = 1 / s, in Q10.
|
||||
// 131072 = 1 in Q17, and (|std| >> 1) is for rounding instead of truncation.
|
||||
// Q-domain: Q17 / Q7 = Q10.
|
||||
tmp32 = (int32_t) 131072 + (int32_t) (std >> 1);
|
||||
inv_std = (int16_t) WebRtcSpl_DivW32W16(tmp32, std);
|
||||
|
||||
// Calculate |inv_std2| = 1 / s^2, in Q14.
|
||||
tmp16 = (inv_std >> 2); // Q10 -> Q8.
|
||||
// Q-domain: (Q8 * Q8) >> 2 = Q14.
|
||||
inv_std2 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(tmp16, tmp16, 2);
|
||||
// TODO(bjornv): Investigate if changing to
|
||||
// |inv_std2| = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(|inv_std|, |inv_std|, 6);
|
||||
// gives better accuracy.
|
||||
|
||||
tmp16 = (input << 3); // Q4 -> Q7
|
||||
tmp16 = tmp16 - mean; // Q7 - Q7 = Q7
|
||||
|
||||
// To be used later, when updating noise/speech model.
|
||||
// |delta| = (x - m) / s^2, in Q11.
|
||||
// Q-domain: (Q14 * Q7) >> 10 = Q11.
|
||||
*delta = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(inv_std2, tmp16, 10);
|
||||
|
||||
// Calculate the exponent |tmp32| = (x - m)^2 / (2 * s^2), in Q10. Replacing
|
||||
// division by two with one shift.
|
||||
// Q-domain: (Q11 * Q7) >> 8 = Q10.
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16_RSFT(*delta, tmp16, 9);
|
||||
|
||||
// If the exponent is small enough to give a non-zero probability we calculate
|
||||
// |exp_value| ~= exp(-(x - m)^2 / (2 * s^2))
|
||||
// ~= exp2(-log2(exp(1)) * |tmp32|).
|
||||
if (tmp32 < kCompVar) {
|
||||
// Calculate |tmp16| = log2(exp(1)) * |tmp32|, in Q10.
|
||||
// Q-domain: (Q12 * Q10) >> 12 = Q10.
|
||||
tmp16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(kLog2Exp, (int16_t) tmp32, 12);
|
||||
tmp16 = -tmp16;
|
||||
exp_value = (0x0400 | (tmp16 & 0x03FF));
|
||||
tmp16 ^= 0xFFFF;
|
||||
tmp16 >>= 10;
|
||||
tmp16 += 1;
|
||||
// Get |exp_value| = exp(-|tmp32|) in Q10.
|
||||
exp_value >>= tmp16;
|
||||
}
|
||||
|
||||
// Calculate and return (1 / s) * exp(-(x - m)^2 / (2 * s^2)), in Q20.
|
||||
// Q-domain: Q10 * Q10 = Q20.
|
||||
return WEBRTC_SPL_MUL_16_16(inv_std, exp_value);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Gaussian probability calculations internally used in vad_core.c.
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
|
||||
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
// Calculates the probability for |input|, given that |input| comes from a
|
||||
// normal distribution with mean and standard deviation (|mean|, |std|).
|
||||
//
|
||||
// Inputs:
|
||||
// - input : input sample in Q4.
|
||||
// - mean : mean input in the statistical model, Q7.
|
||||
// - std : standard deviation, Q7.
|
||||
//
|
||||
// Output:
|
||||
//
|
||||
// - delta : input used when updating the model, Q11.
|
||||
// |delta| = (|input| - |mean|) / |std|^2.
|
||||
//
|
||||
// Return:
|
||||
// (probability for |input|) =
|
||||
// 1 / |std| * exp(-(|input| - |mean|)^2 / (2 * |std|^2));
|
||||
int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t mean,
|
||||
int16_t std,
|
||||
int16_t* delta);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "vad_sp.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "../signal_processing/include/signal_processing_library.h"
|
||||
#include "vad_core.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
// Allpass filter coefficients, upper and lower, in Q13.
|
||||
// Upper: 0.64, Lower: 0.17.
|
||||
static const int16_t kAllPassCoefsQ13[2] = { 5243, 1392 }; // Q13.
|
||||
static const int16_t kSmoothingDown = 6553; // 0.2 in Q15.
|
||||
static const int16_t kSmoothingUp = 32439; // 0.99 in Q15.
|
||||
|
||||
// TODO(bjornv): Move this function to vad_filterbank.c.
|
||||
// Downsampling filter based on splitting filter and allpass functions.
|
||||
void WebRtcVad_Downsampling(int16_t* signal_in,
|
||||
int16_t* signal_out,
|
||||
int32_t* filter_state,
|
||||
int in_length) {
|
||||
int16_t tmp16_1 = 0, tmp16_2 = 0;
|
||||
int32_t tmp32_1 = filter_state[0];
|
||||
int32_t tmp32_2 = filter_state[1];
|
||||
int n = 0;
|
||||
int half_length = (in_length >> 1); // Downsampling by 2 gives half length.
|
||||
|
||||
// Filter coefficients in Q13, filter state in Q0.
|
||||
for (n = 0; n < half_length; n++) {
|
||||
// All-pass filtering upper branch.
|
||||
tmp16_1 = (int16_t) ((tmp32_1 >> 1) +
|
||||
WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[0], *signal_in, 14));
|
||||
*signal_out = tmp16_1;
|
||||
tmp32_1 = (int32_t) (*signal_in++) -
|
||||
WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[0], tmp16_1, 12);
|
||||
|
||||
// All-pass filtering lower branch.
|
||||
tmp16_2 = (int16_t) ((tmp32_2 >> 1) +
|
||||
WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[1], *signal_in, 14));
|
||||
*signal_out++ += tmp16_2;
|
||||
tmp32_2 = (int32_t) (*signal_in++) -
|
||||
WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[1], tmp16_2, 12);
|
||||
}
|
||||
// Store the filter states.
|
||||
filter_state[0] = tmp32_1;
|
||||
filter_state[1] = tmp32_2;
|
||||
}
|
||||
|
||||
// Inserts |feature_value| into |low_value_vector|, if it is one of the 16
|
||||
// smallest values the last 100 frames. Then calculates and returns the median
|
||||
// of the five smallest values.
|
||||
int16_t WebRtcVad_FindMinimum(VadInstT* self,
|
||||
int16_t feature_value,
|
||||
int channel) {
|
||||
int i = 0, j = 0;
|
||||
int position = -1;
|
||||
// Offset to beginning of the 16 minimum values in memory.
|
||||
const int offset = (channel << 4);
|
||||
int16_t current_median = 1600;
|
||||
int16_t alpha = 0;
|
||||
int32_t tmp32 = 0;
|
||||
// Pointer to memory for the 16 minimum values and the age of each value of
|
||||
// the |channel|.
|
||||
int16_t* age = &self->index_vector[offset];
|
||||
int16_t* smallest_values = &self->low_value_vector[offset];
|
||||
|
||||
assert(channel < kNumChannels);
|
||||
|
||||
// Each value in |smallest_values| is getting 1 loop older. Update |age|, and
|
||||
// remove old values.
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (age[i] != 100) {
|
||||
age[i]++;
|
||||
} else {
|
||||
// Too old value. Remove from memory and shift larger values downwards.
|
||||
for (j = i; j < 16; j++) {
|
||||
smallest_values[j] = smallest_values[j + 1];
|
||||
age[j] = age[j + 1];
|
||||
}
|
||||
age[15] = 101;
|
||||
smallest_values[15] = 10000;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if |feature_value| is smaller than any of the values in
|
||||
// |smallest_values|. If so, find the |position| where to insert the new value
|
||||
// (|feature_value|).
|
||||
if (feature_value < smallest_values[7]) {
|
||||
if (feature_value < smallest_values[3]) {
|
||||
if (feature_value < smallest_values[1]) {
|
||||
if (feature_value < smallest_values[0]) {
|
||||
position = 0;
|
||||
} else {
|
||||
position = 1;
|
||||
}
|
||||
} else if (feature_value < smallest_values[2]) {
|
||||
position = 2;
|
||||
} else {
|
||||
position = 3;
|
||||
}
|
||||
} else if (feature_value < smallest_values[5]) {
|
||||
if (feature_value < smallest_values[4]) {
|
||||
position = 4;
|
||||
} else {
|
||||
position = 5;
|
||||
}
|
||||
} else if (feature_value < smallest_values[6]) {
|
||||
position = 6;
|
||||
} else {
|
||||
position = 7;
|
||||
}
|
||||
} else if (feature_value < smallest_values[15]) {
|
||||
if (feature_value < smallest_values[11]) {
|
||||
if (feature_value < smallest_values[9]) {
|
||||
if (feature_value < smallest_values[8]) {
|
||||
position = 8;
|
||||
} else {
|
||||
position = 9;
|
||||
}
|
||||
} else if (feature_value < smallest_values[10]) {
|
||||
position = 10;
|
||||
} else {
|
||||
position = 11;
|
||||
}
|
||||
} else if (feature_value < smallest_values[13]) {
|
||||
if (feature_value < smallest_values[12]) {
|
||||
position = 12;
|
||||
} else {
|
||||
position = 13;
|
||||
}
|
||||
} else if (feature_value < smallest_values[14]) {
|
||||
position = 14;
|
||||
} else {
|
||||
position = 15;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have detected a new small value, insert it at the correct position
|
||||
// and shift larger values up.
|
||||
if (position > -1) {
|
||||
for (i = 15; i > position; i--) {
|
||||
smallest_values[i] = smallest_values[i - 1];
|
||||
age[i] = age[i - 1];
|
||||
}
|
||||
smallest_values[position] = feature_value;
|
||||
age[position] = 1;
|
||||
}
|
||||
|
||||
// Get |current_median|.
|
||||
if (self->frame_counter > 2) {
|
||||
current_median = smallest_values[2];
|
||||
} else if (self->frame_counter > 0) {
|
||||
current_median = smallest_values[0];
|
||||
}
|
||||
|
||||
// Smooth the median value.
|
||||
if (self->frame_counter > 0) {
|
||||
if (current_median < self->mean_value[channel]) {
|
||||
alpha = kSmoothingDown; // 0.2 in Q15.
|
||||
} else {
|
||||
alpha = kSmoothingUp; // 0.99 in Q15.
|
||||
}
|
||||
}
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(alpha + 1, self->mean_value[channel]);
|
||||
tmp32 += WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX - alpha, current_median);
|
||||
tmp32 += 16384;
|
||||
self->mean_value[channel] = (int16_t) (tmp32 >> 15);
|
||||
|
||||
return self->mean_value[channel];
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
// This file includes specific signal processing tools used in vad_core.c.
|
||||
|
||||
#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
|
||||
#define WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
|
||||
|
||||
#include "vad_core.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
// Downsamples the signal by a factor 2, eg. 32->16 or 16->8.
|
||||
//
|
||||
// Inputs:
|
||||
// - signal_in : Input signal.
|
||||
// - in_length : Length of input signal in samples.
|
||||
//
|
||||
// Input & Output:
|
||||
// - filter_state : Current filter states of the two all-pass filters. The
|
||||
// |filter_state| is updated after all samples have been
|
||||
// processed.
|
||||
//
|
||||
// Output:
|
||||
// - signal_out : Downsampled signal (of length |in_length| / 2).
|
||||
void WebRtcVad_Downsampling(int16_t* signal_in,
|
||||
int16_t* signal_out,
|
||||
int32_t* filter_state,
|
||||
int in_length);
|
||||
|
||||
// Updates and returns the smoothed feature minimum. As minimum we use the
|
||||
// median of the five smallest feature values in a 100 frames long window.
|
||||
// As long as |handle->frame_counter| is zero, that is, we haven't received any
|
||||
// "valid" data, FindMinimum() outputs the default value of 1600.
|
||||
//
|
||||
// Inputs:
|
||||
// - feature_value : New feature value to update with.
|
||||
// - channel : Channel number.
|
||||
//
|
||||
// Input & Output:
|
||||
// - handle : State information of the VAD.
|
||||
//
|
||||
// Returns:
|
||||
// : Smoothed minimum value for a moving window.
|
||||
int16_t WebRtcVad_FindMinimum(VadInstT* handle,
|
||||
int16_t feature_value,
|
||||
int channel);
|
||||
|
||||
#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "include/webrtc_vad.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../signal_processing/include/signal_processing_library.h"
|
||||
#include "vad_core.h"
|
||||
#include "../include/typedefs.h"
|
||||
|
||||
static const int kInitCheck = 42;
|
||||
static const int kValidRates[] = { 8000, 16000, 32000, 48000 };
|
||||
static const size_t kRatesSize = sizeof(kValidRates) / sizeof(*kValidRates);
|
||||
static const int kMaxFrameLengthMs = 30;
|
||||
|
||||
int WebRtcVad_Create(VadInst** handle) {
|
||||
VadInstT* self = NULL;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
self = (VadInstT*) malloc(sizeof(VadInstT));
|
||||
*handle = (VadInst*) self;
|
||||
|
||||
if (self == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcSpl_Init();
|
||||
|
||||
self->init_flag = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcVad_Free(VadInst* handle) {
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(bjornv): Move WebRtcVad_InitCore() code here.
|
||||
int WebRtcVad_Init(VadInst* handle) {
|
||||
// Initialize the core VAD component.
|
||||
return WebRtcVad_InitCore((VadInstT*) handle);
|
||||
}
|
||||
|
||||
// TODO(bjornv): Move WebRtcVad_set_mode_core() code here.
|
||||
int WebRtcVad_set_mode(VadInst* handle, int mode) {
|
||||
VadInstT* self = (VadInstT*) handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (self->init_flag != kInitCheck) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return WebRtcVad_set_mode_core(self, mode);
|
||||
}
|
||||
|
||||
int WebRtcVad_Process(VadInst* handle, int fs, int16_t* audio_frame,
|
||||
int frame_length) {
|
||||
int vad = -1;
|
||||
VadInstT* self = (VadInstT*) handle;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->init_flag != kInitCheck) {
|
||||
return -1;
|
||||
}
|
||||
if (audio_frame == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (WebRtcVad_ValidRateAndFrameLength(fs, frame_length) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs == 48000) {
|
||||
vad = WebRtcVad_CalcVad48khz(self, audio_frame, frame_length);
|
||||
} else if (fs == 32000) {
|
||||
vad = WebRtcVad_CalcVad32khz(self, audio_frame, frame_length);
|
||||
} else if (fs == 16000) {
|
||||
vad = WebRtcVad_CalcVad16khz(self, audio_frame, frame_length);
|
||||
} else if (fs == 8000) {
|
||||
vad = WebRtcVad_CalcVad8khz(self, audio_frame, frame_length);
|
||||
}
|
||||
|
||||
if (vad > 0) {
|
||||
vad = 1;
|
||||
}
|
||||
return vad;
|
||||
}
|
||||
|
||||
int WebRtcVad_ValidRateAndFrameLength(int rate, int frame_length) {
|
||||
int return_value = -1;
|
||||
size_t i;
|
||||
int valid_length_ms;
|
||||
int valid_length;
|
||||
|
||||
// We only allow 10, 20 or 30 ms frames. Loop through valid frame rates and
|
||||
// see if we have a matching pair.
|
||||
for (i = 0; i < kRatesSize; i++) {
|
||||
if (kValidRates[i] == rate) {
|
||||
for (valid_length_ms = 10; valid_length_ms <= kMaxFrameLengthMs;
|
||||
valid_length_ms += 10) {
|
||||
valid_length = (kValidRates[i] / 1000 * valid_length_ms);
|
||||
if (frame_length == valid_length) {
|
||||
return_value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#include "webrtc/common_audio/vad/include/webrtc_vad.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include <stdlib.h>
|
||||
#include "webrtc/common_audio/include/typedefs.h"
|
||||
#include <jni.h>
|
||||
|
||||
#define AGGRESSIVENESS 3
|
||||
#define BUFFER_SIZE 512
|
||||
VadInst* internalHandle;
|
||||
int resultVad;
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_mozilla_speechlibrary_Vad_start (JNIEnv * env, jobject obj){
|
||||
short buffer[BUFFER_SIZE];
|
||||
int ret_state = 0;
|
||||
internalHandle = NULL;
|
||||
|
||||
ret_state = WebRtcVad_Create(&internalHandle);
|
||||
if (ret_state == -1) return -1;
|
||||
ret_state = WebRtcVad_Init(internalHandle);
|
||||
if (ret_state == -1) return -2;
|
||||
ret_state = WebRtcVad_set_mode(internalHandle, AGGRESSIVENESS);
|
||||
if (ret_state == -1) return -3;
|
||||
return ret_state;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_mozilla_speechlibrary_Vad_stop(JNIEnv * env, jobject object) {
|
||||
WebRtcVad_Free(internalHandle);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_mozilla_speechlibrary_Vad_isSilence(JNIEnv * env, jobject object) {
|
||||
return resultVad;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_mozilla_speechlibrary_Vad_feed(JNIEnv * env, jobject object, jshortArray bytes, jint size) {
|
||||
jshort * arrayElements = (*env)->GetShortArrayElements(env, bytes, 0);
|
||||
resultVad = WebRtcVad_Process(internalHandle, 16000, arrayElements, size);
|
||||
(*env)->ReleaseShortArrayElements( env, bytes, arrayElements, 0 );
|
||||
return resultVad;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the VAD API calls. Specific function calls are given below.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_VAD_WEBRTC_VAD_H_
|
||||
#define WEBRTC_VAD_WEBRTC_VAD_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
typedef struct WebRtcVadInst VadInst;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_get_version(...)
|
||||
*
|
||||
* This function returns the version number of the code.
|
||||
*
|
||||
* Output:
|
||||
* - version : Pointer to a buffer where the version info will
|
||||
* be stored.
|
||||
* Input:
|
||||
* - size_bytes : Size of the buffer.
|
||||
*
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_get_version(char *version, size_t size_bytes);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_AssignSize(...)
|
||||
*
|
||||
* This functions get the size needed for storing the instance for encoder
|
||||
* and decoder, respectively
|
||||
*
|
||||
* Input/Output:
|
||||
* - size_in_bytes : Pointer to integer where the size is returned
|
||||
*
|
||||
* Return value : 0
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_AssignSize(int *size_in_bytes);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_Assign(...)
|
||||
*
|
||||
* This functions Assigns memory for the instances.
|
||||
*
|
||||
* Input:
|
||||
* - vad_inst_addr : Address to where to assign memory
|
||||
* Output:
|
||||
* - vad_inst : Pointer to the instance that should be created
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_Assign(VadInst **vad_inst, void *vad_inst_addr);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_Create(...)
|
||||
*
|
||||
* This function creates an instance to the VAD structure
|
||||
*
|
||||
* Input:
|
||||
* - vad_inst : Pointer to VAD instance that should be created
|
||||
*
|
||||
* Output:
|
||||
* - vad_inst : Pointer to created VAD instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_Create(VadInst **vad_inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_Free(...)
|
||||
*
|
||||
* This function frees the dynamic memory of a specified VAD instance
|
||||
*
|
||||
* Input:
|
||||
* - vad_inst : Pointer to VAD instance that should be freed
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_Free(VadInst *vad_inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_Init(...)
|
||||
*
|
||||
* This function initializes a VAD instance
|
||||
*
|
||||
* Input:
|
||||
* - vad_inst : Instance that should be initialized
|
||||
*
|
||||
* Output:
|
||||
* - vad_inst : Initialized instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_Init(VadInst *vad_inst);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_set_mode(...)
|
||||
*
|
||||
* This function initializes a VAD instance
|
||||
*
|
||||
* Input:
|
||||
* - vad_inst : VAD instance
|
||||
* - mode : Aggressiveness setting (0, 1, 2, or 3)
|
||||
*
|
||||
* Output:
|
||||
* - vad_inst : Initialized instance
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_set_mode(VadInst *vad_inst, WebRtc_Word16 mode);
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcVad_Process(...)
|
||||
*
|
||||
* This functions does a VAD for the inserted speech frame
|
||||
*
|
||||
* Input
|
||||
* - vad_inst : VAD Instance. Needs to be initiated before call.
|
||||
* - fs : sampling frequency (Hz): 8000, 16000, or 32000
|
||||
* - speech_frame : Pointer to speech frame buffer
|
||||
* - frame_length : Length of speech frame buffer in number of samples
|
||||
*
|
||||
* Output:
|
||||
* - vad_inst : Updated VAD instance
|
||||
*
|
||||
* Return value : 1 - Active Voice
|
||||
* 0 - Non-active Voice
|
||||
* -1 - Error
|
||||
*/
|
||||
WebRtc_Word16 WebRtcVad_Process(VadInst *vad_inst,
|
||||
WebRtc_Word16 fs,
|
||||
WebRtc_Word16 *speech_frame,
|
||||
WebRtc_Word16 frame_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_VAD_WEBRTC_VAD_H_
|
|
@ -0,0 +1,9 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
public interface Encoder {
|
||||
|
||||
void encode(short[] buf, int pos, int len);
|
||||
|
||||
void close();
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
public class EncoderInfo {
|
||||
public int channels;
|
||||
public int hz;
|
||||
public int bps;
|
||||
|
||||
public EncoderInfo(int channels, int sampleRate, int bps) {
|
||||
this.channels = channels;
|
||||
this.hz = sampleRate;
|
||||
this.bps = bps;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioFormat;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileDescriptor;
|
||||
|
||||
public class Factory {
|
||||
|
||||
public static int getBitrate(int hz) {
|
||||
if (hz < 16000) {
|
||||
return 32000;
|
||||
} else if (hz < 44100) {
|
||||
return 64000;
|
||||
} else {
|
||||
return 128000;
|
||||
}
|
||||
}
|
||||
|
||||
public static Encoder getEncoder(Context context, String ext, EncoderInfo info, ByteArrayOutputStream out) {
|
||||
if (ext.equals(FormatOPUS.EXT)) {
|
||||
if (Build.VERSION.SDK_INT >= 23) { // Android 6.0 (has ogg/opus support) https://en.wikipedia.org/wiki/Opus_(audio_format)
|
||||
return new FormatOPUS_OGG(context, info, out); // android6+ supports ogg/opus
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long getEncoderRate(String ext, int rate) {
|
||||
if (ext.equals(FormatOPUS.EXT)) {
|
||||
long y1 = 202787; // one minute sample 16000Hz
|
||||
long x1 = 16000; // at 16000
|
||||
long y2 = 319120; // one minute sample
|
||||
long x2 = 44000; // at 44000
|
||||
long x = rate;
|
||||
long y = (x - x1) * (y2 - y1) / (x2 - x1) + y1;
|
||||
return y / 60;
|
||||
}
|
||||
|
||||
// default raw
|
||||
int c = Sound.DEFAULT_AUDIOFORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1;
|
||||
return c * rate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import com.github.axet.opusjni.Config;
|
||||
import com.github.axet.opusjni.Opus;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
@TargetApi(21)
|
||||
public class FormatOPUS implements Encoder {
|
||||
public static final String TAG = FormatOPUS.class.getSimpleName();
|
||||
|
||||
public static final String EXT = "opus";
|
||||
|
||||
public static final int SHORT_BYTES = Short.SIZE / Byte.SIZE;
|
||||
|
||||
EncoderInfo info;
|
||||
Opus opus;
|
||||
long NumSamples;
|
||||
ShortBuffer left;
|
||||
int frameSize = 960; // default 20ms
|
||||
int hz;
|
||||
Resample resample;
|
||||
|
||||
public static void natives(Context context) {
|
||||
if (Config.natives) {
|
||||
Natives.loadLibraries(context, "opus", "opusjni");
|
||||
Config.natives = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean supported(Context context) {
|
||||
try {
|
||||
FormatOPUS.natives(context);
|
||||
Opus v = new Opus();
|
||||
return true;
|
||||
} catch (NoClassDefFoundError | ExceptionInInitializerError | UnsatisfiedLinkError e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getBitrate(int hz) { // https://wiki.xiph.org/index.php?title=Opus_Recommended_Settings
|
||||
if (hz < 16000) {
|
||||
return 16000; // 0 - 16Hz
|
||||
} else if (hz < 44100) {
|
||||
return 24000; // 16 - 44Hz
|
||||
} else {
|
||||
return 32000; // 48Hz
|
||||
}
|
||||
}
|
||||
|
||||
public static int match(int hz) { // opus supports only selected Hz's
|
||||
int[] hh = new int[]{
|
||||
8000,
|
||||
12000,
|
||||
16000,
|
||||
24000,
|
||||
48000,
|
||||
};
|
||||
int i = Integer.MAX_VALUE;
|
||||
int r = 0;
|
||||
for (int h : hh) {
|
||||
int d = Math.abs(hz - h);
|
||||
if (d <= i) { // higher is better
|
||||
i = d;
|
||||
r = h;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public FormatOPUS(Context context, EncoderInfo info, ByteArrayOutputStream out) {
|
||||
natives(context);
|
||||
create(info, out);
|
||||
}
|
||||
|
||||
public void create(final EncoderInfo info, ByteArrayOutputStream out) {
|
||||
this.info = info;
|
||||
this.hz = match(info.hz);
|
||||
|
||||
if (hz != info.hz)
|
||||
resample = new Resample(info.hz, info.channels, hz);
|
||||
|
||||
opus = new Opus();
|
||||
opus.open(info.channels, hz, getBitrate(info.hz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(short[] buf, int pos, int len) {
|
||||
if (resample != null) {
|
||||
resample.write(buf, pos, len);
|
||||
resample();
|
||||
return;
|
||||
}
|
||||
encode2(buf, pos, len);
|
||||
}
|
||||
|
||||
void encode2(short[] buf, int pos, int len) {
|
||||
if (left != null) {
|
||||
ShortBuffer ss = ShortBuffer.allocate(left.position() + len);
|
||||
left.flip();
|
||||
ss.put(left);
|
||||
ss.put(buf, pos, len);
|
||||
buf = ss.array();
|
||||
pos = 0;
|
||||
len = ss.position();
|
||||
}
|
||||
if (frameSize == 0) {
|
||||
if (len < 240) {
|
||||
frameSize = 120;
|
||||
} else if (len < 480) {
|
||||
frameSize = 240;
|
||||
} else if (len < 960) {
|
||||
frameSize = 480;
|
||||
} else if (len < 1920) {
|
||||
frameSize = 960;
|
||||
} else if (len < 2880) {
|
||||
frameSize = 1920;
|
||||
} else {
|
||||
frameSize = 2880;
|
||||
}
|
||||
}
|
||||
int frameSizeStereo = frameSize * info.channels;
|
||||
int lenEncode = len / frameSizeStereo * frameSizeStereo;
|
||||
int end = pos + lenEncode;
|
||||
for (int p = pos; p < end; p += frameSizeStereo) {
|
||||
byte[] bb = opus.encode(buf, p, frameSizeStereo);
|
||||
encode(ByteBuffer.wrap(bb), frameSize);
|
||||
NumSamples += frameSizeStereo / info.channels;
|
||||
}
|
||||
int diff = len - lenEncode;
|
||||
if (diff > 0) {
|
||||
left = ShortBuffer.allocate(diff);
|
||||
left.put(buf, end, diff);
|
||||
} else {
|
||||
left = null;
|
||||
}
|
||||
}
|
||||
|
||||
void resample() {
|
||||
ByteBuffer bb;
|
||||
while ((bb = resample.read()) != null) {
|
||||
int len = bb.position() / SHORT_BYTES;
|
||||
short[] b = new short[len];
|
||||
bb.flip();
|
||||
bb.asShortBuffer().get(b, 0, len);
|
||||
encode2(b, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
void encode(ByteBuffer bb, long dur) {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (resample != null) {
|
||||
resample.end();
|
||||
resample();
|
||||
resample.close();
|
||||
resample = null;
|
||||
}
|
||||
opus.close();
|
||||
}
|
||||
|
||||
long getCurrentTimeStamp() {
|
||||
return NumSamples * 1000 / info.hz;
|
||||
}
|
||||
|
||||
public EncoderInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import org.gagravarr.ogg.OggFile;
|
||||
import org.gagravarr.ogg.OggPacketWriter;
|
||||
import org.gagravarr.opus.OpusAudioData;
|
||||
import org.gagravarr.opus.OpusInfo;
|
||||
import org.gagravarr.opus.OpusTags;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
// https://wiki.xiph.org/OggOpus
|
||||
@TargetApi(23)
|
||||
public class FormatOPUS_OGG extends FormatOPUS {
|
||||
public static final String TAG = FormatOPUS_OGG.class.getSimpleName();
|
||||
|
||||
OggFile file;
|
||||
OggPacketWriter writer;
|
||||
long lastGranule = 0;
|
||||
|
||||
public FormatOPUS_OGG(Context context, EncoderInfo info, ByteArrayOutputStream out) {
|
||||
super(context, info, out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(final EncoderInfo info, ByteArrayOutputStream out) {
|
||||
super.create(info, out);
|
||||
try {
|
||||
OpusInfo oinfo = new OpusInfo();
|
||||
oinfo.setNumChannels(info.channels);
|
||||
oinfo.setOutputGain(0);
|
||||
oinfo.setPreSkip(0);
|
||||
oinfo.setSampleRate(info.hz);
|
||||
OpusTags otags = new OpusTags();
|
||||
file = new OggFile(out);
|
||||
writer = file.getPacketWriter();
|
||||
writer.bufferPacket(oinfo.write());
|
||||
writer.flush();
|
||||
writer.bufferPacket(otags.write());
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void encode(ByteBuffer bb, long dur) {
|
||||
OpusAudioData frame = new OpusAudioData(bb.array());
|
||||
long end = NumSamples + dur;
|
||||
long gr = OpusAudioData.OPUS_GRANULE_RATE * end / info.hz; // Ogg gr always at 48000hz
|
||||
frame.setGranulePosition(gr);
|
||||
try {
|
||||
if (frame.getGranulePosition() >= 0 && lastGranule != frame.getGranulePosition()) {
|
||||
writer.flush();
|
||||
lastGranule = frame.getGranulePosition();
|
||||
writer.setGranulePosition(lastGranule);
|
||||
}
|
||||
writer.bufferPacket(frame.write());
|
||||
if (writer.getSizePendingFlush() > 16384) {
|
||||
writer.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
try {
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
writer = null;
|
||||
}
|
||||
if (file != null) {
|
||||
file.close();
|
||||
file = null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class Natives {
|
||||
|
||||
public static String ARCH = Build.CPU_ABI;
|
||||
|
||||
public static class ArchFirst implements Comparator<File> {
|
||||
@Override
|
||||
public int compare(File o1, File o2) {
|
||||
String p1 = o1.getPath();
|
||||
String p2 = o2.getPath();
|
||||
boolean b1 = p1.contains(ARCH);
|
||||
boolean b2 = p2.contains(ARCH);
|
||||
if (b1 && b2)
|
||||
return p1.compareTo(p2);
|
||||
if (b1)
|
||||
return -1;
|
||||
if (b2)
|
||||
return 1;
|
||||
return p1.compareTo(p2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadLibraries(Context context, String... libs) {
|
||||
try {
|
||||
for (String l : libs) {
|
||||
System.loadLibrary(l); // API16 failed to find dependencies
|
||||
}
|
||||
} catch (ExceptionInInitializerError | UnsatisfiedLinkError e) { // API15 crash
|
||||
for (String l : libs) {
|
||||
Natives.loadLibrary(context, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* API15 crash while loading wrong arch native libraries. We need to find and load them manually.
|
||||
* <p>
|
||||
* Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1286]: 1823 cannot locate '__aeabi_idiv0'...
|
||||
* at java.lang.Runtime.loadLibrary(Runtime.java:370)
|
||||
* at java.lang.System.loadLibrary(System.java:535)
|
||||
*/
|
||||
public static void loadLibrary(final Context context, String libname) {
|
||||
String file = search(context, System.mapLibraryName(libname));
|
||||
if (file == null)
|
||||
throw new UnsatisfiedLinkError("file not found: " + libname);
|
||||
System.load(file);
|
||||
}
|
||||
|
||||
public static String search(Context context, String filename) {
|
||||
String dir = context.getApplicationInfo().nativeLibraryDir;
|
||||
if (dir.endsWith(ARCH)) {
|
||||
File f = new File(dir);
|
||||
f = f.getParentFile();
|
||||
String lib = search(f, filename);
|
||||
if (lib != null)
|
||||
return lib;
|
||||
}
|
||||
return search(new File(dir), filename);
|
||||
}
|
||||
|
||||
public static String search(File f, String filename) {
|
||||
List<File> ff = list(f, filename);
|
||||
Collections.sort(ff, new ArchFirst());
|
||||
if (ff.size() == 0)
|
||||
return null;
|
||||
return ff.get(0).getAbsolutePath();
|
||||
}
|
||||
|
||||
public static ArrayList<File> list(File f, String filename) {
|
||||
ArrayList<File> ff = new ArrayList<>();
|
||||
File[] aa = f.listFiles();
|
||||
if (aa != null) {
|
||||
for (File a : aa) {
|
||||
if (a.isDirectory()) {
|
||||
ArrayList<File> mm = list(a, filename);
|
||||
ff.addAll(mm);
|
||||
}
|
||||
if (a.getName().equals(filename))
|
||||
ff.add(a);
|
||||
}
|
||||
}
|
||||
return ff;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.util.Log;
|
||||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import vavi.sound.pcm.resampling.ssrc.SSRC;
|
||||
|
||||
public class Resample {
|
||||
public static final String TAG = Resample.class.getSimpleName();
|
||||
|
||||
public static final ByteOrder ORDER = ByteOrder.LITTLE_ENDIAN;
|
||||
public static final int SHORT_BYTES = Short.SIZE / Byte.SIZE;
|
||||
public static final int PIPE_SIZE = 100 * 1024;
|
||||
|
||||
Thread thread;
|
||||
PipedOutputStream os;
|
||||
PipedInputStream is;
|
||||
RuntimeException delayed;
|
||||
|
||||
public Resample(final int sampleRate, final int channels, final int hz) {
|
||||
try {
|
||||
this.os = new PipedOutputStream();
|
||||
this.is = new PipedInputStream(PIPE_SIZE);
|
||||
final PipedInputStream is = new PipedInputStream(this.os);
|
||||
final PipedOutputStream os = new PipedOutputStream(this.is);
|
||||
final int c = Sound.DEFAULT_AUDIOFORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1;
|
||||
thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SSRC ssrc = new SSRC(is, os, sampleRate, hz, c, c, channels, Integer.MAX_VALUE, 0, 0, true);
|
||||
} catch (RuntimeException e) {
|
||||
Log.d(TAG, "SSRC failed", e);
|
||||
delayed = e;
|
||||
} catch (IOException e) {
|
||||
Log.d(TAG, "SSRC failed", e);
|
||||
delayed = new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}, "SSRC");
|
||||
thread.start();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (delayed != null)
|
||||
throw delayed;
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(short[] buf, int pos, int len) {
|
||||
if (delayed != null)
|
||||
throw delayed;
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.allocate(len * SHORT_BYTES);
|
||||
bb.order(ORDER);
|
||||
bb.asShortBuffer().put(buf, pos, len);
|
||||
os.write(bb.array());
|
||||
os.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer read() {
|
||||
if (delayed != null)
|
||||
throw delayed;
|
||||
try {
|
||||
int blen = is.available();
|
||||
if (blen <= 0)
|
||||
return null;
|
||||
byte[] b = new byte[blen];
|
||||
int read = is.read(b);
|
||||
ByteBuffer bb = ByteBuffer.allocate(read);
|
||||
bb.order(ORDER);
|
||||
bb.put(b, 0, read);
|
||||
return bb;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (thread != null) {
|
||||
thread.interrupt();
|
||||
try {
|
||||
thread.join();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
thread = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.github.axet.audiolibrary.encoders;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder;
|
||||
import org.apache.commons.math3.complex.Complex;
|
||||
import org.apache.commons.math3.transform.DftNormalization;
|
||||
import org.apache.commons.math3.transform.FastFourierTransformer;
|
||||
import org.apache.commons.math3.transform.TransformType;
|
||||
|
||||
public class Sound {
|
||||
public static final int DEFAULT_AUDIOFORMAT = AudioFormat.ENCODING_PCM_16BIT;
|
||||
|
||||
public static AudioRecord getAudioRecord(int aNumChannels, int aSampleRate){
|
||||
int minBufSize = AudioRecord.getMinBufferSize(aSampleRate,
|
||||
aNumChannels == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO,
|
||||
AudioFormat.ENCODING_PCM_16BIT);
|
||||
|
||||
// initialize audio recorder
|
||||
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
|
||||
aSampleRate,
|
||||
aNumChannels == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO,
|
||||
AudioFormat.ENCODING_PCM_16BIT,
|
||||
minBufSize);
|
||||
|
||||
return recorder;
|
||||
|
||||
}
|
||||
|
||||
public static double[] fft(short[] buffer, int offset, int len) {
|
||||
int len2 = (int) Math.pow(2, Math.ceil(Math.log(len) / Math.log(2)));
|
||||
|
||||
final double[][] dataRI = new double[][]{
|
||||
new double[len2], new double[len2]
|
||||
};
|
||||
|
||||
double[] dataR = dataRI[0];
|
||||
double[] dataI = dataRI[1];
|
||||
|
||||
double powerInput = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
dataR[i] = buffer[offset + i] / (float) 0x7fff;
|
||||
powerInput += dataR[i] * dataR[i];
|
||||
}
|
||||
powerInput = Math.sqrt(powerInput / len);
|
||||
|
||||
FastFourierTransformer.transformInPlace(dataRI, DftNormalization.STANDARD, TransformType.FORWARD);
|
||||
|
||||
double[] data = new double[len2 / 2];
|
||||
|
||||
data[0] = 10 * Math.log10(Math.pow(new Complex(dataR[0], dataI[0]).abs() / len2, 2));
|
||||
|
||||
double powerOutput = 0;
|
||||
for (int i = 1; i < data.length; i++) {
|
||||
Complex c = new Complex(dataR[i], dataI[i]);
|
||||
double p = c.abs();
|
||||
p = p / len2;
|
||||
p = p * p;
|
||||
p = p * 2;
|
||||
double dB = 10 * Math.log10(p);
|
||||
|
||||
powerOutput += p;
|
||||
data[i] = dB;
|
||||
}
|
||||
powerOutput = Math.sqrt(powerOutput);
|
||||
|
||||
// if(powerInput != powerOutput) {
|
||||
// throw new RuntimeException("in " + powerInput + " out " + powerOutput);
|
||||
// }
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.mozilla.speechlibrary;
|
||||
|
||||
public interface ISpeechRecognitionListener {
|
||||
void onSpeechStatusChanged(MozillaSpeechService.SpeechState aState, Object aPayload);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.mozilla.speechlibrary;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MozillaSpeechService {
|
||||
|
||||
protected static final String TAG = "MozillaSpeech";
|
||||
private final int SAMPLERATE = 16000;
|
||||
private final int CHANNELS = 1;
|
||||
private ArrayList<ISpeechRecognitionListener> mListeners;
|
||||
private Context mContext;
|
||||
private boolean isIdle = true;
|
||||
|
||||
public enum SpeechState
|
||||
{
|
||||
DECODING, MIC_ACTIVITY, STT_RESULT, START_LISTEN,
|
||||
NO_VOICE, CANCELED, ERROR
|
||||
}
|
||||
|
||||
private static final MozillaSpeechService ourInstance = new MozillaSpeechService();
|
||||
private SpeechRecognition mSpeechRecognition;
|
||||
private SpeechState mState;
|
||||
private Vad mVad;
|
||||
|
||||
public static MozillaSpeechService getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
private MozillaSpeechService() {
|
||||
}
|
||||
|
||||
public void start(Context aContext) {
|
||||
|
||||
try {
|
||||
if (!isIdle) {
|
||||
notifyListeners(SpeechState.ERROR, "Recognition already In progress");
|
||||
} else {
|
||||
mVad = new Vad();
|
||||
int retVal = mVad.start();
|
||||
this.mContext = aContext;
|
||||
if (retVal < 0) {
|
||||
notifyListeners(SpeechState.ERROR, "Error Initializing VAD " + String.valueOf(retVal));
|
||||
} else {
|
||||
this.mSpeechRecognition = new SpeechRecognition(SAMPLERATE, CHANNELS, mVad, aContext, this);
|
||||
Thread audio_thread = new Thread(this.mSpeechRecognition);
|
||||
audio_thread.start();
|
||||
isIdle = false;
|
||||
}
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
notifyListeners(SpeechState.ERROR, "General error loading the module.");
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(ISpeechRecognitionListener aListener) {
|
||||
if (mListeners == null) {
|
||||
mListeners = new ArrayList<>();
|
||||
}
|
||||
mListeners.add(aListener);
|
||||
}
|
||||
|
||||
public void notifyListeners(MozillaSpeechService.SpeechState aState, Object aPayload) {
|
||||
mState = aState;
|
||||
for (ISpeechRecognitionListener listener : mListeners) {
|
||||
listener.onSpeechStatusChanged(aState, aPayload);
|
||||
if (aState == SpeechState.STT_RESULT || aState == SpeechState.ERROR
|
||||
|| aState == SpeechState.NO_VOICE || aState == SpeechState.CANCELED) {
|
||||
isIdle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
this.mSpeechRecognition.cancel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package com.mozilla.speechlibrary;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import com.loopj.android.http.AsyncHttpResponseHandler;
|
||||
import com.loopj.android.http.SyncHttpClient;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import cz.msebera.android.httpclient.Header;
|
||||
import cz.msebera.android.httpclient.entity.ByteArrayEntity;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import static com.mozilla.speechlibrary.MozillaSpeechService.TAG;
|
||||
|
||||
public class Networking {
|
||||
|
||||
final String STT_ENDPOINT = "https://speaktome-2.services.mozilla.com/";
|
||||
MozillaSpeechService mSpeechService;
|
||||
public boolean cancelled;
|
||||
protected Context mContext;
|
||||
|
||||
public Networking(MozillaSpeechService aSpeechService) {
|
||||
this.mSpeechService = aSpeechService;
|
||||
}
|
||||
|
||||
protected void doSTT(final ByteArrayOutputStream baos) {
|
||||
|
||||
if (cancelled) {
|
||||
mSpeechService.notifyListeners(MozillaSpeechService.SpeechState.CANCELED, null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Looper.prepare();
|
||||
ByteArrayEntity byteArrayEntity = new ByteArrayEntity(baos.toByteArray());
|
||||
SyncHttpClient client = new SyncHttpClient();
|
||||
client.post(mContext,STT_ENDPOINT, byteArrayEntity, "audio/3gpp",
|
||||
new AsyncHttpResponseHandler() {
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
// called before request is started
|
||||
mSpeechService.notifyListeners(MozillaSpeechService.SpeechState.DECODING, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
|
||||
// Implement cancelation
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// called when response HTTP status is "200 OK"
|
||||
String json = new String(response);
|
||||
try {
|
||||
JSONObject reader = new JSONObject(json);
|
||||
JSONArray results = reader.getJSONArray("data");
|
||||
final String transcription = results.getJSONObject(0).getString("text");
|
||||
final String confidence = results.getJSONObject(0).getString("confidence");
|
||||
STTResult sttResult = new STTResult(transcription, Float.parseFloat(confidence));
|
||||
mSpeechService.notifyListeners(MozillaSpeechService.SpeechState.STT_RESULT, sttResult);
|
||||
} catch (Exception exc) {
|
||||
String error = String.format("Error parsing results: %s", exc.getMessage());
|
||||
mSpeechService.notifyListeners(MozillaSpeechService.SpeechState.ERROR, error);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
|
||||
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
|
||||
String error = String.format("Network Error: %s (%s)", errorResponse == null ? "General Error" : new String(errorResponse), String.valueOf(statusCode));
|
||||
mSpeechService.notifyListeners(MozillaSpeechService.SpeechState.ERROR, error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRetry(int retryNo) {
|
||||
// called when request is retried
|
||||
String error = String.format("Network Error: Retrying %s", String.valueOf(retryNo));
|
||||
mSpeechService.notifyListeners(MozillaSpeechService.SpeechState.ERROR, error);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.mozilla.speechlibrary;
|
||||
|
||||
public class STTResult {
|
||||
|
||||
public String mTranscription;
|
||||
public float mConfidence;
|
||||
|
||||
public STTResult(String aTranscription, float aConfidence) {
|
||||
this.mTranscription = aTranscription;
|
||||
this.mConfidence = aConfidence;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package com.mozilla.speechlibrary;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioRecord;
|
||||
import android.os.Process;
|
||||
import com.github.axet.audiolibrary.encoders.Encoder;
|
||||
import com.github.axet.audiolibrary.encoders.EncoderInfo;
|
||||
import com.github.axet.audiolibrary.encoders.Factory;
|
||||
import com.github.axet.audiolibrary.encoders.FormatOPUS;
|
||||
import com.github.axet.audiolibrary.encoders.Sound;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
class SpeechRecognition implements Runnable {
|
||||
|
||||
Vad mVad;
|
||||
short[] mBuftemp;
|
||||
ByteArrayOutputStream baos ;
|
||||
int mMinimumVoice = 250;
|
||||
int mMaximumSilence = 1500;
|
||||
int mUpperLimit = 10;
|
||||
static final int FRAME_SIZE = 160;
|
||||
boolean done;
|
||||
boolean cancelled;
|
||||
Context mContext;
|
||||
int mSampleRate;
|
||||
int mChannels;
|
||||
MozillaSpeechService mService;
|
||||
Networking network;
|
||||
|
||||
protected SpeechRecognition(int aSampleRate, int aChannels, Vad aVad, Context aContext, MozillaSpeechService aService) {
|
||||
this.mVad = aVad;
|
||||
this.mContext = aContext;
|
||||
this.mSampleRate = aSampleRate;
|
||||
this.mChannels = aChannels;
|
||||
this.mService = aService;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
|
||||
|
||||
baos = new ByteArrayOutputStream();
|
||||
boolean finishedvoice = false;
|
||||
long samplesvoice = 0 ;
|
||||
long samplessilence = 0 ;
|
||||
boolean touchedvoice = false;
|
||||
boolean touchedsilence = false;
|
||||
int vad = 0;
|
||||
long dtantes = System.currentTimeMillis();
|
||||
long dtantesmili = System.currentTimeMillis();
|
||||
boolean raisenovoice = false;
|
||||
network = new Networking(mService);
|
||||
network.mContext = this.mContext;
|
||||
AudioRecord recorder = Sound.getAudioRecord(mChannels, mSampleRate);
|
||||
EncoderInfo ef = new EncoderInfo(1, mSampleRate, 16);
|
||||
Encoder e = Factory.getEncoder(mContext, FormatOPUS.EXT, ef, baos);
|
||||
|
||||
recorder.startRecording();
|
||||
mService.notifyListeners(MozillaSpeechService.SpeechState.START_LISTEN, null);
|
||||
|
||||
while (!this.done && !this.cancelled) {
|
||||
int nshorts = 0 ;
|
||||
|
||||
try {
|
||||
mBuftemp = new short[FRAME_SIZE * mChannels * 2];
|
||||
nshorts = recorder.read(mBuftemp, 0, mBuftemp.length);
|
||||
vad = mVad.feed(mBuftemp, nshorts);
|
||||
e.encode(mBuftemp, 0, nshorts);
|
||||
double[] fft = Sound.fft(mBuftemp, 0, nshorts);
|
||||
double fftsum = Arrays.stream(fft).sum()/fft.length;
|
||||
mService.notifyListeners(MozillaSpeechService.SpeechState.MIC_ACTIVITY, fftsum);
|
||||
}
|
||||
catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
}
|
||||
|
||||
long dtdepois = System.currentTimeMillis();
|
||||
|
||||
if (vad == 0) {
|
||||
if (touchedvoice) {
|
||||
samplessilence += dtdepois - dtantesmili;
|
||||
if (samplessilence > mMaximumSilence) touchedsilence = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
samplesvoice += dtdepois - dtantesmili;
|
||||
if (samplesvoice > mMinimumVoice) touchedvoice = true;
|
||||
}
|
||||
dtantesmili = dtdepois;
|
||||
|
||||
if (touchedvoice && touchedsilence)
|
||||
finishedvoice = true;
|
||||
|
||||
if (finishedvoice) {
|
||||
this.done = true;
|
||||
network.doSTT(baos);
|
||||
}
|
||||
|
||||
if ((dtdepois - dtantes)/1000 > mUpperLimit ) {
|
||||
this.done = true;
|
||||
if (touchedvoice) {
|
||||
network.doSTT(baos);
|
||||
}
|
||||
else {
|
||||
raisenovoice = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nshorts <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
e.close();
|
||||
mVad.stop();
|
||||
recorder.stop();
|
||||
recorder.release();
|
||||
|
||||
if (raisenovoice) mService.notifyListeners(MozillaSpeechService.SpeechState.NO_VOICE, null);
|
||||
|
||||
if (cancelled) {
|
||||
cancelled = false;
|
||||
mService.notifyListeners(MozillaSpeechService.SpeechState.CANCELED, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
String error = String.format("General audio error %s", exc.getMessage());
|
||||
mService.notifyListeners(MozillaSpeechService.SpeechState.ERROR, error);
|
||||
exc.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void cancel(){
|
||||
cancelled = true;
|
||||
network.cancel();
|
||||
}
|
||||
}
|