Пример #1
0
        public override void ConvertData(ProjectFile pf)
        {
            EmptyRefsForNamed(pf.DataHandle.GetChunk <GMChunkSOND>().List, pf.Sounds, (asset) =>
            {
                GMSound sound = (GMSound)asset;

                BufferRegion buff;
                if ((sound.Flags & AudioEntryFlags.IsEmbedded) != AudioEntryFlags.IsEmbedded &&
                    (sound.Flags & AudioEntryFlags.IsCompressed) != AudioEntryFlags.IsCompressed)
                {
                    buff = null;
                }
                else
                {
                    if (pf._CachedAudioChunks.TryGetValue(sound.GroupID, out var chunk))
                    {
                        buff = chunk.List[sound.AudioID].Data;
                    }
                    else
                    {
                        pf.WarningHandler.Invoke(ProjectFile.WarningType.MissingAudioGroup, $"Missing audio group ID {sound.GroupID} for {sound.Name?.Content ?? "<null>"}");
                        buff = null;
                    }
                }

                if (pf.AudioGroupSettings == null)
                {
                    return(new CachedSoundRefData(buff, ""));
                }

                return(new CachedSoundRefData(buff,
                                              (sound.GroupID >= 0 && sound.GroupID < pf.AudioGroupSettings.AudioGroups.Count)
                                                    ? pf.AudioGroupSettings.AudioGroups[sound.GroupID] : ""));
            });
        }
Пример #2
0
        public static void Sound(ProjectWriter writer, GMSound self, GMProject _)
        {
            writer.Write(self.Name);
            writer.Write(self.Version);
            writer.Write((int)self.Kind);
            writer.Write(self.FileType);
            writer.Write(self.FileName);
            if (self.Data != null)
            {
                writer.Write(true);
                writer.Write(self.Data.Length);
                writer.Write(self.Data);
            }
            else
            {
                writer.Write(false);
            }

            writer.Write(self.GetEffectsInt());
            writer.Write(self.Volume);
            writer.Write(self.Panning);
            writer.Write(self.Preload);
        }
Пример #3
0
        /// <summary>
        /// Reads a Game Maker project file
        /// </summary>
        public void ReadProject(string file)
        {
            // If the file does not exist, throw exception
            if (File.Exists(file) == false)
            {
                throw new Exception("The Game Maker project file does not exist.");
            }

            // Get file extension
            string ext = file.Substring(file.LastIndexOf('.')).ToLower();

            // If a GMS project file
            if (ext == ".gmx")
            {
                // Read in the project as a Game Maker Studio project and return
                ReadProjectGMS(file);
                return;
            }

            // Get file size
            FileInfo info   = new FileInfo(file);
            long     length = info.Length;

            // Create a new GM file reader
            using (GMFileReader reader = new GMFileReader(new FileStream(file, FileMode.Open, FileAccess.Read)))
            {
                // Progress event
                ProgressChanged("Starting project read...", reader.BaseStream.Position, length);

                // Read the magic number
                int id = reader.ReadGMInt();

                // If the magic number was incorrect, not a Game Maker project file
                if (id != 1234321)
                {
                    throw new Exception("Not a valid Game Maker project file.");
                }

                // Get Game Maker project file version
                int version = reader.ReadGMInt();

                // Check version
                switch (version)
                {
                case 500: this.GameMakerVersion = GMVersionType.GameMaker50; break;

                case 510: this.GameMakerVersion = GMVersionType.GameMaker51; break;

                case 520: this.GameMakerVersion = GMVersionType.GameMaker52; break;

                case 530: this.GameMakerVersion = GMVersionType.GameMaker53; break;

                case 600: this.GameMakerVersion = GMVersionType.GameMaker60; break;

                case 701: this.GameMakerVersion = GMVersionType.GameMaker70; break;

                case 800: this.GameMakerVersion = GMVersionType.GameMaker80; break;

                case 810: this.GameMakerVersion = GMVersionType.GameMaker81; break;
                }

                // Skip over reserved bytes
                if (version < 600)
                {
                    reader.ReadGMBytes(4);
                }

                // Game Maker 7 project file encryption
                if (version == 701)
                {
                    // Bill and Fred, psssttt they like each other ;)
                    int bill = reader.ReadGMInt();
                    int fred = reader.ReadGMInt();

                    // Skip bytes to treasure.
                    reader.ReadGMBytes(bill * 4);

                    // Get the seed for swap table
                    int seed = reader.ReadGMInt();

                    // Skip bytes to get out of the junk yard
                    reader.ReadGMBytes(fred * 4);

                    // Read first byte of Game id (Not encrypted)
                    byte b = reader.ReadByte();

                    // Set the seed
                    reader.SetSeed(seed);

                    // Read game id
                    id = reader.ReadGMInt(b);
                }
                else  // Read game id normally
                {
                    id = reader.ReadGMInt();
                }

                // Skip unknown bytes
                reader.ReadGMBytes(16);

                // Read settings
                ProgressChanged("Reading Settings...", reader.BaseStream.Position, length);

                // Read main project objects
                this.Settings = GMSettings.ReadSettings(reader);
                this.Settings.GameIdentifier = id;

                // If the version is greater than Game Maker 7.0
                if (version > 701)
                {
                    // Read triggers and constants.
                    this.Triggers           = GMTrigger.ReadTriggers(reader);
                    this.Settings.Constants = GMConstant.ReadConstants(reader);
                }

                // Read sounds
                ProgressChanged("Reading Sounds...", reader.BaseStream.Position, length);
                this.Sounds = GMSound.ReadSounds(reader);

                // Read sprites
                ProgressChanged("Reading Sprites...", reader.BaseStream.Position, length);
                this.Sprites = GMSprite.ReadSprites(reader);

                // Read backgrounds
                ProgressChanged("Reading Backgrounds...", reader.BaseStream.Position, length);
                this.Backgrounds = GMBackground.ReadBackgrounds(reader);

                // Read paths
                ProgressChanged("Reading Paths...", reader.BaseStream.Position, length);
                this.Paths = GMPath.ReadPaths(reader);

                // Read scripts
                ProgressChanged("Reading Scripts...", reader.BaseStream.Position, length);
                this.Scripts = GMScript.ReadScripts(reader);

                // Get version
                int version2 = reader.ReadGMInt();

                // Check version
                if (version2 != 440 && version2 != 540 && version2 != 800)
                {
                    throw new Exception("Unsupported Pre-Font/Pre-Data File object version.");
                }

                // If version is old, read data files else, read fonts.
                if (version2 == 440)
                {
                    // Read data files
                    ProgressChanged("Reading Data Files...", reader.BaseStream.Position, length);
                    this.DataFiles = GMDataFile.ReadDataFiles(reader);
                }
                else
                {
                    // Read fonts
                    ProgressChanged("Reading Fonts...", reader.BaseStream.Position, length);
                    this.Fonts = GMFont.ReadFonts(version2, reader);
                }

                // Read timelines
                ProgressChanged("Reading Timelines...", reader.BaseStream.Position, length);
                this.Timelines = GMTimeline.ReadTimelines(reader);

                // Read objects
                ProgressChanged("Reading Objects...", reader.BaseStream.Position, length);
                this.Objects = GMObject.ReadObjects(reader);

                // Read rooms
                ProgressChanged("Reading Rooms...", reader.BaseStream.Position, length);
                this.Rooms = GMRoom.ReadRooms(this.Objects, reader);

                // Read last ids for instances and tiles
                this.LastInstanceId = reader.ReadGMInt();
                this.LastTileId     = reader.ReadGMInt();

                // If the version is above 6.1, read include files and packages
                if (version >= 700)
                {
                    // Read includes
                    ProgressChanged("Reading Includes...", reader.BaseStream.Position, length);
                    this.Settings.Includes = GMInclude.ReadIncludes(reader);

                    // Read packages
                    ProgressChanged("Reading Packages...", reader.BaseStream.Position, length);
                    this.Packages.AddRange(GMPackage.ReadPackages(reader));
                }

                // Read game information
                ProgressChanged("Reading Game Information...", reader.BaseStream.Position, length);
                this.GameInformation = GMGameInformation.ReadGameInformation(reader);

                // Get version
                version = reader.ReadGMInt();

                // Check version
                if (version != 500)
                {
                    throw new Exception("Unsupported Post-Game Information object version.");
                }

                // Read libraries
                ProgressChanged("Reading Libraries...", reader.BaseStream.Position, length);
                this.Libraries = GMLibrary.ReadLibraries(reader);

                // Read project tree
                ProgressChanged("Reading Project Tree...", reader.BaseStream.Position, length);
                this.ProjectTree = GMNode.ReadTree(file.Substring(file.LastIndexOf(@"\") + 1), reader);

                // Progress event
                ProgressChanged("Finished Reading Project.", reader.BaseStream.Position, length);
            }
        }
Пример #4
0
        private static void ConvertSounds(ProjectFile pf)
        {
            var dataAssets = ((GMChunkSOND)pf.DataHandle.Chunks["SOND"]).List;
            var agrp       = (GMChunkAGRP)pf.DataHandle.Chunks["AGRP"];
            var groups     = agrp.List;

            bool updatedVersion = pf.DataHandle.VersionInfo.IsNumberAtLeast(1, 0, 0, 9999);

            // First, sort sounds alphabetically
            List <AssetSound> sortedSounds = updatedVersion ? pf.Sounds.OrderBy(x => x.Name).ToList() : pf.Sounds;

            // Get all the AUDO chunk handles in the game
            GMChunkAUDO defaultChunk = (GMChunkAUDO)pf.DataHandle.Chunks["AUDO"];

            defaultChunk.List.Clear();
            Dictionary <string, GMChunkAUDO> audioChunks       = new Dictionary <string, GMChunkAUDO>();
            Dictionary <string, int>         audioChunkIndices = new Dictionary <string, int>();

            if (agrp.AudioData != null)
            {
                for (int i = 1; i < groups.Count; i++)
                {
                    if (agrp.AudioData.ContainsKey(i))
                    {
                        var currChunk = (GMChunkAUDO)agrp.AudioData[i].Chunks["AUDO"];
                        currChunk.List.Clear();
                        audioChunks.Add(groups[i].Name.Content, currChunk);
                        audioChunkIndices.Add(groups[i].Name.Content, i);
                    }
                }
            }

            dataAssets.Clear();
            Dictionary <AssetSound, GMSound> finalMap = new Dictionary <AssetSound, GMSound>();

            for (int i = 0; i < sortedSounds.Count; i++)
            {
                AssetSound asset     = sortedSounds[i];
                GMSound    dataAsset = new GMSound()
                {
                    Name    = pf.DataHandle.DefineString(asset.Name),
                    Volume  = asset.Volume,
                    Flags   = GMSound.AudioEntryFlags.Regular,
                    Effects = 0,
                    Pitch   = asset.Pitch,
                    File    = pf.DataHandle.DefineString(asset.OriginalSoundFile),
                    Type    = (asset.Type != null) ? pf.DataHandle.DefineString(asset.Type) : null
                };
                finalMap[asset] = dataAsset;

                switch (asset.Attributes)
                {
                case AssetSound.Attribute.CompressedStreamed:
                    if (updatedVersion)
                    {
                        dataAsset.AudioID = -1;
                    }
                    else
                    {
                        dataAsset.AudioID = defaultChunk.List.Count - 1;
                    }
                    dataAsset.GroupID = pf.DataHandle.VersionInfo.BuiltinAudioGroupID;     // might be wrong

                    File.WriteAllBytes(Path.Combine(pf.DataHandle.Directory, asset.SoundFile), asset.SoundFileBuffer);
                    break;

                case AssetSound.Attribute.UncompressOnLoad:
                case AssetSound.Attribute.Uncompressed:
                    dataAsset.Flags |= GMSound.AudioEntryFlags.IsEmbedded;
                    goto case AssetSound.Attribute.CompressedNotStreamed;

                case AssetSound.Attribute.CompressedNotStreamed:
                    if (asset.Attributes != AssetSound.Attribute.Uncompressed)
                    {
                        dataAsset.Flags |= GMSound.AudioEntryFlags.IsCompressed;
                    }

                    int         ind;
                    GMChunkAUDO chunk;
                    if (!audioChunkIndices.TryGetValue(asset.AudioGroup, out ind))
                    {
                        ind   = pf.DataHandle.VersionInfo.BuiltinAudioGroupID;   // might be wrong
                        chunk = defaultChunk;
                    }
                    else
                    {
                        chunk = audioChunks[asset.AudioGroup];
                    }

                    dataAsset.GroupID = ind;
                    dataAsset.AudioID = chunk.List.Count;
                    chunk.List.Add(new GMAudio()
                    {
                        Data = asset.SoundFileBuffer
                    });
                    break;
                }
            }

            // Actually add sounds to the data
            foreach (AssetSound snd in pf.Sounds)
            {
                dataAssets.Add(finalMap[snd]);
            }
        }
Пример #5
0
        /// <summary>
        /// Reads all sounds from Game Maker project file.
        /// </summary>
        private GMList<GMSound> ReadSounds()
        {
            // Get version.
            int version = ReadInt();

            // Check version.
            if (version != 400 && version != 800)
                throw new Exception("Unsupported Pre-Sound object version.");

            // Create a new sound list.
            GMList<GMSound> sounds = new GMList<GMSound>();

            // Amount of sound ids.
            int num = ReadInt();

            // Iterate through sounds.
            for (int i = 0; i < num; i++)
            {
                // If version is 8.0, start inflate.
                if (version == 800)
                    Decompress();

                // If the sound at index does not exists, continue.
                if (ReadBool() == false)
                {
                    sounds.LastId++;
                    EndDecompress();
                    continue;
                }

                // Create sound object.
                GMSound sound = new GMSound();

                // Set sound id.
                sound.Id = i;

                // Read sound data.
                sound.Name = ReadString();

                // If version is 8.0, get last changed.
                if (version == 800)
                    sound.LastChanged = ReadDouble();

                // Get version.
                version = ReadInt();

                // Check version.
                if (version != 440 && version != 600 && version != 800)
                    throw new Exception("Unsupported Sound object version.");

                // Check version.
                if (version == 440)
                    sound.Kind = (SoundKind)ReadInt();
                else
                    // Read sound data.
                    sound.Type = (SoundType)ReadInt();

                // Read sound data.
                sound.FileType = ReadString();

                // Check version.
                if (version == 440)
                {
                    // If sound data exists, read it.
                    if ((int)sound.Kind != -1)
                        sound.Data = ReadBytes(ReadInt());

                    // Read sound data.
                    sound.AllowSoundEffects = ReadBool();
                    sound.Buffers = ReadInt();
                    sound.LoadOnlyOnUse = ReadBool();
                }
                else
                {
                    // Read sound data.
                    sound.FileName = ReadString();

                    // If sound data exists, read it.
                    if (ReadBool() == true)
                        sound.Data = ReadBytes(ReadInt());

                    // Read sound data.
                    sound.Effects = ReadInt();
                    sound.Volume = ReadDouble();
                    sound.Pan = ReadDouble();
                    sound.Preload = ReadBool();
                }

                // End object inflate.
                EndDecompress();

                // Add sound.
                sounds.Add(sound);
            }

            // Return sounds.
            return sounds;
        }
Пример #6
0
        public static List <Asset> ConvertSounds(GMData data)
        {
            var dataAssets = ((GMChunkSOND)data.Chunks["SOND"]).List;
            var agrp       = (GMChunkAGRP)data.Chunks["AGRP"];
            var groups     = agrp.List;

            // Get all the AUDO chunk handles in the game
            Dictionary <int, GMChunkAUDO> audioChunks = new Dictionary <int, GMChunkAUDO>()
            {
                { data.VersionInfo.BuiltinAudioGroupID, (GMChunkAUDO)data.Chunks["AUDO"] }
            };

            if (agrp.AudioData != null)
            {
                for (int i = 1; i < groups.Count; i++)
                {
                    if (agrp.AudioData.ContainsKey(i))
                    {
                        audioChunks.Add(i, (GMChunkAUDO)agrp.AudioData[i].Chunks["AUDO"]);
                    }
                }
            }

            List <Asset> list = new List <Asset>();

            for (int i = 0; i < dataAssets.Count; i++)
            {
                GMSound    asset        = dataAssets[i];
                AssetSound projectAsset = new AssetSound()
                {
                    Name              = asset.Name.Content,
                    AudioGroup        = (asset.GroupID >= 0 && asset.GroupID < groups.Count) ? groups[asset.GroupID].Name.Content : "",
                    Volume            = asset.Volume,
                    Pitch             = asset.Pitch,
                    Type              = asset.Type?.Content,
                    OriginalSoundFile = asset.File.Content,
                    SoundFile         = asset.File.Content
                };

                if ((asset.Flags & AudioEntryFlags.IsEmbedded) != AudioEntryFlags.IsEmbedded &&
                    (asset.Flags & AudioEntryFlags.IsCompressed) != AudioEntryFlags.IsCompressed)
                {
                    // External file
                    projectAsset.Attributes = AssetSound.Attribute.CompressedStreamed;

                    string soundFilePath = Path.Combine(data.Directory, asset.File.Content);
                    if (!soundFilePath.EndsWith(".ogg") && !soundFilePath.EndsWith(".mp3"))
                    {
                        soundFilePath += ".ogg";
                    }

                    if (File.Exists(soundFilePath))
                    {
                        projectAsset.SoundFileBuffer = File.ReadAllBytes(soundFilePath);
                        if (!projectAsset.SoundFile.Contains("."))
                        {
                            projectAsset.SoundFile += Path.GetExtension(soundFilePath);
                        }
                    }
                }
                else
                {
                    // Internal file
                    projectAsset.SoundFileBuffer = audioChunks[asset.GroupID].List[asset.AudioID].Data;

                    if ((asset.Flags & AudioEntryFlags.IsCompressed) == AudioEntryFlags.IsCompressed)
                    {
                        // But compressed!
                        if ((asset.Flags & AudioEntryFlags.IsEmbedded) == AudioEntryFlags.IsEmbedded)
                        {
                            projectAsset.Attributes = AssetSound.Attribute.UncompressOnLoad;
                        }
                        else
                        {
                            projectAsset.Attributes = AssetSound.Attribute.CompressedNotStreamed;
                        }
                        if (projectAsset.SoundFileBuffer.Length > 4 && !projectAsset.SoundFile.Contains("."))
                        {
                            if (projectAsset.SoundFileBuffer[0] == 'O' &&
                                projectAsset.SoundFileBuffer[1] == 'g' &&
                                projectAsset.SoundFileBuffer[2] == 'g' &&
                                projectAsset.SoundFileBuffer[3] == 'S')
                            {
                                projectAsset.SoundFile += ".ogg";
                            }
                            else
                            {
                                projectAsset.SoundFile += ".mp3";
                            }
                        }
                    }
                    else
                    {
                        projectAsset.Attributes = AssetSound.Attribute.Uncompressed;
                        if (!projectAsset.SoundFile.Contains("."))
                        {
                            projectAsset.SoundFile += ".wav";
                        }
                    }
                }

                list.Add(projectAsset);
            }
            return(list);
        }
Пример #7
0
        public override void ConvertData(ProjectFile pf, int index)
        {
            GMSound asset = (GMSound)pf.Sounds[index].DataAsset;

            AssetSound projectAsset = new AssetSound()
            {
                Name              = asset.Name?.Content,
                AudioGroup        = ((CachedSoundRefData)pf.Sounds[index].CachedData).AudioGroupName,
                Volume            = asset.Volume,
                Pitch             = asset.Pitch,
                Type              = asset.Type?.Content,
                OriginalSoundFile = asset.File.Content,
                SoundFile         = asset.File.Content
            };

            if ((asset.Flags & AudioEntryFlags.IsEmbedded) != AudioEntryFlags.IsEmbedded &&
                (asset.Flags & AudioEntryFlags.IsCompressed) != AudioEntryFlags.IsCompressed)
            {
                // External file
                projectAsset.Attributes = AssetSound.Attribute.CompressedStreamed;

                string soundFilePath = Path.Combine(pf.DataHandle.Directory, asset.File.Content);
                if (!soundFilePath.EndsWith(".ogg") && !soundFilePath.EndsWith(".mp3"))
                {
                    soundFilePath += ".ogg";
                }

                if (File.Exists(soundFilePath))
                {
                    projectAsset.SoundFileBuffer = new BufferRegion(File.ReadAllBytes(soundFilePath));
                    if (!projectAsset.SoundFile.Contains("."))
                    {
                        projectAsset.SoundFile += Path.GetExtension(soundFilePath);
                    }
                }
            }
            else
            {
                // Internal file
                projectAsset.SoundFileBuffer = pf._CachedAudioChunks[asset.GroupID].List[asset.AudioID].Data;

                if ((asset.Flags & AudioEntryFlags.IsCompressed) == AudioEntryFlags.IsCompressed)
                {
                    // But compressed!
                    if ((asset.Flags & AudioEntryFlags.IsEmbedded) == AudioEntryFlags.IsEmbedded)
                    {
                        projectAsset.Attributes = AssetSound.Attribute.UncompressOnLoad;
                    }
                    else
                    {
                        projectAsset.Attributes = AssetSound.Attribute.CompressedNotStreamed;
                    }
                    if (projectAsset.SoundFileBuffer.Length > 4 && !projectAsset.SoundFile.Contains("."))
                    {
                        var span = projectAsset.SoundFileBuffer.Memory.Span;
                        if (span[0] == 'O' && span[1] == 'g' && span[2] == 'g' && span[3] == 'S')
                        {
                            projectAsset.SoundFile += ".ogg";
                        }
                        else
                        {
                            projectAsset.SoundFile += ".mp3";
                        }
                    }
                }
                else
                {
                    projectAsset.Attributes = AssetSound.Attribute.Uncompressed;
                    if (!projectAsset.SoundFile.Contains("."))
                    {
                        projectAsset.SoundFile += ".wav";
                    }
                }
            }

            pf.Sounds[index].Asset = projectAsset;
        }
Пример #8
0
        public override void ConvertProject(ProjectFile pf)
        {
            var dataAssets = pf.DataHandle.GetChunk <GMChunkSOND>().List;
            var agrp       = pf.DataHandle.GetChunk <GMChunkAGRP>();
            var groups     = agrp.List;

            bool updatedVersion = pf.DataHandle.VersionInfo.IsNumberAtLeast(1, 0, 0, 9999);

            // First, sort sounds alphabetically
            List <AssetRef <AssetSound> > sortedSounds = updatedVersion ? pf.Sounds.OrderBy(x => x.Name).ToList() : pf.Sounds;

            // Get all the AUDO chunk handles in the game
            GMChunkAUDO defaultChunk = pf.DataHandle.GetChunk <GMChunkAUDO>();

            defaultChunk.List.Clear();
            Dictionary <string, GMChunkAUDO> audioChunks       = new Dictionary <string, GMChunkAUDO>();
            Dictionary <string, int>         audioChunkIndices = new Dictionary <string, int>();

            if (agrp.AudioData != null)
            {
                for (int i = 1; i < groups.Count; i++)
                {
                    if (agrp.AudioData.ContainsKey(i))
                    {
                        var currChunk = agrp.AudioData[i].GetChunk <GMChunkAUDO>();
                        currChunk.List.Clear();
                        audioChunks.Add(groups[i].Name.Content, currChunk);
                        audioChunkIndices.Add(groups[i].Name.Content, i);
                    }
                }
            }

            dataAssets.Clear();
            Dictionary <AssetRef <AssetSound>, GMSound> finalMap = new Dictionary <AssetRef <AssetSound>, GMSound>();

            for (int i = 0; i < sortedSounds.Count; i++)
            {
                AssetSound asset = sortedSounds[i].Asset;
                if (asset == null)
                {
                    // This asset was never converted, so handle references and re-add it
                    GMSound s = (GMSound)sortedSounds[i].DataAsset;

                    // Get the group name from the cache
                    var cachedData = (CachedSoundRefData)sortedSounds[i].CachedData;

                    // Potentially handle the internal sound buffer
                    if (cachedData.SoundBuffer != null)
                    {
                        string groupName = cachedData.AudioGroupName;

                        int         ind;
                        GMChunkAUDO chunk;
                        if (!audioChunkIndices.TryGetValue(groupName, out ind))
                        {
                            ind   = pf.DataHandle.VersionInfo.BuiltinAudioGroupID; // might be wrong
                            chunk = defaultChunk;
                        }
                        else
                        {
                            chunk = audioChunks[groupName];
                        }

                        s.GroupID = ind;
                        s.AudioID = chunk.List.Count;
                        chunk.List.Add(new GMAudio()
                        {
                            Data = cachedData.SoundBuffer
                        });
                    }

                    finalMap[sortedSounds[i]] = s;
                    continue;
                }

                GMSound dataAsset = new GMSound()
                {
                    Name    = pf.DataHandle.DefineString(asset.Name),
                    Volume  = asset.Volume,
                    Flags   = GMSound.AudioEntryFlags.Regular,
                    Effects = 0,
                    Pitch   = asset.Pitch,
                    File    = pf.DataHandle.DefineString(asset.OriginalSoundFile),
                    Type    = (asset.Type != null) ? pf.DataHandle.DefineString(asset.Type) : null
                };
                finalMap[sortedSounds[i]] = dataAsset;

                switch (asset.Attributes)
                {
                case AssetSound.Attribute.CompressedStreamed:
                    if (updatedVersion)
                    {
                        dataAsset.AudioID = -1;
                    }
                    else
                    {
                        dataAsset.AudioID = defaultChunk.List.Count - 1;
                    }
                    dataAsset.GroupID = pf.DataHandle.VersionInfo.BuiltinAudioGroupID;     // might be wrong

                    if (asset.SoundFileBuffer != null)
                    {
                        pf.DataHandle.Logger?.Invoke($"Writing sound file \"{asset.SoundFile}\"...");
                        pf.DataHandle.FileWrites.Post(new (Path.Combine(pf.DataHandle.Directory, asset.SoundFile), asset.SoundFileBuffer));
                    }
                    break;

                case AssetSound.Attribute.UncompressOnLoad:
                case AssetSound.Attribute.Uncompressed:
                    dataAsset.Flags |= GMSound.AudioEntryFlags.IsEmbedded;
                    goto case AssetSound.Attribute.CompressedNotStreamed;

                case AssetSound.Attribute.CompressedNotStreamed:
                    if (asset.Attributes != AssetSound.Attribute.Uncompressed)
                    {
                        dataAsset.Flags |= GMSound.AudioEntryFlags.IsCompressed;
                    }

                    int         ind;
                    GMChunkAUDO chunk;
                    if (!audioChunkIndices.TryGetValue(asset.AudioGroup, out ind))
                    {
                        ind   = pf.DataHandle.VersionInfo.BuiltinAudioGroupID;   // might be wrong
                        chunk = defaultChunk;
                    }
                    else
                    {
                        chunk = audioChunks[asset.AudioGroup];
                    }

                    dataAsset.GroupID = ind;
                    dataAsset.AudioID = chunk.List.Count;
                    chunk.List.Add(new GMAudio()
                    {
                        Data = asset.SoundFileBuffer
                    });
                    break;
                }
            }

            // Actually add sounds to the data
            foreach (var assetRef in pf.Sounds)
            {
                dataAssets.Add(finalMap[assetRef]);
            }
        }