コード例 #1
0
ファイル: AudioBackend.cs プロジェクト: fossabot/jazz2
        internal void EnqueueForStreaming(NativeAudioSource source)
        {
            if (streamWorkerQueue.Contains(source))
            {
                return;
            }

            streamWorkerQueue.Add(source);
            streamWorkerQueueEvent.Set();
        }
コード例 #2
0
ファイル: AudioBackend.cs プロジェクト: fossabot/jazz2
        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();
            }