2009-08-22 22:13:03 +00:00
/ * *
* CUETools . Flake : pure managed FLAC audio encoder
2012-04-08 23:54:36 +00:00
* Copyright ( c ) 2009 Grigory Chudov
2009-08-22 22:13:03 +00:00
* Based on Flake encoder , http : //flake-enc.sourceforge.net/
* Copyright ( c ) 2006 - 2009 Justin Ruggles
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
* /
2010-05-18 17:18:37 +00:00
#define NOINTEROP
2014-08-26 23:48:16 -04:00
#define VARIANT1
2009-10-16 23:35:56 +00:00
2009-08-17 03:39:53 +00:00
using System ;
2010-05-18 17:18:37 +00:00
using System.ComponentModel ;
2009-08-17 03:39:53 +00:00
using System.Text ;
using System.IO ;
using System.Collections.Generic ;
using System.Security.Cryptography ;
2009-10-16 23:35:56 +00:00
#if INTEROP
using System.Runtime.InteropServices ;
#endif
2009-08-17 03:39:53 +00:00
using CUETools.Codecs ;
namespace CUETools.Codecs.FLAKE
{
2013-04-07 20:41:58 -04:00
public class FlakeWriterSettings : AudioEncoderSettings
{
public FlakeWriterSettings ( )
2013-04-08 23:11:03 -04:00
: base ( )
2013-04-07 20:41:58 -04:00
{
2013-04-01 23:03:22 -04:00
}
2013-04-08 23:11:03 -04:00
public override string GetSupportedModes ( out string defaultMode )
2013-04-01 23:03:22 -04:00
{
2013-04-08 23:11:03 -04:00
defaultMode = "7" ;
2013-06-18 20:45:53 -04:00
return this . AllowNonSubset | | ( this . PCM ! = null & & this . PCM . SampleRate > 48000 ) ? "0 1 2 3 4 5 6 7 8 9 10 11" : "0 1 2 3 4 5 6 7 8" ;
2013-04-01 23:03:22 -04:00
}
2013-06-18 20:45:53 -04:00
public bool IsSubset ( )
2013-04-04 22:07:15 -04:00
{
2013-06-18 20:45:53 -04:00
return ( BlockSize = = 0 | | ( BlockSize < = 16384 & & ( PCM . SampleRate > 48000 | | BlockSize < = 4608 ) ) )
& & ( PCM . SampleRate > 48000 | | MaxLPCOrder < = 12 )
& & MaxPartitionOrder < = 8
;
//The blocksize bits in the frame header must be 0001-1110. The blocksize must be <=16384; if the sample rate is <= 48000Hz, the blocksize must be <=4608.
//The sample rate bits in the frame header must be 0001-1110.
//The bits-per-sample bits in the frame header must be 001-111.
//If the sample rate is <= 48000Hz, the filter order in LPC subframes must be less than or equal to 12, i.e. the subframe type bits in the subframe header may not be 101100-111111.
//The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
2013-04-04 22:07:15 -04:00
}
2013-06-18 20:45:53 -04:00
public void Validate ( )
{
if ( EncoderModeIndex < 0 )
throw new Exception ( "unsupported encoder mode" ) ;
2013-06-19 03:40:43 -04:00
SetDefaultValuesForMode ( ) ;
2013-06-18 20:45:53 -04:00
if ( Padding < 0 )
throw new Exception ( "unsupported padding value " + Padding . ToString ( ) ) ;
if ( BlockSize ! = 0 & & ( BlockSize < 256 | | BlockSize > = Flake . MAX_BLOCKSIZE ) )
throw new Exception ( "unsupported block size " + BlockSize . ToString ( ) ) ;
if ( MinLPCOrder > MaxLPCOrder | | MaxLPCOrder > lpc . MAX_LPC_ORDER )
throw new Exception ( "invalid MaxLPCOrder " + MaxLPCOrder . ToString ( ) ) ;
if ( MinFixedOrder < 0 | | MinFixedOrder > 4 )
throw new Exception ( "invalid MinFixedOrder " + MinFixedOrder . ToString ( ) ) ;
if ( MaxFixedOrder < 0 | | MaxFixedOrder > 4 )
throw new Exception ( "invalid MaxFixedOrder " + MaxFixedOrder . ToString ( ) ) ;
if ( MinPartitionOrder < 0 )
throw new Exception ( "invalid MinPartitionOrder " + MinPartitionOrder . ToString ( ) ) ;
if ( MinPartitionOrder > MaxPartitionOrder | | MaxPartitionOrder > 8 )
throw new Exception ( "invalid MaxPartitionOrder " + MaxPartitionOrder . ToString ( ) ) ;
2014-12-08 22:18:34 -05:00
if ( PredictionType = = PredictionType . None )
throw new Exception ( "invalid PredictionType " + PredictionType . ToString ( ) ) ;
if ( PredictionType ! = PredictionType . Fixed )
{
if ( WindowMethod = = WindowMethod . Invalid )
throw new InvalidOperationException ( "invalid WindowMethod " + WindowMethod . ToString ( ) ) ;
if ( WindowFunctions = = WindowFunction . None )
throw new InvalidOperationException ( "invalid WindowFunctions " + WindowFunctions . ToString ( ) ) ;
if ( EstimationDepth > 32 | | EstimationDepth < 1 )
throw new InvalidOperationException ( "invalid EstimationDepth " + EstimationDepth . ToString ( ) ) ;
if ( MinPrecisionSearch < 0 | | MinPrecisionSearch > = lpc . MAX_LPC_PRECISIONS )
throw new Exception ( "unsupported MinPrecisionSearch value" ) ;
if ( MaxPrecisionSearch < 0 | | MaxPrecisionSearch > = lpc . MAX_LPC_PRECISIONS )
throw new Exception ( "unsupported MaxPrecisionSearch value" ) ;
if ( MaxPrecisionSearch < MinPrecisionSearch )
throw new Exception ( "unsupported MaxPrecisionSearch value" ) ;
}
2013-06-18 20:45:53 -04:00
if ( ! AllowNonSubset & & ! IsSubset ( ) )
throw new Exception ( "the encoding parameters specified do not conform to the FLAC Subset" ) ;
}
[DefaultValue(-1)]
2014-12-08 22:18:34 -05:00
[DefaultValueForMode(2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0)]
2013-06-18 20:45:53 -04:00
[Browsable(false)]
[DisplayName("MinFixedOrder")]
[SRDescription(typeof(Properties.Resources), "MinFixedOrderDescription")]
public int MinFixedOrder { get ; set ; }
[DefaultValue(-1)]
2014-12-08 22:18:34 -05:00
[DefaultValueForMode(2, 4, 4, 4, 2, 2, 4, 4, 4, 4, 4, 4)]
2013-06-18 20:45:53 -04:00
[Browsable(false)]
[DisplayName("MaxFixedOrder")]
[SRDescription(typeof(Properties.Resources), "MaxFixedOrderDescription")]
public int MaxFixedOrder { get ; set ; }
[DefaultValue(1)]
[Browsable(false)]
[DisplayName("MinLPCOrder")]
[SRDescription(typeof(Properties.Resources), "MinLPCOrderDescription")]
public int MinLPCOrder { get ; set ; }
[DefaultValue(-1)]
2014-08-26 23:48:16 -04:00
[DefaultValueForMode(8, 8, 8, 12, 12, 12, 12, 12, 12, 32, 32, 32)]
2013-06-18 20:45:53 -04:00
[Browsable(false)]
[DisplayName("MaxLPCOrder")]
[SRDescription(typeof(Properties.Resources), "MaxLPCOrderDescription")]
public int MaxLPCOrder { get ; set ; }
[DefaultValue(0)]
[DisplayName("MinPartitionOrder")]
[Browsable(false)]
[SRDescription(typeof(Properties.Resources), "MinPartitionOrderDescription")]
public int MinPartitionOrder { get ; set ; }
[DefaultValue(-1)]
2014-12-08 22:18:34 -05:00
[DefaultValueForMode(6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 8)]
2013-06-18 20:45:53 -04:00
[DisplayName("MaxPartitionOrder")]
[Browsable(false)]
[SRDescription(typeof(Properties.Resources), "MaxPartitionOrderDescription")]
public int MaxPartitionOrder { get ; set ; }
2013-04-07 20:41:58 -04:00
[DefaultValue(false)]
[DisplayName("Verify")]
[SRDescription(typeof(Properties.Resources), "DoVerifyDescription")]
public bool DoVerify { get ; set ; }
2010-05-18 17:18:37 +00:00
2013-04-07 20:41:58 -04:00
[DefaultValue(true)]
[DisplayName("MD5")]
[SRDescription(typeof(Properties.Resources), "DoMD5Description")]
public bool DoMD5 { get ; set ; }
2010-05-18 17:18:37 +00:00
2013-04-01 23:03:22 -04:00
[DefaultValue(false)]
[DisplayName("Allow Non-subset")]
[SRDescription(typeof(Properties.Resources), "AllowNonSubsetDescription")]
public bool AllowNonSubset { get ; set ; }
2014-12-08 22:18:34 -05:00
[DefaultValue(StereoMethod.Invalid)]
[ DefaultValueForMode (
/* 0 */ StereoMethod . Independent ,
/* 1 */ StereoMethod . EstimateFixed ,
/* 2 */ StereoMethod . Estimate ,
/* 3 */ StereoMethod . Estimate ,
/* 4 */ StereoMethod . Evaluate ,
/* 5 */ StereoMethod . Evaluate ,
/* 6 */ StereoMethod . Evaluate ,
/* 7 */ StereoMethod . Evaluate ,
/* 8 */ StereoMethod . Evaluate ,
/* 9 */ StereoMethod . Evaluate ,
/* 10 */ StereoMethod . Evaluate ,
/* 11 */ StereoMethod . Evaluate ) ]
[Browsable(false)]
public StereoMethod StereoMethod { get ; set ; }
[DefaultValue(PredictionType.None)]
[ DefaultValueForMode (
/* 0 */ PredictionType . Fixed ,
/* 1 */ PredictionType . Fixed ,
/* 2 */ PredictionType . Levinson ,
/* 3 */ PredictionType . Levinson ,
/* 4 */ PredictionType . Search ,
/* 5 */ PredictionType . Search ,
/* 6 */ PredictionType . Search ,
/* 7 */ PredictionType . Search ,
/* 8 */ PredictionType . Search ,
/* 9 */ PredictionType . Levinson ,
/* 10 */ PredictionType . Search ,
/* 11 */ PredictionType . Search ) ]
[Browsable(false)]
public PredictionType PredictionType { get ; set ; }
[DefaultValue(WindowMethod.Invalid)]
[ DefaultValueForMode (
/* 0 */ WindowMethod . Invalid ,
/* 1 */ WindowMethod . Invalid ,
/* 2 */ WindowMethod . Estimate ,
/* 3 */ WindowMethod . Estimate ,
/* 4 */ WindowMethod . Estimate ,
/* 5 */ WindowMethod . EvaluateN ,
/* 6 */ WindowMethod . EvaluateN ,
/* 7 */ WindowMethod . EvaluateN ,
/* 8 */ WindowMethod . EvaluateN ,
/* 9 */ WindowMethod . EvaluateN ,
/* 10 */ WindowMethod . EvaluateN ,
/* 11 */ WindowMethod . EvaluateN ) ]
[Browsable(false)]
public WindowMethod WindowMethod { get ; set ; }
[DefaultValue(WindowFunction.None)]
[ DefaultValueForMode (
/* 0 */ WindowFunction . None ,
/* 1 */ WindowFunction . None ,
/* 2 */ WindowFunction . Tukey3 ,
/* 3 */ WindowFunction . Tukey4 ,
/* 4 */ WindowFunction . Tukey4 ,
/* 5 */ WindowFunction . Tukey4 | WindowFunction . Tukey3 ,
/* 6 */ WindowFunction . Tukey4 | WindowFunction . Tukey3 | WindowFunction . Tukey ,
/* 7 */ WindowFunction . Tukey4 | WindowFunction . Tukey3 | WindowFunction . Tukey2 | WindowFunction . Tukey ,
/* 8 */ WindowFunction . Tukey4 | WindowFunction . Tukey3 | WindowFunction . Tukey2 | WindowFunction . Tukey ,
/* 9 */ WindowFunction . Tukey3 | WindowFunction . Tukey2 | WindowFunction . Tukey ,
/* 10 */ WindowFunction . Tukey3 | WindowFunction . Tukey2 | WindowFunction . Tukey ,
/* 11 */ WindowFunction . Tukey3 | WindowFunction . Tukey2 | WindowFunction . Tukey ) ]
[Browsable(false)]
[DisplayName("WindowFunctions")]
[SRDescription(typeof(Properties.Resources), "WindowFunctionsDescription")]
public WindowFunction WindowFunctions { get ; set ; }
[DefaultValue(0)]
[DefaultValueForMode(0, 0, 1, 1, 1, 1, 1, 1, 3, 1, 1, 5)]
[Browsable(false)]
public int EstimationDepth { get ; set ; }
[DefaultValue(-1)]
[DefaultValueForMode(1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1)]
[Browsable(false)]
public int MinPrecisionSearch { get ; set ; }
[DefaultValue(-1)]
[DefaultValueForMode(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)]
[Browsable(false)]
public int MaxPrecisionSearch { get ; set ; }
[DefaultValue(0)]
[Browsable(false)]
public int TukeyParts { get ; set ; }
[DefaultValue(1.0)]
[Browsable(false)]
public double TukeyOverlap { get ; set ; }
[DefaultValue(1.0)]
[Browsable(false)]
public double TukeyP { get ; set ; }
[Browsable(false)]
public string [ ] Tags { get ; set ; }
2013-04-01 23:03:22 -04:00
}
[AudioEncoderClass("cuetools", "flac", true, 4, typeof(FlakeWriterSettings))]
2010-05-18 17:18:37 +00:00
//[AudioEncoderClass("libFlake nonsub", "flac", true, "9 10 11", "9", 3, typeof(FlakeWriterSettings))]
2009-08-17 03:39:53 +00:00
public class FlakeWriter : IAudioDest
{
Stream _IO = null ;
string _path ;
long _position ;
// number of audio channels
// set by user prior to calling flake_encode_init
// valid values are 1 to 8
int channels , ch_code ;
// audio sample rate in Hz
// set by user prior to calling flake_encode_init
2010-02-06 23:17:07 +00:00
int sr_code0 , sr_code1 ;
2009-08-17 03:39:53 +00:00
// sample size in bits
// set by user prior to calling flake_encode_init
// only 16-bit is currently supported
int bps_code ;
// total stream samples
// set by user prior to calling flake_encode_init
// if 0, stream length is unknown
2010-02-06 23:17:07 +00:00
int sample_count = - 1 ;
2009-08-17 03:39:53 +00:00
FlakeEncodeParams eparams ;
// maximum frame size in bytes
// set by flake_encode_init
// this can be used to allocate memory for output
int max_frame_size ;
byte [ ] frame_buffer = null ;
int frame_count = 0 ;
2009-08-20 04:09:53 +00:00
long first_frame_offset = 0 ;
2009-10-16 23:35:56 +00:00
#if INTEROP
2009-08-17 03:39:53 +00:00
TimeSpan _userProcessorTime ;
2009-10-16 23:35:56 +00:00
#endif
2009-08-17 03:39:53 +00:00
// header bytes
// allocated by flake_encode_init and freed by flake_encode_close
byte [ ] header ;
int [ ] samplesBuffer ;
int [ ] verifyBuffer ;
int [ ] residualBuffer ;
2009-10-16 23:35:56 +00:00
float [ ] windowBuffer ;
2009-12-24 16:11:22 +00:00
double [ ] windowScale ;
2014-08-26 23:48:16 -04:00
LpcWindowSection [ , , ] windowSections ;
WindowFunction [ ] windowType ;
2009-08-17 03:39:53 +00:00
int samplesInBuffer = 0 ;
2013-04-04 22:07:15 -04:00
int m_blockSize = 0 ;
2009-08-17 03:39:53 +00:00
int _totalSize = 0 ;
int _windowsize = 0 , _windowcount = 0 ;
Crc8 crc8 ;
MD5 md5 ;
2009-08-28 13:00:27 +00:00
FlacFrame frame ;
2009-08-17 03:39:53 +00:00
FlakeReader verify ;
2009-08-20 04:09:53 +00:00
SeekPoint [ ] seek_table ;
int seek_table_offset = - 1 ;
2009-08-17 03:39:53 +00:00
bool inited = false ;
2013-04-07 20:41:58 -04:00
public FlakeWriter ( string path , Stream IO , FlakeWriterSettings settings )
2009-08-17 03:39:53 +00:00
{
2013-06-18 20:45:53 -04:00
m_settings = settings . Clone ( ) as FlakeWriterSettings ;
m_settings . Validate ( ) ;
2010-02-06 23:17:07 +00:00
2013-04-07 20:41:58 -04:00
//if (Settings.PCM.BitsPerSample != 16)
2010-12-07 22:52:34 +00:00
// throw new Exception("Bits per sample must be 16.");
2013-04-07 20:41:58 -04:00
//if (Settings.PCM.ChannelCount != 2)
2012-07-12 00:11:39 +00:00
// throw new Exception("ChannelCount must be 2.");
2009-08-17 03:39:53 +00:00
2013-04-07 20:41:58 -04:00
channels = Settings . PCM . ChannelCount ;
2009-08-17 03:39:53 +00:00
// flake_validate_params
_path = path ;
_IO = IO ;
samplesBuffer = new int [ Flake . MAX_BLOCKSIZE * ( channels = = 2 ? 4 : channels ) ] ;
2009-08-21 03:26:12 +00:00
residualBuffer = new int [ Flake . MAX_BLOCKSIZE * ( channels = = 2 ? 10 : channels + 1 ) ] ;
2009-10-16 23:35:56 +00:00
windowBuffer = new float [ Flake . MAX_BLOCKSIZE * 2 * lpc . MAX_LPC_WINDOWS ] ;
2014-08-26 23:48:16 -04:00
windowScale = new double [ lpc . MAX_LPC_WINDOWS ] ;
windowType = new WindowFunction [ lpc . MAX_LPC_WINDOWS ] ;
windowSections = new LpcWindowSection [ 12 , lpc . MAX_LPC_WINDOWS , lpc . MAX_LPC_SECTIONS ] ;
2009-08-17 03:39:53 +00:00
2013-06-18 20:45:53 -04:00
eparams . flake_set_defaults ( m_settings ) ;
2009-08-17 03:39:53 +00:00
crc8 = new Crc8 ( ) ;
2009-08-28 13:00:27 +00:00
frame = new FlacFrame ( channels * 2 ) ;
2009-08-17 03:39:53 +00:00
}
2013-04-07 20:41:58 -04:00
public FlakeWriter ( string path , FlakeWriterSettings settings )
: this ( path , null , settings )
2010-02-06 23:17:07 +00:00
{
}
2009-08-17 03:39:53 +00:00
public int TotalSize
{
get
{
return _totalSize ;
}
}
2013-04-07 20:41:58 -04:00
FlakeWriterSettings m_settings ;
2010-05-18 17:18:37 +00:00
2013-04-01 23:03:22 -04:00
public AudioEncoderSettings Settings
2009-08-17 03:39:53 +00:00
{
get
{
2013-04-04 22:07:15 -04:00
return m_settings ;
2009-08-17 03:39:53 +00:00
}
}
2009-10-16 23:35:56 +00:00
#if INTEROP
[DllImport("kernel32.dll")]
static extern bool GetThreadTimes ( IntPtr hThread , out long lpCreationTime , out long lpExitTime , out long lpKernelTime , out long lpUserTime ) ;
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread ( ) ;
#endif
2009-08-17 03:39:53 +00:00
void DoClose ( )
{
2009-08-20 04:09:53 +00:00
if ( inited )
2009-08-17 03:39:53 +00:00
{
2009-08-21 03:26:12 +00:00
while ( samplesInBuffer > 0 )
2009-08-20 04:09:53 +00:00
{
2013-04-04 22:07:15 -04:00
m_blockSize = samplesInBuffer ;
2009-08-20 04:09:53 +00:00
output_frame ( ) ;
}
if ( _IO . CanSeek )
{
2010-02-06 23:17:07 +00:00
if ( sample_count < = 0 & & _position ! = 0 )
{
BitWriter bitwriter = new BitWriter ( header , 0 , 4 ) ;
bitwriter . writebits ( 32 , ( int ) _position ) ;
bitwriter . flush ( ) ;
_IO . Position = 22 ;
_IO . Write ( header , 0 , 4 ) ;
}
2009-08-20 04:09:53 +00:00
if ( md5 ! = null )
{
md5 . TransformFinalBlock ( frame_buffer , 0 , 0 ) ;
_IO . Position = 26 ;
_IO . Write ( md5 . Hash , 0 , md5 . Hash . Length ) ;
}
if ( seek_table ! = null )
{
_IO . Position = seek_table_offset ;
int len = write_seekpoints ( header , 0 , 0 ) ;
_IO . Write ( header , 4 , len - 4 ) ;
}
}
_IO . Close ( ) ;
inited = false ;
2012-07-12 00:11:39 +00:00
}
2009-08-17 03:39:53 +00:00
2009-10-16 23:35:56 +00:00
#if INTEROP
long fake , KernelStart , UserStart ;
GetThreadTimes ( GetCurrentThread ( ) , out fake , out fake , out KernelStart , out UserStart ) ;
_userProcessorTime = new TimeSpan ( UserStart ) ;
#endif
2009-08-17 03:39:53 +00:00
}
public void Close ( )
{
DoClose ( ) ;
2010-02-06 23:17:07 +00:00
if ( sample_count > 0 & & _position ! = sample_count )
2010-05-18 17:18:37 +00:00
throw new Exception ( Properties . Resources . ExceptionSampleCount ) ;
2009-08-17 03:39:53 +00:00
}
public void Delete ( )
{
2009-08-21 03:26:12 +00:00
if ( inited )
{
_IO . Close ( ) ;
inited = false ;
}
2009-08-20 04:09:53 +00:00
if ( _path ! = "" )
File . Delete ( _path ) ;
2009-08-17 03:39:53 +00:00
}
public long Position
{
get
{
return _position ;
}
}
public long FinalSampleCount
{
set { sample_count = ( int ) value ; }
}
public OrderMethod OrderMethod
{
get { return eparams . order_method ; }
set { eparams . order_method = value ; }
}
2012-07-12 00:11:39 +00:00
public int DevelopmentMode
{
get { return eparams . development_mode ; }
set { eparams . development_mode = value ; }
}
2009-08-20 04:09:53 +00:00
public bool DoSeekTable
{
get { return eparams . do_seektable ; }
set { eparams . do_seektable = value ; }
}
2009-08-21 03:26:12 +00:00
public int VBRMode
{
get { return eparams . variable_block_size ; }
set { eparams . variable_block_size = value ; }
}
2009-08-17 03:39:53 +00:00
public TimeSpan UserProcessorTime
{
2009-10-16 23:35:56 +00:00
get
{
#if INTEROP
return _userProcessorTime ;
#else
2010-05-18 17:18:37 +00:00
return new TimeSpan ( 0 ) ;
2009-10-16 23:35:56 +00:00
#endif
}
2009-08-17 03:39:53 +00:00
}
2010-02-06 23:17:07 +00:00
unsafe int get_wasted_bits ( int * signal , int samples )
2009-08-17 03:39:53 +00:00
{
int i , shift ;
int x = 0 ;
for ( i = 0 ; i < samples & & 0 = = ( x & 1 ) ; i + + )
x | = signal [ i ] ;
if ( x = = 0 )
{
shift = 0 ;
}
else
{
for ( shift = 0 ; 0 = = ( x & 1 ) ; shift + + )
x > > = 1 ;
}
if ( shift > 0 )
{
for ( i = 0 ; i < samples ; i + + )
signal [ i ] > > = shift ;
}
2010-02-06 23:17:07 +00:00
return shift ;
2009-08-17 03:39:53 +00:00
}
2009-08-28 13:00:27 +00:00
/// <summary>
2009-08-20 04:09:53 +00:00
/// Copy channel-interleaved input samples into separate subframes
2009-08-28 13:00:27 +00:00
/// </summary>
/// <param name="samples"></param>
/// <param name="pos"></param>
/// <param name="block"></param>
unsafe void copy_samples ( int [ , ] samples , int pos , int block )
2009-08-17 03:39:53 +00:00
{
2009-08-20 04:09:53 +00:00
fixed ( int * fsamples = samplesBuffer , src = & samples [ pos , 0 ] )
{
if ( channels = = 2 )
2010-02-06 23:17:07 +00:00
{
2014-12-08 22:18:34 -05:00
if ( m_settings . StereoMethod = = StereoMethod . Independent )
2010-02-06 23:17:07 +00:00
AudioSamples . Deinterlace ( fsamples + samplesInBuffer , fsamples + Flake . MAX_BLOCKSIZE + samplesInBuffer , src , block ) ;
else
{
int * left = fsamples + samplesInBuffer ;
int * right = left + Flake . MAX_BLOCKSIZE ;
int * leftM = right + Flake . MAX_BLOCKSIZE ;
int * rightM = leftM + Flake . MAX_BLOCKSIZE ;
for ( int i = 0 ; i < block ; i + + )
{
int l = src [ 2 * i ] ;
int r = src [ 2 * i + 1 ] ;
left [ i ] = l ;
right [ i ] = r ;
leftM [ i ] = ( l + r ) > > 1 ;
rightM [ i ] = l - r ;
}
}
}
2009-08-20 04:09:53 +00:00
else
for ( int ch = 0 ; ch < channels ; ch + + )
{
int * psamples = fsamples + ch * Flake . MAX_BLOCKSIZE + samplesInBuffer ;
for ( int i = 0 ; i < block ; i + + )
psamples [ i ] = src [ i * channels + ch ] ;
}
}
2009-08-17 03:39:53 +00:00
samplesInBuffer + = block ;
}
2010-12-07 22:52:34 +00:00
//unsafe static void channel_decorrelation(int* leftS, int* rightS, int *leftM, int *rightM, int blocksize)
//{
// for (int i = 0; i < blocksize; i++)
// {
// leftM[i] = (leftS[i] + rightS[i]) >> 1;
// rightM[i] = leftS[i] - rightS[i];
// }
//}
2009-08-17 03:39:53 +00:00
unsafe void encode_residual_verbatim ( int * res , int * smp , uint n )
{
2009-08-30 21:58:54 +00:00
AudioSamples . MemCpy ( res , smp , ( int ) n ) ;
2009-08-17 03:39:53 +00:00
}
2014-12-08 22:18:34 -05:00
unsafe static ulong encode_residual_fixed_partition ( int * res , int * smp , int * end , int order , int * last_errors )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
ulong sum = 0 UL ;
switch ( order )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
case 0 :
{
while ( smp < end )
{
int error = * ( res + + ) = * ( smp + + ) ;
sum + = ( uint ) ( ( error < < 1 ) ^ ( error > > 31 ) ) ;
}
break ;
}
case 1 :
{
int last_error_0 = last_errors [ 0 ] ;
while ( smp < end )
{
int error , save ;
error = * ( smp + + ) ; save = error ;
error - = last_error_0 ; * ( res + + ) = error ; last_error_0 = save ;
sum + = ( uint ) ( ( error < < 1 ) ^ ( error > > 31 ) ) ;
}
last_errors [ 0 ] = last_error_0 ;
break ;
}
case 2 :
{
int last_error_0 = last_errors [ 0 ] , last_error_1 = last_errors [ 1 ] ;
while ( smp < end )
{
int error , save ;
error = * ( smp + + ) ; save = error ;
error - = last_error_0 ; last_error_0 = save ; save = error ;
error - = last_error_1 ; * ( res + + ) = error ; last_error_1 = save ;
sum + = ( uint ) ( ( error < < 1 ) ^ ( error > > 31 ) ) ;
}
last_errors [ 0 ] = last_error_0 ; last_errors [ 1 ] = last_error_1 ; ;
break ;
}
case 3 :
{
int last_error_0 = last_errors [ 0 ] , last_error_1 = last_errors [ 1 ] , last_error_2 = last_errors [ 2 ] ;
while ( smp < end )
{
int error , save ;
error = * ( smp + + ) ; save = error ;
error - = last_error_0 ; last_error_0 = save ; save = error ;
error - = last_error_1 ; last_error_1 = save ; save = error ;
error - = last_error_2 ; * ( res + + ) = error ; last_error_2 = save ;
sum + = ( uint ) ( ( error < < 1 ) ^ ( error > > 31 ) ) ;
}
last_errors [ 0 ] = last_error_0 ; last_errors [ 1 ] = last_error_1 ; last_errors [ 2 ] = last_error_2 ;
break ;
}
case 4 :
{
int last_error_0 = last_errors [ 0 ] , last_error_1 = last_errors [ 1 ] , last_error_2 = last_errors [ 2 ] , last_error_3 = last_errors [ 3 ] ;
while ( smp < end )
{
int error , save ;
error = * ( smp + + ) ; save = error ;
error - = last_error_0 ; last_error_0 = save ; save = error ;
error - = last_error_1 ; last_error_1 = save ; save = error ;
error - = last_error_2 ; last_error_2 = save ; save = error ;
error - = last_error_3 ; * ( res + + ) = error ; last_error_3 = save ;
sum + = ( uint ) ( ( error < < 1 ) ^ ( error > > 31 ) ) ;
}
last_errors [ 0 ] = last_error_0 ; last_errors [ 1 ] = last_error_1 ; last_errors [ 2 ] = last_error_2 ; last_errors [ 3 ] = last_error_3 ;
break ;
}
default :
throw new ArgumentOutOfRangeException ( ) ;
2014-08-26 23:48:16 -04:00
}
2014-12-08 22:18:34 -05:00
return sum ;
}
2014-08-26 23:48:16 -04:00
2014-12-08 22:18:34 -05:00
unsafe static void encode_residual_fixed ( int * res , int * smp , int n , int order , ulong * sums , int pmax )
{
int * last_errors = stackalloc int [ 4 ] ;
int * end = smp + n ;
int * seg_end = smp + ( n > > pmax ) ;
2014-08-26 23:48:16 -04:00
2014-12-08 22:18:34 -05:00
if ( order > 4 )
throw new ArgumentOutOfRangeException ( ) ;
2014-08-26 23:48:16 -04:00
2014-12-08 22:18:34 -05:00
for ( int i = 0 ; i < order ; i + + )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
int * next_errors = stackalloc int [ 4 ] ;
next_errors [ 0 ] = * ( res + + ) = * ( smp + + ) ;
for ( int j = 0 ; j < i ; j + + )
next_errors [ j + 1 ] = next_errors [ j ] - last_errors [ j ] ;
for ( int j = 0 ; j < = i ; j + + )
last_errors [ j ] = next_errors [ j ] ;
2014-08-26 23:48:16 -04:00
}
2014-12-08 22:18:34 -05:00
while ( smp < end )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
* ( sums + + ) = encode_residual_fixed_partition ( res , smp , seg_end , order , last_errors ) ;
res + = seg_end - smp ;
smp = seg_end ;
seg_end + = n > > pmax ;
2014-08-26 23:48:16 -04:00
}
}
2014-12-08 22:18:34 -05:00
2014-08-26 23:48:16 -04:00
#if XXX
unsafe static int encode_residual_fixed_estimate_best_order ( int * res , int * smp , int n , int order )
{
int next_error_0 , next_error_1 , next_error_2 , next_error_3 , next_error_4 ;
int last_error_0 , last_error_1 , last_error_2 , last_error_3 ;
int * end = smp + n ;
ulong total_error_0 = 0 , total_error_1 = 0 , total_error_2 = 0 , total_error_3 = 0 , total_error_4 = 0 ;
if ( order = = 0 )
{
AudioSamples . MemCpy ( res , smp , n ) ;
return 0 ;
}
next_error_0 = * ( res + + ) = * ( smp + + ) ;
last_error_0 = next_error_0 ;
if ( order = = 1 )
{
while ( smp < end )
{
next_error_0 = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
last_error_0 = next_error_0 ;
total_error_0 + = ( ulong ) ( ( next_error_0 < < 1 ) ^ ( next_error_0 > > 31 ) ) ;
total_error_1 + = ( ulong ) ( ( next_error_1 < < 1 ) ^ ( next_error_1 > > 31 ) ) ;
* ( res + + ) = ( int ) next_error_1 ;
}
if ( ( total_error_0 < total_error_1 ) )
return 0 ;
return 1 ;
}
next_error_0 = * ( res + + ) = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
if ( order = = 2 )
{
while ( smp < end )
{
next_error_0 = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
next_error_2 = next_error_1 - last_error_1 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
total_error_0 + = ( ulong ) ( ( next_error_0 < < 1 ) ^ ( next_error_0 > > 31 ) ) ;
total_error_1 + = ( ulong ) ( ( next_error_1 < < 1 ) ^ ( next_error_1 > > 31 ) ) ;
total_error_2 + = ( ulong ) ( ( next_error_2 < < 1 ) ^ ( next_error_2 > > 31 ) ) ;
* ( res + + ) = ( int ) next_error_2 ;
}
if ( ( total_error_0 < total_error_1 ) & ( total_error_0 < total_error_2 ) )
return 0 ;
else if ( ( total_error_1 < total_error_2 ) )
return 1 ;
return 2 ;
}
next_error_0 = * ( res + + ) = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
next_error_2 = next_error_1 - last_error_1 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
last_error_2 = next_error_2 ;
if ( order = = 3 )
{
while ( smp < end )
{
next_error_0 = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
next_error_2 = next_error_1 - last_error_1 ;
next_error_3 = next_error_2 - last_error_2 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
last_error_2 = next_error_2 ;
total_error_0 + = ( ulong ) ( ( next_error_0 < < 1 ) ^ ( next_error_0 > > 31 ) ) ;
total_error_1 + = ( ulong ) ( ( next_error_1 < < 1 ) ^ ( next_error_1 > > 31 ) ) ;
total_error_2 + = ( ulong ) ( ( next_error_2 < < 1 ) ^ ( next_error_2 > > 31 ) ) ;
total_error_3 + = ( ulong ) ( ( next_error_3 < < 1 ) ^ ( next_error_3 > > 31 ) ) ;
* ( res + + ) = ( int ) next_error_3 ;
}
if ( ( total_error_0 < total_error_1 ) & ( total_error_0 < total_error_2 ) & ( total_error_0 < total_error_3 ) )
return 0 ;
else if ( ( total_error_1 < total_error_2 ) & ( total_error_1 < total_error_3 ) )
return 1 ;
else if ( ( total_error_2 < total_error_3 ) )
return 2 ;
return 3 ;
}
next_error_0 = * ( res + + ) = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
next_error_2 = next_error_1 - last_error_1 ;
next_error_3 = next_error_2 - last_error_2 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
last_error_2 = next_error_2 ;
last_error_3 = next_error_3 ;
2009-08-17 03:39:53 +00:00
2014-08-26 23:48:16 -04:00
if ( order = = 4 )
{
while ( smp < end )
{
next_error_0 = * ( smp + + ) ;
next_error_1 = next_error_0 - last_error_0 ;
next_error_2 = next_error_1 - last_error_1 ;
next_error_3 = next_error_2 - last_error_2 ;
next_error_4 = next_error_3 - last_error_3 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
last_error_2 = next_error_2 ;
last_error_3 = next_error_3 ;
total_error_0 + = ( ulong ) ( ( next_error_0 < < 1 ) ^ ( next_error_0 > > 31 ) ) ;
total_error_1 + = ( ulong ) ( ( next_error_1 < < 1 ) ^ ( next_error_1 > > 31 ) ) ;
total_error_2 + = ( ulong ) ( ( next_error_2 < < 1 ) ^ ( next_error_2 > > 31 ) ) ;
total_error_3 + = ( ulong ) ( ( next_error_3 < < 1 ) ^ ( next_error_3 > > 31 ) ) ;
total_error_4 + = ( ulong ) ( ( next_error_4 < < 1 ) ^ ( next_error_4 > > 31 ) ) ;
* ( res + + ) = ( int ) next_error_4 ;
}
if ( ( total_error_0 < total_error_1 ) & ( total_error_0 < total_error_2 ) & ( total_error_0 < total_error_3 ) & ( total_error_0 < total_error_4 ) )
return 0 ;
else if ( ( total_error_1 < total_error_2 ) & ( total_error_1 < total_error_3 ) & ( total_error_1 < total_error_4 ) )
return 1 ;
else if ( ( total_error_2 < total_error_3 ) & ( total_error_2 < total_error_4 ) )
return 2 ;
else if ( total_error_3 < total_error_4 )
return 3 ;
return 4 ;
}
throw new ArgumentOutOfRangeException ( ) ;
}
#endif
2010-12-07 22:52:34 +00:00
static unsafe uint calc_optimal_rice_params ( int porder , int * parm , ulong * sums , uint n , uint pred_order , ref int method )
2009-08-17 03:39:53 +00:00
{
uint part = ( 1 U < < porder ) ;
2009-10-16 23:35:56 +00:00
uint cnt = ( n > > porder ) - pred_order ;
2010-12-07 22:52:34 +00:00
int maxK = method > 0 ? 30 : Flake . MAX_RICE_PARAM ;
int k = cnt > 0 ? Math . Min ( maxK , BitReader . log2i ( sums [ 0 ] / cnt ) ) : 0 ;
int realMaxK0 = k ;
ulong all_bits = cnt * ( ( uint ) k + 1 U ) + ( sums [ 0 ] > > k ) ;
2009-10-16 23:35:56 +00:00
parm [ 0 ] = k ;
cnt = ( n > > porder ) ;
2014-12-08 22:18:34 -05:00
int logcnt = BitReader . log2i ( cnt ) ;
if ( cnt = = 1 < < logcnt )
{
for ( uint i = 1 ; i < part ; i + + )
{
ulong s = sums [ i ] ;
ulong u = s > > logcnt ;
k = u > > maxK ! = 0 ? maxK : BitReader . log2i ( ( uint ) u ) ;
realMaxK0 = Math . Max ( realMaxK0 , k ) ;
all_bits + = ( ( uint ) k < < logcnt ) + ( s > > k ) ;
parm [ i ] = k ;
}
}
else
{
for ( uint i = 1 ; i < part ; i + + )
{
ulong s = sums [ i ] ;
ulong u = s / cnt ;
k = u > > maxK ! = 0 ? maxK : BitReader . log2i ( ( uint ) u ) ;
realMaxK0 = Math . Max ( realMaxK0 , k ) ;
all_bits + = cnt * ( uint ) k + ( s > > k ) ;
parm [ i ] = k ;
}
}
all_bits + = cnt * ( part - 1 U ) ;
method = realMaxK0 > Flake . MAX_RICE_PARAM ? 1 : 0 ;
2010-12-07 22:52:34 +00:00
return ( uint ) all_bits + ( ( 4 U + ( uint ) method ) * part ) ;
2009-10-16 23:35:56 +00:00
}
2010-12-07 22:52:34 +00:00
static unsafe void calc_lower_sums ( int pmin , int pmax , ulong * sums )
2009-10-16 23:35:56 +00:00
{
for ( int i = pmax - 1 ; i > = pmin ; i - - )
{
for ( int j = 0 ; j < ( 1 < < i ) ; j + + )
{
sums [ i * Flake . MAX_PARTITIONS + j ] =
sums [ ( i + 1 ) * Flake . MAX_PARTITIONS + 2 * j ] +
sums [ ( i + 1 ) * Flake . MAX_PARTITIONS + 2 * j + 1 ] ;
}
2009-08-17 03:39:53 +00:00
}
}
2012-07-12 00:11:39 +00:00
static unsafe uint calc_rice_params_sums ( RiceContext rc , int pmin , int pmax , ulong * sums , uint n , uint pred_order , int bps )
{
int * parm = stackalloc int [ ( pmax + 1 ) * Flake . MAX_PARTITIONS ] ;
//uint* bits = stackalloc uint[Flake.MAX_PARTITION_ORDER];
//assert(pmin >= 0 && pmin <= Flake.MAX_PARTITION_ORDER);
//assert(pmax >= 0 && pmax <= Flake.MAX_PARTITION_ORDER);
//assert(pmin <= pmax);
// sums for lower levels
calc_lower_sums ( pmin , pmax , sums ) ;
uint opt_bits = AudioSamples . UINT32_MAX ;
int opt_porder = pmin ;
int opt_method = 0 ;
for ( int i = pmin ; i < = pmax ; i + + )
{
int method = bps > 16 ? 1 : 0 ;
uint bits = calc_optimal_rice_params ( i , parm + i * Flake . MAX_PARTITIONS , sums + i * Flake . MAX_PARTITIONS , n , pred_order , ref method ) ;
if ( bits < = opt_bits )
{
opt_bits = bits ;
opt_porder = i ;
opt_method = method ;
}
}
rc . porder = opt_porder ;
rc . coding_method = opt_method ;
fixed ( int * rparms = rc . rparams )
AudioSamples . MemCpy ( rparms , parm + opt_porder * Flake . MAX_PARTITIONS , ( 1 < < opt_porder ) ) ;
return opt_bits ;
}
2009-08-17 03:39:53 +00:00
static int get_max_p_order ( int max_porder , int n , int order )
{
2009-08-30 21:58:54 +00:00
int porder = Math . Min ( max_porder , BitReader . log2i ( n ^ ( n - 1 ) ) ) ;
2009-08-17 03:39:53 +00:00
if ( order > 0 )
2009-08-30 21:58:54 +00:00
porder = Math . Min ( porder , BitReader . log2i ( n / order ) ) ;
2009-08-17 03:39:53 +00:00
return porder ;
}
2012-07-12 00:11:39 +00:00
// private static int[,] best_x = new int[14,8193];
private static int [ ] [ ] good_x = new int [ ] [ ] {
new int [ ] { } , // 0
new int [ ] { // 1
0x03 , 0x01 , 0x00 , 0x02
} ,
new int [ ] { // 2
0x01 , 0x07 , 0x06 , 0x02 , 0x03 , 0x04 , 0x00 , 0x05
} ,
new int [ ] { // 3
0x0b , 0x0f , 0x0e , 0x0d , 0x03 , 0x01 , 0x05 , 0x02
} ,
new int [ ] { //4
0x17 , 0x09 , 0x03 , 0x0a , 0x06 , 0x1d , 0x1f , 0x05 , 0x1c , 0x0d , 0x07 , 0x0c ,
} ,
new int [ ] { // 5
0x2b , 0x3d , 0x37 , 0x07 , 0x11 , 0x15 , 0x36 , 0x3f ,
} ,
new int [ ] { // 6
0x6b , 0x15 , 0x7e , 0x31 , 0x07 , 0x1a , 0x29 , 0x26 , 0x5d , 0x23 , 0x6f , 0x19 , 0x56 , 0x75
} ,
new int [ ] { // 7
0xdb , 0xef , 0xb5 , 0x47 , 0xee , 0x63 , 0x0b , 0xfd , 0x31 , 0xbe , 0xed , 0x33 , 0xff , 0xfb , 0xd6 , 0xbb
} ,
new int [ ] { // 8
0x1bb , 0x1c7 , 0x069 , 0x087 , 0x1fd , 0x16e , 0x095 , 0x1de , 0x066 , 0x071 , 0x055 , 0x09a ,
} ,
new int [ ] { // 9
0x36b , 0x3bd , 0x097 , 0x0c3 , 0x0e3 , 0x0b1 , 0x107 , 0x2de , 0x3ef , 0x2fb , 0x3d5 , 0x139
} ,
new int [ ] { // 10
//0x0e3,0x199,0x383,0x307, 0x1e3,0x01f,0x269,0x0f1, 0x266,0x03f,0x2cd,0x1c3, 0x19a,0x387,0x339,0x259,
0x6eb , 0x187 , 0x77d , 0x271 , 0x195 , 0x259 , 0x5ae , 0x169 ,
} ,
new int [ ] { // 11
0xddb , 0xf77 , 0xb6d , 0x587 , 0x2c3 , 0x03b , 0xef5 , 0x1e3 , 0xdbe ,
} ,
new int [ ] { // 12
0x1aeb , 0x0587 , 0x0a71 , 0x1dbd , 0x0559 , 0x0aa5 , 0x0a2e , 0x0d43 , 0x05aa , 0x00f3 , 0x0696 , 0x03c6 ,
} ,
new int [ ] { // 13
0x35d7 , 0x2f6f , 0x0aa3 , 0x1569 , 0x150f , 0x3d79 , 0x0dc3 , 0x309f /*?*/ ,
} ,
new int [ ] { // 14
0x75d7 , 0x5f7b , 0x6a8f , 0x29a3 ,
} ,
new int [ ] { // 15
0xddd7 , 0xaaaf , 0x55c3 , 0xf77b ,
} ,
new int [ ] { // 16
0x1baeb , 0x1efaf , 0x1d5bf , 0x1cff3 ,
} ,
new int [ ] { // 17
0x36dd7 , 0x3bb7b , 0x3df6f , 0x2d547 ,
} ,
new int [ ] { // 18
0x75dd7 , 0x6f77b , 0x7aaaf , 0x5ddd3 ,
} ,
new int [ ] { // 19
0xdddd7 , 0xf777b , 0xd5547 , 0xb6ddb ,
} ,
new int [ ] { // 20
0x1baeeb , 0x1efbaf , 0x1aaabf , 0x17bbeb ,
} ,
new int [ ] { // 21
0x376dd7 , 0x3ddf7b , 0x2d550f , 0x0aaaa3 ,
} ,
new int [ ] { // 22
0x6eddd7 , 0x77777b , 0x5dcd4f , 0x5d76f9 ,
} ,
new int [ ] { // 23
0xdeddd7 , 0xb5b6eb , 0x55552b , 0x2aaac3 ,
} ,
new int [ ] { // 24
0x1dddbb7 , 0x1b76eeb , 0x17bbf5f , 0x1eeaa9f ,
} ,
new int [ ] { // 25
} ,
new int [ ] { // 26
} ,
new int [ ] { // 27
} ,
new int [ ] { // 28
} ,
new int [ ] { // 29
} ,
new int [ ] { // 30
} ,
} ;
unsafe void postprocess_coefs ( FlacFrame frame , FlacSubframe sf , int ch )
{
if ( eparams . development_mode < 0 )
return ;
if ( sf . type ! = SubframeType . LPC | | sf . order > 30 )
return ;
int orig_window = sf . window ;
int orig_order = sf . order ;
int orig_shift = sf . shift ;
int orig_cbits = sf . cbits ;
uint orig_size = sf . size ;
var orig_coefs = stackalloc int [ orig_order ] ;
for ( int i = 0 ; i < orig_order ; i + + ) orig_coefs [ i ] = sf . coefs [ i ] ;
int orig_xx = - 1 ;
int orig_seq = 0 ;
int maxxx = Math . Min ( good_x [ orig_order ] . Length , eparams . development_mode ) ;
2013-06-18 20:45:53 -04:00
var pmax = get_max_p_order ( m_settings . MaxPartitionOrder , frame . blocksize , orig_order ) ;
var pmin = Math . Min ( m_settings . MinPartitionOrder , pmax ) ;
2012-07-12 00:11:39 +00:00
ulong * sums = stackalloc ulong [ ( pmax + 1 ) * Flake . MAX_PARTITIONS ] ;
while ( true )
{
var best_coefs = stackalloc int [ orig_order ] ;
int best_shift = orig_shift ;
int best_cbits = orig_cbits ;
uint best_size = orig_size ;
int best_xx = - 1 ;
for ( int xx = - 1 ; xx < maxxx ; xx + + )
{
int x = xx ;
if ( xx < 0 )
{
if ( orig_xx < 0 | | maxxx < 1 /*3*/ ) // || (orig_xx >> orig_order) != 0)
continue ;
x = orig_xx ;
orig_seq + + ;
}
else
{
orig_seq = 0 ;
if ( orig_order < good_x . Length & & good_x [ orig_order ] ! = null )
x = good_x [ orig_order ] [ xx ] ;
}
frame . current . type = SubframeType . LPC ;
frame . current . order = orig_order ;
frame . current . window = orig_window ;
frame . current . shift = orig_shift ;
frame . current . cbits = orig_cbits ;
if ( ( ( x > > orig_order ) & 1 ) ! = 0 )
{
frame . current . shift - - ;
frame . current . cbits - - ;
if ( frame . current . shift < 0 | | frame . current . cbits < 2 )
continue ;
}
ulong csum = 0 ;
int qmax = ( 1 < < ( frame . current . cbits - 1 ) ) - 1 ;
for ( int i = 0 ; i < frame . current . order ; i + + )
{
int shift = ( x > > orig_order ) & 1 ;
int increment = ( x = = 1 < < orig_order ) ? 0 : ( ( ( x > > i ) & 1 ) < < 1 ) - 1 ;
frame . current . coefs [ i ] = ( orig_coefs [ i ] + ( increment < < orig_seq ) ) > > shift ;
if ( frame . current . coefs [ i ] < - ( qmax + 1 ) ) frame . current . coefs [ i ] = - ( qmax + 1 ) ;
if ( frame . current . coefs [ i ] > qmax ) frame . current . coefs [ i ] = qmax ;
csum + = ( ulong ) Math . Abs ( frame . current . coefs [ i ] ) ;
}
fixed ( int * coefs = frame . current . coefs )
{
if ( ( csum < < frame . subframes [ ch ] . obits ) > = 1 UL < < 32 )
2014-09-19 22:01:20 -04:00
lpc . encode_residual_long ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order , coefs , frame . current . shift , sums + pmax * Flake . MAX_PARTITIONS , pmax ) ;
2012-07-12 00:11:39 +00:00
else
2014-09-19 22:01:20 -04:00
lpc . encode_residual ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order , coefs , frame . current . shift , sums + pmax * Flake . MAX_PARTITIONS , pmax ) ;
2012-07-12 00:11:39 +00:00
}
2014-09-19 22:01:20 -04:00
var cur_size = calc_rice_params_sums ( frame . current . rc , pmin , pmax , sums , ( uint ) frame . blocksize , ( uint ) frame . current . order , Settings . PCM . BitsPerSample ) ;
2012-07-12 00:11:39 +00:00
frame . current . size = ( uint ) ( frame . current . order * frame . subframes [ ch ] . obits + 4 + 5 + frame . current . order * frame . current . cbits + 6 + ( int ) cur_size ) ;
if ( frame . current . size < best_size )
{
//var dif = best_size - frame.current.size;
for ( int i = 0 ; i < frame . current . order ; i + + ) best_coefs [ i ] = frame . current . coefs [ i ] ;
best_shift = frame . current . shift ;
best_cbits = frame . current . cbits ;
best_size = frame . current . size ;
best_xx = x ;
frame . ChooseBestSubframe ( ch ) ;
//if (dif > orig_order * 5)
// break;
}
if ( xx < 0 & & best_size < orig_size )
break ;
}
if ( best_size < orig_size )
{
//if (best_xx >= 0) best_x[order, best_xx]++;
//if (orig_size != 0x7FFFFFFF)
// System.Console.Write(string.Format(" {0}[{1:x}]", orig_size - best_size, best_xx));
for ( int i = 0 ; i < orig_order ; i + + ) orig_coefs [ i ] = best_coefs [ i ] ;
orig_shift = best_shift ;
orig_cbits = best_cbits ;
orig_size = best_size ;
orig_xx = best_xx ;
}
else
{
break ;
}
}
//if (orig_size != 0x7FFFFFFF)
// System.Console.WriteLine();
//if (frame_count % 0x400 == 0)
//{
// for (int o = 0; o < best_x.GetLength(0); o++)
// {
// //for (int x = 0; x <= (1 << o); x++)
// // if (best_x[o, x] != 0)
// // System.Console.WriteLine(string.Format("{0:x2}\t{1:x4}\t{2}", o, x, best_x[o, x]));
// var s = new List<KeyValuePair<int, int>>();
// for (int x = 0; x < (1 << o); x++)
// if (best_x[o, x] != 0)
// s.Add(new KeyValuePair<int, int>(x, best_x[o, x]));
// s.Sort((x, y) => y.Value.CompareTo(x.Value));
// foreach (var x in s)
// System.Console.WriteLine(string.Format("{0:x2}\t{1:x4}\t{2}", o, x.Key, x.Value));
// int i = 0;
// foreach (var x in s)
// {
// System.Console.Write(string.Format(o <= 8 ? "0x{0:x2}," : "0x{0:x3},", x.Key));
// if ((++i) % 16 == 0)
// System.Console.WriteLine();
// }
// System.Console.WriteLine();
// }
//}
}
public static void SetCoefs ( int order , int [ ] coefs )
{
good_x [ order ] = new int [ coefs . Length ] ;
for ( int i = 0 ; i < coefs . Length ; i + + )
good_x [ order ] [ i ] = coefs [ i ] ;
}
unsafe void encode_residual_lpc_sub ( FlacFrame frame , float * lpcs , int iWindow , int order , int ch )
{
// select LPC precision based on block size
uint lpc_precision ;
if ( frame . blocksize < = 192 ) lpc_precision = 7 U ;
else if ( frame . blocksize < = 384 ) lpc_precision = 8 U ;
else if ( frame . blocksize < = 576 ) lpc_precision = 9 U ;
else if ( frame . blocksize < = 1152 ) lpc_precision = 10 U ;
else if ( frame . blocksize < = 2304 ) lpc_precision = 11 U ;
else if ( frame . blocksize < = 4608 ) lpc_precision = 12 U ;
else if ( frame . blocksize < = 8192 ) lpc_precision = 13 U ;
else if ( frame . blocksize < = 16384 ) lpc_precision = 14 U ;
else lpc_precision = 15 ;
2014-12-08 22:18:34 -05:00
for ( int i_precision = m_settings . MinPrecisionSearch ; i_precision < = m_settings . MaxPrecisionSearch & & lpc_precision + i_precision < 16 ; i_precision + + )
2012-07-12 00:11:39 +00:00
// check if we already calculated with this order, window and precision
if ( ( frame . subframes [ ch ] . lpc_ctx [ iWindow ] . done_lpcs [ i_precision ] & ( 1 U < < ( order - 1 ) ) ) = = 0 )
{
frame . subframes [ ch ] . lpc_ctx [ iWindow ] . done_lpcs [ i_precision ] | = ( 1 U < < ( order - 1 ) ) ;
uint cbits = lpc_precision + ( uint ) i_precision ;
frame . current . type = SubframeType . LPC ;
frame . current . order = order ;
frame . current . window = iWindow ;
frame . current . cbits = ( int ) cbits ;
2014-09-19 22:01:20 -04:00
int pmax = get_max_p_order ( m_settings . MaxPartitionOrder , frame . blocksize , frame . current . order ) ;
int pmin = Math . Min ( m_settings . MinPartitionOrder , pmax ) ;
ulong * sums = stackalloc ulong [ ( pmax + 1 ) * Flake . MAX_PARTITIONS ] ;
ulong csum = 0 ;
2012-07-12 00:11:39 +00:00
fixed ( int * coefs = frame . current . coefs )
{
lpc . quantize_lpc_coefs ( lpcs + ( frame . current . order - 1 ) * lpc . MAX_LPC_ORDER ,
frame . current . order , cbits , coefs , out frame . current . shift , 15 , 0 ) ;
if ( frame . current . shift < 0 | | frame . current . shift > 15 )
throw new Exception ( "negative shift" ) ;
for ( int i = frame . current . order ; i > 0 ; i - - )
csum + = ( ulong ) Math . Abs ( coefs [ i - 1 ] ) ;
if ( ( csum < < frame . subframes [ ch ] . obits ) > = 1 UL < < 32 )
2014-09-19 22:01:20 -04:00
lpc . encode_residual_long ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order , coefs , frame . current . shift , sums + pmax * Flake . MAX_PARTITIONS , pmax ) ;
2012-07-12 00:11:39 +00:00
else
2014-09-19 22:01:20 -04:00
lpc . encode_residual ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order , coefs , frame . current . shift , sums + pmax * Flake . MAX_PARTITIONS , pmax ) ;
2012-07-12 00:11:39 +00:00
}
2014-09-19 22:01:20 -04:00
uint best_size = calc_rice_params_sums ( frame . current . rc , pmin , pmax , sums , ( uint ) frame . blocksize , ( uint ) frame . current . order , Settings . PCM . BitsPerSample ) ;
2012-07-12 00:11:39 +00:00
frame . current . size = ( uint ) ( frame . current . order * frame . subframes [ ch ] . obits + 4 + 5 + frame . current . order * ( int ) cbits + 6 + ( int ) best_size ) ;
frame . ChooseBestSubframe ( ch ) ;
//if (frame.current.size >= frame.subframes[ch].best.size)
// postprocess_coefs(frame, frame.current, ch);
//else
//{
// frame.ChooseBestSubframe(ch);
// postprocess_coefs(frame, frame.subframes[ch].best, ch);
//}
}
}
2009-08-17 03:39:53 +00:00
2014-12-08 22:18:34 -05:00
unsafe void encode_residual_fixed_sub ( FlacFrame frame , int order , int ch )
{
if ( ( frame . subframes [ ch ] . done_fixed & ( 1 U < < order ) ) ! = 0 )
return ; // already calculated;
2009-08-17 03:39:53 +00:00
2014-12-08 22:18:34 -05:00
frame . current . order = order ;
frame . current . type = SubframeType . Fixed ;
2009-08-17 03:39:53 +00:00
2014-08-26 23:48:16 -04:00
#if XXX
int best_order = order ;
if ( frame . subframes [ ch ] . done_fixed = = 0 )
{
best_order = encode_residual_fixed_estimate_best_order ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order ) ;
if ( best_order ! = order )
{
//frame.subframes[ch].done_fixed |= (1U << order);
order = best_order ;
frame . current . order = order ;
encode_residual_fixed ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order ) ;
}
}
else
#endif
2013-06-18 20:45:53 -04:00
int pmax = get_max_p_order ( m_settings . MaxPartitionOrder , frame . blocksize , frame . current . order ) ;
int pmin = Math . Min ( m_settings . MinPartitionOrder , pmax ) ;
2014-12-08 22:18:34 -05:00
ulong * sums = stackalloc ulong [ ( pmax + 1 ) * Flake . MAX_PARTITIONS ] ;
encode_residual_fixed ( frame . current . residual , frame . subframes [ ch ] . samples , frame . blocksize , frame . current . order , sums + pmax * Flake . MAX_PARTITIONS , pmax ) ;
2009-08-17 03:39:53 +00:00
2014-12-08 22:18:34 -05:00
frame . current . size = ( uint ) ( frame . current . order * frame . subframes [ ch ] . obits ) + 6
+ calc_rice_params_sums ( frame . current . rc , pmin , pmax , sums , ( uint ) frame . blocksize , ( uint ) frame . current . order , Settings . PCM . BitsPerSample ) ;
2009-08-26 17:30:17 +00:00
2014-12-08 22:18:34 -05:00
frame . subframes [ ch ] . done_fixed | = ( 1 U < < order ) ;
frame . ChooseBestSubframe ( ch ) ;
}
2009-08-26 17:30:17 +00:00
2014-08-26 23:48:16 -04:00
unsafe void fixed_compute_best_predictor ( int * data , uint data_len , ulong * errors ) //, float* residual_bits_per_sample)
{
long last_error_0 = data [ - 1 ] ;
long last_error_1 = data [ - 1 ] - data [ - 2 ] ;
long last_error_2 = last_error_1 - ( data [ - 2 ] - data [ - 3 ] ) ;
long last_error_3 = last_error_2 - ( data [ - 2 ] - 2 * data [ - 3 ] + data [ - 4 ] ) ;
ulong total_error_0 = 0 , total_error_1 = 0 , total_error_2 = 0 , total_error_3 = 0 , total_error_4 = 0 ;
#if VARIANT1
long error , save ;
int * finish = data + data_len ;
while ( data < finish )
{
error = * ( data + + ) ; total_error_0 + = ( ulong ) ( ( error < < 1 ) ^ ( error > > 63 ) ) ; save = error ;
error - = last_error_0 ; total_error_1 + = ( ulong ) ( ( error < < 1 ) ^ ( error > > 63 ) ) ; last_error_0 = save ; save = error ;
error - = last_error_1 ; total_error_2 + = ( ulong ) ( ( error < < 1 ) ^ ( error > > 63 ) ) ; last_error_1 = save ; save = error ;
error - = last_error_2 ; total_error_3 + = ( ulong ) ( ( error < < 1 ) ^ ( error > > 63 ) ) ; last_error_2 = save ; save = error ;
error - = last_error_3 ; total_error_4 + = ( ulong ) ( ( error < < 1 ) ^ ( error > > 63 ) ) ; last_error_3 = save ;
}
#else
int * finish = data + data_len ;
while ( data < finish )
{
long next_error_0 = * ( data + + ) ;
long next_error_1 = next_error_0 - last_error_0 ;
long next_error_2 = next_error_1 - last_error_1 ;
long next_error_3 = next_error_2 - last_error_2 ;
long next_error_4 = next_error_3 - last_error_3 ;
last_error_0 = next_error_0 ;
last_error_1 = next_error_1 ;
last_error_2 = next_error_2 ;
last_error_3 = next_error_3 ;
total_error_0 + = ( ulong ) ( ( last_error_0 < < 1 ) ^ ( last_error_0 > > 63 ) ) ;
total_error_1 + = ( ulong ) ( ( last_error_1 < < 1 ) ^ ( last_error_1 > > 63 ) ) ;
total_error_2 + = ( ulong ) ( ( last_error_2 < < 1 ) ^ ( last_error_2 > > 63 ) ) ;
total_error_3 + = ( ulong ) ( ( last_error_3 < < 1 ) ^ ( last_error_3 > > 63 ) ) ;
total_error_4 + = ( ulong ) ( ( next_error_4 < < 1 ) ^ ( next_error_4 > > 63 ) ) ;
}
#endif
errors [ 0 ] = total_error_0 ;
errors [ 1 ] = total_error_1 ;
errors [ 2 ] = total_error_2 ;
errors [ 3 ] = total_error_3 ;
errors [ 4 ] = total_error_4 ;
//residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
//residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
2014-09-15 00:48:31 -04:00
}
2014-08-26 23:48:16 -04:00
unsafe int fixed_compute_best_predictor_order ( ulong * error )
{
int order ;
if ( ( error [ 0 ] < error [ 1 ] ) & ( error [ 0 ] < error [ 2 ] ) & ( error [ 0 ] < error [ 3 ] ) & ( error [ 0 ] < error [ 4 ] ) )
order = 0 ;
else if ( ( error [ 1 ] < error [ 2 ] ) & ( error [ 1 ] < error [ 3 ] ) & ( error [ 1 ] < error [ 4 ] ) )
order = 1 ;
else if ( ( error [ 2 ] < error [ 3 ] ) & ( error [ 2 ] < error [ 4 ] ) )
order = 2 ;
else if ( error [ 3 ] < error [ 4 ] )
order = 3 ;
else
order = 4 ;
return order ;
}
unsafe void encode_residual ( FlacFrame frame , int ch , PredictionType predict , OrderMethod omethod , int pass , int windows_mask )
2009-08-17 03:39:53 +00:00
{
2009-08-28 13:00:27 +00:00
int * smp = frame . subframes [ ch ] . samples ;
int i , n = frame . blocksize ;
2009-08-26 17:30:17 +00:00
// save best.window, because we can overwrite it later with fixed frame
2009-08-21 03:26:12 +00:00
2009-08-17 03:39:53 +00:00
// CONSTANT
for ( i = 1 ; i < n ; i + + )
{
if ( smp [ i ] ! = smp [ 0 ] ) break ;
}
if ( i = = n )
{
2009-08-28 13:00:27 +00:00
frame . subframes [ ch ] . best . type = SubframeType . Constant ;
frame . subframes [ ch ] . best . residual [ 0 ] = smp [ 0 ] ;
2010-02-06 23:17:07 +00:00
frame . subframes [ ch ] . best . size = ( uint ) frame . subframes [ ch ] . obits ;
2009-08-17 03:39:53 +00:00
return ;
}
// VERBATIM
2009-08-28 13:00:27 +00:00
frame . current . type = SubframeType . Verbatim ;
2010-02-06 23:17:07 +00:00
frame . current . size = ( uint ) ( frame . subframes [ ch ] . obits * frame . blocksize ) ;
2009-08-28 13:00:27 +00:00
frame . ChooseBestSubframe ( ch ) ;
2009-08-17 03:39:53 +00:00
if ( n < 5 | | predict = = PredictionType . None )
return ;
// LPC
2013-06-18 20:45:53 -04:00
if ( n > m_settings . MaxLPCOrder & &
2009-08-17 03:39:53 +00:00
( predict = = PredictionType . Levinson | |
2009-08-26 17:30:17 +00:00
predict = = PredictionType . Search )
//predict == PredictionType.Search ||
2009-08-28 13:00:27 +00:00
//(pass == 2 && frame.subframes[ch].best.type == SubframeType.LPC))
2009-08-26 17:30:17 +00:00
)
2009-08-17 03:39:53 +00:00
{
2009-10-16 23:35:56 +00:00
float * lpcs = stackalloc float [ lpc . MAX_LPC_ORDER * lpc . MAX_LPC_ORDER ] ;
2013-06-18 20:45:53 -04:00
int min_order = m_settings . MinLPCOrder ;
int max_order = m_settings . MaxLPCOrder ;
2009-08-17 03:39:53 +00:00
2009-08-21 03:26:12 +00:00
for ( int iWindow = 0 ; iWindow < _windowcount ; iWindow + + )
{
2014-08-26 23:48:16 -04:00
if ( ( windows_mask & ( 1 < < iWindow ) ) = = 0 )
2009-08-21 03:26:12 +00:00
continue ;
2009-08-20 04:09:53 +00:00
2009-08-28 13:00:27 +00:00
LpcContext lpc_ctx = frame . subframes [ ch ] . lpc_ctx [ iWindow ] ;
2014-08-26 23:48:16 -04:00
fixed ( LpcWindowSection * sections = & windowSections [ frame . nSeg , iWindow , 0 ] )
lpc_ctx . GetReflection (
2014-09-15 00:48:31 -04:00
frame . subframes [ ch ] . sf , max_order , frame . blocksize ,
smp , frame . window_buffer + iWindow * Flake . MAX_BLOCKSIZE * 2 , sections ) ;
2014-08-26 23:48:16 -04:00
lpc_ctx . ComputeLPC ( lpcs ) ;
2009-08-21 03:26:12 +00:00
2009-10-16 23:35:56 +00:00
//int frameSize = n;
//float* F = stackalloc float[frameSize];
//float* B = stackalloc float[frameSize];
//float* PE = stackalloc float[max_order + 1];
//float* arp = stackalloc float[max_order];
//float* rc = stackalloc float[max_order];
//for (int j = 0; j < frameSize; j++)
// F[j] = B[j] = smp[j];
//for (int K = 1; K <= max_order; K++)
//{
// // BURG:
// float denominator = 0.0f;
// //float denominator = F[K - 1] * F[K - 1] + B[frameSize - K] * B[frameSize - K];
// for (int j = 0; j < frameSize - K; j++)
// denominator += F[j + K] * F[j + K] + B[j] * B[j];
// denominator /= 2;
// // Estimate error
// PE[K - 1] = denominator / (frameSize - K);
// float reflectionCoeff = 0.0f;
// for (int j = 0; j < frameSize - K; j++)
// reflectionCoeff += F[j + K] * B[j];
// reflectionCoeff /= denominator;
// rc[K - 1] = arp[K - 1] = reflectionCoeff;
// // Levinson-Durbin
// for (int j = 0; j < (K - 1) >> 1; j++)
// {
// float arptmp = arp[j];
// arp[j] -= reflectionCoeff * arp[K - 2 - j];
// arp[K - 2 - j] -= reflectionCoeff * arptmp;
// }
// if (((K - 1) & 1) != 0)
// arp[(K - 1) >> 1] -= reflectionCoeff * arp[(K - 1) >> 1];
// for (int j = 0; j < frameSize - K; j++)
// {
// float f = F[j + K];
// float b = B[j];
// F[j + K] = f - reflectionCoeff * b;
// B[j] = b - reflectionCoeff * f;
// }
// for (int j = 0; j < K; j++)
// lpcs[(K - 1) * lpc.MAX_LPC_ORDER + j] = (float)arp[j];
//}
2009-08-21 03:26:12 +00:00
switch ( omethod )
{
2009-10-16 23:35:56 +00:00
case OrderMethod . Akaike :
2014-12-08 22:18:34 -05:00
//lpc_ctx.SortOrdersAkaike(frame.blocksize, m_settings.EstimationDepth, max_order, 7.1, 0.0);
lpc_ctx . SortOrdersAkaike ( frame . blocksize , m_settings . EstimationDepth , min_order , max_order , 4.5 , 0 ) ;
2009-08-21 03:26:12 +00:00
break ;
default :
2009-10-16 23:35:56 +00:00
throw new Exception ( "unknown order method" ) ;
2009-08-17 03:39:53 +00:00
}
2009-10-16 23:35:56 +00:00
2014-12-08 22:18:34 -05:00
for ( i = 0 ; i < m_settings . EstimationDepth & & i < max_order ; i + + )
2009-10-16 23:35:56 +00:00
encode_residual_lpc_sub ( frame , lpcs , iWindow , lpc_ctx . best_orders [ i ] , ch ) ;
2012-07-12 00:11:39 +00:00
}
postprocess_coefs ( frame , frame . subframes [ ch ] . best , ch ) ;
}
// FIXED
if ( predict = = PredictionType . Fixed | |
( predict = = PredictionType . Search & & pass ! = 1 ) | |
//predict == PredictionType.Search ||
//(pass == 2 && frame.subframes[ch].best.type == SubframeType.Fixed) ||
2013-06-18 20:45:53 -04:00
( n > m_settings . MaxFixedOrder & & n < = m_settings . MaxLPCOrder ) )
2012-07-12 00:11:39 +00:00
{
2013-06-18 20:45:53 -04:00
int max_fixed_order = Math . Min ( m_settings . MaxFixedOrder , 4 ) ;
int min_fixed_order = Math . Min ( m_settings . MinFixedOrder , max_fixed_order ) ;
2012-07-12 00:11:39 +00:00
2014-08-26 23:48:16 -04:00
if ( min_fixed_order = = 0 & & max_fixed_order = = 4 )
{
2014-12-08 22:18:34 -05:00
fixed ( ulong * fixed_errors = frame . subframes [ ch ] . best_fixed )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
if ( ( frame . subframes [ ch ] . done_fixed & ( 1 U < < 5 ) ) = = 0 )
{
fixed_compute_best_predictor ( smp + 4 , ( uint ) n - 4 , fixed_errors ) ;
frame . subframes [ ch ] . done_fixed | = ( 1 U < < 5 ) ;
}
2014-08-26 23:48:16 -04:00
i = fixed_compute_best_predictor_order ( fixed_errors ) ;
encode_residual_fixed_sub ( frame , i , ch ) ;
}
}
else
{
for ( i = max_fixed_order ; i > = min_fixed_order ; i - - )
encode_residual_fixed_sub ( frame , i , ch ) ;
}
2012-07-12 00:11:39 +00:00
}
}
2009-08-17 03:39:53 +00:00
2009-08-28 13:00:27 +00:00
unsafe void output_frame_header ( FlacFrame frame , BitWriter bitwriter )
2009-08-17 03:39:53 +00:00
{
2009-08-26 17:30:17 +00:00
bitwriter . writebits ( 15 , 0x7FFC ) ;
bitwriter . writebits ( 1 , eparams . variable_block_size > 0 ? 1 : 0 ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 4 , frame . bs_code0 ) ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 4 , sr_code0 ) ;
2009-08-28 13:00:27 +00:00
if ( frame . ch_mode = = ChannelMode . NotStereo )
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 4 , ch_code ) ;
else
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 4 , ( int ) frame . ch_mode ) ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 3 , bps_code ) ;
bitwriter . writebits ( 1 , 0 ) ;
bitwriter . write_utf8 ( frame_count ) ;
// custom block size
2009-08-28 13:00:27 +00:00
if ( frame . bs_code1 > = 0 )
2009-08-17 03:39:53 +00:00
{
2009-08-28 13:00:27 +00:00
if ( frame . bs_code1 < 256 )
bitwriter . writebits ( 8 , frame . bs_code1 ) ;
2009-08-17 03:39:53 +00:00
else
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 16 , frame . bs_code1 ) ;
2009-08-17 03:39:53 +00:00
}
// custom sample rate
if ( sr_code1 > 0 )
{
if ( sr_code1 < 256 )
bitwriter . writebits ( 8 , sr_code1 ) ;
else
bitwriter . writebits ( 16 , sr_code1 ) ;
}
// CRC-8 of frame header
bitwriter . flush ( ) ;
byte crc = crc8 . ComputeChecksum ( frame_buffer , 0 , bitwriter . Length ) ;
bitwriter . writebits ( 8 , crc ) ;
}
2009-08-28 13:00:27 +00:00
unsafe void output_residual ( FlacFrame frame , BitWriter bitwriter , FlacSubframeInfo sub )
2009-08-17 03:39:53 +00:00
{
// rice-encoded block
2010-12-07 22:52:34 +00:00
bitwriter . writebits ( 2 , sub . best . rc . coding_method ) ;
2009-08-17 03:39:53 +00:00
// partition order
2009-08-28 13:00:27 +00:00
int porder = sub . best . rc . porder ;
int psize = frame . blocksize > > porder ;
2009-08-17 03:39:53 +00:00
//assert(porder >= 0);
bitwriter . writebits ( 4 , porder ) ;
2009-08-28 13:00:27 +00:00
int res_cnt = psize - sub . best . order ;
2009-08-17 03:39:53 +00:00
2010-12-07 22:52:34 +00:00
int rice_len = 4 + sub . best . rc . coding_method ;
2009-08-17 03:39:53 +00:00
// residual
2009-08-28 13:00:27 +00:00
int j = sub . best . order ;
2009-10-16 23:35:56 +00:00
fixed ( byte * fixbuf = & frame_buffer [ 0 ] )
2009-08-17 03:39:53 +00:00
for ( int p = 0 ; p < ( 1 < < porder ) ; p + + )
{
2009-08-28 13:00:27 +00:00
int k = sub . best . rc . rparams [ p ] ;
2010-12-07 22:52:34 +00:00
bitwriter . writebits ( rice_len , k ) ;
2009-08-17 03:39:53 +00:00
if ( p = = 1 ) res_cnt = psize ;
2009-08-28 13:00:27 +00:00
int cnt = Math . Min ( res_cnt , frame . blocksize - j ) ;
2009-10-16 23:35:56 +00:00
bitwriter . write_rice_block_signed ( fixbuf , k , sub . best . residual + j , cnt ) ;
2009-08-28 13:00:27 +00:00
j + = cnt ;
2009-08-17 03:39:53 +00:00
}
}
unsafe void
2009-08-28 13:00:27 +00:00
output_subframe_constant ( FlacFrame frame , BitWriter bitwriter , FlacSubframeInfo sub )
2009-08-17 03:39:53 +00:00
{
2009-08-28 13:00:27 +00:00
bitwriter . writebits_signed ( sub . obits , sub . best . residual [ 0 ] ) ;
2009-08-17 03:39:53 +00:00
}
unsafe void
2009-08-28 13:00:27 +00:00
output_subframe_verbatim ( FlacFrame frame , BitWriter bitwriter , FlacSubframeInfo sub )
2009-08-17 03:39:53 +00:00
{
2009-08-28 13:00:27 +00:00
int n = frame . blocksize ;
2009-08-17 03:39:53 +00:00
for ( int i = 0 ; i < n ; i + + )
2009-08-28 13:00:27 +00:00
bitwriter . writebits_signed ( sub . obits , sub . samples [ i ] ) ;
2009-08-17 03:39:53 +00:00
// Don't use residual here, because we don't copy samples to residual for verbatim frames.
}
unsafe void
2009-08-28 13:00:27 +00:00
output_subframe_fixed ( FlacFrame frame , BitWriter bitwriter , FlacSubframeInfo sub )
2009-08-17 03:39:53 +00:00
{
// warm-up samples
2009-08-28 13:00:27 +00:00
for ( int i = 0 ; i < sub . best . order ; i + + )
bitwriter . writebits_signed ( sub . obits , sub . best . residual [ i ] ) ;
2009-08-17 03:39:53 +00:00
// residual
output_residual ( frame , bitwriter , sub ) ;
}
unsafe void
2009-08-28 13:00:27 +00:00
output_subframe_lpc ( FlacFrame frame , BitWriter bitwriter , FlacSubframeInfo sub )
2009-08-17 03:39:53 +00:00
{
// warm-up samples
2009-08-28 13:00:27 +00:00
for ( int i = 0 ; i < sub . best . order ; i + + )
bitwriter . writebits_signed ( sub . obits , sub . best . residual [ i ] ) ;
2009-08-17 03:39:53 +00:00
// LPC coefficients
2009-08-20 04:09:53 +00:00
int cbits = 1 ;
2009-08-28 13:00:27 +00:00
for ( int i = 0 ; i < sub . best . order ; i + + )
while ( cbits < 16 & & sub . best . coefs [ i ] ! = ( sub . best . coefs [ i ] < < ( 32 - cbits ) ) > > ( 32 - cbits ) )
2009-08-20 04:09:53 +00:00
cbits + + ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 4 , cbits - 1 ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits_signed ( 5 , sub . best . shift ) ;
for ( int i = 0 ; i < sub . best . order ; i + + )
bitwriter . writebits_signed ( cbits , sub . best . coefs [ i ] ) ;
2014-09-15 00:48:31 -04:00
2009-08-17 03:39:53 +00:00
// residual
output_residual ( frame , bitwriter , sub ) ;
}
2009-08-28 13:00:27 +00:00
unsafe void output_subframes ( FlacFrame frame , BitWriter bitwriter )
2009-08-17 03:39:53 +00:00
{
for ( int ch = 0 ; ch < channels ; ch + + )
{
2009-08-28 13:00:27 +00:00
FlacSubframeInfo sub = frame . subframes [ ch ] ;
2009-08-17 03:39:53 +00:00
// subframe header
2009-08-28 13:00:27 +00:00
int type_code = ( int ) sub . best . type ;
if ( sub . best . type = = SubframeType . Fixed )
type_code | = sub . best . order ;
if ( sub . best . type = = SubframeType . LPC )
type_code | = sub . best . order - 1 ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 1 , 0 ) ;
bitwriter . writebits ( 6 , type_code ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 1 , sub . wbits ! = 0 ? 1 : 0 ) ;
if ( sub . wbits > 0 )
bitwriter . writebits ( ( int ) sub . wbits , 1 ) ;
2009-08-17 03:39:53 +00:00
// subframe
2009-08-28 13:00:27 +00:00
switch ( sub . best . type )
2009-08-17 03:39:53 +00:00
{
case SubframeType . Constant :
output_subframe_constant ( frame , bitwriter , sub ) ;
break ;
case SubframeType . Verbatim :
output_subframe_verbatim ( frame , bitwriter , sub ) ;
break ;
case SubframeType . Fixed :
output_subframe_fixed ( frame , bitwriter , sub ) ;
break ;
case SubframeType . LPC :
output_subframe_lpc ( frame , bitwriter , sub ) ;
break ;
}
}
}
void output_frame_footer ( BitWriter bitwriter )
{
bitwriter . flush ( ) ;
2013-03-26 19:50:44 -04:00
ushort crc = bitwriter . get_crc16 ( ) ;
bitwriter . writebits ( 16 , crc ) ;
2009-08-17 03:39:53 +00:00
bitwriter . flush ( ) ;
}
2014-08-26 23:48:16 -04:00
unsafe void encode_residual_pass1 ( FlacFrame frame , int ch , int windows_mask )
2009-08-26 17:30:17 +00:00
{
2013-06-18 20:45:53 -04:00
int max_prediction_order = m_settings . MaxLPCOrder ;
2014-08-26 23:48:16 -04:00
//int max_fixed_order = m_settings.MaxFixedOrder;
//int min_fixed_order = m_settings.MinFixedOrder;
2014-12-08 22:18:34 -05:00
int lpc_min_precision_search = m_settings . MinPrecisionSearch ;
int lpc_max_precision_search = m_settings . MaxPrecisionSearch ;
2013-06-18 20:45:53 -04:00
int max_partition_order = m_settings . MaxPartitionOrder ;
2014-12-08 22:18:34 -05:00
int estimation_depth = m_settings . EstimationDepth ;
2012-07-12 00:11:39 +00:00
var development_mode = eparams . development_mode ;
2014-08-26 23:48:16 -04:00
//m_settings.MinFixedOrder = 2;
//m_settings.MaxFixedOrder = 2;
2014-12-08 22:18:34 -05:00
m_settings . MinPrecisionSearch = m_settings . MaxPrecisionSearch ;
2013-06-18 20:45:53 -04:00
m_settings . MaxLPCOrder = Math . Min ( m_settings . MaxLPCOrder , Math . Max ( m_settings . MinLPCOrder , 8 ) ) ;
2014-12-08 22:18:34 -05:00
m_settings . EstimationDepth = 1 ;
2012-07-12 00:11:39 +00:00
eparams . development_mode = Math . Min ( eparams . development_mode , - 1 ) ;
2014-12-08 22:18:34 -05:00
encode_residual ( frame , ch , m_settings . PredictionType , OrderMethod . Akaike , 1 , windows_mask ) ;
2014-08-26 23:48:16 -04:00
//m_settings.MinFixedOrder = min_fixed_order;
//m_settings.MaxFixedOrder = max_fixed_order;
2013-06-18 20:45:53 -04:00
m_settings . MaxLPCOrder = max_prediction_order ;
2014-12-08 22:18:34 -05:00
m_settings . MinPrecisionSearch = lpc_min_precision_search ;
m_settings . MaxPrecisionSearch = lpc_max_precision_search ;
2013-06-18 20:45:53 -04:00
m_settings . MaxPartitionOrder = max_partition_order ;
2014-12-08 22:18:34 -05:00
m_settings . EstimationDepth = estimation_depth ;
2012-07-12 00:11:39 +00:00
eparams . development_mode = development_mode ;
2009-08-26 17:30:17 +00:00
}
2009-08-28 13:00:27 +00:00
unsafe void encode_residual_pass2 ( FlacFrame frame , int ch )
2009-08-26 17:30:17 +00:00
{
2014-12-08 22:18:34 -05:00
encode_residual ( frame , ch , m_settings . PredictionType , eparams . order_method , 2 , estimate_best_windows ( frame , ch ) ) ;
2009-08-26 17:30:17 +00:00
}
2014-08-26 23:48:16 -04:00
unsafe int estimate_best_windows_akaike ( FlacFrame frame , int ch , int count , bool onePerType )
{
int * windows_present = stackalloc int [ _windowcount ] ;
for ( int i = 0 ; i < _windowcount ; i + + )
windows_present [ i ] = 0 ;
if ( onePerType )
{
for ( int i = 0 ; i < _windowcount ; i + + )
for ( int j = 0 ; j < _windowcount ; j + + )
if ( windowType [ j ] = = windowType [ i ] )
windows_present [ j ] + + ;
}
float * err = stackalloc float [ lpc . MAX_LPC_ORDER ] ;
for ( int i = 0 ; i < _windowcount ; i + + )
{
LpcContext lpc_ctx = frame . subframes [ ch ] . lpc_ctx [ i ] ;
if ( onePerType & & windows_present [ i ] < = count )
{
err [ i ] = 0 ;
continue ;
}
int estimate_order = 4 ;
fixed ( LpcWindowSection * sections = & windowSections [ frame . nSeg , i , 0 ] )
lpc_ctx . GetReflection (
2014-09-15 00:48:31 -04:00
frame . subframes [ ch ] . sf , estimate_order , frame . blocksize ,
frame . subframes [ ch ] . samples , frame . window_buffer + i * Flake . MAX_BLOCKSIZE * 2 , sections ) ;
2014-08-26 23:48:16 -04:00
lpc_ctx . SortOrdersAkaike ( frame . blocksize , 1 , 1 , estimate_order , 4.5 , 0.0 ) ;
//err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0));
//err[i] = (float)((frame.blocksize * lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1] / windowScale[i]) + lpc_ctx.best_orders[0] * 4.5);
//err[i] = (float)((frame.blocksize * lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1] / windowScale[i]) + lpc_ctx.best_orders[0] * frame.subframes[ch].obits);
// realistic
//err[i] = (float)(frame.blocksize * Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) / Math.Log(2) / 2.5
//- windowScale[i] / 2 + lpc_ctx.best_orders[0] * frame.subframes[ch].obits / 2);
//err[i] = (float)(frame.blocksize * Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1]) / Math.Log(2) / 2.5
//- frame.blocksize * Math.Log(lpc_ctx.autocorr_values[0]) / 2.1
//+ Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5 / 2.5 / Math.Log(2));
// Akaike
//err[i] = (float)(frame.blocksize * (Math.Log(lpc_ctx.prediction_error[lpc_ctx.best_orders[0] - 1])) + Math.Log(frame.blocksize) * lpc_ctx.best_orders[0] * 4.5);
//err[i] = (float)(lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) - frame.blocksize * (frame.subframes[ch].obits + Math.Log(windowScale[i] / frame.blocksize) / 2));
// tested good
err [ i ] = ( float ) ( lpc_ctx . Akaike ( frame . blocksize , lpc_ctx . best_orders [ 0 ] , 4.5 , 0.0 ) - frame . blocksize * Math . Log ( lpc_ctx . autocorr_values [ 0 ] ) / 2 ) ;
}
int * best_windows = stackalloc int [ lpc . MAX_LPC_ORDER ] ;
for ( int i = 0 ; i < _windowcount ; i + + )
best_windows [ i ] = i ;
for ( int i = 0 ; i < _windowcount ; i + + )
{
for ( int j = i + 1 ; j < _windowcount ; j + + )
{
if ( err [ best_windows [ i ] ] > err [ best_windows [ j ] ] )
{
int tmp = best_windows [ j ] ;
best_windows [ j ] = best_windows [ i ] ;
best_windows [ i ] = tmp ;
}
}
}
int window_mask = 0 ;
if ( onePerType )
{
for ( int i = 0 ; i < _windowcount ; i + + )
windows_present [ i ] = count ;
for ( int i = 0 ; i < _windowcount ; i + + )
{
int w = best_windows [ i ] ;
if ( windows_present [ w ] > 0 )
{
for ( int j = 0 ; j < _windowcount ; j + + )
if ( windowType [ j ] = = windowType [ w ] )
windows_present [ j ] - - ;
window_mask | = 1 < < w ;
}
}
}
else
{
for ( int i = 0 ; i < _windowcount & & i < count ; i + + )
window_mask | = 1 < < best_windows [ i ] ;
}
return window_mask ;
}
unsafe int estimate_best_windows ( FlacFrame frame , int ch )
2009-08-26 17:30:17 +00:00
{
2014-12-08 22:18:34 -05:00
if ( _windowcount = = 1 | | m_settings . PredictionType = = PredictionType . Fixed )
2014-08-26 23:48:16 -04:00
return 1 ;
2014-12-08 22:18:34 -05:00
switch ( m_settings . WindowMethod )
2009-08-26 17:30:17 +00:00
{
2014-08-26 23:48:16 -04:00
case WindowMethod . Estimate :
return estimate_best_windows_akaike ( frame , ch , 1 , false ) ;
case WindowMethod . Estimate2 :
return estimate_best_windows_akaike ( frame , ch , 2 , false ) ;
case WindowMethod . Estimate3 :
return estimate_best_windows_akaike ( frame , ch , 3 , false ) ;
case WindowMethod . EstimateN :
return estimate_best_windows_akaike ( frame , ch , 1 , true ) ;
case WindowMethod . Evaluate2 :
encode_residual_pass1 ( frame , ch , estimate_best_windows_akaike ( frame , ch , 2 , false ) ) ;
return frame . subframes [ ch ] . best . type = = SubframeType . LPC ? 1 < < frame . subframes [ ch ] . best . window : 0 ;
case WindowMethod . Evaluate3 :
encode_residual_pass1 ( frame , ch , estimate_best_windows_akaike ( frame , ch , 3 , false ) ) ;
return frame . subframes [ ch ] . best . type = = SubframeType . LPC ? 1 < < frame . subframes [ ch ] . best . window : 0 ;
case WindowMethod . EvaluateN :
encode_residual_pass1 ( frame , ch , estimate_best_windows_akaike ( frame , ch , 1 , true ) ) ;
#if XXX
if ( frame . subframes [ ch ] . best . type = = SubframeType . LPC & & frame . subframes [ ch ] . best . order < = 4 )
{
LpcContext lpc_ctx = frame . subframes [ ch ] . lpc_ctx [ frame . subframes [ ch ] . best . window ] ;
double err = lpc_ctx . prediction_error [ frame . subframes [ ch ] . best . order - 1 ] / lpc_ctx . autocorr_values [ 0 ] ;
double est = frame . blocksize * ( frame . subframes [ ch ] . obits * ( 1 - err ) ) ;
double est1 = frame . blocksize * ( frame . subframes [ ch ] . obits * ( err ) ) ;
if ( est < 0 | | est1 < 0 ) return - 1 ;
}
#endif
return frame . subframes [ ch ] . best . type = = SubframeType . LPC ? 1 < < frame . subframes [ ch ] . best . window : 0 ;
case WindowMethod . Evaluate2N :
encode_residual_pass1 ( frame , ch , estimate_best_windows_akaike ( frame , ch , 2 , true ) ) ;
return frame . subframes [ ch ] . best . type = = SubframeType . LPC ? 1 < < frame . subframes [ ch ] . best . window : 0 ;
case WindowMethod . Evaluate3N :
encode_residual_pass1 ( frame , ch , estimate_best_windows_akaike ( frame , ch , 3 , true ) ) ;
return frame . subframes [ ch ] . best . type = = SubframeType . LPC ? 1 < < frame . subframes [ ch ] . best . window : 0 ;
case WindowMethod . Evaluate :
2009-12-24 16:11:22 +00:00
encode_residual_pass1 ( frame , ch , - 1 ) ;
2014-08-26 23:48:16 -04:00
return frame . subframes [ ch ] . best . type = = SubframeType . LPC ? 1 < < frame . subframes [ ch ] . best . window : 0 ;
case WindowMethod . Search :
2009-12-24 16:11:22 +00:00
return - 1 ;
}
return - 1 ;
2009-08-26 17:30:17 +00:00
}
2009-08-28 13:00:27 +00:00
unsafe void estimate_frame ( FlacFrame frame , bool do_midside )
2009-08-21 03:26:12 +00:00
{
int subframes = do_midside ? channels * 2 : channels ;
2014-12-08 22:18:34 -05:00
switch ( m_settings . StereoMethod )
2009-08-21 03:26:12 +00:00
{
2014-09-15 00:48:31 -04:00
case StereoMethod . Estimate :
2009-08-21 03:26:12 +00:00
for ( int ch = 0 ; ch < subframes ; ch + + )
2009-10-16 23:35:56 +00:00
{
2014-08-26 23:48:16 -04:00
LpcContext lpc_ctx = frame . subframes [ ch ] . lpc_ctx [ 0 ] ;
int estimate_order = 4 ;
int iWindow = 0 ;
fixed ( LpcWindowSection * sections = & windowSections [ frame . nSeg , iWindow , 0 ] )
lpc_ctx . GetReflection (
2014-09-15 00:48:31 -04:00
frame . subframes [ ch ] . sf , estimate_order , frame . blocksize ,
frame . subframes [ ch ] . samples , frame . window_buffer + iWindow * Flake . MAX_BLOCKSIZE * 2 , sections ) ;
2014-08-26 23:48:16 -04:00
lpc_ctx . SortOrdersAkaike ( frame . blocksize , 1 , 1 , estimate_order , 4.5 , 0.0 ) ;
frame . subframes [ ch ] . best . size
= ( uint ) Math . Max ( 0 , frame . blocksize * ( Math . Log ( lpc_ctx . prediction_error [ lpc_ctx . best_orders [ 0 ] - 1 ] ) ) + Math . Log ( frame . blocksize ) * lpc_ctx . best_orders [ 0 ] * 4.5
//= (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0)
//* 2.0 / Math.Log(windowScale[0] / frame.blocksize)
+ 7.1 * frame . subframes [ ch ] . obits * m_settings . MaxLPCOrder ) ;
}
2009-08-21 03:26:12 +00:00
break ;
2014-09-15 00:48:31 -04:00
case StereoMethod . EstimateFixed :
for ( int ch = 0 ; ch < subframes ; ch + + )
{
2014-12-08 22:18:34 -05:00
fixed ( ulong * fixed_errors = frame . subframes [ ch ] . best_fixed )
{
if ( ( frame . subframes [ ch ] . done_fixed & ( 1 U < < 5 ) ) = = 0 )
{
fixed_compute_best_predictor ( frame . subframes [ ch ] . samples + 4 , ( uint ) frame . blocksize - 4 , fixed_errors ) ;
frame . subframes [ ch ] . done_fixed | = ( 1 U < < 5 ) ;
}
int best_order = fixed_compute_best_predictor_order ( fixed_errors ) ;
//residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
frame . subframes [ ch ] . best . size = ( uint ) fixed_errors [ best_order ] ;
}
2014-09-15 00:48:31 -04:00
}
break ;
case StereoMethod . EstimateX :
for ( int ch = 0 ; ch < subframes ; ch + + )
2014-12-08 22:18:34 -05:00
{
2014-09-15 00:48:31 -04:00
for ( int iWindow = 0 ; iWindow < _windowcount ; iWindow + + )
{
LpcContext lpc_ctx = frame . subframes [ ch ] . lpc_ctx [ iWindow ] ;
int estimate_order = 4 ;
fixed ( LpcWindowSection * sections = & windowSections [ frame . nSeg , iWindow , 0 ] )
lpc_ctx . GetReflection (
frame . subframes [ ch ] . sf , estimate_order , frame . blocksize ,
frame . subframes [ ch ] . samples , frame . window_buffer + iWindow * Flake . MAX_BLOCKSIZE * 2 , sections ) ;
lpc_ctx . SortOrdersAkaike ( frame . blocksize , 1 , 1 , estimate_order , 4.5 , 0.0 ) ;
uint estimate
= ( uint ) Math . Max ( 0 , frame . blocksize * ( Math . Log ( lpc_ctx . prediction_error [ lpc_ctx . best_orders [ 0 ] - 1 ] ) ) + Math . Log ( frame . blocksize ) * lpc_ctx . best_orders [ 0 ] * 4.5
//= (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0)
//* 2.0 / Math.Log(windowScale[0] / frame.blocksize)
+ 7.1 * frame . subframes [ ch ] . obits * m_settings . MaxLPCOrder ) ;
if ( iWindow = = 0 | | frame . subframes [ ch ] . best . size > estimate )
frame . subframes [ ch ] . best . size = estimate ;
}
2014-12-08 22:18:34 -05:00
}
2014-09-15 00:48:31 -04:00
break ;
2014-08-26 23:48:16 -04:00
case StereoMethod . Evaluate :
2012-07-12 00:11:39 +00:00
for ( int ch = 0 ; ch < subframes ; ch + + )
2014-08-26 23:48:16 -04:00
encode_residual_pass1 ( frame , ch , 1 ) ;
2009-08-26 17:30:17 +00:00
break ;
2014-09-15 00:48:31 -04:00
case StereoMethod . EvaluateX :
for ( int ch = 0 ; ch < subframes ; ch + + )
encode_residual_pass1 ( frame , ch ,
estimate_best_windows_akaike ( frame , ch , 1 , false ) ) ;
break ;
2009-08-21 03:26:12 +00:00
case StereoMethod . Search :
for ( int ch = 0 ; ch < subframes ; ch + + )
2009-12-24 16:11:22 +00:00
encode_residual_pass2 ( frame , ch ) ;
2009-08-21 03:26:12 +00:00
break ;
}
}
2009-08-28 13:00:27 +00:00
unsafe uint measure_frame_size ( FlacFrame frame , bool do_midside )
2009-08-21 03:26:12 +00:00
{
2009-08-28 13:00:27 +00:00
// crude estimation of header/footer size
2009-08-30 21:58:54 +00:00
uint total = ( uint ) ( 32 + ( ( BitReader . log2i ( frame_count ) + 4 ) / 5 ) * 8 + ( eparams . variable_block_size ! = 0 ? 16 : 0 ) + 16 ) ;
2009-08-21 03:26:12 +00:00
if ( do_midside )
{
2009-08-30 21:58:54 +00:00
uint bitsBest = AudioSamples . UINT32_MAX ;
2009-08-21 03:26:12 +00:00
ChannelMode modeBest = ChannelMode . LeftRight ;
2009-08-28 13:00:27 +00:00
if ( bitsBest > frame . subframes [ 2 ] . best . size + frame . subframes [ 3 ] . best . size )
2009-08-21 03:26:12 +00:00
{
2009-08-28 13:00:27 +00:00
bitsBest = frame . subframes [ 2 ] . best . size + frame . subframes [ 3 ] . best . size ;
2009-08-21 03:26:12 +00:00
modeBest = ChannelMode . MidSide ;
}
2009-08-28 13:00:27 +00:00
if ( bitsBest > frame . subframes [ 3 ] . best . size + frame . subframes [ 1 ] . best . size )
2009-08-21 03:26:12 +00:00
{
2009-08-28 13:00:27 +00:00
bitsBest = frame . subframes [ 3 ] . best . size + frame . subframes [ 1 ] . best . size ;
2009-08-21 03:26:12 +00:00
modeBest = ChannelMode . RightSide ;
}
2009-08-28 13:00:27 +00:00
if ( bitsBest > frame . subframes [ 3 ] . best . size + frame . subframes [ 0 ] . best . size )
2009-08-21 03:26:12 +00:00
{
2009-08-28 13:00:27 +00:00
bitsBest = frame . subframes [ 3 ] . best . size + frame . subframes [ 0 ] . best . size ;
2009-08-21 03:26:12 +00:00
modeBest = ChannelMode . LeftSide ;
}
2009-08-28 13:00:27 +00:00
if ( bitsBest > frame . subframes [ 0 ] . best . size + frame . subframes [ 1 ] . best . size )
2009-08-21 03:26:12 +00:00
{
2009-08-28 13:00:27 +00:00
bitsBest = frame . subframes [ 0 ] . best . size + frame . subframes [ 1 ] . best . size ;
2009-08-21 03:26:12 +00:00
modeBest = ChannelMode . LeftRight ;
}
2009-08-28 13:00:27 +00:00
frame . ch_mode = modeBest ;
2009-08-21 03:26:12 +00:00
return total + bitsBest ;
}
for ( int ch = 0 ; ch < channels ; ch + + )
2009-08-28 13:00:27 +00:00
total + = frame . subframes [ ch ] . best . size ;
2009-08-21 03:26:12 +00:00
return total ;
}
2009-08-28 13:00:27 +00:00
unsafe void encode_estimated_frame ( FlacFrame frame )
2009-08-21 03:26:12 +00:00
{
2014-12-08 22:18:34 -05:00
switch ( m_settings . StereoMethod )
2009-08-21 03:26:12 +00:00
{
case StereoMethod . Estimate :
2014-09-15 00:48:31 -04:00
case StereoMethod . EstimateX :
2014-12-08 22:18:34 -05:00
case StereoMethod . EstimateFixed :
2014-09-15 00:48:31 -04:00
for ( int ch = 0 ; ch < channels ; ch + + )
2009-08-21 03:26:12 +00:00
{
2009-08-30 21:58:54 +00:00
frame . subframes [ ch ] . best . size = AudioSamples . UINT32_MAX ;
2009-12-24 16:11:22 +00:00
encode_residual_pass2 ( frame , ch ) ;
2009-08-21 03:26:12 +00:00
}
break ;
2014-08-26 23:48:16 -04:00
case StereoMethod . Evaluate :
2014-09-15 00:48:31 -04:00
case StereoMethod . EvaluateX :
for ( int ch = 0 ; ch < channels ; ch + + )
2009-08-26 17:30:17 +00:00
encode_residual_pass2 ( frame , ch ) ;
2009-08-21 03:26:12 +00:00
break ;
case StereoMethod . Search :
break ;
}
}
2009-10-16 23:35:56 +00:00
unsafe delegate void window_function ( float * window , int size ) ;
2009-08-21 03:26:12 +00:00
2009-10-16 23:35:56 +00:00
unsafe void calculate_window ( float * window , window_function func , WindowFunction flag )
2009-08-21 03:26:12 +00:00
{
2014-12-08 22:18:34 -05:00
if ( ( m_settings . WindowFunctions & flag ) = = 0 | | _windowcount = = lpc . MAX_LPC_WINDOWS )
2009-08-21 03:26:12 +00:00
return ;
int sz = _windowsize ;
2009-12-24 16:11:22 +00:00
float * pos1 = window + _windowcount * Flake . MAX_BLOCKSIZE * 2 ;
float * pos = pos1 ;
2014-08-26 23:48:16 -04:00
int nSeg = 0 ;
2009-08-21 03:26:12 +00:00
do
{
2014-08-26 23:48:16 -04:00
windowSections [ nSeg , _windowcount , 0 ] . setData ( 0 , sz ) ;
for ( int j = 1 ; j < lpc . MAX_LPC_SECTIONS ; j + + )
windowSections [ nSeg , _windowcount , j ] . setZero ( sz , sz ) ;
fixed ( LpcWindowSection * sections = & windowSections [ nSeg , _windowcount , 0 ] )
2009-08-21 03:26:12 +00:00
func ( pos , sz ) ;
2014-08-26 23:48:16 -04:00
if ( ( sz & 1 ) ! = 0 )
2009-08-21 03:26:12 +00:00
break ;
2014-08-26 23:48:16 -04:00
nSeg + + ;
pos + = sz ;
2009-08-21 03:26:12 +00:00
sz > > = 1 ;
} while ( sz > = 32 ) ;
2009-12-24 16:11:22 +00:00
double scale = 0.0 ;
for ( int i = 0 ; i < _windowsize ; i + + )
scale + = pos1 [ i ] * pos1 [ i ] ;
windowScale [ _windowcount ] = scale ;
2014-08-26 23:48:16 -04:00
windowType [ _windowcount ] = flag ;
2009-08-21 03:26:12 +00:00
_windowcount + + ;
}
2014-12-08 22:18:34 -05:00
class PunchoutTukeyVariant
{
public PunchoutTukeyVariant (
WindowFunction _type ,
int _parts , double _overlap , double _p )
{
parts = _parts ;
type = _type ;
overlap = _overlap ;
p = _p ;
}
public WindowFunction type ;
public int parts ;
public double overlap ;
public double p ;
} ;
2009-08-21 03:26:12 +00:00
unsafe int encode_frame ( out int size )
2009-08-17 03:39:53 +00:00
{
fixed ( int * s = samplesBuffer , r = residualBuffer )
2009-10-16 23:35:56 +00:00
fixed ( float * window = windowBuffer )
2009-08-17 03:39:53 +00:00
{
2013-04-04 22:07:15 -04:00
frame . InitSize ( m_blockSize , eparams . variable_block_size ! = 0 ) ;
2009-08-20 18:46:37 +00:00
2014-12-08 22:18:34 -05:00
if ( frame . blocksize ! = _windowsize & & frame . blocksize > 4 & & m_settings . PredictionType ! = PredictionType . Fixed )
2014-08-26 23:48:16 -04:00
{
_windowsize = frame . blocksize ;
_windowcount = 0 ;
calculate_window ( window , lpc . window_welch , WindowFunction . Welch ) ;
calculate_window ( window , lpc . window_flattop , WindowFunction . Flattop ) ;
calculate_window ( window , lpc . window_hann , WindowFunction . Hann ) ;
calculate_window ( window , lpc . window_bartlett , WindowFunction . Bartlett ) ;
2014-12-08 22:18:34 -05:00
var tukeys = new PunchoutTukeyVariant [ ]
{
new PunchoutTukeyVariant ( WindowFunction . Tukey4 , 4 , 0 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey4A , 4 , 0 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey4B , 4 , 0 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey4X , 4 , m_settings . TukeyOverlap , m_settings . TukeyP ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey3 , 3 , 1.0 / 3 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey3A , 3 , 1.0 / 3 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey3B , 3 , 1.0 / 3 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey3X , 3 , m_settings . TukeyOverlap , m_settings . TukeyP ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey2 , 2 , 0.25 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey2A , 2 , 0.25 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey2B , 2 , 0.25 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey2X , 2 , m_settings . TukeyOverlap , m_settings . TukeyP ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey , 1 , 0.0 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey1A , 1 , 0.0 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey1B , 1 , 0.0 , 0.03 ) ,
new PunchoutTukeyVariant ( WindowFunction . Tukey1X , 1 , m_settings . TukeyOverlap , m_settings . TukeyP ) ,
} ;
foreach ( var tukey in tukeys )
{
if ( tukey . parts = = 0 | | ( m_settings . WindowFunctions & tukey . type ) = = 0 ) continue ;
if ( tukey . parts = = 1 )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
calculate_window ( window , ( w , wsz ) = >
{
lpc . window_tukey ( w , wsz , tukey . p ) ;
} , tukey . type ) ;
continue ;
}
double overlap = tukey . overlap ;
double overlap_units = overlap / ( 1.0 - overlap ) ;
for ( int m = 0 ; m < tukey . parts ; m + + )
calculate_window ( window , ( w , wsz ) = >
{
lpc . window_punchout_tukey ( w , wsz , tukey . p , tukey . p ,
m / ( tukey . parts + overlap_units ) ,
( m + 1 + overlap_units ) / ( tukey . parts + overlap_units ) ) ;
} , tukey . type ) ;
}
2014-08-26 23:48:16 -04:00
if ( _windowcount = = 0 )
throw new Exception ( "invalid windowfunction" ) ;
int nSeg = 0 ;
int sz = _windowsize ;
float * window_segment = window ;
do
{
fixed ( LpcWindowSection * sections = & windowSections [ nSeg , 0 , 0 ] )
2014-09-15 00:48:31 -04:00
LpcWindowSection . Detect ( _windowcount , window_segment , Flake . MAX_BLOCKSIZE * 2 , sz , Settings . PCM . BitsPerSample , sections ) ;
2014-08-26 23:48:16 -04:00
if ( ( sz & 1 ) ! = 0 )
break ;
window_segment + = sz ;
nSeg + + ;
sz > > = 1 ;
} while ( sz > = 32 ) ;
#if NONONO
2014-12-08 22:18:34 -05:00
using ( TextWriter tx = File . CreateText ( @"H:\ubuntu\flac\w.txt" ) )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
#if ! NONONO
2014-08-26 23:48:16 -04:00
int totaltotal = 0 ;
for ( int i = 0 ; i < _windowcount ; i + + )
{
int total = 0 ;
for ( int sec = 0 ; sec < lpc . MAX_LPC_SECTIONS ; sec + + )
if ( windowSections [ 0 , i , sec ] . m_type ! = LpcWindowSection . SectionType . Zero | | windowSections [ 0 , i , sec ] . m_start ! = windowSections [ 0 , i , sec ] . m_end )
{
2014-09-15 00:48:31 -04:00
tx . WriteLine ( "{0}\t{1}\t{2}\t{3}" , windowSections [ 0 , i , sec ] . m_start , windowSections [ 0 , i , sec ] . m_end , windowSections [ 0 , i , sec ] . m_type , windowSections [ 0 , i , sec ] . m_id ) ;
2014-08-26 23:48:16 -04:00
if ( windowSections [ 0 , i , sec ] . m_type ! = LpcWindowSection . SectionType . One )
total + = windowSections [ 0 , i , sec ] . m_end - windowSections [ 0 , i , sec ] . m_start ;
}
totaltotal + = total ;
tx . WriteLine ( "{0} total window data" , total ) ;
}
tx . WriteLine ( "{0} grand total window data" , totaltotal ) ;
2014-12-08 22:18:34 -05:00
#endif
for ( int x = 0 ; x < frame . blocksize ; x + + )
2014-08-26 23:48:16 -04:00
{
2014-12-08 22:18:34 -05:00
tx . Write ( "{0}" , x ) ;
2014-08-26 23:48:16 -04:00
for ( int i = 0 ; i < _windowcount ; i + + )
2014-12-08 22:18:34 -05:00
tx . Write ( "\t{0}" , window [ i * Flake . MAX_BLOCKSIZE * 2 + x ] ) ;
2014-08-26 23:48:16 -04:00
tx . WriteLine ( ) ;
}
}
#endif
}
2009-08-17 03:39:53 +00:00
2014-12-08 22:18:34 -05:00
if ( channels ! = 2 | | frame . blocksize < = 32 | | m_settings . StereoMethod = = StereoMethod . Independent )
2009-08-17 03:39:53 +00:00
{
2009-08-21 03:26:12 +00:00
frame . window_buffer = window ;
2014-08-26 23:48:16 -04:00
frame . nSeg = 0 ;
2009-08-20 18:46:37 +00:00
frame . current . residual = r + channels * Flake . MAX_BLOCKSIZE ;
frame . ch_mode = channels ! = 2 ? ChannelMode . NotStereo : ChannelMode . LeftRight ;
for ( int ch = 0 ; ch < channels ; ch + + )
2009-08-28 13:00:27 +00:00
frame . subframes [ ch ] . Init ( s + ch * Flake . MAX_BLOCKSIZE , r + ch * Flake . MAX_BLOCKSIZE ,
2013-04-07 20:41:58 -04:00
Settings . PCM . BitsPerSample , get_wasted_bits ( s + ch * Flake . MAX_BLOCKSIZE , frame . blocksize ) ) ;
2009-08-20 18:46:37 +00:00
2009-08-17 03:39:53 +00:00
for ( int ch = 0 ; ch < channels ; ch + + )
2009-12-24 16:11:22 +00:00
encode_residual_pass2 ( frame , ch ) ;
2009-08-17 03:39:53 +00:00
}
else
{
2010-02-06 23:17:07 +00:00
//channel_decorrelation(s, s + Flake.MAX_BLOCKSIZE, s + 2 * Flake.MAX_BLOCKSIZE, s + 3 * Flake.MAX_BLOCKSIZE, frame.blocksize);
2009-08-21 03:26:12 +00:00
frame . window_buffer = window ;
2014-08-26 23:48:16 -04:00
frame . nSeg = 0 ;
2009-08-20 18:46:37 +00:00
frame . current . residual = r + 4 * Flake . MAX_BLOCKSIZE ;
for ( int ch = 0 ; ch < 4 ; ch + + )
2010-02-06 23:17:07 +00:00
frame . subframes [ ch ] . Init ( s + ch * Flake . MAX_BLOCKSIZE , r + ch * Flake . MAX_BLOCKSIZE ,
2013-04-07 20:41:58 -04:00
Settings . PCM . BitsPerSample + ( ch = = 3 ? 1 : 0 ) , get_wasted_bits ( s + ch * Flake . MAX_BLOCKSIZE , frame . blocksize ) ) ;
2009-10-16 23:35:56 +00:00
//for (int ch = 0; ch < 4; ch++)
// for (int iWindow = 0; iWindow < _windowcount; iWindow++)
// frame.subframes[ch].lpc_ctx[iWindow].GetReflection(32, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer + iWindow * Flake.MAX_BLOCKSIZE * 2);
2009-08-28 13:00:27 +00:00
estimate_frame ( frame , true ) ;
uint fs = measure_frame_size ( frame , true ) ;
2009-08-17 03:39:53 +00:00
2009-08-21 03:26:12 +00:00
if ( 0 ! = eparams . variable_block_size )
2009-08-17 03:39:53 +00:00
{
2009-08-28 13:00:27 +00:00
FlacFrame frame2 = new FlacFrame ( channels * 2 ) ;
FlacFrame frame3 = new FlacFrame ( channels * 2 ) ;
2009-08-21 03:26:12 +00:00
int tumbler = 1 ;
while ( ( frame . blocksize & 1 ) = = 0 & & frame . blocksize > = 1024 )
{
2009-08-28 13:00:27 +00:00
frame2 . InitSize ( frame . blocksize / 2 , true ) ;
2009-08-21 03:26:12 +00:00
frame2 . window_buffer = frame . window_buffer + frame . blocksize ;
2014-09-19 22:01:20 -04:00
frame2 . nSeg = frame . nSeg + 1 ;
2009-08-21 03:26:12 +00:00
frame2 . current . residual = r + tumbler * 5 * Flake . MAX_BLOCKSIZE ;
2009-08-20 18:46:37 +00:00
for ( int ch = 0 ; ch < 4 ; ch + + )
2009-08-28 13:00:27 +00:00
frame2 . subframes [ ch ] . Init ( frame . subframes [ ch ] . samples , frame2 . current . residual + ( ch + 1 ) * frame2 . blocksize ,
2009-08-21 03:26:12 +00:00
frame . subframes [ ch ] . obits + frame . subframes [ ch ] . wbits , frame . subframes [ ch ] . wbits ) ;
2009-08-28 13:00:27 +00:00
estimate_frame ( frame2 , true ) ;
2014-09-19 22:01:20 -04:00
//measure_frame_size(frame2, true);
//frame2.ChooseSubframes();
//encode_estimated_frame(frame2);
//uint fs2 = measure_frame_size(frame2, false);
uint fs2 = measure_frame_size ( frame2 , true ) ;
2009-08-21 03:26:12 +00:00
uint fs3 = fs2 ;
if ( eparams . variable_block_size = = 2 | | eparams . variable_block_size = = 4 )
2009-08-20 18:46:37 +00:00
{
2009-08-28 13:00:27 +00:00
frame3 . InitSize ( frame2 . blocksize , true ) ;
2009-08-21 03:26:12 +00:00
frame3 . window_buffer = frame2 . window_buffer ;
2014-08-26 23:48:16 -04:00
frame3 . nSeg = frame2 . nSeg ;
2009-08-21 03:26:12 +00:00
frame3 . current . residual = frame2 . current . residual + 5 * frame2 . blocksize ;
2009-08-20 18:46:37 +00:00
for ( int ch = 0 ; ch < 4 ; ch + + )
2009-08-28 13:00:27 +00:00
frame3 . subframes [ ch ] . Init ( frame2 . subframes [ ch ] . samples + frame2 . blocksize , frame3 . current . residual + ( ch + 1 ) * frame3 . blocksize ,
2009-08-21 03:26:12 +00:00
frame . subframes [ ch ] . obits + frame . subframes [ ch ] . wbits , frame . subframes [ ch ] . wbits ) ;
2009-08-28 13:00:27 +00:00
estimate_frame ( frame3 , true ) ;
fs3 = measure_frame_size ( frame3 , true ) ;
2009-08-20 18:46:37 +00:00
}
2009-08-21 03:26:12 +00:00
if ( fs2 + fs3 > fs )
break ;
2009-08-28 13:00:27 +00:00
FlacFrame tmp = frame ;
2009-08-21 03:26:12 +00:00
frame = frame2 ;
2009-08-28 13:00:27 +00:00
frame2 = tmp ;
2009-08-21 03:26:12 +00:00
fs = fs2 ;
if ( eparams . variable_block_size < = 2 )
break ;
tumbler = 1 - tumbler ;
}
2009-08-17 03:39:53 +00:00
}
2009-08-21 03:26:12 +00:00
2009-08-28 13:00:27 +00:00
frame . ChooseSubframes ( ) ;
encode_estimated_frame ( frame ) ;
2009-08-17 03:39:53 +00:00
}
BitWriter bitwriter = new BitWriter ( frame_buffer , 0 , max_frame_size ) ;
2009-08-28 13:00:27 +00:00
output_frame_header ( frame , bitwriter ) ;
output_subframes ( frame , bitwriter ) ;
2009-08-17 03:39:53 +00:00
output_frame_footer ( bitwriter ) ;
2010-12-07 22:52:34 +00:00
if ( bitwriter . Length > = max_frame_size )
throw new Exception ( "buffer overflow" ) ;
2009-08-17 03:39:53 +00:00
if ( frame_buffer ! = null )
{
if ( eparams . variable_block_size > 0 )
2009-08-21 03:26:12 +00:00
frame_count + = frame . blocksize ;
2009-08-17 03:39:53 +00:00
else
frame_count + + ;
}
2009-08-21 03:26:12 +00:00
size = frame . blocksize ;
2009-08-17 03:39:53 +00:00
return bitwriter . Length ;
}
}
2009-08-21 03:26:12 +00:00
unsafe int output_frame ( )
2009-08-17 03:39:53 +00:00
{
if ( verify ! = null )
{
fixed ( int * s = verifyBuffer , r = samplesBuffer )
for ( int ch = 0 ; ch < channels ; ch + + )
2013-04-04 22:07:15 -04:00
AudioSamples . MemCpy ( s + ch * Flake . MAX_BLOCKSIZE , r + ch * Flake . MAX_BLOCKSIZE , m_blockSize ) ;
2009-08-17 03:39:53 +00:00
}
2009-08-21 03:26:12 +00:00
int fs , bs ;
2013-04-04 22:07:15 -04:00
//if (0 != eparams.variable_block_size && 0 == (m_blockSize & 7) && m_blockSize >= 128)
2009-08-21 03:26:12 +00:00
// fs = encode_frame_vbs();
//else
fs = encode_frame ( out bs ) ;
2009-08-17 03:39:53 +00:00
2009-08-20 04:09:53 +00:00
if ( seek_table ! = null & & _IO . CanSeek )
{
for ( int sp = 0 ; sp < seek_table . Length ; sp + + )
{
if ( seek_table [ sp ] . framesize ! = 0 )
continue ;
2010-02-06 23:17:07 +00:00
if ( seek_table [ sp ] . number > _position + bs )
2009-08-20 04:09:53 +00:00
break ;
2010-02-06 23:17:07 +00:00
if ( seek_table [ sp ] . number > = _position )
2009-08-20 04:09:53 +00:00
{
2010-02-06 23:17:07 +00:00
seek_table [ sp ] . number = _position ;
seek_table [ sp ] . offset = _IO . Position - first_frame_offset ;
seek_table [ sp ] . framesize = bs ;
2009-08-20 04:09:53 +00:00
}
}
}
2009-08-21 03:26:12 +00:00
_position + = bs ;
2009-08-17 03:39:53 +00:00
_IO . Write ( frame_buffer , 0 , fs ) ;
_totalSize + = fs ;
if ( verify ! = null )
2014-09-19 22:40:47 -04:00
try
2014-09-19 01:17:23 -04:00
{
2014-09-19 22:40:47 -04:00
int decoded = verify . DecodeFrame ( frame_buffer , 0 , fs ) ;
if ( decoded ! = fs | | verify . Remaining ! = bs )
throw new Exception ( Properties . Resources . ExceptionValidationFailed ) ;
fixed ( int * s = verifyBuffer , r = verify . Samples )
{
for ( int ch = 0 ; ch < channels ; ch + + )
if ( AudioSamples . MemCmp ( s + ch * Flake . MAX_BLOCKSIZE , r + ch * Flake . MAX_BLOCKSIZE , bs ) )
throw new Exception ( Properties . Resources . ExceptionValidationFailed ) ;
}
}
catch ( Exception ex )
{
//if (channels == 2)
//{
// var sw = new WAVWriter(string.Format("verify_{0}.wav", this.frame_count), new WAVWriterSettings(this.Settings.PCM));
// sw.FinalSampleCount = this.frame.blocksize;
// var ab = new AudioBuffer(this.Settings.PCM, this.frame.blocksize);
// ab.Prepare(this.frame.blocksize);
// fixed (int* abs = ab.Samples, s = verifyBuffer)
// AudioSamples.Interlace(abs, s, s + Flake.MAX_BLOCKSIZE, this.frame.blocksize);
// sw.Write(ab);
// sw.Close();
//} else
throw ex ;
2014-09-19 01:17:23 -04:00
}
2009-08-21 03:26:12 +00:00
2013-04-04 22:07:15 -04:00
if ( bs < m_blockSize )
2009-08-21 03:26:12 +00:00
{
2010-04-16 04:30:51 +00:00
for ( int ch = 0 ; ch < ( channels = = 2 ? 4 : channels ) ; ch + + )
2013-04-04 22:07:15 -04:00
Buffer . BlockCopy ( samplesBuffer , ( bs + ch * Flake . MAX_BLOCKSIZE ) * sizeof ( int ) , samplesBuffer , ch * Flake . MAX_BLOCKSIZE * sizeof ( int ) , ( m_blockSize - bs ) * sizeof ( int ) ) ;
2010-04-16 04:30:51 +00:00
//fixed (int* s = samplesBuffer)
// for (int ch = 0; ch < channels; ch++)
2013-04-04 22:07:15 -04:00
// AudioSamples.MemCpy(s + ch * Flake.MAX_BLOCKSIZE, s + bs + ch * Flake.MAX_BLOCKSIZE, m_blockSize - bs);
2009-08-21 03:26:12 +00:00
}
samplesInBuffer - = bs ;
return bs ;
2009-08-17 03:39:53 +00:00
}
2010-02-06 23:17:07 +00:00
public void Write ( AudioBuffer buff )
2009-08-17 03:39:53 +00:00
{
if ( ! inited )
{
if ( _IO = = null )
2014-12-08 22:18:34 -05:00
_IO = new FileStream ( _path , FileMode . Create , FileAccess . Write , FileShare . Read , 0x10000 ) ;
2013-03-11 23:02:25 -04:00
inited = true ;
int header_size = flake_encode_init ( ) ;
2009-08-17 03:39:53 +00:00
_IO . Write ( header , 0 , header_size ) ;
2009-08-20 04:09:53 +00:00
if ( _IO . CanSeek )
first_frame_offset = _IO . Position ;
2009-08-17 03:39:53 +00:00
}
2010-02-06 23:17:07 +00:00
buff . Prepare ( this ) ;
2009-08-17 03:39:53 +00:00
2010-02-06 23:17:07 +00:00
int pos = 0 ;
while ( pos < buff . Length )
{
2013-04-04 22:07:15 -04:00
int block = Math . Min ( buff . Length - pos , m_blockSize - samplesInBuffer ) ;
2009-08-17 03:39:53 +00:00
2010-02-06 23:17:07 +00:00
copy_samples ( buff . Samples , pos , block ) ;
2009-08-17 03:39:53 +00:00
pos + = block ;
2009-08-21 03:26:12 +00:00
2013-04-04 22:07:15 -04:00
while ( samplesInBuffer > = m_blockSize )
2009-08-21 03:26:12 +00:00
output_frame ( ) ;
2009-08-17 03:39:53 +00:00
}
2010-02-06 23:17:07 +00:00
if ( md5 ! = null )
md5 . TransformBlock ( buff . Bytes , 0 , buff . ByteLength , null , 0 ) ;
2009-08-17 03:39:53 +00:00
}
public string Path { get { return _path ; } }
2013-04-28 14:33:48 -04:00
public static string Vendor
{
get
{
var version = typeof ( FlakeWriter ) . Assembly . GetName ( ) . Version ;
return vendor_string ? ? "CUETools " + version . Major + "." + version . Minor + "." + version . Build ;
}
set
{
vendor_string = value ;
}
}
static string vendor_string = null ;
2009-08-17 03:39:53 +00:00
int select_blocksize ( int samplerate , int time_ms )
{
2009-08-17 20:16:56 +00:00
int blocksize = Flake . flac_blocksizes [ 1 ] ;
2009-08-17 03:39:53 +00:00
int target = ( samplerate * time_ms ) / 1000 ;
2009-08-22 09:39:32 +00:00
if ( eparams . variable_block_size > 0 )
{
blocksize = 1024 ;
while ( target > = blocksize )
blocksize < < = 1 ;
return blocksize > > 1 ;
}
2013-06-18 20:45:53 -04:00
for ( int i = 8 ; i < Flake . flac_blocksizes . Length - 1 ; i + + )
2009-08-17 20:16:56 +00:00
if ( target > = Flake . flac_blocksizes [ i ] & & Flake . flac_blocksizes [ i ] > blocksize )
2009-08-17 03:39:53 +00:00
{
2009-08-17 20:16:56 +00:00
blocksize = Flake . flac_blocksizes [ i ] ;
2009-08-17 03:39:53 +00:00
}
return blocksize ;
}
void write_streaminfo ( byte [ ] header , int pos , int last )
{
Array . Clear ( header , pos , 38 ) ;
BitWriter bitwriter = new BitWriter ( header , pos , 38 ) ;
// metadata header
bitwriter . writebits ( 1 , last ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 7 , ( int ) MetadataType . StreamInfo ) ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 24 , 34 ) ;
if ( eparams . variable_block_size > 0 )
bitwriter . writebits ( 16 , 0 ) ;
else
2013-04-04 22:07:15 -04:00
bitwriter . writebits ( 16 , m_blockSize ) ;
2009-08-17 03:39:53 +00:00
2013-04-04 22:07:15 -04:00
bitwriter . writebits ( 16 , m_blockSize ) ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 24 , 0 ) ;
bitwriter . writebits ( 24 , max_frame_size ) ;
2013-04-07 20:41:58 -04:00
bitwriter . writebits ( 20 , Settings . PCM . SampleRate ) ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 3 , channels - 1 ) ;
2013-04-07 20:41:58 -04:00
bitwriter . writebits ( 5 , Settings . PCM . BitsPerSample - 1 ) ;
2009-08-17 03:39:53 +00:00
// total samples
if ( sample_count > 0 )
{
bitwriter . writebits ( 4 , 0 ) ;
bitwriter . writebits ( 32 , sample_count ) ;
}
else
{
bitwriter . writebits ( 4 , 0 ) ;
bitwriter . writebits ( 32 , 0 ) ;
}
bitwriter . flush ( ) ;
}
/ * *
* Write vorbis comment metadata block to byte array .
* Just writes the vendor string for now .
* /
2014-12-08 22:18:34 -05:00
int write_vorbis_comment ( byte [ ] comment , int pos , int len , int last )
2009-08-17 03:39:53 +00:00
{
2014-12-08 22:18:34 -05:00
BitWriter bitwriter = new BitWriter ( comment , pos , len ) ;
Encoding enc = new UTF8Encoding ( ) ;
byte [ ] str = enc . GetBytes ( Vendor ) ;
2009-08-17 03:39:53 +00:00
// metadata header
bitwriter . writebits ( 1 , last ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 7 , ( int ) MetadataType . VorbisComment ) ;
2014-12-08 22:18:34 -05:00
int tagsLen = 0 ;
if ( m_settings . Tags ! = null )
foreach ( var t in m_settings . Tags )
tagsLen + = 4 + enc . GetByteCount ( t ) ;
bitwriter . writebits ( 24 , 8 + str . Length + tagsLen ) ;
for ( int i = 0 ; i < 4 ; i + + )
bitwriter . writebits ( 8 , ( str . Length > > ( i * 8 ) ) & 0xff ) ;
bitwriter . write ( str ) ;
int nTags = m_settings . Tags ! = null ? m_settings . Tags . Length : 0 ;
for ( int i = 0 ; i < 4 ; i + + )
bitwriter . writebits ( 8 , ( nTags > > ( i * 8 ) ) & 0xff ) ;
if ( m_settings . Tags ! = null )
foreach ( var tag in m_settings . Tags )
{
str = enc . GetBytes ( tag ) ;
for ( int i = 0 ; i < 4 ; i + + )
bitwriter . writebits ( 8 , ( str . Length > > ( i * 8 ) ) & 0xff ) ;
bitwriter . write ( str ) ;
}
2009-08-17 03:39:53 +00:00
bitwriter . flush ( ) ;
2014-12-08 22:18:34 -05:00
return bitwriter . Length ;
2009-08-17 03:39:53 +00:00
}
2009-08-20 04:09:53 +00:00
int write_seekpoints ( byte [ ] header , int pos , int last )
{
seek_table_offset = pos + 4 ;
BitWriter bitwriter = new BitWriter ( header , pos , 4 + 18 * seek_table . Length ) ;
// metadata header
bitwriter . writebits ( 1 , last ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 7 , ( int ) MetadataType . Seektable ) ;
2009-08-20 04:09:53 +00:00
bitwriter . writebits ( 24 , 18 * seek_table . Length ) ;
for ( int i = 0 ; i < seek_table . Length ; i + + )
{
2013-03-25 22:33:21 -04:00
bitwriter . writebits ( Flake . FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN , ( ulong ) seek_table [ i ] . number ) ;
bitwriter . writebits ( Flake . FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN , ( ulong ) seek_table [ i ] . offset ) ;
2009-08-20 04:09:53 +00:00
bitwriter . writebits ( Flake . FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN , seek_table [ i ] . framesize ) ;
}
bitwriter . flush ( ) ;
return 4 + 18 * seek_table . Length ;
}
2009-08-17 03:39:53 +00:00
/ * *
* Write padding metadata block to byte array .
* /
int
write_padding ( byte [ ] padding , int pos , int last , int padlen )
{
BitWriter bitwriter = new BitWriter ( padding , pos , 4 ) ;
// metadata header
bitwriter . writebits ( 1 , last ) ;
2009-08-28 13:00:27 +00:00
bitwriter . writebits ( 7 , ( int ) MetadataType . Padding ) ;
2009-08-17 03:39:53 +00:00
bitwriter . writebits ( 24 , padlen ) ;
2013-03-28 22:17:03 -04:00
bitwriter . flush ( ) ;
return padlen + 4 ;
2009-08-17 03:39:53 +00:00
}
int write_headers ( )
{
int header_size = 0 ;
int last = 0 ;
// stream marker
header [ 0 ] = 0x66 ;
header [ 1 ] = 0x4C ;
header [ 2 ] = 0x61 ;
header [ 3 ] = 0x43 ;
header_size + = 4 ;
// streaminfo
write_streaminfo ( header , header_size , last ) ;
header_size + = 38 ;
2009-08-20 04:09:53 +00:00
// seek table
if ( _IO . CanSeek & & seek_table ! = null )
header_size + = write_seekpoints ( header , header_size , last ) ;
2014-12-08 22:18:34 -05:00
// vorbis comments
if ( m_settings . Padding = = 0 ) last = 1 ;
header_size + = write_vorbis_comment ( header , header_size , header . Length - header_size , last ) ;
2009-08-17 03:39:53 +00:00
// padding
2013-04-04 22:07:15 -04:00
if ( m_settings . Padding > 0 )
2009-08-17 03:39:53 +00:00
{
last = 1 ;
2013-04-04 22:07:15 -04:00
header_size + = write_padding ( header , header_size , last , m_settings . Padding ) ;
2009-08-17 03:39:53 +00:00
}
return header_size ;
}
int flake_encode_init ( )
{
int i , header_len ;
//if(flake_validate_params(s) < 0)
ch_code = channels - 1 ;
// find samplerate in table
2013-03-11 23:02:25 -04:00
for ( i = 1 ; i < 12 ; i + + )
2009-08-17 03:39:53 +00:00
{
2013-04-07 20:41:58 -04:00
if ( Settings . PCM . SampleRate = = Flake . flac_samplerates [ i ] )
2009-08-17 03:39:53 +00:00
{
sr_code0 = i ;
break ;
}
}
// if not in table, samplerate is non-standard
if ( i = = 12 )
throw new Exception ( "non-standard samplerate" ) ;
for ( i = 1 ; i < 8 ; i + + )
{
2013-04-07 20:41:58 -04:00
if ( Settings . PCM . BitsPerSample = = Flake . flac_bitdepths [ i ] )
2009-08-17 03:39:53 +00:00
{
bps_code = i ;
break ;
}
}
if ( i = = 8 )
throw new Exception ( "non-standard bps" ) ;
2013-04-04 22:07:15 -04:00
m_blockSize = m_settings . BlockSize ! = 0 ? m_settings . BlockSize :
2013-04-07 20:41:58 -04:00
select_blocksize ( Settings . PCM . SampleRate , eparams . block_time_ms ) ;
2009-08-17 03:39:53 +00:00
// set maximum encoded frame size (if larger, re-encodes in verbatim mode)
if ( channels = = 2 )
2013-04-07 20:41:58 -04:00
max_frame_size = 16 + ( ( m_blockSize * ( Settings . PCM . BitsPerSample + Settings . PCM . BitsPerSample + 1 ) + 7 ) > > 3 ) ;
2009-08-17 03:39:53 +00:00
else
2013-04-07 20:41:58 -04:00
max_frame_size = 16 + ( ( m_blockSize * channels * Settings . PCM . BitsPerSample + 7 ) > > 3 ) ;
2009-08-17 03:39:53 +00:00
2010-02-06 23:17:07 +00:00
if ( _IO . CanSeek & & eparams . do_seektable & & sample_count > 0 )
2009-08-20 04:09:53 +00:00
{
2013-04-07 20:41:58 -04:00
int seek_points_distance = Settings . PCM . SampleRate * 10 ;
2009-08-20 04:09:53 +00:00
int num_seek_points = 1 + sample_count / seek_points_distance ; // 1 seek point per 10 seconds
if ( sample_count % seek_points_distance = = 0 )
num_seek_points - - ;
seek_table = new SeekPoint [ num_seek_points ] ;
for ( int sp = 0 ; sp < num_seek_points ; sp + + )
{
seek_table [ sp ] . framesize = 0 ;
seek_table [ sp ] . offset = 0 ;
2010-02-06 23:17:07 +00:00
seek_table [ sp ] . number = sp * seek_points_distance ;
2009-08-20 04:09:53 +00:00
}
}
2009-08-17 03:39:53 +00:00
// output header bytes
2014-12-08 22:18:34 -05:00
int tagsLen = 0 ;
Encoding enc = new UTF8Encoding ( ) ;
if ( m_settings . Tags ! = null )
foreach ( var t in m_settings . Tags )
tagsLen + = 4 + enc . GetByteCount ( t ) ;
header = new byte [ m_settings . Padding + 1024 + ( seek_table = = null ? 0 : seek_table . Length * 18 ) + tagsLen ] ;
2009-08-17 03:39:53 +00:00
header_len = write_headers ( ) ;
// initialize CRC & MD5
2013-04-04 22:07:15 -04:00
if ( _IO . CanSeek & & m_settings . DoMD5 )
2009-08-20 04:09:53 +00:00
md5 = new MD5CryptoServiceProvider ( ) ;
2013-04-04 22:07:15 -04:00
if ( m_settings . DoVerify )
2009-08-20 04:09:53 +00:00
{
2013-04-07 20:41:58 -04:00
verify = new FlakeReader ( Settings . PCM ) ;
2009-08-20 04:09:53 +00:00
verifyBuffer = new int [ Flake . MAX_BLOCKSIZE * channels ] ;
}
2009-08-17 03:39:53 +00:00
frame_buffer = new byte [ max_frame_size ] ;
return header_len ;
}
}
struct FlakeEncodeParams
{
// prediction order selection method
// set by user prior to calling flake_encode_init
// if set to less than 0, it is chosen based on compression.
// valid values are 0 to 5
// 0 = use maximum order only
// 1 = use estimation
// 2 = 2-level
// 3 = 4-level
// 4 = 8-level
// 5 = full search
// 6 = log search
public OrderMethod order_method ;
// block time in milliseconds
// set by the user prior to calling flake_encode_init
// used to calculate block_size based on sample rate
// can also be changed by user before encoding a frame
public int block_time_ms ;
// whether to use variable block sizes
// set by user prior to calling flake_encode_init
// 0 = fixed block size
// 1 = variable block size
public int variable_block_size ;
2009-08-20 04:09:53 +00:00
public bool do_seektable ;
2012-07-12 00:11:39 +00:00
public int development_mode ;
2014-12-08 22:18:34 -05:00
public int flake_set_defaults ( FlakeWriterSettings settings )
{
order_method = OrderMethod . Akaike ;
block_time_ms = 105 ;
2013-06-18 20:45:53 -04:00
variable_block_size = 0 ;
2014-12-08 22:18:34 -05:00
do_seektable = true ;
2012-07-12 00:11:39 +00:00
development_mode = - 1 ;
2009-08-17 03:39:53 +00:00
2014-12-08 22:18:34 -05:00
if ( settings . EncoderModeIndex = = 11 )
variable_block_size = 4 ;
2009-08-17 03:39:53 +00:00
2014-12-08 22:18:34 -05:00
return 0 ;
}
2009-08-17 03:39:53 +00:00
}
}