Simultaneous Speech

Started by bx83, Tue 23/01/2018 21:20:44

Previous topic - Next topic

bx83

Hi,

I've been trying to find this for some time; and I have someone who I was prepared to pay to make a plugin for it, but he's not avilable atm.

Are there any functions, plugins, or anything else, that can produce code which follows these principles:
-saying lines of character A would be said, and block other lines of the same character (so lines A1 A2 and A3 would be said one after the other, A1 A2 A3)
-saying lines of character A and B would have them both spoken simultaneously, so A1 and B1 would be spoken at the same time.

so:

Code: ags

//said one after the other: - "1 and 2"
cA.SimultanneousSpeech("1 ")
cA.SimultanneousSpeech("and 2")

//said simultaneously
//"1 2 3" 
//"4 5 6" 
cA.SimultanneousSpeech("1 2 3")
cB.SimultanneousSpeech("4 5 6")

//all speech is paused, or cache is cleaned - this makes easy to differentiate A B A from all being played simultaneously
PauseAllSpeech()

//B says something
cB.SimultanneousSpeech("something")
PauseAllSpeech()
//A says something else
cA.SimultanneousSpeech("something else")


Instead of PauseAllSpeech(), perhaps using a blocking function like Say would be easier?..

This allows speech, and lipsync (using TotalLipSync) to work independantly of eachother - in other word, on 2 or 3 characters simultaneously.

Gurok

Just so you're aware, the only practical way to do this is to use SayBackground. I don't know this will impact your lip sync.

Here's a script module:

http://www.mediafire.com/file/vjd74pf5s45yfs3/SimultaenousSpeech.scm

I understood your PauseAllSpeech() function as wanting to wait synchronously till the queued events completed. I also implemented an alternate wait that's asynchronous. There's also a wait function for individual characters as you'll probably want that for speech timing. Here's an example of both in use:

Code: ags

	/* Method 1 */
	cEgo.SaySimultaneous("My ding a ling...");
	cEgo.WaitSimultaneous(30);
	cEgo.SaySimultaneous("... My ding a ling...");
	SimultaneousSpeech.WaitForSpeech(); // This is like calling Wait() -- it pauses the game and gives you a busy cursor
	cChar1.SaySimultaneous("I want you to play");
	cChar1.SaySimultaneous("with my ding a ling!");
	cChar2.SaySimultaneous("I want you to play");
	cChar2.SaySimultaneous("with my ding a ling!");
	
	/* Method 2 */
	cEgo.SaySimultaneous("My ding a ling...");
	cEgo.WaitSimultaneous(30);
	cEgo.SaySimultaneous("... My ding a ling...");
	cChar1.WaitSimultaneousForCharacter(cEgo); // These let a character wait for another before they start talking
	cChar2.WaitSimultaneousForCharacter(cEgo);
	cChar1.SaySimultaneous("I want you to play");
	cChar1.SaySimultaneous("with my ding a ling!");
	cChar2.SaySimultaneous("I want you to play");
	cChar2.SaySimultaneous("with my ding a ling!");


You can send money along to <pen(nospam)neyb@tpg.com.au> (PayPal, remove (nospam)) if you found it helpful, or I can PM you my bank details. I won't say no to that.
[img]http://7d4iqnx.gif;rWRLUuw.gi

Crimson Wizard

I won't be very useful here, just wanted to mention that I was participating in a game project which had paralllel character speech and characters interrupting each other, and from playtester's perspective that annoyed the hell out of me. Having player to read two or more lines of text at the same time - it's a quite a unusual game design choice. Please be careful with that, or your players may hate you. :)

Snarky

I can see a couple of use-cases for this:

-To have multiple characters speaking in unison (like the pirate leaders all shouting "GROG!!!" at the same time in Monkey Island) or contradicting each other ("So the most important thing in life is..." "-Family! -Money!")
-In a scrolling room, to have multiple background conversations going on in parallel in different parts of the room

bx83

Snarky and Crimson, exactly that. No plugins for this? Is it possible with the sound system, perhaps if I just did play(someline, noblock)?

bx83

Snarky, could I do the following:

Code: ags

cJulius.DisplayABubbleNonBlocking("this is a line")
cSomeoneElse.DisplayABubbleNonBlocking("this is a line, too")
chan1=TheCombinedLineOfTwoPlayers.Play(prioritynormal,once);

Snarky

It's easy enough to do by itself. The hard part is if you want to make the whole thing non-blocking, but still queue it so that there are other lines before and after it.

In a blocking conversation, you could just do:

Code: ags
  game.bgspeech_stay_on_display = 1;
  cSomeoneElse.SayBackgroundBubble("this is a line, too", true); // Putting the LONGER line as non-blocking
  cJulius.SayBubble("&123 this is a line"); // Where JULI123.ogg is the combined speech clip 
  cSomeoneElse.StopBackgroundBubble();


(Depending on how long the speech clip is, cSomeoneElse's line might disappear before it finished playing, but otherwise this ought to work.)

And yes, to do just this particular line entirely non-blocking you could do basically what you said:

Code: ags
  cJulius.SayBackgroundBubble("this is a line");
  cSomeoneElse.SayBackgroundBubble("this is a line, too", true);
  chan1 = aCombinedLine.Play();


Again, the trick is to be able to embed this inside a queued, non-blocking conversation. That's where I assume Gurok's code comes in. It might just need to be adapted to use the SpeechBubble SayBackgroundBubble() function instead of the plain AGS SayBackground() function, but I haven't looked at it.

bx83

#7
I tried the solution:

Code: ags

game.bgspeech_stay_on_display = 1;
chan1 = aCombinedLines.Play(eAudioPriorityNormal, eOnce);
cJulius.SayBackgroundBubble("a slightly longer line",true);
cNerd.SayBubble("a bit shorter line");
cJulius.StopBackgroundBubble();
aCombinedLines.Stop();


The result was the only one that worked; I tried all the others, but they had a habit of: allowing one character to lipsync, but not the other; giving non-blocking to one character, so that clicking anywhere would have him move, and then cause an error; etc. etc. etc.

Granted, some of these were perversions of what you wrote originally, some were combinations, and some had 'true' as a second argument, or the longer line first/last, *BUT*, this one works all the time ;)

bx83

Also, to set the game fade in/fade out option correctly:

Code: ags

    SetGameOption(OPT_CROSSFADEMUSIC, 0);
    [do all code from example above]
    SetGameOption(OPT_CROSSFADEMUSIC, 2);


I found the sound was fading in/out whether this was sample was set as Sound, Music (which is supposed to have the crossfade effect), or "3 [unknown]" (whatever the hell that is).

bx83

#9
Well I've run into a problem :(

The speech is said simultaneously; but only the second speech bubble (SayBubble as opposed to SayBackgroundBubble) is getting the lipsync right.
I use TotalLipSync 5.0 - Here

Why is this happening? No other combination of the code get's the 1st person (Julius) to lipsync correctly. What is it with Bakground?

Exactly as in my game:
Code: ags

SetGameOption(OPT_CROSSFADEMUSIC, 0);      
game.bgspeech_stay_on_display = 1;
chan1 = aCombinedLine_110_1321.Play(eAudioPriorityNormal, eOnce);
cJulius.SayBackgroundBubble("&1321 We are very sorry to makers of Everyone Loves Raymond. He is not our own creation and wholly the property of 'Where's Lunch', 'Worldwide Pants', and 'HBO Independent Productions'. Thankyou for viewing our slapstick play. Peace out.",true);
cNerd.SayBubble("&110 We are very sorry to makers of Everybody Loves Raymond. He is not our own creation and wholly the property of 'Where's Lunch', 'Worldwide Pants', and 'HBO Independent Productions'.");
cJulius.StopBackgroundBubble();
aCombinedLine_110_1321.Stop();
SetGameOption(OPT_CROSSFADEMUSIC, 2);


Yes, the .TSV's are correct and exist in Compiled/sync and Compiled/Windows/sync.

UPDATE: I was missing a piece of code that allowed SayBackgroundBubble to animate:

Code: ags

bool SB_sayBackgroundAnimateImpl(this Character*, String message)
{
    this.SaySync(message);        //<--- THIS LINE
    return true;
}


Now, the speechbubble is displayed (behind another speechbubble with exactly the same text and no background..?), and speech animation is animated.
BUT NOW nothing is simultaneous; because (I assume) TotalLipSync has a function which animates the lines... that's a blocking function! :cheesy::cheesy::cheesy:
So everything blocks, and 1 line is said after the other, Background or not.
So I don't know, I give up. :/

Snarky

#10
The reason this doesn't work is that TotalLipSync doesn't support background speech:

Quote from: Gurok on Wed 24/01/2018 04:29:04
Just so you're aware, the only practical way to do this is to use SayBackground. I don't know this will impact your lip sync.

It's on my TODO list of future extensions for the module, but it's not a trivial change: it might require an almost total rewrite of the code. (The two main problems: first, the current code assumes only one lip-syncing character at a time, with state variables that would now have to become arrays and logic to match; and second, the code relies on a blocking speech clip to determine the length of the line. And not all the lip-sync formats store the total length of the clip, which might be different from the length of the animation, so some way to find and store this information somewhere would be needed.)

Especially with the AGS Awards coming up, I can't commit to making this change any time soon. Maybe in a couple of months. If that's not soon enough, I recommend you accept that characters that use background speech won't be lip-synced, and just use normal speech animation in these cases. (You could make a separate "non-lipsync speech view", and it wouldn't be too hard to switch their speech view to this whenever they're background-speaking, and back when they're done.)

bx83

#11
Yep, as I thought.
I was thinking of that (separate speech animation), but this could be veeeeery tedious. But it looks like my only option, for the moment.
I can wait a month though, I have until the end of the year and this is minor.

Also, I can pay...? ;)

PS - You could attach this to a run-one-time function? Like is (message=="JUSTTHIS") then do this else do everything as normal.

Snarky

Quote from: bx83 on Sat 10/02/2018 07:17:06
I can wait a month though, I have until the end of the year and this is minor.

I said "maybe in a couple of months". :P
Well before the end of the year shouldn't be a problem.

QuoteAlso, I can pay...? ;)

I simply don't have time right now. If someone else wants to hack away at the TLS code for pay they are free to, but otherwise I'll get around to it later.

bx83

Well, did the frames myself. Quicker than I thought it would be, but working off the TSV file means I have to use a custom delay for *every frame* - I didn't bother. Most of it works. I just put the stop frame code in at the points where there was a pause, 80% of the rest is like semi random speech. Meh.
I await your edit, probably, in 3 months or whatever :P

SMF spam blocked by CleanTalk