Skip to content

Commit

Permalink
Quick and dirty port to C
Browse files Browse the repository at this point in the history
Very direct port from C# version.
Same files, function/variable names.
Band extension isn't handled.
Tables are pre-generated instead of being created at runtime.
Extensive testing has not been done.
  • Loading branch information
Thealexbarney committed Jan 3, 2018
1 parent 109e63b commit 46d4203
Show file tree
Hide file tree
Showing 28 changed files with 5,556 additions and 0 deletions.
119 changes: 119 additions & 0 deletions C/bit_allocation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include "bit_allocation.h"
#include "tables.h"
#include "utility.h"
#include <string.h>

at9_status CreateGradient(block* block)
{
int valueCount = block->GradientEndValue - block->GradientStartValue;
int unitCount = block->GradientEndUnit - block->GradientStartUnit;

for (int i = 0; i < block->GradientEndUnit; i++)
{
block->Gradient[i] = block->GradientStartValue;
}

for (int i = block->GradientEndUnit; i <= block->QuantizationUnitCount; i++)
{
block->Gradient[i] = block->GradientEndValue;
}
if (unitCount <= 0) return ERR_SUCCESS;
if (valueCount == 0) return ERR_SUCCESS;

const unsigned char* curve = GradientCurves[unitCount - 1];
if (valueCount <= 0)
{
double scale = (-valueCount - 1) / 31.0;
int baseVal = block->GradientStartValue - 1;
for (int i = block->GradientStartUnit; i < block->GradientEndUnit; i++)
{
block->Gradient[i] = baseVal - (int)(curve[i - block->GradientStartUnit] * scale);
}
}
else
{
double scale = (valueCount - 1) / 31.0;
int baseVal = block->GradientStartValue + 1;
for (int i = block->GradientStartUnit; i < block->GradientEndUnit; i++)
{
block->Gradient[i] = baseVal + (int)(curve[i - block->GradientStartUnit] * scale);
}
}

return ERR_SUCCESS;
}

void CalculateMask(channel* channel)
{
memset(channel->PrecisionMask, 0, sizeof(channel->PrecisionMask));
for (int i = 1; i < channel->Block->QuantizationUnitCount; i++)
{
const int delta = channel->ScaleFactors[i] - channel->ScaleFactors[i - 1];
if (delta > 1)
{
channel->PrecisionMask[i] += min(delta - 1, 5);
}
else if (delta < -1)
{
channel->PrecisionMask[i - 1] += min(delta * -1 - 1, 5);
}
}
}

void CalculatePrecisions(channel* channel)
{
block* block = channel->Block;

if (block->GradientMode != 0)
{
for (int i = 0; i < block->QuantizationUnitCount; i++)
{
channel->Precisions[i] = channel->ScaleFactors[i] + channel->PrecisionMask[i] - block->Gradient[i];
if (channel->Precisions[i] > 0)
{
switch (block->GradientMode)
{
case 1:
channel->Precisions[i] /= 2;
break;
case 2:
channel->Precisions[i] = 3 * channel->Precisions[i] / 8;
break;
case 3:
channel->Precisions[i] /= 4;
break;
}
}
}
}
else
{
for (int i = 0; i < block->QuantizationUnitCount; i++)
{
channel->Precisions[i] = channel->ScaleFactors[i] - block->Gradient[i];
}
}

for (int i = 0; i < block->QuantizationUnitCount; i++)
{
if (channel->Precisions[i] < 1)
{
channel->Precisions[i] = 1;
}
}

for (int i = 0; i < block->GradientBoundary; i++)
{
channel->Precisions[i]++;
}

for (int i = 0; i < block->QuantizationUnitCount; i++)
{
channel->PrecisionsFine[i] = 0;
if (channel->Precisions[i] > 15)
{
channel->PrecisionsFine[i] = channel->Precisions[i] - 15;
channel->Precisions[i] = 15;
}
}
}
6 changes: 6 additions & 0 deletions C/bit_allocation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once
#include "unpack.h"

at9_status CreateGradient(block* block);
void CalculateMask(channel* channel);
void CalculatePrecisions(channel* channel);
110 changes: 110 additions & 0 deletions C/bit_reader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "bit_reader.h"
#include "utility.h"

static int peek_int_fallback(bit_reader_cxt* br, int bit_count);

void init_bit_reader_cxt(bit_reader_cxt* br, const void * buffer)
{
br->buffer = buffer;
br->position = 0;
}

int read_int(bit_reader_cxt* br, const int bits)
{
const int value = peek_int(br, bits);
br->position += bits;
return value;
}

int read_signed_int(bit_reader_cxt* br, const int bits)
{
const int value = peek_int(br, bits);
br->position += bits;
return SignExtend32(value, bits);
}

int read_offset_binary(bit_reader_cxt* br, const int bits)
{
const int offset = 1 << (bits - 1);
const int value = peek_int(br, bits) - offset;
br->position += bits;
return value;
}

int peek_int(bit_reader_cxt* br, const int bits)
{
const int byte_index = br->position / 8;
const int bit_index = br->position % 8;
const unsigned char* buffer = br->buffer;

if (bits <= 9)
{
int value = buffer[byte_index] << 8 | buffer[byte_index + 1];
value &= 0xFFFF >> bit_index;
value >>= 16 - bits - bit_index;
return value;
}

if (bits <= 17)
{
int value = buffer[byte_index] << 16 | buffer[byte_index + 1] << 8 | buffer[byte_index + 2];
value &= 0xFFFFFF >> bit_index;
value >>= 24 - bits - bit_index;
return value;
}

if (bits <= 25)
{
int value = buffer[byte_index] << 24
| buffer[byte_index + 1] << 16
| buffer[byte_index + 2] << 8
| buffer[byte_index + 3];

value &= (int)(0xFFFFFFFF >> bit_index);
value >>= 32 - bits - bit_index;
return value;
}
return peek_int_fallback(br, bits);
}

void align_position(bit_reader_cxt* br, const unsigned int multiple)
{
const int position = br->position;
if (position % multiple == 0)
{
return;
}

br->position = position + multiple - position % multiple;
}

static int peek_int_fallback(bit_reader_cxt* br, int bit_count)
{
int value = 0;
int byte_index = br->position / 8;
int bit_index = br->position % 8;
const unsigned char* buffer = br->buffer;

while (bit_count > 0)
{
if (bit_index >= 8)
{
bit_index = 0;
byte_index++;
}

int bits_to_read = bit_count;
if (bits_to_read > 8 - bit_index)
{
bits_to_read = 8 - bit_index;
}

const int mask = 0xFF >> bit_index;
const int current_byte = (mask & buffer[byte_index]) >> (8 - bit_index - bits_to_read);

value = (value << bits_to_read) | current_byte;
bit_index += bits_to_read;
bit_count -= bits_to_read;
}
return value;
}
13 changes: 13 additions & 0 deletions C/bit_reader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

typedef struct {
const unsigned char * buffer;
int position;
} bit_reader_cxt;

void init_bit_reader_cxt(bit_reader_cxt* br, const void * buffer);
int peek_int(bit_reader_cxt* br, const int bits);
int read_int(bit_reader_cxt* br, const int bits);
int read_signed_int(bit_reader_cxt* br, const int bits);
int read_offset_binary(bit_reader_cxt* br, const int bits);
void align_position(bit_reader_cxt* br, const unsigned int multiple);
110 changes: 110 additions & 0 deletions C/decinit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "bit_reader.h"
#include "decinit.h"
#include "error_codes.h"
#include "structures.h"
#include "tables.h"
#include <string.h>

static int BlockTypeToChannelCount(BlockType block_type);

at9_status init_decoder(atrac9_handle* handle, unsigned char* config_data, int wlength)
{
ERROR_CHECK(init_config_data(&handle->config, config_data));
ERROR_CHECK(init_frame(handle));
handle->wlength = wlength;
handle->initialized = 1;
return ERR_SUCCESS;
}

at9_status init_config_data(ConfigData* config, unsigned char* config_data)
{
memcpy(config->ConfigData, config_data, CONFIG_DATA_SIZE);
ERROR_CHECK(read_config_data(config));

config->FramesPerSuperframe = 1 << config->SuperframeIndex;
config->SuperframeBytes = config->FrameBytes << config->SuperframeIndex;

config->ChannelConfig = ChannelConfigs[config->ChannelConfigIndex];
config->ChannelCount = config->ChannelConfig.ChannelCount;
config->SampleRate = SampleRates[config->SampleRateIndex];
config->HighSampleRate = config->SampleRateIndex > 7;
config->FrameSamplesPower = SamplingRateIndexToFrameSamplesPower[config->SampleRateIndex];
config->FrameSamples = 1 << config->FrameSamplesPower;
config->SuperframeSamples = config->FrameSamples * config->FramesPerSuperframe;

return ERR_SUCCESS;
}

at9_status read_config_data(ConfigData* config)
{
bit_reader_cxt br;
init_bit_reader_cxt(&br, &config->ConfigData);

const int header = read_int(&br, 8);
config->SampleRateIndex = read_int(&br, 4);
config->ChannelConfigIndex = read_int(&br, 3);
const int validation_bit = read_int(&br, 1);
config->FrameBytes = read_int(&br, 11) + 1;
config->SuperframeIndex = read_int(&br, 2);

if (header != 0xFE || validation_bit != 0)
{
return ERR_BAD_CONFIG_DATA;
}

return ERR_SUCCESS;
}

at9_status init_frame(atrac9_handle* handle)
{
const int block_count = handle->config.ChannelConfig.BlockCount;
handle->frame.config = &handle->config;

for (int i = 0; i < block_count; i++)
{
ERROR_CHECK(init_block(&handle->frame.Blocks[i], &handle->frame, i));
}

return ERR_SUCCESS;
}

at9_status init_block(block* block, frame* parent_frame, int block_index)
{
block->Frame = parent_frame;
block->BlockIndex = block_index;
block->config = parent_frame->config;
block->BlockType = block->config->ChannelConfig.Types[block_index];
block->ChannelCount = BlockTypeToChannelCount(block->BlockType);

for (int i = 0; i < block->ChannelCount; i++)
{
ERROR_CHECK(init_channel(&block->Channels[i], block, i));
}

return ERR_SUCCESS;
}

at9_status init_channel(channel* channel, block* parent_block, int channel_index)
{
channel->Block = parent_block;
channel->Frame = parent_block->Frame;
channel->config = parent_block->config;
channel->ChannelIndex = channel_index;
channel->mdct.bits = parent_block->config->FrameSamplesPower;
return ERR_SUCCESS;
}

static int BlockTypeToChannelCount(BlockType block_type)
{
switch (block_type)
{
case Mono:
return 1;
case Stereo:
return 2;
case LFE:
return 1;
default:
return 0;
}
}
11 changes: 11 additions & 0 deletions C/decinit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "error_codes.h"
#include "structures.h"

at9_status init_decoder(atrac9_handle* handle, unsigned char * config_data, int wlength);
at9_status init_config_data(ConfigData* config, unsigned char * config_data);
at9_status read_config_data(ConfigData* config);
at9_status init_frame(atrac9_handle* handle);
at9_status init_block(block* block, frame* parent_frame, int block_index);
at9_status init_channel(channel* channel, block* parent_block, int channel_index);
Loading

0 comments on commit 46d4203

Please sign in to comment.