Flutter - TTS로 글자 읽어주는 기능 구현하기 (flutter_tts)

반응형

 

TTS (Text To Speach)

  • 한국어로는 음성합성'이라고 칭한다.
  • 컴퓨터의 프로그램을 통해 사람의 목소리를 구현해 내는 것을 말한다.
  • 말 그대로 컴퓨터가 특정 글자들을 읽어주는 것을 말한다.

 
포스팅에서 설명하는 프로젝트는 아래의 링크에서 다운받을 수 있습니다.


TTS Package Setting (설치 및 설정)

TTS 패키지 설치

텍스트를 읽어주기 위해서는 우선 필요한 패키지를 설치를 해야한다.

flutter pub add flutter_tts

안드로이드 설정

  • android - app - build.gradle
  • 해당 경로의 파일을 열어 defaultConfig의 minSdkVersion을 21로 변경한다.
minSdkVersion 21

 

  • android - app - src - main - AndroidManifest.xml
  • 해당 경로의 파일을 열어 <manifest> 하위 트리에 아래와 같이 내용 추가한다.
<queries>
  <intent>
    <action android:name="android.intent.action.TTS_SERVICE" />
  </intent>
</queries>

iOS 설정

  • 초기 설정은 따로 존재 하지 않는다.
  • 단, iOS 전용 코드 설정이 존재하므로 필요에 따라 설정해주자.
    • 공유 오디오 인스턴스 설정
    • 백그라운드 음악과 앱 내 오디오 세션 동시 사용 설정
// tts 인스턴스 생성
FlutterTts flutterTts = FlutterTts();

// iOS 전용 옵션 : 공유 오디오 인스턴스 설정
await flutterTts.setSharedInstance(true);

// 배경 음악와 인앱 오디오 세션을 동시에 사용
await flutterTts.setIosAudioCategory(
    IosTextToSpeechAudioCategory.ambient,
    [
      IosTextToSpeechAudioCategoryOptions.allowBluetooth,
      IosTextToSpeechAudioCategoryOptions.allowBluetoothA2DP,
      IosTextToSpeechAudioCategoryOptions.mixWithOthers
    ],
    IosTextToSpeechAudioMode.voicePrompt);

TTS 초기 설정

tts 인스턴스 생성 (FlutterTts)

  • tts 인스턴스 객체 생성하는 코드이다.
FlutterTts flutterTts = FlutterTts();

언어 설정 (setLanguage)

  • 설정한 언어로 tts가 글자를 읽어준다.
  • 지원되는 언어는 getLanguage를 통해서 확인 가능하다.
/* 언어 설정
    한국어    =   "ko-KR"
    일본어    =   "ja-JP"
    영어      =   "en-US"
    중국어    =   "zh-CN"
    프랑스어  =   "fr-FR"
*/ 
flutterTts.setLanguage("ko-KR");

지원되는 언어 확인하기 (getLanguages)

flutterTts.getLanguages;

/* print */
// [ko-KR, mr-IN, ru-RU, zh-TW, hu-HU, th-TH, ur-PK,
// nb-NO, da-DK, tr-TR, et-EE, bs, sw, pt-PT, vi-VN,
// en-US,sv-SE, ar, su-ID, bn-BD, gu-IN, kn-IN, el-GR,
// hi-IN, fi-FI, km-KH, bn-IN, fr-FR, uk-UA, pa-IN, en-AU,
// lv-LV, nl-NL, fr-CA, sr, pt-BR, ml-IN, si-LK, de-DE, ku,
// cs-CZ, pl-PL, sk-SK, fil-PH, it-IT, ne-NP, ms-MY, hr,
// en-NG, nl-BE, zh-CN, es-ES, cy, ta-IN, ja-JP, bg-BG,
// sq, yue-HK, en-IN, es-US, jv-ID, la, id-ID, te-IN,
// ro-RO, ca, en-GB]

음성 선택하기 (setVoice)

  • tts가 읽어주는 음성을 선택할 수 있다.
  • 남성과 여성의 목소리로 각 나라별 음성을 설정할 수 있다.
  • 관련된 정보를 찾다가 도저히 못 찾겠어서 타 사이트의 제공된 문서를 통해 확인하였다.
/* 음성 설정
	영어 여성 {"name": "en-us-x-tpf-local", "locale": "en-US"}
    일본어 여성 {"name": "ja-JP-language", "locale": "ja-JP"}
    중국어 여성 {"name": "cmn-cn-x-ccc-local", "locale": "zh-CN"}
    중국어 남성 {"name": "cmn-cn-x-ccd-local", "locale": "zh-CN"}
*/

// 한국어 여성 음성으로 설정
flutterTts.setVoice({"name": "ko-kr-x-ism-local", "locale": "ko-KR"});

지원되는 음성 확인하기 (getVoice)

'name'과 'locale'로 구성된 지원되는 음성 값을 확인할 수 있다.
음성이 너무 많아 확인이 어려울 경우, 문자열이 포함되어 있는지 확인하는 contains 메서드를 활용하여 찾아보자.

flutterTts.getVoices;

/* 한국어 음성 찾기
List<Object?> objVoices = await flutterTts.getVoices;
    List<String> ttsVoices = [];
    for (var item in objVoices) {
      if (item.toString().contains('ko-KR')) {
        ttsVoices.add(item.toString());
      }
}
*/

음성의 음높이 설정 (setPitch)

  • tts가 읽어주는 음성의 음높이를 의미한다.
  • 기본값은 1.0이며, 0.5와 2.0 사이의 값으로 조절한다.
flutterTts.setPitch(1.0);

음성의 속도 설정 (setSpeechRate)

  • tts가 글자를 읽어주는 속도를 의미한다.
  • 값은 0.0에 가까울수록 느려지며, 1.0에 가까울수록 빠르게 말한다.
flutterTts.setSpeechRate(0.5);

음성 볼륨 설정 (setVolume)

  • tts가 읽어주는 볼륨을 설정한다.
  • 값은 0.0에 가까울수록 조용하며, 1.0에 가까울수록 소리가 커진다.
flutterTts.setVolume(0.8);

TTS로 읽어주기 (speak)

TTS를 통해 해당 문자열을 읽어주는 것은 생각보다 간단하다.
.speak의 메서드에 읽을 문자열을 넣어주면 된다.

flutterTts.speak(text);

구현

텍스트필드에 내용을 입력하고 버튼을 누르면,
입력한 내용을 TTS로 읽어주는 간단한 기능을 구현해보자.
 

초기 변수 설정

  FlutterTts flutterTts = FlutterTts();
  /* 언어 설정
    한국어    =   "ko-KR"
    일본어    =   "ja-JP"
    영어      =   "en-US"
    중국어    =   "zh-CN"
    프랑스어  =   "fr-FR"
  */
  String language = "ko-KR";

  /* 음성 설정
    한국어 여성 {"name": "ko-kr-x-ism-local", "locale": "ko-KR"}
	  영어 여성 {"name": "en-us-x-tpf-local", "locale": "en-US"}
    일본어 여성 {"name": "ja-JP-language", "locale": "ja-JP"}
    중국어 여성 {"name": "cmn-cn-x-ccc-local", "locale": "zh-CN"}
    중국어 남성 {"name": "cmn-cn-x-ccd-local", "locale": "zh-CN"}
*/
  Map<String, String> voice = {"name": "ko-kr-x-ism-local", "locale": "ko-KR"};
  String engine = "com.google.android.tts";
  double volume = 0.8;
  double pitch = 1.0;
  double rate = 0.5;

  // 사용자의 입력 값을 받을 컨트롤러
  final TextEditingController textEditingController = TextEditingController();

초기화

  @override
  void initState() {
    super.initState();

    // TTS 초기 설정
    initTts();
  }

  // TTS 초기 설정
  initTts() async {
    await initTtsIosOnly(); // iOS 설정

    flutterTts.setLanguage(language);
    flutterTts.setVoice(voice);
    flutterTts.setEngine(engine);
    flutterTts.setVolume(volume);
    flutterTts.setPitch(pitch);
    flutterTts.setSpeechRate(rate);
  }

  // TTS iOS 옵션
  Future<void> initTtsIosOnly() async {
    // iOS 전용 옵션 : 공유 오디오 인스턴스 설정
    await flutterTts.setSharedInstance(true);

    // 배경 음악와 인앱 오디오 세션을 동시에 사용
    await flutterTts.setIosAudioCategory(
        IosTextToSpeechAudioCategory.ambient,
        [
          IosTextToSpeechAudioCategoryOptions.allowBluetooth,
          IosTextToSpeechAudioCategoryOptions.allowBluetoothA2DP,
          IosTextToSpeechAudioCategoryOptions.mixWithOthers
        ],
        IosTextToSpeechAudioMode.voicePrompt);
  }

TTS로 읽기

  // TTS로 읽어주기
  Future _speak(voiceText) async {
    flutterTts.speak(voiceText);
  }

UI 디자인 및 버튼 클릭 이벤트 기능 구현

  • 버튼을 누를 경우, TTS로 읽어주는 함수를 호출하여 입력한 내용을 TTS가 읽어주기
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          TextField(
            controller: textEditingController,
          ),
          ElevatedButton(
              onPressed: () {
                _speak(textEditingController.text);
              },
              child: const Text('내용 읽기')),
        ],
      ),
    );
  }

 

&lt;UI 디자인 화면&gt;

전체 소스 코드

import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';

void main() {
  runApp(const MaterialApp(
    home: Scaffold(
      body: SafeArea(child: MyTts()),
    ),
  ));
}

class MyTts extends StatefulWidget {
  const MyTts({super.key});

  @override
  State<MyTts> createState() => _MyTtsState();
}

class _MyTtsState extends State<MyTts> {
  FlutterTts flutterTts = FlutterTts();
  /* 언어 설정
    한국어    =   "ko-KR"
    일본어    =   "ja-JP"
    영어      =   "en-US"
    중국어    =   "zh-CN"
    프랑스어  =   "fr-FR"
  */
  String language = "ko-KR";

  /* 음성 설정
    한국어 여성 {"name": "ko-kr-x-ism-local", "locale": "ko-KR"}
	  영어 여성 {"name": "en-us-x-tpf-local", "locale": "en-US"}
    일본어 여성 {"name": "ja-JP-language", "locale": "ja-JP"}
    중국어 여성 {"name": "cmn-cn-x-ccc-local", "locale": "zh-CN"}
    중국어 남성 {"name": "cmn-cn-x-ccd-local", "locale": "zh-CN"}
*/
  Map<String, String> voice = {"name": "ko-kr-x-ism-local", "locale": "ko-KR"};
  String engine = "com.google.android.tts";
  double volume = 0.8;
  double pitch = 1.0;
  double rate = 0.5;

  // 사용자의 입력 값을 받을 컨트롤러
  final TextEditingController textEditingController = TextEditingController();

  @override
  void initState() {
    super.initState();

    // TTS 초기 설정
    initTts();
  }

  // TTS 초기 설정
  initTts() async {
    await initTtsIosOnly(); // iOS 설정

    flutterTts.setLanguage(language);
    flutterTts.setVoice(voice);
    flutterTts.setEngine(engine);
    flutterTts.setVolume(volume);
    flutterTts.setPitch(pitch);
    flutterTts.setSpeechRate(rate);
  }

  // TTS iOS 옵션
  Future<void> initTtsIosOnly() async {
    // iOS 전용 옵션 : 공유 오디오 인스턴스 설정
    await flutterTts.setSharedInstance(true);

    // 배경 음악와 인앱 오디오 세션을 동시에 사용
    await flutterTts.setIosAudioCategory(
        IosTextToSpeechAudioCategory.ambient,
        [
          IosTextToSpeechAudioCategoryOptions.allowBluetooth,
          IosTextToSpeechAudioCategoryOptions.allowBluetoothA2DP,
          IosTextToSpeechAudioCategoryOptions.mixWithOthers
        ],
        IosTextToSpeechAudioMode.voicePrompt);
  }

  // TTS로 읽어주기
  Future _speak(voiceText) async {
    flutterTts.speak(voiceText);
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          TextField(
            controller: textEditingController,
          ),
          ElevatedButton(
              onPressed: () {
                _speak(textEditingController.text);
              },
              child: const Text('내용 읽기')),
        ],
      ),
    );
  }
}

참고

반응형