Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/alexmarsev/soundtouch.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoroparviai <oparviai@f3a24b6a-cf45-0410-b55a-8c22e2698227>2015-05-15 03:07:10 +0300
committeroparviai <oparviai@f3a24b6a-cf45-0410-b55a-8c22e2698227>2015-05-15 03:07:10 +0300
commit2816202b12d5eee8d29a1b31e924bb393a2e3bc3 (patch)
tree2260f3a0d877a086843e9205ae0c1dd2258b6b51
parentf63712faa394603006e84811f18c01f452767a04 (diff)
Developed more refined Android example application that also works in ARM & X86 platforms.
-rw-r--r--include/STTypes.h1
-rw-r--r--source/Android-lib/AndroidManifest.xml3
-rw-r--r--source/Android-lib/README-SoundTouch-Android.html77
-rw-r--r--source/Android-lib/jni/Android.mk8
-rw-r--r--source/Android-lib/jni/Application.mk2
-rw-r--r--source/Android-lib/jni/soundtouch-jni.cpp158
-rw-r--r--source/Android-lib/res/layout/activity_example.xml55
-rw-r--r--source/Android-lib/src/net/surina/ExampleActivity.java201
-rw-r--r--source/Android-lib/src/net/surina/soundtouch/SoundTouch.java54
9 files changed, 457 insertions, 102 deletions
diff --git a/include/STTypes.h b/include/STTypes.h
index c11a9d9..e5633b9 100644
--- a/include/STTypes.h
+++ b/include/STTypes.h
@@ -172,6 +172,7 @@ namespace soundtouch
#else
// use c++ standard exceptions
#include <stdexcept>
+ #include <string>
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
#endif
diff --git a/source/Android-lib/AndroidManifest.xml b/source/Android-lib/AndroidManifest.xml
index b1f9798..b77e35e 100644
--- a/source/Android-lib/AndroidManifest.xml
+++ b/source/Android-lib/AndroidManifest.xml
@@ -8,6 +8,9 @@
android:minSdkVersion="11"
android:targetSdkVersion="21" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
diff --git a/source/Android-lib/README-SoundTouch-Android.html b/source/Android-lib/README-SoundTouch-Android.html
index b6184c0..171f680 100644
--- a/source/Android-lib/README-SoundTouch-Android.html
+++ b/source/Android-lib/README-SoundTouch-Android.html
@@ -45,9 +45,7 @@
open Cygwin/bash shell, go to directory <b>&quot;soundtouch/source/Android-lib/jni&quot;</b> and invoke the NDK
compiler with following command:</p>
<pre> $NDK/ndk-build</pre>
-<p>This will build the ARMv5 and ARMv7 versions of SoundTouch library (including
- also the example JNI
- interface, see below) into the &quot;libs&quot; subdirectory.</p>
+<p>This will build binaries for all the supported Android platforms (arm-v5, arm-v7, X86, MIPS etc) of SoundTouch library, plus the JNI wrapper interface as discussed below. The target binaries will be built into the &quot;libs&quot; subdirectory. As long as all these .so binary library versions are included in the APK Application delivery package, the targer Android device can choose the correct library version to use. </p>
<p>Notice that to allow Cygwin/bash to locate the NDK compile scripts, you
need to define the location of the NDK installation defined in environment
variable &quot;NDK&quot;. That's easiest done by adding the NDK path definition at end of
@@ -55,40 +53,6 @@
<pre> NDK=/cygdrive/d/Android/android-ndk-r6</pre>
<hr />
<h2>
- Android floating-point performance considerations</h2>
-<p>
- Default build target for
- Android NDK is ARMv5 CPU generation, as that works in
- all ARM-based Android devices.<p>
- This has a pitfall though: For ideal sound quality SoundTouch should be compiled
- to use floating-point algorithms, however, all low-end Android devices do not
- have floating-point hardware in their CPUs, and hence the default ARMv5 compilation uses software-emulation for floating-point calculations instead of
- hardware floating-point to allow running the binary executables also in low-end devices.<p>
- The floating point software-emulation is however several tens of times slower
- than real hardware-level floating-point calculations, making
- floating-point-intensive applications such as SoundTouch infeasible with low-end
- devices.<p>
- As workaround, the SoundTouch Android compilation builds two separate versions
- of the library:<ul>
- <li>ARMv5 version that compiles SoundTouch using integer algorithm version. The integer
- algorithm version compromises the sound quality but provides good performance also
- with low-end
- devices without hardware floating-point support in the CPU level.</li>
- <li>ARMv7 version that compiles SoundTouch using hardware floating-point algorithms.
- These algorithms provide ideal sound quality yet do not work in simpler CPU
- models.</li>
- </ul>
- <p>
- These two library compilations are already defined in file &quot;<b>jni/Application.mk</b>&quot;
- so that these two separate library targets are automatically built under the &quot;<b>libs</b>&quot;
- directory. As far as you include both these compiled library versions into your
- application delivery, the Android devices can automatically select the right
- library version based on the available device&#39;s capabilities.<p>
- Please yet be aware that depending on capabilities of the Android devices you
- will need to provide the SoundTouch routines with samples in either integer or
- floating-point format, so build your interface routines to take this into
- account.<hr />
-<h2>
Calling SoundTouch native routines from Android application</h2>
<p>The NDK tools build the SoundTouch c++ routines into a native binary library, while
Android applications are written in Java language. To call the SoundTouch and other c/c++
@@ -96,23 +60,42 @@
Interface (JNI).</p>
<p>
The SoundTouch source code package provides source code example how to
- use JNI to call native c++ routines from a Java class through the following
- source code file pair:<ul>
- <li><b>Android-lib/jni/soundtouch-jni.cpp</b>: This file contains c/c++ routine that
- calls SoundTouch library routine to return the library version string to the main
- Android application. The NDK compiles this file along with the SoundTouch
+ use JNI to call native c++ routines from a Java class, and provides source codes also for
+ a simple example Android application:<ul>
+ <li><b>ExampleActivity</b>: This is simple Android example application that
+ utilizes SoundTouch native routines for processing WAV audio files. To build the example
+ application, use Eclipse Android SDK environment to import the "ExampleActivity" project in the "Android-lib" folder into the Eclipse workspace.
+ <li><b>Android-lib/jni/soundtouch-jni.cpp</b>: This file contains c/c++ wrapper routines
+ for performing elementary audio file processing with adjusted tempo/pitch/speed parameters
+ from the Android application. The wrapper interface is not complete, but provides example
+ that is easy to extend when necessary. The NDK compiles this file along with the SoundTouch
routines into the native binary library.</li>
- <li><b>Android-lib/src/net/surina/soundtouch/SoundTouch.java</b>: This file provides
- a Java interface class to load the native library and to invoke the native routine implemented in
- the file <b>soundtouch-jni.cpp</b></li>
+ <li><b>Android-lib/src/net/surina/soundtouch/SoundTouch.java</b>: This file implements
+ the Java interface class that loasd & accesses the JNI routines in the natively compiled library.
+ The example Android application uses this class as interface for processing audio files
+ with SoundTouch.</li>
</ul>
<p>
Feel free to examine and extend the provided cpp/java source code example file pair to
- implement and integrate the desired SoundTouch library capabilities into your Android application.</p>
+ implement and integrate the desired SoundTouch library capabilities into your own Android application.</p>
+<hr />
+<h2>
+ Android floating-point performance considerations</h2>
+<p>
+ The make process will build dedicated binaries for each supported Android CPU hardware platform type.
+</p><p>SoundTouch uses floating-point algorithms for ideal sound quality on all other platform than in the lowest-end ARMv5. That is because lowest-end Android devices are not guaranteed to
+ have floating-point hardware in their CPUs, so that the ARMv5 compilation uses by default software-emulation for floating-point calculations to allow running the binary executables also in low-end devices without floating-point hardware.<p>
+ As floating point software-emulation is however several tens of times slower
+ than real hardware-level floating-point calculations, that would make running
+ floating-point-intensive applications such as SoundTouch infeasible in these low-end
+ devices. As workaround, the SoundTouch Android compilation builds the ARMv5 version using integer algorithm versions. The integer
+ algorithm version compromises the sound quality but provides good performance also
+ with low-end devices without hardware floating-point support in the CPU level.</p>
+ <p>When Android devices with more capable device is used, the device will automatically choose a proper library version for ideal sound quality.</p>
<hr />
<p style="text-align: center"><i>Copyright &copy; Olli Parviainen</i></p>
<!--
$Id$
-->
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/source/Android-lib/jni/Android.mk b/source/Android-lib/jni/Android.mk
index 6a88196..ef5cfef 100644
--- a/source/Android-lib/jni/Android.mk
+++ b/source/Android-lib/jni/Android.mk
@@ -23,7 +23,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := soundtouch
LOCAL_SRC_FILES := soundtouch-jni.cpp ../../SoundTouch/AAFilter.cpp ../../SoundTouch/FIFOSampleBuffer.cpp \
../../SoundTouch/FIRFilter.cpp ../../SoundTouch/cpu_detect_x86.cpp \
- ../../SoundTouch/sse_optimized.cpp \
+ ../../SoundTouch/sse_optimized.cpp ../../SoundStretch/WavFile.cpp \
../../SoundTouch/RateTransposer.cpp ../../SoundTouch/SoundTouch.cpp \
../../SoundTouch/InterpolateCubic.cpp ../../SoundTouch/InterpolateLinear.cpp \
../../SoundTouch/InterpolateShannon.cpp ../../SoundTouch/TDStretch.cpp \
@@ -37,7 +37,9 @@ LOCAL_LDLIBS += -llog
# for native asset manager
#LOCAL_LDLIBS += -landroid
# don't export all symbols
-# added "-marm" switch to use arm instruction set instead of thumb for improved calculation performance.
-LOCAL_CFLAGS += -fvisibility=hidden -I ../../../include -D ST_NO_EXCEPTION_HANDLING -fdata-sections -ffunction-sections
+#
+# in ARM-only environment could add "-marm" switch to force arm instruction set instead
+# of thumb for improved calculation performance.
+LOCAL_CFLAGS += -fvisibility=hidden -I ../../../include -fdata-sections -ffunction-sections
include $(BUILD_SHARED_LIBRARY)
diff --git a/source/Android-lib/jni/Application.mk b/source/Android-lib/jni/Application.mk
index 9f0c50a..68ef2d0 100644
--- a/source/Android-lib/jni/Application.mk
+++ b/source/Android-lib/jni/Application.mk
@@ -5,3 +5,5 @@
APP_ABI := all #armeabi-v7a armeabi
APP_OPTIM := release
+APP_STL := stlport_static
+APP_CPPFLAGS := -fexceptions \ No newline at end of file
diff --git a/source/Android-lib/jni/soundtouch-jni.cpp b/source/Android-lib/jni/soundtouch-jni.cpp
index 8df3543..15fb446 100644
--- a/source/Android-lib/jni/soundtouch-jni.cpp
+++ b/source/Android-lib/jni/soundtouch-jni.cpp
@@ -14,17 +14,101 @@
#include <jni.h>
#include <android/log.h>
+#include <stdexcept>
+#include <string>
+
+using namespace std;
#include "../../../include/SoundTouch.h"
+#include "../source/SoundStretch/WavFile.h"
#define LOGV(...) __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
//#define LOGV(...)
+// String for keeping possible c++ exception error messages. Notice that this isn't
+// thread-safe but it's expected that exceptions are special situations that won't
+// occur in several threads in parallel.
+static string _errMsg = "";
+
+
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
+#define BUFF_SIZE 4096
+
using namespace soundtouch;
+
+// Set error message to return
+static void _setErrmsg(const char *msg)
+{
+ _errMsg = msg;
+}
+
+
+
+// Processes the sound file
+static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
+{
+ int nSamples;
+ int nChannels;
+ int buffSizeSamples;
+ SAMPLETYPE sampleBuffer[BUFF_SIZE];
+
+ // open input file
+ WavInFile inFile(inFileName);
+ int sampleRate = inFile.getSampleRate();
+ int bits = inFile.getNumBits();
+ nChannels = inFile.getNumChannels();
+
+ // create output file
+ WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
+
+ pSoundTouch->setSampleRate(sampleRate);
+ pSoundTouch->setChannels(nChannels);
+
+ assert(nChannels > 0);
+ buffSizeSamples = BUFF_SIZE / nChannels;
+
+ // Process samples read from the input file
+ while (inFile.eof() == 0)
+ {
+ int num;
+
+ // Read a chunk of samples from the input file
+ num = inFile.read(sampleBuffer, BUFF_SIZE);
+ nSamples = num / nChannels;
+
+ // Feed the samples into SoundTouch processor
+ pSoundTouch->putSamples(sampleBuffer, nSamples);
+
+ // Read ready samples from SoundTouch processor & write them output file.
+ // NOTES:
+ // - 'receiveSamples' doesn't necessarily return any samples at all
+ // during some rounds!
+ // - On the other hand, during some round 'receiveSamples' may have more
+ // ready samples than would fit into 'sampleBuffer', and for this reason
+ // the 'receiveSamples' call is iterated for as many times as it
+ // outputs samples.
+ do
+ {
+ nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
+ outFile.write(sampleBuffer, nSamples * nChannels);
+ } while (nSamples != 0);
+ }
+
+ // Now the input file is processed, yet 'flush' few last samples that are
+ // hiding in the SoundTouch's internal processing pipeline.
+ pSoundTouch->flush();
+ do
+ {
+ nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
+ outFile.write(sampleBuffer, nSamples * nChannels);
+ } while (nSamples != 0);
+}
+
+
+
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
{
const char *verStr;
@@ -37,3 +121,77 @@ extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionSt
// return version as string
return env->NewStringUTF(verStr);
}
+
+
+
+extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
+{
+ return (jlong)(new SoundTouch());
+}
+
+
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
+{
+ SoundTouch *ptr = (SoundTouch*)handle;
+ delete ptr;
+}
+
+
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
+{
+ SoundTouch *ptr = (SoundTouch*)handle;
+ ptr->setTempo(tempo);
+}
+
+
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
+{
+ SoundTouch *ptr = (SoundTouch*)handle;
+ ptr->setPitchSemiTones(pitch);
+}
+
+
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
+{
+ SoundTouch *ptr = (SoundTouch*)handle;
+ ptr->setRate(speed);
+}
+
+
+extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
+{
+ jstring result = env->NewStringUTF(_errMsg.c_str());
+ _errMsg.clear();
+
+ return result;
+}
+
+
+extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
+{
+ SoundTouch *ptr = (SoundTouch*)handle;
+
+ const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
+ const char *outputFile = env->GetStringUTFChars(joutputFile, 0);
+
+ LOGV("JNI process file %s", inputFile);
+
+ try
+ {
+ _processFile(ptr, inputFile, outputFile);
+ }
+ catch (const runtime_error &e)
+ {
+ const char *err = e.what();
+ // An exception occurred during processing, return the error message
+ LOGV("JNI exception in SoundTouch::processFile: %s", err);
+ _setErrmsg(err);
+ return -1;
+ }
+
+
+ env->ReleaseStringUTFChars(jinputFile, inputFile);
+ env->ReleaseStringUTFChars(joutputFile, outputFile);
+
+ return 0;
+}
diff --git a/source/Android-lib/res/layout/activity_example.xml b/source/Android-lib/res/layout/activity_example.xml
index fcb296f..b333511 100644
--- a/source/Android-lib/res/layout/activity_example.xml
+++ b/source/Android-lib/res/layout/activity_example.xml
@@ -24,7 +24,7 @@
android:id="@+id/editTextTempo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ems="10"
+ android:ems="5"
android:inputType="numberDecimal"
android:text="100" >
</EditText>
@@ -38,45 +38,24 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Pitch steps:"
+ android:text="Pitch half-steps:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/editTextPitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ems="10"
- android:inputType="numberDecimal"
+ android:ems="5"
+ android:inputType="numberSigned"
android:text="0" >
</EditText>
</TableRow>
-
- <TableRow
- android:id="@+id/tableRow3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Speed % :"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <EditText
- android:id="@+id/editTextSpeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ems="10"
- android:inputType="numberDecimal"
- android:text="100" >
- </EditText>
- </TableRow>
</TableLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:paddingTop="20dp" >
+ android:layout_marginTop="10dp" >
<TextView
android:layout_width="wrap_content"
@@ -88,7 +67,9 @@
android:id="@+id/editTextSrcFileName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:text="/sdcard/Download/test.wav"
android:layout_weight="1" />
+
<Button
android:id="@+id/buttonSelectSrcFile"
@@ -111,6 +92,7 @@
android:id="@+id/editTextOutFileName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:text="/sdcard/Download/soundtouch-output.wav"
android:layout_weight="1" />
<Button
@@ -120,8 +102,15 @@
android:text="Select" />
</LinearLayout>
+ <CheckBox
+ android:id="@+id/checkBoxPlay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:text="Play the output file after processing!" />
+
<Button
- android:id="@+id/button1"
+ android:id="@+id/buttonProcess"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -130,14 +119,22 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="20dp"
+ android:layout_marginTop="10dp"
android:text="Status console:"
android:textAppearance="?android:attr/textAppearanceMedium" />
- <TextView
+ <ScrollView
+ android:id="@+id/scrollView1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <TextView
android:id="@+id/textViewResult"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/hello_world" />
+
+ </ScrollView>
+
</LinearLayout>
diff --git a/source/Android-lib/src/net/surina/ExampleActivity.java b/source/Android-lib/src/net/surina/ExampleActivity.java
index d1f8e1c..465cb9d 100644
--- a/source/Android-lib/src/net/surina/ExampleActivity.java
+++ b/source/Android-lib/src/net/surina/ExampleActivity.java
@@ -1,21 +1,50 @@
+/////////////////////////////////////////////////////////////////////////////
+///
+/// Example Android Application/Activity that allows processing WAV
+/// audio files with SoundTouch library
+///
+/// Copyright (c) Olli Parviainen
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// $Id: SoundTouch.java 210 2015-05-14 20:03:56Z oparviai $
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
package net.surina;
+import java.io.File;
+
import net.surina.soundtouch.SoundTouch;
import net.surina.soundtouchexample.R;
-import net.surina.soundtouchexample.R.id;
-import net.surina.soundtouchexample.R.layout;
import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
import android.widget.TextView;
+import android.widget.Toast;
-public class ExampleActivity extends Activity
+public class ExampleActivity extends Activity implements OnClickListener
{
- TextView textViewConsole;
+ TextView textViewConsole = null;
+ EditText editSourceFile = null;
+ EditText editOutputFile = null;
+ EditText editTempo = null;
+ EditText editPitch = null;
+ CheckBox checkBoxPlay = null;
+
StringBuilder consoleText = new StringBuilder();
+ /// Called when the activity is created
@Override
protected void onCreate(Bundle savedInstanceState)
{
@@ -23,38 +52,164 @@ public class ExampleActivity extends Activity
setContentView(R.layout.activity_example);
textViewConsole = (TextView)findViewById(R.id.textViewResult);
+ editSourceFile = (EditText)findViewById(R.id.editTextSrcFileName);
+ editOutputFile = (EditText)findViewById(R.id.editTextOutFileName);
+
+ editTempo = (EditText)findViewById(R.id.editTextTempo);
+ editPitch = (EditText)findViewById(R.id.editTextPitch);
- // Check soundtouch
+ Button buttonFileSrc = (Button)findViewById(R.id.buttonSelectSrcFile);
+ Button buttonFileOutput = (Button)findViewById(R.id.buttonSelectOutFile);
+ Button buttonProcess = (Button)findViewById(R.id.buttonProcess);
+ buttonFileSrc.setOnClickListener(this);
+ buttonFileOutput.setOnClickListener(this);
+ buttonProcess.setOnClickListener(this);
+
+ checkBoxPlay = (CheckBox)findViewById(R.id.checkBoxPlay);
+
+ // Check soundtouch library presence & version
checkLibVersion();
}
-
- @Override
- protected void onDestroy()
+
+ /// Function to append status text onto "console box" on the Activity
+ public void appendToConsole(final String text)
{
- textViewConsole = null;
+ // run on UI thread to avoid conflicts
+ runOnUiThread(new Runnable()
+ {
+ public void run()
+ {
+ consoleText.append(text);
+ consoleText.append("\n");
+ textViewConsole.setText(consoleText);
+ }
+ });
}
+
- /// Append text to console on the activity
- public void appendToConsole(String text)
+ /// print SoundTouch native library version onto console
+ protected void checkLibVersion()
{
- if (textViewConsole == null) return;
- consoleText.append(text);
- consoleText.append("\n");
- textViewConsole.setText(consoleText);
+ String ver = SoundTouch.getVersionString();
+ appendToConsole("SoundTouch native library version = " + ver);
+ }
+
+
+
+ /// Button click handler
+ @Override
+ public void onClick(View arg0)
+ {
+ switch (arg0.getId())
+ {
+ case R.id.buttonSelectSrcFile:
+ case R.id.buttonSelectOutFile:
+ // one of the file select buttons clicked ... we've not just implemented them ;-)
+ Toast.makeText(this, "File selector not implemented, sorry! Enter the file path manually ;-)", Toast.LENGTH_LONG).show();
+ break;
+
+ case R.id.buttonProcess:
+ // button "process" pushed
+ process();
+ break;
+ }
+
}
+ /// Play audio file
+ protected void playWavFile(String fileName)
+ {
+ File file2play = new File(fileName);
+ Intent i = new Intent();
+ i.setAction(android.content.Intent.ACTION_VIEW);
+ i.setDataAndType(Uri.fromFile(file2play), "audio/wav");
+ startActivity(i);
+ }
- /// print SoundTouch native library version onto console
- protected void checkLibVersion()
+
+
+ /// Helper class that will execute the SoundTouch processing. As the processing may take
+ /// some time, run it in background thread to avoid hanging of the UI.
+ protected class ProcessTask extends AsyncTask<ProcessTask.Parameters, Integer, Long>
{
- SoundTouch st = new SoundTouch();
+ /// Helper class to store the SoundTouch file processing parameters
+ public final class Parameters
+ {
+ String inFileName;
+ String outFileName;
+ float tempo;
+ float pitch;
+ }
+
+
+ /// Processing routine
+ @Override
+ protected Long doInBackground(Parameters... aparams)
+ {
+ Parameters params = aparams[0];
+
+ SoundTouch st = new SoundTouch();
+ st.setTempo(params.tempo);
+ st.setPitchSemiTones(params.pitch);
+ Log.i("SoundTouch", "process file " + params.inFileName);
+ long startTime = System.currentTimeMillis();
+ int res = st.processFile(params.inFileName, params.outFileName);
+ long endTime = System.currentTimeMillis();
+ float duration = (endTime - startTime) * 0.001f;
+
+ Log.i("SoundTouch", "process file done, duration = " + duration);
+ appendToConsole("Processing done, duration " + duration + " sec.");
+ if (res != 0)
+ {
+ String err = SoundTouch.getErrorString();
+ appendToConsole("Failure: " + err);
+ return -1L;
+ }
+
+ // Play file if so is desirable
+ if (checkBoxPlay.isChecked())
+ {
+ playWavFile(params.outFileName);
+ }
+ return 0L;
+ }
- String ver = st.getVersionString();
- appendToConsole("SoundTouch native library version = " + ver);
}
-}
+
+ /// process a file with SoundTouch. Do the processing using a background processing
+ /// task to avoid hanging of the UI
+ protected void process()
+ {
+ try
+ {
+ ProcessTask task = new ProcessTask();
+ ProcessTask.Parameters params = task.new Parameters();
+ // parse processing parameters
+ params.inFileName = editSourceFile.getText().toString();
+ params.outFileName = editOutputFile.getText().toString();
+ params.tempo = 0.01f * Float.parseFloat(editTempo.getText().toString());
+ params.pitch = Float.parseFloat(editPitch.getText().toString());
+
+ // update UI about status
+ appendToConsole("Process audio file :" + params.inFileName +" => " + params.outFileName);
+ appendToConsole("Tempo = " + params.tempo);
+ appendToConsole("Pitch adjust = " + params.pitch);
+
+ Toast.makeText(this, "Starting to process file " + params.inFileName + "...", Toast.LENGTH_SHORT).show();
+
+ // start processing task in background
+ task.execute(params);
+
+ }
+ catch (Exception exp)
+ {
+ exp.printStackTrace();
+ }
+
+ }
+} \ No newline at end of file
diff --git a/source/Android-lib/src/net/surina/soundtouch/SoundTouch.java b/source/Android-lib/src/net/surina/soundtouch/SoundTouch.java
index 40a6f8c..323cd9e 100644
--- a/source/Android-lib/src/net/surina/soundtouch/SoundTouch.java
+++ b/source/Android-lib/src/net/surina/soundtouch/SoundTouch.java
@@ -20,7 +20,61 @@ public final class SoundTouch
// Native interface function that returns SoundTouch version string.
// This invokes the native c++ routine defined in "soundtouch-jni.cpp".
public native final static String getVersionString();
+
+ private native final void setTempo(long handle, float tempo);
+ private native final void setPitchSemiTones(long handle, float pitch);
+
+ private native final void setSpeed(long handle, float speed);
+
+ private native final int processFile(long handle, String inputFile, String outputFile);
+
+ public native final static String getErrorString();
+
+ private native final static long newInstance();
+
+ private native final void deleteInstance(long handle);
+
+ long handle = 0;
+
+
+ public SoundTouch()
+ {
+ handle = newInstance();
+ }
+
+
+ public void close()
+ {
+ deleteInstance(handle);
+ handle = 0;
+ }
+
+
+ public void setTempo(float tempo)
+ {
+ setTempo(handle, tempo);
+ }
+
+
+ public void setPitchSemiTones(float pitch)
+ {
+ setPitchSemiTones(handle, pitch);
+ }
+
+
+ public void setSpeed(float speed)
+ {
+ setSpeed(handle, speed);
+ }
+
+
+ public int processFile(String inputFile, String outputFile)
+ {
+ return processFile(handle, inputFile, outputFile);
+ }
+
+
// Load the native library upon startup
static
{