Flutter で VIVANT のドラムが使用するアプリを再現してみた(解説編)

Flutter

Flutter で VIVANT のドラムが使用するアプリを再現してみた(作成編)で作成したソースコードを解説していきます!

作成編は、以下ご参照ください!

ソースコード

おさらいですが、作成したソースコードは以下になります。

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});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Doramu',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const ReadOutPage(),
    );
  }
}

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

  @override
  State<ReadOutPage> createState() => _ReadOutPageState();
}

class _ReadOutPageState extends State<ReadOutPage> {
  late FlutterTts tts;
  String text = "";
  final TextEditingController controller = TextEditingController();

  final serifMap = {
    // 1話
    "ドラムです" : "私はドラムです。よろしくね。",
    "了解" : "了解したよ。野崎さん。",
    "案内" : "皆さん、このおじさんが案内してくれますから。",
    "10万ドル" : "でも本当にやばい。100,000ドルっていうのは。",
    "みんな警察" : "そういうこと。みんな、血眼になって探すよ。全員、警察と思ったほうがいいよ。",
    "チンギス" : "チンギス、バルカ警察で一番優秀ね。",
    "クーダン" : "クーダンは電車ないよ。公共交通機関はバスだけ。だから、車だらけ。世界で、有名な、渋滞天国ね。クーダンに入ってから、車で大使館に行くのは、超危険、超危険。",
    "これでいい?" : "これでよろしいですか?野崎さん。",
    // 2話
    "ガラすき" : "今、正門、ガラすきよ。チャンス、チャンス。",
    // 4話
    "日本来た" : "乃木さん、約束通り、ニッポンに来ました。また会えてめっちゃ嬉しい、めっちゃ嬉しい。これからもよろしくね。",
    // 5話
    "どうかした?" : "どうかしました?野崎さん",
  };

  @override
  initState() {
    super.initState();
    initTts();
  }

  initTts() {
    tts = FlutterTts();
    tts.setLanguage('ja-JP');
    tts.setPitch(1.0);
    tts.setSpeechRate(0.55);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Doramu App'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(0.0),
              child: TextFormField(
                controller: controller,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: "文章を指定する場合はここに入力",
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 0.0),
              child: SizedBox(
                width: double.infinity,
                height: 50,
                child: ElevatedButton(
                    onPressed: () {
                      tts.speak(controller.text);
                    },
                    child: const Text("発話")),
              ),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 16.0),
              child: Container(
                width: double.infinity,
                height: 1,
                color: Colors.grey,
              ),
            ),
            Expanded(
              child: GridView.builder(
                itemCount: serifMap.keys.toList().length,
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisSpacing: 16,
                  mainAxisSpacing: 16,
                  crossAxisCount: 2,
                  childAspectRatio: 3 / 1,
                ),
                itemBuilder: (context, index) {
                  return SizedBox(
                    height: 50,
                    child: ElevatedButton(
                      onPressed: () {
                        tts.speak(serifMap[serifMap.keys.toList()[index]]!);
                      },
                      child: Text(serifMap.keys.toList()[index]),
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}
ドラム風アプリの実行画面

解説

音声の設定

60行目〜の部分で、発話音声に関する設定を行っています。
setLanguage で言語を日本語に設定し、setPitch で音声のピッチ、setSpeechRate で発話速度を設定しています。
音声を変更したい場合、ここで設定を変更します。

  initTts() {
    tts = FlutterTts();
    tts.setLanguage('ja-JP');
    tts.setPitch(1.0);
    tts.setSpeechRate(0.55);
  }

他の設定も行いたい場合は、flutter_tts パッケージのサイトをご参照ください。

入力した文章を発話する部分

78行目〜の部分で、文章の入力を受け付けるフォームと、入力された文章を発話するボタンの設定を行っています。
80行目の TextFormField が文章入力フォーム、93行目の ElevatedButton が押下時に入力された文章発話する設定をしたボタンです。

            Padding(
              padding: const EdgeInsets.all(0.0),
              child: TextFormField(
                controller: controller,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                  labelText: "文章を指定する場合はここに入力",
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 0.0),
              child: SizedBox(
                width: double.infinity,
                height: 50,
                child: ElevatedButton(
                    onPressed: () {
                      tts.speak(controller.text);
                    },
                    child: const Text("発話")),
              ),
            ),

固定セリフの一覧

36行目〜の部分では、VIVANT のドラムのセリフを serifMap に定義しています。
serifMapは、ボタン名とセリフの組み合わせになっています。
固定セリフを追加したい場合は、この serifMap に “ボタン名” : “セリフ” の形で追加してください。

  final serifMap = {
    // 1話
    "ドラムです" : "私はドラムです。よろしくね。",
    "了解" : "了解したよ。野崎さん。",
    "案内" : "皆さん、このおじさんが案内してくれますから。",
    "10万ドル" : "でも本当にやばい。100,000ドルっていうのは。",
    "みんな警察" : "そういうこと。みんな、血眼になって探すよ。全員、警察と思ったほうがいいよ。",
    "チンギス" : "チンギス、バルカ警察で一番優秀ね。",
    "クーダン" : "クーダンは電車ないよ。公共交通機関はバスだけ。だから、車だらけ。世界で、有名な、渋滞天国ね。クーダンに入ってから、車で大使館に行くのは、超危険、超危険。",
    "これでいい?" : "これでよろしいですか?野崎さん。",
    // 2話
    "ガラすき" : "今、正門、ガラすきよ。チャンス、チャンス。",
    // 4話
    "日本来た" : "乃木さん、約束通り、ニッポンに来ました。また会えてめっちゃ嬉しい、めっちゃ嬉しい。これからもよろしくね。",
    // 5話
    "どうかした?" : "どうかしました?野崎さん",
  };

固定セリフの発話ボタン表示部

固定セリフを発話するボタンは、108行目〜の部分で作成しています。
serifMap に追加されている分だけ、ボタンを生成するようにしています。そのため、この部分に関しては、固定セリフを追加しても、特に変更する必要はありません。

            Expanded(
              child: GridView.builder(
                itemCount: serifMap.keys.toList().length,
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisSpacing: 16,
                  mainAxisSpacing: 16,
                  crossAxisCount: 2,
                  childAspectRatio: 3 / 1,
                ),
                itemBuilder: (context, index) {
                  return SizedBox(
                    height: 50,
                    child: ElevatedButton(
                      onPressed: () {
                        tts.speak(serifMap[serifMap.keys.toList()[index]]!);
                      },
                      child: Text(serifMap.keys.toList()[index]),
                    ),
                  );
                },
              ),
            ),

まとめ

Flutter で VIVANT のドラムが使用するアプリを再現してみた(作成編)で作成したソースコードを解説しました!
アプリの構成について興味のあった方の理解の
アプリを自分の好きなように修正する際のポイントを以下にまとめます。

  • 60行目〜:音声の設定
    flutter_tts パッケージで設定できる項目が設定可能。
    例)音声のピッチ、速度 など
  • 36行目〜:固定セリフの追加
    固定セリフの追加は、serifMap に “ボタン名” : “セリフ” の形で追加。
    ボタンの生成に関しては、変更の必要なし。

おすすめ書籍

 

コメント

タイトルとURLをコピーしました