New feature to allow for easier voice acting

Discussion of all aspects of the game engine, including development of new and existing features.

Moderator: Forum Moderators

User avatar
The_Gnat
Posts: 2215
Joined: October 10th, 2016, 3:06 am
Contact:

New feature to allow for easier voice acting

Post by The_Gnat »

Hi,

Myself and a few other people are working on voice acting another two campaigns (DiD and AOI). We really think having campaigns with voice acting adds a lot to the campaign and we hope to do even more campaigns soon.

However, currently in order to voice act a campaign the campaign has to be duplicated as an add-on and then modified extensively in order to add a voice line to every story and message the users speak. In order to allow voice acting to be done even easier we had thought that perhaps the mainline campaigns could look automatically for voice files and if they exist play them. This would save the creation of an extra add-on and more importantly save the extra unnecessary work allowing voice acting to be done much easier. Josteph suggested a very interesting idea for doing so by making the engine automatically look for a file named after the md5 of the string.

For example, if we have message = _ "female^Hello world", the engine would automatically look for a file called 9f8a2a8f5acb58df67cfdf625997e672.ogg. If the file exists then the sound will be played.

This then would allow users who wanted voice acting to download the add-on which contained the voice files and they would automatically be played by the campaign.

(Note: Pentarctagon did point out that this could potentially limit the development of campaigns but I believe if we get enough people interested in voice acting we could easily post updates to the voice files if campaigns are changed. Also as voice acting becomes easier then it will hopefully gain more interest!)

Josteph said he would be interested in implementing this but it would of course need approval. Also it would be great to hear any thoughts or suggestions anyone has!
User avatar
Ravana
Forum Moderator
Posts: 2933
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: New feature to allow for easier voice acting

Post by Ravana »

Using hash has disadvantage of practically useless file names. Hash could be part of file name, but there should be readable part too.

You should not require each string ever only being allowed to be said by one speaker.
User avatar
The_Gnat
Posts: 2215
Joined: October 10th, 2016, 3:06 am
Contact:

Re: New feature to allow for easier voice acting

Post by The_Gnat »

I agree, in order to make the usage practical it would be best not to make each string used by only one. That would necessitate duplicating files if you want the same line said twice which is definitely a waste. However, only rarely is a line repeated exactly so I don't know if it is a huge issue.

Also is there any way where strings can automatically call a single file automatically if a code is not used to determine which file?

Ideally a file would A) have a more readable name, and B) be able to be used multiple times but I don't think these are critical elements.
User avatar
Ravana
Forum Moderator
Posts: 2933
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: New feature to allow for easier voice acting

Post by Ravana »

6-symbol hash like git reflog should be enough to determine which file should be used, leaving rest of filename for readable name.
User avatar
Pentarctagon
Project Manager
Posts: 5496
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: New feature to allow for easier voice acting

Post by Pentarctagon »

If you have the exact same line, it would give the exact same hash. If you have two different people potentially saying the same line though, then I assume you would want different files.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
josteph
Inactive Developer
Posts: 741
Joined: August 19th, 2017, 6:58 pm

Re: New feature to allow for easier voice acting

Post by josteph »

About filename, we could add some more information to the filename like scenario id, line number, and locale (like po files are named with de or en). I would say add the id of the speaker, but [message] can specify the speaker by SUF and there's no easy way to put the SUF in the filename. Or maybe the filename should be the whole English message, with punctuation removed. In either case, autogenerated filenames will require a way to list what names the engine looks for.

Ravana, Pentarctagon, if two different people say the same line, that can be resolved with the caret mechanism, like this:

Code: Select all

[message]
	speaker=Arvith
	message= _ "Arvith^Yes."
[/message]

[message]
	speaker=Baran
	message= _ "Baran^Yes."
[/message]
These two lines would look for different filenames.
User avatar
GunChleoc
Translator
Posts: 506
Joined: September 28th, 2012, 7:35 am
Contact:

Re: New feature to allow for easier voice acting

Post by GunChleoc »

Line number is fragile when campaigns get changed. How about adding the speaker's name to the filename? Something like this:

Code: Select all

Baran_<hash>_en_<something human readable that the engine will ignore>.ogg
User avatar
josteph
Inactive Developer
Posts: 741
Joined: August 19th, 2017, 6:58 pm

Re: New feature to allow for easier voice acting

Post by josteph »

I think it's a good idea to put <something human readable that the engine will ignore> in the filename. The speaker's name, however, may be unknown, as in this example:

Code: Select all

[message]
  race=orc,troll
  level=2
  message=_ "I am a high-level orc or troll!"
[/message]
so maybe the filename could have the speaker's id when the speaker is specified by id, and some fixed string otherwise. (As in Baran_<hash>_en_<foo>.ogg, noid_<hash>_en_<bar>.ogg)
User avatar
The_Gnat
Posts: 2215
Joined: October 10th, 2016, 3:06 am
Contact:

Re: New feature to allow for easier voice acting

Post by The_Gnat »

Hi josteph, Yes that is a good idea. Having it at least somewhat readable is important since we will probably want to make modifications in the future. Also sorting it by character name is important for finding the files.
User avatar
josteph
Inactive Developer
Posts: 741
Joined: August 19th, 2017, 6:58 pm

Re: New feature to allow for easier voice acting

Post by josteph »

I think we have enough of a consensus to try to prototype this in WML/Lua? We could wrap wesnoth.actions.message and have it compute the filename and call wesnoth.play_sound.
User avatar
Pentarctagon
Project Manager
Posts: 5496
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: New feature to allow for easier voice acting

Post by Pentarctagon »

There isn't hashing built into lua, I don't think, so that would need to be done in C++ I think(unless Wesnoth's lua API already has hashing functionality).
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
josteph
Inactive Developer
Posts: 741
Joined: August 19th, 2017, 6:58 pm

Re: New feature to allow for easier voice acting

Post by josteph »

There's an implementation of md5 in src/hash.cpp, but I don't think it's exposed to lua.

I have a prototype:

Code: Select all

diff --git a/data/core/sounds/noid-00000000-en-message_by_an_orc.ogg b/data/core/sounds/noid-00000000-en-message_by_an_orc.ogg
new file mode 120000
index 00000000000..6cdc5624214
--- /dev/null
+++ b/data/core/sounds/noid-00000000-en-message_by_an_orc.ogg
@@ -0,0 +1 @@
+ambient/wardrums.ogg
\ No newline at end of file
diff --git a/data/scenario-test.cfg b/data/scenario-test.cfg
index 778cf5af56a..58213e1a74a 100644
--- a/data/scenario-test.cfg
+++ b/data/scenario-test.cfg
@@ -1437,6 +1437,47 @@ My best advancement costs $next_cost gold and I’m $experience|% there."
     [event]
         name=start
 
+    [lua]
+        code = <<
+            old_message = wesnoth.wml_actions.message
+            function wesnoth.wml_actions.message(cfg)
+                -- Speaker may be specified by id or by SUF.
+                local speaker = cfg.speaker or cfg.id
+                if (not speaker) or speaker:find(',') or speaker == 'narrator' or speaker == 'unit' or speaker == 'second_unit' then
+                    -- Keep the list of exceptions in sync with get_speaker in data/lua/wml/message.lua
+                    speaker = 'noid'
+                end
+
+                -- Hash: we ought to use CRC32, but for this prototype we'll just use random numbers.
+                local hash = 0
+                for i=1,32 do
+                    if helper.rand('0,1') == '1' then
+                        hash = hash | 1
+                    end
+                    hash = hash << 1
+                end
+                local hash = string.format('%x', hash)
+
+                -- Target language. We ought to obtain this from somewhere.
+                local language = 'en'
+
+                -- Human-readable part.
+                -- tostring needed because cfg.message is usually a localized string
+                local readable = tostring(cfg.message):gsub(' ', '_'):gsub('[^A-Za-z0-9_]', '')
+
+                hash = '00000000'
+                local filename = string.format("%s-%s-%s-%s.ogg", speaker, hash, language, readable)
+                -- Can't use have_file here because it has a different interface than play_sound:
+                -- have_file("core/sounds/ambient/wardrums.ogg") v. play_sound("ambient/wardrums.ogg")
+                wesnoth.message("Hello world: playing " .. filename)
+                wesnoth.play_sound(filename) -- may log "error audio: Could not loud sound file '%s'"
+
+                -- TODO handle show_if and SUF's with no matches
+                old_message(cfg)
+            end
+        >>
+    [/lua]
+
         [gold]
             side=1
             amount=1000
It works for me: if you add [message] race=orc message="message by an orc"[/message], war drums will be played when the message is shown.

TODO items:

1. Figure out the target language
2. Handle show_if and SUF's that don't match, don't play the sound in that case (won't be an issue if this is accepted for mainline, in that case we'll change data/lua/wml/message.lua)
3. Do something about the hash. As you can see I don't actually use it so maybe just drop it entirely? We can use foo^ to disambiguate identical messages, as I said in an earlier post. (edit: jyrkive suggests FNV-1a, see #modding on Feb 18.)
(edit:)
4. That tostring() returns the localized string, meaning the file would be named after the localized string. If we want to fix this we'd have to call t_string::base_str or t_string::value (C++ method names, possibly aren't exposed to lua right now)
User avatar
The_Gnat
Posts: 2215
Joined: October 10th, 2016, 3:06 am
Contact:

Re: New feature to allow for easier voice acting

Post by The_Gnat »

josteph wrote: February 15th, 2019, 3:00 pm I have a prototype:
Awesome! 8) It is great to see this moving forward!
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: New feature to allow for easier voice acting

Post by gfgtdf »

i wonder what your plan is for messages that are constructed at runtime? Like message= _ "Don't hurt $ogre_name|!" or message= _ "Three days ride to the northeast, in a deserted castle. The passwords to the guards are $first_password_$first_password and $second_password_$second_password|." ?
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
josteph
Inactive Developer
Posts: 741
Joined: August 19th, 2017, 6:58 pm

Re: New feature to allow for easier voice acting

Post by josteph »

gfgtdf wrote: February 15th, 2019, 10:56 pm i wonder what your plan is for messages that are constructed at runtime? Like message= _ "Don't hurt $ogre_name|!" or message= _ "Three days ride to the northeast, in a deserted castle. The passwords to the guards are $first_password_$first_password and $second_password_$second_password|." ?
I guess the simplest option to deal with variables will be to change the campaign to eliminate them from the source string. For your first example this is needed anyway since otherwise it's untranslatable (viewtopic.php?f=8&t=11445). For your second example, maybe the "right" password could be the same in every playthrough, rather than random. I'm sure there are other solutions too.
josteph wrote: February 15th, 2019, 3:00 pm TODO items:

1. Figure out the target language
So, adding a wesnoth.get_language function that returns the current language is easy (I have a prototype of that too). Is there a reason we shouldn't make that value exposed to UMC though? If so we'd have to have some sort of wesnoth.play_localized_sound function, implemented in C++, that takes a filename foo.ogg and calls wesnoth.play_sound "en_US/foo.ogg" (replacing en_US by the appropriate locale), to hide the locale from Lua.
Post Reply