🍃

【Flutter】音声読み上げをやってみた【flutter_tts】

2024/12/04に公開

はじめに

こんにちは。
今回は、Flutterを使って、音声読み上げをやってみたいと思います。
なお、当方Windowsパソコン&Androidスマホユーザーのため、以下のスマホでしか動作確認できていませんのでご了承ください。

  • Galaxy S24

手順

1. ファイル作成

Android Studioを使っていつも通り、ファイルを作成します。
最初のサンプルコードを削除し、一旦以下のように書いておきます。
「デモアプリ」とだけ表示されるシンプルなアプリです。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text(
            'デモアプリ',
            style: TextStyle(fontSize: 24),
          ),
        ),
      ),
    );
  }
}

2. パッケージを入れる

  1. 以下のコマンドを入力
flutter pub add flutter_tts
  1. 以下のコマンドを入力するか、pub getをクリックする
flutter pub get

エラーが出たときの対処法

Building with plugins requires symlink support.

Please enable Developer Mode in your system settings. Run
start ms-settings:developers
to open settings.

設定の、「開発者モード」にチェックを入れればOKです。
設定画面の開発者モード
参考:dart - Flutter: Building with plugins requires symlink support - Stack Overflow

3. gradleなどのバージョンを書き換える

  1. android/app/build.gradleを以下のように書き換える
- minSdk = flutter.minSdkVersion
+ minSdk = 21
  1. android/build.gradleに以下を追記する
buildscript{
    ext.kotlin_version="1.9.20"
}
  1. android/settings.gradleを以下のように変更する。
-  id "org.jetbrains.kotlin.android" version "1.8.22" apply false
+  id "org.jetbrains.kotlin.android" version "1.9.20" apply false

参考:Flutter Text To Speech | Convert Text To speech in Flutter | Flutter Ttsの「Adding Flutter_Tts Package」の部分

4. コードを書く(とりあえず動かしてみる)

Create Your Own Text-to-Speech App in Flutter: Step-by-Step Tutorial - YouTubeを参考に、まず動かしてみようと思い、動画を見たまま、コードを書いていきました。
main.dart

import 'package:flutter/material.dart';

import 'home_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "Text To Speech",
      theme: ThemeData(
        primarySwatch: Colors.indigo,
      ),
      home: const HomeScreen(),
    );
  }
}

home_screen.dart

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

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

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final FlutterTts flutterTts = FlutterTts();
  final TextEditingController textController = TextEditingController();
  
  void dispose() {
    textController.dispose();
    super.dispose();
  }

  Future<void> speak(String text) async {
    await flutterTts.setLanguage('en-US');
    await flutterTts
        .setPitch(1.0); // you can set pitch from 0.5 to 2.0 , default is 1.0
    await flutterTts.setSpeechRate(
        0.5); // you can set speech rate from 0 (slowest) to 1 (fastest)
    await flutterTts.speak(text);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Text To Speech"),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextField(
              controller: textController,
              decoration: InputDecoration(
                hintText: "Enter Text",
                border: OutlineInputBorder(),
              ),
            ),
            SizedBox(
              height: 30,
            ),
            ElevatedButton(
                onPressed: () {
                  speak(textController.text);
                },
                child: Text("Speak"))
          ],
        ),
      ),
    );
  }
}

コードの引用:Create Your Own Text-to-Speech App in Flutter: Step-by-Step Tutorial - YouTube

5. アレンジする

  1. のアプリで実行できることがわかったので、以下のように変更を加えてみました。
  • 日本語も読み上げ可能にする
  • 日本語と、英語が切り替えられるようにする
  • 日本語と英語が切り替わったとき、アプリバーのタイトルやボタンの言語も変わるようにする
import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "Text To Speech",
      theme: ThemeData(
        primarySwatch: Colors.indigo,
      ),
      home: const HomeScreen(),
    );
  }
}

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

  
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final FlutterTts flutterTts = FlutterTts();
  final TextEditingController textController = TextEditingController();
  String selectedLanguage = 'en-US';

  
  void dispose() {
    textController.dispose();
    super.dispose();
  }

  Future<void> speak(String text) async {
    await flutterTts.setLanguage(selectedLanguage);
    await flutterTts.setPitch(1.0); // ピッチを設定(0.5から2.0の範囲)
    await flutterTts.setSpeechRate(0.5); // 読み上げ速度を設定(0から1の範囲)
    await flutterTts.speak(text);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(selectedLanguage == 'ja-JP' ? 'テキスト読み上げ' : 'Text To Speech'),
      ),
      body: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            DropdownButton<String>(
              value: selectedLanguage,
              onChanged: (String? newValue) {
                setState(() {
                  selectedLanguage = newValue!;
                });
              },
              items: <String>['en-US', 'ja-JP']
                  .map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value == 'en-US' ? 'English' : '日本語'),
                );
              }).toList(),
            ),
            TextField(
              controller: textController,
              decoration: InputDecoration(
                hintText: 'テキストを入力してください',
                border: OutlineInputBorder(),
              ),
            ),
            SizedBox(height: 30),
            ElevatedButton(
              onPressed: () {
                speak(textController.text);
              },
              child: Text(selectedLanguage == 'ja-JP' ? '話す' : 'Speak'),
            ),
          ],
        ),
      ),
    );
  }
}

作成したアプリ

MP4はZennでは掲載できなかったので、動作だけ、GIFです。

終わりに

今回はflutter_ttsを用いて、簡易的なテキスト読み上げアプリを作成することができました。
勉強にもなったので、引き続き、Flutterの勉強をしていこうと思います。

Discussion