Пример #1
0
        private void PerformStreamingUpdate()
        {
            int num;

            AL.GetSource(this.handle, ALGetSourcei.BuffersProcessed, out num);
            while (num > 0)
            {
                num--;

                int unqueuedBufferHandle          = AL.SourceUnqueueBuffer(this.handle);
                INativeAudioBuffer unqueuedBuffer = null;
                for (int i = 0; i < this.strAlBuffers.Length; i++)
                {
                    NativeAudioBuffer buffer = this.strAlBuffers[i] as NativeAudioBuffer;
                    if (buffer.Handle == unqueuedBufferHandle)
                    {
                        unqueuedBuffer = buffer;
                        break;
                    }
                }

                bool eof = !this.streamProvider.ReadStream(unqueuedBuffer);
                if (!eof)
                {
                    AL.SourceQueueBuffer(this.handle, unqueuedBufferHandle);
                }
                else
                {
                    this.strStopReq = StopRequest.EndOfStream;
                }
            }
        }
Пример #2
0
        void INativeAudioSource.Play(INativeAudioBuffer buffer)
        {
            if (!this.isInitial)
            {
                throw new InvalidOperationException(
                          "Native audio source already in use. To re-use an audio source, reset it first.");
            }
            this.isInitial = false;
            IsStopped      = false;

            this.strStopReq = StopRequest.None;

            // All samples are available now (buffer is completed)
            NativeAudioBuffer newBuffer = buffer as NativeAudioBuffer;

            AvailableBuffers = new[] { newBuffer };
            QueuedBuffersPos = new[] { 0 };
            QueuedBuffers.Enqueue(0);

            AudioBackend.ActiveInstance.EnqueueForStreaming(this);
        }
Пример #3
0
        private void PerformStreamingUpdate()
        {
            while (true)
            {
                int unqueuedBufferIndex = UnqueuedBuffer;
                for (int i = 0; i < AvailableBuffers.Length; i++)
                {
                    NativeAudioBuffer buffer = AvailableBuffers[i];
                    if (QueuedBuffersPos[i] == UnqueuedBuffer)
                    {
                        // Buffer was played to the end - rewind it to the start and use it
                        buffer.Length       = 0;
                        QueuedBuffersPos[i] = 0;
                        unqueuedBufferIndex = i;
                        break;
                    }
                }

                if (unqueuedBufferIndex == UnqueuedBuffer)
                {
                    // No free buffer found, we are done for now...
                    break;
                }

                // Stream data to the buffer
                bool eof = !streamProvider.ReadStream(AvailableBuffers[unqueuedBufferIndex]);
                if (!eof)
                {
                    QueuedBuffers.Enqueue(unqueuedBufferIndex);
                }
                else
                {
                    strStopReq = StopRequest.EndOfStream;
                }
            }
        }
Пример #4
0
        private void ThreadStreamFunc()
        {
            short[] buffer = new short[bufferSizeSamples];

            Stopwatch watch = new Stopwatch();

            watch.Restart();

            while (!streamWorkerEnd)
            {
                // Process even number of samples (both channels of interleaved stereo)
                // Fill only small part of the main buffer to lower the latency
                // Latency is already quite high on Android
                int samplesPlayed = masterTrack.PlaybackHeadPosition * 2;
                int samplesNeeded = ((samplesPlayed + bufferSizeSamples - samplesWritten) / 12) & ~1;

                for (int j = 0; j < streamWorkerQueue.Count; j++)
                {
                    NativeAudioSource source = streamWorkerQueue[j];

                    // Mix samples into the main buffer
                    int bufferPos = 0;
                    while (bufferPos < samplesNeeded && source.QueuedBuffers.Count > 0)
                    {
                        int     bufferIndex = source.QueuedBuffers.Peek();
                        ref int playbackPos = ref source.QueuedBuffersPos[bufferIndex];

                        NativeAudioBuffer sourceBuffer = source.AvailableBuffers[bufferIndex];
                        int samplesInBuffer            = MathF.Min(sourceBuffer.Length - playbackPos, samplesNeeded - bufferPos);
                        //int samplesInBuffer = MathF.Min((int)((sourceBuffer.Length - playbackPos) / source.LastState.Pitch), samplesNeeded - bufferPos);
                        if (!mute)
                        {
                            //if (MathF.Abs(1f - source.LastState.Pitch) < 0.01f) {
                            for (int i = 0; i < samplesInBuffer; i += 2)
                            {
                                int sampleLeft  = buffer[bufferPos] + (short)(sourceBuffer.InternalBuffer[playbackPos + i] * source.VolumeLeft);
                                int sampleRight = buffer[bufferPos + 1] + (short)(sourceBuffer.InternalBuffer[playbackPos + i + 1] * source.VolumeRight);

                                // Fast check to prevent clipping
                                if (MathF.Abs(sampleLeft) < short.MaxValue &&
                                    MathF.Abs(sampleRight) < short.MaxValue)
                                {
                                    buffer[bufferPos]     = (short)sampleLeft;
                                    buffer[bufferPos + 1] = (short)sampleRight;
                                }

                                bufferPos += 2;
                            }
                            //} else {
                            //    // ToDo: Check this pitch changing...
                            //    for (int i = 0; i < samplesInBuffer; i += 2) {

                            //        float io = playbackPos + (int)(i * source.LastState.Pitch);

                            //        short sample11 = sourceBuffer.InternalBuffer[(int)io];
                            //        short sample12 = sourceBuffer.InternalBuffer[MathF.Min((int)io + 2, sourceBuffer.Length - 2)];

                            //        short sampleLeft = (short)((sample11 + (sample12 - sample11) * (io % 1f)) * source.VolumeLeft);

                            //        short sample21 = sourceBuffer.InternalBuffer[MathF.Min((int)io + 1, sourceBuffer.Length - 1)];
                            //        short sample22 = sourceBuffer.InternalBuffer[MathF.Min((int)io + 3, sourceBuffer.Length - 1)];
                            //        short sampleRight = (short)((sample21 + (sample22 - sample21) * (io % 1f)) * source.VolumeRight);

                            //        // Fast check to prevent clipping
                            //        // ToDo: Do this better somehow...
                            //        if (MathF.Abs(buffer[bufferPos] + sampleLeft) < short.MaxValue &&
                            //            MathF.Abs(buffer[bufferPos + 1] + sampleRight) < short.MaxValue) {
                            //            buffer[bufferPos] += sampleLeft;
                            //            buffer[bufferPos + 1] += sampleRight;
                            //        }

                            //        bufferPos += 2;
                            //    }
                            //}
                        }
                        playbackPos += samplesInBuffer;
                        //playbackPos += (int)(samplesInBuffer * source.LastState.Pitch);

                        if (playbackPos >= sourceBuffer.Length)
                        {
                            playbackPos = NativeAudioSource.UnqueuedBuffer;
                            source.QueuedBuffers.Dequeue();
                        }
                    }

                    // Perform the necessary streaming operations on the audio source, and remove it when requested
                    if (source.IsStreamed)
                    {
                        // Try to stream new data
                        if (source.IsStopped || !source.PerformStreaming())
                        {
                            // End of stream, remove from queue
                            streamWorkerQueue.RemoveAtFast(j);
                            j--;
                        }
                    }
                    else
                    {
                        if (source.QueuedBuffers.Count == 0)
                        {
                            if (source.LastState.Looped)
                            {
                                // Enqueue sample again if looping is turned on
                                source.QueuedBuffers.Enqueue(0);
                                source.QueuedBuffersPos[0] = 0;
                            }
                            else
                            {
                                // End of sample array, remove from queue
                                streamWorkerQueue.RemoveAtFast(j);
                                j--;
                            }
                        }
                    }
                }

                // Write used part of the main buffer to Android's Audio Track
                masterTrack.Write(buffer, 0, samplesNeeded);
                samplesWritten += samplesNeeded;

                // Erase buffer to be ready for next batch
                for (int i = 0; i < samplesNeeded; i++)
                {
                    buffer[i] = 0;
                }

                // After each roundtrip, sleep a little, don't keep the processor busy for no reason
                watch.Stop();
                int roundtripTime = (int)watch.ElapsedMilliseconds;
                if (roundtripTime <= 1)
                {
                    streamWorkerQueueEvent.WaitOne(16);
                }
                watch.Restart();
            }