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