consolidate all repos to one for archive
This commit is contained in:
4
semester_5/racunalniska_vecpredstavnost/.gitignore
vendored
Normal file
4
semester_5/racunalniska_vecpredstavnost/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.vscode
|
||||
*.zip
|
||||
main
|
||||
*.bin
|
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "Buffer.hpp"
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
int k = 8;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
int readInt()
|
||||
{
|
||||
int ret = buffer.buffer[pos];
|
||||
pos += 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char readByte()
|
||||
{
|
||||
x = buffer.buffer[pos];
|
||||
pos++;
|
||||
return x;
|
||||
}
|
||||
|
||||
bool readBit()
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
readByte();
|
||||
k = 0;
|
||||
}
|
||||
bool b = (x >> k) & 1;
|
||||
k++;
|
||||
return b;
|
||||
}
|
||||
};
|
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "Buffer.hpp"
|
||||
|
||||
class BitWriter
|
||||
{
|
||||
public:
|
||||
int k = 0;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
|
||||
void writeByte(uint8_t x)
|
||||
{
|
||||
// f.write((char*)&x, 1);
|
||||
buffer.add_end(&x, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void writeInt(int x)
|
||||
{
|
||||
buffer.add_end((uint8_t *)&x, sizeof(x));
|
||||
}
|
||||
|
||||
void writeBit(bool b)
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
writeByte(x);
|
||||
k = 0;
|
||||
x = 0;
|
||||
}
|
||||
x ^= (-b ^ x) & (1 << k);
|
||||
k++;
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
if (k > 0)
|
||||
writeByte(x);
|
||||
}
|
||||
};
|
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
uint8_t *buffer = nullptr;
|
||||
size_t taken = 0;
|
||||
size_t size = 0;
|
||||
std::string file_path;
|
||||
|
||||
Buffer(size_t size);
|
||||
Buffer();
|
||||
~Buffer();
|
||||
bool resize(size_t new_size);
|
||||
int add_end(uint8_t *data, size_t data_size);
|
||||
int add_middle(uint8_t *data, size_t data_size, size_t index);
|
||||
|
||||
// Removes data from buffer without checking if it's in the buffer
|
||||
void remove_fast(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(size_t index, size_t data_size);
|
||||
|
||||
int find(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(uint8_t *data, size_t data_size);
|
||||
|
||||
void clear() { taken = 0; }
|
||||
|
||||
bool save_to_file();
|
||||
bool save_to_file(std::string file_path);
|
||||
|
||||
bool load_from_file();
|
||||
bool load_from_file(std::string file_path);
|
||||
};
|
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "BitWriter.hpp"
|
||||
#include <vector>
|
||||
|
||||
class Compressor
|
||||
{
|
||||
|
||||
public:
|
||||
Compressor() = default;
|
||||
~Compressor() = default;
|
||||
void compress(std::vector<uint8_t> &input);
|
||||
BitWriter bitWriter;
|
||||
|
||||
private:
|
||||
void two_bit_dif(int8_t num);
|
||||
void tree_bit_dif(int8_t num);
|
||||
void four_bit_dif(int8_t num);
|
||||
void five_bit_dif(int8_t num);
|
||||
void encode_diff(int8_t num);
|
||||
void encode_abs(int16_t num);
|
||||
void write_zero();
|
||||
|
||||
int numOfZeros = 0;
|
||||
};
|
@@ -0,0 +1,15 @@
|
||||
#include "BitReader.hpp"
|
||||
#include <vector>
|
||||
|
||||
class Decompressor
|
||||
{
|
||||
public:
|
||||
std::vector<uint8_t> decompress();
|
||||
BitReader bitReader;
|
||||
|
||||
private:
|
||||
int8_t twoZero();
|
||||
int8_t treeZero();
|
||||
int8_t forZero();
|
||||
int8_t fiveZero();
|
||||
};
|
114
semester_5/racunalniska_vecpredstavnost/vaja_1/main.cpp
Normal file
114
semester_5/racunalniska_vecpredstavnost/vaja_1/main.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <random>
|
||||
|
||||
#include "Compressor.hpp"
|
||||
#include "Decompressor.hpp"
|
||||
|
||||
/*
|
||||
• Prikažite graf ali tabelo kompresijskega razmerja
|
||||
• Prikažite graf ali tabelo časa kompresije
|
||||
• Prikažite graf ali tabelo časa dekompresije
|
||||
• 5-10 stavkov ugotovitev
|
||||
|
||||
• Uporabite N števil
|
||||
• N = {5, 50, 500, 5000}
|
||||
• Naključno generirana števila na intervalu od 0 do 255
|
||||
• Števila (na intervalu med 0 in 255), ki se med seboj razlikujejo za M
|
||||
(razlika med sosednjima številoma je med 0 in M)
|
||||
• M = {5, 10, 15, 30}
|
||||
• Primer: N = 5 in M = 5; podatki: 135, 133, 136, 141, 141
|
||||
|
||||
|
||||
55 53 53 53 53 53 10 10 11 11 11 11
|
||||
|
||||
00110111 000000 01011 10100101011 01000 000010 01010 11
|
||||
*/
|
||||
|
||||
void genRandNum(int N, int M, std::vector<uint8_t> &vec)
|
||||
{
|
||||
|
||||
std::random_device rand_dev;
|
||||
std::mt19937 generator(rand_dev());
|
||||
std::uniform_real_distribution<double> distr(0.0, 1.0);
|
||||
|
||||
uint8_t last = 0;
|
||||
uint8_t max = 255;
|
||||
uint8_t min = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
// std::cout << 25 + static_cast<int>((distr(generator) * (63 - 25 + 1))) << '\n';
|
||||
float r = distr(generator);
|
||||
uint8_t num = min + (r * (max - min));
|
||||
max = num + M;
|
||||
if (max > 255)
|
||||
max = 255;
|
||||
min = num - M;
|
||||
if (min < 0)
|
||||
min = 0;
|
||||
vec.push_back(num);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
auto start = std::chrono::system_clock::now();
|
||||
std::vector<int> N = {5, 50, 500, 5000, 50000};
|
||||
std::vector<int> M = {2, 5, 10, 15, 30, 60};
|
||||
|
||||
printf("N, \t M, \t Compress time, \tDecompress time, \t Input size, \t Output size, \t Compression ratio, \n");
|
||||
|
||||
for (size_t i = 0; i < N.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < M.size(); j++)
|
||||
{
|
||||
|
||||
std::vector<uint8_t> input;
|
||||
genRandNum(N[i], M[j], input);
|
||||
|
||||
Compressor compressor;
|
||||
|
||||
auto startCom = std::chrono::system_clock::now();
|
||||
compressor.compress(input);
|
||||
auto endCom = std::chrono::system_clock::now();
|
||||
|
||||
Decompressor decompressor;
|
||||
decompressor.bitReader.buffer.add_end(compressor.bitWriter.buffer.buffer, compressor.bitWriter.buffer.taken);
|
||||
|
||||
auto startDec = std::chrono::system_clock::now();
|
||||
std::vector<uint8_t> output = decompressor.decompress();
|
||||
auto endDec = std::chrono::system_clock::now();
|
||||
|
||||
for (size_t k = 0; k < input.size(); k++)
|
||||
{
|
||||
if (input[k] != output[k])
|
||||
{
|
||||
printf("Error\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::duration<double> compTime = endCom - startCom;
|
||||
std::chrono::duration<double> decTime = endDec - startDec;
|
||||
|
||||
printf("%d,\t %d,\t ", N[i], M[j]);
|
||||
printf("%f,\t\t", compTime.count());
|
||||
printf("%f,\t\t ", decTime.count());
|
||||
uint64_t input_size = N[i] * sizeof(uint8_t);
|
||||
uint64_t output_size = compressor.bitWriter.buffer.taken;
|
||||
printf("%ld,\t\t ", input_size);
|
||||
printf("%ld,\t\t ", output_size);
|
||||
printf("%f,\t", (float)input_size / (float)output_size);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double> decTime = end - start;
|
||||
printf("Total time: %f\n", decTime.count());
|
||||
return 0;
|
||||
}
|
27
semester_5/racunalniska_vecpredstavnost/vaja_1/makefile
Normal file
27
semester_5/racunalniska_vecpredstavnost/vaja_1/makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
CC=g++
|
||||
|
||||
CFLAGS= -std=c++23
|
||||
|
||||
INCLUDE_DIR= include
|
||||
|
||||
SRC_DIR= src
|
||||
|
||||
# Get all cpp files from src directory
|
||||
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
|
||||
|
||||
all: main
|
||||
|
||||
main: main.cpp $(SRCS)
|
||||
$(CC) $(CFLAGS) -o3 -I$(INCLUDE_DIR) $(SRCS) main.cpp -o main
|
||||
|
||||
debug: main.cpp $(SRCS)
|
||||
$(CC) $(CFLAGS) -I$(INCLUDE_DIR) $(SRCS) -g main.cpp -o main
|
||||
|
||||
run: main
|
||||
./main
|
||||
|
||||
zip:
|
||||
zip -r main.zip src include makefile main.cpp
|
||||
|
||||
clean:
|
||||
rm main main.zip
|
153
semester_5/racunalniska_vecpredstavnost/vaja_1/src/Buffer.cpp
Normal file
153
semester_5/racunalniska_vecpredstavnost/vaja_1/src/Buffer.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "Buffer.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
buffer = nullptr;
|
||||
size = 0;
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
Buffer::Buffer(size_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->buffer = new uint8_t[size];
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
if (buffer)
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool Buffer::resize(size_t new_size)
|
||||
{
|
||||
if (size >= new_size)
|
||||
return true;
|
||||
if (new_size < size * 2)
|
||||
new_size = size * 2;
|
||||
uint8_t *new_buffer = (uint8_t *)realloc(buffer, new_size);
|
||||
if (!new_buffer)
|
||||
{
|
||||
printf("Error resizing buffer\n");
|
||||
return false;
|
||||
}
|
||||
buffer = new_buffer;
|
||||
size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Buffer::add_end(uint8_t *data, size_t data_size)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
|
||||
memcpy(buffer + taken, data, data_size);
|
||||
taken += data_size;
|
||||
return taken - data_size;
|
||||
}
|
||||
|
||||
int Buffer::add_middle(uint8_t *data, size_t data_size, size_t index)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
memmove(buffer + index + data_size, buffer + index, taken - index);
|
||||
memcpy(buffer + index, data, data_size);
|
||||
taken += data_size;
|
||||
return index;
|
||||
}
|
||||
|
||||
void Buffer::remove_fast(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int64_t index = data - buffer;
|
||||
if (index < 0 || index > taken || index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
void Buffer::remove(size_t index, size_t data_size)
|
||||
{
|
||||
if (index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
int Buffer::find(uint8_t *data, size_t data_size)
|
||||
{
|
||||
for (int i = 0; i < taken; i++)
|
||||
if (memcmp(buffer + i, data, data_size) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Buffer::remove(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int index = find(data, data_size);
|
||||
if (index == -1)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
remove(index, data_size);
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file()
|
||||
{
|
||||
std::ofstream file(this->file_path, std::ios::binary | std::ios::out);
|
||||
if (!file.is_open())
|
||||
{
|
||||
printf("Error saving file\n");
|
||||
return false;
|
||||
}
|
||||
file.write((char *)this->buffer, this->taken);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return save_to_file();
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file()
|
||||
{
|
||||
std::ifstream file(this->file_path, std::ios::binary | std::ios::in);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
|
||||
size_t file_size = file.tellg();
|
||||
resize(file_size);
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read((char *)buffer, size);
|
||||
|
||||
if (file)
|
||||
taken = file_size;
|
||||
else
|
||||
taken = file.gcount();
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return load_from_file();
|
||||
}
|
@@ -0,0 +1,158 @@
|
||||
#include "Compressor.hpp"
|
||||
|
||||
void Compressor::two_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(0);
|
||||
|
||||
if (num < 0)
|
||||
num += 2;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::tree_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(1);
|
||||
|
||||
if (num < 0)
|
||||
num += 6;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 4);
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::four_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(0);
|
||||
|
||||
if (num < 0)
|
||||
num += 14;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 8);
|
||||
bitWriter.writeBit(num & 4);
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::five_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(1);
|
||||
|
||||
if (num < 0)
|
||||
num += 30;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 16);
|
||||
bitWriter.writeBit(num & 8);
|
||||
bitWriter.writeBit(num & 4);
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::encode_diff(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(0);
|
||||
if (-2 <= num && num <= 2)
|
||||
two_bit_dif(num);
|
||||
else if (-6 <= num && num <= 6)
|
||||
tree_bit_dif(num);
|
||||
else if (-14 <= num && num <= 14)
|
||||
four_bit_dif(num);
|
||||
else if (-30 <= num && num <= 30)
|
||||
five_bit_dif(num);
|
||||
}
|
||||
|
||||
void Compressor::encode_abs(int16_t num)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(0);
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
num = -num;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
}
|
||||
|
||||
uint8_t numOfBits = num;
|
||||
|
||||
for (int i = 7; i >= 0; i--)
|
||||
bitWriter.writeBit(numOfBits & 1 << i);
|
||||
}
|
||||
|
||||
void Compressor::write_zero()
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(1);
|
||||
numOfZeros--;
|
||||
bitWriter.writeBit(numOfZeros & 4);
|
||||
bitWriter.writeBit(numOfZeros & 2);
|
||||
bitWriter.writeBit(numOfZeros & 1);
|
||||
numOfZeros = 0;
|
||||
}
|
||||
|
||||
void Compressor::compress(std::vector<uint8_t> &input)
|
||||
{
|
||||
std::vector<int16_t> diference;
|
||||
|
||||
diference.push_back(input[0]);
|
||||
for (size_t i = 1; i < input.size(); i++)
|
||||
{
|
||||
diference.push_back(input[i] - input[i - 1]);
|
||||
}
|
||||
|
||||
bitWriter.writeByte(diference[0]);
|
||||
for (size_t i = 1; i < diference.size(); i++)
|
||||
{
|
||||
int16_t j = diference[i];
|
||||
if (j == 0)
|
||||
{
|
||||
if (numOfZeros == 8)
|
||||
{
|
||||
write_zero();
|
||||
}
|
||||
|
||||
numOfZeros++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numOfZeros > 0)
|
||||
{
|
||||
write_zero();
|
||||
}
|
||||
|
||||
if (-30 <= j && j <= 30)
|
||||
encode_diff(j);
|
||||
else
|
||||
encode_abs(j);
|
||||
|
||||
numOfZeros = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (numOfZeros > 0)
|
||||
{
|
||||
write_zero();
|
||||
}
|
||||
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.finish();
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
#include "Decompressor.hpp"
|
||||
|
||||
int8_t Decompressor::twoZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 1; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 2)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 2;
|
||||
}
|
||||
|
||||
int8_t Decompressor::treeZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 2; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 4)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 6;
|
||||
}
|
||||
|
||||
int8_t Decompressor::forZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 8)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 14;
|
||||
}
|
||||
|
||||
int8_t Decompressor::fiveZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 16)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 30;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Decompressor::decompress()
|
||||
{
|
||||
std::vector<uint8_t> output;
|
||||
bool end = false;
|
||||
uint8_t previus = bitReader.readByte();
|
||||
output.push_back(previus);
|
||||
|
||||
do
|
||||
{
|
||||
uint8_t type = bitReader.readBit() << 1 | bitReader.readBit();
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
uint8_t numOfZero = bitReader.readBit() << 1 | bitReader.readBit();
|
||||
int8_t diff = 0;
|
||||
switch (numOfZero)
|
||||
{
|
||||
case 0:
|
||||
diff = twoZero();
|
||||
break;
|
||||
case 1:
|
||||
diff = treeZero();
|
||||
break;
|
||||
case 2:
|
||||
diff = forZero();
|
||||
break;
|
||||
case 3:
|
||||
diff = fiveZero();
|
||||
break;
|
||||
}
|
||||
|
||||
previus += diff;
|
||||
output.push_back(previus);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
uint8_t numOfZero = bitReader.readBit() << 2 | bitReader.readBit() << 1 | bitReader.readBit();
|
||||
|
||||
numOfZero++;
|
||||
for (size_t i = 0; i < numOfZero; i++)
|
||||
{
|
||||
output.push_back(previus);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
uint8_t sign = bitReader.readBit();
|
||||
int16_t diff = 0;
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
uint8_t bit = bitReader.readBit();
|
||||
diff |= bit << i;
|
||||
}
|
||||
if (sign)
|
||||
diff = -diff;
|
||||
|
||||
previus += diff;
|
||||
output.push_back(previus);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
end = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!end);
|
||||
return output;
|
||||
}
|
BIN
semester_5/racunalniska_vecpredstavnost/vaja_2/RV_Vaja_2.pdf
Normal file
BIN
semester_5/racunalniska_vecpredstavnost/vaja_2/RV_Vaja_2.pdf
Normal file
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "Buffer.h"
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
int k = 8;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
int readInt()
|
||||
{
|
||||
int ret = *(int *)&buffer.buffer[pos];
|
||||
pos += 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned short int readShort()
|
||||
{
|
||||
short ret = *(unsigned short int *)&buffer.buffer[pos];
|
||||
pos += 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char readByte()
|
||||
{
|
||||
x = buffer.buffer[pos];
|
||||
pos++;
|
||||
return x;
|
||||
}
|
||||
|
||||
bool readBit()
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
readByte();
|
||||
k = 0;
|
||||
}
|
||||
bool b = (x >> k) & 1;
|
||||
k++;
|
||||
return b;
|
||||
}
|
||||
};
|
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "Buffer.h"
|
||||
|
||||
class BitWriter
|
||||
{
|
||||
public:
|
||||
int k = 0;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
|
||||
void writeByte(uint8_t v)
|
||||
{
|
||||
buffer.add_end(&v, sizeof(v));
|
||||
}
|
||||
|
||||
void writeInt(int v)
|
||||
{
|
||||
buffer.add_end((uint8_t *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void write16(unsigned short int v)
|
||||
{
|
||||
buffer.add_end((uint8_t *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void writeBit(bool b)
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
writeByte(x);
|
||||
k = 0;
|
||||
x = 0;
|
||||
}
|
||||
x ^= (-b ^ x) & (1 << k);
|
||||
k++;
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
if (k > 0)
|
||||
writeByte(x);
|
||||
}
|
||||
};
|
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
uint8_t *buffer = nullptr;
|
||||
size_t taken = 0;
|
||||
size_t size = 0;
|
||||
std::string file_path;
|
||||
|
||||
Buffer(size_t size);
|
||||
Buffer();
|
||||
~Buffer();
|
||||
bool resize(size_t new_size);
|
||||
int add_end(uint8_t *data, size_t data_size);
|
||||
int add_middle(uint8_t *data, size_t data_size, size_t index);
|
||||
void copy(Buffer &other);
|
||||
|
||||
// Removes data from buffer without checking if it's in the buffer
|
||||
void remove_fast(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(size_t index, size_t data_size);
|
||||
|
||||
int find(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(uint8_t *data, size_t data_size);
|
||||
|
||||
void clear() { taken = 0; }
|
||||
|
||||
bool save_to_file();
|
||||
bool save_to_file(std::string file_path);
|
||||
|
||||
bool load_from_file();
|
||||
bool load_from_file(std::string file_path);
|
||||
};
|
@@ -0,0 +1,15 @@
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include "BitWriter.h"
|
||||
|
||||
class Compressor
|
||||
{
|
||||
public:
|
||||
BitWriter writer;
|
||||
void compress(std::vector<std::vector<uint8_t>> &matrix);
|
||||
|
||||
private:
|
||||
void IC(std::vector<int> &C, int L, int H);
|
||||
std::vector<int> predict(std::vector<std::vector<uint8_t>> &P);
|
||||
void encode(int v, int g);
|
||||
};
|
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "BitReader.h"
|
||||
#include <vector>
|
||||
class Decompressor
|
||||
{
|
||||
public:
|
||||
std::vector<unsigned char> decompress();
|
||||
|
||||
BitReader reader;
|
||||
|
||||
int decode(int g);
|
||||
void DEIC(std::vector<int> &C, int L, int H);
|
||||
std::vector<unsigned char> predictInvers(std::vector<int> &E, int width, int hight);
|
||||
};
|
9370
semester_5/racunalniska_vecpredstavnost/vaja_2/include/stb_image.h
Normal file
9370
semester_5/racunalniska_vecpredstavnost/vaja_2/include/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
325
semester_5/racunalniska_vecpredstavnost/vaja_2/include/utils.h
Normal file
325
semester_5/racunalniska_vecpredstavnost/vaja_2/include/utils.h
Normal file
@@ -0,0 +1,325 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
#define VECTOR_UTILS
|
||||
#define BUFFER
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef BUFFER
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
uint8_t *buffer = nullptr;
|
||||
size_t taken = 0;
|
||||
size_t size = 0;
|
||||
std::string file_path;
|
||||
|
||||
Buffer(size_t size);
|
||||
Buffer();
|
||||
~Buffer();
|
||||
bool resize(size_t new_size);
|
||||
int add_end(uint8_t *data, size_t data_size);
|
||||
int add_middle(uint8_t *data, size_t data_size, size_t index);
|
||||
void copy(Buffer &other);
|
||||
|
||||
// Removes data from buffer without checking if it's in the buffer
|
||||
void remove_fast(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(size_t index, size_t data_size);
|
||||
|
||||
int find(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(uint8_t *data, size_t data_size);
|
||||
|
||||
void clear() { taken = 0; }
|
||||
|
||||
bool save_to_file();
|
||||
bool save_to_file(std::string file_path);
|
||||
|
||||
bool load_from_file();
|
||||
bool load_from_file(std::string file_path);
|
||||
};
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
buffer = nullptr;
|
||||
size = 0;
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
Buffer::Buffer(size_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->buffer = new uint8_t[size];
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
if (buffer)
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool Buffer::resize(size_t new_size)
|
||||
{
|
||||
if (size >= new_size)
|
||||
return true;
|
||||
if (new_size < size * 2)
|
||||
new_size = size * 2;
|
||||
uint8_t *new_buffer = (uint8_t *)realloc(buffer, new_size);
|
||||
if (!new_buffer)
|
||||
{
|
||||
printf("Error resizing buffer\n");
|
||||
return false;
|
||||
}
|
||||
buffer = new_buffer;
|
||||
size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Buffer::add_end(uint8_t *data, size_t data_size)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
|
||||
memcpy(buffer + taken, data, data_size);
|
||||
taken += data_size;
|
||||
return taken - data_size;
|
||||
}
|
||||
|
||||
int Buffer::add_middle(uint8_t *data, size_t data_size, size_t index)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
memmove(buffer + index + data_size, buffer + index, taken - index);
|
||||
memcpy(buffer + index, data, data_size);
|
||||
taken += data_size;
|
||||
return index;
|
||||
}
|
||||
|
||||
void Buffer::copy(Buffer &other)
|
||||
{
|
||||
if (other.size > size)
|
||||
if (!resize(other.size))
|
||||
return;
|
||||
memcpy(buffer, other.buffer, other.taken);
|
||||
taken = other.taken;
|
||||
}
|
||||
|
||||
void Buffer::remove_fast(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int64_t index = data - buffer;
|
||||
if (index < 0 || index > taken || index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
void Buffer::remove(size_t index, size_t data_size)
|
||||
{
|
||||
if (index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
int Buffer::find(uint8_t *data, size_t data_size)
|
||||
{
|
||||
for (int i = 0; i < taken; i++)
|
||||
if (memcmp(buffer + i, data, data_size) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Buffer::remove(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int index = find(data, data_size);
|
||||
if (index == -1)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
remove(index, data_size);
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file()
|
||||
{
|
||||
std::ofstream file(this->file_path, std::ios::binary | std::ios::out);
|
||||
if (!file.is_open())
|
||||
{
|
||||
printf("Error saving file\n");
|
||||
return false;
|
||||
}
|
||||
file.write((char *)this->buffer, this->taken);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return save_to_file();
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file()
|
||||
{
|
||||
std::ifstream file(this->file_path, std::ios::binary | std::ios::in);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
|
||||
size_t file_size = file.tellg();
|
||||
resize(file_size);
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read((char *)buffer, size);
|
||||
|
||||
if (file)
|
||||
taken = file_size;
|
||||
else
|
||||
taken = file.gcount();
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return load_from_file();
|
||||
}
|
||||
|
||||
#endif // BUFFER
|
||||
|
||||
#ifdef BIT_READER
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
int k = 8;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
int readInt()
|
||||
{
|
||||
int ret = *(int *)&buffer.buffer[pos];
|
||||
pos += 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned short int readShort()
|
||||
{
|
||||
short ret = *(unsigned short int *)&buffer.buffer[pos];
|
||||
pos += 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char readByte()
|
||||
{
|
||||
x = buffer.buffer[pos];
|
||||
pos++;
|
||||
return x;
|
||||
}
|
||||
|
||||
bool readBit()
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
readByte();
|
||||
k = 0;
|
||||
}
|
||||
bool b = (x >> k) & 1;
|
||||
k++;
|
||||
return b;
|
||||
}
|
||||
};
|
||||
#endif // BIT_READER
|
||||
|
||||
#ifdef BIT_WRITER
|
||||
|
||||
class BitWriter
|
||||
{
|
||||
public:
|
||||
int k = 0;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
|
||||
void writeByte(uint8_t v)
|
||||
{
|
||||
buffer.add_end(&v, sizeof(v));
|
||||
}
|
||||
|
||||
void writeInt(int v)
|
||||
{
|
||||
buffer.add_end((uint8_t *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void write16(unsigned short int v)
|
||||
{
|
||||
buffer.add_end((uint8_t *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void writeBit(bool b)
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
writeByte(x);
|
||||
k = 0;
|
||||
x = 0;
|
||||
}
|
||||
x ^= (-b ^ x) & (1 << k);
|
||||
k++;
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
if (k > 0)
|
||||
writeByte(x);
|
||||
}
|
||||
};
|
||||
#endif // BIT_WRITER
|
||||
|
||||
#ifdef VECTOR_UTILS
|
||||
template <typename T>
|
||||
void print_vec(std::vector<T> &vec, int wrap = 5)
|
||||
{
|
||||
for (size_t i = 0; i < vec.size(); i++)
|
||||
{
|
||||
printf("%2d ", vec[i]);
|
||||
if (i % wrap == wrap - 1)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void print_matrix(std::vector<std::vector<T>> &vec)
|
||||
{
|
||||
for (size_t i = 0; i < vec.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < vec[i].size(); j++)
|
||||
{
|
||||
printf("%2d ", vec[i][j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif // VECTOR_UTILS
|
131
semester_5/racunalniska_vecpredstavnost/vaja_2/main.cpp
Normal file
131
semester_5/racunalniska_vecpredstavnost/vaja_2/main.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <filesystem>
|
||||
|
||||
#include "compressor.h"
|
||||
#include "decompressor.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
struct ResultS
|
||||
{
|
||||
int original;
|
||||
int compressed;
|
||||
int64_t compression_time;
|
||||
int64_t decompression_time;
|
||||
};
|
||||
|
||||
std::optional<ResultS> run(const char *filepath)
|
||||
{
|
||||
int x, y, n;
|
||||
unsigned char *data = stbi_load(filepath, &x, &y, &n, 1);
|
||||
if (data == NULL)
|
||||
{
|
||||
printf("Error loading image!\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<std::vector<unsigned char>> matrix(x, std::vector<unsigned char>(y));
|
||||
for (int i = 0; i < x; i++)
|
||||
{
|
||||
for (int j = 0; j < y; j++)
|
||||
{
|
||||
matrix[i][j] = data[i * y + j];
|
||||
}
|
||||
}
|
||||
delete[] data;
|
||||
|
||||
Compressor com;
|
||||
|
||||
auto startCom = std::chrono::high_resolution_clock::now();
|
||||
com.compress(matrix);
|
||||
auto endCom = std::chrono::high_resolution_clock::now();
|
||||
|
||||
Decompressor dec;
|
||||
|
||||
dec.reader.buffer.copy(com.writer.buffer);
|
||||
|
||||
auto startDec = std::chrono::high_resolution_clock::now();
|
||||
std::vector<unsigned char> ret = dec.decompress();
|
||||
auto endDec = std::chrono::high_resolution_clock::now();
|
||||
|
||||
stbi_write_bmp("out.bmp", x, y, 1, ret.data());
|
||||
|
||||
auto compTime = std::chrono::duration_cast<std::chrono::milliseconds>(endCom - startCom);
|
||||
auto decTime = std::chrono::duration_cast<std::chrono::milliseconds>(endDec - startDec);
|
||||
|
||||
ResultS res;
|
||||
res.original = x * y;
|
||||
res.compressed = com.writer.buffer.taken;
|
||||
res.compression_time = compTime.count();
|
||||
res.decompression_time = decTime.count();
|
||||
|
||||
return res;
|
||||
}
|
||||
// ... x = width, y = height
|
||||
// Velikost original, Velikost stisnjena, Razmerje (orig./stisn.), Čas kompresije, Čas dekompresije,
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (false)
|
||||
{
|
||||
std::optional<ResultS> ret = run("slike/Sunrise.bmp");
|
||||
if (ret.has_value())
|
||||
{
|
||||
ResultS res = ret.value();
|
||||
printf("%9d\t", res.original);
|
||||
printf("%9d\t", res.compressed);
|
||||
printf("%9f\t", (float)res.original / (float)res.compressed);
|
||||
printf("%9ld\t", res.compression_time);
|
||||
printf("%9ld\t", res.decompression_time);
|
||||
printf("%s", "slike/Sunrise.bmp");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("%9s\t%9s\t%9s\t%9s\t%9s\t\n", "Original", "Comp.", "Ratio", "Comp. ms", "Dec. ms");
|
||||
|
||||
std::string directory_path = "slike/";
|
||||
|
||||
std::vector<std::string> files;
|
||||
|
||||
// Iterate over the files in the directory
|
||||
for (const auto &entry : std::filesystem::directory_iterator(directory_path))
|
||||
{
|
||||
// Check if the entry is a regular file
|
||||
if (std::filesystem::is_regular_file(entry.path()))
|
||||
{
|
||||
files.push_back(entry.path().string());
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(files.begin(), files.end());
|
||||
|
||||
for (auto file : files)
|
||||
{
|
||||
// std::cout << file << std::endl;
|
||||
// if (file == "slike/Sunrise.bmp") continue;
|
||||
|
||||
std::optional<ResultS> ret = run(file.c_str());
|
||||
if (ret.has_value())
|
||||
{
|
||||
ResultS res = ret.value();
|
||||
printf("%9d\t", res.original);
|
||||
printf("%9d\t", res.compressed);
|
||||
printf("%9f\t", (float)res.original / (float)res.compressed);
|
||||
printf("%9ld\t", res.compression_time);
|
||||
printf("%9ld\t", res.decompression_time);
|
||||
printf("%s", file.c_str());
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
27
semester_5/racunalniska_vecpredstavnost/vaja_2/makefile
Normal file
27
semester_5/racunalniska_vecpredstavnost/vaja_2/makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
CC=g++
|
||||
|
||||
CFLAGS= -std=c++23
|
||||
|
||||
INCLUDE_DIR= include
|
||||
|
||||
SRC_DIR= src
|
||||
|
||||
# Get all cpp files from src directory
|
||||
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
|
||||
|
||||
all: main run
|
||||
|
||||
main: main.cpp $(SRCS) $(INCLUDE_DIR)/*.h
|
||||
$(CC) $(CFLAGS) -O3 -I $(INCLUDE_DIR) $(SRCS) main.cpp -o main
|
||||
|
||||
debug: main.cpp $(SRCS)
|
||||
$(CC) $(CFLAGS) -I$(INCLUDE_DIR) $(SRCS) -g main.cpp -o main
|
||||
|
||||
run: main
|
||||
./main
|
||||
|
||||
zip:
|
||||
zip -r main.zip main.cpp $(INCLUDE_DIR) $(SRC_DIR) makefile
|
||||
|
||||
clean:
|
||||
rm main
|
BIN
semester_5/racunalniska_vecpredstavnost/vaja_2/slike/Baboon.bmp
Normal file
BIN
semester_5/racunalniska_vecpredstavnost/vaja_2/slike/Baboon.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 257 KiB |
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
162
semester_5/racunalniska_vecpredstavnost/vaja_2/src/Buffer.cpp
Normal file
162
semester_5/racunalniska_vecpredstavnost/vaja_2/src/Buffer.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "Buffer.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
buffer = nullptr;
|
||||
size = 0;
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
Buffer::Buffer(size_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->buffer = new uint8_t[size];
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
if (buffer)
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool Buffer::resize(size_t new_size)
|
||||
{
|
||||
if (size >= new_size)
|
||||
return true;
|
||||
if (new_size < size * 2)
|
||||
new_size = size * 2;
|
||||
uint8_t *new_buffer = (uint8_t *)realloc(buffer, new_size);
|
||||
if (!new_buffer)
|
||||
{
|
||||
printf("Error resizing buffer\n");
|
||||
return false;
|
||||
}
|
||||
buffer = new_buffer;
|
||||
size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Buffer::add_end(uint8_t *data, size_t data_size)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
|
||||
memcpy(buffer + taken, data, data_size);
|
||||
taken += data_size;
|
||||
return taken - data_size;
|
||||
}
|
||||
|
||||
int Buffer::add_middle(uint8_t *data, size_t data_size, size_t index)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
memmove(buffer + index + data_size, buffer + index, taken - index);
|
||||
memcpy(buffer + index, data, data_size);
|
||||
taken += data_size;
|
||||
return index;
|
||||
}
|
||||
|
||||
void Buffer::copy(Buffer &other)
|
||||
{
|
||||
if (other.size > size)
|
||||
if (!resize(other.size))
|
||||
return;
|
||||
memcpy(buffer, other.buffer, other.taken);
|
||||
taken = other.taken;
|
||||
}
|
||||
|
||||
void Buffer::remove_fast(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int64_t index = data - buffer;
|
||||
if (index < 0 || index > taken || index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
void Buffer::remove(size_t index, size_t data_size)
|
||||
{
|
||||
if (index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
int Buffer::find(uint8_t *data, size_t data_size)
|
||||
{
|
||||
for (int i = 0; i < taken; i++)
|
||||
if (memcmp(buffer + i, data, data_size) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Buffer::remove(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int index = find(data, data_size);
|
||||
if (index == -1)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
remove(index, data_size);
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file()
|
||||
{
|
||||
std::ofstream file(this->file_path, std::ios::binary | std::ios::out);
|
||||
if (!file.is_open())
|
||||
{
|
||||
printf("Error saving file\n");
|
||||
return false;
|
||||
}
|
||||
file.write((char *)this->buffer, this->taken);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return save_to_file();
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file()
|
||||
{
|
||||
std::ifstream file(this->file_path, std::ios::binary | std::ios::in);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
|
||||
size_t file_size = file.tellg();
|
||||
resize(file_size);
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read((char *)buffer, size);
|
||||
|
||||
if (file)
|
||||
taken = file_size;
|
||||
else
|
||||
taken = file.gcount();
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return load_from_file();
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
#include "compressor.h"
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
std::vector<int> Compressor::predict(std::vector<std::vector<uint8_t>> &P)
|
||||
{
|
||||
int hight = P.size();
|
||||
int width = P[0].size();
|
||||
std::vector<int> E(hight * width, 0);
|
||||
|
||||
E[0] = P[0][0];
|
||||
|
||||
for (size_t i = 1; i < width; i++)
|
||||
{
|
||||
E[i] = P[0][i - 1] - P[0][i];
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < hight; i++)
|
||||
{
|
||||
E[i * width] = P[i - 1][0] - P[i][0];
|
||||
}
|
||||
|
||||
for (size_t y = 1; y < hight; y++)
|
||||
{
|
||||
for (size_t x = 1; x < width; x++)
|
||||
{
|
||||
if (P[y - 1][x - 1] >= std::max(P[y][x - 1], P[y - 1][x]))
|
||||
{
|
||||
E[y * width + x] = std::min(P[y][x - 1], P[y - 1][x]) - P[y][x];
|
||||
}
|
||||
else if (P[y - 1][x - 1] <= std::min(P[y][x - 1], P[y - 1][x]))
|
||||
{
|
||||
E[y * width + x] = std::max(P[y][x - 1], P[y - 1][x]) - P[y][x];
|
||||
}
|
||||
else
|
||||
{
|
||||
E[y * width + x] = P[y][x - 1] + P[y - 1][x] - P[y - 1][x - 1] - P[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
void Compressor::encode(int v, int g)
|
||||
{
|
||||
for (int i = 0; i < g; ++i)
|
||||
{
|
||||
writer.writeBit((v >> i) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Compressor::IC(std::vector<int> &C, int L, int H)
|
||||
{
|
||||
if (H - L <= 1)
|
||||
return;
|
||||
if (C[H] == C[L])
|
||||
return;
|
||||
|
||||
int m = (H + L) / 2;
|
||||
int g = std::ceil(std::log2(C[H] - C[L] + 1));
|
||||
|
||||
encode(C[m] - C[L], g);
|
||||
|
||||
if (L < m)
|
||||
IC(C, L, m);
|
||||
if (m < H)
|
||||
IC(C, m, H);
|
||||
}
|
||||
|
||||
void Compressor::compress(std::vector<std::vector<uint8_t>> &matrix)
|
||||
{
|
||||
std::vector<int> E = predict(matrix);
|
||||
|
||||
std::vector<int> N(E.size(), 0);
|
||||
N[0] = E[0];
|
||||
for (size_t i = 1; i < E.size(); i++)
|
||||
{
|
||||
if (E[i] >= 0)
|
||||
N[i] = 2 * E[i];
|
||||
else
|
||||
N[i] = 2 * std::abs(E[i]) - 1;
|
||||
}
|
||||
|
||||
std::vector<int> C(N.size(), 0);
|
||||
C[0] = N[0];
|
||||
for (size_t i = 1; i < C.size(); i++)
|
||||
{
|
||||
C[i] = C[i - 1] + N[i];
|
||||
}
|
||||
writer.write16(matrix.size());
|
||||
writer.writeByte(E[0]);
|
||||
writer.writeInt(C[C.size() - 1]);
|
||||
writer.writeInt(C.size());
|
||||
|
||||
IC(C, 0, C.size() - 1);
|
||||
writer.finish();
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
#
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
#include "decompressor.h"
|
||||
#include "BitReader.h"
|
||||
|
||||
int Decompressor::decode(int g)
|
||||
{
|
||||
int v = 0;
|
||||
for (int i = 0; i < g; i++)
|
||||
{
|
||||
bool bit = reader.readBit();
|
||||
v |= bit << i;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void Decompressor::DEIC(std::vector<int> &C, int L, int H)
|
||||
{
|
||||
if (H - L <= 1)
|
||||
return;
|
||||
|
||||
if (C[L] == C[H])
|
||||
{
|
||||
for (size_t i = L + 1; i < H; i++)
|
||||
{
|
||||
C[i] = C[L];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int M = (L + H) / 2;
|
||||
|
||||
int G = std::ceil(std::log2(C[H] - C[L] + 1));
|
||||
C[M] = C[L] + decode(G);
|
||||
if (L < M)
|
||||
DEIC(C, L, M);
|
||||
if (M < H)
|
||||
DEIC(C, M, H);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Decompressor::predictInvers(std::vector<int> &E, int width, int hight)
|
||||
{
|
||||
std::vector<unsigned char> matrix1(width * hight, 0);
|
||||
matrix1[0] = E[0];
|
||||
|
||||
for (size_t i = 1; i < width; i++)
|
||||
{
|
||||
matrix1[i] = matrix1[i - 1] - E[i];
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < hight; i++)
|
||||
{
|
||||
matrix1[i * width] = matrix1[(i - 1) * width] - E[i * width];
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < hight; i++)
|
||||
{
|
||||
for (size_t j = 1; j < width; j++)
|
||||
{
|
||||
if (matrix1[(i - 1) * width + j - 1] >= std::max(matrix1[i * width + j - 1], matrix1[(i - 1) * width + j]))
|
||||
{
|
||||
matrix1[i * width + j] = std::min(matrix1[i * width + j - 1], matrix1[(i - 1) * width + j]) - E[i * width + j];
|
||||
}
|
||||
else if (matrix1[(i - 1) * width + j - 1] <= std::min(matrix1[i * width + j - 1], matrix1[(i - 1) * width + j]))
|
||||
{
|
||||
matrix1[i * width + j] = std::max(matrix1[i * width + j - 1], matrix1[(i - 1) * width + j]) - E[i * width + j];
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix1[i * width + j] = matrix1[i * width + j - 1] + matrix1[(i - 1) * width + j] - matrix1[(i - 1) * width + j - 1] - E[i * width + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matrix1;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Decompressor::decompress()
|
||||
{
|
||||
|
||||
int hight = reader.readShort();
|
||||
int first = reader.readByte();
|
||||
int last = reader.readInt();
|
||||
int size = reader.readInt();
|
||||
int width = size / hight;
|
||||
|
||||
std::vector<int> C(size, 0);
|
||||
C[0] = first;
|
||||
C[size - 1] = last;
|
||||
DEIC(C, 0, size - 1);
|
||||
|
||||
std::vector<int> N(size, 0);
|
||||
N[0] = C[0];
|
||||
for (size_t i = 1; i < size; i++)
|
||||
{
|
||||
N[i] = C[i] - C[i - 1];
|
||||
}
|
||||
|
||||
std::vector<int> E(size, 0);
|
||||
E[0] = N[0];
|
||||
|
||||
for (size_t i = 1; i < size; i++)
|
||||
{
|
||||
if (N[i] % 2 == 0)
|
||||
{
|
||||
E[i] = N[i] / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
E[i] = -((N[i] + 1) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
return predictInvers(E, width, hight);
|
||||
}
|
BIN
semester_5/racunalniska_vecpredstavnost/vaja_3/Navodila_MDCT.pdf
Normal file
BIN
semester_5/racunalniska_vecpredstavnost/vaja_3/Navodila_MDCT.pdf
Normal file
Binary file not shown.
BIN
semester_5/racunalniska_vecpredstavnost/vaja_3/RV - Vaja 3.pdf
Normal file
BIN
semester_5/racunalniska_vecpredstavnost/vaja_3/RV - Vaja 3.pdf
Normal file
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
#include <string>
|
||||
#include "utils.hpp"
|
||||
|
||||
class Compressor
|
||||
{
|
||||
BitWriter writer;
|
||||
|
||||
public:
|
||||
Compressor() = default;
|
||||
~Compressor() = default;
|
||||
void compress(const short *samples_p, std::size_t sampleCount, int N, int M, const char *filename);
|
||||
void write_blocks(std::vector<std::vector<float>> &mdct_blocks, int M);
|
||||
void samples_to_blocks(std::vector<signed short> &samples, std::vector<std::vector<float>> &blocks, int N);
|
||||
void window(std::vector<std::vector<float>> &blocks, float N);
|
||||
void mdct(std::vector<std::vector<float>> &blocks, std::vector<std::vector<float>> &mdct_blocks, float N);
|
||||
};
|
@@ -0,0 +1,14 @@
|
||||
#include "utils.hpp"
|
||||
|
||||
class Decompressor
|
||||
{
|
||||
private:
|
||||
BitReader reader;
|
||||
|
||||
public:
|
||||
Decompressor() = default;
|
||||
~Decompressor() = default;
|
||||
|
||||
std::vector<signed short> decompress(const char *filename);
|
||||
void read_blocks(std::vector<std::vector<float>> &mdct_blocks, int M);
|
||||
};
|
410
semester_5/racunalniska_vecpredstavnost/vaja_3/include/utils.hpp
Normal file
410
semester_5/racunalniska_vecpredstavnost/vaja_3/include/utils.hpp
Normal file
@@ -0,0 +1,410 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
#define VECTOR_UTILS
|
||||
#define BUFFER
|
||||
#define BIT_READER
|
||||
#define BIT_WRITER
|
||||
#define EXECUTE_COMAND
|
||||
*/
|
||||
|
||||
#ifndef NIKOLA_UTILS
|
||||
#define NIKOLA_UTILS
|
||||
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
unsigned char *buffer = nullptr;
|
||||
size_t taken = 0;
|
||||
size_t size = 0;
|
||||
std::string file_path;
|
||||
|
||||
Buffer(size_t size);
|
||||
Buffer();
|
||||
~Buffer();
|
||||
bool resize(size_t new_size);
|
||||
int add_end(unsigned char *data, size_t data_size);
|
||||
int add_middle(unsigned char *data, size_t data_size, size_t index);
|
||||
void copy(Buffer &other);
|
||||
|
||||
// Removes data from buffer without checking if it's in the buffer
|
||||
void remove_fast(unsigned char *data, size_t data_size);
|
||||
|
||||
void remove(size_t index, size_t data_size);
|
||||
|
||||
int find(unsigned char *data, size_t data_size);
|
||||
|
||||
void remove(unsigned char *data, size_t data_size);
|
||||
|
||||
void clear() { taken = 0; }
|
||||
|
||||
bool save_to_file();
|
||||
bool save_to_file(std::string file_path);
|
||||
|
||||
bool load_from_file();
|
||||
bool load_from_file(std::string file_path);
|
||||
};
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
int k = 8;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
size_t pos = 0;
|
||||
long readNBits(int n);
|
||||
float readFloat();
|
||||
long readLong();
|
||||
int readInt();
|
||||
short readShort();
|
||||
char readByte();
|
||||
bool readBit();
|
||||
};
|
||||
|
||||
class BitWriter
|
||||
{
|
||||
public:
|
||||
int k = 0;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
void writeNBits(long value, int n);
|
||||
void writeFloat(float v);
|
||||
void writeLong(long v);
|
||||
void writeInt(int v);
|
||||
void writeShort(short v);
|
||||
void writeByte(char v);
|
||||
void writeBit(bool b);
|
||||
void finish();
|
||||
};
|
||||
|
||||
std::optional<std::string> exec(const char *cmd);
|
||||
|
||||
void print_vec(std::vector<short> &vec, int wrap = 5);
|
||||
void print_matrix(std::vector<std::vector<float>> &vec);
|
||||
|
||||
#ifdef NIKOLA_UTILS_IMPLEMENTATION
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
buffer = nullptr;
|
||||
size = 0;
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
Buffer::Buffer(size_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->buffer = new unsigned char[size];
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
if (buffer)
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool Buffer::resize(size_t new_size)
|
||||
{
|
||||
if (size >= new_size)
|
||||
return true;
|
||||
if (new_size < size * 2)
|
||||
new_size = size * 2;
|
||||
unsigned char *new_buffer = (unsigned char *)realloc(buffer, new_size);
|
||||
if (!new_buffer)
|
||||
{
|
||||
printf("Error resizing buffer\n");
|
||||
return false;
|
||||
}
|
||||
buffer = new_buffer;
|
||||
size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Buffer::add_end(unsigned char *data, size_t data_size)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
|
||||
memcpy(buffer + taken, data, data_size);
|
||||
taken += data_size;
|
||||
return taken - data_size;
|
||||
}
|
||||
|
||||
int Buffer::add_middle(unsigned char *data, size_t data_size, size_t index)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
memmove(buffer + index + data_size, buffer + index, taken - index);
|
||||
memcpy(buffer + index, data, data_size);
|
||||
taken += data_size;
|
||||
return index;
|
||||
}
|
||||
|
||||
void Buffer::copy(Buffer &other)
|
||||
{
|
||||
if (other.size > size)
|
||||
if (!resize(other.size))
|
||||
return;
|
||||
memcpy(buffer, other.buffer, other.taken);
|
||||
taken = other.taken;
|
||||
}
|
||||
|
||||
void Buffer::remove_fast(unsigned char *data, size_t data_size)
|
||||
{
|
||||
int64_t index = data - buffer;
|
||||
if (index < 0 || index > taken || index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
void Buffer::remove(size_t index, size_t data_size)
|
||||
{
|
||||
if (index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
int Buffer::find(unsigned char *data, size_t data_size)
|
||||
{
|
||||
for (int i = 0; i < taken; i++)
|
||||
if (memcmp(buffer + i, data, data_size) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Buffer::remove(unsigned char *data, size_t data_size)
|
||||
{
|
||||
int index = find(data, data_size);
|
||||
if (index == -1)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
remove(index, data_size);
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file()
|
||||
{
|
||||
std::ofstream file(this->file_path, std::ios::binary | std::ios::out);
|
||||
if (!file.is_open())
|
||||
{
|
||||
printf("Error saving file\n");
|
||||
return false;
|
||||
}
|
||||
file.write((char *)this->buffer, this->taken);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return save_to_file();
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file()
|
||||
{
|
||||
std::ifstream file(this->file_path, std::ios::binary | std::ios::in);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
|
||||
size_t file_size = file.tellg();
|
||||
resize(file_size);
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read((char *)buffer, size);
|
||||
|
||||
if (file)
|
||||
taken = file_size;
|
||||
else
|
||||
taken = file.gcount();
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return load_from_file();
|
||||
}
|
||||
|
||||
long BitReader::readNBits(int n)
|
||||
{
|
||||
long ret = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
ret |= readBit() << i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
float BitReader::readFloat()
|
||||
{
|
||||
float ret = *(float *)&buffer.buffer[pos];
|
||||
pos += sizeof(float);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long BitReader::readLong()
|
||||
{
|
||||
long ret = *(long *)&buffer.buffer[pos];
|
||||
pos += sizeof(long);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BitReader::readInt()
|
||||
{
|
||||
int ret = *(int *)&buffer.buffer[pos];
|
||||
pos += sizeof(int);
|
||||
return ret;
|
||||
}
|
||||
|
||||
short BitReader::readShort()
|
||||
{
|
||||
short ret = *(short *)&buffer.buffer[pos];
|
||||
pos += sizeof(short);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char BitReader::readByte()
|
||||
{
|
||||
x = buffer.buffer[pos];
|
||||
pos += sizeof(char);
|
||||
return x;
|
||||
}
|
||||
|
||||
bool BitReader::readBit()
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
readByte();
|
||||
k = 0;
|
||||
}
|
||||
bool b = (x >> k) & 1;
|
||||
k++;
|
||||
return b;
|
||||
}
|
||||
|
||||
void BitWriter::writeByte(char v)
|
||||
{
|
||||
buffer.add_end((unsigned char *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void BitWriter::writeNBits(long value, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
writeBit(value & (1 << i));
|
||||
}
|
||||
}
|
||||
|
||||
void BitWriter::writeFloat(float v)
|
||||
{
|
||||
buffer.add_end((unsigned char *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void BitWriter::writeLong(long v)
|
||||
{
|
||||
buffer.add_end((unsigned char *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void BitWriter::writeInt(int v)
|
||||
{
|
||||
buffer.add_end((unsigned char *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void BitWriter::writeShort(short v)
|
||||
{
|
||||
buffer.add_end((unsigned char *)&v, sizeof(v));
|
||||
}
|
||||
|
||||
void BitWriter::writeBit(bool b)
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
writeByte(x);
|
||||
k = 0;
|
||||
x = 0;
|
||||
}
|
||||
x ^= (-b ^ x) & (1 << k);
|
||||
k++;
|
||||
}
|
||||
|
||||
void BitWriter::finish()
|
||||
{
|
||||
if (k > 0)
|
||||
writeByte(x);
|
||||
}
|
||||
|
||||
std::optional<std::string> exec(const char *cmd)
|
||||
{
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
FILE *pipe = popen(cmd, "r");
|
||||
if (!pipe)
|
||||
return std::nullopt;
|
||||
|
||||
try
|
||||
{
|
||||
while (fgets(buffer, sizeof buffer, pipe) != NULL)
|
||||
result += buffer;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pclose(pipe);
|
||||
return std::nullopt;
|
||||
}
|
||||
pclose(pipe);
|
||||
return result;
|
||||
}
|
||||
|
||||
void print_vec(std::vector<short> &vec, int wrap)
|
||||
{
|
||||
for (size_t i = 0; i < vec.size(); i++)
|
||||
{
|
||||
printf("%2d ", vec[i]);
|
||||
if (i % wrap == wrap - 1)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_matrix(std::vector<std::vector<float>> &vec)
|
||||
{
|
||||
for (size_t i = 0; i < vec.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < vec[i].size(); j++)
|
||||
{
|
||||
printf("%f ", vec[i][j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif // NIKOLA_UTILS_IMPLEMENTATION
|
||||
|
||||
#endif // NIKOLA_UTILS
|
68
semester_5/racunalniska_vecpredstavnost/vaja_3/main.cpp
Normal file
68
semester_5/racunalniska_vecpredstavnost/vaja_3/main.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <SFML/Audio.hpp>
|
||||
|
||||
#define NIKOLA_UTILS_IMPLEMENTATION
|
||||
#include "utils.hpp"
|
||||
|
||||
#include "Compressor.hpp"
|
||||
#include "Decompressor.hpp"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc <= 2)
|
||||
{
|
||||
printf("Usage: %s <1|2>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (std::atoi(argv[1]) == 1)
|
||||
{
|
||||
if (argc != 6)
|
||||
{
|
||||
printf("Usage: %s 1 <input.wav> <block size> <window size> <output.bin>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sf::SoundBuffer buffer;
|
||||
|
||||
if (!buffer.loadFromFile(argv[2]))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::size_t sampleCount = buffer.getSampleCount();
|
||||
const sf::Int16 *samples_p = buffer.getSamples();
|
||||
Compressor compressor;
|
||||
compressor.compress(samples_p, sampleCount, std::atoi(argv[3]), std::atoi(argv[4]), argv[5]);
|
||||
printf("compressed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (argc != 4)
|
||||
{
|
||||
printf("Usage: %s 2 <input.bin> <output.wav>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
Decompressor decompressor;
|
||||
std::vector<signed short> out = decompressor.decompress(argv[2]);
|
||||
|
||||
sf::SoundBuffer buffer2;
|
||||
buffer2.loadFromSamples(&out[0], out.size(), 2, 44100);
|
||||
buffer2.saveToFile(argv[3]);
|
||||
sf::Sound sound(buffer2);
|
||||
|
||||
sound.play();
|
||||
while (sound.getStatus() == sf::Sound::Playing)
|
||||
{
|
||||
sf::sleep(sf::milliseconds(1000));
|
||||
sf::Time t = sound.getPlayingOffset();
|
||||
printf("\rplaying offset: %f", t.asSeconds());
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
33
semester_5/racunalniska_vecpredstavnost/vaja_3/makefile
Normal file
33
semester_5/racunalniska_vecpredstavnost/vaja_3/makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
CC=g++
|
||||
|
||||
CFLAGS= -std=c++23
|
||||
|
||||
INCLUDE_DIR= include
|
||||
|
||||
SRC_DIR= src
|
||||
|
||||
# Get all cpp files from src directory
|
||||
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
|
||||
|
||||
# Get all header files from include directory
|
||||
HDRS := $(wildcard $(INCLUDE_DIR)/*.h)
|
||||
|
||||
all: main com
|
||||
|
||||
main: main.cpp $(SRCS) $(HDRS)
|
||||
$(CC) $(CFLAGS) -O3 -I$(INCLUDE_DIR) $(SRCS) main.cpp -o main -lsfml-audio -lsfml-system
|
||||
|
||||
debug: main.cpp $(SRCS) $(HDRS)
|
||||
$(CC) $(CFLAGS) -I$(INCLUDE_DIR) $(SRCS) -g main.cpp -o main
|
||||
|
||||
com: main
|
||||
./main 1 song.wav 4 3 out.bin
|
||||
|
||||
dec: main
|
||||
./main 2 out.bin out.wav
|
||||
|
||||
zip:
|
||||
zip -r main.zip main.cpp $(INCLUDE_DIR) $(SRC_DIR) makefile
|
||||
|
||||
clean:
|
||||
rm main out.* *.bin *.zip
|
@@ -0,0 +1,127 @@
|
||||
#include "Compressor.hpp"
|
||||
#include <numbers>
|
||||
#include <cmath>
|
||||
|
||||
void Compressor::samples_to_blocks(std::vector<signed short> &samples, std::vector<std::vector<float>> &blocks, int N)
|
||||
{
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
blocks[0][i + N] = samples[i];
|
||||
}
|
||||
|
||||
for (int i = N, pos = 1; i < samples.size(); i += N, pos++)
|
||||
{
|
||||
for (int j = -N; j < N; j++)
|
||||
{
|
||||
blocks[pos][j + N] = samples[i + j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = samples.size() - N, j = 0; i < samples.size(); i++, j++)
|
||||
{
|
||||
blocks[blocks.size() - 1][j] = samples[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Compressor::window(std::vector<std::vector<float>> &blocks, float N)
|
||||
{
|
||||
std::vector<float> window(N * 2, 0);
|
||||
|
||||
float a = 0;
|
||||
for (int i = 0; i < window.size(); i++, a += 1.0)
|
||||
{
|
||||
window[i] = std::sin((std::numbers::pi / (2 * N)) * (a + 0.5));
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < blocks[i].size(); j++)
|
||||
{
|
||||
blocks[i][j] *= window[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Compressor::mdct(std::vector<std::vector<float>> &blocks, std::vector<std::vector<float>> &mdct_blocks, float N)
|
||||
{
|
||||
|
||||
std::vector<std::vector<float>> cos_vals(N, std::vector<float>(N * 2, 0));
|
||||
|
||||
float k = 0;
|
||||
for (int i = 0; i < N; i++, k++)
|
||||
{
|
||||
float n = 0;
|
||||
for (int j = 0; j < N * 2; j++, n++)
|
||||
{
|
||||
cos_vals[i][j] = std::cos((std::numbers::pi / N) * (n + 0.5 + N / 2) * (k + 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < N; j++)
|
||||
{
|
||||
float tmp = 0;
|
||||
for (int k = 0; k < N * 2; k++)
|
||||
{
|
||||
tmp += blocks[i][k] * cos_vals[j][k];
|
||||
}
|
||||
mdct_blocks[i][j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Compressor::compress(const short *samples_p, std::size_t sampleCount, int N, int M, const char *filename)
|
||||
{
|
||||
|
||||
std::vector<signed short> left(sampleCount / 2);
|
||||
std::vector<signed short> right(sampleCount / 2);
|
||||
for (size_t i = 0, j = 0; i < sampleCount; i += 2, j++)
|
||||
{
|
||||
left[j] = samples_p[i];
|
||||
right[j] = samples_p[i + 1];
|
||||
}
|
||||
|
||||
std::vector<std::vector<float>> blocks(left.size() / N + 1, std::vector<float>(N * 2, 0));
|
||||
std::vector<std::vector<float>> mdct_blocks(blocks.size(), std::vector<float>(N, 0));
|
||||
|
||||
writer.writeLong(sampleCount);
|
||||
writer.writeInt(N);
|
||||
writer.writeInt(M);
|
||||
|
||||
samples_to_blocks(left, blocks, N);
|
||||
window(blocks, N);
|
||||
mdct(blocks, mdct_blocks, N);
|
||||
write_blocks(mdct_blocks, M);
|
||||
|
||||
samples_to_blocks(right, blocks, N);
|
||||
window(blocks, N);
|
||||
|
||||
mdct(blocks, mdct_blocks, N);
|
||||
|
||||
write_blocks(mdct_blocks, M);
|
||||
|
||||
writer.finish();
|
||||
writer.buffer.save_to_file(filename);
|
||||
}
|
||||
|
||||
void Compressor::write_blocks(std::vector<std::vector<float>> &mdct_blocks, int M)
|
||||
{
|
||||
for (int i = 0; i < mdct_blocks.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < M; j++)
|
||||
{
|
||||
// writer.writeFloat(mdct_blocks[i][j]);
|
||||
// printf("%f ", mdct_blocks[i][j]);
|
||||
|
||||
long x = std::lround(mdct_blocks[i][j]);
|
||||
bool is_negative = x < 0;
|
||||
x = std::abs(x);
|
||||
int bits = std::ceil(std::log2(x + 1));
|
||||
writer.writeNBits(bits, 6);
|
||||
writer.writeBit(is_negative);
|
||||
writer.writeNBits(x, bits);
|
||||
// printf("%ld %d %d\n", x, is_negative, bits);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "Decompressor.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
void imdct(std::vector<std::vector<float>> &mdct_blocks, std::vector<std::vector<float>> &blocks, float N)
|
||||
{
|
||||
std::vector<std::vector<float>> cos_vals(N * 2, std::vector<float>(N, 0));
|
||||
|
||||
float n = 0;
|
||||
for (int i = 0; i < N * 2; i++, n++)
|
||||
{
|
||||
float k = 0;
|
||||
for (int j = 0; j < N; j++, k++)
|
||||
{
|
||||
cos_vals[i][j] = std::cos((std::numbers::pi / N) * (n + 0.5 + N / 2) * (k + 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks.size(); i++)
|
||||
{
|
||||
for (int k = 0; k < N * 2; k++)
|
||||
{
|
||||
float tmp = 0;
|
||||
for (int j = 0; j < N; j++)
|
||||
{
|
||||
tmp += mdct_blocks[i][j] * cos_vals[k][j];
|
||||
}
|
||||
blocks[i][k] = tmp * (2 / N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void window(std::vector<std::vector<float>> &blocks, float N)
|
||||
{
|
||||
std::vector<float> window(N * 2, 0);
|
||||
|
||||
float a = 0;
|
||||
for (int i = 0; i < window.size(); i++, a += 1.0)
|
||||
{
|
||||
window[i] = std::sin((std::numbers::pi / (2 * N)) * (a + 0.5));
|
||||
}
|
||||
|
||||
for (int i = 0; i < blocks.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < blocks[i].size(); j++)
|
||||
{
|
||||
blocks[i][j] *= window[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void recunstruct(std::vector<std::vector<float>> &blocks, std::vector<signed short> &samples, int N)
|
||||
{
|
||||
std::size_t p = 0;
|
||||
for (std::size_t i = 1; i < blocks.size(); i++)
|
||||
{
|
||||
for (std::size_t j = 0; j < N; j++)
|
||||
{
|
||||
samples[(i - 1) * N + j] = std::lround(blocks[i - 1][j + N] + blocks[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<signed short> Decompressor::decompress(const char *filename)
|
||||
{
|
||||
reader.buffer.load_from_file(filename);
|
||||
|
||||
std::size_t sampleCount = reader.readLong();
|
||||
int N = reader.readInt();
|
||||
int M = reader.readInt();
|
||||
|
||||
std::vector<std::vector<float>> mdct_blocks(sampleCount / 2 / N + 1, std::vector<float>(N, 0));
|
||||
std::vector<std::vector<float>> blocks(sampleCount / 2 / N + 1, std::vector<float>(N * 2, 0));
|
||||
|
||||
std::vector<signed short> tmp(sampleCount / 2);
|
||||
std::vector<signed short> samples(sampleCount);
|
||||
|
||||
read_blocks(mdct_blocks, M);
|
||||
imdct(mdct_blocks, blocks, N);
|
||||
window(blocks, N);
|
||||
recunstruct(blocks, tmp, N);
|
||||
|
||||
for (size_t i = 0, j = 0; i < sampleCount; i += 2, j++)
|
||||
{
|
||||
samples[i] = tmp[j];
|
||||
}
|
||||
|
||||
read_blocks(mdct_blocks, M);
|
||||
imdct(mdct_blocks, blocks, N);
|
||||
|
||||
window(blocks, N);
|
||||
|
||||
recunstruct(blocks, tmp, N);
|
||||
|
||||
for (size_t i = 1, j = 0; i < sampleCount; i += 2, j++)
|
||||
{
|
||||
samples[i] = tmp[j];
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
void Decompressor::read_blocks(std::vector<std::vector<float>> &mdct_blocks, int M)
|
||||
{
|
||||
for (int i = 0; i < mdct_blocks.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < M; j++)
|
||||
{
|
||||
// mdct_blocks[i][j] = reader.readFloat();
|
||||
// printf("%f ", mdct_blocks[i][j]);
|
||||
|
||||
long bits = reader.readNBits(6);
|
||||
bool is_negative = reader.readBit();
|
||||
long x = reader.readNBits(bits);
|
||||
// printf("%ld %d %d\n", x, is_negative, bits);
|
||||
(is_negative) ? x = -x : x = x;
|
||||
mdct_blocks[i][j] = x;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user