1f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert/*
2f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * Copyright (C) 2011 The Android Open Source Project
3f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert *
4f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * use this file except in compliance with the License. You may obtain a copy of
6f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * the License at
7f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert *
8f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
9f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert *
10f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
11f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * License for the specific language governing permissions and limitations under
14f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * the License.
15f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert */
16f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringertpackage com.android.tts.compat;
17f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
18d79748518477851b8f68b9744db844e0ec8d6727Narayan Kamathimport android.speech.tts.SynthesisCallback;
19f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringertimport android.speech.tts.SynthesisRequest;
20f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringertimport android.util.Log;
21f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
22f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert/**
23f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * The SpeechSynthesis class provides a high-level api to create and play
24f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * synthesized speech. This class is used internally to talk to a native
25f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * TTS library that implements the interface defined in
26f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert * frameworks/base/include/tts/TtsEngine.h
27f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert *
28f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert */
29f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringertpublic class SynthProxy {
30f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
31f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    static {
32f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        System.loadLibrary("ttscompat");
33f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
34f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
35f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private final static String TAG = "SynthProxy";
36f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
37f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    // Default parameters of a filter to be applied when using the Pico engine.
38f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    // Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at
39f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    // the output of the synthesis. The low shelving filter removes it, leaving room for
40f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    // amplification.
41f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private final static float PICO_FILTER_GAIN = 5.0f; // linear gain
42f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB
43f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f;     // in Hz
44f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private final static float PICO_FILTER_SHELF_SLOPE = 1.0f;            // Q
45f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
46d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private long mJniData = 0;
47f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
48f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
49f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Constructor; pass the location of the native TTS .so to use.
50f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
51f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public SynthProxy(String nativeSoLib, String engineConfig) {
52f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        boolean applyFilter = shouldApplyAudioFilter(nativeSoLib);
53f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        Log.v(TAG, "About to load "+ nativeSoLib + ", applyFilter=" + applyFilter);
54f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        mJniData = native_setup(nativeSoLib, engineConfig);
55f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        if (mJniData == 0) {
56f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            throw new RuntimeException("Failed to load " + nativeSoLib);
57f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        }
58f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION,
59f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert                PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE);
60f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
61f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
62f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    // HACK: Apply audio filter if the engine is pico
63f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private boolean shouldApplyAudioFilter(String nativeSoLib) {
64f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return nativeSoLib.toLowerCase().contains("pico");
65f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
66f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
67f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
68f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Stops and clears the AudioTrack.
69f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
70f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public int stop() {
71f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_stop(mJniData);
72f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
73f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
74f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
75f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Synchronous stop of the synthesizer. This method returns when the synth
76f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * has completed the stop procedure and doesn't use any of the resources it
77f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * was using while synthesizing.
78f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     *
79f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * @return {@link android.speech.tts.TextToSpeech#SUCCESS} or
80f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     *         {@link android.speech.tts.TextToSpeech#ERROR}
81f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
82f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public int stopSync() {
83f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_stopSync(mJniData);
84f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
85f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
86d79748518477851b8f68b9744db844e0ec8d6727Narayan Kamath    public int speak(SynthesisRequest request, SynthesisCallback callback) {
87d79748518477851b8f68b9744db844e0ec8d6727Narayan Kamath        return native_speak(mJniData, request.getText(), callback);
88f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
89f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
90f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
91f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Queries for language support.
92f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Return codes are defined in android.speech.tts.TextToSpeech
93f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
94f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public int isLanguageAvailable(String language, String country, String variant) {
95f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_isLanguageAvailable(mJniData, language, country, variant);
96f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
97f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
98f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
99f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Updates the engine configuration.
100f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
101f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public int setConfig(String engineConfig) {
102f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_setProperty(mJniData, "engineConfig", engineConfig);
103f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
104f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
105f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
106f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Sets the language.
107f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
108f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public int setLanguage(String language, String country, String variant) {
109f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_setLanguage(mJniData, language, country, variant);
110f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
111f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
112f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
113f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Loads the language: it's not set, but prepared for use later.
114f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
115f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public int loadLanguage(String language, String country, String variant) {
116f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_loadLanguage(mJniData, language, country, variant);
117f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
118f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
119f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
120f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Sets the speech rate.
121f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
122f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public final int setSpeechRate(int speechRate) {
123f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_setProperty(mJniData, "rate", String.valueOf(speechRate));
124f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
125f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
126f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
127f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Sets the pitch of the synthesized voice.
128f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
129f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public final int setPitch(int pitch) {
130f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_setProperty(mJniData, "pitch", String.valueOf(pitch));
131f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
132f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
133f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
134f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Returns the currently set language, country and variant information.
135f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
136f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    public String[] getLanguage() {
137f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        return native_getLanguage(mJniData);
138f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
139f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
140f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    /**
141f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     * Shuts down the native synthesizer.
142f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert     */
143e246fccbaf595e39c647502fa76f996dee8f0711Bjorn Bringert    public void shutdown() {
144f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        native_shutdown(mJniData);
145e246fccbaf595e39c647502fa76f996dee8f0711Bjorn Bringert        mJniData = 0;
146f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
147f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
148f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    @Override
149f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    protected void finalize() {
150f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        if (mJniData != 0) {
151f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            Log.w(TAG, "SynthProxy finalized without being shutdown");
152f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            native_finalize(mJniData);
153f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            mJniData = 0;
154f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert        }
155f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    }
156f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
157d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final long native_setup(String nativeSoLib, String engineConfig);
158f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
159f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert    private native final int native_setLowShelf(boolean applyFilter, float filterGain,
160f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            float attenuationInDb, float freqInHz, float slope);
161f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
162d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final void native_finalize(long jniData);
163f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
164d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int native_stop(long jniData);
165f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
166d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int native_stopSync(long jniData);
167f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
168d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int native_speak(long jniData, String text, SynthesisCallback request);
169f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
170d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int  native_isLanguageAvailable(long jniData, String language,
171f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            String country, String variant);
172f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
173d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int native_setLanguage(long jniData, String language, String country,
174f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            String variant);
175f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
176d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int native_loadLanguage(long jniData, String language, String country,
177f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert            String variant);
178f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
179d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final int native_setProperty(long jniData, String name, String value);
180f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
181d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final String[] native_getLanguage(long jniData);
182f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
183d12fa9eb428db88f399a89566772eaed99b2fe58Marcus Oakland    private native final void native_shutdown(long jniData);
184f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert
185f41e1f808fbcf9014c0a5668fba4eff6dd051366Bjorn Bringert}
186