public void QueueChunk(AudioChunk chunk) { if (_outputDevice != null) { _activeStream.QueueChunk(chunk); } }
public void QueueChunk(AudioChunk chunk) { _streamLock.WaitOne(); short[] resampledData = Lanczos.Resample(chunk.Data, chunk.SampleRate, 44100); AudioChunk resampledChunk = new AudioChunk(resampledData, 44100); _inputChunks.Enqueue(resampledChunk); _streamLock.ReleaseMutex(); }
public AudioChunk Concatenate(AudioChunk other) { AudioChunk toConcatenate = other; int combinedDataLength = DataLength + toConcatenate.DataLength; short[] combinedData = new short[combinedDataLength]; Array.Copy(Data, combinedData, DataLength); Array.Copy(toConcatenate.Data, 0, combinedData, DataLength, toConcatenate.DataLength); return(new AudioChunk(combinedData, SampleRate)); }
public byte[] Compress(AudioChunk input) { int frameSize = GetFrameSize(); if (input != null) { short[] newData = input.Data; _incomingSamples.Write(newData); } else { // If input is null, assume we are at end of stream and pad the output with zeroes int paddingNeeded = _incomingSamples.Available() % frameSize; if (paddingNeeded > 0) { _incomingSamples.Write(new short[paddingNeeded]); } } int outCursor = 0; if (_incomingSamples.Available() >= frameSize) { unsafe { fixed(byte *benc = scratchBuffer) { short[] nextFrameData = _incomingSamples.Read(frameSize); byte[] nextFrameBytes = AudioMath.ShortsToBytes(nextFrameData); IntPtr encodedPtr = new IntPtr(benc); _timer.Reset(); _timer.Start(); int thisPacketSize = opus_encode(_encoder, nextFrameBytes, frameSize, encodedPtr, scratchBuffer.Length); outCursor += thisPacketSize; _timer.Stop(); } } } if (outCursor > 0) { _statistics.EncodeSpeed = _frameSize / ((double)_timer.ElapsedTicks / Stopwatch.Frequency * 1000); } byte[] finalOutput = new byte[outCursor]; Array.Copy(scratchBuffer, 0, finalOutput, 0, outCursor); return(finalOutput); }
public void Run(object dummy) { foreach (var inputStream in InputFiles) { inputStream.Initialize(); } _running = true; _player.Start(); while (_running) { // Spin until the output buffer has some room while (_player.BufferSizeMs() > BUFFER_LENGTH_MS) { Thread.Sleep(5); } // Check for updated parameters and send them to the codec if needed _codecParamLock.WaitOne(); if (_codecParamChanged) { _currentCodec.SetBitrate(_bitrate); _currentCodec.SetComplexity(_complexity); _currentCodec.SetFrameSize(_frameSize); _currentCodec.SetPacketLoss(_packetLoss); _currentCodec.SetApplication(_application); _currentCodec.SetVBRMode(_useVBR, _useCVBR); _codecParamChanged = false; } AudioChunk inputPcm = _currentMusic.ReadChunk(); _codecParamLock.ReleaseMutex(); // Run the opus encoder and decoder byte[] compressedFrame = _currentCodec.Compress(inputPcm); if (compressedFrame != null && compressedFrame.Length > 0) { AudioChunk decompressed = _currentCodec.Decompress(compressedFrame); // Pipe the output to the audio device _player.QueueChunk(decompressed); } } }
/// <summary> /// Sends an encoded audio sample through a decompressor and returns the decoded audio /// </summary> /// <param name="input"></param> /// <param name="decompressor"></param> /// <returns></returns> internal static AudioChunk DecompressAudioUsingStream(byte[] input, IAudioDecompressionStream decompressor) { if (decompressor == null) { return(null); } AudioChunk first = decompressor.Decompress(input); AudioChunk second = decompressor.Close(); if (second != null && second.DataLength > 0) { first = first.Concatenate(second); } return(first); }
/// <summary> /// Sends an entire audio chunk through a compressor and returns the byte array output and encode params /// </summary> /// <param name="audio"></param> /// <param name="compressor"></param> /// <param name="encodeParams"></param> /// <returns></returns> internal static byte[] CompressAudioUsingStream(AudioChunk audio, IAudioCompressionStream compressor, out string encodeParams) { if (compressor == null) { encodeParams = "ERROR: NULL ENCODER"; return(new byte[0]); } encodeParams = compressor.GetEncodeParams(); byte[] body = compressor.Compress(audio); byte[] footer = compressor.Close(); if (footer == null) { footer = new byte[0]; } byte[] returnVal = new byte[body.Length + footer.Length]; Array.Copy(body, 0, returnVal, 0, body.Length); Array.Copy(footer, 0, returnVal, body.Length, footer.Length); return(returnVal); }
public int Read(float[] buffer, int offset, int count) { if (_nextChunk == null) { _streamLock.WaitOne(); if (_inputChunks.Count != 0) { _nextChunk = _inputChunks.Dequeue(); _streamLock.ReleaseMutex(); } else { // Serious buffer underrun. In this case, just return silence instead of stuttering _nextChunk = null; for (int c = 0; c < count; c++) { buffer[c + offset] = 0.0f; } _streamLock.ReleaseMutex(); return(count); } } int samplesWritten = 0; short[] returnVal = new short[count]; while (samplesWritten < count && _nextChunk != null) { int remainingInThisChunk = _nextChunk.DataLength - _inCursor; int remainingToWrite = (count - samplesWritten); int chunkSize = Math.Min(remainingInThisChunk, remainingToWrite); Array.Copy(_nextChunk.Data, _inCursor, returnVal, samplesWritten, chunkSize); _inCursor += chunkSize; samplesWritten += chunkSize; if (_inCursor >= _nextChunk.DataLength) { _inCursor = 0; _streamLock.WaitOne(); if (_inputChunks.Count != 0) { _nextChunk = _inputChunks.Dequeue(); _streamLock.ReleaseMutex(); } else { _nextChunk = null; for (int c = 0; c < count; c++) { buffer[c + offset] = 0.0f; } _streamLock.ReleaseMutex(); return(count); } } } for (int c = 0; c < samplesWritten; c++) { buffer[c + offset] = ((float)returnVal[c]) / ((float)short.MaxValue); } return(samplesWritten); }