Пример #1
0
        public SoundSourcePool(int sourceCount = SoundManager.SOURCE_COUNT)
        {
            int alError = Al.NoError;

            ALSources = new uint[sourceCount];
            for (int i = 0; i < sourceCount; i++)
            {
                Al.GenSource(out ALSources[i]);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Error generating alSource[" + i.ToString() + "]: " + Al.GetErrorString(alError));
                }

                if (!Al.IsSource(ALSources[i]))
                {
                    throw new Exception("Generated alSource[" + i.ToString() + "] is invalid!");
                }

                Al.SourceStop(ALSources[i]);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Error stopping newly generated alSource[" + i.ToString() + "]: " + Al.GetErrorString(alError));
                }

                Al.Sourcef(ALSources[i], Al.MinGain, 0.0f);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Error setting min gain: " + Al.GetErrorString(alError));
                }

                Al.Sourcef(ALSources[i], Al.MaxGain, 1.0f);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Error setting max gain: " + Al.GetErrorString(alError));
                }

                Al.Sourcef(ALSources[i], Al.RolloffFactor, 1.0f);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Error setting rolloff factor: " + Al.GetErrorString(alError));
                }
            }
        }
Пример #2
0
        private const int AMPLITUDE_SAMPLE_COUNT = 4410; //100ms in a 44100hz file

        public OggSound(SoundManager owner, string filename, bool stream, XElement xElement) : base(owner, filename, stream, true, xElement)
        {
            filename = filename.CleanUpPath();
            if (!ToolBox.IsProperFilenameCase(filename))
            {
                DebugConsole.ThrowError("Sound file \"" + filename + "\" has incorrect case!");
            }

            reader = new VorbisReader(filename);

            ALFormat   = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16;
            SampleRate = reader.SampleRate;

            if (!stream)
            {
                int bufferSize = (int)reader.TotalSamples * reader.Channels;

                float[] floatBuffer = new float[bufferSize];
                short[] shortBuffer = new short[bufferSize];

                int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize);

                playbackAmplitude = new List <float>();
                for (int i = 0; i < bufferSize; i += reader.Channels * AMPLITUDE_SAMPLE_COUNT)
                {
                    float maxAmplitude = 0.0f;
                    for (int j = i; j < i + reader.Channels * AMPLITUDE_SAMPLE_COUNT; j++)
                    {
                        if (j >= bufferSize)
                        {
                            break;
                        }
                        maxAmplitude = Math.Max(maxAmplitude, Math.Abs(floatBuffer[j]));
                    }
                    playbackAmplitude.Add(maxAmplitude);
                }

                CastBuffer(floatBuffer, shortBuffer, readSamples);

                Al.BufferData(ALBuffer, ALFormat, shortBuffer,
                              readSamples * sizeof(short), SampleRate);

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError));
                }

                MuffleBuffer(floatBuffer, SampleRate, reader.Channels);

                CastBuffer(floatBuffer, shortBuffer, readSamples);

                Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer,
                              readSamples * sizeof(short), SampleRate);

                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError));
                }

                reader.Dispose();
            }
        }
Пример #3
0
        public override void InitializeALBuffers()
        {
            base.InitializeALBuffers();

            reader ??= new VorbisReader(Filename);

            ALFormat   = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16;
            SampleRate = reader.SampleRate;

            if (!Stream)
            {
                int bufferSize = (int)reader.TotalSamples * reader.Channels;

                float[] floatBuffer = new float[bufferSize];
                short[] shortBuffer = new short[bufferSize];

                int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize);

                playbackAmplitude = new List <float>();
                for (int i = 0; i < bufferSize; i += reader.Channels * AMPLITUDE_SAMPLE_COUNT)
                {
                    float maxAmplitude = 0.0f;
                    for (int j = i; j < i + reader.Channels * AMPLITUDE_SAMPLE_COUNT; j++)
                    {
                        if (j >= bufferSize)
                        {
                            break;
                        }
                        maxAmplitude = Math.Max(maxAmplitude, Math.Abs(floatBuffer[j]));
                    }
                    playbackAmplitude.Add(maxAmplitude);
                }

                CastBuffer(floatBuffer, shortBuffer, readSamples);

                Al.BufferData(ALBuffer, ALFormat, shortBuffer,
                              readSamples * sizeof(short), SampleRate);

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError));
                }

                MuffleBuffer(floatBuffer, SampleRate, reader.Channels);

                CastBuffer(floatBuffer, shortBuffer, readSamples);

                Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer,
                              readSamples * sizeof(short), SampleRate);

                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError));
                }

                reader.Dispose(); reader = null;
            }
        }
Пример #4
0
        public virtual void DeleteALBuffers()
        {
            Owner.KillChannels(this);
            if (alBuffer != 0)
            {
                if (!Al.IsBuffer(alBuffer))
                {
                    throw new Exception("Buffer to delete is invalid!");
                }

                Al.DeleteBuffer(alBuffer); alBuffer = 0;

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }
            }
            if (alMuffledBuffer != 0)
            {
                if (!Al.IsBuffer(alMuffledBuffer))
                {
                    throw new Exception("Buffer to delete is invalid!");
                }

                Al.DeleteBuffer(alMuffledBuffer); alMuffledBuffer = 0;

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }
            }
        }
Пример #5
0
        public virtual void InitializeALBuffers()
        {
            if (!Stream)
            {
                Al.GenBuffer(out alBuffer);
                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }

                if (!Al.IsBuffer(alBuffer))
                {
                    throw new Exception("Generated OpenAL buffer is invalid!");
                }

                Al.GenBuffer(out alMuffledBuffer);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }

                if (!Al.IsBuffer(alMuffledBuffer))
                {
                    throw new Exception("Generated OpenAL buffer is invalid!");
                }
            }
            else
            {
                alBuffer = 0;
            }
        }
Пример #6
0
        public void UpdateStream()
        {
            if (!IsStream)
            {
                throw new Exception("Called UpdateStream on a non-streamed sound channel!");
            }

            try
            {
                Monitor.Enter(mutex);
                if (!reachedEndSample)
                {
                    uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);

                    int state;
                    Al.GetSourcei(alSource, Al.SourceState, out state);
                    bool playing = state == Al.Playing;
                    int  alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        throw new Exception("Failed to determine playing state from streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                    }

                    int unqueuedBufferCount;
                    Al.GetSourcei(alSource, Al.BuffersProcessed, out unqueuedBufferCount);
                    alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        throw new Exception("Failed to determine processed buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                    }

                    Al.SourceUnqueueBuffers(alSource, unqueuedBufferCount, unqueuedBuffers);
                    alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        throw new Exception("Failed to unqueue buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                    }

                    buffersToRequeue += unqueuedBufferCount;

                    int iterCount = buffersToRequeue;
                    for (int k = 0; k < iterCount; k++)
                    {
                        int     index         = queueStartIndex;
                        short[] buffer        = streamShortBuffer;
                        int     readSamples   = Sound.FillStreamBuffer(streamSeekPos, buffer);
                        float   readAmplitude = 0.0f;

                        for (int i = 0; i < Math.Min(readSamples, buffer.Length); i++)
                        {
                            float sampleF = ((float)buffer[i]) / ((float)short.MaxValue);
                            readAmplitude = Math.Max(readAmplitude, Math.Abs(sampleF));
                        }

                        if (FilledByNetwork)
                        {
                            if (Sound is VoipSound voipSound)
                            {
                                voipSound.ApplyFilters(buffer, readSamples);
                            }

                            if (readSamples <= 0)
                            {
                                streamAmplitude *= 0.5f;
                                decayTimer++;
                                if (decayTimer > 120) //TODO: replace magic number
                                {
                                    reachedEndSample = true;
                                }
                            }
                            else
                            {
                                decayTimer = 0;
                            }
                        }
                        else if (Sound.StreamsReliably)
                        {
                            streamSeekPos += readSamples;
                            if (readSamples < STREAM_BUFFER_SIZE)
                            {
                                if (looping)
                                {
                                    streamSeekPos = 0;
                                }
                                else
                                {
                                    reachedEndSample = true;
                                }
                            }
                        }

                        if (readSamples > 0)
                        {
                            streamBufferAmplitudes[index] = readAmplitude;

                            Al.BufferData <short>(streamBuffers[index], Sound.ALFormat, buffer, readSamples, Sound.SampleRate);

                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to assign data to stream buffer: " +
                                                    Al.GetErrorString(alError) + ": " + streamBuffers[index].ToString() + "/" + streamBuffers.Length + ", readSamples: " + readSamples + ", " + debugName);
                            }

                            Al.SourceQueueBuffer(alSource, streamBuffers[index]);
                            queueStartIndex = (queueStartIndex + 1) % 4;

                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to queue streamBuffer[" + index.ToString() + "] to stream: " + debugName + ", " + Al.GetErrorString(alError));
                            }
                        }
                        else
                        {
                            if (readSamples < 0)
                            {
                                reachedEndSample = true;
                            }
                            break;
                        }
                        buffersToRequeue--;
                    }

                    streamAmplitude = streamBufferAmplitudes[queueStartIndex];

                    Al.GetSourcei(alSource, Al.SourceState, out state);
                    alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        throw new Exception("Failed to retrieve stream source state: " + debugName + ", " + Al.GetErrorString(alError));
                    }

                    if (state != Al.Playing)
                    {
                        Al.SourcePlay(alSource);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to start stream playback: " + debugName + ", " + Al.GetErrorString(alError));
                        }
                    }
                }

                if (reachedEndSample)
                {
                    streamAmplitude = 0.0f;
                }
            }
            catch (Exception e)
            {
                DebugConsole.ThrowError($"An exception was thrown when updating a sound stream ({debugName})", e);
            }
            finally
            {
                Monitor.Exit(mutex);
            }
        }
Пример #7
0
 public void Dispose()
 {
     for (int i = 0; i < ALSources.Length; i++)
     {
         Al.DeleteSource(ALSources[i]);
         int alError = Al.GetError();
         if (alError != Al.NoError)
         {
             throw new Exception("Failed to delete ALSources[" + i.ToString() + "]: " + Al.GetErrorString(alError));
         }
     }
     ALSources = null;
 }
Пример #8
0
        public Sound(SoundManager owner, string filename, bool stream, bool streamsReliably)
        {
            Owner           = owner;
            Filename        = Path.GetFullPath(filename);
            Stream          = stream;
            StreamsReliably = streamsReliably;

            BaseGain = 1.0f;
            BaseNear = 100.0f;
            BaseFar  = 200.0f;

            if (!stream)
            {
                Al.GenBuffer(out alBuffer);
                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }

                if (!Al.IsBuffer(alBuffer))
                {
                    throw new Exception("Generated OpenAL buffer is invalid!");
                }

                Al.GenBuffer(out alMuffledBuffer);
                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to create OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }

                if (!Al.IsBuffer(alMuffledBuffer))
                {
                    throw new Exception("Generated OpenAL buffer is invalid!");
                }
            }
            else
            {
                alBuffer = 0;
            }
        }
Пример #9
0
        public SoundChannel(Sound sound, float gain, Vector3?position, float near, float far, string category, bool muffle = false)
        {
            Sound = sound;

            debugName = sound == null ?
                        "SoundChannel (null)" :
                        $"SoundChannel ({(string.IsNullOrEmpty(sound.Filename) ? "filename empty" : sound.Filename) })";

            IsStream         = sound.Stream;
            FilledByNetwork  = sound is VoipSound;
            decayTimer       = 0;
            streamSeekPos    = 0; reachedEndSample = false;
            buffersToRequeue = 4;
            muffled          = muffle;

            if (IsStream)
            {
                mutex = new object();
            }

            try
            {
                if (mutex != null)
                {
                    Monitor.Enter(mutex);
                }
                if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances)
                {
                    ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this);
                }

                if (ALSourceIndex >= 0)
                {
                    if (!IsStream)
                    {
                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0);
                        int alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to reset source buffer: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        if (!Al.IsBuffer(sound.ALBuffer))
                        {
                            throw new Exception(sound.Filename + " has an invalid buffer!");
                        }

                        uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer;
                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        Al.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to play source: " + debugName + ", " + Al.GetErrorString(alError));
                        }
                    }
                    else
                    {
                        uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer;
                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer);
                        int alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to reset source buffer: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Looping, Al.False);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to set stream looping state: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        streamShortBuffer = new short[STREAM_BUFFER_SIZE];

                        streamBuffers          = new uint[4];
                        unqueuedBuffers        = new uint[4];
                        streamBufferAmplitudes = new float[4];
                        for (int i = 0; i < 4; i++)
                        {
                            Al.GenBuffer(out streamBuffers[i]);

                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to generate stream buffers: " + debugName + ", " + Al.GetErrorString(alError));
                            }

                            if (!Al.IsBuffer(streamBuffers[i]))
                            {
                                throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid! " + debugName);
                            }
                        }
                        Sound.Owner.InitStreamThread();
                    }
                }

                this.Position = position;
                this.Gain     = gain;
                this.Looping  = false;
                this.Near     = near;
                this.Far      = far;
                this.Category = category;
            }
            catch
            {
                throw;
            }
            finally
            {
                if (mutex != null)
                {
                    Monitor.Exit(mutex);
                }
            }

            Sound.Owner.Update();
        }
Пример #10
0
        public SoundChannel(Sound sound, float gain, Vector3?position, float near, float far, string category, bool muffle = false)
        {
            Sound = sound;

            IsStream        = sound.Stream;
            FilledByNetwork = sound is VoipSound;
            decayTimer      = 0;
            streamSeekPos   = 0; reachedEndSample = false;
            startedPlaying  = true;

            mutex = new object();

            lock (mutex)
            {
                if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances)
                {
                    ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this);
                }

                if (ALSourceIndex >= 0)
                {
                    if (!IsStream)
                    {
                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0);
                        int alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to reset source buffer: " + Al.GetErrorString(alError));
                        }

                        if (!Al.IsBuffer(sound.ALBuffer))
                        {
                            throw new Exception(sound.Filename + " has an invalid buffer!");
                        }

                        uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer;
                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + sound.ALBuffer.ToString() + "): " + Al.GetErrorString(alError));
                        }

                        Al.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to play source: " + Al.GetErrorString(alError));
                        }
                    }
                    else
                    {
                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)sound.ALBuffer);
                        int alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to reset source buffer: " + Al.GetErrorString(alError));
                        }

                        Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Looping, Al.False);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to set stream looping state: " + Al.GetErrorString(alError));
                        }

                        streamShortBuffer = new short[STREAM_BUFFER_SIZE];

                        streamBuffers = new uint[4];
                        emptyBuffers  = new List <uint>();
                        for (int i = 0; i < 4; i++)
                        {
                            Al.GenBuffer(out streamBuffers[i]);

                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to generate stream buffers: " + Al.GetErrorString(alError));
                            }

                            if (!Al.IsBuffer(streamBuffers[i]))
                            {
                                throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid!");
                            }
                        }

                        Sound.Owner.InitStreamThread();
                    }
                }

                this.Position = position;
                this.Gain     = gain;
                this.Looping  = false;
                this.Near     = near;
                this.Far      = far;
                this.Category = category;
            }
        }
Пример #11
0
        public void UpdateStream()
        {
            if (!IsStream)
            {
                throw new Exception("Called UpdateStream on a non-streamed sound channel!");
            }

            lock (mutex)
            {
                if (!reachedEndSample)
                {
                    uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);

                    int state;
                    Al.GetSourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.SourceState, out state);
                    bool playing = state == Al.Playing;
                    int  alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        throw new Exception("Failed to determine playing state from streamed source: " + Al.GetErrorString(alError));
                    }

                    int    buffersToUnqueue = 0;
                    uint[] unqueuedBuffers  = null;
                    if (!startedPlaying)
                    {
                        buffersToUnqueue = 0;
                        Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToUnqueue);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError));
                        }

                        unqueuedBuffers = new uint[buffersToUnqueue + emptyBuffers.Count];
                        Al.SourceUnqueueBuffers(alSource, buffersToUnqueue, unqueuedBuffers);
                        for (int i = 0; i < emptyBuffers.Count; i++)
                        {
                            unqueuedBuffers[buffersToUnqueue + i] = emptyBuffers[i];
                        }
                        buffersToUnqueue += emptyBuffers.Count;
                        emptyBuffers.Clear();
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to unqueue buffers from streamed source: " + Al.GetErrorString(alError));
                        }
                    }
                    else
                    {
                        startedPlaying   = false;
                        buffersToUnqueue = 4;
                        unqueuedBuffers  = new uint[4];
                        for (int i = 0; i < 4; i++)
                        {
                            unqueuedBuffers[i] = streamBuffers[i];
                        }
                    }

                    for (int i = 0; i < buffersToUnqueue; i++)
                    {
                        short[] buffer      = streamShortBuffer;
                        int     readSamples = Sound.FillStreamBuffer(streamSeekPos, buffer);
                        if (FilledByNetwork)
                        {
                            if (Sound is VoipSound voipSound)
                            {
                                voipSound.ApplyFilters(buffer, readSamples);
                            }

                            if (readSamples <= 0)
                            {
                                decayTimer++;
                                if (decayTimer > 120) //TODO: replace magic number
                                {
                                    reachedEndSample = true;
                                }
                            }
                            else
                            {
                                decayTimer = 0;
                            }
                        }
                        else if (Sound.StreamsReliably)
                        {
                            streamSeekPos += readSamples;
                            if (readSamples < STREAM_BUFFER_SIZE)
                            {
                                if (looping)
                                {
                                    streamSeekPos = 0;
                                }
                                else
                                {
                                    reachedEndSample = true;
                                }
                            }
                        }

                        if (readSamples > 0)
                        {
                            Al.BufferData <short>(unqueuedBuffers[i], Sound.ALFormat, buffer, readSamples, Sound.SampleRate);

                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to assign data to stream buffer: " +
                                                    Al.GetErrorString(alError) + ": " + unqueuedBuffers[i].ToString() + "/" + unqueuedBuffers.Length + ", readSamples: " + readSamples);
                            }

                            Al.SourceQueueBuffer(alSource, unqueuedBuffers[i]);
                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to queue buffer[" + i.ToString() + "] to stream: " + Al.GetErrorString(alError));
                            }
                        }
                        else if (readSamples < 0)
                        {
                            reachedEndSample = true;
                        }
                        else
                        {
                            emptyBuffers.Add((uint)unqueuedBuffers[i]);
                        }
                    }

                    Al.GetSourcei(alSource, Al.SourceState, out state);
                    if (state != Al.Playing)
                    {
                        Al.SourcePlay(alSource);
                    }
                }
            }
        }
Пример #12
0
        public SoundManager()
        {
            loadedSounds      = new List <Sound>();
            streamingThread   = null;
            categoryModifiers = null;

            alcDevice = Alc.OpenDevice(null);
            if (alcDevice == null)
            {
                DebugConsole.ThrowError("Failed to open an ALC device! Disabling audio playback...");
                Disabled = true;
                return;
            }

            int alcError = Alc.GetError(alcDevice);

            if (alcError != Alc.NoError)
            {
                //The audio device probably wasn't ready, this happens quite often
                //Just wait a while and try again
                Thread.Sleep(100);

                alcDevice = Alc.OpenDevice(null);

                alcError = Alc.GetError(alcDevice);
                if (alcError != Alc.NoError)
                {
                    DebugConsole.ThrowError("Error initializing ALC device: " + alcError.ToString() + ". Disabling audio playback...");
                    Disabled = true;
                    return;
                }
            }

            int[] alcContextAttrs = new int[] { };
            alcContext = Alc.CreateContext(alcDevice, alcContextAttrs);
            if (alcContext == null)
            {
                DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback...");
                Disabled = true;
                return;
            }

            if (!Alc.MakeContextCurrent(alcContext))
            {
                DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback...");
                Disabled = true;
                return;
            }

            alcError = Alc.GetError(alcDevice);
            if (alcError != Alc.NoError)
            {
                DebugConsole.ThrowError("Error after assigning ALC context: " + alcError.ToString() + ". Disabling audio playback...");
                Disabled = true;
                return;
            }

            sourcePools = new SoundSourcePool[2];
            sourcePools[(int)SourcePoolIndex.Default]     = new SoundSourcePool(SOURCE_COUNT);
            playingChannels[(int)SourcePoolIndex.Default] = new SoundChannel[SOURCE_COUNT];

            sourcePools[(int)SourcePoolIndex.Voice]     = new SoundSourcePool(16);
            playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[16];

            Al.DistanceModel(Al.LinearDistanceClamped);

            int alError = Al.GetError();

            if (alError != Al.NoError)
            {
                DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback...");
                Disabled = true;
                return;
            }

            ListenerPosition     = Vector3.Zero;
            ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f);
            ListenerUpVector     = new Vector3(0.0f, -1.0f, 0.0f);

            CompressionDynamicRangeGain = 1.0f;
        }
Пример #13
0
        public OggSound(SoundManager owner, string filename, bool stream) : base(owner, filename, stream, true)
        {
            if (!ToolBox.IsProperFilenameCase(filename))
            {
                DebugConsole.ThrowError("Sound file \"" + filename + "\" has incorrect case!");
            }

            reader = new VorbisReader(filename);

            ALFormat   = reader.Channels == 1 ? Al.FormatMono16 : Al.FormatStereo16;
            SampleRate = reader.SampleRate;

            if (!stream)
            {
                int bufferSize = (int)reader.TotalSamples * reader.Channels;

                float[] floatBuffer = new float[bufferSize];
                short[] shortBuffer = new short[bufferSize];

                int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize);

                CastBuffer(floatBuffer, shortBuffer, readSamples);

                Al.BufferData(ALBuffer, ALFormat, shortBuffer,
                              readSamples * sizeof(short), SampleRate);

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError));
                }

                MuffleBuffer(floatBuffer, SampleRate, reader.Channels);

                CastBuffer(floatBuffer, shortBuffer, readSamples);

                Al.BufferData(ALMuffledBuffer, ALFormat, shortBuffer,
                              readSamples * sizeof(short), SampleRate);

                alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to set buffer data for non-streamed audio! " + Al.GetErrorString(alError));
                }

                reader.Dispose();
            }
        }
Пример #14
0
        public SoundManager()
        {
            loadedSounds      = new List <Sound>();
            streamingThread   = null;
            categoryModifiers = null;

            int alcError = Alc.NoError;

            string deviceName = Alc.GetString(IntPtr.Zero, Alc.DefaultDeviceSpecifier);

            DebugConsole.NewMessage($"Attempting to open ALC device \"{deviceName}\"");

            alcDevice = IntPtr.Zero;
            for (int i = 0; i < 3; i++)
            {
                alcDevice = Alc.OpenDevice(deviceName);
                if (alcDevice == IntPtr.Zero)
                {
                    DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: device is null");
                }
                else
                {
                    alcError = Alc.GetError(alcDevice);
                    if (alcError != Alc.NoError)
                    {
                        DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: error code {Alc.GetErrorString(alcError)}");
                        bool closed = Alc.CloseDevice(alcDevice);
                        if (!closed)
                        {
                            DebugConsole.NewMessage($"Failed to close ALC device");
                        }
                        alcDevice = IntPtr.Zero;
                    }
                }
            }
            if (alcDevice == IntPtr.Zero)
            {
                DebugConsole.ThrowError("ALC device creation failed too many times!");
                Disabled = true;
                return;
            }

            int[] alcContextAttrs = new int[] { };
            alcContext = Alc.CreateContext(alcDevice, alcContextAttrs);
            if (alcContext == null)
            {
                DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback...");
                Disabled = true;
                return;
            }

            if (!Alc.MakeContextCurrent(alcContext))
            {
                DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback...");
                Disabled = true;
                return;
            }

            alcError = Alc.GetError(alcDevice);
            if (alcError != Alc.NoError)
            {
                DebugConsole.ThrowError("Error after assigning ALC context: " + Alc.GetErrorString(alcError) + ". Disabling audio playback...");
                Disabled = true;
                return;
            }

            sourcePools = new SoundSourcePool[2];
            sourcePools[(int)SourcePoolIndex.Default]     = new SoundSourcePool(SOURCE_COUNT);
            playingChannels[(int)SourcePoolIndex.Default] = new SoundChannel[SOURCE_COUNT];

            sourcePools[(int)SourcePoolIndex.Voice]     = new SoundSourcePool(16);
            playingChannels[(int)SourcePoolIndex.Voice] = new SoundChannel[16];

            Al.DistanceModel(Al.LinearDistanceClamped);

            int alError = Al.GetError();

            if (alError != Al.NoError)
            {
                DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback...");
                Disabled = true;
                return;
            }

            ListenerPosition     = Vector3.Zero;
            ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f);
            ListenerUpVector     = new Vector3(0.0f, -1.0f, 0.0f);

            CompressionDynamicRangeGain = 1.0f;
        }
Пример #15
0
        public bool InitializeAlcDevice(string deviceName)
        {
            ReleaseResources(true);

            DebugConsole.NewMessage($"Attempting to open ALC device \"{deviceName}\"");

            alcDevice = IntPtr.Zero;
            int alcError = Al.NoError;

            for (int i = 0; i < 3; i++)
            {
                alcDevice = Alc.OpenDevice(deviceName);
                if (alcDevice == IntPtr.Zero)
                {
                    alcError = Alc.GetError(IntPtr.Zero);
                    DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: device is null (error code {Alc.GetErrorString(alcError)})");
                    if (!string.IsNullOrEmpty(deviceName))
                    {
                        deviceName = null;
                        DebugConsole.NewMessage($"Switching to default device...");
                    }
                }
                else
                {
                    alcError = Alc.GetError(alcDevice);
                    if (alcError != Alc.NoError)
                    {
                        DebugConsole.NewMessage($"ALC device initialization attempt #{i + 1} failed: error code {Alc.GetErrorString(alcError)}");
                        bool closed = Alc.CloseDevice(alcDevice);
                        if (!closed)
                        {
                            DebugConsole.NewMessage($"Failed to close ALC device");
                        }
                        alcDevice = IntPtr.Zero;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            if (alcDevice == IntPtr.Zero)
            {
                DebugConsole.ThrowError("ALC device creation failed too many times!");
                Disabled = true;
                return(false);
            }

            CanDetectDisconnect = Alc.IsExtensionPresent(alcDevice, "ALC_EXT_disconnect");
            alcError            = Alc.GetError(alcDevice);
            if (alcError != Alc.NoError)
            {
                DebugConsole.ThrowError("Error determining if disconnect can be detected: " + alcError.ToString() + ". Disabling audio playback...");
                Disabled = true;
                return(false);
            }

            Disconnected = false;

            int[] alcContextAttrs = new int[] { };
            alcContext = Alc.CreateContext(alcDevice, alcContextAttrs);
            if (alcContext == null)
            {
                DebugConsole.ThrowError("Failed to create an ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback...");
                Disabled = true;
                return(false);
            }

            if (!Alc.MakeContextCurrent(alcContext))
            {
                DebugConsole.ThrowError("Failed to assign the current ALC context! (error code: " + Alc.GetError(alcDevice).ToString() + "). Disabling audio playback...");
                Disabled = true;
                return(false);
            }

            alcError = Alc.GetError(alcDevice);
            if (alcError != Alc.NoError)
            {
                DebugConsole.ThrowError("Error after assigning ALC context: " + Alc.GetErrorString(alcError) + ". Disabling audio playback...");
                Disabled = true;
                return(false);
            }

            Al.DistanceModel(Al.LinearDistanceClamped);

            int alError = Al.GetError();

            if (alError != Al.NoError)
            {
                DebugConsole.ThrowError("Error setting distance model: " + Al.GetErrorString(alError) + ". Disabling audio playback...");
                Disabled = true;
                return(false);
            }

            sourcePools[(int)SourcePoolIndex.Default] = new SoundSourcePool(SOURCE_COUNT);
            sourcePools[(int)SourcePoolIndex.Voice]   = new SoundSourcePool(16);

            ReloadSounds();

            Disabled = false;

            return(true);
        }
Пример #16
0
        public void Dispose()
        {
            try
            {
                if (mutex != null)
                {
                    Monitor.Enter(mutex);
                }
                if (ALSourceIndex >= 0)
                {
                    Al.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
                    int alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        throw new Exception("Failed to stop source: " + debugName + ", " + Al.GetErrorString(alError));
                    }

                    if (IsStream)
                    {
                        uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);

                        Al.SourceStop(alSource);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to stop streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        int buffersToRequeue = 0;

                        buffersToRequeue = 0;
                        Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToRequeue);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to determine processed buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        Al.SourceUnqueueBuffers(alSource, buffersToRequeue, unqueuedBuffers);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to unqueue buffers from streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        Al.Sourcei(alSource, Al.Buffer, 0);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to reset buffer for streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                        }

                        for (int i = 0; i < 4; i++)
                        {
                            Al.DeleteBuffer(streamBuffers[i]);
                            alError = Al.GetError();
                            if (alError != Al.NoError)
                            {
                                throw new Exception("Failed to delete streamBuffers[" + i.ToString() + "] (" + streamBuffers[i].ToString() + "): " + debugName + ", " + Al.GetErrorString(alError));
                            }
                        }

                        reachedEndSample = true;
                    }
                    else
                    {
                        Al.Sourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, 0);
                        alError = Al.GetError();
                        if (alError != Al.NoError)
                        {
                            throw new Exception("Failed to unbind buffer to non-streamed source: " + debugName + ", " + Al.GetErrorString(alError));
                        }
                    }

                    ALSourceIndex = -1;
                    debugName    += " [DISPOSED]";
                }
            }
            finally
            {
                if (mutex != null)
                {
                    Monitor.Exit(mutex);
                }
            }
        }
Пример #17
0
        public bool RequestAlBuffers()
        {
            if (AlBuffer != 0)
            {
                return(false);
            }
            int alError;

            lock (bufferPool)
            {
                while (bufferPool.Count < 2 && BuffersGenerated < MaxBuffers)
                {
                    Al.GenBuffer(out uint newBuffer);
                    alError = Al.GetError();
                    if (alError != Al.NoError)
                    {
                        DebugConsole.AddWarning($"Error when generating sound buffer: {Al.GetErrorString(alError)}. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
                        BuffersGenerated = MaxBuffers;
                    }
                    else if (!Al.IsBuffer(newBuffer))
                    {
                        DebugConsole.AddWarning($"Error when generating sound buffer: result is not a valid buffer. {BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
                        BuffersGenerated = MaxBuffers;
                    }
                    else
                    {
                        bufferPool.Add(newBuffer);
                        BuffersGenerated++;
                        if (BuffersGenerated >= MaxBuffers)
                        {
                            DebugConsole.AddWarning($"{BuffersGenerated} buffer(s) were generated. No more sound buffers will be generated.");
                        }
                    }
                }

                if (bufferPool.Count >= 2)
                {
                    AlBuffer = bufferPool.First();
                    bufferPool.Remove(AlBuffer);
                    AlMuffledBuffer = bufferPool.First();
                    bufferPool.Remove(AlMuffledBuffer);
                    return(true);
                }
            }

            //can't generate any more OpenAL buffers! we'll have to steal a buffer from someone...
            foreach (var otherSound in sound.Owner.LoadedSounds)
            {
                if (otherSound == sound)
                {
                    continue;
                }
                if (otherSound.IsPlaying())
                {
                    continue;
                }
                if (otherSound.Buffers == null)
                {
                    continue;
                }
                if (otherSound.Buffers.AlBuffer == 0)
                {
                    continue;
                }

                // Dispose all channels that are holding
                // a reference to these buffers, otherwise
                // an INVALID_OPERATION error will be thrown
                // when attempting to set the buffer data later.
                // Having the sources not play is not enough,
                // as OpenAL assumes that you may want to call
                // alSourcePlay without reassigning the buffer.
                otherSound.Owner.KillChannels(otherSound);

                AlBuffer                           = otherSound.Buffers.AlBuffer;
                AlMuffledBuffer                    = otherSound.Buffers.AlMuffledBuffer;
                otherSound.Buffers.AlBuffer        = 0;
                otherSound.Buffers.AlMuffledBuffer = 0;

                // For performance reasons, sift the current sound to
                // the end of the loadedSounds list, that way it'll
                // be less likely to have its buffers stolen, which
                // means less reuploads for frequently played sounds.
                sound.Owner.MoveSoundToPosition(sound, sound.Owner.LoadedSoundCount - 1);

                if (!Al.IsBuffer(AlBuffer))
                {
                    throw new Exception(sound.Filename + " has an invalid buffer!");
                }
                if (!Al.IsBuffer(AlMuffledBuffer))
                {
                    throw new Exception(sound.Filename + " has an invalid muffled buffer!");
                }

                return(true);
            }

            return(false);
        }
Пример #18
0
        public virtual void Dispose()
        {
            if (disposed)
            {
                return;
            }

            Owner.KillChannels(this);
            if (alBuffer != 0)
            {
                if (!Al.IsBuffer(alBuffer))
                {
                    throw new Exception("Buffer to delete is invalid!");
                }

                Al.DeleteBuffer(alBuffer); alBuffer = 0;

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }
            }
            if (alMuffledBuffer != 0)
            {
                if (!Al.IsBuffer(alMuffledBuffer))
                {
                    throw new Exception("Buffer to delete is invalid!");
                }

                Al.DeleteBuffer(alMuffledBuffer); alMuffledBuffer = 0;

                int alError = Al.GetError();
                if (alError != Al.NoError)
                {
                    throw new Exception("Failed to delete OpenAL buffer for non-streamed sound: " + Al.GetErrorString(alError));
                }
            }

            Owner.RemoveSound(this);
            disposed = true;
        }