Example #1
0
		public ALACWriter(string path, Stream IO, AudioPCMConfig pcm)
		{
			_pcm = pcm;

			if (_pcm.BitsPerSample != 16)
				throw new Exception("Bits per sample must be 16.");
			if (_pcm.ChannelCount != 2)
				throw new Exception("ChannelCount must be 2.");

			_path = path;
			_IO = IO;
			_pathGiven = _IO == null;
			if (_IO != null && !_IO.CanSeek)
				throw new NotSupportedException("stream doesn't support seeking");

			samplesBuffer = new int[Alac.MAX_BLOCKSIZE * (_pcm.ChannelCount == 2 ? 5 : _pcm.ChannelCount)];
			residualBuffer = new int[Alac.MAX_BLOCKSIZE * (_pcm.ChannelCount == 2 ? 6 : _pcm.ChannelCount + 1)];
			windowBuffer = new float[Alac.MAX_BLOCKSIZE * 2 * Alac.MAX_LPC_WINDOWS];

			eparams.set_defaults(_compressionLevel);
			eparams.padding_size = 4096;

			crc8 = new Crc8();
			crc16 = new Crc16();
			frame = new ALACFrame(_pcm.ChannelCount == 2 ? 5 : _pcm.ChannelCount);
			chunk_pos = new List<int>();
		}
Example #2
0
		unsafe void encode_residual_pass2(ALACFrame frame, int ch)
		{
			encode_residual(frame, ch, 2, estimate_best_window(frame, ch));
		}
Example #3
0
		unsafe int estimate_best_window(ALACFrame frame, int ch)
		{
			if (_windowcount == 1)
				return 0;
			switch (eparams.window_method)
			{
				case WindowMethod.Estimate:
					{
						int best_window = -1;
						double best_error = 0;
						int order = 2;
						for (int i = 0; i < _windowcount; i++)
						{
							frame.subframes[ch].lpc_ctx[i].GetReflection(order, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer + i * Alac.MAX_BLOCKSIZE * 2);
							double err = frame.subframes[ch].lpc_ctx[i].prediction_error[order - 1] / frame.subframes[ch].lpc_ctx[i].autocorr_values[0];
							if (best_window == -1 || best_error > err)
							{
								best_window = i;
								best_error = err;
							}
						}
						return best_window;
					}
				case WindowMethod.Evaluate:
					encode_residual_pass1(frame, ch, -1);
					return frame.subframes[ch].best.window;
				case WindowMethod.Search:
					return -1;
			}
			return -1;
		}
Example #4
0
		unsafe void output_frame_header(ALACFrame frame, BitWriter bitwriter)
		{
			bitwriter.writebits(3, _pcm.ChannelCount - 1);
			bitwriter.writebits(16, 0);
			bitwriter.writebits(1, frame.blocksize != eparams.block_size ? 1 : 0); // sample count is in the header
			bitwriter.writebits(2, 0); // wasted bytes
			bitwriter.writebits(1, frame.type == FrameType.Verbatim ? 1 : 0); // is verbatim
			if (frame.blocksize != eparams.block_size)
				bitwriter.writebits(32, frame.blocksize);
			if (frame.type != FrameType.Verbatim)
			{
				bitwriter.writebits(8, frame.interlacing_shift);
				bitwriter.writebits(8, frame.interlacing_leftweight);
				for (int ch = 0; ch < _pcm.ChannelCount; ch++)
				{
					bitwriter.writebits(4, 0); // prediction type
					bitwriter.writebits(4, frame.subframes[ch].best.shift);
					bitwriter.writebits(3, frame.subframes[ch].best.ricemodifier);
					bitwriter.writebits(5, frame.subframes[ch].best.order);
					if (frame.subframes[ch].best.order != 31)
						for (int c = 0; c < frame.subframes[ch].best.order; c++)
							bitwriter.writebits_signed(16, frame.subframes[ch].best.coefs[c]);
				}
			}
		}
Example #5
0
		unsafe void encode_residual_pass1(ALACFrame frame, int ch, int best_window)
		{
			int max_prediction_order = eparams.max_prediction_order;
			int estimation_depth = eparams.estimation_depth;
			int min_modifier = eparams.min_modifier;
			int adaptive_passes = eparams.adaptive_passes;
			eparams.max_prediction_order = Math.Min(8,eparams.max_prediction_order);
			eparams.estimation_depth = 1;
			eparams.min_modifier = eparams.max_modifier;
			eparams.adaptive_passes = 0;
			encode_residual(frame, ch, 1, best_window);
			eparams.max_prediction_order = max_prediction_order;
			eparams.estimation_depth = estimation_depth;
			eparams.min_modifier = min_modifier;
			eparams.adaptive_passes = adaptive_passes;
		}
Example #6
0
		unsafe void encode_residual(ALACFrame frame, int ch, int pass, int best_window)
		{
			int* smp = frame.subframes[ch].samples;
			int i, n = frame.blocksize;
			int bps = _pcm.BitsPerSample + _pcm.ChannelCount - 1;

			// FIXED
			//if (0 == (2 & frame.subframes[ch].done_fixed) && (pass != 1 || n < eparams.max_prediction_order))
			//{
			//    frame.subframes[ch].done_fixed |= 2;
			//    frame.current.order = 31;
			//    frame.current.window = -1;
			//    alac_encode_residual_31(frame.current.residual, frame.subframes[ch].samples, frame.blocksize);
			//    frame.current.size = (uint)(alac_entropy_coder(frame.current.residual, frame.blocksize, bps, out frame.current.ricemodifier) + 16);
			//    frame.ChooseBestSubframe(ch);
			//}
			//if (0 == (1 & frame.subframes[ch].done_fixed) && (pass != 1 || n < eparams.max_prediction_order))
			//{
			//    frame.subframes[ch].done_fixed |= 1;
			//    frame.current.order = 0;
			//    frame.current.window = -1;
			//    alac_encode_residual_0(frame.current.residual, frame.subframes[ch].samples, frame.blocksize);
			//    frame.current.size = (uint)(alac_entropy_coder(frame.current.residual, frame.blocksize, bps, out frame.current.ricemodifier) + 16);
			//    frame.ChooseBestSubframe(ch);
			//}

			// LPC
			if (n < eparams.max_prediction_order)
				return;

			float* lpcs = stackalloc float[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER];
			int min_order = eparams.min_prediction_order;
			int max_order = eparams.max_prediction_order;

			for (int iWindow = 0; iWindow < _windowcount; iWindow++)
			{
				if (best_window != -1 && iWindow != best_window)
					continue;

				LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[iWindow];

				lpc_ctx.GetReflection(max_order, smp, n, frame.window_buffer + iWindow * Alac.MAX_BLOCKSIZE * 2);
				lpc_ctx.ComputeLPC(lpcs);
				lpc_ctx.SortOrdersAkaike(frame.blocksize, eparams.estimation_depth, max_order, 5.0, 1.0/18);
				for (i = 0; i < eparams.estimation_depth && i < max_order; i++)
					encode_residual_lpc_sub(frame, lpcs, iWindow, lpc_ctx.best_orders[i], ch);
			}
		}
Example #7
0
		unsafe void encode_residual_lpc_sub(ALACFrame frame, float* lpcs, int iWindow, int order, int ch)
		{
			// check if we already calculated with this order, window and precision
			if ((frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[eparams.adaptive_passes] & (1U << (order - 1))) == 0)
			{
				frame.subframes[ch].lpc_ctx[iWindow].done_lpcs[eparams.adaptive_passes] |= (1U << (order - 1));

				uint cbits = 15U;

				frame.current.order = order;
				frame.current.window = iWindow;

				int bps = _pcm.BitsPerSample + _pcm.ChannelCount - 1;

				int* coefs = stackalloc int[lpc.MAX_LPC_ORDER];

				//if (frame.subframes[ch].best.order == order && frame.subframes[ch].best.window == iWindow)
				//{
				//    frame.current.shift = frame.subframes[ch].best.shift;
				//    for (int i = 0; i < frame.current.order; i++)
				//        frame.current.coefs[i] = frame.subframes[ch].best.coefs_adapted[i];
				//}
				//else
				{
					lpc.quantize_lpc_coefs(lpcs + (frame.current.order - 1) * lpc.MAX_LPC_ORDER,
						frame.current.order, cbits, coefs, out frame.current.shift, 15, 1);

					if (frame.current.shift < 0 || frame.current.shift > 15)
						throw new Exception("negative shift");

					for (int i = 0; i < frame.current.order; i++)
						frame.current.coefs[i] = coefs[i];
				}

				for (int i = 0; i < frame.current.order; i++)
					coefs[i] = frame.current.coefs[frame.current.order - 1 - i];
				for (int i = frame.current.order; i < lpc.MAX_LPC_ORDER;  i++)
					coefs[i] = 0;

				alac_encode_residual(frame.current.residual, frame.subframes[ch].samples, frame.blocksize,
					frame.current.order, coefs, frame.current.shift, bps);

				for (int i = 0; i < frame.current.order; i++)
					frame.current.coefs_adapted[i] = coefs[frame.current.order - 1 - i];

				for (int adaptive_pass = 0; adaptive_pass < eparams.adaptive_passes; adaptive_pass++)
				{
					for (int i = 0; i < frame.current.order; i++)
						frame.current.coefs[i] = frame.current.coefs_adapted[i];

					alac_encode_residual(frame.current.residual, frame.subframes[ch].samples, frame.blocksize,
						frame.current.order, coefs, frame.current.shift, bps);

					for (int i = 0; i < frame.current.order; i++)
						frame.current.coefs_adapted[i] = coefs[frame.current.order - 1 - i];
				}

				frame.current.size = (uint)(alac_entropy_estimate(frame.current.residual, frame.blocksize, bps, eparams.max_modifier) + 16 + 16 * order);
				
				frame.ChooseBestSubframe(ch);
			}
		}
Example #8
0
		unsafe void encode_estimated_frame(ALACFrame frame)
		{
			switch (eparams.stereo_method)
			{
				case StereoMethod.Estimate:
					for (int ch = 0; ch < _pcm.ChannelCount; ch++)
					{
						frame.subframes[ch].best.size = AudioSamples.UINT32_MAX;
						encode_residual_pass2(frame, ch);
					}
					break;
				case StereoMethod.Evaluate:
					for (int ch = 0; ch < _pcm.ChannelCount; ch++)
						encode_residual_pass2(frame, ch);
					break;
				case StereoMethod.Search:
					break;
			}
		}
Example #9
0
		unsafe uint measure_frame_size(ALACFrame frame, bool do_midside)
		{
			// crude estimation of header/footer size
			uint total = 16 + 3;

			if (do_midside)
			{
				uint bitsBest = frame.subframes[0].best.size + frame.subframes[1].best.size;
				frame.interlacing_leftweight = 0;
				frame.interlacing_shift = 0;

				if (bitsBest > frame.subframes[3].best.size + frame.subframes[0].best.size) // leftside
				{
					bitsBest = frame.subframes[3].best.size + frame.subframes[0].best.size;
					frame.interlacing_leftweight = 1;
					frame.interlacing_shift = 0;
				}
				if (bitsBest > frame.subframes[3].best.size + frame.subframes[2].best.size) // midside
				{
					bitsBest = frame.subframes[3].best.size + frame.subframes[2].best.size;
					frame.interlacing_leftweight = 1;
					frame.interlacing_shift = 1;
				}
				if (bitsBest > frame.subframes[3].best.size + frame.subframes[4].best.size) // rightside
				{
					bitsBest = frame.subframes[3].best.size + frame.subframes[4].best.size;
					frame.interlacing_leftweight = 1;
					frame.interlacing_shift = 31;
				}

				return total + bitsBest;
			}

			for (int ch = 0; ch < _pcm.ChannelCount; ch++)
				total += frame.subframes[ch].best.size;

			return total;
		}
Example #10
0
		unsafe void estimate_frame(ALACFrame frame, bool do_midside)
		{
			int subframes = do_midside ? 5 : _pcm.ChannelCount;

			switch (eparams.stereo_method)
			{
				case StereoMethod.Estimate:
					for (int ch = 0; ch < subframes; ch++)
					{
						LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0];
						int stereo_order = Math.Min(8, eparams.max_prediction_order);
						double alpha = 1.5; // 4.5 + eparams.max_prediction_order / 10.0;
						lpc_ctx.GetReflection(stereo_order, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer);
						lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, stereo_order, alpha, 0);
						frame.subframes[ch].best.size = (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], alpha, 0));
					}
					break;
				case StereoMethod.Evaluate:
					for (int ch = 0; ch < subframes; ch++)
						encode_residual_pass1(frame, ch, 0);
					break;
				case StereoMethod.Search:
					for (int ch = 0; ch < subframes; ch++)
						encode_residual_pass2(frame, ch);
					break;
			}
		}