sitelink1 https://blog.naver.com/cosmosjs/220963959630 
sitelink2  
sitelink3  

네이버가 제공하는 API중에 '음성합성'을 앱개발에 적용하여 간단한 예제를 만들어 보기로 하자. 이것은 간단히 말해서 텍스트를 음성으로 재생해 주는 것이다. 구글에도 있는 서비스로 네이버에서는 현재 한국어, 영어, 일본어, 중국어 4개국어를 제공하고 있고 하루 10,000글자로 처리한도가 정해져 있다. 그게 어느 정도인지는 감이 안오네... 

https://developers.naver.com/products/tts/

위 링크에서 이용신청을 해야 한다.

 

이미지_039.pngimage_6992693121490092442803.jpg

 

애플리케이션 등록으로 Client ID와 Clinet Secret를 확보했다. 이제 안드로이드 스튜디오에서 작업을 하자.

 

 

안드로이스 스튜디오

안드로이드 스튜디오에서 사전에 특별히 실치하거나 하는 것은 없는것 같다. 단지 POST방식으로 네이버 서버에 요청만 하면 텍스트를 음성으로 바꿔서 보내 주는 방식인듯 하다. 앱에서는 그 결과 데이터(음성)를 받아서 재생하도록 해주면 될것 같다.

 

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout 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.js.naverstt.MainActivity">

 

    <TextView

        android:id="@+id/tv_title"

        android:gravity="center"

        android:layout_marginTop="36dp"

        android:layout_marginBottom="50dp"

        android:textColor="@color/colorPrimaryDark"

        android:textSize="28dp"

        android:layout_centerHorizontal="true"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="Naver Text to Speech!"/>

 

    <EditText

        android:id="@+id/et_text"

        android:hint="텍스트를 입력하세요."

        android:layout_centerHorizontal="true"

        android:layout_below="@+id/tv_title"

        android:layout_width="300dp"

        android:layout_height="wrap_content" />

 

    <LinearLayout

        android:layout_below="@+id/et_text"

        android:gravity="center"

        android:layout_margin="16dp"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

 

        <Button

            android:id="@+id/bt_tts"

            android:text="미진씨 읽어줘!"

            android:layout_centerHorizontal="true"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" />

 

        <Button

            android:id="@+id/bt_reset"

            android:text="새로작성"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" />

 

    </LinearLayout>

 

</RelativeLayout>

 

레이아웃은 간단히 텍스트를 입력하는 뷰와 재생버튼등으로 구성했다. 버튼을 누르면 입력된 텍스트를 네이버 서버로 보내서 음성으로 변환 mp3파일을 폰으로 받아 온다. 그리고 즉시 재생을 한다.

 

 

네이버 API 클래스

 


// 네이버 음성합성 Open API 예제
//아주 아주 아주 중요!!!! 네트워크 접속을 사용시 AsyncTask(즉 쓰레드)를 사용해야 한다. 아 미쳐~

import android.media.MediaPlayer;
import android.os.Environment;
import android.util.Log;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

public class APIExamTTS {

    private static String TAG = "APIExamTTS";

    public static void main(String[] args) {
        String clientId = "유어클라이언트아이디";//애플리케이션 클라이언트 아이디값";
        String clientSecret = "유어시크릿";//애플리케이션 클라이언트 시크릿값";
        try {
            String text = URLEncoder.encode(args[0], "UTF-8"); // 13자
            String apiURL = "https://openapi.naver.com/v1/voice/tts.bin";
            URL url = new URL(apiURL);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("X-Naver-Client-Id", clientId);
            con.setRequestProperty("X-Naver-Client-Secret", clientSecret);
            // post request
            String postParams = "speaker=mijin&speed=0&text=" + text;
            con.setDoOutput(true);
            con.setDoInput(true);
            DataOutputStream wr = new DataOutputStream(con.getOutputStream());///여기서 에러 난다?
            Log.d(TAG, String.valueOf(wr));
            wr.writeBytes(postParams);
            wr.flush();
            wr.close();
            int responseCode = con.getResponseCode();
            BufferedReader br;
            if(responseCode==200) { // 정상 호출
                InputStream is = con.getInputStream();
                int read = 0;
                byte[] bytes = new byte[1024];
                //폴더를 만들어 줘야 겠다. 없으면 새로 생성하도록 해야 한다. 일단 Naver폴더에 저장하도록 하자.
                File dir = new File(Environment.getExternalStorageDirectory()+"/", "Naver");
                if(!dir.exists()){
                    dir.mkdirs();
                }
                // 랜덤한 이름으로 mp3 파일 생성
                //String tempname = Long.valueOf(new Date().getTime()).toString();
                String tempname = "naverttstemp"; //하나의 파일명으로 덮어쓰기 하자.
                File f = new File(Environment.getExternalStorageDirectory() + File.separator + "Naver/" + tempname + ".mp3");
                f.createNewFile();
                OutputStream outputStream = new FileOutputStream(f);
                while ((read =is.read(bytes)) != -1) {
                    outputStream.write(bytes, 0, read);
                }
                is.close();

                //여기서 바로 재생하도록 하자. mp3파일 재생 어떻게 하지? 구글링!
                String Path_to_file = Environment.getExternalStorageDirectory()+File.separator+"Naver/"+tempname+".mp3";
                MediaPlayer audioPlay = new MediaPlayer();
                audioPlay.setDataSource(Path_to_file);
                audioPlay.prepare();//이걸 해줘야 하는군. 없으면 에러난다.
                audioPlay.start();
                //재생하고 나서 파일을 지워줘야 하나? 이거참 고민이네... if문으로 분기 시켜야 하나?
                //아니면 유니크한 파일로 만들지 말고 하나의 파일명으로 저장하게 할수도 있을듯...



            } else {  // 에러 발생
                br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
                String inputLine;
                StringBuffer response = new StringBuffer();
                while ((inputLine = br.readLine()) != null) {
                    response.append(inputLine);
                }
                br.close();
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

 

네이버 API예제에 몇군데 추가하거나 수정했다. http통신하는 분은 뭐 손댈게 없다. 어려워서 뭔지 잘 모르기도 하고 ... 흐름만 파악하면 될것 같다. 처음엔 뭔가 에러가 나고 작동이 안되었다. 몇시간 골머리를 않다가 알게 된게 네트워크 접속을 하려는 경우 쓰레드를 사용해야 한다고 한다. 요즘은 AsyncTask를 사용해야 한다고 한다. 이런... 저번에도 이것 때문에 당하고도 그새 까먹고 헤메고 있었다. 

 

 

메인액티비티

마지막으로 메인액티비티에서 AsyncTask를 작성해 보자.

 


public class MainActivity extends AppCompatActivity {

    private NaverTTSTask mNaverTTSTask;
    String[] mTextString;
    EditText etText;
    Button btTTS, btReset;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etText = (EditText) findViewById(R.id.et_text);
        btTTS = (Button) findViewById(R.id.bt_tts);
        btReset = (Button) findViewById(R.id.bt_reset);

        //버튼 클릭이벤트 - 클릭하면 에디터뷰에 있는 글자를 가져와서 네이버에 보낸다. MP3로 바꿔 달라고 ...
        btTTS.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //사용자가 입력한 텍스트를 이 배열변수에 담는다.
                String mText;
                if (etText.getText().length() > 0) { //한글자 이상 1
                    mText = etText.getText().toString();
                    mTextString = new String[]{mText};

                    //AsyncTask 실행
                    mNaverTTSTask = new NaverTTSTask();
                    mNaverTTSTask.execute(mTextString);
                } else {
                    Toast.makeText(MainActivity.this, "텍스트를 입력하세요.", Toast.LENGTH_SHORT).show();
                    return;
                }
            }
        });

        //리셋버튼
        btReset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                etText.setText("");
                etText.setHint("텍스트를 입력하세요.");
            }
        });
    }

    
    private class NaverTTSTask extends AsyncTask{

        @Override
        protected String doInBackground(String[]... strings) {
            //여기서 서버에 요청
            APIExamTTS.main(mTextString);
            return null;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            //방금 받은 파일명의 mp3가 있으면 플레이 시키자. 맞나 여기서 하는거?
            //아닌가 파일을 만들고 바로 실행되게 해야 하나? AsyncTask 백그라운드 작업중에...?

        }
    }
}

   

Screenshot_2017-03-22-00-12-05.png  Screenshot_2017-03-22-00-41-40.png

 

 

서버로 요청을 보내면 음성으로 변환해서 결과를 보내주는데 mp3 파일이다. 지정된 디렉토리에 파일이 저장되는것을 확인 할 수 있다. 이 예제에서는 하나의 파일을 덮어쓰도록 수정했다. 파일을 저장하고 싶다면 설정을 만들어서 선택하게 해주면 될것 같다.

 

 

 

잘된다. 구글 TTS보다 부드럽게 잘한다. 실제 성우의 목소리를 사용했다는 건가? 만족스럽다. 쓸일이 있으면 네이버 TTS를 사용하도록 하자. 여러가지 설정을 더해 주면 좀 더 다양한 기능의 앱을 만들 수 있을것 같다. 

다음에는 '음성인식' API도 알아 보기로 하자.

매니페스트 파일에 인터넷과 스토리지 읽기, 쓰기 퍼미션을 주는것도 잊지 말자!

번호 제목 글쓴이 날짜 조회 수
68 TTS 를 위한 스마트폰 설정 및 TTS 샘플 file 황제낙엽 2019.02.16 460
67 Creating swipe views with tabs file 황제낙엽 2019.02.10 102
66 [번역] 안드로이드 ViewPager 를 이용한 수평 화면 전환 file 황제낙엽 2019.02.09 71
65 동적 레이아웃 생성과 자동 줄바꿈 구현 file 황제낙엽 2018.12.26 311
64 qemu-system-~.exe 의 작동이 중지되었습니다 file 황제낙엽 2018.11.27 55
63 Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'. file 황제낙엽 2018.11.27 59
62 Error:Minimum supported Gradle version is 4.1. 황제낙엽 2018.11.27 84
61 No toolchains found in the NDK toolchains folder for ABI 황제낙엽 2018.11.27 33
60 [성공샘플] HttpURLConnection 을 이용하여 JSON 데이터 보내기 예제 황제낙엽 2018.11.10 649
» [Android] 네이버 음성합성(TTS) API 사용해 보기 file 황제낙엽 2018.11.01 167
58 [Android] TTS (Text To Speech) API 샘플 코드 file 황제낙엽 2018.11.01 128
57 Google Cloud API 설정법 file 황제낙엽 2018.11.01 39
56 AsyncTask 사용하기 황제낙엽 2018.10.29 36
55 Volley 소개 및 관련 링크 황제낙엽 2018.10.29 63
54 AsyncTask 를 이용한 HttpURLConnection 사용법 [1] 황제낙엽 2018.10.20 33
53 HttpURLConnection 을 이용하여 JSON 데이터 보내기 예제 [1] file 황제낙엽 2018.10.20 102
52 STT 학습 링크 모음 (sample link) 황제낙엽 2018.10.11 552
51 코틀린(Kotlin) 학습용 링크 모음 황제낙엽 2018.10.11 64
50 저장소 파일 불러올 때 권한 요청 설정 file 황제낙엽 2018.08.21 55
49 안드로이드 파일시스템에 파일 생성하여 데이터 저장, 불러오기 예제 황제낙엽 2018.08.21 58