working dos vga writes!
This commit is contained in:
1 parent
5789cafd4e
commit
55ac075e4d
25 files changed
+454
-149
No files matched your search
@@ -14,5 +14,6 @@ Player/player
|
|||||||
Player/player.wasm
|
Player/player.wasm
|
||||||
Player/Cosmo
|
Player/Cosmo
|
||||||
Master/master
|
Master/master
|
||||||
|
Tools/assets
|
||||||
|
|
||||||
Player/Out/Cosmo/player*
|
Player/Out/Cosmo/player*
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
Simple fixed point bitcrash.
|
||||||
|
https://github.com/schollz/fpfx
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COM_SND_BITCRSH_H
|
||||||
|
#define COM_SND_BITCRSH_H
|
||||||
|
|
||||||
|
#include "../fix.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct com_snd_bitcrsh {
|
||||||
|
uint8_t bits; /* How much to trim when triggered. */
|
||||||
|
uint8_t reduce; /* Every Nth sample frame. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void com_snd_bitcrsh_process(Bitcrush *bitcrush, int32_t *buf,
|
||||||
|
unsigned int nr_samples) {
|
||||||
|
for (int i = 0; i < nr_samples; i++) {
|
||||||
|
if (i % bitcrush->reduce == 0) {
|
||||||
|
// bitcrush fixedpoint
|
||||||
|
buf[i] = buf[i] >> (16 - bitcrush->bits) << (16 - bitcrush->bits);
|
||||||
|
} else {
|
||||||
|
buf[i] = buf[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Dinky fixed point oscillators.
|
||||||
|
https://git.poto.cafe/veclavtalica/stfu/src/branch/master/Source/oscillators.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COM_SND_OSCS_H
|
||||||
|
#define COM_SND_OSCS_H
|
||||||
|
|
||||||
|
#include "../cfg.h"
|
||||||
|
#include "../fix.h"
|
||||||
|
#include "../std.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Intended to be executed offline with values then embedded in the binary. */
|
||||||
|
struct com_snd_swave {
|
||||||
|
uint16_t f, s, c;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct com_snd_swave
|
||||||
|
com_snd_swave_init(com_fix_t frequency, uint16_t phase, uint16_t amplitude) {
|
||||||
|
com_std_assert(frequency > 0);
|
||||||
|
struct com_snd_swave r;
|
||||||
|
r.f = 2.f * sinf((float)M_PI * frequency / STFU_AUDIO_FRAME_RATE);
|
||||||
|
r.s = amplitude * sinf(phase);
|
||||||
|
r.c = amplitude * cosf(phase);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int16_t com_snd_swave_pump(struct com_snd_swave *wave) {
|
||||||
|
int16_t const f = com_fix_sin(com_fix_mul(
|
||||||
|
wave->phase, com_fix_div(com_fix_mul(wave->frequency, COM_FIX_PI2),
|
||||||
|
COM_CFG_SNDFRMRATE)));
|
||||||
|
wave->phase += 1;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implemented over sinewave */
|
||||||
|
// struct com_snd_oscs_sqrtwave {
|
||||||
|
// struct com_snd_swave w;
|
||||||
|
// union {
|
||||||
|
// float f;
|
||||||
|
// uint32_t u;
|
||||||
|
// } v;
|
||||||
|
// } com_snd_oscs_init_sqrtwave(float frequency, float phase, float amplitude) {
|
||||||
|
// struct com_snd_oscs_sqrtwave r;
|
||||||
|
// union {
|
||||||
|
// float f;
|
||||||
|
// uint32_t u;
|
||||||
|
// } v, a;
|
||||||
|
// r.w = com_snd_oscs_init_sinewave(frequency, phase, 1.f);
|
||||||
|
// v.f = r.w.s;
|
||||||
|
// a.f = amplitude;
|
||||||
|
// r.v.u = (a.u & 0x7fffffff) | (v.u & 0x80000000);
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* Use floating point bit representation to infer sign, all other bits are
|
||||||
|
// set
|
||||||
|
// * to amplitude */
|
||||||
|
// struct com_snd_oscs_sqrtwave
|
||||||
|
// com_snd_oscs_pump_sqrtwave(struct com_snd_oscs_sqrtwave wave) {
|
||||||
|
// union {
|
||||||
|
// float f;
|
||||||
|
// uint32_t u;
|
||||||
|
// } v;
|
||||||
|
// com_snd_oscs_pump_sinewave(wave.w);
|
||||||
|
// v.f = wave.w.s;
|
||||||
|
// wave.v.u = (wave.v.u & 0x7fffffff) | (v.u & 0x80000000);
|
||||||
|
// return wave;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// struct com_snd_oscs_sawtooth {
|
||||||
|
// float v, a, i;
|
||||||
|
// } com_snd_oscs_init_sawtooth(float frequency, float phase, float amplitude) {
|
||||||
|
// struct com_snd_oscs_sawtooth r;
|
||||||
|
// r.v = sinf(phase) * amplitude;
|
||||||
|
// r.a = amplitude;
|
||||||
|
// r.i = 2.f * frequency / STFU_AUDIO_FRAME_RATE * amplitude;
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* Simple amplitude overflow check with truncation */
|
||||||
|
// struct com_snd_oscs_sawtooth
|
||||||
|
// com_snd_oscs_pump_sawtooth(struct com_snd_oscs_sawtooth wave) {
|
||||||
|
// wave.v += wave.i;
|
||||||
|
// if (wave.v > wave.a)
|
||||||
|
// wave.v -= wave.a * 2.f;
|
||||||
|
// return wave;
|
||||||
|
// }
|
||||||
|
|
||||||
|
#endif
|
||||||
+2
-1
@@ -1,5 +1,4 @@
|
|||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
#include "any.c"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -10,6 +9,8 @@
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <tgmath.h>
|
#include <tgmath.h>
|
||||||
|
|
||||||
|
#include "any.c"
|
||||||
|
|
||||||
void *com_std_alloc(void *ptr, size_t size) {
|
void *com_std_alloc(void *ptr, size_t size) {
|
||||||
return size != 0 ? realloc(ptr, size) : (free(ptr), NULL);
|
return size != 0 ? realloc(ptr, size) : (free(ptr), NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ size_t strlen(char const *s) {
|
|||||||
return p - s;
|
return p - s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if COM_DEF_CPU == COM_DEF_CPU_AMD64 || COM_DEF_CPU == COM_DEF_CPU_X86
|
||||||
|
|
||||||
double sin(double v) {
|
double sin(double v) {
|
||||||
double r;
|
double r;
|
||||||
__asm__ __volatile__("fsin" : "=t"(r) : "0"(v));
|
__asm__ __volatile__("fsin" : "=t"(r) : "0"(v));
|
||||||
@@ -49,3 +51,17 @@ double sqrt(double v) {
|
|||||||
__asm__ volatile("sqrtss %1, %0" : "=x"(r) : "x"(v));
|
__asm__ volatile("sqrtss %1, %0" : "=x"(r) : "x"(v));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
double sin(double v) { return __builtin_sin(v); }
|
||||||
|
|
||||||
|
double cos(double v) { return __builtin_cos(v); }
|
||||||
|
|
||||||
|
void sincos(double v, double *s, double *c) {
|
||||||
|
return __builtin_sincos(v, s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
double sqrt(double v) { return __builtin_sqrt(v); }
|
||||||
|
|
||||||
|
#endif
|
||||||
+2
-12
@@ -1,23 +1,13 @@
|
|||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
|
|
||||||
#include "any.c"
|
#include "any.c"
|
||||||
|
#include "nolibc.c"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void *com_std_alloc(void *ptr, size_t size) { return NULL; }
|
void *com_std_alloc(void *ptr, size_t size) { return NULL; }
|
||||||
|
|
||||||
double com_std_sqrt(double v) { return __builtin_sqrt(v); }
|
|
||||||
double com_std_fabs(double v) { return __builtin_fabs(v); }
|
|
||||||
#if COM_DEF_COMPILER == COM_DEF_COMPILER_CLANG
|
|
||||||
double com_std_sin(double v) { return __builtin_sin(v); }
|
|
||||||
double com_std_cos(double v) { return __builtin_cos(v); }
|
|
||||||
#else
|
|
||||||
/* TODO: Use fsin/fcos, no matter how slow. */
|
|
||||||
double com_std_sin(double v) { return 0; }
|
|
||||||
double com_std_cos(double v) { return 0; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
com_std_fd com_std_open(char const *path, uint32_t flags) { return NULL; }
|
com_std_fd com_std_open(char const *path, uint32_t flags) { return NULL; }
|
||||||
bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) {
|
bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) {
|
||||||
return false;
|
return false;
|
||||||
@@ -28,7 +18,7 @@ com_std_fd com_std_socket(bool isnetwork) { return NULL; }
|
|||||||
bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) {
|
bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void com_std_exit(uint32_t status) {
|
void com_std_exit(int32_t status) {
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
while (1) {
|
while (1) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Centralized benchmark suite.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fix.h"
|
||||||
|
#include "std.h"
|
||||||
|
#include "time.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define TEST(p_e) \
|
||||||
|
do { \
|
||||||
|
if (!(p_e)) { \
|
||||||
|
com_std_print('c', COM_DEF_STRLIT(p_e) " failed!"); \
|
||||||
|
anyfail = true; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void com_bnch_fix(void) {
|
||||||
|
uint64_t start = com_timer_count_ns();
|
||||||
|
for (int i = 5000000; i--;) {
|
||||||
|
com_fix_t sqrt = com_fix_sqrt(i);
|
||||||
|
com_def_profile_sink(sqrt);
|
||||||
|
}
|
||||||
|
com_timer_profile(start, "fixed: sqrt");
|
||||||
|
|
||||||
|
start = com_timer_count_ns();
|
||||||
|
for (int i = 50000000; i--;) {
|
||||||
|
com_fix_t sin = com_fix_sin(i);
|
||||||
|
com_def_profile_sink(sin);
|
||||||
|
}
|
||||||
|
com_timer_profile(start, "fixed: sin");
|
||||||
|
|
||||||
|
start = com_timer_count_ns();
|
||||||
|
for (int i = 50000000; i--;) {
|
||||||
|
com_fix_t cos = com_fix_cos(i);
|
||||||
|
com_def_profile_sink(cos);
|
||||||
|
}
|
||||||
|
com_timer_profile(start, "fixed: cos");
|
||||||
|
|
||||||
|
start = com_timer_count_ns();
|
||||||
|
for (int i = 50000000; i--;) {
|
||||||
|
com_fix_t sin, cos;
|
||||||
|
com_fix_sincos(i, &sin, &cos);
|
||||||
|
com_fix_t sinv = sin;
|
||||||
|
com_fix_t cosv = cos;
|
||||||
|
com_def_profile_sink(sinv);
|
||||||
|
com_def_profile_sink(cosv);
|
||||||
|
}
|
||||||
|
com_timer_profile(start, "fixed: sincos");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void com_bnch_run(void) { com_bnch_fix(); }
|
||||||
|
|
||||||
|
#undef TEST
|
||||||
@@ -19,4 +19,9 @@
|
|||||||
|
|
||||||
#define COM_CFG_FBSIZE (COM_CFG_WIDTH * COM_CFG_HEIGHT * COM_CFG_COLORS)
|
#define COM_CFG_FBSIZE (COM_CFG_WIDTH * COM_CFG_HEIGHT * COM_CFG_COLORS)
|
||||||
|
|
||||||
|
#define COM_CFG_SNDFRMRATE 44100
|
||||||
|
|
||||||
|
/* TODO: Generate file with precompiled note frequencies. */
|
||||||
|
#define COM_CFG_A4FIX (440 << COM_FIX_FRACBITS)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -70,37 +70,3 @@ com_fix_t com_fix_sqrt(com_fix_t a) {
|
|||||||
return final_shift > 0 ? (int32_t)(x << final_shift)
|
return final_shift > 0 ? (int32_t)(x << final_shift)
|
||||||
: (int32_t)(x >> (-final_shift));
|
: (int32_t)(x >> (-final_shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
void com_fix_run_bench(void) {
|
|
||||||
uint64_t start = com_timer_count_ns();
|
|
||||||
for (int i = 5000000; i--;) {
|
|
||||||
com_fix_t sqrt = com_fix_sqrt(i);
|
|
||||||
com_def_profile_sink(sqrt);
|
|
||||||
}
|
|
||||||
com_timer_profile(start, "fixed: sqrt");
|
|
||||||
|
|
||||||
start = com_timer_count_ns();
|
|
||||||
for (int i = 50000000; i--;) {
|
|
||||||
com_fix_t sin = com_fix_sin(i);
|
|
||||||
com_def_profile_sink(sin);
|
|
||||||
}
|
|
||||||
com_timer_profile(start, "fixed: sin");
|
|
||||||
|
|
||||||
start = com_timer_count_ns();
|
|
||||||
for (int i = 50000000; i--;) {
|
|
||||||
com_fix_t cos = com_fix_cos(i);
|
|
||||||
com_def_profile_sink(cos);
|
|
||||||
}
|
|
||||||
com_timer_profile(start, "fixed: cos");
|
|
||||||
|
|
||||||
start = com_timer_count_ns();
|
|
||||||
for (int i = 50000000; i--;) {
|
|
||||||
com_fix_t sin, cos;
|
|
||||||
com_fix_sincos(i, &sin, &cos);
|
|
||||||
com_fix_t sinv = sin;
|
|
||||||
com_fix_t cosv = cos;
|
|
||||||
com_def_profile_sink(sinv);
|
|
||||||
com_def_profile_sink(cosv);
|
|
||||||
}
|
|
||||||
com_timer_profile(start, "fixed: sincos");
|
|
||||||
}
|
|
||||||
+5
-5
@@ -23,9 +23,6 @@ typedef int32_t com_fix_t;
|
|||||||
|
|
||||||
extern const uint16_t com_fix_sin_lut[128];
|
extern const uint16_t com_fix_sin_lut[128];
|
||||||
|
|
||||||
void com_fix_run_tests(void);
|
|
||||||
void com_fix_run_bench(void);
|
|
||||||
|
|
||||||
static inline com_fix_t com_fix_add(com_fix_t a, com_fix_t b) { return a + b; }
|
static inline com_fix_t com_fix_add(com_fix_t a, com_fix_t b) { return a + b; }
|
||||||
|
|
||||||
static inline com_fix_t com_fix_sub(com_fix_t a, com_fix_t b) { return a - b; }
|
static inline com_fix_t com_fix_sub(com_fix_t a, com_fix_t b) { return a - b; }
|
||||||
@@ -64,6 +61,7 @@ static inline com_fix_t com_fix_floor(com_fix_t const a) {
|
|||||||
com_fix_t com_fix_sqrt(com_fix_t a);
|
com_fix_t com_fix_sqrt(com_fix_t a);
|
||||||
|
|
||||||
/* Approximated using LUT. */
|
/* Approximated using LUT. */
|
||||||
|
/* Integer part only houses sign. */
|
||||||
/* TODO: test whether linearly interpolated version could be default. */
|
/* TODO: test whether linearly interpolated version could be default. */
|
||||||
/* things like camera movement can be jarring if done without.*/
|
/* things like camera movement can be jarring if done without.*/
|
||||||
/* https://namoseley.wordpress.com/2015/07/26/sincos-generation-using-table-lookup-and-iterpolation/
|
/* https://namoseley.wordpress.com/2015/07/26/sincos-generation-using-table-lookup-and-iterpolation/
|
||||||
@@ -90,9 +88,11 @@ static inline com_fix_t com_fix_sin(com_fix_t q) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline com_fix_t com_fix_sin_from_lut(uint8_t l) {
|
||||||
|
return com_fix_sin_lut[l];
|
||||||
|
}
|
||||||
|
|
||||||
/* Implemented over sin, as to share one single LUT. */
|
/* Implemented over sin, as to share one single LUT. */
|
||||||
/* Additionally, optimizer probably can collapse some math for combined sincos
|
|
||||||
* case. */
|
|
||||||
static inline com_fix_t com_fix_cos(com_fix_t a) {
|
static inline com_fix_t com_fix_cos(com_fix_t a) {
|
||||||
return com_fix_sin(a + COM_FIX_PIHALF);
|
return com_fix_sin(a + COM_FIX_PIHALF);
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-14
@@ -6,6 +6,8 @@
|
|||||||
#ifndef COM_STD_H
|
#ifndef COM_STD_H
|
||||||
#define COM_STD_H
|
#define COM_STD_H
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -40,20 +42,6 @@ void com_std_close(com_std_fd fd);
|
|||||||
/* Note: Freeing is done by passing 0 size to pointer. */
|
/* Note: Freeing is done by passing 0 size to pointer. */
|
||||||
void *com_std_alloc(void *ptr, size_t size);
|
void *com_std_alloc(void *ptr, size_t size);
|
||||||
|
|
||||||
/* Note: Functions listed below are only available for dev builds. */
|
|
||||||
/* Trigonometry functions are for reference testing of our own fixed point
|
|
||||||
* implementations. Do not use otherwise. */
|
|
||||||
#define com_std_assert(p_h) \
|
|
||||||
do { \
|
|
||||||
if (!(p_h)) { \
|
|
||||||
const char msg[] = \
|
|
||||||
"Assertion failed at "__FILE__ \
|
|
||||||
":" COM_DEF_STRLIT(__LINE__) ": " COM_DEF_STRLIT(p_h); \
|
|
||||||
com_std_print_str(msg, sizeof msg, true); \
|
|
||||||
com_std_exit(-1); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Basic printing utility that doesn't utilize format string.
|
Basic printing utility that doesn't utilize format string.
|
||||||
Instead a vector of arguments is passed and concatenated, based on type.
|
Instead a vector of arguments is passed and concatenated, based on type.
|
||||||
@@ -81,9 +69,25 @@ void com_std_print_(int32_t start, ...);
|
|||||||
#define com_std_print(...) com_std_print_(__VA_ARGS__, '.')
|
#define com_std_print(...) com_std_print_(__VA_ARGS__, '.')
|
||||||
void com_std_print_str(char const *str, uint32_t len, bool newline);
|
void com_std_print_str(char const *str, uint32_t len, bool newline);
|
||||||
|
|
||||||
|
#define COM_STD_PIF ((float)3.14159265358979323846)
|
||||||
|
|
||||||
double com_std_sqrt(double v);
|
double com_std_sqrt(double v);
|
||||||
double com_std_fabs(double v);
|
double com_std_fabs(double v);
|
||||||
double com_std_sin(double v);
|
double com_std_sin(double v);
|
||||||
double com_std_cos(double v);
|
double com_std_cos(double v);
|
||||||
|
|
||||||
|
/* Note: Functions listed below are only available for dev builds. */
|
||||||
|
/* Trigonometry functions are for reference testing of our own fixed point
|
||||||
|
* implementations. Do not use otherwise. */
|
||||||
|
#define com_std_assert(p_h) \
|
||||||
|
do { \
|
||||||
|
if (!(p_h)) { \
|
||||||
|
const char msg[] = \
|
||||||
|
"Assertion failed at "__FILE__ \
|
||||||
|
":" COM_DEF_STRLIT(__LINE__) ": " COM_DEF_STRLIT(p_h); \
|
||||||
|
com_std_print_str(msg, sizeof msg, true); \
|
||||||
|
com_std_exit(-1); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+1
-1
@@ -49,7 +49,7 @@ static inline int32_t com_str_ext_find_char(char const *s, char ch) {
|
|||||||
static inline bool com_str_ext_prefixed(char const *__restrict a,
|
static inline bool com_str_ext_prefixed(char const *__restrict a,
|
||||||
struct com_str const *prefix) {
|
struct com_str const *prefix) {
|
||||||
uint32_t n = prefix->len;
|
uint32_t n = prefix->len;
|
||||||
char *b = prefix->data;
|
char const *b = prefix->data;
|
||||||
while (n && *a && (*a == *b)) {
|
while (n && *a && (*a == *b)) {
|
||||||
++a;
|
++a;
|
||||||
++b;
|
++b;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
/*
|
||||||
|
https://gist.github.com/takaswie/d8a9553c230971d974a3dfc759b2ff67
|
||||||
|
*/
|
||||||
+22
-31
@@ -1,3 +1,4 @@
|
|||||||
|
#include "../../Common/def.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -259,6 +260,17 @@ static inline bool set_segment_rights(uint16_t selector, bool read,
|
|||||||
return !carry_clear;
|
return !carry_clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline intptr_t get_segment_base_address(uint16_t selector) {
|
||||||
|
bool carry_clear;
|
||||||
|
uint16_t high, low;
|
||||||
|
__asm__ volatile("int $0x31"
|
||||||
|
: "=@ccnc"(carry_clear), "=c"(high), "=d"(low)
|
||||||
|
: "a"(0x0006), "b"(selector)
|
||||||
|
: "memory", "cc");
|
||||||
|
// return carry_clear ? 0 : (((intptr_t)high << 16) | (intptr_t)low);
|
||||||
|
return ((intptr_t)high << 16) | (intptr_t)low;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void use_segment(uint16_t selector) {
|
static inline void use_segment(uint16_t selector) {
|
||||||
__asm__ volatile("" : "=S"(selector)::);
|
__asm__ volatile("" : "=S"(selector)::);
|
||||||
}
|
}
|
||||||
@@ -271,40 +283,19 @@ static inline void print_to_console(char *const str) {
|
|||||||
|
|
||||||
static uint32_t test = 0x1420124;
|
static uint32_t test = 0x1420124;
|
||||||
|
|
||||||
// extern int plr_display_dos_main(int argc, char *argv[]) {
|
|
||||||
extern int plr_display_dos_main(void) {
|
extern int plr_display_dos_main(void) {
|
||||||
print_to_console("Fuck you stupid shit");
|
/* Fat DS trick, see __djgpp_nearptr_enable() */
|
||||||
return -1;
|
unsigned short ds_selector;
|
||||||
|
asm("movw %%ds, %0" : "=r"(ds_selector));
|
||||||
uint16_t base = alloc_ldt_descriptor();
|
set_segment_limit(ds_selector, 0xFFFFFFFF);
|
||||||
if (!base) {
|
intptr_t baseaddr = get_segment_base_address(ds_selector);
|
||||||
print_to_console("Cannot allocate LDT descriptor");
|
if (baseaddr == 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_segment_base_address(base, 0xA0000)) {
|
unsigned char *volatile buf =
|
||||||
print_to_console("Cannot set LDT base address");
|
(unsigned char *)((intptr_t)0xA0000 - baseaddr); // VGA memory address
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_segment_limit(base, 0x10000)) {
|
|
||||||
print_to_console("Cannot set LDT limit");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
use_segment(base);
|
|
||||||
|
|
||||||
// char *volatile buf = (void *)(intptr_t)0xA0000; // VGA memory address
|
|
||||||
// char *buf = map_physical_address(0xA0000, 0x10000); // VGA memory
|
|
||||||
char *buf = map_physical_address(0xA0000, 0x10000); // VGA memory
|
|
||||||
// address
|
|
||||||
if (!buf)
|
|
||||||
return -1;
|
|
||||||
int x, y;
|
|
||||||
|
|
||||||
// if (!buf)
|
|
||||||
// return -1;
|
|
||||||
|
|
||||||
|
/* TODO: Make VESA work for sweet sweet 640x480. */
|
||||||
// unsigned char saved_mode = get_video_mode(); // Save original mode
|
// unsigned char saved_mode = get_video_mode(); // Save original mode
|
||||||
// set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode
|
// set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode
|
||||||
set_video_mode(MODE_VGA_320_200_8); // Set our VGA mode
|
set_video_mode(MODE_VGA_320_200_8); // Set our VGA mode
|
||||||
@@ -327,6 +318,7 @@ extern int plr_display_dos_main(void) {
|
|||||||
// wait_for_key();
|
// wait_for_key();
|
||||||
// set_video_mode(saved_mode); // Restore original mode
|
// set_video_mode(saved_mode); // Restore original mode
|
||||||
|
|
||||||
|
int x, y;
|
||||||
while (1) {
|
while (1) {
|
||||||
for (y = 0; y < HEIGHT; y++) {
|
for (y = 0; y < HEIGHT; y++) {
|
||||||
for (x = 0; x < WIDTH; x++) {
|
for (x = 0; x < WIDTH; x++) {
|
||||||
@@ -339,7 +331,6 @@ extern int plr_display_dos_main(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// writetest();
|
// writetest();
|
||||||
__asm__ volatile("int $0x16" : : "a"(0x00) : "memory", "cc");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dpmi_regs = (struct dpmi_regs){.eax = 0x00004C00};
|
// dpmi_regs = (struct dpmi_regs){.eax = 0x00004C00};
|
||||||
|
|||||||
+22
-16
@@ -126,9 +126,11 @@ static bool plr_x11_handshake(com_std_fd xfd,
|
|||||||
if (!com_std_write(xfd, AUTH_ENTRY_MAGIC_COOKIE,
|
if (!com_std_write(xfd, AUTH_ENTRY_MAGIC_COOKIE,
|
||||||
sizeof AUTH_ENTRY_MAGIC_COOKIE - 1))
|
sizeof AUTH_ENTRY_MAGIC_COOKIE - 1))
|
||||||
return false;
|
return false;
|
||||||
/* Use 2 bytes back for padding. */
|
/* 2 bytes padding after magic cookie. */
|
||||||
if (!com_std_write(xfd, &auth_entry.auth_data->data[-2],
|
if (!com_std_write(xfd, &request, 2))
|
||||||
auth_entry.auth_data->len + 2))
|
return false;
|
||||||
|
if (!com_std_write(xfd, auth_entry.auth_data->data,
|
||||||
|
auth_entry.auth_data->len))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -293,8 +295,8 @@ static uint32_t plr_x11_create_graphical_context(com_std_fd xfd) {
|
|||||||
|
|
||||||
static uint32_t plr_x11_create_window(com_std_fd xfd) {
|
static uint32_t plr_x11_create_window(com_std_fd xfd) {
|
||||||
/* TODO: Use the ones provided in headers ? */
|
/* TODO: Use the ones provided in headers ? */
|
||||||
#define FLAG_WIN_BG_PIXEL 2
|
#define FLAG_WIN_BG_PIXEL 0x0002
|
||||||
#define FLAG_WIN_EVENT 0x800
|
#define FLAG_WIN_EVENT 0x0800
|
||||||
#define EVENT_FLAG_EXPOSURE 0x8000
|
#define EVENT_FLAG_EXPOSURE 0x8000
|
||||||
#define EVENT_FLAG_KEY_PRESS 0x1
|
#define EVENT_FLAG_KEY_PRESS 0x1
|
||||||
#define EVENT_FLAG_KEY_RELEASE 0x2
|
#define EVENT_FLAG_KEY_RELEASE 0x2
|
||||||
@@ -331,7 +333,7 @@ static uint32_t plr_x11_create_window(com_std_fd xfd) {
|
|||||||
.class = 1,
|
.class = 1,
|
||||||
.root_visual_id = plr_x11_root_screen.root_visual_id,
|
.root_visual_id = plr_x11_root_screen.root_visual_id,
|
||||||
.bitmask = FLAG_WIN_BG_PIXEL | FLAG_WIN_EVENT,
|
.bitmask = FLAG_WIN_BG_PIXEL | FLAG_WIN_EVENT,
|
||||||
.value1 = 0x00000000,
|
.value1 = 0xff000000,
|
||||||
.value2 = EVENT_FLAG_EXPOSURE | EVENT_FLAG_BUTTON_RELEASE |
|
.value2 = EVENT_FLAG_EXPOSURE | EVENT_FLAG_BUTTON_RELEASE |
|
||||||
EVENT_FLAG_BUTTON_PRESS | EVENT_FLAG_KEY_PRESS |
|
EVENT_FLAG_BUTTON_PRESS | EVENT_FLAG_KEY_PRESS |
|
||||||
EVENT_FLAG_KEY_RELEASE,
|
EVENT_FLAG_KEY_RELEASE,
|
||||||
@@ -419,6 +421,10 @@ static uint8_t plr_x11_query_extension(com_std_fd xfd, com_str const *ext) {
|
|||||||
static bool plr_x11_enable_big_requests(com_std_fd xfd) {
|
static bool plr_x11_enable_big_requests(com_std_fd xfd) {
|
||||||
static com_str bigreqext = com_str_lit("BIG-REQUESTS");
|
static com_str bigreqext = com_str_lit("BIG-REQUESTS");
|
||||||
uint8_t const opcode = plr_x11_query_extension(xfd, &bigreqext);
|
uint8_t const opcode = plr_x11_query_extension(xfd, &bigreqext);
|
||||||
|
if (!opcode) {
|
||||||
|
com_std_print('c', "Big request can't accommodate for framebuffer.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Request the thing. */
|
/* Request the thing. */
|
||||||
struct {
|
struct {
|
||||||
@@ -439,8 +445,8 @@ static bool plr_x11_enable_big_requests(com_std_fd xfd) {
|
|||||||
plr_x11_poll_reply(xfd, seq, &response);
|
plr_x11_poll_reply(xfd, seq, &response);
|
||||||
|
|
||||||
uint32_t const limit = *(uint32_t *)response.reply.pad;
|
uint32_t const limit = *(uint32_t *)response.reply.pad;
|
||||||
com_std_print('c', "Request limit: ", 'u', limit);
|
com_std_print('c', "X11 request limit: ", 'u', limit);
|
||||||
if (limit < COM_CFG_FBSIZE) {
|
if (limit < COM_CFG_FBSIZE / 4) {
|
||||||
com_std_print('c', "Big request can't accommodate for framebuffer.");
|
com_std_print('c', "Big request can't accommodate for framebuffer.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -449,7 +455,7 @@ static bool plr_x11_enable_big_requests(com_std_fd xfd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
|
static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
|
||||||
uint32_t pixmap_id,
|
uint32_t drawable_id,
|
||||||
uint8_t pixels[COM_CFG_FBSIZE]) {
|
uint8_t pixels[COM_CFG_FBSIZE]) {
|
||||||
uint32_t const padded = com_bits_nalign(COM_CFG_FBSIZE, 4);
|
uint32_t const padded = com_bits_nalign(COM_CFG_FBSIZE, 4);
|
||||||
uint32_t const seq = plr_x11_next_seqid();
|
uint32_t const seq = plr_x11_next_seqid();
|
||||||
@@ -472,7 +478,7 @@ static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
|
|||||||
.opcode = 72,
|
.opcode = 72,
|
||||||
.format = 2, // ZPixmap
|
.format = 2, // ZPixmap
|
||||||
.request_length = sizeof request / 4 + padded / 4,
|
.request_length = sizeof request / 4 + padded / 4,
|
||||||
.drawable_id = pixmap_id,
|
.drawable_id = drawable_id,
|
||||||
.gc_id = gc_id,
|
.gc_id = gc_id,
|
||||||
.width = COM_CFG_WIDTH,
|
.width = COM_CFG_WIDTH,
|
||||||
.height = COM_CFG_HEIGHT,
|
.height = COM_CFG_HEIGHT,
|
||||||
@@ -600,11 +606,11 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t const fb = plr_x11_create_pixmap(xfd, win);
|
// uint32_t const fb = plr_x11_create_pixmap(xfd, win);
|
||||||
if (!fb) {
|
// if (!fb) {
|
||||||
com_std_print('c', "Failure to initialize X11");
|
// com_std_print('c', "Failure to initialize X11");
|
||||||
return -1;
|
// return -1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Display *display = XOpenDisplay(NULL);
|
// Display *display = XOpenDisplay(NULL);
|
||||||
// if (NULL == display) {
|
// if (NULL == display) {
|
||||||
@@ -704,7 +710,7 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
|
|||||||
uint8_t *fbm = plr_draw_get_pixel_buffer();
|
uint8_t *fbm = plr_draw_get_pixel_buffer();
|
||||||
plr_draw_screen(fbm);
|
plr_draw_screen(fbm);
|
||||||
|
|
||||||
if (!plr_x11_put_framebuffer(xfd, gc, fb, fbm)) {
|
if (!plr_x11_put_framebuffer(xfd, gc, win, fbm)) {
|
||||||
com_std_print('c', "Failure to drive X11");
|
com_std_print('c', "Failure to drive X11");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
.section .data
|
.section .data
|
||||||
.align 4
|
.align 4
|
||||||
# TODO: Make sure it's placed under 1 MiB.
|
# TODO: Make sure it's placed under 1 MiB.
|
||||||
# The DPMI Register Structure (50 bytes total)
|
|
||||||
# This holds the register states injected into Real Mode.
|
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.global _start
|
.global _start
|
||||||
|
|||||||
Whitespace-only changes.
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
Inter-process communicating socket, useful for local testing and admin
|
|
||||||
playing.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
#define MAXBUFFSIZE 4194304 /* 4.0MiB */
|
|
||||||
|
|
||||||
int plr_socket_unix_try_connect(const char *filepath) {
|
|
||||||
int sock = 0;
|
|
||||||
|
|
||||||
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
||||||
perror("Error creating client UNIX socket: ");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_un remote = {0};
|
|
||||||
remote.sun_family = AF_UNIX;
|
|
||||||
strcpy(remote.sun_path, filepath);
|
|
||||||
int const remote_len = SUN_LEN(&remote);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+4
-7
@@ -6,29 +6,26 @@ We do not use abstractions, as the simplicity of the required set of features sh
|
|||||||
---- Restrictions ----
|
---- Restrictions ----
|
||||||
* Fixed sized paletted frambuffer, defaulted to 640x480.
|
* Fixed sized paletted frambuffer, defaulted to 640x480.
|
||||||
* Deterministic logic via Q15.16 fixed point numbers.
|
* Deterministic logic via Q15.16 fixed point numbers.
|
||||||
* .gam image format, derived from .gif. RLE and Delta Frame Optimiztion is added, palette is predefined.
|
* .gam image format, derived from .gif. Palette is globally predefined.
|
||||||
* Textures are 32x32 pixels.
|
* Textures are 32x32 pixels.
|
||||||
* 30 FPS display rate.
|
* 30 FPS display rate.
|
||||||
* Fonts are in ASCII bitmaps. Tile slicing commands are issued to render them in.
|
* Fonts are in ASCII bitmaps. Tile slicing commands are issued to render them in.
|
||||||
* Audio samples are in our own .sam format (s8 frame delta + lzw).
|
* Audio samples are in our own .sam format (s8 + ulaw + lzw).
|
||||||
* Music pieces are written in our own simple .tam tracker format, using the same .sam sample db.
|
* Music pieces are written in our own simple .tam tracker format, using the same .sam sample db.
|
||||||
* Connections are over TCP and their supersets (like WebSocket).
|
* Connections are over TCP and their supersets (like WebSocket).
|
||||||
* Textbox provides another client-controlled view, with history.
|
|
||||||
* Content usage has to be predefined, to allow preloading and compilation.
|
* Content usage has to be predefined, to allow preloading and compilation.
|
||||||
|
|
||||||
|
|
||||||
---- Building ----
|
---- Building ----
|
||||||
==== DOS ====
|
==== DOS ====
|
||||||
Open Watcom 2.0 32bit toolchain is used under Linux host.
|
Nothing is needed. Just compile.
|
||||||
Place a copy of DOS4GW.EXE alongside the executable.
|
|
||||||
Expect to need to configure $INCLUDE and $LIB variables.
|
|
||||||
|
|
||||||
|
|
||||||
---- .sam format ----
|
---- .sam format ----
|
||||||
Thin sample compressing scheme tailored for use with .tam tracker.
|
Thin sample compressing scheme tailored for use with .tam tracker.
|
||||||
Leading and tailing silence is stored as number of frames.
|
Leading and tailing silence is stored as number of frames.
|
||||||
Sample data is 1 channel only, but panning can be expressed via graph.
|
Sample data is 1 channel only, but panning can be expressed via graph.
|
||||||
Sample bit format is signed 8 bit delta, first frame is delta against 0. Clamping is allowed.
|
Sample bit format is signed 8 bit delta. Clamping is allowed.
|
||||||
Generic LZW compression is applied as the last step.
|
Generic LZW compression is applied as the last step.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Tracker program to create awesome music!
|
||||||
|
Is supposed to only work on Linux, as it's where the development happens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../Common/Snd/oscs.h"
|
||||||
|
#include "../../Common/Std/libc.c"
|
||||||
|
#include "../../Common/Timer/posix.c"
|
||||||
|
#include "../../Common/fix.c"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
struct com_snd_swave swave = com_snd_swave_init(COM_CFG_A4FIX, 0, UINT16_MAX);
|
||||||
|
|
||||||
|
FILE *f = fopen("test.raw", "w");
|
||||||
|
if (!f) {
|
||||||
|
printf("Can't open file %s\n", "test.raw");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate 5 seconds of sinwave. */
|
||||||
|
int16_t frames[COM_CFG_SNDFRMRATE * 5];
|
||||||
|
for (int i = 0; i < COM_CFG_SNDFRMRATE * 5; ++i)
|
||||||
|
frames[i] = com_snd_swave_pump(&swave);
|
||||||
|
|
||||||
|
fwrite(frames, 2, COM_CFG_SNDFRMRATE * 5, f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Binary file not shown.
Executable
+100
@@ -0,0 +1,100 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Compression testing for image data for expected cases of ours.
|
||||||
|
|
||||||
|
# TODO: Implement our own CLI tool that uses our LZW implementation, as it differs.
|
||||||
|
|
||||||
|
import imageio.v3 as iio
|
||||||
|
import ncompress
|
||||||
|
import numpy as np
|
||||||
|
import sys
|
||||||
|
|
||||||
|
uncompressed = iio.imread(sys.argv[1])
|
||||||
|
compressed = ncompress.compress(uncompressed.tobytes())
|
||||||
|
print("Uncompressed:", uncompressed.nbytes)
|
||||||
|
print("Compressed:", len(compressed), len(compressed) / uncompressed.nbytes)
|
||||||
|
|
||||||
|
with open(sys.argv[1] + "-indexed.raw", "rb") as file:
|
||||||
|
raw_bytes = file.read()
|
||||||
|
indexmapping = {}
|
||||||
|
indexset = set(raw_bytes)
|
||||||
|
for idx, value in enumerate(indexset):
|
||||||
|
indexmapping[value] = idx
|
||||||
|
print(indexmapping)
|
||||||
|
indexmap = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.uint8)
|
||||||
|
for y in range(uncompressed.shape[0]):
|
||||||
|
for x in range(uncompressed.shape[1]):
|
||||||
|
indexmap[y * uncompressed.shape[0] + x] = indexmapping[raw_bytes[y * uncompressed.shape[0] + x]]
|
||||||
|
indexedcompressed = ncompress.compress(indexmap.tobytes())
|
||||||
|
print("Indexed:", len(indexedcompressed), len(indexedcompressed) / len(raw_bytes))
|
||||||
|
|
||||||
|
# https://arxiv.org/html/2006.02639v2
|
||||||
|
def pixel_art_predictive_filter(image_channel):
|
||||||
|
"""
|
||||||
|
Applies a spatial prediction filter to a 2D image matrix
|
||||||
|
to prepare it for lossless compression.
|
||||||
|
"""
|
||||||
|
rows, cols = image_channel.shape
|
||||||
|
residual_map = np.zeros((rows, cols), dtype=np.int16)
|
||||||
|
|
||||||
|
for r in range(rows):
|
||||||
|
for c in range(cols):
|
||||||
|
# Handle edge cases (boundaries where neighbors don't exist)
|
||||||
|
if r == 0 and c == 0:
|
||||||
|
pred = 0
|
||||||
|
elif r == 0:
|
||||||
|
pred = image_channel[r, c-1] # Only Left neighbor exists
|
||||||
|
elif c == 0:
|
||||||
|
pred = image_channel[r-1, c] # Only Top neighbor exists
|
||||||
|
else:
|
||||||
|
# Core DSP Neighborhood definition
|
||||||
|
A = image_channel[r, c-1] # Left
|
||||||
|
B = image_channel[r-1, c] # Top
|
||||||
|
C = image_channel[r-1, c-1] # Top-Left
|
||||||
|
|
||||||
|
# Median Edge Detector logic
|
||||||
|
if C >= max(A, B):
|
||||||
|
pred = min(A, B)
|
||||||
|
elif C <= min(A, B):
|
||||||
|
pred = max(A, B)
|
||||||
|
else:
|
||||||
|
pred = int(A) + int(B) - int(C)
|
||||||
|
|
||||||
|
# Map the actual value to the residual difference
|
||||||
|
residual_map[r, c] = int(image_channel[r, c]) - int(pred)
|
||||||
|
|
||||||
|
return residual_map
|
||||||
|
|
||||||
|
predictivefilter = pixel_art_predictive_filter(indexmap)
|
||||||
|
predictivefiltercompressed = ncompress.compress(predictivefilter.tobytes())
|
||||||
|
print("Predictive filter:", len(predictivefiltercompressed), len(predictivefiltercompressed) / len(raw_bytes))
|
||||||
|
|
||||||
|
def encode_zorder_2d(x: int, y: int) -> int:
|
||||||
|
z = 0
|
||||||
|
for i in range(16):
|
||||||
|
z |= ((x & (1 << i)) << i) | ((y & (1 << i)) << (i + 1))
|
||||||
|
return z
|
||||||
|
|
||||||
|
zordered = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.uint8)
|
||||||
|
for y in range(uncompressed.shape[0]):
|
||||||
|
for x in range(uncompressed.shape[1]):
|
||||||
|
idx = encode_zorder_2d(x, y)
|
||||||
|
zordered[idx] = uncompressed[y, x]
|
||||||
|
|
||||||
|
zcompressed = ncompress.compress(zordered.tobytes())
|
||||||
|
print("Zordered:", len(zcompressed), len(zcompressed) / uncompressed.nbytes)
|
||||||
|
|
||||||
|
delta = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.int8)
|
||||||
|
for y in range(uncompressed.shape[0]):
|
||||||
|
for x in range(uncompressed.shape[1]):
|
||||||
|
delta[y * uncompressed.shape[0] + x] = int(uncompressed[y, x]) - int(uncompressed[y, (x + 1) % uncompressed.shape[0]])
|
||||||
|
deltacompressed = ncompress.compress(delta.tobytes())
|
||||||
|
print("Delta:", len(deltacompressed), len(deltacompressed) / uncompressed.nbytes)
|
||||||
|
|
||||||
|
deltaz = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.int8)
|
||||||
|
for y in range(uncompressed.shape[0]):
|
||||||
|
for x in range(uncompressed.shape[1]):
|
||||||
|
idx = encode_zorder_2d(x, y)
|
||||||
|
deltaz[idx] = int(uncompressed[y, x]) - int(uncompressed[y, (x + 1) % uncompressed.shape[0]])
|
||||||
|
deltazcompressed = ncompress.compress(deltaz.tobytes())
|
||||||
|
print("Deltaz:", len(deltazcompressed), len(deltazcompressed) / uncompressed.nbytes)
|
||||||
|
|
||||||
Executable
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Compression testing for sound sample data for expected cases of ours.
|
||||||
|
|
||||||
|
# TODO: Implement our own CLI tool that uses our LZW implementation, as it differs.
|
||||||
|
|
||||||
|
import ncompress
|
||||||
|
import sys
|
||||||
|
import wave
|
||||||
|
import audioop
|
||||||
|
import numpy as np
|
||||||
|
import array
|
||||||
|
|
||||||
|
with wave.open(sys.argv[1], 'rb') as wf:
|
||||||
|
channels = wf.getnchannels()
|
||||||
|
samplerate = wf.getframerate()
|
||||||
|
frames = wf.getnframes()
|
||||||
|
uncompressed = wf.readframes(frames)
|
||||||
|
depth = wf.getsampwidth()
|
||||||
|
|
||||||
|
compressed = ncompress.compress(uncompressed)
|
||||||
|
print("Uncompressed:", len(uncompressed))
|
||||||
|
print("Compressed:", len(compressed), len(compressed) / len(uncompressed))
|
||||||
|
|
||||||
|
delta = bytearray(uncompressed[0].to_bytes(2, signed=False))
|
||||||
|
for i in range(len(uncompressed)-1):
|
||||||
|
delta += (uncompressed[i+1] - uncompressed[i]).to_bytes(2, signed=True)
|
||||||
|
|
||||||
|
dtcompressed = ncompress.compress(bytes(delta))
|
||||||
|
print("Delta:", len(dtcompressed), len(dtcompressed) / len(uncompressed))
|
||||||
|
assert(len(delta) == len(uncompressed)*2)
|
||||||
|
|
||||||
|
ulaw = audioop.lin2ulaw(uncompressed, depth)
|
||||||
|
ulawcompressed = ncompress.compress(ulaw)
|
||||||
|
print("Ulaw:", len(ulawcompressed), len(ulawcompressed) / len(uncompressed))
|
||||||
|
|
||||||
|
absfold = bytearray()
|
||||||
|
for i in range(len(uncompressed)):
|
||||||
|
absfold.append(uncompressed[i] - 128 if uncompressed[i] >= 128 else uncompressed[i])
|
||||||
|
absfoldulaw = audioop.lin2ulaw(absfold, depth)
|
||||||
|
absfoldulawcompressed = ncompress.compress(absfoldulaw)
|
||||||
|
print("Ulawabs:", len(absfoldulawcompressed), len(absfoldulawcompressed) / len(absfold))
|
||||||
|
|
||||||
|
with open(sys.argv[1] + ".ulaw", "wb") as file:
|
||||||
|
file.write(audioop.ulaw2lin(ulaw, depth))
|
||||||
File renamed without changes.
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
magick $1 -resize 32x32 +dither -type Palette -depth 8 -colors 16 PNG8:$1-indexed
|
||||||
|
magick stream -map r -storage-type char $1-indexed $1-indexed.raw
|
||||||
Reference in new issue
Block a user