// --- sound --- /// <summary>Loads a sound and returns the sound data.</summary> /// <param name="path">The path to the file or folder that contains the sound.</param> /// <param name="sound">Receives the sound.</param> /// <returns>Whether loading the sound was successful.</returns> public override bool LoadSound(string path, out OpenBveApi.Sounds.Sound sound) { if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) { for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Sound != null) { try { if (Program.CurrentHost.Plugins[i].Sound.CanLoadSound(path)) { try { if (Program.CurrentHost.Plugins[i].Sound.LoadSound(path, out sound)) { return(true); } Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadSound"); } catch (Exception ex) { Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadSound:" + ex.Message); } } } catch (Exception ex) { Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadSound:" + ex.Message); } } } Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading sound " + path); } else { ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); } sound = null; return(false); }
/// <summary>Loads the specified sound.</summary> /// <param name="path">The path to the file or folder that contains the sound.</param> /// <param name="sound">Receives the sound.</param> /// <returns>Whether loading the sound was successful.</returns> public override bool LoadSound(string path, out Sound sound) { // --- decode file --- int sampleRate; int bitsPerSample; int[][] samples = Flac.Decoder.Decode(path, out sampleRate, out bitsPerSample); // --- format data for API structure --- byte[][] bytes = new byte[samples.Length][]; unchecked { int bytesPerSample = (int)((bitsPerSample + 7) >> 3); for (int i = 0; i < samples.Length; i++) { bytes[i] = new byte[samples[i].Length * bytesPerSample]; if (bitsPerSample <= 8) { for (int j = 0; j < samples[i].Length; j++) { int value = (samples[i][j] >> 24) + 128; bytes[i][j] = (byte)value; } bitsPerSample = 8; } else { for (int j = 0; j < samples[i].Length; j++) { int value = samples[i][j] >> 16; bytes[i][2 * j + 0] = (byte)value; bytes[i][2 * j + 1] = (byte)(value >> 8); } bitsPerSample = 16; } } } sound = new Sound(sampleRate, bitsPerSample, bytes); return true; }
internal SoundBuffer(Sound sound, double radius) { this.Origin = new RawOrigin(sound); this.Radius = radius; this.Loaded = false; this.OpenAlBufferName = 0; this.Duration = 0.0; this.Ignore = false; }
/// <summary>Creates a new sound buffer</summary> /// <param name="sound">The raw sound source, loaded via an API plugin</param> /// <param name="radius">The radius of the sound</param> internal SoundBuffer(OpenBveApi.Sounds.Sound sound, double radius) { this.Origin = new RawOrigin(sound); this.Radius = radius; this.Loaded = false; this.OpenAlBufferName = 0; this.Duration = 0.0; this.Ignore = false; }
/// <summary>Registers a sound buffer and returns a handle to the buffer.</summary> /// <param name="data">The raw sound data.</param> /// <param name="radius">The default effective radius.</param> /// <returns>The handle to the sound buffer.</returns> internal static SoundBuffer RegisterBuffer(OpenBveApi.Sounds.Sound data, double radius) { if (Buffers.Length == BufferCount) { Array.Resize <SoundBuffer>(ref Buffers, Buffers.Length << 1); } Buffers[BufferCount] = new SoundBuffer(data, radius); BufferCount++; return(Buffers[BufferCount - 1]); }
/// <summary>Creates a new sound buffer</summary> /// <param name="sound">The raw sound source, loaded via an API plugin</param> /// <param name="radius">The radius of the sound</param> internal SoundBuffer(OpenBveApi.Sounds.Sound sound, double radius) { this.Origin = new RawOrigin(sound); this.Radius = radius; this.Loaded = false; this.OpenAlBufferName = 0; this.Duration = 0.0; this.InternalVolumeFactor = 0.5; this.Ignore = false; this.PitchFunction = null; this.VolumeFunction = null; }
/// <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 || sound.Bytes[0].Length == 0) return sound.Bytes[0]; /* * Convert integer samples to floating-point samples. */ float[][] samples; if (sound.BitsPerSample == 8) { 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); } } } 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); } } } 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>Registers a sound and returns a handle to the sound.</summary> /// <param name="sound">The sound data.</param> /// <param name="handle">Receives a handle to the sound.</param> /// <returns>Whether loading the sound was successful.</returns> public override bool RegisterSound(OpenBveApi.Sounds.Sound sound, out OpenBveApi.Sounds.SoundHandle handle) { handle = Program.Sounds.RegisterBuffer(sound, 0.0); return(true); }
/// <summary>Loads a sound and returns the sound data.</summary> /// <param name="path">The path to the file or folder that contains the sound.</param> /// <param name="sound">Receives the sound.</param> /// <returns>Whether loading the sound was successful.</returns> public virtual bool LoadSound(string path, out Sound sound) { sound = null; return false; }
/// <summary>Loads the specified sound.</summary> /// <param name="path">The path to the file or folder that contains the sound.</param> /// <param name="sound">Receives the sound.</param> /// <returns>Whether loading the sound was successful.</returns> public override bool LoadSound(string path, out Sound sound) { sound = LoadFromFile(path); return true; }
/// <summary>Loads the specified sound.</summary> /// <param name="path">The path to the file or folder that contains the sound.</param> /// <param name="sound">Receives the sound.</param> /// <returns>Whether loading the sound was successful.</returns> public abstract bool LoadSound(string path, out Sound sound);