예제 #1
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;
            }
        }
예제 #2
0
        internal unsafe AudioClip(IResource resource)
        {
            Al.GenBuffer(out Buffer);

            using var reader = new VorbisReader(resource.OpenStream());

            var channels   = reader.Channels;
            var sampleRate = reader.SampleRate;
            var seconds    = reader.TotalTime.TotalSeconds;
            var samples    = (int)Math.Ceiling(seconds * sampleRate * channels);

            var floats = new Span <float>(new float[samples]);

            if (reader.ReadSamples(floats) <= 0)
            {
                throw new Exception("Failed to read OGG stream.");
            }

            var shorts = new Span <short>(new short[samples]); // 16 bit

            for (var i = 0; i < floats.Length; i++)
                shorts[i] = (short)(short.MaxValue * floats[i]);

            fixed(void *p = &shorts.GetPinnableReference())
            {
                Al.BufferData(Buffer, channels == 2 ? Al.FormatStereo16 : Al.FormatMono16, p, shorts.Length * sizeof(short), sampleRate);
            }
        }
예제 #3
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();
            }
        }
예제 #4
0
        protected override unsafe void CreateInternal(byte[] soundData)
        {
            // Load by base SoundFile.
            base.CreateInternal(soundData);

            // Upload to the sound manager.
            ALThread.ExecuteALThread(() =>
            {
                Al.GenBuffer(out uint buffer);
                ALBuffer = buffer;

                fixed(byte *dataBuffer = &soundData[0])
                {
                    Al.BufferData(ALBuffer, GetSoundFormat(Channels, BitsPerSample), dataBuffer, soundData.Length, SampleRate);
                }
            }).Wait();
        }
예제 #5
0
        private int Buffer(short[] data, uint id)
        {
            var numSamples = GetDataChunk(data);

            if (numSamples < 0)
            {
                return(numSamples);
            }
            unsafe
            {
                fixed(short *pData = data)
                {
                    Al.BufferData(id, Al.FormatMono16, pData, numSamples * 2, _rate);
                }
            }
            return(numSamples);
        }
예제 #6
0
 /// <summary>
 /// For some reason you can't use unsafe code in coroutines :)
 /// </summary>
 private void UploadDataToBuffer(byte[] data, uint buffer, int byteLengthPerSampleChannel)
 {
     Al.BufferData(buffer, _openALFormatId, data, byteLengthPerSampleChannel, _openALAudioFormat.SampleRate);
     CheckALError();
 }
예제 #7
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();
            }
        }
예제 #8
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);
            }
        }
예제 #9
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);
                    }
                }
            }
        }