public static bool ExportSample(SampleGeneratingArgs sampleGeneratingArgs, string name,
                                        string exportFolder, Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null)
        {
            SampleSoundGenerator sampleSoundGenerator;

            if (loadedSamples != null)
            {
                if (SampleImporter.ValidateSampleArgs(sampleGeneratingArgs, loadedSamples))
                {
                    sampleSoundGenerator = loadedSamples[sampleGeneratingArgs];
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                try {
                    sampleSoundGenerator = SampleImporter.ImportSample(sampleGeneratingArgs);
                } catch (Exception ex) {
                    Console.WriteLine($@"{ex.Message} while importing sample {sampleGeneratingArgs}.");
                    return(false);
                }
            }

            // TODO: Allow mp3, ogg and aif export.
            string filename = name + ".wav";

            CreateWaveFile(Path.Combine(exportFolder, filename), sampleSoundGenerator.GetSampleProvider().ToWaveProvider16());

            return(true);
        }
示例#2
0
        public static Dictionary <SampleGeneratingArgs, string> GenerateSampleNames(IEnumerable <SampleGeneratingArgs> samples,
                                                                                    Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples)
        {
            var usedNames   = new HashSet <string>();
            var sampleNames = new Dictionary <SampleGeneratingArgs, string>();

            foreach (var sample in samples)
            {
                if (!SampleImporter.ValidateSampleArgs(sample, loadedSamples))
                {
                    sampleNames[sample] = string.Empty;
                    continue;
                }

                var baseName = sample.GetFilename();
                var name     = baseName;
                int i        = 1;

                while (usedNames.Contains(name))
                {
                    name = baseName + "-" + ++i;
                }

                usedNames.Add(name);
                sampleNames[sample] = name;
            }

            return(sampleNames);
        }
        public static void ExportCustomIndices(List<CustomIndex> customIndices, string exportFolder, Dictionary<SampleGeneratingArgs, SampleSoundGenerator> loadedSamples=null) {
            foreach (CustomIndex ci in customIndices) {
                foreach (KeyValuePair<string, HashSet<SampleGeneratingArgs>> kvp in ci.Samples) {
                    if (kvp.Value.Count == 0) {
                        continue;
                    }
                    var samples = new List<ISampleProvider>();
                    var volumes = new List<double>();
                    int soundsAdded = 0;
                    
                    if (loadedSamples != null) {
                        foreach (SampleGeneratingArgs args in kvp.Value) {
                            if (SampleImporter.ValidateSampleArgs(args, loadedSamples)) {
                                var sample = loadedSamples[args];
                                samples.Add(sample.GetSampleProvider());
                                volumes.Add(sample.VolumeCorrection != -1 ? sample.VolumeCorrection : 1f);
                                soundsAdded++;
                            }
                        }
                    } else {
                        foreach (SampleGeneratingArgs args in kvp.Value) {
                            try {
                                var sample = SampleImporter.ImportSample(args);
                                samples.Add(sample.GetSampleProvider());
                                volumes.Add(sample.VolumeCorrection != -1 ? sample.VolumeCorrection : 1f);
                                soundsAdded++;
                            } catch (Exception) { }
                        }
                    }

                    if (soundsAdded == 0) {
                        continue;
                    }

                    int maxSampleRate = samples.Max(o => o.WaveFormat.SampleRate);
                    int maxChannels = samples.Max(o => o.WaveFormat.Channels);
                    IEnumerable<ISampleProvider> sameFormatSamples = samples.Select(o => (ISampleProvider)new WdlResamplingSampleProvider(SampleImporter.SetChannels(o, maxChannels), maxSampleRate));

                    ISampleProvider result = new MixingSampleProvider(sameFormatSamples);

                    if (soundsAdded > 1) {
                        result = new VolumeSampleProvider(result) {
                            Volume = (float)(1 / Math.Sqrt(soundsAdded * volumes.Average()))
                        };
                        result = new SimpleCompressorEffect(result) {
                            Threshold = 16,
                            Ratio = 6,
                            Attack = 0.1,
                            Release = 0.1,
                            Enabled = true,
                            MakeUpGain = 15 * Math.Log10(Math.Sqrt(soundsAdded * volumes.Average()))
                        };
                    }

                    // TODO: Allow mp3, ogg and aif export.
                    string filename = ci.Index == 1 ? kvp.Key + ".wav" : kvp.Key + ci.Index + ".wav";
                    CreateWaveFile(Path.Combine(exportFolder, filename), result.ToWaveProvider16());
                }
            }
        }
        public static void BalanceVolumes(List <SamplePackage> packages, VolumeBalancingArgs args)
        {
            foreach (SamplePackage package in packages)
            {
                double maxVolume = package.Samples.Max(o => o.SampleArgs.Volume);
                if (Math.Abs(maxVolume - -0.01) < Precision.DOUBLE_EPSILON)
                {
                    maxVolume = 1;
                }

                foreach (Sample sample in package.Samples)
                {
                    if (Math.Abs(sample.SampleArgs.Volume - -0.01) < Precision.DOUBLE_EPSILON)
                    {
                        sample.SampleArgs.Volume = 1;
                    }

                    // I pick the new volume such that the samples have a volume as high as possible and the greenline brings the volume down.
                    // With this equation the final amplitude stays the same while the greenline has the volume of the loudest sample at this time.
                    double newVolume = SampleImporter.AmplitudeToVolume(
                        SampleImporter.VolumeToAmplitude(package.Volume) *
                        SampleImporter.VolumeToAmplitude(sample.SampleArgs.Volume) /
                        SampleImporter.VolumeToAmplitude(maxVolume));


                    if (Math.Abs(newVolume - 1) > args.Roughness && !args.AlwaysFullVolume)
                    {
                        // If roughness is not 0 it will quantize the new volume in order to reduce the number of different volumes
                        sample.SampleArgs.Volume = Math.Abs(args.Roughness) > Precision.DOUBLE_EPSILON ?
                                                   args.Roughness * Math.Round(newVolume / args.Roughness) :
                                                   newVolume;
                    }
                    else
                    {
                        sample.SampleArgs.Volume = 1;
                    }
                }

                if (args.AlwaysFullVolume)
                {
                    // Assuming the volume of the sample is always maximum, this equation makes sure that
                    // the loudest sample at this time has the wanted amplitude using the volume change from the greenline.
                    package.Volume = SampleImporter.AmplitudeToVolume(
                        SampleImporter.VolumeToAmplitude(package.Volume) *
                        SampleImporter.VolumeToAmplitude(maxVolume));
                }
                else
                {
                    package.Volume = maxVolume;
                }
            }
        }
示例#5
0
        public static void ExportLoadedSamples(Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples,
                                               string exportFolder, Dictionary <SampleGeneratingArgs, string> names = null,
                                               SampleExportFormat format = SampleExportFormat.Default)
        {
            if (names == null)
            {
                names = GenerateSampleNames(loadedSamples.Keys, loadedSamples);
            }

            foreach (var sample in loadedSamples.Keys.Where(sample => SampleImporter.ValidateSampleArgs(sample, loadedSamples)))
            {
                ExportSample(sample, names[sample], exportFolder, loadedSamples, format);
            }
        }
示例#6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="loadedSamples"></param>
        public void CleanInvalids(Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null, bool validateSampleFile = true)
        {
            // Replace all invalid paths with "" and remove the invalid path if another valid path is also in the hashset
            foreach (HashSet <SampleGeneratingArgs> paths in Samples.Values)
            {
                int initialCount = paths.Count;
                int removed      = paths.RemoveWhere(o => !SampleImporter.ValidateSampleArgs(o, loadedSamples, validateSampleFile));

                if (paths.Count == 0 && initialCount != 0)
                {
                    // All the paths where invalid and it didn't just start out empty
                    paths.Add(new SampleGeneratingArgs());  // This "" is here to prevent this hashset from getting new paths
                }
            }
        }
示例#7
0
        public static void AddNewSampleName(Dictionary <SampleGeneratingArgs, string> sampleNames, SampleGeneratingArgs sample,
                                            Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples)
        {
            if (!SampleImporter.ValidateSampleArgs(sample, loadedSamples))
            {
                sampleNames[sample] = string.Empty;
                return;
            }

            var baseName = sample.GetFilename();
            var name     = baseName;
            int i        = 1;

            while (sampleNames.ContainsValue(name))
            {
                name = baseName + "-" + ++i;
            }

            sampleNames[sample] = name;
        }
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public ISampleProvider GetSampleProvider()
        {
            Wave.Position = 0;
            ISampleProvider output = WaveToSampleProvider(Wave);

            if (FadeStart != -1 && FadeLength != -1)
            {
                output = new DelayFadeOutSampleProvider(output);
                ((DelayFadeOutSampleProvider)output).BeginFadeOut(FadeStart * 1000, FadeLength * 1000);
            }
            if (KeyCorrection != 0)
            {
                output = SampleImporter.PitchShift(output, KeyCorrection);
            }
            if (VolumeCorrection != 1)
            {
                output = SampleImporter.VolumeChange(output, VolumeCorrection);
            }
            return(output);
        }
示例#9
0
        public static List <HitsoundEvent> GetHitsounds(List <SamplePackage> samplePackages,
                                                        ref Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples,
                                                        ref Dictionary <SampleGeneratingArgs, string> names,
                                                        ref Dictionary <SampleGeneratingArgs, Vector2> positions)
        {
            HashSet <SampleGeneratingArgs> allSampleArgs = new HashSet <SampleGeneratingArgs>();

            foreach (SamplePackage sp in samplePackages)
            {
                allSampleArgs.UnionWith(sp.Samples.Select(o => o.SampleArgs));
            }

            if (loadedSamples == null)
            {
                loadedSamples = SampleImporter.ImportSamples(allSampleArgs);
            }

            if (names == null)
            {
                names = HitsoundExporter.GenerateSampleNames(allSampleArgs, loadedSamples);
            }

            if (positions == null)
            {
                positions = HitsoundExporter.GenerateHitsoundPositions(allSampleArgs);
            }

            var hitsounds = new List <HitsoundEvent>();

            foreach (var p in samplePackages)
            {
                foreach (var s in p.Samples)
                {
                    hitsounds.Add(new HitsoundEvent(p.Time,
                                                    positions[s.SampleArgs], s.OutsideVolume, names[s.SampleArgs], s.SampleSet, s.SampleSet,
                                                    0, s.Whistle, s.Finish, s.Clap));
                }
            }

            return(hitsounds);
        }
示例#10
0
        public static void ExportMixedSample(IEnumerable <SampleGeneratingArgs> sampleGeneratingArgses, string name,
                                             string exportFolder, Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                             SampleExportFormat format = SampleExportFormat.Default, SampleExportFormat mixedFormat = SampleExportFormat.Default)
        {
            // Try loading all the valid samples
            var validLoadedSamples = new Dictionary <SampleGeneratingArgs, SampleSoundGenerator>();

            if (loadedSamples != null)
            {
                foreach (var args in sampleGeneratingArgses)
                {
                    if (!SampleImporter.ValidateSampleArgs(args, loadedSamples))
                    {
                        continue;
                    }

                    var sample = loadedSamples[args];
                    validLoadedSamples.Add(args, sample);
                }
            }
            else
            {
                // Import each sample individually
                foreach (SampleGeneratingArgs args in sampleGeneratingArgses)
                {
                    try {
                        var sample = SampleImporter.ImportSample(args);
                        validLoadedSamples.Add(args, sample);
                    } catch (Exception ex) {
                        Console.WriteLine($@"{ex.Message} while importing sample {args}.");
                    }
                }
            }

            if (validLoadedSamples.Count == 0)
            {
                return;
            }

            // If all the valid samples are blank samples, then also export only a single blank sample
            if (validLoadedSamples.Count == 1 || validLoadedSamples.All(o => o.Value.BlankSample))
            {
                // It has only one valid sample, so we can just export it with the single sample export
                ExportSample(validLoadedSamples.Keys.First(), name, exportFolder, loadedSamples, format);
            }
            else if (validLoadedSamples.Count > 1)
            {
                // Synchronize the sample rate and channels for all samples and get the sample providers
                int maxSampleRate = validLoadedSamples.Values.Max(o => o.Wave.WaveFormat.SampleRate);
                int maxChannels   = validLoadedSamples.Values.Max(o => o.Wave.WaveFormat.Channels);

                IEnumerable <ISampleProvider> sameFormatSamples = validLoadedSamples.Select(o =>
                                                                                            (ISampleProvider) new WdlResamplingSampleProvider(SampleImporter.SetChannels(o.Value.GetSampleProvider(), maxChannels),
                                                                                                                                              maxSampleRate));

                ISampleProvider sampleProvider = new MixingSampleProvider(sameFormatSamples);

                // If the input is Ieee float or you are mixing multiple samples, then clipping is possible,
                // so you can either export as IEEE float or use a compressor and export as 16-bit PCM (half filesize) or Vorbis (even smaller filesize)
                // If the input is only The Blank Sample then it should export The Blank Sample

                if (mixedFormat == SampleExportFormat.WavePcm || mixedFormat == SampleExportFormat.OggVorbis)
                {
                    // When the sample is mixed and the export format is PCM or Vorbis, then clipping is possible, so we add a limiter
                    sampleProvider = new SoftLimiter(sampleProvider);
                }

                switch (mixedFormat)
                {
                case SampleExportFormat.WaveIeeeFloat:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                    break;

                case SampleExportFormat.WavePcm:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider16());
                    break;

                case SampleExportFormat.OggVorbis:
                    VorbisFileWriter.CreateVorbisFile(Path.Combine(exportFolder, name + ".ogg"), sampleProvider.ToWaveProvider());
                    break;

                default:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                    break;
                }
            }
        }
示例#11
0
        public static bool ExportSample(SampleGeneratingArgs sampleGeneratingArgs, string name,
                                        string exportFolder, Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                        SampleExportFormat format = SampleExportFormat.Default)
        {
            if (sampleGeneratingArgs.CanCopyPaste && format == SampleExportFormat.Default)
            {
                var dest = Path.Combine(exportFolder, name + sampleGeneratingArgs.GetExtension());
                return(CopySample(sampleGeneratingArgs.Path, dest));
            }

            SampleSoundGenerator sampleSoundGenerator;

            if (loadedSamples != null)
            {
                if (SampleImporter.ValidateSampleArgs(sampleGeneratingArgs, loadedSamples))
                {
                    sampleSoundGenerator = loadedSamples[sampleGeneratingArgs];
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                try {
                    sampleSoundGenerator = SampleImporter.ImportSample(sampleGeneratingArgs);
                } catch (Exception ex) {
                    Console.WriteLine($@"{ex.Message} while importing sample {sampleGeneratingArgs}.");
                    return(false);
                }
            }

            var sourceEncoding = sampleSoundGenerator.Wave.WaveFormat.Encoding;

            // Either if it is the blank sample or the source file is literally what the user wants to be exported
            if (sampleSoundGenerator.BlankSample && sampleGeneratingArgs.GetExtension() == ".wav" ||
                sampleGeneratingArgs.CanCopyPaste && IsFormatEncodingCompatible(sourceEncoding, format))
            {
                var dest = Path.Combine(exportFolder, name + sampleGeneratingArgs.GetExtension());
                return(CopySample(sampleGeneratingArgs.Path, dest));
            }

            var sampleProvider = sampleSoundGenerator.GetSampleProvider();

            if ((format == SampleExportFormat.WavePcm || format == SampleExportFormat.OggVorbis) && sourceEncoding == WaveFormatEncoding.IeeeFloat)
            {
                // When the source is IEEE float and the export format is PCM or Vorbis, then clipping is possible, so we add a limiter
                sampleProvider = new SoftLimiter(sampleProvider);
            }

            switch (format)
            {
            case SampleExportFormat.WaveIeeeFloat:
                CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                break;

            case SampleExportFormat.WavePcm:
                CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider16());
                break;

            case SampleExportFormat.OggVorbis:
                VorbisFileWriter.CreateVorbisFile(Path.Combine(exportFolder, name + ".ogg"), sampleProvider.ToWaveProvider());
                break;

            default:
                switch (sourceEncoding)
                {
                case WaveFormatEncoding.IeeeFloat:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                    break;

                case WaveFormatEncoding.Pcm:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider16());
                    break;

                case WaveFormatEncoding.Vorbis1:
                case WaveFormatEncoding.Vorbis2:
                case WaveFormatEncoding.Vorbis3:
                case WaveFormatEncoding.Vorbis1P:
                case WaveFormatEncoding.Vorbis2P:
                case WaveFormatEncoding.Vorbis3P:
                    // Vorbis files default to being exported as 16-bit PCM wave files because that's lossless
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider16());
                    break;

                default:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                    break;
                }

                break;
            }

            return(true);
        }
示例#12
0
        /// <summary>
        /// Balances the volume of <see cref="SamplePackage"/> such that volume is mostly handled by osu!'s volume controllers rather than
        /// in-sample amplitude changes.
        /// </summary>
        /// <param name="packages"></param>
        /// <param name="roughness">Quantizing level in the new volumes of samples. Can be used to decrease the number of distinct volume levels.</param>
        /// <param name="alwaysFullVolume">Forces to always use maximum amplitude in the samples.</param>
        /// <param name="individualVolume">Allows for multiple distinct volume levels within a single <see cref="SamplePackage"/>.</param>
        public static void BalanceVolumes(IEnumerable <SamplePackage> packages, double roughness, bool alwaysFullVolume, bool individualVolume = false)
        {
            foreach (SamplePackage package in packages)
            {
                if (individualVolume)
                {
                    // Simply mix the volume in the sample to the outside volume
                    foreach (Sample sample in package.Samples)
                    {
                        sample.OutsideVolume = SampleImporter.AmplitudeToVolume(
                            SampleImporter.VolumeToAmplitude(sample.OutsideVolume) *
                            SampleImporter.VolumeToAmplitude(sample.SampleArgs.Volume));
                        sample.SampleArgs.Volume = 1;
                    }
                    continue;
                }

                double maxVolume = package.Samples.Max(o => o.SampleArgs.Volume);
                if (Math.Abs(maxVolume - -0.01) < Precision.DOUBLE_EPSILON)
                {
                    maxVolume = 1;
                }

                foreach (Sample sample in package.Samples)
                {
                    if (Math.Abs(sample.SampleArgs.Volume - -0.01) < Precision.DOUBLE_EPSILON)
                    {
                        sample.SampleArgs.Volume = 1;
                    }

                    // Pick the new volume such that the samples have a volume as high as possible and the greenline brings the volume down.
                    // With this equation the final amplitude stays the same while the greenline has the volume of the loudest sample at this time.
                    double newVolume = SampleImporter.AmplitudeToVolume(
                        SampleImporter.VolumeToAmplitude(sample.OutsideVolume) *
                        SampleImporter.VolumeToAmplitude(sample.SampleArgs.Volume) /
                        SampleImporter.VolumeToAmplitude(maxVolume));


                    if (Math.Abs(newVolume - 1) > roughness && !alwaysFullVolume)
                    {
                        // If roughness is not 0 it will quantize the new volume in order to reduce the number of different volumes
                        sample.SampleArgs.Volume = Math.Abs(roughness) > Precision.DOUBLE_EPSILON ?
                                                   roughness * Math.Round(newVolume / roughness) :
                                                   newVolume;
                    }
                    else
                    {
                        sample.SampleArgs.Volume = 1;
                    }
                }

                if (alwaysFullVolume)
                {
                    // Assuming the volume of the sample is always maximum, this equation makes sure that
                    // the loudest sample at this time has the wanted amplitude using the volume change from the greenline.
                    package.SetAllOutsideVolume(SampleImporter.AmplitudeToVolume(
                                                    SampleImporter.VolumeToAmplitude(package.MaxOutsideVolume) *
                                                    SampleImporter.VolumeToAmplitude(maxVolume)));
                }
                else
                {
                    package.SetAllOutsideVolume(maxVolume);
                }
            }
        }
示例#13
0
        public static List <HitsoundEvent> GetHitsounds(List <SamplePackage> samplePackages,
                                                        ref Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples,
                                                        ref Dictionary <SampleGeneratingArgs, string> names,
                                                        ref Dictionary <SampleGeneratingArgs, Vector2> positions,
                                                        bool maniaPositions     = false, bool includeRegularHitsounds         = true, bool allowNamingGrowth = false,
                                                        bool validateSampleFile = true, SampleGeneratingArgsComparer comparer = null)
        {
            if (comparer == null)
            {
                comparer = new SampleGeneratingArgsComparer();
            }

            HashSet <SampleGeneratingArgs> allSampleArgs = new HashSet <SampleGeneratingArgs>(comparer);

            foreach (SamplePackage sp in samplePackages)
            {
                allSampleArgs.UnionWith(sp.Samples.Select(o => o.SampleArgs));
            }

            if (loadedSamples == null)
            {
                loadedSamples = SampleImporter.ImportSamples(allSampleArgs, comparer);
            }

            if (names == null)
            {
                names = HitsoundExporter.GenerateSampleNames(allSampleArgs, loadedSamples, validateSampleFile, comparer);
            }

            if (positions == null)
            {
                positions = maniaPositions ? HitsoundExporter.GenerateManiaHitsoundPositions(allSampleArgs, comparer) :
                            HitsoundExporter.GenerateHitsoundPositions(allSampleArgs, comparer);
            }

            var hitsounds = new List <HitsoundEvent>();

            foreach (var p in samplePackages)
            {
                foreach (var s in p.Samples)
                {
                    string filename;

                    if (names.ContainsKey(s.SampleArgs))
                    {
                        filename = names[s.SampleArgs];
                    }
                    else
                    {
                        // Validate the sample because we expect only valid samples to be present in the sample schema
                        if (SampleImporter.ValidateSampleArgs(s.SampleArgs, loadedSamples, validateSampleFile))
                        {
                            if (allowNamingGrowth)
                            {
                                HitsoundExporter.AddNewSampleName(names, s.SampleArgs, loadedSamples);
                                filename = names[s.SampleArgs];
                            }
                            else
                            {
                                throw new Exception($"Given sample schema doesn't support sample ({s.SampleArgs}) and growth is disabled.");
                            }
                        }
                        else
                        {
                            filename = string.Empty;
                        }
                    }

                    if (includeRegularHitsounds)
                    {
                        hitsounds.Add(new HitsoundEvent(p.Time,
                                                        positions[s.SampleArgs], s.OutsideVolume, filename, s.SampleSet, s.SampleSet,
                                                        0, s.Whistle, s.Finish, s.Clap));
                    }
                    else
                    {
                        hitsounds.Add(new HitsoundEvent(p.Time,
                                                        positions[s.SampleArgs], s.OutsideVolume, filename, SampleSet.Auto, SampleSet.Auto,
                                                        0, false, false, false));
                    }
                }
            }

            return(hitsounds);
        }
示例#14
0
        /// <summary>
        /// Analyses all sound samples in a folder and generates a mapping from a full path without extension to the full path of the first sample which makes the same sound.
        /// Use this to detect duplicate samples.
        /// </summary>
        /// <param name="dir"></param>
        /// <param name="extended"></param>
        /// <param name="detectDuplicateSamples"></param>
        /// <returns></returns>
        public static Dictionary <string, string> AnalyzeSamples(string dir, bool extended = false, bool detectDuplicateSamples = true)
        {
            var           extList     = new[] { ".wav", ".ogg", ".mp3" };
            List <string> samplePaths = Directory.GetFiles(dir, "*.*", extended ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                                        .Where(n => extList.Contains(Path.GetExtension(n), StringComparer.OrdinalIgnoreCase)).ToList();

            Dictionary <string, string> dict = new Dictionary <string, string>();
            bool error = false;

            // Compare all samples to find ones with the same data
            if (detectDuplicateSamples)
            {
                for (int i = 0; i < samplePaths.Count; i++)
                {
                    long thisLength = new FileInfo(samplePaths[i]).Length;

                    for (int k = 0; k <= i; k++)
                    {
                        if (samplePaths[i] != samplePaths[k])
                        {
                            long otherLength = new FileInfo(samplePaths[k]).Length;

                            if (thisLength != otherLength)
                            {
                                continue;
                            }

                            try {
                                using (var thisWave = SampleImporter.OpenSample(samplePaths[i])) {
                                    using (var otherWave = SampleImporter.OpenSample(samplePaths[k])) {
                                        if (thisWave.Length != otherWave.Length)
                                        {
                                            continue;
                                        }

                                        byte[] thisBuffer = new byte[thisWave.Length];
                                        thisWave.Read(thisBuffer, 0, (int)thisWave.Length);

                                        byte[] otherBuffer = new byte[otherWave.Length];
                                        otherWave.Read(otherBuffer, 0, (int)otherWave.Length);

                                        if (!thisBuffer.SequenceEqual(otherBuffer))
                                        {
                                            continue;
                                        }
                                    }
                                }
                            } catch (Exception ex) {
                                // Something went wrong reading the samples. I'll just assume they weren't the same
                                if (!error)
                                {
                                    MessageBox.Show($"Exception '{ex.Message}' while trying to analyze samples.",
                                                    "Warning");
                                    ex.Show();
                                    error = true;
                                }

                                continue;
                            }
                        }

                        string samplePath      = samplePaths[i];
                        string fullPathExtLess =
                            Path.Combine(Path.GetDirectoryName(samplePath) ?? throw new InvalidOperationException(),
                                         Path.GetFileNameWithoutExtension(samplePath));
                        dict[fullPathExtLess] = samplePaths[k];
                        break;
                    }
                }
            }
            else
            {
                foreach (var samplePath in samplePaths)
                {
                    string fullPathExtLess =
                        Path.Combine(Path.GetDirectoryName(samplePath) ?? throw new InvalidOperationException(),
                                     Path.GetFileNameWithoutExtension(samplePath));
                    dict[fullPathExtLess] = samplePath;
                }
            }

            return(dict);
        }
        public static void ExportMixedSample(IEnumerable <SampleGeneratingArgs> sampleGeneratingArgses, string name,
                                             string exportFolder, Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null)
        {
            var samples     = new List <ISampleProvider>();
            var volumes     = new List <double>();
            int soundsAdded = 0;

            if (loadedSamples != null)
            {
                foreach (var sample in from args in sampleGeneratingArgses where SampleImporter.ValidateSampleArgs(args, loadedSamples) select loadedSamples[args])
                {
                    samples.Add(sample.GetSampleProvider());
                    volumes.Add(Math.Abs(sample.VolumeCorrection - -1) > Precision.DOUBLE_EPSILON ? sample.VolumeCorrection : 1f);
                    soundsAdded++;
                }
            }
            else
            {
                foreach (SampleGeneratingArgs args in sampleGeneratingArgses)
                {
                    try {
                        var sample = SampleImporter.ImportSample(args);
                        samples.Add(sample.GetSampleProvider());
                        volumes.Add(Math.Abs(sample.VolumeCorrection - -1) > Precision.DOUBLE_EPSILON
                            ? sample.VolumeCorrection
                            : 1f);
                        soundsAdded++;
                    } catch (Exception ex) {
                        Console.WriteLine($@"{ex.Message} while importing sample {args}.");
                    }
                }
            }

            if (soundsAdded == 0)
            {
                return;
            }

            int maxSampleRate = samples.Max(o => o.WaveFormat.SampleRate);
            int maxChannels   = samples.Max(o => o.WaveFormat.Channels);
            IEnumerable <ISampleProvider> sameFormatSamples = samples.Select(o => (ISampleProvider) new WdlResamplingSampleProvider(SampleImporter.SetChannels(o, maxChannels), maxSampleRate));

            ISampleProvider result = new MixingSampleProvider(sameFormatSamples);

            if (soundsAdded > 1)
            {
                result = new VolumeSampleProvider(result)
                {
                    Volume = (float)(1 / Math.Sqrt(soundsAdded * volumes.Average()))
                };
                result = new SimpleCompressorEffect(result)
                {
                    Threshold  = 16,
                    Ratio      = 6,
                    Attack     = 0.1,
                    Release    = 0.1,
                    Enabled    = true,
                    MakeUpGain = 15 * Math.Log10(Math.Sqrt(soundsAdded * volumes.Average()))
                };
            }

            // TODO: Allow mp3, ogg and aif export.
            string filename = name + ".wav";

            CreateWaveFile(Path.Combine(exportFolder, filename), result.ToWaveProvider16());
        }
示例#16
0
        public static bool ExportSample(SampleGeneratingArgs sampleGeneratingArgs, string name,
                                        string exportFolder, Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                        SampleExportFormat format = SampleExportFormat.Default)
        {
            // Export as midi file with single note
            if (format == SampleExportFormat.MidiChords)
            {
                MidiExporter.SaveToFile(Path.Combine(exportFolder, name + ".mid"), new[] { sampleGeneratingArgs });
                return(true);
            }

            if (sampleGeneratingArgs.CanCopyPaste && format == SampleExportFormat.Default)
            {
                var dest = Path.Combine(exportFolder, name + sampleGeneratingArgs.GetExtension());
                return(CopySample(sampleGeneratingArgs.Path, dest));
            }

            SampleSoundGenerator sampleSoundGenerator;

            if (loadedSamples != null)
            {
                if (SampleImporter.ValidateSampleArgs(sampleGeneratingArgs, loadedSamples))
                {
                    sampleSoundGenerator = loadedSamples[sampleGeneratingArgs];
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                try {
                    sampleSoundGenerator = SampleImporter.ImportSample(sampleGeneratingArgs);
                } catch (Exception ex) {
                    Console.WriteLine($@"{ex.Message} while importing sample {sampleGeneratingArgs}.");
                    return(false);
                }
            }

            var sourceWaveEncoding = sampleSoundGenerator.Wave.WaveFormat.Encoding;

            // Either if it is the blank sample or the source file is literally what the user wants to be exported
            if (sampleSoundGenerator.BlankSample && sampleGeneratingArgs.GetExtension().ToLower() == ".wav" ||
                sampleGeneratingArgs.CanCopyPaste && IsCopyCompatible(sampleGeneratingArgs, sourceWaveEncoding, format))
            {
                var dest = Path.Combine(exportFolder, name + sampleGeneratingArgs.GetExtension());
                return(CopySample(sampleGeneratingArgs.Path, dest));
            }

            var sampleProvider = sampleSoundGenerator.GetSampleProvider();

            if ((format == SampleExportFormat.WavePcm || format == SampleExportFormat.OggVorbis) && sourceWaveEncoding == WaveFormatEncoding.IeeeFloat)
            {
                // When the source is IEEE float and the export format is PCM or Vorbis, then clipping is possible, so we add a limiter
                sampleProvider = new SoftLimiter(sampleProvider);
            }

            switch (format)
            {
            case SampleExportFormat.WaveIeeeFloat:
                CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                break;

            case SampleExportFormat.WavePcm:
                CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider16());
                break;

            case SampleExportFormat.OggVorbis:
                var resampled = new WdlResamplingSampleProvider(sampleProvider,
                                                                VorbisFileWriter.GetSupportedSampleRate(sampleProvider.WaveFormat.SampleRate));
                VorbisFileWriter.CreateVorbisFile(Path.Combine(exportFolder, name + ".ogg"), resampled.ToWaveProvider());
                break;

            default:
                switch (sourceWaveEncoding)
                {
                case WaveFormatEncoding.IeeeFloat:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                    break;

                case WaveFormatEncoding.Pcm:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider16());
                    break;

                default:
                    CreateWaveFile(Path.Combine(exportFolder, name + ".wav"), sampleProvider.ToWaveProvider());
                    break;
                }

                break;
            }

            return(true);
        }