consolidate all repos to one for archive

This commit is contained in:
2025-01-28 13:46:42 +01:00
commit a6610fbc7a
5350 changed files with 2705721 additions and 0 deletions

View File

@@ -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);
};

View File

@@ -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);
};

View 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

View 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;
}

View 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

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}