Example #1
0
        public int SampleCount(LevelSettings settings)
        {
            if (settings.GameVersion.UsesMainSfx() || Samples == null || Samples.Count <= 0)
            {
                return(-1);
            }

            int result = 0;

            foreach (var sample in Samples)
            {
                var path = WadSounds.TryGetSamplePath(settings, sample.FileName);
                if (path != null)
                {
                    result++;
                }
            }
            return(result);
        }
Example #2
0
        public static SortedDictionary <int, WadSample> CompileSamples(List <WadSoundInfo> soundMap, LevelSettings settings, bool onlyIndexed, IProgressReporter reporter, out bool samplesMissing)
        {
            var samples = new List <WadSample>();

            foreach (var soundInfo in soundMap)
            {
                if (onlyIndexed && !soundInfo.Indexed)
                {
                    continue;
                }
                foreach (var sample in soundInfo.Samples)
                {
                    samples.Add(sample);
                }
            }

            var loadedSamples = new SortedDictionary <int, WadSample>();

            // Set up maximum buffer sizes and sample rate
            int  maxBufferLength     = 1024 * 256;
            int  warnBufferLength    = 1024 * 256;
            uint supportedSampleRate = 22050;
            uint supportedBitness    = 16;

            switch (settings.GameVersion)
            {
            case TRVersion.Game.TR5Main:
                maxBufferLength  = int.MaxValue;    // Unlimited
                warnBufferLength = int.MaxValue;
                break;

            case TRVersion.Game.TR4:
            case TRVersion.Game.TRNG:
                maxBufferLength = 1024 * 1024;     // Raised TREP limit
                break;

            case TRVersion.Game.TR1:
            case TRVersion.Game.TR2:
                supportedSampleRate = 11025;
                supportedBitness    = 8;
                break;
            }

            var missing = false;

            Parallel.For(0, samples.Count, i =>
            {
                WadSample currentSample = NullSample;
                try
                {
                    string samplePath = WadSounds.TryGetSamplePath(settings, samples[i].FileName);

                    // If sample was found, then load it...
                    if (!string.IsNullOrEmpty(samplePath))
                    {
                        using (var stream = new FileStream(samplePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                        {
                            var buffer = new byte[stream.Length];
                            if (stream.Read(buffer, 0, buffer.Length) != buffer.Length)
                            {
                                throw new EndOfStreamException();
                            }

                            if (settings.GameVersion.UsesMainSfx())
                            {
                                var sampleRate = settings.GameVersion < TRVersion.Game.TR3 ? 11025 : 22050;
                                currentSample  = new WadSample(samplePath, ConvertSampleFormat(buffer, true, (uint)sampleRate));
                            }
                            else
                            {
                                currentSample = new WadSample(samplePath, ConvertSampleFormat(buffer, false));
                            }

                            if (currentSample.SampleRate != supportedSampleRate)
                            {
                                reporter?.ReportWarn("Sample " + samplePath + " has a sample rate of " + currentSample.SampleRate + " which is unsupported for this engine version.");
                            }

                            if (currentSample.ChannelCount > 1)
                            {
                                reporter?.ReportWarn("Sample " + samplePath + " isn't mono. Only mono samples are supported. Crashes may occur.");
                            }

                            if (currentSample.BitsPerSample != supportedBitness)
                            {
                                reporter?.ReportWarn("Sample " + samplePath + " is not " + supportedBitness + "-bit sample and is not supported in this game version. Crashes may occur.");
                            }

                            if (buffer.Length > maxBufferLength)
                            {
                                reporter?.ReportWarn("Sample " + samplePath + " is more than " + maxBufferLength / 1024 + " kbytes long. It is too big for this game version, crashes may occur.");
                            }
                            else if (buffer.Length > warnBufferLength)
                            {
                                reporter?.ReportWarn("Sample " + samplePath + " is more than " + warnBufferLength / 1024 + " kbytes long. It may cause problems without additional measures, such as patching.");
                            }
                        }
                    }
                    // ... otherwise output null sample
                    else
                    {
                        currentSample = WadSample.NullSample;
                        logger.Warn(new FileNotFoundException(), "Unable to find sample '" + samplePath + "'");
                        missing = true;
                    }
                }
                catch (Exception exc)
                {
                    logger.Warn(exc, "Unable to read file '" + samples[i].FileName + "' from provided location.");
                }

                lock (loadedSamples)
                    loadedSamples.Add(i, currentSample);
            });

            if (missing)
            {
                reporter?.ReportWarn("Some samples are missing. Make sure sample paths are specified correctly. Check level settings for details.");
            }

            samplesMissing = missing;
            return(loadedSamples);
        }
Example #3
0
        public static void PlaySample(Level level, WadSample sample, int channel, float volume = 1.0f, float pitch = 1.0f, float pan = 0.0f, int loopCount = 1)
        {
            if (volume <= 0.0f || loopCount <= 0)
            {
                return;
            }

            var disposables = new List <IDisposable>();

            try
            {
                // Load data.
                // If waveform data is loaded into memory, use it to play sound, otherwise find wav file on disk.

                WaveFileReader waveStream;
                MemoryStream   memoryStream;

                if (sample.IsLoaded)
                {
                    memoryStream = disposables.AddAndReturn(new MemoryStream(sample.Data, false));
                    waveStream   = disposables.AddAndReturn(new WaveFileReader(memoryStream));
                }
                else
                {
                    var path = WadSounds.TryGetSamplePath(level.Settings, sample.FileName);
                    if (path == null)
                    {
                        return;
                    }
                    else
                    {
                        waveStream = disposables.AddAndReturn(new WaveFileReader(path));
                    }
                }

                // Apply looping
                ISampleProvider sampleStream;
                if (loopCount <= 1)
                {
                    sampleStream = waveStream.ToSampleProvider();
                }
                else
                {
                    sampleStream = new RepeatedStream(waveStream)
                    {
                        LoopCount = loopCount
                    }
                };

                // Always play sample as 22 khz
                if (sampleStream.WaveFormat.SampleRate != 22050)
                {
                    sampleStream = new PitchedStream {
                        Source = sampleStream, Pitch = 22050.0f / sampleStream.WaveFormat.SampleRate
                    }
                }
                ;

                // Apply panning
                if (pan != 1.0f)
                {
                    sampleStream = new PanningSampleProvider(sampleStream)
                    {
                        Pan = pan
                    }
                }
                ;

                // Apply pitch
                if (pitch != 1.0f)
                {
                    sampleStream = new PitchedStream {
                        Source = sampleStream, Pitch = pitch
                    }
                }
                ;

                // Apply volume
                if (volume != 1.0f)
                {
                    sampleStream = new VolumeSampleProvider(sampleStream)
                    {
                        Volume = volume
                    }
                }
                ;

                // Add some silence to make sure the audio plays out.
                const int latencyInMilliseconds = 200;
                int       latencyInSamples      = (sampleStream.WaveFormat.SampleRate * latencyInMilliseconds * 2) / 1000;
                sampleStream = new OffsetSampleProvider(sampleStream)
                {
                    LeadOutSamples = sampleStream.WaveFormat.Channels * latencyInSamples
                };

                // Play
                _channels[channel] = disposables.AddAndReturn(new WaveOut());
                _channels[channel].Init(sampleStream);
                _channels[channel].PlaybackStopped += (s, e) =>
                {
                    foreach (IDisposable disposable in disposables)
                    {
                        disposable?.Dispose();
                    }
                    _channels[channel] = null;
                    _indices[channel]  = -1;
                };
                _channels[channel].Play();
            }
            catch (Exception ex)
            {
                // Clean up in case of a problem
                foreach (IDisposable disposable in disposables)
                {
                    disposable?.Dispose();
                }

                _logger.Error("Error while playing sample " + sample + ", exception: " + ex);
            }
        }