Skip to content

Commit

Permalink
Add bit reduction
Browse files Browse the repository at this point in the history
  • Loading branch information
jatinchowdhury18 committed Jul 24, 2023
1 parent 1f1cf2f commit f35a3ac
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 10 deletions.
5 changes: 1 addition & 4 deletions src/jai/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
file(GLOB_RECURSE JAI_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.jai)
#message(STATUS "Found Jai source files ${JAI_SRC_FILES}")

if(WIN32)
set(JAI_LIBRARY_FILE "byod_jai_lib.lib")
else()
Expand All @@ -10,7 +7,7 @@ endif()
add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${JAI_LIBRARY_FILE}
COMMAND ${JAI_COMPILER} build.jai
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${JAI_SRC_FILES} # To make sure this command re-runs whenever we update the Jai source files
DEPENDS build.jai krusher/bit_reduction.jai krusher/lofi_downsampler.jai
)
add_custom_target(jai_library_build DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${JAI_LIBRARY_FILE})

Expand Down
9 changes: 8 additions & 1 deletion src/jai/build.jai
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

#run build();

SRC_FILES :: string.[
"krusher/lofi_downsampler.jai",
"krusher/bit_reduction.jai"
];

build :: () {
header_info : Header_Info;
header_info.jai_type_prefix = "jai_";
Expand All @@ -20,7 +25,9 @@ build :: () {
set_build_options(target_options, w);

compiler_begin_intercept(w);
add_build_file(tprint("%/krusher/lofi_downsampler.jai", #filepath), w);
for file, _ : SRC_FILES {
add_build_file(tprint("%/%", #filepath, file), w);
}
while true {
message := compiler_wait_for_message();
handle_message(*header_info, message);
Expand Down
8 changes: 8 additions & 0 deletions src/jai/byod_jai_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct jai_Buffer;
struct jai_String_Builder;
struct jai_Print_Style;
struct jai_Context;
struct jai_Krusher_Bit_Reducer_Filter_State;
struct jai_Krusher_Lofi_Resample_State;

enum jai_Type_Info_Tag {
Expand Down Expand Up @@ -318,6 +319,11 @@ typedef struct jai_Context {
struct jai_Print_Style print_style;
} jai_Context;

typedef struct jai_Krusher_Bit_Reducer_Filter_State {
s32 p1;
s32 p2;
} jai_Krusher_Bit_Reducer_Filter_State;

typedef struct jai_Krusher_Lofi_Resample_State {
double upsample_overshoot;
double downsample_overshoot;
Expand All @@ -328,6 +334,8 @@ void __jai_runtime_fini(void *_context);

struct jai_Context * __jai_runtime_init(s32 argc, u8 **argv);

void krusher_bit_reduce_process_block(float **buffer, s32 num_channels, s32 num_samples, s32 filter_index, s32 bit_depth, struct jai_Krusher_Bit_Reducer_Filter_State *filter_states);

void krusher_process_lofi_downsample(struct jai_Context *ctx, struct jai_Krusher_Lofi_Resample_State *state, float **buffer, s32 num_channels, s32 num_samples, double resample_factor);

void krusher_init_lofi_resample(struct jai_Krusher_Lofi_Resample_State *state);
Expand Down
159 changes: 159 additions & 0 deletions src/jai/krusher/bit_reduction.jai
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
Krusher_Bit_Reducer_Filter_State :: struct {
p1: s32;
p2: s32;
}

#program_export
krusher_bit_reduce_process_block :: (buffer: **float,
num_channels: s32,
num_samples: s32,
filter_index: s32,
bit_depth: s32,
filter_states: *Krusher_Bit_Reducer_Filter_State) #c_call {
small_block_size : s32 : 16;
samples_int : [small_block_size]s16 = ---;

for channel : 0..num_channels-1 {
samples_remaining : s32 = num_samples;
while samples_remaining > 0 {
samples_to_process := ifx samples_remaining > small_block_size then small_block_size else samples_remaining;
defer { samples_remaining -= samples_to_process; }

samples_float_span : []float32;
samples_float_span.data = buffer[channel] + num_samples - samples_remaining;
samples_float_span.count = samples_to_process;

memset(*samples_int, 0, size_of(s32) * small_block_size);
samples_int_span : []s16;
samples_int_span.data = samples_int.data;
samples_int_span.count = samples_to_process;

convert_float_to_int(samples_float_span, samples_int_span);

if (bit_depth < 12) {
br_data := bit_reduce_encode(samples_int_span, bit_depth);
bit_reduce_decode(br_data, samples_int_span, cast(BR_Filter) filter_index, *filter_states[channel]);
}

convert_int_to_float(samples_int_span, samples_float_span);
}
}
}

#scope_file
BIT_MASKS :: u16.[
0, // 0
0x0001, // 1
0x0003, // 2
0x0007, // 3
0x000F, // 4
0x001F, // 5
0x003F, // 6
0x007F, // 7
0x00FF, // 8
0x01FF, // 9
0x03FF, // 10
0x07FF, // 11
0x0FFF, // 12
0x1FFF, // 13
0x3FFF, // 14
0x7FFF, // 15
];

Bit_Reduction_Block :: struct {
shift_amount: u8;
data: [16] u16;
}

BR_Filter :: enum {
TYPE_0;
TYPE_1;
TYPE_2;
TYPE_3;
}

encode_sample :: inline (shift: u8, bit_depth: s32, x: s16) -> u16 #no_context {
value_unsigned := cast(u16) (x + (1 << 8));
return cast(u16) (value_unsigned >> shift) & BIT_MASKS[bit_depth];
}

decode_sample :: inline (shift: u8, x: u16) -> s16 #no_context {
return cast(s16) (cast(u16) (x << shift) - (1 << 8));
}

bit_reduce_decode :: (using br_block: Bit_Reduction_Block,
out: []s16,
filter: BR_Filter,
using state: *Krusher_Bit_Reducer_Filter_State) #no_context {

type1_filter :: inline (nibble_2r: s16, using state: *Krusher_Bit_Reducer_Filter_State) -> s16 #no_context {
y := cast(s32) nibble_2r + ((p1 * 15) >> 4);
p2 = 0;
p1 = y;
return cast(s16) (y >> 4);
}

type2_filter :: inline (nibble_2r: s16, using state: *Krusher_Bit_Reducer_Filter_State) -> s16 #no_context {
y := cast(s32) nibble_2r + ((p1 * 61) >> 5) - ((p2 * 15) >> 4);
p2 = p1;
p1 = y;
return cast(s16) (y >> 5);
}

type3_filter :: inline (nibble_2r: s16, using state: *Krusher_Bit_Reducer_Filter_State) -> s16 #no_context {
y := cast(s32) nibble_2r + ((p1 * 115) >> 6) - ((p2 * 13) >> 4);
p2 = p1;
p1 = y;
return cast(s16) (y >> 6);
}

for br_sample, i : data {
if #complete filter == {
case .TYPE_0; out[i] = decode_sample(shift_amount, br_sample);
case .TYPE_1; out[i] = type1_filter (decode_sample(shift_amount, br_sample), state);
case .TYPE_2; out[i] = type2_filter (decode_sample(shift_amount, br_sample), state);
case .TYPE_3; out[i] = type3_filter (decode_sample(shift_amount, br_sample), state);
}
}
}

bit_reduce_encode :: (pcm_data: []s16, bit_depth: s32) -> Bit_Reduction_Block #no_context {
shift_best : u8 = 0;
err_min : float64 = Math.FLOAT64_MAX;

for s : cast(u8) 0.. cast(u8) (16 - bit_depth) {
err_square_accum : float64 = 0.0;
for pcm_sample, _ : pcm_data {
pred := decode_sample(s, encode_sample(s, bit_depth, pcm_sample));
err := cast(float64) (pcm_sample - pred);
err_square_accum += err * err;
}

if err_square_accum < err_min {
err_min = err_square_accum;
shift_best = s;
}
}

using br_block : Bit_Reduction_Block = ---;
shift_amount = shift_best;
for pcm_sample, i : pcm_data {
data[i] = encode_sample(shift_best, bit_depth, pcm_sample);
}

return br_block;
}

convert_float_to_int :: (data_float: [] float, data_int: [] s16) #no_context {
for float_sample, i : data_float {
data_int[i] = cast(s16) (float_sample * cast(float32) (1 << 8));
}
}

convert_int_to_float :: (data_int: [] s16, data_float: [] float) #no_context {
for _, i : data_float {
data_float[i] = cast(float32) data_int[i] / cast(float32) (1 << 8);
}
}

Math :: #import "Math";
11 changes: 8 additions & 3 deletions src/processors/other/krusher/Krusher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ void Krusher::prepare (double sampleRate, int samplesPerBlock)

krusher_init_lofi_resample (&resample_state);

// for (auto& state : brrFilterStates)
// state = {};
for (auto& state : brFilterStates)
state = {};

dcBlocker.prepare (2);
dcBlocker.calcCoefs (20.0f, (float) sampleRate);
Expand Down Expand Up @@ -108,7 +108,12 @@ void Krusher::processAudio (AudioBuffer<float>& buffer)
dryBuffer.setCurrentSize (buffer.getNumChannels(), buffer.getNumSamples());
chowdsp::BufferMath::copyBufferData (buffer, dryBuffer);

// brr_helpers::processBlock (buffer, brrFilterIndex->getIndex(), (int) *bitDepthParam, brrFilterStates);
krusher_bit_reduce_process_block (const_cast<float**> (buffer.getArrayOfWritePointers()),
buffer.getNumChannels(),
buffer.getNumSamples(),
brrFilterIndex->getIndex(),
(int) *bitDepthParam,
brFilterStates.data());

processDownsampler (buffer, *sampleRateParam, antialiasParam->get());

Expand Down
3 changes: 1 addition & 2 deletions src/processors/other/krusher/Krusher.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ class Krusher : public BaseProcessor
#if KRUSHER_USE_JAI_IMPL
SharedJaiContext jai_context;
jai_Krusher_Lofi_Resample_State resample_state {};
std::array<jai_Krusher_Bit_Reducer_Filter_State, 2> brFilterStates {};
#else
std::unique_ptr<chowdsp::NullType> jai_context;
Krusher_Lofi_Resample_State resample_state {};
#endif

// std::array<brr_helpers::BRRFilterState, 2> brrFilterStates {};

chowdsp::FirstOrderHPF<float> dcBlocker;

chowdsp::Gain<float> wetGain;
Expand Down

0 comments on commit f35a3ac

Please sign in to comment.