EmuMusicFan
1st Lieutenant
We know that WC2, SO1 and SO2 have only certain important plots equipped with audio speech, and the rest just come with subtitles. This is the situation for all platform versions of WC2.
So, is there a way to make other parts of the story also equipped with voice?
Note: This is a technical discussion, and I know the biggest issue is actually finding voice actors to dub the plots.
1. The speech files:
So, first of all, let's take a look at the speech files of WC2. They are in a very simple package format. A speech file, named with SPEECH.S** or COMMUNIC.S**, starts with an index area for all the audio sections, and then there are sequential audio sections. The audio sections just store the raw 8bit PCM data. Note that the samplerate might be 10752Hz, a very strange one, as I found in DOSBox Debugger.
If you would like to take a look at the format, please read this:
2. How does the game load the speech files?
I once had an extravagant expecting that the program could automatically find a matching voice based on the text of the line, which is unrealistic. The speech playing is achieved via opcodes in the game script.
Now, let's take a look at the main script file of WC2: SERIES.S00
Thanks to @UnnamedCharacter for Wing Commander Toolbox. I could easily unpack the script file with this tool:
Then I got the unpacked files: SERIES.S00.xml and a lot of bin files.
In the xml, I found a lot of <ContainerBlock> elements. It seems each one links with a mission in the game. The first one contains such data:
See it? These are the lines of the opening scene. Yes, all the lines of the opening are here.
Then, I found another element:
So, it is pretty clear. Identifier corresponds to speech file, Block corresponds to the audio section.
And then how does the game load them? The answer is in the assembled script:
I am using this tool to assemble/disassemble the scripts:
Note: The ASSEMBLE / DISASSEMBLE COMMANDS of WC Toolbox do not work for me. I just use the standalone one.
And I got a text file: SERIES.S00-ContainerBlock000-ContainerGroup-SequenceGroup-ScriptGroup-OffsetChunk.asm
To make a long story short, after observing, analyzing and experimenting, I found that the minimum unit of voice playback is as follows:
Then:
All these above let you hear or see the Kilrah emperor saying "I will speak with Prince Thrakhath alone. Guards, you are dismissed."
Have you discovered the mystery? This line is written in the third element of the text group (3rd is 2, since the beginning is 0), which corresponds to the first element (1st is 0) of the speech group.
So the following line of "Arise, grandson." works by these:
Then:
Next, I have found these:
So, I guess the usage of this combination is:
So could I just only use the 1st speech slot, solt 0, before each get text?
Well, the answer is YES!
3. How do we add new speeches?
See here:
It's Shadow's words: "Well, it's another exciting day at Action Central."
I think I could just use the speech playing opcodes before it:
Note that the entry at the beginning. Why the new opcodes starts with entries begin with _0244? That is because, the last opcode line in this section is:
Each entry must be unique within the segment. So, we could use the entry numbers larger than the last one in the original script.
Now, Shadow speaks with Blair's voice. Yes! I added a new speech to WC2 cutscene!
But, of course, I would like to add REAL new speech voices, not letting a woman pilot speak in a man's voice.
So, let's back to the SERIES.S00.xml.
Note that I added something new! speech.s30, yes, it is made from Shadow's communication speech file.
And in the asm:
Finally, let's pack it up!
Backup the original SERIES.S00 in WC2's GAMEDAT directory, then copy the newly generated SERIES.S00 to that directory.
4. How to make a new speech file?
Use XmlUnpack finction to unpack a current speech file, you will get the xml and a lot of wav files. Open the xml, the sturcture is prety clear. You could add or remove audio block elements. Then XmlPack it, that's all.
5. What is the audio format again?
8bit, 10752Hz, mono. But I think you could use 11025Hz ones, at most they just sounds lower and longer in 10752Hz mode, very slightly.
NOTE: Currently WCToolbox does not accept 10752Hz wav files.
6. Let Hobbes talk in a cutscene!
Now, we could find the line of "Hobbes to å. Inflight comm check.
Switch to channel 3-2-7." in <ContainerBlock> 008.
So, let's take a look at the disassembled script. There is something new in the following opcodes:
This is a special get text operation, means say in a certain interface. In this case, it is the player sees Hobbes speaking in communication.
So, just treat it as a normal get text.
And, this <ContainerBlock> has no <SpeechGroup>. Do not worry, just add one.
If everything is correct, you could hear hobbes talking in this cutscene.
7. How do I test the cutscenes quickly?
Launch the game like this:
wc2.exe Origin s3 m0
This specific command directly takes you to Ghorah Khar system, Mission 1.
So just change the numbers, you will be taken to any mission.
Under construction...
So, is there a way to make other parts of the story also equipped with voice?
Note: This is a technical discussion, and I know the biggest issue is actually finding voice actors to dub the plots.
1. The speech files:
So, first of all, let's take a look at the speech files of WC2. They are in a very simple package format. A speech file, named with SPEECH.S** or COMMUNIC.S**, starts with an index area for all the audio sections, and then there are sequential audio sections. The audio sections just store the raw 8bit PCM data. Note that the samplerate might be 10752Hz, a very strange one, as I found in DOSBox Debugger.
If you would like to take a look at the format, please read this:
The SPEECH file format of WC2 FM TOWNS
The FM TOWNS WC2 is the only Japanese version of Wing Commander 2. It was also not fully dubbed, but after all, professional Japanese voice actors were invited. We could hear Touru FURUYA's Maniac, for example. What is more, the lines are a bit different from the English version sometimes. So, I...
www.wcnews.com
2. How does the game load the speech files?
I once had an extravagant expecting that the program could automatically find a matching voice based on the text of the line, which is unrealistic. The speech playing is achieved via opcodes in the game script.
Now, let's take a look at the main script file of WC2: SERIES.S00
Thanks to @UnnamedCharacter for Wing Commander Toolbox. I could easily unpack the script file with this tool:
Code:
WCToolsCmd WC2:PC:XmlUnpack SERIES.S00
Then I got the unpacked files: SERIES.S00.xml and a lot of bin files.
In the xml, I found a lot of <ContainerBlock> elements. It seems each one links with a mission in the game. The first one contains such data:
XML:
<SymbolItem Text=" " />
<SymbolItem Text="K'Tithrak Mang 
 Kilrathi Sector HQ" />
<SymbolItem Text="I will speak with Prince Thrakhath alone.
Guards, you are dismissed." />
<SymbolItem Text="Arise, grandson." />
<SymbolItem Text=" " />
<SymbolItem Text="How goes the war against the Terrans?" />
...
See it? These are the lines of the opening scene. Yes, all the lines of the opening are here.
Then, I found another element:
XML:
<SpeechGroup>
<FileChunk>
<FileChunk.Entries>
<FileEntryItem Block="0" Identifier="0" />
<FileEntryItem Block="1" Identifier="0" />
...
<FileEntryItem Block="17" Identifier="0" />
<FileEntryItem Block="0" Identifier="1" />
<FileEntryItem Block="1" Identifier="1" />
...
<FileEntryItem Block="15" Identifier="1" />
<FileEntryItem Block="0" Identifier="2" />
<FileEntryItem Block="1" Identifier="2" />
...
<FileEntryItem Block="9" Identifier="2" />
</FileChunk.Entries>
<FileChunk.Names>
<FileEntryNameItem Name="speech.s00" />
<FileEntryNameItem Name="speech.s01" />
<FileEntryNameItem Name="speech.s02" />
</FileChunk.Names>
</FileChunk>
</SpeechGroup>
So, it is pretty clear. Identifier corresponds to speech file, Block corresponds to the audio section.
And then how does the game load them? The answer is in the assembled script:
XML:
<OffsetChunk file="SERIES.S00-ContainerBlock000-ContainerGroup-SequenceGroup-ScriptGroup-OffsetChunk.bin" />
I am using this tool to assemble/disassemble the scripts:
Wing Commander Toolbox
Does anyone know, which file contains the sound effects of WC2? They are within the WING2.TIM file. The file has three blocks dividing the effects by audio format: MIDI, SoundBlaster, PC Speaker. If you unpack the TIM file and view the content of individual files (ex...
www.wcnews.com
Note: The ASSEMBLE / DISASSEMBLE COMMANDS of WC Toolbox do not work for me. I just use the standalone one.
Code:
WC2Assembler.exe SERIES.S00-ContainerBlock000-ContainerGroup-SequenceGroup-ScriptGroup-OffsetChunk.bin
And I got a text file: SERIES.S00-ContainerBlock000-ContainerGroup-SequenceGroup-ScriptGroup-OffsetChunk.asm
To make a long story short, after observing, analyzing and experimenting, I found that the minimum unit of voice playback is as follows:
Code:
_0055: c036 0 ; push constant, byte
_0057: c162 0 ; preload speech
_0059: c036 0 ; push constant, byte
_005b: c040 761 ; set global[<uintvar:index>]
Then:
Code:
_0074: c111 2 ; get text
All these above let you hear or see the Kilrah emperor saying "I will speak with Prince Thrakhath alone. Guards, you are dismissed."
Have you discovered the mystery? This line is written in the third element of the text group (3rd is 2, since the beginning is 0), which corresponds to the first element (1st is 0) of the speech group.
So the following line of "Arise, grandson." works by these:
Code:
_0085: c036 0 ; push constant, byte
_0087: c162 1 ; preload speech
_0089: c036 0 ; push constant, byte
_008b: c040 761 ; set global[<uintvar:index>]
Then:
Code:
_00a4: c111 3 ; get text
Next, I have found these:
Code:
_0100: c036 0 ; push constant, byte
_0102: c162 2 ; preload speech
_0104: c036 1 ; push constant, byte
_0106: c162 3 ; preload speech
_0108: c036 2 ; push constant, byte
_010a: c162 4 ; preload speech
_010c: c036 3 ; push constant, byte
_010e: c162 5 ; preload speech
_0110: c036 0 ; push constant, byte
_0112: c040 761 ; set global[<uintvar:index>]
So, I guess the usage of this combination is:
Code:
c036 0 ; Indicate the speech slot
c162 2 ; Preload speech
c036 1 ; Indicate the next slot, if you need to do so
c162 3 ; Preload the next speech
...
c036 0 ; Done now!
c040 761 ; Ready to play the speech blocks!
...
So could I just only use the 1st speech slot, solt 0, before each get text?
Well, the answer is YES!
3. How do we add new speeches?
See here:
Code:
_00cb: c111 53 ; get text
It's Shadow's words: "Well, it's another exciting day at Action Central."
I think I could just use the speech playing opcodes before it:
Code:
_0244: c036 0 ; push constant, byte
_0245: c162 22 ; preload speech
_0246: c036 0 ; push constant, byte
_0247: c040 761 ; set global[<uintvar:index>]
_00cb: c111 53 ; get text
Note that the entry at the beginning. Why the new opcodes starts with entries begin with _0244? That is because, the last opcode line in this section is:
Code:
_0243: c014 _0000 ; jmp
Each entry must be unique within the segment. So, we could use the entry numbers larger than the last one in the original script.
Now, Shadow speaks with Blair's voice. Yes! I added a new speech to WC2 cutscene!
But, of course, I would like to add REAL new speech voices, not letting a woman pilot speak in a man's voice.
So, let's back to the SERIES.S00.xml.
XML:
<SpeechGroup>
<FileChunk>
<FileChunk.Entries>
<FileEntryItem Block="0" Identifier="0" />
<FileEntryItem Block="1" Identifier="0" />
...
<FileEntryItem Block="9" Identifier="2" />
<FileEntryItem Block="0" Identifier="3" />
</FileChunk.Entries>
<FileChunk.Names>
<FileEntryNameItem Name="speech.s00" />
<FileEntryNameItem Name="speech.s01" />
<FileEntryNameItem Name="speech.s02" />
<FileEntryNameItem Name="speech.s30" />
</FileChunk.Names>
</FileChunk>
</SpeechGroup>
Note that I added something new! speech.s30, yes, it is made from Shadow's communication speech file.
And in the asm:
Code:
_0244: c036 0 ; push constant, byte
_0245: c162 43 ; preload speech, THE REAL NEW SPEECH BLOCK!
_0246: c036 0 ; push constant, byte
_0247: c040 761 ; set global[<uintvar:index>]
_00cb: c111 53 ; get text
Finally, let's pack it up!
Code:
WC2Assembler.exe SERIES.S00-ContainerBlock000-ContainerGroup-SequenceGroup-ScriptGroup-OffsetChunk.asm
WCToolsCmd WC2:PC:XmlPack SERIES.S00.xml
Backup the original SERIES.S00 in WC2's GAMEDAT directory, then copy the newly generated SERIES.S00 to that directory.
4. How to make a new speech file?
Use XmlUnpack finction to unpack a current speech file, you will get the xml and a lot of wav files. Open the xml, the sturcture is prety clear. You could add or remove audio block elements. Then XmlPack it, that's all.
5. What is the audio format again?
8bit, 10752Hz, mono. But I think you could use 11025Hz ones, at most they just sounds lower and longer in 10752Hz mode, very slightly.
NOTE: Currently WCToolbox does not accept 10752Hz wav files.
6. Let Hobbes talk in a cutscene!
Now, we could find the line of "Hobbes to å. Inflight comm check.
Switch to channel 3-2-7." in <ContainerBlock> 008.
So, let's take a look at the disassembled script. There is something new in the following opcodes:
Code:
_0498: c135 49, 12
This is a special get text operation, means say in a certain interface. In this case, it is the player sees Hobbes speaking in communication.
So, just treat it as a normal get text.
And, this <ContainerBlock> has no <SpeechGroup>. Do not worry, just add one.
If everything is correct, you could hear hobbes talking in this cutscene.
7. How do I test the cutscenes quickly?
Launch the game like this:
wc2.exe Origin s3 m0
This specific command directly takes you to Ghorah Khar system, Mission 1.
So just change the numbers, you will be taken to any mission.
Under construction...
Last edited: