Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SUPERNOVA: Text To Speech (TTS) for the game #3267

Merged
merged 5 commits into from Sep 4, 2021

Conversation

@taylorzhancher
Copy link
Contributor

@taylorzhancher taylorzhancher commented Aug 12, 2021

Tentatively adding TTS to the game
This includes

  • Speech for opening intro story
  • Speech for dialogue trees
  • GUI option for TTS
Copy link
Member

@criezy criezy left a comment

This is a good start.
In addition to the comments I added, here are a few other changes to do:

  • You are missing the call to TextToSpeechManager::setLanguage() to either English or German depending which version we are playing.
  • Similarly to Dreamweb, you need to specify the text encoding. When playing in English it does not matter, but when playing in German it does. Here the encoding is again kDos850 (for both German and English).

In addition it would also be good to add TTS for some other text:

  • Moving cursor on objects in the inventory or a hotspot.
  • Automatic dialogs (when there is no choice). There is an example with the savegame I provided for Mission Supernova 2 when you are on the scene ("One moment, I have to think about what I am playing for you").

For the inventory and hotspot I will need to have a look as I don't remember how it is handled.
For the automatic dialogs, I think it is using GameManager::say().

engines/supernova/game-manager.cpp Outdated Show resolved Hide resolved
engines/supernova/game-manager.cpp Show resolved Hide resolved
engines/supernova/detection.cpp Show resolved Hide resolved
engines/supernova/screen.cpp Outdated Show resolved Hide resolved
@taylorzhancher
Copy link
Contributor Author

@taylorzhancher taylorzhancher commented Aug 14, 2021

@criezy There are 2 things I wish to share & ask

  1. The action panel can have TTS to highlighted options by doing this in void GameManager::processInput() Which seems great (see line 529)
				_guiInventoryArrow[_mouseField - 768].setHighlight(true);
				_ttsMan->say(_guiInventoryArrow[_mouseField - 768].getText(), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);
				break;
			case onInventory:
				_guiInventory[_mouseField - 512].setHighlight(true);
				_currentInputObject = _inventory.get(_mouseField - 512 + _inventoryScroll);
				_ttsMan->say(_guiInventory[_mouseField - 512].getText(), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);
				break;
			case onCmdButton:
				_guiCommandButton[_mouseField - 256].setHighlight(true);
				_ttsMan->say(_guiCommandButton[_mouseField - 256].getText(), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);
				break;
			case onObject:
				_currentInputObject = _currentRoom->getObject(_mouseField);
  • On the last 2 lines of the code above, it is found that the objects in the scene are also able to have TTS by case onObject
  • However, I don't know how to get the text from the last line? In the API documentation I didn't find something that looked like text
  1. I tried to add a get language function but was in vain. This was my attempt. The error complained that it doesn't recognize _gameDescription.
  • I hope to push the changes here soon
  • In case the reason is obvious, I've attached the code below
    from supernova.cpp
#include "engines/advancedDetector.h"
#include "common/text-to-speech.h"

@ -99,6 +101,8 @@ SupernovaEngine::SupernovaEngine(OSystem *syst)
		_MSPart = 0;

	_improved = ConfMan.getBool("improved");

	_ttsMan = g_system->getTextToSpeechManager();
}

SupernovaEngine::~SupernovaEngine() {
@ -110,6 +114,9 @@ SupernovaEngine::~SupernovaEngine() {
}

Common::Error SupernovaEngine::run() {
	 if (_ttsMan != nullptr)
	 	_ttsMan->setLanguage(Common::getLanguageCode(getLanguage()));

@ -830,5 +837,8 @@ void SupernovaEngine::stopSound() {
	_sound->stop();
}

 Common::Language SupernovaEngine::getLanguage() const {
  	return _gameDescription->language;
 }

}

from supernova.h

@ -137,6 +137,8 @@ public:
	void renderBox(const GuiElement &guiElement);
	void setColor63(byte value);
	void stopSound();
	Common::Language getLanguage() const;
	Common::TextToSpeechManager *_ttsMan;
};

@criezy
Copy link
Member

@criezy criezy commented Aug 15, 2021

@criezy There are 2 things I wish to share & ask

  1. The action panel can have TTS to highlighted options by doing this in void GameManager::processInput() Which seems great (see line 529)

This is indeed a good place to add TTS

	case onInventoryArrowUp:
	case onInventoryArrowDown:
		// Fallthrough
		_guiInventoryArrow[_mouseField - 768].setHighlight(true);
		_ttsMan->say(_guiInventoryArrow[_mouseField - 768].getText(), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);
		break;

Are you sure those up and down arrows (the buttons to scroll the inventory) have a text that can be spoken?

	case onInventory:
		_guiInventory[_mouseField - 512].setHighlight(true);
		_currentInputObject = _inventory.get(_mouseField - 512 + _inventoryScroll);
		_ttsMan->say(_guiInventory[_mouseField - 512].getText(), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);
		break;

Does this actually work?
I don't think the _guiInventory elements have the text set, or at least not always. I think you might need to use the _currentInputObject instead.

		if (!isNullObject(_currentInputObject))
			_ttsMan->say(_vm->getGameString(_currentInputObject->_name), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);

Also the Common::TextToSpeechManager::INTERRUPT_NO_REPEAT action is the default, so you don't need to specify it.

		if (!isNullObject(_currentInputObject))
			_ttsMan->say(_vm->getGameString(_currentInputObject->_name), Common::kDos850);
	case onCmdButton:
		_guiCommandButton[_mouseField - 256].setHighlight(true);
		_ttsMan->say(_guiCommandButton[_mouseField - 256].getText(), Common::TextToSpeechManager::INTERRUPT_NO_REPEAT, Common::kDos850);
		break;

Same remark as above about the Common::TextToSpeechManager::INTERRUPT_NO_REPEAT that can be removed.

	case onObject:
		_currentInputObject = _currentRoom->getObject(_mouseField);
  • On the last 2 lines of the code above, it is found that the objects in the scene are also able to have TTS by case onObject
  • However, I don't know how to get the text from the last line? In the API documentation I didn't find something that looked like text

Same as for the inventory object case above:

		if (!isNullObject(_currentInputObject))
			_ttsMan->say(_vm->getGameString(_currentInputObject->_name), Common::kDos850);
  1. I tried to add a get language function but was in vain. This was my attempt. The error complained that it doesn't recognize _gameDescription.

There is indeed no _gameDescription member variable in the SupernovaEngine. You can get the language from ConfMan instead.

if (_ttsMan != nullptr)
	_ttsMan->setLanguage(ConfMan.get("language"));

engines/supernova/game-manager.cpp Outdated Show resolved Hide resolved
engines/supernova/game-manager.cpp Outdated Show resolved Hide resolved
engines/supernova/game-manager.cpp Outdated Show resolved Hide resolved
engines/supernova/screen.cpp Show resolved Hide resolved
engines/supernova/supernova.h Outdated Show resolved Hide resolved
@taylorzhancher
Copy link
Contributor Author

@taylorzhancher taylorzhancher commented Aug 15, 2021

@criezy I've made changes to comply with what you said
Would like to add that case onInventory: , although my previous code doesn't actually produce tts, but case onInventory: refers to the objects in the inventory, which is unique to case onObject, and I've just added TTS to the former with _vm->getGameString(_currentInputObject->_name)

engines/sci/tts.cpp Outdated Show resolved Hide resolved
engines/sci/tts.h Outdated Show resolved Hide resolved
engines/supernova/game-manager.cpp Outdated Show resolved Hide resolved
engines/supernova/game-manager.cpp Outdated Show resolved Hide resolved
@criezy
Copy link
Member

@criezy criezy commented Aug 15, 2021

There are a few more changes needed, and you need to remove the changes in the SCI engine.

Would like to add that case onInventory: , although my previous code doesn't actually produce tts, but case onInventory: refers to the objects in the inventory, which is unique to case onObject, and I've just added TTS to the former with _vm->getGameString(_currentInputObject->_name)

I don't understand that sentence. Is that a question?

@taylorzhancher
Copy link
Contributor Author

@taylorzhancher taylorzhancher commented Aug 16, 2021

There are a few more changes needed, and you need to remove the changes in the SCI engine.

Would like to add that case onInventory: , although my previous code doesn't actually produce tts, but case onInventory: refers to the objects in the inventory, which is unique to case onObject, and I've just added TTS to the former with _vm->getGameString(_currentInputObject->_name)

I don't understand that sentence. Is that a question?

No, it's not a question. Sorry for the many mistakes in the previous commit. Hope they're all good now.

@taylorzhancher taylorzhancher marked this pull request as ready for review Aug 16, 2021
criezy
criezy approved these changes Aug 16, 2021
Copy link
Member

@criezy criezy left a comment

Thank you. This looks good now.
The history will need to be cleaned, but we can do that by squashing all the commits when merging this pull request.

Since we are in feature freeze currently to prepare the next release, I will wait before merging this.

@criezy criezy added the GSoC label Aug 18, 2021
@criezy
Copy link
Member

@criezy criezy commented Sep 4, 2021

Now that trunk is unfrozen, I will squash and merge this.

@criezy criezy merged commit fa8845e into scummvm:master Sep 4, 2021
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants