[Pkg-cli-apps-commits] [SCM] openbve branch, master, updated. debian/1.4.0.5-1-7-gf779cee

Paul Sladen debian at paul.sladen.org
Sat Feb 4 16:28:25 UTC 2012


The following commit has been merged in the master branch:
commit 6e4fd248ebcc6e17968fdbeca2f66e2071ea66f1
Author: Michelle Boucquemont <reschanger at gmail.com>
Date:   Sat Feb 4 16:10:59 2012 +0000

    import openbve_stable_source.zip 1.4.0.7 (2012-02-05)
    
    v1.4.0.7 (2012-02-05)
    
    * Compatibility
      The mixing of multi-channel audio files to mono has been improved. The
      algorithm used tries to discard silent channels, then mixes the
      remaining channels to mono while trying to detect destructive
      interference (by resorting to any non-silent channel) and constructive
      interference (by rebalancing volume). Add-on developers should take
      notice that there is no perfect mixing algorithm that works for all
      files. Please just don't provide stereo sounds in the first place!

diff --git a/openBVE/OpenBve/Audio/Sounds.Convert.cs b/openBVE/OpenBve/Audio/Sounds.Convert.cs
index 6bb2b5d..e610b05 100644
--- a/openBVE/OpenBve/Audio/Sounds.Convert.cs
+++ b/openBVE/OpenBve/Audio/Sounds.Convert.cs
@@ -5,60 +5,181 @@ using OpenBveApi.Sounds;
 namespace OpenBve {
 	internal static partial class Sounds {
 		
-		/// <summary>Mixes all channels in the specified sound to get a mono mix.</summary>
+		/// <summary>Mixes all channels into a single channel.</summary>
 		/// <param name="sound">The sound.</param>
 		/// <returns>The mono mix in the same format as the original.</returns>
 		/// <exception cref="System.NotSupportedException">Raised when the bits per sample are not supported.</exception>
 		private static byte[] GetMonoMix(Sound sound) {
-			if (sound.Bytes.Length == 1) {
-				// --- already mono ---
+			/*
+			 * Convert integer samples to floating-point samples.
+			 */
+			float[][] samples;
+			if (sound.Bytes.Length == 1 || sound.Bytes[0].Length == 0) {
 				return sound.Bytes[0];
-			} else if (sound.BitsPerSample != 8 & sound.BitsPerSample != 16) {
-				// --- format not supported ---
-				throw new NotSupportedException();
 			} else if (sound.BitsPerSample == 8) {
-				// --- 8 bits per sample ---
-				byte[] bytes = new byte[sound.Bytes[0].Length];
-				for (int i = 0; i < sound.Bytes[0].Length; i++) {
-					float mix = 0.0f;
-					for (int j = 0; j < sound.Bytes.Length; j++) {
-						float value = ((float)sound.Bytes[j][i] - 128.0f) / 128.0f;
-						mix = Mix(mix, value);
+				samples = new float[sound.Bytes.Length][];
+				for (int i = 0; i < sound.Bytes.Length; i++) {
+					samples[i] = new float[sound.Bytes[i].Length];
+					for (int j = 0; j < sound.Bytes[i].Length; j++) {
+						byte value = sound.Bytes[i][j];
+						samples[i][j] = ((float)value - 128.0f) / (value < 128 ? 128.0f : 127.0f);
 					}
-					int sample = (byte)(mix * 127.0f + 128.0f);
-					bytes[i] = (byte)(sample & 0xFF);
 				}
-				return bytes;
-			} else {
-				// --- 16 bits per sample ---
-				byte[] bytes = new byte[sound.Bytes[0].Length];
-				for (int i = 0; i < sound.Bytes[0].Length; i += 2) {
-					float mix = 0.0f;
-					for (int j = 0; j < sound.Bytes.Length; j++) {
-						float value = (float)(short)(ushort)(sound.Bytes[j][i] | (sound.Bytes[j][i + 1] << 8)) / 32768.0f;
-						mix = Mix(mix, value);
+			} else if (sound.BitsPerSample == 16) {
+				samples = new float[sound.Bytes.Length][];
+				for (int i = 0; i < sound.Bytes.Length; i++) {
+					samples[i] = new float[sound.Bytes[i].Length >> 1];
+					for (int j = 0; j < sound.Bytes[i].Length; j += 2) {
+						short value = (short)(ushort)((int)sound.Bytes[i][j] | ((int)sound.Bytes[i][j + 1] << 8));
+						samples[i][j >> 1] = (float)value / (value < 0 ? 32768.0f : 32767.0f);
 					}
-					int sample = (int)(ushort)(short)(32767.0f * mix);
-					bytes[i] = (byte)(sample & 0xFF);
-					bytes[i + 1] = (byte)(sample >> 8);
 				}
-				return bytes;
+			} else {
+				throw new NotSupportedException();
+			}
+			/*
+			 * Mix floating-point samples to mono.
+			 * */
+			float[] mix = GetNormalizedMonoMix(samples);
+			/*
+			 * Convert floating-point samples to integer samples.
+			 */
+			byte[] result;
+			if (sound.BitsPerSample == 8) {
+				result = new byte[mix.Length];
+				for (int i = 0; i < mix.Length; i++) {
+					result[i] = (byte)((mix[i] < 0.0f ? 128.0f : 127.0f) * mix[i] + 128.0f);
+				}
+			} else if (sound.BitsPerSample == 16) {
+				result = new byte[2 * mix.Length];
+				for (int i = 0; i < mix.Length; i++) {
+					int value = (int)(ushort)(short)((mix[i] < 0.0f ? 32768.0f : 32767.0f) * mix[i]);
+					result[2 * i + 0] = (byte)value;
+					result[2 * i + 1] = (byte)(value >> 8);
+				}
+			} else {
+				throw new NotSupportedException();
 			}
+			return result;
 		}
 		
-		/// <summary>Mixes two samples.</summary>
-		/// <param name="a">The first sample in the range from -1.0 to 1.0.</param>
-		/// <param name="b">The second sample in the range from -1.0 to 1.0.</param>
-		/// <returns>The mixed sample in the range from -1.0 to 1.0.</returns>
-		private static float Mix(float a, float b) {
-			if (a < 0.0f & b < 0.0f) {
-				return a + b + a * b;
-			} else if (a > 0.0f & b > 0.0f) {
-				return a + b - a * b;
+		private static float[] GetNormalizedMonoMix(float[][] samples) {
+			/*
+			 * This mixer tries to find silent channels and discards them.
+			 * It then performs a mix to mono for all remaining channels
+			 * and tries to detect destructive interference (in which case
+			 * the first non-silent channel is returned). In all other cases,
+			 * volume in the mono mix is normalized to the average volume
+			 * in all non-silent channels. If necessary, the volume is
+			 * further normalized to prevent overflow. This also prevents
+			 * constructive interference.
+			 * */
+			// --- determine the volume per channel and the total volume ---
+			float[] channelVolume = new float[samples.Length];
+			float totalVolume = 0.0f;
+			for (int i = 0; i < samples.Length; i++) {
+				for (int j = 0; j < samples[i].Length; j++) {
+					channelVolume[i] += Math.Abs(samples[i][j]);
+				}
+				channelVolume[i] /= samples[i].Length;
+				totalVolume += channelVolume[i];
+			}
+			totalVolume /= samples.Length;
+			// --- discard all channels that are below
+			//     a certain threshold of the total volume ---
+			const float silentThreshold = 0.05f;
+			float[][] remainingSamples = new float[samples.Length][];
+			int remainingSamplesUsed = 0;
+			for (int i = 0; i < samples.Length; i++) {
+				if (channelVolume[i] > silentThreshold * totalVolume) {
+					channelVolume[remainingSamplesUsed] = channelVolume[i];
+					remainingSamples[remainingSamplesUsed] = samples[i];
+					remainingSamplesUsed++;
+				}
+			}
+			if (remainingSamplesUsed == 1) {
+				return remainingSamples[0];
+			} else if (remainingSamplesUsed == 0) {
+				remainingSamples = samples;
+				remainingSamplesUsed = samples.Length;
 			} else {
-				return a + b;
+				totalVolume = 0.0f;
+				for (int i = 0; i < samples.Length; i++) {
+					totalVolume += channelVolume[i];
+				}
+				totalVolume /= remainingSamplesUsed;
+			}
+			// --- produce a mono mix from all remaining channels ---
+			float[] mix = new float[remainingSamples[0].Length];
+			float mixVolume = 0.0f;
+			for (int j = 0; j < remainingSamples[0].Length; j++) {
+				for (int i = 0; i < remainingSamplesUsed; i++) {
+					mix[j] += remainingSamples[i][j];
+				}
+				mix[j] /= remainingSamplesUsed;
+				mixVolume += Math.Abs(mix[j]);
+			}
+			mixVolume /= remainingSamples[0].Length;
+			// --- if the volume in the mono mix is below
+			//     a certain threshold of the total volume,
+			//     assume destructive interference and return
+			//     the first non-silent channel ---
+			const float destructiveInterferenceThreshold = 0.05f;
+			if (mixVolume < destructiveInterferenceThreshold * totalVolume) {
+				return remainingSamples[0];
+			}
+			// --- normalize the volume in the mono mix so that
+			//     it corresponds to the average total volume ---
+			float maximum = 0.0f;
+			for (int j = 0; j < mix.Length; j++) {
+				mix[j] *= totalVolume / mixVolume;
+				float value = Math.Abs(mix[j]);
+				if (value > maximum) maximum = value;
 			}
+			// --- if the maximum value now created exceeds the
+			//     permissible range, normalize the mono mix further ---
+			if (maximum > 1.0f) {
+				for (int j = 0; j < mix.Length; j++) {
+					mix[j] /= maximum;
+				}
+			}
+			return mix;
 		}
 		
+//		private static float[] GetCombiningMonoMix(float[][] samples) {
+//			float[] mix = new float[samples[0].Length];
+//			for (int j = 0; j < mix.Length; j++) {
+//				mix[j] = samples[0][j];
+//				for (int i = 1; i < samples.Length; i++) {
+//					mix[j] = GetCombiningMonoMix(mix[j], samples[i][j]);
+//				}
+//			}
+//			return mix;
+//		}
+
+//		private static float GetCombiningMonoMix(float a, float b) {
+//			if (a < 0.0f & b < 0.0f) {
+//				return a + b + a * b;
+//			} else if (a > 0.0f & b > 0.0f) {
+//				return a + b - a * b;
+//			} else {
+//				return a + b;
+//			}
+//		}
+		
+//		private static float[] GetShiftedMonoMix(float[][] samples, int shift) {
+//			if (samples.Length != 2) {
+//				throw new NotSupportedException();
+//			}
+//			float[] mix = new float[samples[0].Length];
+//			for (int j = 0; j < shift; j++) {
+//				mix[j] = samples[0][j];
+//			}
+//			for (int j = 0; j < samples[0].Length - shift; j++) {
+//				mix[j] = samples[0][j] + samples[1][j + shift];
+//			}
+//			return mix;
+//		}
+		
 	}
 }
\ No newline at end of file
diff --git a/openBVE/OpenBve/Graphics/Screen.cs b/openBVE/OpenBve/Graphics/Screen.cs
index 3798e47..7585d52 100644
--- a/openBVE/OpenBve/Graphics/Screen.cs
+++ b/openBVE/OpenBve/Graphics/Screen.cs
@@ -64,6 +64,7 @@ namespace OpenBve {
 					return false;
 				} else {
 					// --- set up anisotropic filtering ---
+					Interface.CurrentOptions.AnisotropicFilteringMaximum = 0;
 					string[] extensions = Gl.glGetString(Gl.GL_EXTENSIONS).Split(new char[] { ' ' });
 					for (int i = 0; i < extensions.Length; i++) {
 						if (extensions[i] == "GL_EXT_texture_filter_anisotropic") {
@@ -74,7 +75,11 @@ namespace OpenBve {
 							break;
 						}
 					}
-					Interface.CurrentOptions.AnisotropicFilteringLevel = Math.Max(0, Math.Min(Interface.CurrentOptions.AnisotropicFilteringLevel, Interface.CurrentOptions.AnisotropicFilteringMaximum));
+					if (Interface.CurrentOptions.AnisotropicFilteringLevel <= 0) {
+						Interface.CurrentOptions.AnisotropicFilteringLevel = Interface.CurrentOptions.AnisotropicFilteringMaximum;
+					} else {
+						Interface.CurrentOptions.AnisotropicFilteringLevel = Math.Min(Interface.CurrentOptions.AnisotropicFilteringLevel, Interface.CurrentOptions.AnisotropicFilteringMaximum);
+					}
 					// --- done ---
 					Initialized = true;
 					return true;
diff --git a/openBVE/OpenBve/Properties/AssemblyInfo.cs b/openBVE/OpenBve/Properties/AssemblyInfo.cs
index d9e737f..07ddb02 100644
--- a/openBVE/OpenBve/Properties/AssemblyInfo.cs
+++ b/openBVE/OpenBve/Properties/AssemblyInfo.cs
@@ -7,8 +7,8 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyProduct("openBVE")]
 [assembly: AssemblyCopyright("(Public Domain) http://trainsimframework.org/")]
 [assembly: ComVisible(false)]
-[assembly: AssemblyVersion("1.4.0.5")]
-[assembly: AssemblyFileVersion("1.4.0.5")]
+[assembly: AssemblyVersion("1.4.0.7")]
+[assembly: AssemblyFileVersion("1.4.0.7")]
 [assembly: CLSCompliant(true)]
 
 namespace OpenBve {
diff --git a/openBVE/OpenBve/System/ManagedContent.cs b/openBVE/OpenBve/System/ManagedContent.cs
index a2c6563..10c1063 100644
--- a/openBVE/OpenBve/System/ManagedContent.cs
+++ b/openBVE/OpenBve/System/ManagedContent.cs
@@ -72,7 +72,7 @@ namespace OpenBve {
 			}
 		}
 		
-		/// <summary>Represents the specific version of a package.</summary>
+		/// <summary>Represents a specific version of a package.</summary>
 		internal class Version {
 			// --- members ---
 			/// <summary>The package name.</summary>
@@ -132,7 +132,7 @@ namespace OpenBve {
 				 * Parse the enclosing file format that holds the
 				 * compressed data and then decompress the data.
 				 * */
-				uint version;
+				int version;
 				byte[] compressed;
 				byte[] md5;
 				using (MemoryStream stream = new MemoryStream(bytes)) {
@@ -140,8 +140,8 @@ namespace OpenBve {
 						if (reader.ReadUInt64() != 0x5453494C5F465354) {
 							throw new InvalidDataException("The identifier in the header is invalid.");
 						}
-						version = reader.ReadUInt32();
-						if (version != 1 & version != 2) {
+						version = reader.ReadInt32();
+						if (version != 2) {
 							throw new InvalidDataException("The version number in the header is invalid.");
 						}
 						md5 = reader.ReadBytes(16);
@@ -177,24 +177,10 @@ namespace OpenBve {
 								database.Packages[i].Versions[j] = new Version();
 								database.Packages[i].Versions[j].Name = database.Packages[i].Name;
 								database.Packages[i].Versions[j].Number = reader.ReadString();
-								int sourceSize;
-								byte[] sourceMd5;
-								if (version == 1) {
-									sourceSize = reader.ReadInt32();
-									sourceMd5 = reader.ReadBytes(16);
-								} else {
-									sourceSize = 0;
-									sourceMd5 = null;
-								}
 								database.Packages[i].Versions[j].Sources = new Source[reader.ReadInt32()];
 								for (int k = 0; k < database.Packages[i].Versions[j].Sources.Length; k++) {
-									if (version == 1) {
-										database.Packages[i].Versions[j].Sources[k].Size = sourceSize;
-										database.Packages[i].Versions[j].Sources[k].Md5 = sourceMd5;
-									} else {
-										database.Packages[i].Versions[j].Sources[k].Size = reader.ReadInt32();
-										database.Packages[i].Versions[j].Sources[k].Md5 = reader.ReadBytes(16);
-									}
+									database.Packages[i].Versions[j].Sources[k].Size = reader.ReadInt32();
+									database.Packages[i].Versions[j].Sources[k].Md5 = reader.ReadBytes(16);
 									database.Packages[i].Versions[j].Sources[k].Url = reader.ReadString();
 								}
 								database.Packages[i].Versions[j].Dependencies = new Dependency[reader.ReadInt32()];

-- 
openbve



More information about the Pkg-cli-apps-commits mailing list