Flutter - 下劃線或繪製文字到語音(TTS) (Flutter - underline or paint words text to speech (TTS))


問題描述

Flutter ‑ 下劃線或繪製文字到語音(TTS) (Flutter ‑ underline or paint words text to speech (TTS))

我有一個將文本轉換為語音的顫振程序,但我有一個問題,如何強調它所說的內容?也就是說的每一個字都有下劃線或者畫,希望有人能幫幫我,非常感謝。


參考解法

方法 1:

I presume you're getting a progress callback during the TTS that has begin and end values. Just break the text into three parts (part before begin, part between begin and end, and part after end), and assign them into three TextSpan with the appropriate annotation.

方法 2:

This discussion should assist you: https://github.com/dlutton/flutter_tts/discussions/193 Below is the code from the gist provided in that discussion:

import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

enum TtsState { playing, stopped, paused, continued }

class _MyAppState extends State<MyApp> {
  late FlutterTts flutterTts;
  dynamic languages;
  String? language;
  double volume = 0.5;
  double pitch = 1.0;
  double rate = 0.5;
  bool isCurrentLanguageInstalled = false;
  int start = 0;
  int end = 0;

  String? _newVoiceText;

  TtsState ttsState = TtsState.stopped;

  get isPlaying => ttsState == TtsState.playing;
  get isStopped => ttsState == TtsState.stopped;
  get isPaused => ttsState == TtsState.paused;
  get isContinued => ttsState == TtsState.continued;

  bool get isIOS => !kIsWeb && Platform.isIOS;
  bool get isAndroid => !kIsWeb && Platform.isAndroid;
  bool get isWeb => kIsWeb;

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

  initTts() {
    flutterTts = FlutterTts();

    _getLanguages();

    if (isAndroid) {
      _getEngines();
    }

    flutterTts.setStartHandler(() {
      setState(() {
        print("Playing");
        ttsState = TtsState.playing;
      });
    });

    flutterTts.setCompletionHandler(() {
      setState(() {
        print("Complete");
        ttsState = TtsState.stopped;
      });
    });

    flutterTts.setCancelHandler(() {
      setState(() {
        print("Cancel");
        ttsState = TtsState.stopped;
      });
    });

    if (isWeb || isIOS) {
      flutterTts.setPauseHandler(() {
        setState(() {
          print("Paused");
          ttsState = TtsState.paused;
        });
      });

      flutterTts.setContinueHandler(() {
        setState(() {
          print("Continued");
          ttsState = TtsState.continued;
        });
      });
    }

    flutterTts.setErrorHandler((msg) {
      setState(() {
        print("error: $msg");
        ttsState = TtsState.stopped;
      });
    });

    flutterTts.setProgressHandler(
        (String text, int startOffset, int endOffset, String word) {
      setState(() {
        start = startOffset;
        end = endOffset;
      });
    });
  }

  Future _getLanguages() async {
    languages = await flutterTts.getLanguages;
    if (languages != null) setState(() => languages);
  }

  Future _getEngines() async {
    var engines = await flutterTts.getEngines;
    if (engines != null) {
      for (dynamic engine in engines) {
        print(engine);
      }
    }
  }

  Future _speak() async {
    await flutterTts.setVolume(volume);
    await flutterTts.setSpeechRate(rate);
    await flutterTts.setPitch(pitch);

    if (_newVoiceText != null) {
      await flutterTts.awaitSpeakCompletion(true);
      await flutterTts.speak(_newVoiceText!);
    }
  }

  Future _stop() async {
    var result = await flutterTts.stop();
    if (result == 1) setState(() => ttsState = TtsState.stopped);
  }

  Future _pause() async {
    var result = await flutterTts.pause();
    if (result == 1) setState(() => ttsState = TtsState.paused);
  }

  @override
  void dispose() {
    super.dispose();
    flutterTts.stop();
  }

  List<DropdownMenuItem<String>> getLanguageDropDownMenuItems() {
    var items = <DropdownMenuItem<String>>[];
    for (dynamic type in languages) {
      items.add(DropdownMenuItem(value: type as String, child: Text(type)));
    }
    return items;
  }

  void changedLanguageDropDownItem(String? selectedType) {
    setState(() {
      language = selectedType;
      flutterTts.setLanguage(language!);
      if (isAndroid) {
        flutterTts
            .isLanguageInstalled(language!)
            .then((value) => isCurrentLanguageInstalled = (value as bool));
      }
    });
  }

  void _onChange(String text) {
    setState(() {
      _newVoiceText = text;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text('Flutter TTS'),
            ),
            body: SingleChildScrollView(
                scrollDirection: Axis.vertical,
                child: Column(children: [
                  _inputSection(),
                  ttsState == TtsState.playing
                      ? _textFromInput(start, end)
                      : Text(""),
                  _btnSection(),
                  languages != null ? _languageDropDownSection() : Text(""),
                  _buildSliders()
                ]))));
  }

  Widget _inputSection() => Container(
      alignment: Alignment.topCenter,
      padding: EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0),
      child: TextField(
        onChanged: (String value) {
          _onChange(value);
          start = 0;
          end = value.length;
        },
      ));

  Widget _textFromInput(int start, int end) => Container(
      alignment: Alignment.topCenter,
      padding: EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0),
      child: RichText(
        textAlign: TextAlign.center,
        text: TextSpan(children: <TextSpan>[
          TextSpan(
              text: _newVoiceText != null && start != 0
                  ? _newVoiceText!.substring(0, start)
                  : "",
              style: TextStyle(color: Colors.black)),
          TextSpan(
              text: _newVoiceText != null
                  ? _newVoiceText!.substring(start, end)
                  : "",
              style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)),
          TextSpan(
              text: _newVoiceText != null ? _newVoiceText!.substring(end) : "",
              style: TextStyle(color: Colors.black)),
        ]),
      ));

  Widget _btnSection() {
    if (isAndroid) {
      return Container(
          padding: EdgeInsets.only(top: 50.0),
          child:
              Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
            _buildButtonColumn(Colors.green, Colors.greenAccent,
                Icons.play_arrow, 'PLAY', _speak),
            _buildButtonColumn(
                Colors.red, Colors.redAccent, Icons.stop, 'STOP', _stop),
          ]));
    } else {
      return Container(
          padding: EdgeInsets.only(top: 50.0),
          child:
              Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
            _buildButtonColumn(Colors.green, Colors.greenAccent,
                Icons.play_arrow, 'PLAY', _speak),
            _buildButtonColumn(
                Colors.red, Colors.redAccent, Icons.stop, 'STOP', _stop),
            _buildButtonColumn(
                Colors.blue, Colors.blueAccent, Icons.pause, 'PAUSE', _pause),
          ]));
    }
  }

  Widget _languageDropDownSection() => Container(
      padding: EdgeInsets.only(top: 50.0),
      child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
        DropdownButton(
          value: language,
          items: getLanguageDropDownMenuItems(),
          onChanged: changedLanguageDropDownItem,
        ),
        Visibility(
          visible: isAndroid,
          child: Text("Is installed: $isCurrentLanguageInstalled"),
        ),
      ]));

  Column _buildButtonColumn(Color color, Color splashColor, IconData icon,
      String label, Function func) {
    return Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          IconButton(
              icon: Icon(icon),
              color: color,
              splashColor: splashColor,
              onPressed: () => func()),
          Container(
              margin: const EdgeInsets.only(top: 8.0),
              child: Text(label,
                  style: TextStyle(
                      fontSize: 12.0,
                      fontWeight: FontWeight.w400,
                      color: color)))
        ]);
  }

  Widget _buildSliders() {
    return Column(
      children: [_volume(), _pitch(), _rate()],
    );
  }

  Widget _volume() {
    return Slider(
        value: volume,
        onChanged: (newVolume) {
          setState(() => volume = newVolume);
        },
        min: 0.0,
        max: 1.0,
        divisions: 10,
        label: "Volume: $volume");
  }

  Widget _pitch() {
    return Slider(
      value: pitch,
      onChanged: (newPitch) {
        setState(() => pitch = newPitch);
      },
      min: 0.5,
      max: 2.0,
      divisions: 15,
      label: "Pitch: $pitch",
      activeColor: Colors.red,
    );
  }

  Widget _rate() {
    return Slider(
      value: rate,
      onChanged: (newRate) {
        setState(() => rate = newRate);
      },
      min: 0.0,
      max: 1.0,
      divisions: 10,
      label: "Rate: $rate",
      activeColor: Colors.green,
    );
  }
}

(by Daniel Salas DGRandal SchwartzDaniel Lutton)

參考文件

  1. Flutter ‑ underline or paint words text to speech (TTS) (CC BY‑SA 2.5/3.0/4.0)

#text-to-speech #Flutter #underline






相關問題

在 Text-to-Speech C# 應用程序中操作“speaker voicer” (Manipulate "speaker voicer'' in Text-to-Speech C# Application)

android:手機處於睡眠狀態時等待的正確方法(使用 TTS) (android: proper way to wait while phone is in sleep state (using TTS))

音頻樣本庫(口語文本) (Libraries of audio samples (spoken text))

文字轉語音:葡萄牙語不可用? (Text to speech: Portuguese language not available?)

嵌入式應用的語音識別引擎 (Voice recogntion engines for embedded applications)

C# SpeechSynthesizer - “系統上沒有安裝語音” (C# SpeechSynthesizer - "No voice installed on the system")

任何 TTS 引擎都可以改變聲音的語言,進而改變它的音素嗎? (Can any TTS engine change a voice's language, and subsequently its phoneme?)

將 SAPI Text-To-Speech 本地化為西班牙語 (Localizing SAPI Text-To-Speech to spanish)

如何以編程方式讀取 .pdf 文件並將其轉換為音頻(.mp3 格式)? (How to read a .pdf file programmatically and convert it into audio (.mp3 format)?)

如何將 AudioRecord 類中識別的語音保存在文件中? (How can I save recognized voice from AudioRecord class in a file?)

SpeechToText synthesizeToFile 不排隊 (SpeechToText synthesizeToFile not queuing)

Flutter - 下劃線或繪製文字到語音(TTS) (Flutter - underline or paint words text to speech (TTS))







留言討論