コード例 #1
0
 bool AllocateSource(out uint source, int priority)
 {
     while (!Ready)
     {
     }
     if (freeSources.Count > 0)
     {
         return(freeSources.TryDequeue(out source));
     }
     else
     {
         //Try and stop playing oldest lower priority source
         for (int i = 0; i < sfxInstances.Count; i++)
         {
             var info = Instances[sfxInstances[i]];
             if (info.Instance != null && info.Instance.Priority <= priority)
             {
                 if (info.Source != uint.MaxValue)
                 {
                     Al.alSourceStopv(1, ref info.Source);
                     Al.alSourcei(info.Source, Al.AL_BUFFER, 0);
                     info.Instance.Stopped();
                 }
                 Instances[sfxInstances[i]].Source = uint.MaxValue;
                 sfxInstances.RemoveAt(i);
                 source = info.Source;
                 return(true);
             }
         }
         source = uint.MaxValue;
         return(false);
     }
 }
コード例 #2
0
 static void SetPropertiesAl(uint src, ref SourceProperties prop, int flags)
 {
     if ((flags & FLAG_POS) == FLAG_POS)
     {
         Al.alSourcei(src, Al.AL_SOURCE_RELATIVE, prop.Is3D ? 0 : 1);
         Al.alSource3f(src, Al.AL_POSITION, prop.Position.X, prop.Position.Y, prop.Position.Z);
     }
     if ((flags & FLAG_VEL) == FLAG_VEL)
     {
         Al.alSource3f(src, Al.AL_VELOCITY, prop.Velocity.X, prop.Velocity.Y, prop.Velocity.Z);
     }
     if ((flags & FLAG_DIRECTION) == FLAG_DIRECTION)
     {
         Al.alSource3f(src, Al.AL_DIRECTION, prop.Direction.X, prop.Direction.Y, prop.Direction.Z);
     }
     if ((flags & FLAG_GAIN) == FLAG_GAIN)
     {
         Al.alSourcef(src, Al.AL_GAIN, prop.Gain);
     }
     if ((flags & FLAG_PITCH) == FLAG_PITCH)
     {
         Al.alSourcef(src, Al.AL_PITCH, prop.Pitch);
     }
     if ((flags & FLAG_DIST) == FLAG_DIST)
     {
         Al.alSourcef(src, Al.AL_REFERENCE_DISTANCE, prop.ReferenceDistance);
         Al.alSourcef(src, Al.AL_MAX_DISTANCE, prop.MaxDistance);
     }
     if ((flags & FLAG_CONE) == FLAG_CONE)
     {
         Al.alSourcef(src, Al.AL_CONE_INNER_ANGLE, prop.ConeInnerAngle);
         Al.alSourcef(src, Al.AL_CONE_OUTER_ANGLE, prop.ConeOuterAngle);
         Al.alSourcef(src, Al.AL_CONE_OUTER_GAIN, prop.ConeOuterGain);
     }
 }
コード例 #3
0
        public void Play(bool loop = false, float timeOffset = 0)
        {
            if (ID == uint.MaxValue)
            {
                throw new ObjectDisposedException("SoundInstance");
            }
            var props = properties;

            if (!gainSet)
            {
                UpdateAttenuation();
            }
            dirtyFlags = 0;
            Playing    = true;
            man.Do(() =>
            {
                var src = man.AM_GetInstanceSource(ID, true);
                if (src == uint.MaxValue)
                {
                    dirtyFlags = int.MaxValue;
                    Playing    = false;
                    return;
                }
                SetPropertiesAl(src, ref props, int.MaxValue);
                if (timeOffset > 0)
                {
                    Al.alSourcef(src, Al.AL_SEC_OFFSET, timeOffset);
                }
                Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID);
                Al.alSourcei(src, Al.AL_LOOPING, loop ? 1 : 0);
                Al.alSourcePlay(src);
                man.AM_AddInstance(ID);
            });
        }
コード例 #4
0
 public void SetGain(float gain)
 {
     if (Active)
     {
         Al.alSourcef(ID, Al.AL_GAIN, gain);
     }
     Al.CheckErrors();
 }
コード例 #5
0
 public void SetAttenuation(float attenuation)
 {
     if (Active)
     {
         Al.alSourcef(ID, Al.AL_GAIN, ALUtils.DbToAlGain(attenuation) * man.GetVolume(SoundType.Sfx));
     }
     Al.CheckErrors();
 }
コード例 #6
0
 public void SetPitch(float pitch)
 {
     if (Active)
     {
         Al.alSourcef(ID, Al.AL_PITCH, pitch);
     }
     Al.CheckErrors();
 }
コード例 #7
0
 public void SetVelocity(Vector3 pos)
 {
     if (Active)
     {
         Al.alSource3f(ID, Al.AL_VELOCITY, pos.X, pos.Y, pos.Z);
     }
     Al.CheckErrors();
 }
コード例 #8
0
 public void Stop()
 {
     if (Active)
     {
         Al.alSourceStopv(1, ref ID);
         Al.CheckErrors();
         Active = false;
     }
 }
コード例 #9
0
ファイル: Al.cs プロジェクト: gp-alex/Librelancer
        public static void CheckErrors()
        {
            int error;

            if ((error = Al.alGetError()) != Al.AL_NO_ERROR)
            {
                throw new InvalidOperationException(Al.GetString(error));
            }
        }
コード例 #10
0
 public void StopAllSfx()
 {
     Actions.Enqueue(() =>
     {
         foreach (var sfx in sfxInstances)
         {
             Al.alSourceStopv(1, ref sfx.ID);
         }
         sfxInstances.Clear();
     });
 }
コード例 #11
0
        void _Begin()
        {
            if (playing)
            {
                Cleanup();
            }
            dataleft = true;
            playing  = true;
            var bytes = ArrayPool <byte> .Shared.Rent(POOL_BUFFER_SIZE);

            for (int i = 0; i < 3; i++)
            {
                var b    = manager.Buffers.Dequeue();
                int read = Read(bytes, sound.Data);
                if (read != 0)
                {
                    try
                    {
                        Al.BufferData(b, sound.Format, bytes, read, sound.Frequency);
                    }
                    catch (Exception)
                    {
                        FLLog.Error("AL", $"Error in source {info}");
                        throw;
                    }
                    Al.alSourceQueueBuffers(ID, 1, ref b);
                }
                else
                {
                    manager.Buffers.Enqueue(b);
                }
                if (read < POOL_BUFFER_SIZE)
                {
                    if (!looping)
                    {
                        dataleft = false;
                        break;
                    }
                    else
                    {
                        sound.Data.Seek(0, SeekOrigin.Begin);
                    }
                }
            }
            ArrayPool <byte> .Shared.Return(bytes);

            Al.alSourcef(ID, Al.AL_GAIN, ALUtils.ClampVolume(_gain));
            Al.alSourcePlay(ID);
            manager.activeStreamers.Add(this);
        }
コード例 #12
0
        public void Stop()
        {
            uint _id = ID;

            Playing = false;
            man.Do(() =>
            {
                var src = man.AM_GetInstanceSource(_id, false);
                if (src != uint.MaxValue)
                {
                    Al.alSourceStopv(1, ref src);
                }
            });
        }
コード例 #13
0
 public void SetPosition(Vector3 pos)
 {
     if (float.IsNaN(pos.X) || float.IsNaN(pos.Y) || float.IsNaN(pos.Z))
     {
         //NaN ??? - Exit
         FLLog.Error("Sound", "Attempted to set NaN pos");
         return;
     }
     if (Active)
     {
         Al.alSource3f(ID, Al.AL_POSITION, pos.X, pos.Y, pos.Z);
     }
     Al.CheckErrors();
 }
コード例 #14
0
        void Cleanup()
        {
            playing = false;
            Al.alSourceStopv(1, ref ID);
            int p = 0;

            Al.alGetSourcei(ID, Al.AL_BUFFERS_PROCESSED, out p);
            for (int i = 0; i < p; i++)
            {
                uint buf = 0;
                Al.alSourceUnqueueBuffers(ID, 1, ref buf);
                manager.Buffers.Enqueue(buf);
            }
            sound.Data.Seek(0, SeekOrigin.Begin);
        }
コード例 #15
0
        public void PlaySound(SoundData data, float volume = 1f)
        {
            uint src;

            if (!AllocateSource(out src))
            {
                return;
            }
            Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID);
            Al.alSourcef(src, Al.AL_GAIN, volume);
            Al.alSourcePlay(src);
            toAdd.Enqueue(new SoundEffectInstance()
            {
                ID = src
            });
        }
コード例 #16
0
 public void Update()
 {
     if (running)
     {
         //Run actions
         Action toRun;
         while (actions.TryDequeue(out toRun))
         {
             toRun();
         }
         //update SFX
         for (int i = sfxInstances.Count - 1; i >= 0; i--)
         {
             var src      = Instances[sfxInstances[i]].Source;
             var instance = Instances[sfxInstances[i]].Instance;
             if (src == uint.MaxValue)
             {
                 continue;
             }
             int state;
             Al.alGetSourcei(src, Al.AL_SOURCE_STATE, out state);
             if (state == Al.AL_STOPPED)
             {
                 Al.alSourcei(src, Al.AL_BUFFER, 0);
                 freeSources.Enqueue(src);
                 Instances[sfxInstances[i]].Source = uint.MaxValue;
                 instance?.Stopped();
                 sfxInstances.RemoveAt(i);
                 i--;
             }
         }
         //update Streaming
         //Task.Run(() =>
         //{
         foreach (var item in activeStreamers)
         {
             item.Update();
         }
         foreach (var item in toRemove)
         {
             activeStreamers.Remove(item);
             item.OnStopped();
         }
         toRemove.Clear();
         //});
     }
 }
コード例 #17
0
        void _Begin()
        {
            if (playing)
            {
                Cleanup();
            }
            dataleft = true;
            playing  = true;
            var bytes = BufferAllocator.AllocateBytes();

            for (int i = 0; i < 3; i++)
            {
                var b    = manager.Buffers.Dequeue();
                int read = sound.Data.Read(bytes, 0, bytes.Length);
                if (read != 0)
                {
                    Al.BufferData(b, sound.Format, bytes, read, sound.Frequency);
                    Al.CheckErrors();
                    Al.alSourceQueueBuffers(ID, 1, ref b);
                    Al.CheckErrors();
                }
                else
                {
                    manager.Buffers.Enqueue(b);
                }
                if (read < bytes.Length)
                {
                    if (!looping)
                    {
                        dataleft = false;
                        break;
                    }
                    else
                    {
                        sound.Data.Seek(0, SeekOrigin.Begin);
                    }
                }
            }
            BufferAllocator.Free(bytes);
            Al.alSourcef(ID, Al.AL_GAIN, ALUtils.ClampVolume(_gain));
            Al.alSourcePlay(ID);
            Al.CheckErrors();
            manager.activeStreamers.Add(this);
        }
コード例 #18
0
        public AudioManager(IUIThread uithread)
        {
            UIThread      = uithread;
            audioThreadId = Thread.CurrentThread.ManagedThreadId;
            initTask      = Task.Run(() =>
            {
                Platform.RegisterDllMap(typeof(AudioManager).Assembly);
                Music = new MusicPlayer(this);
                //Init context
                dev = Alc.alcOpenDevice(null);
                ctx = Alc.alcCreateContext(dev, IntPtr.Zero);
                Alc.alcMakeContextCurrent(ctx);
                for (int i = 0; i < MAX_SOURCES; i++)
                {
                    freeSources.Enqueue(Al.GenSource());
                }

                for (int i = 0; i < MAX_STREAM_BUFFERS; i++)
                {
                    Buffers.Enqueue(Al.GenBuffer());
                }

                Instances = new InstanceInfo[MAX_INSTANCES];
                for (int i = 0; i < MAX_INSTANCES; i++)
                {
                    Instances[i].Source = uint.MaxValue;
                    freeInstances.Enqueue((uint)i);
                }

                uint musicSource;
                for (int i = 0; i < 2; i++)
                {
                    while (!freeSources.TryDequeue(out musicSource))
                    {
                    }

                    streamingSources.Enqueue(musicSource);
                }

                FLLog.Debug("Audio", "Audio initialised");
                Al.alListenerf(Al.AL_GAIN, ALUtils.ClampVolume(ALUtils.LinearToAlGain(_masterVolume)));
                Ready = true;
            });
        }
コード例 #19
0
        public void PlaySound(Stream stream, float volume = 1f)
        {
            uint src;

            if (!AllocateSource(out src))
            {
                return;
            }
            var data = AllocateData();

            data.LoadStream(stream);
            Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID);
            Al.alSourcef(src, Al.AL_GAIN, volume);
            Al.alSourcePlay(src);
            toAdd.Enqueue(new SoundEffectInstance()
            {
                ID = src, Dispose = data
            });
        }
コード例 #20
0
 public void ReleaseAllSfx()
 {
     actions.Enqueue(() =>
     {
         foreach (var sfx in sfxInstances)
         {
             var id = Instances[sfx].Source;
             if (id != uint.MaxValue)
             {
                 Al.alSourceStopv(1, ref id);
                 Al.alSourcei(id, Al.AL_BUFFER, 0);
                 freeSources.Enqueue(id);
                 Instances[sfx].Source = uint.MaxValue;
             }
             Instances[sfx].Instance?.Stopped();
             Instances[sfx].Instance?.Dispose(true);
         }
         sfxInstances.Clear();
     });
 }
コード例 #21
0
 public void LoadStream(Stream stream)
 {
     using (var snd = SoundLoader.Open(stream))
     {
         byte[] data;
         if (snd.Size != -1)
         {
             data = new byte[snd.Size];
             System.Diagnostics.Trace.Assert(snd.Data.Read(data, 0, snd.Size) == snd.Size);
         }
         else
         {
             using (var mem = new MemoryStream())
             {
                 snd.Data.CopyTo(mem);
                 data = mem.GetBuffer();
             }
         }
         Al.BufferData(ID, snd.Format, data, data.Length, snd.Frequency);
     }
 }
コード例 #22
0
        public SoundInstance PlaySound(SoundData data, bool loop = false, float volume = 1f, float minD = -1, float maxD = -1, Vector3?posv = null, SoundData dispose = null, Action onFinish = null)
        {
            uint src;

            if (!AllocateSource(out src))
            {
                return(null);
            }
            Al.alSourcei(src, Al.AL_BUFFER, (int)data.ID);
            Al.alSourcef(src, Al.AL_GAIN, volume);
            Al.alSourcei(src, Al.AL_LOOPING, loop ? 1 : 0);
            if (posv != null)
            {
                Al.alSourcei(src, Al.AL_SOURCE_RELATIVE, 0);
                var pos = posv.Value;
                Al.alSource3f(src, Al.AL_POSITION, pos.X, pos.Y, pos.Z);
            }
            else
            {
                Al.alSourcei(src, Al.AL_SOURCE_RELATIVE, 1);
                Al.alSource3f(src, Al.AL_POSITION, 0, 0, 0);
            }
            if (minD != -1 && maxD != -1)
            {
                Al.alSourcef(src, Al.AL_REFERENCE_DISTANCE, minD);
                Al.alSourcef(src, Al.AL_MAX_DISTANCE, maxD);
            }
            Al.alSourcePlay(src);
            var inst = new SoundInstance(src)
            {
                Dispose = dispose, OnFinish = onFinish
            };

            toAdd.Enqueue(inst);
            return(inst);
        }
コード例 #23
0
        public bool Update()
        {
            bool hadData = dataleft;

            //Do things
            if (dataleft)
            {
                int processed;
                Al.alGetSourcei(ID, Al.AL_BUFFERS_PROCESSED, out processed);
                var bytes = ArrayPool <byte> .Shared.Rent(POOL_BUFFER_SIZE);

                for (int i = 0; i < processed; i++)
                {
                    uint buf = 0;
                    Al.alSourceUnqueueBuffers(ID, 1, ref buf);
                    int read = Read(bytes, sound.Data);
                    if (read != 0)
                    {
                        try
                        {
                            Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency);
                        }
                        catch (Exception)
                        {
                            FLLog.Error("AL", $"Error in source {info}");
                            throw;
                        }
                        Al.alSourceQueueBuffers(ID, 1, ref buf);
                        if (read < POOL_BUFFER_SIZE)
                        {
                            if (looping)
                            {
                                sound.Data.Seek(0, SeekOrigin.Begin);
                            }
                            else
                            {
                                dataleft = false;
                            }
                        }
                    }
                    else
                    {
                        if (looping)
                        {
                            sound.Data.Seek(0, SeekOrigin.Begin);
                            read = sound.Data.Read(bytes, 0, POOL_BUFFER_SIZE);
                            Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency);
                            Al.alSourceQueueBuffers(ID, 1, ref buf);
                        }
                        else
                        {
                            dataleft = false;
                            manager.Buffers.Enqueue(buf);
                            break;
                        }
                    }
                }
                ArrayPool <byte> .Shared.Return(bytes);
            }
            //Return buffers
            int val;

            Al.alGetSourcei(ID, Al.AL_SOURCE_STATE, out val);
            if (val != Al.AL_PLAYING && val != Al.AL_PAUSED)
            {
                if (hadData)
                {
                    FLLog.Warning("Audio", "Buffer underrun");
                    Al.alSourcePlay(ID);
                }
                else
                {
                    CleanupDelayed();
                    return(false);
                }
            }
            return(true);
        }
コード例 #24
0
        void UpdateThread()
        {
            audioThreadId = Thread.CurrentThread.ManagedThreadId;
            //Init context
            IntPtr dev = Alc.alcOpenDevice(null);
            IntPtr ctx = Alc.alcCreateContext(dev, IntPtr.Zero);

            Alc.alcMakeContextCurrent(ctx);
            Al.CheckErrors();
            for (int i = 0; i < MAX_SOURCES; i++)
            {
                freeSources.Enqueue(Al.GenSource());
            }
            for (int i = 0; i < MAX_STREAM_BUFFERS; i++)
            {
                Buffers.Enqueue(Al.GenBuffer());
            }
            Instances = new InstanceInfo[MAX_INSTANCES];
            for (int i = 0; i < MAX_INSTANCES; i++)
            {
                Instances[i].Source = uint.MaxValue;
                freeInstances.Enqueue((uint)i);
            }
            uint musicSource;

            for (int i = 0; i < 2; i++)
            {
                while (!freeSources.TryDequeue(out musicSource))
                {
                }
                streamingSources.Enqueue(musicSource);
            }
            FLLog.Debug("Audio", "Audio initialised");
            Ready = true;
            Al.alListenerf(Al.AL_GAIN, ALUtils.ClampVolume(ALUtils.LinearToAlGain(_masterVolume)));
            while (running)
            {
                //Run actions
                Action toRun;
                while (actions.TryDequeue(out toRun))
                {
                    toRun();
                }
                //update SFX
                for (int i = sfxInstances.Count - 1; i >= 0; i--)
                {
                    var src      = Instances[sfxInstances[i]].Source;
                    var instance = Instances[sfxInstances[i]].Instance;
                    int state;
                    Al.alGetSourcei(src, Al.AL_SOURCE_STATE, out state);
                    Al.CheckErrors();
                    if (state == Al.AL_STOPPED)
                    {
                        Al.alSourcei(src, Al.AL_BUFFER, 0);
                        freeSources.Enqueue(src);
                        Instances[sfxInstances[i]].Source = uint.MaxValue;
                        instance?.Stopped();
                        sfxInstances.RemoveAt(i);
                        i--;
                    }
                }
                //update Streaming
                foreach (var item in activeStreamers)
                {
                    item.Update();
                }

                foreach (var item in toRemove)
                {
                    activeStreamers.Remove(item);
                    item.OnStopped();
                }
                toRemove.Clear();
                Thread.Sleep((sfxInstances.Count > 0 || activeStreamers.Count > 0) ? 1 : 5);
            }
            //Delete context
            Alc.alcMakeContextCurrent(IntPtr.Zero);
            Alc.alcDestroyContext(ctx);
            Alc.alcCloseDevice(dev);
        }
コード例 #25
0
 public void SetListenerPosition(Vector3 pos)
 {
     Al.alListener3f(Al.AL_POSITION, pos.X, pos.Y, pos.Z);
 }
コード例 #26
0
        public bool Update()
        {
            bool hadData = dataleft;

            //Do things
            if (dataleft)
            {
                int processed;
                Al.alGetSourcei(ID, Al.AL_BUFFERS_PROCESSED, out processed);
                Al.CheckErrors();
                var bytes = BufferAllocator.AllocateBytes();
                for (int i = 0; i < processed; i++)
                {
                    uint buf = 0;
                    Al.alSourceUnqueueBuffers(ID, 1, ref buf);
                    int read = sound.Data.Read(bytes, 0, bytes.Length);
                    if (read != 0)
                    {
                        Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency);
                        Al.CheckErrors();
                        Al.alSourceQueueBuffers(ID, 1, ref buf);
                        Al.CheckErrors();
                        if (read < bytes.Length)
                        {
                            if (looping)
                            {
                                sound.Data.Seek(0, SeekOrigin.Begin);
                            }
                            else
                            {
                                dataleft = false;
                            }
                        }
                    }
                    else
                    {
                        if (looping)
                        {
                            sound.Data.Seek(0, SeekOrigin.Begin);
                            read = sound.Data.Read(bytes, 0, bytes.Length);
                            Al.BufferData(buf, sound.Format, bytes, read, sound.Frequency);
                            Al.CheckErrors();
                            Al.alSourceQueueBuffers(ID, 1, ref buf);
                            Al.CheckErrors();
                        }
                        else
                        {
                            dataleft = false;
                            manager.Buffers.Enqueue(buf);
                            break;
                        }
                    }
                }
                BufferAllocator.Free(bytes);
            }
            //Return buffers
            int val;

            Al.alGetSourcei(ID, Al.AL_SOURCE_STATE, out val);
            Al.CheckErrors();
            if (val != Al.AL_PLAYING && val != Al.AL_PAUSED)
            {
                if (hadData)
                {
                    FLLog.Warning("Audio", "Buffer underrun");
                    Al.alSourcePlay(ID);
                    Al.CheckErrors();
                }
                else
                {
                    CleanupDelayed();
                    return(false);
                }
            }
            return(true);
        }
コード例 #27
0
        void UpdateThread()
        {
            //Init context
            IntPtr dev = Alc.alcOpenDevice(null);
            IntPtr ctx = Alc.alcCreateContext(dev, IntPtr.Zero);

            Alc.alcMakeContextCurrent(ctx);
            for (int i = 0; i < MAX_SOURCES; i++)
            {
                freeSources.Enqueue(Al.GenSource());
            }
            for (int i = 0; i < MAX_BUFFERS; i++)
            {
                Buffers.Enqueue(Al.GenBuffer());
            }
            uint musicSource;

            for (int i = 0; i < 2; i++)
            {
                while (!freeSources.TryDequeue(out musicSource))
                {
                }
                streamingSources.Enqueue(musicSource);
            }
            FLLog.Debug("Audio", "Audio initialised");
            Ready = true;
            while (running)
            {
                //insert into items to update
                while (toAdd.Count > 0)
                {
                    SoundEffectInstance item;
                    if (toAdd.TryDequeue(out item))
                    {
                        sfxInstances.Add(item);
                    }
                }
                Action toRun;
                if (Actions.TryDequeue(out toRun))
                {
                    toRun();
                }
                //update SFX
                for (int i = sfxInstances.Count - 1; i >= 0; i--)
                {
                    int state;
                    Al.alGetSourcei(sfxInstances[i].ID, Al.AL_SOURCE_STATE, out state);
                    if (state != Al.AL_PLAYING)
                    {
                        if (sfxInstances[i].Dispose != null)
                        {
                            sfxInstances[i].Dispose.Dispose();
                        }
                        freeSources.Enqueue(sfxInstances[i].ID);
                        sfxInstances.RemoveAt(i);
                        i--;
                    }
                }
                //update Streaming
                foreach (var item in activeStreamers)
                {
                    item.Update();
                }
                foreach (var item in toRemove)
                {
                    activeStreamers.Remove(item);
                    if (item.Stopped != null)
                    {
                        item.OnStopped();
                    }
                }
                Thread.Sleep(5);
            }
            //Delete context
            Alc.alcMakeContextCurrent(IntPtr.Zero);
            Alc.alcDestroyContext(ctx);
            Alc.alcCloseDevice(ctx);
        }
コード例 #28
0
ファイル: SoundData.cs プロジェクト: HaydnTrigg/Librelancer
 internal SoundData(AudioManager manager)
 {
     this.manager = manager;
     ID           = Al.GenBuffer();
 }
コード例 #29
0
ファイル: SoundData.cs プロジェクト: HaydnTrigg/Librelancer
 public void Dispose()
 {
     Al.alDeleteBuffers(1, ref ID);
 }