View Full Version : Soundtrack Pack in Progress

Nov 07, 2011, 11:37 PM
I've PMed this to a couple of folks, but I figured it'd be easier just to have an open inquiry about these issues, so there ya go:

I have compiled an extremely large collection of mp3 files which offers well over 200 new tracks for all eras, categorized and folderized be era. There are a grand total of 277 files, but some of these are existing tracks that I have either retained or repurposed. The chief issue is not the size, however; I'm sure that the file could simply be hosted here as a seperate download (it's around 1.11 GB in total) and split into 100-150 MB segments by era if there's enough demand for it.

The main issue is how to get it into the game. It would be extremely impractical to actually put all 200+ tracks into the 2Ds audio files, and I'd rather not put a heavy load on an xml team already overburdened with the goods-resource conversion project. There is the custom music folder option, but I don't know if that can distinguish between era, and even if it could, could it distinguish between the new eras C2C adds?

As such, I'm putting this out there for those who have any ideas as to handle the situation. I'm no expert on xml files, but I like to think I have more experience in musical taste. But without a way to get it in, it's a moot point.

Nov 07, 2011, 11:56 PM
That should be easy... package the download so that all we have to do is drop it in our C2C mod file and select to overwrite everything that creates a conflict.

Aside from that, I'm not sure without looking exactly which files control the track references, but I don't think it'd be hard to find and manipulate with a text editor.

Nov 08, 2011, 12:08 AM
The issue isn't conflicts between files; that is indeed easily overwritten. The issue is how to get particular tracks in the game and for them to *only* play in particular eras. Say, all tracks in Folder X must only play in Prehistoric, all tracks in Folder Y must only play in Ancient, Folder Z is for Classical and so on. There are categorizations like this in both the vanilla CivIv and C2C soundtrack, but I'm not sure whether they have any actual function (meaning that putting tracks in, say, the folder "modern" automatically means that track will play during the modern era) or are merely there for administrative purposes.

Nov 08, 2011, 12:42 AM
If you can get this to work it sound like an awesome add-on pack for C2C.

Nov 08, 2011, 10:31 AM
Yeah, there are xml controls on the sound references... I'm not sure how to work all that but I don't think it'd be very hard to figure out. If I had time today I'd sort it out and let you know how to go about it but I've gotta go to work :P

Nov 08, 2011, 11:39 AM
Unfortunately it seems like the audio XML files are loaded in the exe and not the dll.
So we can't just enumerate files in directories and load them as if they were in the XML.

This means you have to change these files:

Probably only the last of these is usable as module.
Since this is extremely repetetive work, I would suggest to write a small script that automatically creates those files.

The era info should not be overwritten though but instead only the soundtracks redefined in a module.

Nov 08, 2011, 09:49 PM
Who's our resident scripter? I'm afraid my knowledge of the matter is rivalled only by my knowledge of Anasazi culture and medieval Polish history.

Nov 08, 2011, 10:00 PM
:lol: !

Nov 17, 2011, 08:23 PM
I'll take it then that there isn't currently a dedicated scripter on hand? Might have to outsource it, then...

Nov 18, 2011, 03:37 AM
I'll take it then that there isn't currently a dedicated scripter on hand? Might have to outsource it, then...
My time is quite limited at the moment so if you find someone else that would be good.
If not, then tell me by the beginning of next week and I'll try to squeeze it in before the beginning of my 2 week holiday at the end of the week.

Feb 16, 2012, 02:13 AM
With the audio update script present now, any plan to release that, Praetyre?

Feb 16, 2012, 09:07 AM
Example perl script I just whipped up (I've been working on file processing stuff all week so it all sprang to mind):

package QuickXMLTagGeneratingScript;

use strict;
use warnings;

my $era= "Ancient Era"; # << Whatever the XML expects.
my $dir = "PATH TO ANCIENT ERA MP3s";
my @files = <$dir/*>;

# Open up a temporary output files, create if needed.
# This will just store the XML tags for now.
open FILEONE, "+<", "C:\\File1.txt";
open FILETWO, "+<", "C:\\File2.txt";
open FILETHREE, "+<", "C:\\File3.txt";

# For the length of files array
foreach my $i (0 .. (@files - 1)) {

# If the file ends in .mp3
if ($files[$i] =~ /^.+.mp3$/) {

# Print in whatever format the XML Expects it, adds a new line to the end:
print FILEONE ("\<OPEN TAG\> $files($i) \<\\CLOSE TAG\>\n");
print FILETWO ("\<OPEN TAG\> $era, $files($i) \<\\CLOSE TAG\>\n");

} # Ends if file is mp3.
} # Ends for all files.

print "(@files) processed. Hit enter to continue.\n";

Just change the print output format to whatever the XML expects and then you can just do it quick and nasty with this script. It's not as smart as the script you guys were talking about, but you only have to copy/paste it from there. I assume you already know which sounds you want in different eras.

Obviously, this script won't work as is (it may not work at all, really don't know the civ4 xml structure), but if its helpful for you to use after slight tweaking, then feel free to use it :).

- Micael

Feb 16, 2012, 09:24 AM
@Micael: I have since then included a similar functionality as a Python script in C2C. You load/start a game in C2C and it runs and includes all files in specific folders (the EraName New folders in the soundtrack folder) as music files for the era. In addition it changes the title music to a random file in the Title folder.

It works by editing the XML files so the changes are active the next time you load the game:
## MusicUpdate
## Adds music files in special directories to the respective sound registration files.
## Chooses a random file in a specific directory as title music

import BugUtil
import BugPath
import os
import os.path
import random
import re
import shutil
import string

def init():
BugUtil.debug("MusicUpdate INIT.")

soundtrackFolder = BugPath.getModDir() + '/Assets/Sounds/Soundtrack/'
audioXMLFolder = BugPath.getModDir() + '/Assets/XML/Audio/'
titleFolder = soundtrackFolder + '/Title/'

eraNames = [ "Prehistoric", "Ancient", "Classical", "Medieval", "Renaissance", "Industrial", "Modern", "Transhuman", "Galactic", "Future" ]

defineFilename = audioXMLFolder + 'AudioDefines.xml'
scriptsFilename = audioXMLFolder + 'Audio2DScripts.xml'
eraInfoFilename = BugPath.getModDir() + '/Assets/XML/GameInfo/CIV4EraInfos.xml'

titleFilenames = os.listdir(titleFolder)
titleFile = random.choice(titleFilenames)
titleFile = os.path.splitext(titleFile)[0]

f = open(defineFilename, "r")
content =
content = re.sub(r'(<SoundID>SONG_OPENING_MENU</SoundID>\s*<Filename>)[^<]*',r'\1Sounds/Soundtrack/Title/'+titleFile,content)
f = open(defineFilename, "w")

f = open(eraInfoFilename, 'r')
infoFileContent =

toInsertDef = ""
toInsertScript = ""

for era in eraNames:
eraFolder = soundtrackFolder + era
eraNewFolder = eraFolder + 'New'
newFiles = os.listdir(eraNewFolder)
if newFiles:
toInsert = ""
for newFile in newFiles:
if os.path.isdir(eraNewFolder + '/' + newFile):
shutil.move(eraNewFolder + '/' + newFile, eraFolder + '/' + newFile)
fileTag = os.path.splitext(newFile)[0]
fileTagUpper = string.upper(fileTag)
fileTagUpper = re.sub(r'\s', r'_', fileTagUpper)
fileTagUpper = re.sub(r'[^A-Z0-9_]', r'', fileTagUpper)
toInsert = toInsert + "\n<EraInfoSoundtrack>AS2D_"+fileTagUpper+"</EraInfoSoundtrack>"
toInsertDef = toInsertDef + "<SoundData>\n<SoundID>SONG_"+fileTagUpper+"</SoundID>\n<Filename>Sounds/Soundtrack/"+era+"/"+fileTag+"</Filename>\n<LoadType>STREAMED</LoadType>\n<bIsCompressed>1</bIsCompressed>\n<bInGeneric>1</bInGeneric>\n</SoundData>\n"
toInsertScript = toInsertScript + "<Script2DSound>\n<ScriptID>AS2D_"+fileTagUpper+"</ScriptID>\n<SoundID>SONG_"+fileTagUpper+"</SoundID>\n<SoundType>GAME_MUSIC</SoundType>\n<iMinVolume>80</iMinVolume>\n<iMaxVolume>80</iMaxVolume>\n<iPitchChangeDown>0</iPitchChangeDown>\n<iPitchChangeUp>0</iPitchChangeUp>\n<iMinLeftPan>-1</iMinLeftPan>\n<iMaxLeftPan>-1</iMaxLeftPan>\n<iMinRightPan>-1</iMinRightPan>\n<iMaxRightPan>-1</iMaxRightPan>\n<bLooping>0</bLooping>\n<iMinTimeDelay>0</iMinTimeDelay>\n<iMaxTimeDelay>0</iMaxTimeDelay>\n<bTaperForSoundtracks>0</bTaperForSoundtracks>\n<iLengthOfSound>0</iLengthOfSound>\n<fMinDryLevel>1.0</fMinDryLevel>\n<fMaxDryLevel>1.0</fMaxDryLevel>\n<fMinWetLevel>0.0</fMinWetLevel>\n<fMaxWetLevel>0.0</fMaxWetLevel>\n<iNotPlayPercent>0</iNotPlayPercent>\n</Script2DSound>\n"
if toInsert:
infoFileContent = re.sub(r'(\<Type\>ERA_'+string.upper(era)+r'(?:.|\n)*?\<EraInfoSoundtracks\>)', r'\1'+toInsert, infoFileContent)

f = open(eraInfoFilename, 'w')

if toInsertDef:
f = open(defineFilename, 'r')
content =
content = re.sub(r'(\</SoundDatas\>)', toInsertDef+r'\1', content)
f = open(defineFilename, 'w')

f = open(scriptsFilename, 'r')
content =
content = re.sub(r'(\</Script2DSounds\>)', toInsertScript+r'\1', content)
f = open(scriptsFilename, 'w')

Feb 16, 2012, 09:35 AM

- Micael