aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/include/ancient/src/RangeDecoder.cpp
blob: 061c4edc0196f5b6a4b214590418dbc62d1ef818 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* Copyright (C) Teemu Suutari */

#include "RangeDecoder.hpp"


namespace ancient::internal
{

RangeDecoder::BitReader::BitReader()
{
	// nothing needed
}

RangeDecoder::BitReader::~BitReader()
{
	// nothing needed
}

RangeDecoder::RangeDecoder(BitReader &bitReader,uint16_t initialValue) :
		_bitReader(bitReader),
		_stream(initialValue)
{
	// nothing needed
}

RangeDecoder::~RangeDecoder()
{
	// nothing needed
}

uint16_t RangeDecoder::decode(uint16_t length)
{
	return ((uint32_t(_stream-_low)+1)*length-1)/(uint32_t(_high-_low)+1);
}

void RangeDecoder::scale(uint16_t newLow,uint16_t newHigh,uint16_t newRange)
{
	uint32_t range=uint32_t(_high-_low)+1;
	_high=(range*newHigh)/newRange+_low-1;
	_low=(range*newLow)/newRange+_low;

	auto doubleContext=[&](uint16_t decr)
	{
		_low-=decr;
		_high-=decr;
		_stream-=decr;
		_low<<=1;
		_high=(_high<<1)|1U;
		_stream=(_stream<<1)|_bitReader.readBit();
	};

	for (;;)
	{
		if (_high<0x8000U)
		{
			doubleContext(0U);
		} else if (_low>=0x8000U) {
			doubleContext(0x8000U);
		} else if (_low>=0x4000U && _high<0xc000U) {
			doubleContext(0x4000U);
		} else break;
	}
}

}