├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sdsb8432 │ │ └── texttospeech │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── sdsb8432 │ │ │ └── texttospeech │ │ │ ├── MainActivity.java │ │ │ └── TTS.java │ └── res │ │ ├── drawable │ │ └── bg_edit_text.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── sdsb8432 │ └── texttospeech │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenShots └── capture01.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Text To Speech with Google for Android 2 | 3 | 구글이 제공하는 TextToSpeech Class를 활용해 텍스트를 음성으로 변환하는 프로젝트이다. 4 | 5 | 6 | ## 1. 사용법 7 | 8 | ### 1. 클래스 선언 9 | 10 | 제일 기본이 되는 `TextToSpeech(Context context, TextToSpeech.OnInitListener listener)` 생성자이다. TTS engine을 설정할 수있는 생성자가 있으나 생략하기로 한다. 11 | 12 | initListener의 경우는 아래에서 설명할 것이다. 13 | 14 | ``` 15 | private TextToSpeech textToSpeech; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | textToSpeech = new TextToSpeech(this, initListener); 20 | } 21 | ``` 22 | 23 | ### 2. interface, abstract 클래스 선언 24 | 25 | ``` 26 | //음성 재생 상태에 대한 callback을 받을 수 있는 추상 클래스 27 | private UtteranceProgressListener progressListener = new UtteranceProgressListener() { 28 | @Override 29 | public void onStart(String utteranceId) { // 음성이 재생되었을 때 30 | 31 | } 32 | 33 | @Override 34 | public void onDone(String utteranceId) { // 제공된 텍스트를 모두 음성으로 재생한 경우 35 | 36 | } 37 | 38 | @Override 39 | public void onError(String utteranceId) { // ERROR! 40 | 41 | } 42 | }; 43 | 44 | textToSpeech.setOnUtteranceProgressListener(progressListener); 45 | 46 | ``` 47 | 48 | 아래 `setLanguage()` 메소드는 음성 언어를 설정할 수 있다. Locale.ENGLISH, Locale.CANADA 등 상황에 맞춰 필요한 음성을 선택해 사용하면 된다. 49 | 50 | 51 | ``` 52 | //음성 관련 초기화 상태에 대한 callback을 받을 수 있는 인터페이스 53 | private TextToSpeech.OnInitListener initListener = new TextToSpeech.OnInitListener() { 54 | @Override 55 | public void onInit(int status) { 56 | if(status != TextToSpeech.ERROR) 57 | textToSpeech.setLanguage(Locale.KOREAN); // 한글로 설정 58 | } 59 | }; 60 | ``` 61 | 62 | ### 3. start & stop & shutdown 63 | 64 | #### 1. start 65 | 66 | 67 | 설명하기 앞서 'utteranceID'는 단어 그대로 현재 재생중인 음성에 대한 ID값을 나타낸다. 68 | 여러 개의 음성을 컨트롤할 때 유용하게 사용될 것 같다. 69 | 70 | 기존의 `speak(String text, int queueMode, HashMap params)` 메소드는 API Level 21부터 deprecated 되었다. 그러니 API level에 맞춰 21 이상은 아래와 같이 가급적 새로운 `speak(CharSequence text, int queueMode, Bundle params, String utteranceId)`메소드를 사용하도록 하자. 71 | 72 | ``` 73 | String text = editText.getText.toString(); 74 | 75 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 76 | String myUtteranceID = "myUtteranceID"; 77 | textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, myUtteranceID); 78 | } 79 | else { 80 | HashMap hashMap = new HashMap<>(); 81 | hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "myUtteranceID"); 82 | textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, hashMap); 83 | } 84 | ``` 85 | 86 | #### 2. stop 87 | 88 | 89 | 현재 재생중인 음성에 대한 정지는 간단하게 `textToSpeech.stop()`와 같은 메소드를 사용하면 된다. 90 | 91 | #### 3. shutdown 92 | 93 | Speech Engine을 통해 초기화된 TextToSpeech 인스턴트는 꼭 `textToSpeech.shutDown()`을 통해 완전히 종료시켜 주어야 한다. 아니면 SeviceConnection...어쩌구저쩌구하는 Exception이 발생된다. 94 | 95 | ex. 아래와 같이 Activity일 경우 생명주기에 맞춰 `shutDown()`을 호출 할 수 있다. 96 | 97 | ``` 98 | @Override 99 | protected void onDestroy() { 100 | if(textToSpeech != null) 101 | textToSpeech.shutDown(); 102 | super.onDestroy(); 103 | } 104 | ``` 105 | 106 | ## 2. 프로젝트 107 | 108 | 해당 프로젝트는 TTS Class를 생성하여 조금 더 사용하기 편하도록 만들어두었다. 109 | 이 후 목소리와 재생 속도에 관련된 부분을 프로젝트에 추가할 예정이다. 110 | 111 | 112 | ## 3. 스크린샷 113 | 114 | 115 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | dataBinding { 7 | enabled = true 8 | } 9 | defaultConfig { 10 | applicationId "com.sdsb8432.texttospeech" 11 | minSdkVersion 16 12 | targetSdkVersion 25 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:25.2.0' 31 | testCompile 'junit:junit:4.12' 32 | } 33 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/sonseongbin/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/sdsb8432/texttospeech/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.sdsb8432.texttospeech; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.sdsb8432.texttospeech", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/sdsb8432/texttospeech/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.sdsb8432.texttospeech; 2 | 3 | import android.databinding.DataBindingUtil; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.sdsb8432.texttospeech.databinding.ActivityMainBinding; 9 | 10 | import java.util.Locale; 11 | 12 | public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 13 | 14 | private ActivityMainBinding mainBinding; 15 | 16 | 17 | 18 | private TTS tts; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | mainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); 24 | 25 | tts = new TTS(this, Locale.KOREAN); 26 | 27 | mainBinding.buttonTextToSpeech.setOnClickListener(this); 28 | } 29 | 30 | @Override 31 | public void onClick(View v) { 32 | tts.speak(mainBinding.editText.getText().toString()); 33 | } 34 | 35 | @Override 36 | protected void onDestroy() { 37 | 38 | if(tts != null && tts.isSpeaking()) { 39 | tts.stop(); 40 | } 41 | 42 | if(tts != null) { 43 | tts.shutdown(); 44 | } 45 | 46 | tts = null; 47 | 48 | super.onDestroy(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/sdsb8432/texttospeech/TTS.java: -------------------------------------------------------------------------------- 1 | package com.sdsb8432.texttospeech; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.speech.tts.TextToSpeech; 6 | import android.speech.tts.UtteranceProgressListener; 7 | import android.util.Log; 8 | 9 | import java.util.HashMap; 10 | import java.util.Locale; 11 | 12 | /** 13 | * Created by sonseongbin on 2017. 3. 19.. 14 | */ 15 | 16 | public class TTS extends UtteranceProgressListener implements TextToSpeech.OnInitListener{ 17 | 18 | private final String TAG = TTS.class.getSimpleName(); 19 | 20 | private TextToSpeech textToSpeech; 21 | private Locale locale; 22 | 23 | public TTS(Context context, Locale locale) { 24 | this.locale = locale; 25 | textToSpeech = new TextToSpeech(context, this); 26 | textToSpeech.setOnUtteranceProgressListener(this); 27 | } 28 | 29 | 30 | public void speak(String text) { 31 | if(textToSpeech != null) { 32 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 33 | String myUtteranceID = "myUtteranceID"; 34 | textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null, myUtteranceID); 35 | } 36 | else { 37 | HashMap hashMap = new HashMap<>(); 38 | hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "myUtteranceID"); 39 | textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, hashMap); 40 | } 41 | } 42 | } 43 | 44 | public void stop() { 45 | textToSpeech.stop(); 46 | } 47 | 48 | public void shutdown() { 49 | textToSpeech.shutdown(); 50 | } 51 | 52 | public boolean isSpeaking() { 53 | return textToSpeech.isSpeaking(); 54 | } 55 | 56 | @Override 57 | public void onStart(String utteranceId) { 58 | Log.d(TAG, "onStart / utteranceID = " + utteranceId); 59 | } 60 | 61 | @Override 62 | public void onDone(String utteranceId) { 63 | Log.d(TAG, "onDone / utteranceID = " + utteranceId); 64 | } 65 | 66 | @Override 67 | public void onError(String utteranceId) { 68 | Log.d(TAG, "onError / utteranceID = " + utteranceId); 69 | } 70 | 71 | @Override 72 | public void onInit(int status) { 73 | if(status != TextToSpeech.ERROR) 74 | textToSpeech.setLanguage(locale); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_edit_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | 26 | 27 | 33 | 34 |