internal override FlacMethodAndDataPair[] FindBestMethods(int[][] samples, int bitsPerSamples) { FlacMethodAndDataPair[] samplesAndMethods = new FlacMethodAndDataPair[samples.Length]; parallel.For(0, samples.Length, i => { samplesAndMethods[i] = new FlacMethodAndDataPair( FindBestMethod(samples[i], bitsPerSamples), bitsPerSamples, samples[i]); }); return(samplesAndMethods); }
private void WriteSubframe(FlacBitStreamWriter bitWriter, FlacMethodAndDataPair flacMethodAndDataPair) { bitWriter.WriteUnsigned(0, 1); int subframeType = flacMethodAndDataPair.Method.SubframeTypeCode; bitWriter.WriteUnsigned((uint)subframeType, 6); bitWriter.WriteUnsigned(0, 1); flacMethodAndDataPair.WriteData(bitWriter); }
internal override FlacMethodAndDataPair[] FindBestMethods(int[][] samples, int bitsPerSamples) { FlacMethodAndDataPair[] samplesAndMethods = new FlacMethodAndDataPair[samples.Length]; parallel.For(0, samples.Length, i => { samplesAndMethods[i] = new FlacMethodAndDataPair( FindBestMethod(samples[i], bitsPerSamples), bitsPerSamples, samples[i]); }); return samplesAndMethods; }
public void WriteFrame(FlacMethodAndDataPair[] methods, SoundChannelAssignmentType channelAssignment) { EnsureFramesMode(); sink.StartFrame(streamPosition, currentSample); if (methods == null) throw new ArgumentNullException("methods"); if(methods.Length != Streaminfo.ChannelsCount) throw new ArgumentNullException("Methods items does not correspond to amount of channels"); int samplesCount = methods[0].Data.Length; const byte Blocking = 0x00; // fixed MemoryStream frameHeader = new MemoryStream(); // sync code + reserved = 0 + blocking frameHeader.WriteByte(0xFF); frameHeader.WriteByte(0xF8 | Blocking); int interChannelSamplesTypeIndex = Array.IndexOf(FlacCommons.StaticBlockSizeSamples, samplesCount); int interChannelSamplesType; if (interChannelSamplesTypeIndex > 0) interChannelSamplesType = interChannelSamplesTypeIndex; else if (samplesCount > 256) interChannelSamplesType = FlacCommons.Bit16BlockSizeSamplesType; else interChannelSamplesType = FlacCommons.Bit8BlockSizeSamplesType; int sampleRateTypeIndex = Array.IndexOf(FlacCommons.StaticSampleRates, Streaminfo.SampleRate); int sampleRateType = sampleRateTypeIndex > 0 ? sampleRateTypeIndex : FlacCommons.StreaminfoSampleRateType; frameHeader.WriteByte((byte)(interChannelSamplesType << 4 | sampleRateType)); int channelAssignmetType = (int)channelAssignment; int sampleSizeInBitsTypeIndex = Array.IndexOf(FlacCommons.StaticSampleSizeInBits, Streaminfo.BitsPerSample); int sampleSizeInBitsType = sampleSizeInBitsTypeIndex > 0 ? sampleSizeInBitsTypeIndex : FlacCommons.StreaminfoSizeInBitsType; frameHeader.WriteByte((byte)(channelAssignmetType << 4 | sampleSizeInBitsType << 1)); WriteUtf8Number(frameHeader, frameNumber); switch (interChannelSamplesType) { case FlacCommons.Bit8BlockSizeSamplesType: frameHeader.WriteByte((byte)(samplesCount - 1)); break; case FlacCommons.Bit16BlockSizeSamplesType: frameHeader.WriteByte((byte)((samplesCount - 1) >> 8)); frameHeader.WriteByte((byte)(samplesCount - 1)); break; } frameHeader.Close(); byte[] frameHeaderData = frameHeader.ToArray(); byte crc8 = CrcUtils.Crc8(0, frameHeaderData); BaseStream.Write(frameHeaderData, 0, frameHeaderData.Length); BaseStream.WriteByte(crc8); ++frameNumber; ushort crc16Seed = CrcUtils.Crc16(CrcUtils.Crc16(0, frameHeaderData), crc8); // write channels FlacBitStreamWriter bitWriter = new FlacBitStreamWriter(BaseStream, crc16Seed); for (int i = 0; i < methods.Length; i++) { WriteSubframe(bitWriter, methods[i]); } int subframesLength; ushort crc16; bitWriter.Complete(out crc16, out subframesLength); // write footer BaseStream.WriteByte((byte)(crc16 >> 8)); BaseStream.WriteByte((byte)crc16); int frameSize = frameHeaderData.Length + 1 + subframesLength + 2; streamPosition += frameSize; currentSample += samplesCount; sink.EndFrame(streamPosition, currentSample); }
public SoundChannelAssignmentType FindBestMethod(int[] leftSamples, int[] rightSamples, out FlacMethodAndDataPair[] methods) { if (leftSamples == null) throw new ArgumentNullException("leftSamples"); if (rightSamples == null) throw new ArgumentNullException("rightSamples"); if (leftSamples.Length != rightSamples.Length) throw new ArgumentException("leftSamples and rightSamples has to have same amount of samples"); if(leftSamples.Length == 0) throw new ArgumentException("channels has to have at least one item"); return estimator.FindBestMethods(leftSamples, rightSamples, Streaminfo.BitsPerSample, out methods); }
internal override SoundChannelAssignmentType FindBestMethods(int[] leftSamples, int[] rightSamples, int bitsPerSample, out FlacMethodAndDataPair[] methods) { if (policy.StereoEncoding == StereoEncodingPolicy.AsIs) { methods = FindBestMethods(new int[2][] { leftSamples, rightSamples }, bitsPerSample); return(SoundChannelAssignmentType.LeftRight); } int samplesPerChannel = leftSamples.Length; int[] differenceLeftMinusRight = null, average = null; FlacMethod methodForLeft = null, methodForRight = null, methodForSide = null, methodForAverage = null; parallel.Invoke( delegate { methodForLeft = FindBestMethod(leftSamples, bitsPerSample); }, delegate { methodForRight = FindBestMethod(rightSamples, bitsPerSample); }, delegate { differenceLeftMinusRight = new int[samplesPerChannel]; for (int i = 0; i < samplesPerChannel; i++) { differenceLeftMinusRight[i] = leftSamples[i] - rightSamples[i]; } methodForSide = FindBestMethod(differenceLeftMinusRight, bitsPerSample + 1); }, delegate { if (policy.StereoEncoding == StereoEncodingPolicy.TrySidesAndAverage) { average = new int[samplesPerChannel]; for (int i = 0; i < samplesPerChannel; i++) { average[i] = (leftSamples[i] + rightSamples[i]) >> 1; } methodForAverage = FindBestMethod(average, bitsPerSample); } } ); int independentEstimation = methodForLeft.EstimatedSize + methodForRight.EstimatedSize; int leftSideEstimation = methodForLeft.EstimatedSize + methodForSide.EstimatedSize; int rightSideEstimation = methodForSide.EstimatedSize + methodForRight.EstimatedSize; int averageEstimation = average == null ? int.MaxValue : methodForAverage.EstimatedSize + methodForSide.EstimatedSize; SoundChannelAssignmentType type; if (Math.Min(independentEstimation, leftSideEstimation) < Math.Min(rightSideEstimation, averageEstimation)) { if (independentEstimation <= leftSideEstimation) { type = SoundChannelAssignmentType.LeftRight; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForLeft, bitsPerSample, leftSamples), new FlacMethodAndDataPair(methodForRight, bitsPerSample, rightSamples) }; } else { type = SoundChannelAssignmentType.LeftSide; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForLeft, bitsPerSample, leftSamples), new FlacMethodAndDataPair(methodForSide, bitsPerSample + 1, differenceLeftMinusRight) }; } } else { if (rightSideEstimation <= averageEstimation) { type = SoundChannelAssignmentType.RightSide; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForSide, bitsPerSample + 1, differenceLeftMinusRight), new FlacMethodAndDataPair(methodForRight, bitsPerSample, rightSamples) }; } else { type = SoundChannelAssignmentType.MidSide; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForAverage, bitsPerSample, average), new FlacMethodAndDataPair(methodForSide, bitsPerSample + 1, differenceLeftMinusRight) }; } } return(type); }
internal override SoundChannelAssignmentType FindBestMethods(int[] leftSamples, int[] rightSamples, int bitsPerSample, out FlacMethodAndDataPair[] methods) { if (policy.StereoEncoding == StereoEncodingPolicy.AsIs) { methods = FindBestMethods(new int[2][] { leftSamples, rightSamples }, bitsPerSample); return SoundChannelAssignmentType.LeftRight; } int samplesPerChannel = leftSamples.Length; int[] differenceLeftMinusRight = null, average = null; FlacMethod methodForLeft = null, methodForRight = null, methodForSide = null, methodForAverage = null; parallel.Invoke( delegate { methodForLeft = FindBestMethod(leftSamples, bitsPerSample); }, delegate { methodForRight = FindBestMethod(rightSamples, bitsPerSample); }, delegate { differenceLeftMinusRight = new int[samplesPerChannel]; for (int i = 0; i < samplesPerChannel; i++) { differenceLeftMinusRight[i] = leftSamples[i] - rightSamples[i]; } methodForSide = FindBestMethod(differenceLeftMinusRight, bitsPerSample + 1); }, delegate { if (policy.StereoEncoding == StereoEncodingPolicy.TrySidesAndAverage) { average = new int[samplesPerChannel]; for (int i = 0; i < samplesPerChannel; i++) { average[i] = (leftSamples[i] + rightSamples[i]) >> 1; } methodForAverage = FindBestMethod(average, bitsPerSample); } } ); int independentEstimation = methodForLeft.EstimatedSize + methodForRight.EstimatedSize; int leftSideEstimation = methodForLeft.EstimatedSize + methodForSide.EstimatedSize; int rightSideEstimation = methodForSide.EstimatedSize + methodForRight.EstimatedSize; int averageEstimation = average == null ? int.MaxValue : methodForAverage.EstimatedSize + methodForSide.EstimatedSize; SoundChannelAssignmentType type; if (Math.Min(independentEstimation, leftSideEstimation) < Math.Min(rightSideEstimation, averageEstimation)) { if (independentEstimation <= leftSideEstimation) { type = SoundChannelAssignmentType.LeftRight; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForLeft, bitsPerSample, leftSamples), new FlacMethodAndDataPair(methodForRight, bitsPerSample, rightSamples) }; } else { type = SoundChannelAssignmentType.LeftSide; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForLeft, bitsPerSample, leftSamples), new FlacMethodAndDataPair(methodForSide, bitsPerSample + 1, differenceLeftMinusRight) }; } } else { if (rightSideEstimation <= averageEstimation) { type = SoundChannelAssignmentType.RightSide; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForSide, bitsPerSample + 1, differenceLeftMinusRight), new FlacMethodAndDataPair(methodForRight, bitsPerSample, rightSamples) }; } else { type = SoundChannelAssignmentType.MidSide; methods = new FlacMethodAndDataPair[] { new FlacMethodAndDataPair(methodForAverage, bitsPerSample, average), new FlacMethodAndDataPair(methodForSide, bitsPerSample + 1, differenceLeftMinusRight) }; } } return type; }
internal abstract SoundChannelAssignmentType FindBestMethods(int[] leftSamples, int[] rightSamples, int bitsPerSample, out FlacMethodAndDataPair[] methods);