Esempio n. 1
0
 /// <summary>
 ///
 /// </summary>
 public CustomIndex(SampleGeneratingArgsComparer comparer = null)
 {
     Index    = -1;
     Comparer = comparer ?? new SampleGeneratingArgsComparer();
     Samples  = new Dictionary <string, HashSet <SampleGeneratingArgs> >();
     foreach (string key in AllKeys)
     {
         Samples[key] = new HashSet <SampleGeneratingArgs>(Comparer);
     }
 }
Esempio n. 2
0
        public static List <CustomIndex> GetCustomIndices(List <SamplePackage> packages,
                                                          Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                                          bool validateSampleFile = true,
                                                          SampleGeneratingArgsComparer comparer = null)
        {
            var indices = packages.Select(o => o.GetCustomIndex(comparer)).ToList();

            indices.ForEach(o => o.CleanInvalids(loadedSamples, validateSampleFile));
            return(indices);
        }
 public static void ExportSampleSchema(SampleSchema sampleSchema, string exportFolder,
                                       Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                       SampleExportFormat format             = SampleExportFormat.Default, SampleExportFormat mixedFormat = SampleExportFormat.Default,
                                       SampleGeneratingArgsComparer comparer = null)
 {
     foreach (var kvp in sampleSchema)
     {
         ExportMixedSample(kvp.Value, kvp.Key, exportFolder, loadedSamples, format, mixedFormat, comparer);
     }
 }
Esempio n. 4
0
        public CustomIndex GetCustomIndex(SampleGeneratingArgsComparer comparer = null)
        {
            if (comparer == null)
            {
                comparer = new SampleGeneratingArgsComparer();
            }

            SampleSet sampleSet = GetSampleSet();
            SampleSet additions = GetAdditions();

            HashSet <SampleGeneratingArgs> normals  = new HashSet <SampleGeneratingArgs>(Samples.Where(o => o.Hitsound == Hitsound.Normal).Select(o => o.SampleArgs), comparer);
            HashSet <SampleGeneratingArgs> whistles = new HashSet <SampleGeneratingArgs>(Samples.Where(o => o.Hitsound == Hitsound.Whistle).Select(o => o.SampleArgs), comparer);
            HashSet <SampleGeneratingArgs> finishes = new HashSet <SampleGeneratingArgs>(Samples.Where(o => o.Hitsound == Hitsound.Finish).Select(o => o.SampleArgs), comparer);
            HashSet <SampleGeneratingArgs> claps    = new HashSet <SampleGeneratingArgs>(Samples.Where(o => o.Hitsound == Hitsound.Clap).Select(o => o.SampleArgs), comparer);

            CustomIndex ci = new CustomIndex(comparer);

            if (sampleSet == SampleSet.Normal)
            {
                ci.Samples["normal-hitnormal"] = normals;
            }
            else if (sampleSet == SampleSet.Drum)
            {
                ci.Samples["drum-hitnormal"] = normals;
            }
            else
            {
                ci.Samples["soft-hitnormal"] = normals;
            }

            if (additions == SampleSet.Normal)
            {
                ci.Samples["normal-hitwhistle"] = whistles;
                ci.Samples["normal-hitfinish"]  = finishes;
                ci.Samples["normal-hitclap"]    = claps;
            }
            else if (additions == SampleSet.Drum)
            {
                ci.Samples["drum-hitwhistle"] = whistles;
                ci.Samples["drum-hitfinish"]  = finishes;
                ci.Samples["drum-hitclap"]    = claps;
            }
            else
            {
                ci.Samples["soft-hitwhistle"] = whistles;
                ci.Samples["soft-hitfinish"]  = finishes;
                ci.Samples["soft-hitclap"]    = claps;
            }
            return(ci);
        }
Esempio n. 5
0
        /// <summary>
        /// Generates a dictionary which maps <see cref="SampleGeneratingArgs"/> to their corresponding filename which makes that sample sound.
        /// Only maps the <see cref="SampleGeneratingArgs"/> which are non-mixed.
        /// </summary>
        /// <returns></returns>
        public Dictionary <SampleGeneratingArgs, string> GetSampleNames(SampleGeneratingArgsComparer comparer = null)
        {
            var sampleNames = new Dictionary <SampleGeneratingArgs, string>(comparer ?? new SampleGeneratingArgsComparer());

            foreach (var kvp in this.Where(kvp => kvp.Value.Count == 1))
            {
                if (!sampleNames.ContainsKey(kvp.Value[0]))
                {
                    sampleNames.Add(kvp.Value[0], kvp.Key);
                }
            }

            return(sampleNames);
        }
Esempio n. 6
0
        public List <CustomIndex> GetCustomIndices(SampleGeneratingArgsComparer comparer = null)
        {
            if (comparer == null)
            {
                comparer = new SampleGeneratingArgsComparer();
            }

            var customIndices = new Dictionary <int, CustomIndex>();

            foreach (var kvp in this)
            {
                var name = Path.GetFileNameWithoutExtension(kvp.Key);
                if (name == null)
                {
                    continue;
                }

                var match = Regex.Match(name, "^(normal|soft|drum)-hit(normal|whistle|finish|clap)");
                if (!match.Success)
                {
                    continue;
                }

                var hitsound = match.Value;

                var remainder = name.Substring(match.Index + match.Length);
                int index     = 1;
                if (!string.IsNullOrEmpty(remainder))
                {
                    if (!FileFormatHelper.TryParseInt(remainder, out index))
                    {
                        continue;
                    }
                }

                if (customIndices.ContainsKey(index))
                {
                    customIndices[index].Samples[hitsound] = new HashSet <SampleGeneratingArgs>(kvp.Value);
                }
                else
                {
                    var ci = new CustomIndex(index, comparer);
                    customIndices.Add(index, ci);
                    ci.Samples[hitsound] = new HashSet <SampleGeneratingArgs>(kvp.Value, comparer);
                }
            }

            return(customIndices.Values.ToList());
        }
        /// <summary>
        /// Exports all samples for a collection of custom indices.
        /// </summary>
        /// <param name="customIndices"></param>
        /// <param name="exportFolder"></param>
        /// <param name="loadedSamples"></param>
        /// <param name="format"></param>
        /// <param name="mixedFormat"></param>
        /// <param name="comparer"></param>
        public static void ExportCustomIndices(List <CustomIndex> customIndices, string exportFolder,
                                               Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                               SampleExportFormat format             = SampleExportFormat.Default, SampleExportFormat mixedFormat = SampleExportFormat.Default,
                                               SampleGeneratingArgsComparer comparer = null)
        {
            foreach (CustomIndex ci in customIndices)
            {
                foreach (KeyValuePair <string, HashSet <SampleGeneratingArgs> > kvp in ci.Samples)
                {
                    if (kvp.Value.Count == 0)
                    {
                        continue;
                    }

                    string filename = ci.Index == 1 ? kvp.Key : kvp.Key + ci.Index;
                    ExportMixedSample(kvp.Value, filename, exportFolder, loadedSamples, format, mixedFormat, comparer);
                }
            }
        }
Esempio n. 8
0
        public static CompleteHitsounds GetCompleteHitsounds(List <SamplePackage> packages,
                                                             Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                                             List <CustomIndex> customIndices = null, bool allowGrowth                      = false, int firstCustomIndex = 1,
                                                             bool validateSampleFile          = true, SampleGeneratingArgsComparer comparer = null)
        {
            if (customIndices == null)
            {
                customIndices = OptimizeCustomIndices(GetCustomIndices(packages, loadedSamples, validateSampleFile, comparer));
                GiveCustomIndicesIndices(customIndices, false, firstCustomIndex);
            }
            else if (allowGrowth)
            {
                customIndices = OptimizeCustomIndices(customIndices.Concat(GetCustomIndices(packages, loadedSamples, validateSampleFile, comparer)).ToList());
                GiveCustomIndicesIndices(customIndices, true, firstCustomIndex);
            }

            var hitsounds = GetHitsounds(packages, customIndices, loadedSamples, validateSampleFile, comparer);

            return(new CompleteHitsounds(hitsounds, customIndices));
        }
Esempio n. 9
0
        /// <summary>
        /// Generates 1-to-1 <see cref="HitsoundEvent"/> of out <see cref="SamplePackage"/> using provided custom indices.
        /// </summary>
        /// <param name="samplePackages">The SamplePackages to get hitsounds out of</param>
        /// <param name="customIndices">The CustomIndices that fit all the packages</param>
        /// <param name="loadedSamples">Loaded samples for the validation of samples files from the sample packages.</param>
        /// <param name="validateSampleFile">Whether to validate sample files from the sample packages.</param>
        /// <param name="comparer">Comparer for <see cref="SampleGeneratingArgs"/></param>
        /// <returns></returns>
        public static List <HitsoundEvent> GetHitsounds(List <SamplePackage> samplePackages,
                                                        List <CustomIndex> customIndices,
                                                        Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                                        bool validateSampleFile = true, SampleGeneratingArgsComparer comparer = null)
        {
            List <HitsoundEvent> hitsounds            = new List <HitsoundEvent>(samplePackages.Count);
            List <CustomIndex>   packageCustomIndices = GetCustomIndices(samplePackages, loadedSamples, validateSampleFile, comparer);

            int index = 0;

            while (index < packageCustomIndices.Count)
            {
                // Find CustomIndex that fits the most packages from here
                CustomIndex bestCustomIndex = null;
                int         bestFits        = 0;

                foreach (CustomIndex ci in customIndices)
                {
                    int fits = NumSupportedPackages(packageCustomIndices, index, ci);

                    if (fits <= bestFits)
                    {
                        continue;
                    }
                    bestCustomIndex = ci;
                    bestFits        = fits;
                }


                if (bestFits == 0)
                {
                    throw new Exception("Custom indices can't fit the sample packages.\n" +
                                        "Maybe you are using an incompatible previous sample schema and growth is disabled.");
                }

                // Add all the fitted packages as hitsounds
                for (int i = 0; i < bestFits; i++)
                {
                    if (bestCustomIndex != null)
                    {
                        hitsounds.Add(samplePackages[index + i].GetHitsound(bestCustomIndex.Index));
                    }
                }
                index += bestFits;
            }
            return(hitsounds);
        }
Esempio n. 10
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);
        }
Esempio n. 11
0
        /// <summary>
        /// Imports all samples specified by <see cref="SampleGeneratingArgs"/> and returns a dictionary which maps the <see cref="SampleGeneratingArgs"/>
        /// to their <see cref="SampleSoundGenerator"/>. If a sample couldn't be imported then it has a null instead.
        /// </summary>
        /// <param name="argsList"></param>
        /// <returns></returns>
        public static Dictionary <SampleGeneratingArgs, SampleSoundGenerator> ImportSamples(IEnumerable <SampleGeneratingArgs> argsList, SampleGeneratingArgsComparer comparer = null)
        {
            if (comparer == null)
            {
                comparer = new SampleGeneratingArgsComparer();
            }

            var samples         = new Dictionary <SampleGeneratingArgs, SampleSoundGenerator>(comparer);
            var separatedByPath = new Dictionary <string, HashSet <SampleGeneratingArgs> >();

            foreach (var args in argsList)
            {
                if (separatedByPath.TryGetValue(args.Path, out HashSet <SampleGeneratingArgs> value))
                {
                    value.Add(args);
                }
                else
                {
                    separatedByPath.Add(args.Path, new HashSet <SampleGeneratingArgs>(comparer)
                    {
                        args
                    });
                }
            }

            foreach (var pair in separatedByPath)
            {
                var path = pair.Key;
                if (!ValidateSamplePath(path))
                {
                    foreach (var args in pair.Value)
                    {
                        samples.Add(args, null);
                    }
                    continue;
                }

                try {
                    switch (Path.GetExtension(path))
                    {
                    case ".sf2": {
                        var sf2 = new SoundFont(path);
                        foreach (var args in pair.Value)
                        {
                            var sample = ImportFromSoundFont(args, sf2);
                            samples.Add(args, sample);
                        }

                        break;
                    }

                    case ".ogg": {
                        foreach (var args in pair.Value)
                        {
                            samples.Add(args, ImportFromVorbis(args));
                        }

                        break;
                    }

                    default: {
                        foreach (var args in pair.Value)
                        {
                            samples.Add(args, ImportFromAudio(args));
                        }

                        break;
                    }
                    }
                } catch (Exception ex) {
                    Console.WriteLine(ex.Message);

                    foreach (var args in pair.Value)
                    {
                        samples.Add(args, null);
                    }
                }
                GC.Collect();
            }
            return(samples);
        }
        public static void ExportLoadedSamples(Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples,
                                               string exportFolder, Dictionary <SampleGeneratingArgs, string> names = null,
                                               SampleExportFormat format = SampleExportFormat.Default, SampleGeneratingArgsComparer comparer = null)
        {
            if (names == null)
            {
                names = GenerateSampleNames(loadedSamples.Keys, loadedSamples, format != SampleExportFormat.MidiChords, comparer);
            }

            foreach (var sample in loadedSamples.Keys.Where(sample => SampleImporter.ValidateSampleArgs(sample, loadedSamples, format != SampleExportFormat.MidiChords)))
            {
                ExportSample(sample, names[sample], exportFolder, loadedSamples, format);
            }
        }
        public static Dictionary <SampleGeneratingArgs, Vector2> GenerateManiaHitsoundPositions(IEnumerable <SampleGeneratingArgs> samples,
                                                                                                SampleGeneratingArgsComparer comparer = null)
        {
            var sampleArray = samples.ToArray();
            var sampleCount = sampleArray.Length;

            // One key per unique sample but clamped between 1 and 18
            int numKeys = MathHelper.Clamp(sampleCount, 1, 18);

            var    positions = new Dictionary <SampleGeneratingArgs, Vector2>(comparer ?? new SampleGeneratingArgsComparer());
            double x         = 256d / numKeys;

            foreach (var sample in sampleArray)
            {
                positions.Add(sample, new Vector2(Math.Round(x), 192));

                x += 512d / numKeys;
                if (x > 512)
                {
                    x = 256d / numKeys;
                }
            }

            return(positions);
        }
        public static Dictionary <SampleGeneratingArgs, Vector2> GenerateHitsoundPositions(IEnumerable <SampleGeneratingArgs> samples,
                                                                                           SampleGeneratingArgsComparer comparer = null)
        {
            var sampleArray = samples.ToArray();
            var sampleCount = sampleArray.Length;

            // Find the biggest spacing that will still fit all the samples
            int  spacingX = 128;
            int  spacingY = 128;
            bool reduceX  = false;

            while ((int)(512d / spacingX + 1) * (int)(384d / spacingY + 1) < sampleCount && spacingX > 1)
            {
                reduceX = !reduceX;
                if (reduceX)
                {
                    spacingX /= 2;
                }
                else
                {
                    spacingY /= 2;
                }
            }

            var positions = new Dictionary <SampleGeneratingArgs, Vector2>(comparer ?? new SampleGeneratingArgsComparer());
            int x         = 0;
            int y         = 0;

            foreach (var sample in sampleArray)
            {
                positions.Add(sample, new Vector2(x, y));

                x += spacingX;
                if (x > 512)
                {
                    x  = 0;
                    y += spacingY;

                    if (y > 384)
                    {
                        y = 0;
                    }
                }
            }

            return(positions);
        }
        public static Dictionary <SampleGeneratingArgs, string> GenerateSampleNames(IEnumerable <SampleGeneratingArgs> samples,
                                                                                    Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples,
                                                                                    bool validateSampleFile = true, SampleGeneratingArgsComparer comparer = null)
        {
            var usedNames   = new HashSet <string>();
            var sampleNames = new Dictionary <SampleGeneratingArgs, string>(comparer ?? new SampleGeneratingArgsComparer());

            foreach (var sample in samples)
            {
                if (!SampleImporter.ValidateSampleArgs(sample, loadedSamples, validateSampleFile))
                {
                    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 ExportMixedSample(IEnumerable <SampleGeneratingArgs> sampleGeneratingArgses, string name,
                                             string exportFolder, Dictionary <SampleGeneratingArgs, SampleSoundGenerator> loadedSamples = null,
                                             SampleExportFormat format             = SampleExportFormat.Default, SampleExportFormat mixedFormat = SampleExportFormat.Default,
                                             SampleGeneratingArgsComparer comparer = null)
        {
            // Export as midi file with single chord
            if (format == SampleExportFormat.MidiChords)
            {
                MidiExporter.SaveToFile(Path.Combine(exportFolder, name + ".mid"), sampleGeneratingArgses.ToArray());
                return;
            }

            // Try loading all the valid samples
            var validLoadedSamples = new Dictionary <SampleGeneratingArgs, SampleSoundGenerator>(comparer ?? new SampleGeneratingArgsComparer());

            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);

                // Resample to a supported sample rate when exporting in vorbis format
                if (mixedFormat == SampleExportFormat.OggVorbis)
                {
                    maxSampleRate = VorbisFileWriter.GetSupportedSampleRate(maxSampleRate);
                }

                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;
                }
            }
        }