summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2010-01-11 14:04:50 -0800
committerJean-Michel Trivi <jmtrivi@google.com>2010-01-11 14:16:28 -0800
commit0320f8bdfbaa733ff9d702f30417315830a162da (patch)
treed516e19505be5f2e1deba9260920dc3e3c568e73 /packages
parent9b0b155e6075b4aef742535afd1719ee6a88c1a3 (diff)
downloadframeworks_base-0320f8bdfbaa733ff9d702f30417315830a162da.zip
frameworks_base-0320f8bdfbaa733ff9d702f30417315830a162da.tar.gz
frameworks_base-0320f8bdfbaa733ff9d702f30417315830a162da.tar.bz2
Apply EQ on the output of the speech synthesis only when using the Pico
TTS engine.
Diffstat (limited to 'packages')
-rw-r--r--packages/TtsService/jni/android_tts_SynthProxy.cpp78
-rwxr-xr-xpackages/TtsService/src/android/tts/SynthProxy.java20
2 files changed, 76 insertions, 22 deletions
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index d114ea9..35b5675 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -41,8 +41,6 @@
#define FILTER_TRANSITION_FREQ 1100.0f // in Hz
#define FILTER_SHELF_SLOPE 1.0f // Q
#define FILTER_GAIN 5.5f // linear gain
-// such a huge gain is justified by how much energy in the low frequencies is "wasted" at the output
-// of the synthesis. The low shelving filter removes it, leaving room for amplification.
#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_WRITE_TO_FILE 1
@@ -80,13 +78,19 @@ double out0;// y[n]
double out1;// y[n-1]
double out2;// y[n-2]
+static float fFilterLowshelfAttenuation = FILTER_LOWSHELF_ATTENUATION;
+static float fFilterTransitionFreq = FILTER_TRANSITION_FREQ;
+static float fFilterShelfSlope = FILTER_SHELF_SLOPE;
+static float fFilterGain = FILTER_GAIN;
+static bool bUseFilter = false;
+
void initializeEQ() {
- amp = float(pow(10.0, FILTER_LOWSHELF_ATTENUATION / 40.0));
- w = 2.0 * M_PI * (FILTER_TRANSITION_FREQ / DEFAULT_TTS_RATE);
+ amp = float(pow(10.0, fFilterLowshelfAttenuation / 40.0));
+ w = 2.0 * M_PI * (fFilterTransitionFreq / DEFAULT_TTS_RATE);
sinw = float(sin(w));
cosw = float(cos(w));
- beta = float(sqrt(amp)/FILTER_SHELF_SLOPE);
+ beta = float(sqrt(amp)/fFilterShelfSlope);
// initialize low-shelf parameters
b0 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) + (beta*sinw));
@@ -96,9 +100,9 @@ void initializeEQ() {
a1 = 2.0F * ((amp-1.0F) + ((amp+1.0F)*cosw));
a2 = -((amp+1.0F) + ((amp-1.0F)*cosw) - (beta*sinw));
- m_fa = FILTER_GAIN * b0/a0;
- m_fb = FILTER_GAIN * b1/a0;
- m_fc = FILTER_GAIN * b2/a0;
+ m_fa = fFilterGain * b0/a0;
+ m_fb = fFilterGain * b1/a0;
+ m_fc = fFilterGain * b2/a0;
m_fd = a1/a0;
m_fe = a2/a0;
}
@@ -284,7 +288,9 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
if (bufferSize > 0) {
prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel);
if (pJniData->mAudioOut) {
- applyFilter((int16_t*)wav, bufferSize/2);
+ if (bUseFilter) {
+ applyFilter((int16_t*)wav, bufferSize/2);
+ }
pJniData->mAudioOut->write(wav, bufferSize);
memset(wav, 0, bufferSize);
//LOGV("AudioTrack wrote: %d bytes", bufferSize);
@@ -300,7 +306,9 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
return TTS_CALLBACK_HALT;
}
if (bufferSize > 0){
- applyFilter((int16_t*)wav, bufferSize/2);
+ if (bUseFilter) {
+ applyFilter((int16_t*)wav, bufferSize/2);
+ }
fwrite(wav, 1, bufferSize, pForAfter->outputFile);
memset(wav, 0, bufferSize);
}
@@ -334,23 +342,50 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
// ----------------------------------------------------------------------------
-static void
+static int
+android_tts_SynthProxy_setLowShelf(JNIEnv *env, jobject thiz, jboolean applyFilter,
+ jfloat filterGain, jfloat attenuationInDb, jfloat freqInHz, jfloat slope)
+{
+ int result = TTS_SUCCESS;
+
+ bUseFilter = applyFilter;
+ if (applyFilter) {
+ fFilterLowshelfAttenuation = attenuationInDb;
+ fFilterTransitionFreq = freqInHz;
+ fFilterShelfSlope = slope;
+ fFilterGain = filterGain;
+
+ if (fFilterShelfSlope != 0.0f) {
+ initializeEQ();
+ } else {
+ LOGE("Invalid slope, can't be null");
+ result = TTS_FAILURE;
+ }
+ }
+
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+static int
android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jstring nativeSoLib)
{
+ int result = TTS_FAILURE;
+
+ bUseFilter = false;
+
SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage();
prepAudioTrack(pJniStorage,
DEFAULT_TTS_STREAM_TYPE, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS);
- const char *nativeSoLibNativeString =
- env->GetStringUTFChars(nativeSoLib, 0);
+ const char *nativeSoLibNativeString = env->GetStringUTFChars(nativeSoLib, 0);
void *engine_lib_handle = dlopen(nativeSoLibNativeString,
RTLD_NOW | RTLD_LOCAL);
if (engine_lib_handle == NULL) {
LOGE("android_tts_SynthProxy_native_setup(): engine_lib_handle == NULL");
- // TODO report error so the TTS can't be used
} else {
TtsEngine *(*get_TtsEngine)() =
reinterpret_cast<TtsEngine* (*)()>(dlsym(engine_lib_handle, "getTtsEngine"));
@@ -362,18 +397,19 @@ android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
Mutex::Autolock l(engineMutex);
pJniStorage->mNativeSynthInterface->init(ttsSynthDoneCB);
}
+
+ result = TTS_SUCCESS;
}
// we use a weak reference so the SynthProxy object can be garbage collected.
pJniStorage->tts_ref = env->NewGlobalRef(weak_this);
// save the JNI resources so we can use them (and free them) later
- env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData,
- (int)pJniStorage);
-
- initializeEQ();
+ env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData, (int)pJniStorage);
env->ReleaseStringUTFChars(nativeSoLib, nativeSoLibNativeString);
+
+ return result;
}
@@ -842,9 +878,13 @@ static JNINativeMethod gMethods[] = {
(void*)android_tts_SynthProxy_shutdown
},
{ "native_setup",
- "(Ljava/lang/Object;Ljava/lang/String;)V",
+ "(Ljava/lang/Object;Ljava/lang/String;)I",
(void*)android_tts_SynthProxy_native_setup
},
+ { "native_setLowShelf",
+ "(ZFFFF)I",
+ (void*)android_tts_SynthProxy_setLowShelf
+ },
{ "native_finalize",
"(I)V",
(void*)android_tts_SynthProxy_native_finalize
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index 1d37ba0..6255275 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -32,6 +32,15 @@ import java.lang.ref.WeakReference;
@SuppressWarnings("unused")
public class SynthProxy {
+ // Default parameters of a filter to be applied when using the Pico engine.
+ // Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at
+ // the output of the synthesis. The low shelving filter removes it, leaving room for
+ // amplification.
+ private final static float PICO_FILTER_GAIN = 5.5f; // linear gain
+ private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB
+ private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f; // in Hz
+ private final static float PICO_FILTER_SHELF_SLOPE = 1.0f; // Q
+
//
// External API
//
@@ -40,8 +49,11 @@ public class SynthProxy {
* Constructor; pass the location of the native TTS .so to use.
*/
public SynthProxy(String nativeSoLib) {
- Log.v(TtsService.SERVICE_TAG, "TTS is loading " + nativeSoLib);
+ boolean applyFilter = nativeSoLib.toLowerCase().contains("pico");
+ Log.v(TtsService.SERVICE_TAG, "about to load "+ nativeSoLib + ", applyFilter="+applyFilter);
native_setup(new WeakReference<SynthProxy>(this), nativeSoLib);
+ native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION,
+ PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE);
}
/**
@@ -161,8 +173,10 @@ public class SynthProxy {
*/
private int mJniData = 0;
- private native final void native_setup(Object weak_this,
- String nativeSoLib);
+ private native final int native_setup(Object weak_this, String nativeSoLib);
+
+ private native final int native_setLowShelf(boolean applyFilter, float filterGain,
+ float attenuationInDb, float freqInHz, float slope);
private native final void native_finalize(int jniData);