private void PlatformStop(bool immediate)
        {
            if (!SourceId.HasValue)
            {
                return;
            }

            AL.SourceStop(SourceId.Value);
            ALHelper.CheckError("Failed to stop source.");

            // Reset the SendFilter to 0 if we are NOT using reverb since sources are recycled
            if (Controller.Efx.IsAvailable)
            {
                Controller.Efx.BindSourceToAuxiliarySlot(SourceId.Value, 0, 0, 0);
                ALHelper.CheckError("Failed to unset reverb.");

                AL.Source(SourceId.Value, ALSourcei.EfxDirectFilter, 0);
                ALHelper.CheckError("Failed to unset filter.");
            }

            AL.Source(SourceId.Value, ALSourcei.Buffer, 0);
            ALHelper.CheckError("Failed to free source from buffer.");

            Controller.RecycleSource(SourceId.Value);
            SourceId = null;
        }
        private void PlatformApply3D(AudioListener listener, AudioEmitter emitter)
        {
            if (!SourceId.HasValue)
            {
                return;
            }

            AL.GetListener(ALListener3f.Position, out float x, out float y, out float z);
            ALHelper.CheckError("Failed to get source position.");

            // get the emitter offset from origin
            Vector3 posOffset = emitter.Position - listener.Position;

            // set up orientation matrix
            var orientation = Matrix4x4.CreateWorld(Vector3.Zero, listener.Forward, listener.Up);

            // set up our final position and velocity according to orientation of listener
            var finalPos = Vector3.Transform(new Vector3(x, y, z) + posOffset, orientation);
            var finalVel = Vector3.Transform(emitter.Velocity, orientation);

            // set the position based on relative positon
            AL.Source(SourceId.Value, ALSource3f.Position, finalPos.X, finalPos.Y, finalPos.Z);
            ALHelper.CheckError("Failed to set source position.");

            AL.Source(SourceId.Value, ALSource3f.Velocity, finalVel.X, finalVel.Y, finalVel.Z);
            ALHelper.CheckError("Failed to set source velocity.");

            AL.Source(SourceId.Value, ALSourcef.ReferenceDistance, SoundEffect.DistanceScale);
            ALHelper.CheckError("Failed to set source distance scale.");

            AL.DopplerFactor(SoundEffect.DopplerScale);
            ALHelper.CheckError("Failed to set Doppler scale.");
        }
        private SoundState PlatformGetState()
        {
            if (!SourceId.HasValue)
            {
                return(SoundState.Stopped);
            }

            var alState = AL.GetSourceState(SourceId.Value);

            ALHelper.CheckError("Failed to get source state.");

            switch (alState)
            {
            case ALSourceState.Initial:
            case ALSourceState.Stopped:
                SoundState = SoundState.Stopped;
                break;

            case ALSourceState.Paused:
                SoundState = SoundState.Paused;
                break;

            case ALSourceState.Playing:
                SoundState = SoundState.Playing;
                break;
            }

            return(SoundState);
        }
 private void PlatformSetPitch(float value)
 {
     if (SourceId.HasValue)
     {
         AL.Source(SourceId.Value, ALSourcef.Pitch, value);
         ALHelper.CheckError("Failed to set source pitch.");
     }
 }
 private void PlatformSetPan(float value)
 {
     if (SourceId.HasValue)
     {
         AL.Source(SourceId.Value, ALSource3f.Position, value, 0f, 0.1f);
         ALHelper.CheckError("Failed to set source pan.");
     }
 }
 private void PlatformSetVolume(float value)
 {
     _alVolume = value;
     if (SourceId.HasValue)
     {
         AL.Source(SourceId.Value, ALSourcef.Gain, _alVolume);
         ALHelper.CheckError("Failed to set source volume.");
     }
 }
 private void PlatformSetIsLooped(bool value)
 {
     _looped = value;
     if (SourceId.HasValue)
     {
         AL.Source(SourceId.Value, ALSourceb.Looping, _looped);
         ALHelper.CheckError("Failed to set source loop state.");
     }
 }
        private void ApplyReverb()
        {
            if (_reverb <= 0f || SoundEffect.ReverbSlot == 0)
            {
                return;
            }

            Controller.Efx.BindSourceToAuxiliarySlot(SourceId !.Value, (int)SoundEffect.ReverbSlot, 0, 0);
            ALHelper.CheckError("Failed to set reverb.");
        }
        private void PlatformCreate()
        {
            PlatformInitialize();

            SourceId = Controller.ReserveSource();

            // Ensure that the source is not looped (due to source recycling)
            AL.Source(SourceId.Value, ALSourceb.Looping, false);
            ALHelper.CheckError("Failed to set source loop state.");
        }
        private void PlatformPause()
        {
            if (!SourceId.HasValue || SoundState != SoundState.Playing)
            {
                return;
            }

            AL.SourcePause(SourceId.Value);
            ALHelper.CheckError("Failed to pause source.");
            SoundState = SoundState.Paused;
        }
예제 #11
0
        public void RecycleSource(uint sourceId)
        {
            AL.Source(sourceId, ALSourcei.Buffer, 0);
            ALHelper.CheckError("Failed to free source from buffers.");

            lock (_availableSources)
            {
                if (_sourcesInUse.Remove(sourceId))
                {
                    _availableSources.Enqueue(sourceId);
                }
            }
        }
        private void PlatformResume()
        {
            if (!SourceId.HasValue)
            {
                PlatformPlay();
                return;
            }

            if (SoundState == SoundState.Paused)
            {
                AL.SourcePlay(SourceId.Value);
                ALHelper.CheckError("Failed to play source.");

                SoundState = SoundState.Playing;
            }
        }
        private void PlatformStop()
        {
            AL.SourceStop(SourceId.Value);
            ALHelper.CheckError("Failed to stop the source.");

            // Remove all queued buffers
            AL.Source(SourceId.Value, ALSourcei.Buffer, 0);
            ALHelper.CheckError("Failed to unbind the buffer.");

            lock (_queuedBuffers)
            {
                while (_queuedBuffers.Count > 0)
                {
                    var buffer = _queuedBuffers.Dequeue();
                    ALBufferPool.Return(buffer);
                }
            }
        }
예제 #14
0
        public void ClearBuffer()
        {
            if (IsDisposed || BufferId == 0)
            {
                return;
            }

            bool isBuffer = AL.IsBuffer(BufferId);

            ALHelper.CheckError("Failed to fetch buffer state.");

            if (isBuffer)
            {
                AL.DeleteBuffer(BufferId);
                BufferId = 0;
                ALHelper.CheckError("Failed to delete buffer.");
            }
        }
        private void PlatformPlay()
        {
            if (!SourceId.HasValue)
            {
                SourceId = Controller.ReserveSource();
            }

            AL.Source(SourceId.Value, ALSourcei.Buffer, _effect !.SoundBuffer !.BufferId);
            ALHelper.CheckError("Failed to bind buffer to source.");

            // update the position, gain, looping, pitch, and distance model

            AL.Source(SourceId.Value, ALSourcei.SourceRelative, 1);
            ALHelper.CheckError("Failed set source relative.");

            AL.DistanceModel(ALDistanceModel.InverseDistanceClamped);
            ALHelper.CheckError("Failed set source distance.");

            AL.Source(SourceId.Value, ALSource3f.Position, _pan, 0f, 0f);
            ALHelper.CheckError("Failed to set source pan.");

            AL.Source(SourceId.Value, ALSource3f.Velocity, 0f, 0f, 0f);
            ALHelper.CheckError("Failed to set source pan.");

            AL.Source(SourceId.Value, ALSourcef.Gain, _alVolume);
            ALHelper.CheckError("Failed to set source volume.");

            AL.Source(SourceId.Value, ALSourceb.Looping, IsLooped);
            ALHelper.CheckError("Failed to set source loop state.");

            AL.Source(SourceId.Value, ALSourcef.Pitch, _pitch);
            ALHelper.CheckError("Failed to set source pitch.");

            ApplyReverb();
            ApplyFilter();

            AL.SourcePlay(SourceId.Value);
            ALHelper.CheckError("Failed to play source.");

            SoundState = SoundState.Playing;
        }
        private void ApplyFilter()
        {
            if (!_needsFilterUpdate || Controller.Filter == 0)
            {
                return;
            }

            float freq = _frequency / 20000f;
            float lf   = 1f - freq;
            var   efx  = Controller.Efx;

            efx.Filter(Controller.Filter, EfxFilteri.FilterType, (int)_filterType);
            ALHelper.CheckError("Failed to set filter.");

            switch (_filterType)
            {
            case EfxFilterType.Lowpass:
                efx.Filter(Controller.Filter, EfxFilterf.LowpassGainHF, freq);
                ALHelper.CheckError("Failed to set LowpassGainHF.");
                break;

            case EfxFilterType.Highpass:
                efx.Filter(Controller.Filter, EfxFilterf.HighpassGainLF, freq);
                ALHelper.CheckError("Failed to set HighpassGainLF.");
                break;

            case EfxFilterType.Bandpass:
                efx.Filter(Controller.Filter, EfxFilterf.BandpassGainHF, freq);
                ALHelper.CheckError("Failed to set BandpassGainHF.");

                efx.Filter(Controller.Filter, EfxFilterf.BandpassGainLF, lf);
                ALHelper.CheckError("Failed to set BandpassGainLF.");
                break;
            }

            AL.Source(SourceId !.Value, ALSourcei.EfxDirectFilter, Controller.Filter);
            ALHelper.CheckError("Failed to set DirectFilter.");

            _needsFilterUpdate = false;
        }
예제 #17
0
        public void BufferData <T>(
            ReadOnlySpan <T> data, ALFormat format, int sampleRate, int sampleAlignment = 0)
            where T : unmanaged
        {
            AssertNotDisposed();

            var controller = ALController.Get();

            if (!controller.SupportsFloat32 && (format == ALFormat.MonoFloat32 || format == ALFormat.StereoFloat32))
            {
                throw new InvalidOperationException("Float data is not supported by this OpenAL driver.");
            }

            if (!controller.SupportsAdpcm && (format == ALFormat.MonoMSAdpcm || format == ALFormat.StereoMSAdpcm))
            {
                throw new InvalidOperationException("MS-ADPCM is not supported by this OpenAL driver.");
            }

            if (!controller.SupportsIma4 && (format == ALFormat.MonoIma4 || format == ALFormat.StereoIma4))
            {
                throw new InvalidOperationException("IMA/ADPCM is not supported by this OpenAL driver.");
            }

            if (BufferId != 0)
            {
                ClearBuffer();
            }

            BufferId = AL.GenBuffer();
            ALHelper.CheckError("Failed to generate OpenAL data buffer.");

            if (sampleAlignment > 0)
            {
                AL.Bufferi(BufferId, ALBufferi.UnpackBlockAlignmentSoft, sampleAlignment);
                ALHelper.CheckError("Failed to set buffer alignment.");
            }

            AL.BufferData(BufferId, format, MemoryMarshal.AsBytes(data), sampleRate);
            ALHelper.CheckError("Failed to fill buffer.");
        }
예제 #18
0
        /// <summary>
        /// Sets up the hardware resources used by the controller.
        /// </summary>
        private ALController()
        {
            if (AL.NativeLibrary == IntPtr.Zero)
            {
                throw new DllNotFoundException(
                          "Couldn't initialize OpenAL because the native binaries couldn't be found.");
            }

            if (!Open())
            {
                throw new AudioHardwareException(
                          "OpenAL device could not be initialized, see console output for details.");
            }

            Efx = new EffectsExtension(Device);

            if (ALC.IsExtensionPresent(Device, "ALC_EXT_CAPTURE"))
            {
                Microphone.PopulateCaptureDevices();
            }

            // We have hardware here and it is ready

            _allSources = new uint[MaxNumberOfSources];
            AL.GenSources(_allSources);
            ALHelper.CheckError("Failed to generate sources.");

            // TODO: allow more effects
            if (Efx.IsAvailable)
            {
                Filter = Efx.GenFilter();
            }

            _availableSources = new Queue <uint>(_allSources);
            _sourcesInUse     = new HashSet <uint>();
        }
예제 #19
0
        /// <summary>
        /// Disposes the <see cref="ALController"/>.
        /// </summary>
        /// <param name="disposing">If true, the managed resources are to be disposed.</param>
        private void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    Streamer.Dispose();

                    if (Filter != 0 && Efx.IsAvailable)
                    {
                        Efx.DeleteFilter(Filter);
                    }

                    SoundEffectInstancePool.DisposeInstances();

                    AL.DeleteSources(_allSources);
                    ALHelper.CheckError("Failed to delete source.");

                    Microphone.StopMicrophones();
                    DestroyContexts();
                }
                _isDisposed = true;
            }
        }
예제 #20
0
 public double GetSourceCurrentPosition(uint sourceId)
 {
     AL.GetSource(sourceId, ALGetSourcei.SampleOffset, out int pos);
     ALHelper.CheckError("Failed to set source offset.");
     return(pos);
 }
 private void PlatformResume()
 {
     AL.SourcePlay(SourceId.Value);
     ALHelper.CheckError("Failed to play the source.");
 }
 private void PlatformPause()
 {
     AL.SourcePause(SourceId.Value);
     ALHelper.CheckError("Failed to pause the source.");
 }