Example #1
0
        public bool Redirect(string filePath)
        {
            if (IsCompact)
            {
                mLogger.Error($"Compact wave format not implemented, unable to redirect to {filePath}");
                return(false);
            }

            var fileSize = 0L;

            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                fileSize = stream.Length;

            if (fileSize == 0)
            {
                mLogger.Error($"{filePath} is empty");
                return(false);
            }

            var txthPath = filePath + ".txth";

            if (!File.Exists(txthPath))
            {
                mLogger.Error($"{filePath} Missing .txth file! Expected location: {txthPath}");
                return(false);
            }

            if (!ParseTxth(txthPath))
            {
                mLogger.Error($"{txthPath} Failed to parse. Make sure the file is formatted correctly.");
                return(false);
            }

            if (!IsCompact)
            {
                var originalLength = Native->PlayRegion.Length;

                // Try to recalculate the actual size based on the duration
                if (!WaveBankFormatHelper.TryGetSamplesToByteOffset(Native->Format.FormatTag.Get(), Native->Format.BitsPerSample.Get(), Native->FlagsAndDuration.Duration,
                                                                    Native->Format.CalculatedBlockAlign, Native->Format.Channels, out Native->PlayRegion.Length))
                {
                    // In case we can't, just accept the file size
                    Native->PlayRegion.Length = (int)fileSize;
                }

                if (Native->PlayRegion.Length > originalLength)
                {
                    // If the new size exceeds that of the old, allocate new memory for it
                    Native->PlayRegion.Offset = ( int )(WaveBank.AllocateSectionMemory(WaveBankSegmentIndex.EntryWaveData, ( int )Native->PlayRegion.Length));
                }
            }
            else
            {
                mLogger.Error($"Compact wave format not implemented, unable to redirect to {filePath}");
                return(false);
            }

            FilePath     = filePath;
            FileName     = Path.GetFileNameWithoutExtension(FilePath);
            FileSize     = fileSize;
            IsRedirected = true;
            return(true);
        }
Example #2
0
        private bool ParseTxth(string path)
        {
            using (var reader = new StreamReader(path))
            {
                var txth = new ParsedTxth();

                while (!reader.EndOfStream)
                {
                    var line  = reader.ReadLine();
                    var kvp   = line.Split("=", StringSplitOptions.RemoveEmptyEntries);
                    var key   = kvp[0].Trim();
                    var value = kvp[1].Trim();
                    int temp  = 0;

                    switch (key)
                    {
                    case "num_samples":
                        if (!int.TryParse(value, out temp))
                        {
                            return(false);
                        }
                        txth.Duration = temp;
                        break;

                    case "codec":
                        switch (value)
                        {
                        case "PCM16LE":
                            txth.FormatTag = WaveBankMiniFormatTag.PCM;
                            txth.BitDepth  = WaveBankMiniFormatBitDepth._16;
                            break;

                        case "PCM8":
                            txth.FormatTag = WaveBankMiniFormatTag.PCM;
                            txth.BitDepth  = WaveBankMiniFormatBitDepth._8;
                            break;

                        case "XMA2":
                            txth.FormatTag = WaveBankMiniFormatTag.XMA;
                            break;

                        case "MSADPCM":
                            txth.FormatTag = WaveBankMiniFormatTag.ADPCM;
                            break;

                        case "XWMA":
                            txth.FormatTag = WaveBankMiniFormatTag.WMA;
                            break;

                        default:
                            mLogger.Error($"Unsupported codec ({value})");
                            return(false);
                        }
                        break;

                    case "channels":
                        if (!int.TryParse(value, out temp))
                        {
                            return(false);
                        }
                        txth.Channels = temp;
                        break;

                    case "sample_rate":
                        if (!int.TryParse(value, out temp))
                        {
                            return(false);
                        }
                        txth.SampleRate = temp;
                        break;

                    case "interleave":
                        if (!int.TryParse(value, out temp))
                        {
                            return(false);
                        }
                        txth.Interleave = temp;
                        break;

                    case "loop_start_sample":
                        if (!int.TryParse(value, out temp))
                        {
                            return(false);
                        }
                        txth.LoopStart = temp;
                        break;

                    case "loop_end_sample":
                        if (!int.TryParse(value, out temp))
                        {
                            return(false);
                        }
                        txth.LoopEnd = temp;
                        break;

                    default:
                        mLogger.Error($"{path} Unrecognized TXTH command: {key} = {value}");
                        break;
                    }
                }

                if (!txth.Duration.HasValue)
                {
                    mLogger.Error($"{path} num_samples is not set!");
                    return(false);
                }

                if (!txth.FormatTag.HasValue)
                {
                    mLogger.Error($"{path} codec is not set!");
                    return(false);
                }

                if (!txth.Channels.HasValue)
                {
                    mLogger.Error($"{path} channels is not set!");
                    return(false);
                }

                if (!txth.SampleRate.HasValue)
                {
                    mLogger.Error($"{path} sample_rate is not set!");
                    return(false);
                }

                if (!txth.Interleave.HasValue)
                {
                    mLogger.Error($"{path} interleave is not set!");
                    return(false);
                }

                if (txth.LoopStart.HasValue && !txth.LoopEnd.HasValue)
                {
                    // Set end loop sample to the duration if it is somehow missing
                    txth.LoopEnd = txth.Duration;
                }

                // Set settings
                Native->Format.FormatTag.Set(txth.FormatTag.Value);
                Native->Format.BitsPerSample.Set(txth.BitDepth.GetValueOrDefault(0));
                Native->Format.Channels.Set(txth.Channels.Value);
                Native->Format.SamplesPerSecond.Set(txth.SampleRate.Value);
                Native->Format.CalculatedBlockAlign = txth.Interleave.Value;

                var durationAligned = WaveBankFormatHelper.AlignSamples(Native->Format.FormatTag.Get(), txth.Duration.Value,
                                                                        Native->Format.CalculatedBlockAlign, Native->Format.Channels);

                if (txth.LoopStart.HasValue)
                {
                    var startSampleAligned = WaveBankFormatHelper.AlignSamples(Native->Format.FormatTag.Get(), txth.LoopStart.Value,
                                                                               Native->Format.CalculatedBlockAlign, Native->Format.Channels);
                    var startSampleAlignedDiff = startSampleAligned - txth.LoopStart.Value;
                    var endSampleAligned       = WaveBankFormatHelper.AlignSamples(Native->Format.FormatTag.Get(), txth.LoopEnd.Value + startSampleAlignedDiff,
                                                                                   Native->Format.CalculatedBlockAlign, Native->Format.Channels);
                    var endSampleAlignedOff = endSampleAligned - txth.LoopEnd.Value;

                    if (startSampleAlignedDiff > 0)
                    {
                        mLogger.Warning($"{path} Loop start sample is not aligned properly, it may not loop correctly ingame!");
                    }
                    if (endSampleAlignedOff > 0)
                    {
                        mLogger.Warning($"{path} Loop end sample is not aligned properly, it may not loop correctly ingame!");
                    }

                    Native->LoopRegion.StartSample  = startSampleAligned;
                    Native->LoopRegion.TotalSamples = endSampleAligned - startSampleAligned;

                    if (endSampleAligned > durationAligned)
                    {
                        durationAligned = endSampleAligned;
                    }
                }
                else
                {
                    Native->LoopRegion.StartSample  = 0;
                    Native->LoopRegion.TotalSamples = 0;
                }

                if (durationAligned > txth.Duration)
                {
                    mLogger.Warning($"[{path} Duration is not aligned properly, it may not play correctly ingame!");
                }

                Native->FlagsAndDuration.Duration.Set(( uint )durationAligned);
            }

            return(true);
        }