Example #1
0
        public static bool ConvertWad2ToNewSoundFormat(string src, string dest)
        {
            /* PROCEDURE:
             * 1. Collect all sounds from Wad2
             * 2. Initialise the list of SoundInfoConversionRow, getting ID from TrCatalog
             * 3. Show the dialog to the user. Here he can load an additional catalog if he changed sounds via TRLE tools.
             *    He can also choose which sounds to export to Xml and if export also samples.
             * 4. Assign new IDs to sound infos
             * 5. Remap sounds in animcommands
             * 6. Optionally export samples if needed and bind them to sound infos
             * 7. Save Wad2 + Xml (if sounds are present)
             */

            try
            {
                // Load Wad2
                Wad2 wad = Wad2Loader.LoadFromFile(src, false);

                // Check if the Wad2 needs to be converted
                if (wad.SoundSystem != SoundSystem.Dynamic)
                {
                    return(true);
                }

                // Now collect all sound infos from obsolete lists and build a new list
                var soundInfos = wad.AllLoadedSoundInfos.Values.ToList();

                // Loop through each sound info and try to get the classic Id from TrCatalog.xml
                var conversionList = new List <SoundInfoConversionRow>();
                foreach (var soundInfo in soundInfos)
                {
                    var row = new SoundInfoConversionRow(soundInfo, soundInfo.Name);

                    // If user has changed name, result will be -1 and the user will need to manually set the new sound id
                    row.NewId = TrCatalog.TryGetSoundInfoIdByDescription(wad.GameVersion, soundInfo.Name);
                    if (row.NewId != -1)
                    {
                        row.NewName = TrCatalog.GetOriginalSoundName(wad.GameVersion, (uint)row.NewId);
                    }

                    conversionList.Add(row);
                }

                // Now we'll show a dialog with all conversion rows and the user will need to make some choices
                WadSounds sounds = null;
                using (var form = new Wad2SoundsConversionDialog(wad.GameVersion, conversionList))
                {
                    if (form.ShowDialog() == DialogResult.Cancel)
                    {
                        return(false);
                    }

                    // If the user has loaded a custom catalog, let's get a pointer to it
                    if (form.Sounds != null)
                    {
                        sounds = form.Sounds;
                    }
                }

                // Assign new Id and name
                foreach (var row in conversionList)
                {
                    row.SoundInfo.Id   = row.NewId;
                    row.SoundInfo.Name = row.NewName;
                }

                // Remap all sounds in animcommands
                foreach (var row in conversionList)
                {
                    if (row.NewId != -1)
                    {
                        foreach (var moveable in wad.Moveables)
                        {
                            foreach (var animation in moveable.Value.Animations)
                            {
                                foreach (var cmd in animation.AnimCommands)
                                {
                                    if (cmd.SoundInfoObsolete != null && cmd.SoundInfoObsolete == row.SoundInfo)
                                    {
                                        cmd.Parameter2        = (short)((cmd.Parameter2 & 0xc000) | row.NewId);
                                        cmd.SoundInfoObsolete = null;
                                    }
                                }
                            }
                        }
                    }
                }

                // Bind samples (only if additional catalog was loaded, TrCatalog has not samples names)
                if (sounds != null)
                {
                    foreach (var row in conversionList)
                    {
                        if (row.SaveToXml)
                        {
                            if (row.ExportSamples)
                            {
                                // We export samples only if user has marked both Export to Xml and Export samples checkboxes
                                var samples = new List <string>();
                                foreach (var sample in row.SoundInfo.Samples)
                                {
                                    if (sample.IsLoaded)
                                    {
                                        // If sample is valid, export the .WAV file to the same directory of Wad2
                                        string sampleName = row.NewName.ToLower() + "_" + row.SoundInfo.Samples.IndexOf(sample) + ".wav";
                                        samples.Add(sampleName);
                                        File.WriteAllBytes(Path.GetDirectoryName(dest) + "\\" + sampleName, sample.Data);
                                    }
                                }

                                // Assign new samples names
                                row.SoundInfo.Samples.Clear();
                                foreach (var sample in samples)
                                {
                                    row.SoundInfo.Samples.Add(new WadSample(sample));
                                }
                            }
                            else
                            {
                                // If samples count is the same then use samples from catalog
                                var refInfo = sounds.TryGetSoundInfo(row.NewId);

                                if (refInfo != null && row.SoundInfo.Samples.Count == refInfo.Samples.Count)
                                {
                                    row.SoundInfo.Samples.Clear();
                                    row.SoundInfo.Samples.AddRange(refInfo.Samples);
                                }
                                else
                                {
                                    row.SoundInfo.Samples.Clear();
                                }
                            }
                        }
                    }
                }

                // Create the new sounds archive
                foreach (var row in conversionList)
                {
                    if (row.SaveToXml)
                    {
                        wad.Sounds.SoundInfos.Add(row.SoundInfo);
                    }
                }

                // Sort sound infos
                wad.Sounds.SoundInfos.Sort((a, b) => a.Id.CompareTo(b.Id));

                // Make a backup copy
                if (src == dest)
                {
                    int    index          = 0;
                    string backupFilename = "";
                    while (true)
                    {
                        backupFilename = dest + "." + index + ".bak";
                        if (!File.Exists(backupFilename))
                        {
                            break;
                        }
                        index++;
                    }

                    File.Copy(src, backupFilename, true);
                }

                // Save Wad2 with Xml sounds
                wad.SoundSystem = SoundSystem.Xml;
                Wad2Writer.SaveToFile(wad, dest);

                // Finished!
                return(true);
            }
            catch (Exception e)
            {
                return(false);
            }
        }
Example #2
0
        public static bool ConvertPrj2ToNewSoundFormat(Level level, string src, string dest, string soundsCatalog, bool save)
        {
            /* PROCEDURE:
             * 1. Collect all sound sources of level: if embedded sound info is null, then it's a sound source
             *    that is referencing a Wad file and we should just remap it, otherwise it's a custom sound source
             *    created inside Tomb Editor and we must export it to Xml and we must export samples too
             * 2. Try to guess the ID for Wad sounds and generate instead a new ID above 602 for custom sounds
             *    (ID = 602 is the start of TR1 area of extended soundmap of TRNG and it should be rarely used)
             * 3. Show the dialog to the user. Here he can load an additional catalog if he changed sounds via TRLE tools
             * 4. Assign new IDs and new names to sound infos
             * 5. Remap sound sources
             * 6. Export samples if needed
             * 7. Save Prj2 + Xml if custom sounds are present
             */

            try
            {
                // Check for sound system
                if (level.Settings.SoundSystem == SoundSystem.Xml)
                {
                    return(true);
                }

                // Infer the wad version from level version
                TRVersion.Game version = level.Settings.GameVersion.Native();

                // Collect all sounds to remap
                var conversionList = new List <SoundInfoConversionRow>();

                // We start from sound id = 602 which is the TR1 sound area of TRNG extended soundmap.
                // This area is reserved for TR1 enemies and so it *** should *** be used rarely
                int lastSoundId = 602;

                foreach (var room in level.Rooms)
                {
                    if (room != null)
                    {
                        foreach (var obj in room.Objects)
                        {
                            if (obj is SoundSourceInstance)
                            {
                                SoundSourceInstance soundSource = obj as SoundSourceInstance;

                                if (soundSource.WadReferencedSoundName != null && soundSource.WadReferencedSoundName != "")
                                {
                                    if (!conversionList.Select(f => f.OldName).Contains(soundSource.WadReferencedSoundName))
                                    {
                                        // First try to get sound name from TrCatalog
                                        int newId = TrCatalog.TryGetSoundInfoIdByDescription(version, soundSource.WadReferencedSoundName);

                                        var row = new SoundInfoConversionRow(null, soundSource.WadReferencedSoundName);
                                        if (newId == -1)
                                        {
                                            // If sound was not found in catalog, then assign a generic Id and ask to the user
                                            row.NewName = Regex.Replace(soundSource.WadReferencedSoundName, "[^A-Za-z0-9 _]", "").ToUpper();
                                            row.NewId   = lastSoundId++;
                                        }
                                        else
                                        {
                                            // Otherwise, we are lucky, and we can just assign the correct Id
                                            row.NewName = TrCatalog.GetOriginalSoundName(version, (uint)newId);
                                            row.NewId   = newId;
                                        }

                                        conversionList.Add(row);
                                    }
                                }
                                else if (soundSource.EmbeddedSoundInfo != null)
                                {
                                    bool found = false;
                                    foreach (var r in conversionList)
                                    {
                                        if (r.SoundInfo != null && r.SoundInfo == soundSource.EmbeddedSoundInfo)
                                        {
                                            found = true;
                                            break;
                                        }
                                    }

                                    if (found)
                                    {
                                        continue;
                                    }

                                    // Let's first try a search in TrCatalog, maybe we are lucky
                                    // First try to get sound name from TrCatalog

                                    /*int newId = TrCatalog.TryGetSoundInfoIdByDescription(version, soundSource.EmbeddedSoundInfo.Name);
                                     *
                                     * var row = new SoundInfoConversionRow(soundSource.EmbeddedSoundInfo, soundSource.EmbeddedSoundInfo.Name);
                                     * if (newId == -1)
                                     * {
                                     *  // If sound was not found in catalog, then assign a generic Id and ask to the user
                                     *  row.NewName = Regex.Replace(soundSource.EmbeddedSoundInfo.Name, "[^A-Za-z0-9 _]", "").ToUpper();
                                     *  row.NewId = lastSoundId++;
                                     * }
                                     * else
                                     * {
                                     *  // Otherwise, we are lucky, and we can just assign the correct Id
                                     *  row.NewName = TrCatalog.GetOriginalSoundName(version, (uint)newId);
                                     *  row.NewId = newId;
                                     * }*/

                                    // TODO: Lwmte proposed to also there check in TrCatalog, but we should assume that
                                    // embedded sound sources are custom sound sources, created by thhe user with custom samples
                                    // and we should think carrefully about this
                                    var row = new SoundInfoConversionRow(soundSource.EmbeddedSoundInfo, soundSource.EmbeddedSoundInfo.Name);
                                    row.NewName = Regex.Replace(soundSource.EmbeddedSoundInfo.Name, "[^A-Za-z0-9 _]", "").ToUpper();
                                    row.NewId   = lastSoundId++;

                                    // These flags are handle by Tomb Editor and set only for embedded sound sources
                                    row.SaveToXml     = true;
                                    row.ExportSamples = true;

                                    conversionList.Add(row);
                                }
                            }
                        }
                    }
                }

                WadSounds sounds = null;

                // Now we'll show a dialog with all conversion rows and the user will need to make some choices
                if (conversionList.Count != 0)
                {
                    using (var form = new Prj2SoundsConversionDialog(version, conversionList))
                    {
                        if (form.ShowDialog() == DialogResult.Cancel)
                        {
                            return(false);
                        }

                        // If the user has loaded an additional catalog, let's get a pointer to it
                        if (form.Sounds != null)
                        {
                            sounds = form.Sounds;
                        }
                    }
                }

                // Assign new Id and name
                foreach (var row in conversionList)
                {
                    if (row.SoundInfo != null)
                    {
                        row.SoundInfo.Id   = row.NewId;
                        row.SoundInfo.Name = row.NewName;
                    }
                }

                // We'll export only embedded sound sources
                var newSounds = new WadSounds();

                // Remap sound sources
                foreach (var room in level.Rooms)
                {
                    if (room != null)
                    {
                        foreach (var obj in room.Objects)
                        {
                            if (obj is SoundSourceInstance)
                            {
                                SoundSourceInstance soundSource = obj as SoundSourceInstance;
                                if (soundSource.WadReferencedSoundName != null && soundSource.WadReferencedSoundName != "")
                                {
                                    soundSource.SoundId = -1;
                                    foreach (var row in conversionList)
                                    {
                                        if (row.OldName == soundSource.WadReferencedSoundName && row.NewId != -1)
                                        {
                                            soundSource.SoundId = row.NewId;
                                            break;
                                        }
                                    }

                                    soundSource.WadReferencedSoundName = "";
                                    soundSource.EmbeddedSoundInfo      = null;
                                }
                                else if (soundSource.EmbeddedSoundInfo != null)
                                {
                                    // We export embedded sound infos
                                    if (!newSounds.SoundInfos.Contains(soundSource.EmbeddedSoundInfo))
                                    {
                                        newSounds.SoundInfos.Add(soundSource.EmbeddedSoundInfo);
                                    }

                                    soundSource.SoundId = -1;
                                    foreach (var row in conversionList)
                                    {
                                        if (row.SoundInfo == soundSource.EmbeddedSoundInfo && row.NewId != -1)
                                        {
                                            soundSource.SoundId = row.NewId;

                                            // Try to bind samples from additional catalog, if loaded

                                            /*if (sounds != null)
                                             * {
                                             *  WadSoundInfo catalogInfo = sounds.TryGetSoundInfo(row.NewId);
                                             *  if (catalogInfo != null && catalogInfo.Samples.Count > 0)
                                             *  {
                                             *      soundSource.EmbeddedSoundInfo.Samples.Clear();
                                             *      soundSource.EmbeddedSoundInfo.Samples.AddRange(catalogInfo.Samples);
                                             *      // TODO: in theory if valid samples are found in catalog, we shouldn't need to
                                             *      // export them
                                             *      row.ExportSamples = false;
                                             *  }
                                             * }*/

                                            break;
                                        }
                                    }

                                    soundSource.WadReferencedSoundName = "";
                                    soundSource.EmbeddedSoundInfo      = null;
                                }
                            }
                        }
                    }
                }

                // Export samples
                foreach (var row in conversionList)
                {
                    if (row.SoundInfo != null && row.ExportSamples)
                    {
                        var samples = new List <string>();
                        foreach (var sample in row.SoundInfo.Samples)
                        {
                            if (sample.IsLoaded)
                            {
                                string sampleName = Path.GetFileNameWithoutExtension(dest) + "_" + row.NewName.ToLower() + "_" + row.SoundInfo.Samples.IndexOf(sample) + ".wav";
                                samples.Add(sampleName);
                                File.WriteAllBytes(Path.GetDirectoryName(dest) + "\\" + sampleName, sample.Data);
                            }
                        }

                        row.SoundInfo.Samples.Clear();
                        foreach (var sample in samples)
                        {
                            row.SoundInfo.Samples.Add(new WadSample(sample));
                        }
                    }
                }

                // Sort sound infos
                newSounds.SoundInfos.Sort((a, b) => a.Id.CompareTo(b.Id));

                // Make a backup copy
                if (save && src == dest)
                {
                    int    index          = 0;
                    string backupFilename = "";
                    while (true)
                    {
                        backupFilename = dest + "." + index + ".bak";
                        if (!File.Exists(backupFilename))
                        {
                            break;
                        }
                        index++;
                    }

                    File.Copy(src, backupFilename, true);
                }

                // Save Xml to file
                if (newSounds.SoundInfos.Count != 0)
                {
                    string xmlFileName = Path.GetDirectoryName(dest) + "\\" + Path.GetFileNameWithoutExtension(dest) + ".xml";
                    WadSounds.SaveToXml(xmlFileName, newSounds);

                    // Assign Xml to level settings
                    level.Settings.SoundsCatalogs.Add(new ReferencedSoundsCatalog(level.Settings,
                                                                                  level.Settings.MakeRelative(xmlFileName, VariableType.LevelDirectory)));
                }

                level.Settings.SoundSystem = SoundSystem.Xml;

                // Try to get Xml and SFX files
                foreach (var wadRef in level.Settings.Wads)
                {
                    if (wadRef != null && wadRef.LoadException == null)
                    {
                        string wadPath   = level.Settings.MakeAbsolute(wadRef.Path);
                        string extension = Path.GetExtension(wadPath).ToLower();

                        if (extension == ".wad")
                        {
                            string sfxPath = Path.GetDirectoryName(wadPath) + "\\" + Path.GetFileNameWithoutExtension(wadPath) + ".sfx";
                            if (File.Exists(sfxPath))
                            {
                                sounds = WadSounds.ReadFromFile(sfxPath);
                                if (sounds != null)
                                {
                                    level.Settings.SoundsCatalogs.Add(new ReferencedSoundsCatalog(level.Settings,
                                                                                                  level.Settings.MakeRelative(sfxPath, VariableType.LevelDirectory)));
                                }
                            }
                        }
                        else if (extension == ".wad2")
                        {
                            string xmlPath = Path.GetDirectoryName(wadPath) + "\\" + Path.GetFileNameWithoutExtension(wadPath) + ".xml";
                            if (File.Exists(xmlPath))
                            {
                                sounds = WadSounds.ReadFromFile(xmlPath);
                                if (sounds != null)
                                {
                                    level.Settings.SoundsCatalogs.Add(new ReferencedSoundsCatalog(level.Settings,
                                                                                                  level.Settings.MakeRelative(xmlPath, VariableType.LevelDirectory)));
                                }
                            }
                        }
                    }
                }

                // Assign sounds if possible
                foreach (var soundRef in level.Settings.SoundsCatalogs)
                {
                    if (soundRef.LoadException == null)
                    {
                        foreach (var sound in soundRef.Sounds.SoundInfos)
                        {
                            if (!level.Settings.SelectedSounds.Contains(sound.Id))
                            {
                                level.Settings.SelectedSounds.Add(sound.Id);
                            }
                        }
                    }
                }

                // Save Prj2 with Xml sounds
                if (save)
                {
                    using (var stream = File.OpenWrite(dest))
                        Prj2Writer.SaveToPrj2(stream, level);
                }

                return(true);
            }
            catch (Exception ex)
            {
                return(false);
            }
        }