mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-03 03:02:28 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
60
dsp/bmp/bmp.mk
Normal file
60
dsp/bmp/bmp.mk
Normal file
|
@ -0,0 +1,60 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += DSP_BMP
|
||||
|
||||
DSP_BMP_ARTIFACTS += DSP_BMP_A
|
||||
DSP_BMP = $(DSP_BMP_A_DEPS) $(DSP_BMP_A)
|
||||
DSP_BMP_A = o/$(MODE)/dsp/bmp/bmp.a
|
||||
DSP_BMP_A_FILES := $(wildcard dsp/bmp/*)
|
||||
DSP_BMP_A_HDRS = $(filter %.h,$(DSP_BMP_A_FILES))
|
||||
DSP_BMP_A_SRCS_S = $(filter %.S,$(DSP_BMP_A_FILES))
|
||||
DSP_BMP_A_SRCS_C = $(filter %.c,$(DSP_BMP_A_FILES))
|
||||
|
||||
DSP_BMP_A_SRCS = \
|
||||
$(DSP_BMP_A_SRCS_S) \
|
||||
$(DSP_BMP_A_SRCS_C)
|
||||
|
||||
DSP_BMP_A_OBJS = \
|
||||
$(DSP_BMP_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(DSP_BMP_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(DSP_BMP_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
DSP_BMP_A_CHECKS = \
|
||||
$(DSP_BMP_A).pkg \
|
||||
$(DSP_BMP_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
DSP_BMP_A_DIRECTDEPS = \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_STUBS
|
||||
|
||||
DSP_BMP_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(DSP_BMP_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(DSP_BMP_A): dsp/bmp/ \
|
||||
$(DSP_BMP_A).pkg \
|
||||
$(DSP_BMP_A_OBJS)
|
||||
|
||||
$(DSP_BMP_A).pkg: \
|
||||
$(DSP_BMP_A_OBJS) \
|
||||
$(foreach x,$(DSP_BMP_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/dsp/bmp/float2short.o \
|
||||
o/$(MODE)/dsp/bmp/scalevolume.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
$(MATHEMATICAL)
|
||||
|
||||
o/tiny/dsp/bmp/scalevolume.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
DSP_BMP_LIBS = $(foreach x,$(DSP_BMP_ARTIFACTS),$($(x)))
|
||||
DSP_BMP_SRCS = $(foreach x,$(DSP_BMP_ARTIFACTS),$($(x)_SRCS))
|
||||
DSP_BMP_HDRS = $(foreach x,$(DSP_BMP_ARTIFACTS),$($(x)_HDRS))
|
||||
DSP_BMP_CHECKS = $(foreach x,$(DSP_BMP_ARTIFACTS),$($(x)_CHECKS))
|
||||
DSP_BMP_OBJS = $(foreach x,$(DSP_BMP_ARTIFACTS),$($(x)_OBJS))
|
||||
$(DSP_BMP_OBJS): $(BUILD_FILES) dsp/bmp/bmp.mk
|
||||
|
||||
.PHONY: o/$(MODE)/dsp/bmp
|
||||
o/$(MODE)/dsp/bmp: $(DSP_BMP_CHECKS)
|
36
dsp/core/byte2double.c
Normal file
36
dsp/core/byte2double.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
void *byte2double(long n, const void *p, double weight, double bias) {
|
||||
long i;
|
||||
double f, *dst;
|
||||
unsigned char *src;
|
||||
if ((dst = valloc(n * sizeof(double)))) {
|
||||
for (src = p, i = 0; i < n; ++i) {
|
||||
f = src[i];
|
||||
f -= bias;
|
||||
f *= 1 / weight;
|
||||
dst[i] = f;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
22
dsp/core/c11.h
Normal file
22
dsp/core/c11.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C11_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C11_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Fixed-point 8-bit rounded mean kernel.
|
||||
*
|
||||
* @define (a + b) / 2
|
||||
*/
|
||||
static inline pureconst artificial unsigned char C11(unsigned char al,
|
||||
unsigned char bl) {
|
||||
short ax;
|
||||
ax = al;
|
||||
ax += bl;
|
||||
ax += 1;
|
||||
ax /= 2;
|
||||
al = ax;
|
||||
return al;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C11_H_ */
|
21
dsp/core/c121.h
Normal file
21
dsp/core/c121.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C121_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C121_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline pureconst artificial unsigned char C121(unsigned char al,
|
||||
unsigned char bl,
|
||||
unsigned char cl) {
|
||||
unsigned short ax, bx;
|
||||
ax = al;
|
||||
ax += bl;
|
||||
ax += bl;
|
||||
ax += cl;
|
||||
ax += 2;
|
||||
ax >>= 2;
|
||||
return ax;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C121_H_ */
|
19
dsp/core/c121s.h
Normal file
19
dsp/core/c121s.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C121S_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C121S_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
forceinline pureconst artificial signed char C121S(signed char al,
|
||||
signed char bl,
|
||||
signed char cl) {
|
||||
short ax, bx;
|
||||
ax = al;
|
||||
ax += bl;
|
||||
ax += bl;
|
||||
ax += cl;
|
||||
ax += 2;
|
||||
ax >>= 2;
|
||||
return ax;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C121S_H_ */
|
30
dsp/core/c1331.h
Normal file
30
dsp/core/c1331.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C1331_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C1331_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Byte sized kernel for resampling memory in half.
|
||||
*
|
||||
* @define (1*𝑎 + 3*𝑏 + 3*𝑐 + 1*𝑑) / (1 + 3 + 3 + 1)
|
||||
* @see C161() afterward for superior sin(𝑥)/𝑥
|
||||
* @limit [0,255] → [0..2,044] → [0..255]
|
||||
*/
|
||||
forceinline pureconst artificial unsigned char C1331(unsigned char al,
|
||||
unsigned char bl,
|
||||
unsigned char cl,
|
||||
unsigned char dl) {
|
||||
short ax, bx;
|
||||
bx = bl;
|
||||
bx += cl;
|
||||
bx *= 3;
|
||||
ax = al;
|
||||
ax += dl;
|
||||
ax += bx;
|
||||
ax += 4;
|
||||
ax >>= 3;
|
||||
al = ax;
|
||||
return al;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C1331_H_ */
|
28
dsp/core/c1331s.h
Normal file
28
dsp/core/c1331s.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C1331S_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C1331S_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Byte sized kernel for resampling difference samples in half.
|
||||
*
|
||||
* @define (1*(a-128)+3*(a-128)+3*(a-128)+1*(a-128))/(1+3+3+1)+128
|
||||
* @see C1331(), Y420CbCr2RgbScale()
|
||||
*/
|
||||
forceinline pureconst artificial signed char C1331S(signed char al,
|
||||
signed char bl,
|
||||
signed char cl,
|
||||
signed char dl) {
|
||||
short ax, bx;
|
||||
bx = bl;
|
||||
bx += cl;
|
||||
bx *= 3;
|
||||
ax = al;
|
||||
ax += dl;
|
||||
ax += bx;
|
||||
ax += 4;
|
||||
ax >>= 3;
|
||||
return ax;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C1331S_H_ */
|
33
dsp/core/c161.h
Normal file
33
dsp/core/c161.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C161_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C161_H_
|
||||
#include "libc/macros.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define EXTRA_SHARP 2
|
||||
|
||||
/**
|
||||
* Byte sized kernel for restoring sharpness of resampled memory.
|
||||
*
|
||||
* @define CLAMP[(-1*𝑎 + 6*𝑏 + -1*𝑐) / (-1 + 6 + -1)]
|
||||
* @limit [0..255] → [-510..1,532] → [-127..383] → [0..255]
|
||||
* @see C1331()
|
||||
*/
|
||||
forceinline pureconst artificial unsigned char C161(unsigned char al,
|
||||
unsigned char bl,
|
||||
unsigned char cl) {
|
||||
short ax, bx, cx;
|
||||
ax = al;
|
||||
bx = bl;
|
||||
cx = cl;
|
||||
ax *= -1;
|
||||
bx *= +6;
|
||||
cx *= -1;
|
||||
ax += bx;
|
||||
ax += cx;
|
||||
ax += 2;
|
||||
ax >>= 2;
|
||||
return MIN(255, MAX(0, ax));
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C161_H_ */
|
26
dsp/core/c161s.h
Normal file
26
dsp/core/c161s.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C161S_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C161S_H_
|
||||
#include "dsp/core/c161.h"
|
||||
#include "libc/macros.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
forceinline pureconst artificial signed char C161S(signed char al,
|
||||
signed char bl,
|
||||
signed char cl) {
|
||||
short ax, bx, cx;
|
||||
ax = al;
|
||||
bx = bl;
|
||||
cx = cl;
|
||||
ax *= -1 * EXTRA_SHARP;
|
||||
bx *= 6 * EXTRA_SHARP;
|
||||
cx *= -1 * EXTRA_SHARP;
|
||||
ax += bx;
|
||||
ax += cx;
|
||||
ax += 2 * EXTRA_SHARP;
|
||||
ax /= 4 * EXTRA_SHARP;
|
||||
al = MIN(112, MAX(-112, ax));
|
||||
return al;
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C161S_H_ */
|
30
dsp/core/c331.h
Normal file
30
dsp/core/c331.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_C331_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_C331_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* Fixed-point 8-bit magic edge resampling kernel.
|
||||
*
|
||||
* @define (3*a + 3*b + 1*c) / 7
|
||||
* @see C1331()
|
||||
*/
|
||||
static inline pureconst artificial unsigned char C331(unsigned char al,
|
||||
unsigned char bl,
|
||||
unsigned char cl) {
|
||||
unsigned eax, ebx, ecx;
|
||||
eax = al;
|
||||
ebx = bl;
|
||||
ecx = cl;
|
||||
eax += ebx;
|
||||
eax *= 3 * 2350;
|
||||
ecx *= 1 * 2350;
|
||||
eax += ecx;
|
||||
eax >>= 14;
|
||||
al = eax;
|
||||
return al;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_C331_H_ */
|
37
dsp/core/core.h
Normal file
37
dsp/core/core.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_CORE_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_CORE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Digital Signal Processing.
|
||||
*/
|
||||
|
||||
int mulaw(int);
|
||||
void *double2byte(long, const void *, double, double) vallocesque;
|
||||
void *byte2double(long, const void *, double, double) vallocesque;
|
||||
|
||||
void *dct(float[8][8], float, float, float, float, float);
|
||||
void *dctjpeg(float[8][8]);
|
||||
|
||||
double det3(const double[3][3]) nosideeffect;
|
||||
void *inv3(double[restrict 3][3], const double[restrict 3][3], double);
|
||||
void *matmul3(double[restrict 3][3], const double[3][3], const double[3][3]);
|
||||
void *vmatmul3(double[restrict 3], const double[3], const double[3][3]);
|
||||
void *matvmul3(double[restrict 3], const double[3][3], const double[3]);
|
||||
|
||||
double rgb2stdtv(double) pureconst;
|
||||
double rgb2lintv(double) pureconst;
|
||||
double rgb2stdpc(double, double) pureconst;
|
||||
double rgb2linpc(double, double) pureconst;
|
||||
double tv2pcgamma(double, double) pureconst;
|
||||
|
||||
#ifndef __cplusplus
|
||||
void sad16x8n(size_t n, short[n][8], const short[n][8]);
|
||||
void float2short(size_t n, short[n][8], const float[n][8]);
|
||||
void scalevolume(size_t n, int16_t[n][8], int);
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_CORE_H_ */
|
69
dsp/core/core.mk
Normal file
69
dsp/core/core.mk
Normal file
|
@ -0,0 +1,69 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += DSP_CORE
|
||||
|
||||
DSP_CORE_ARTIFACTS += DSP_CORE_A
|
||||
DSP_CORE = $(DSP_CORE_A_DEPS) $(DSP_CORE_A)
|
||||
DSP_CORE_A = o/$(MODE)/dsp/core/core.a
|
||||
DSP_CORE_A_FILES := $(wildcard dsp/core/*)
|
||||
DSP_CORE_A_HDRS = $(filter %.h,$(DSP_CORE_A_FILES))
|
||||
DSP_CORE_A_SRCS_S = $(filter %.S,$(DSP_CORE_A_FILES))
|
||||
DSP_CORE_A_SRCS_C = $(filter %.c,$(DSP_CORE_A_FILES))
|
||||
|
||||
DSP_CORE_A_SRCS = \
|
||||
$(DSP_CORE_A_SRCS_S) \
|
||||
$(DSP_CORE_A_SRCS_C)
|
||||
|
||||
DSP_CORE_A_OBJS = \
|
||||
$(DSP_CORE_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(DSP_CORE_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(DSP_CORE_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
DSP_CORE_A_CHECKS = \
|
||||
$(DSP_CORE_A).pkg \
|
||||
$(DSP_CORE_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
DSP_CORE_A_DIRECTDEPS = \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_MEM \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_STUBS
|
||||
|
||||
DSP_CORE_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(DSP_CORE_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(DSP_CORE_A): dsp/core/ \
|
||||
$(DSP_CORE_A).pkg \
|
||||
$(DSP_CORE_A_OBJS)
|
||||
|
||||
$(DSP_CORE_A).pkg: \
|
||||
$(DSP_CORE_A_OBJS) \
|
||||
$(foreach x,$(DSP_CORE_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/dsp/core/dct.o \
|
||||
o/$(MODE)/dsp/core/c1331.o \
|
||||
o/$(MODE)/dsp/core/magikarp.o \
|
||||
o/$(MODE)/dsp/core/c93654369.o \
|
||||
o/$(MODE)/dsp/core/float2short.o \
|
||||
o/$(MODE)/dsp/core/scalevolume.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
$(MATHEMATICAL)
|
||||
|
||||
o/tiny/dsp/core/scalevolume.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
o/$(MODE)/dsp/core/det3.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-ffast-math
|
||||
|
||||
DSP_CORE_LIBS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)))
|
||||
DSP_CORE_SRCS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_SRCS))
|
||||
DSP_CORE_HDRS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_HDRS))
|
||||
DSP_CORE_CHECKS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_CHECKS))
|
||||
DSP_CORE_OBJS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_OBJS))
|
||||
$(DSP_CORE_OBJS): $(BUILD_FILES) dsp/core/core.mk
|
||||
|
||||
.PHONY: o/$(MODE)/dsp/core
|
||||
o/$(MODE)/dsp/core: $(DSP_CORE_CHECKS)
|
85
dsp/core/dct.c
Normal file
85
dsp/core/dct.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
|
||||
#define DCT(A, B, C, D, E, F, G, H, T, C0, C1, C2, C3, C4) \
|
||||
do { \
|
||||
T z1, z2, z3, z4, z5, z11, z13; \
|
||||
T t0, t1, t2, t3, t4, t5, t6, t7, t8, t10, t11, t12, t13; \
|
||||
t0 = A + H; \
|
||||
t7 = A - H; \
|
||||
t1 = B + G; \
|
||||
t6 = B - G; \
|
||||
t2 = C + F; \
|
||||
t5 = C - F; \
|
||||
t3 = D + E; \
|
||||
t4 = D - E; \
|
||||
t10 = t0 + t3; \
|
||||
t13 = t0 - t3; \
|
||||
t11 = t1 + t2; \
|
||||
t12 = t1 - t2; \
|
||||
A = t10 + t11; \
|
||||
E = t10 - t11; \
|
||||
z1 = (t12 + t13) * C0; \
|
||||
C = t13 + z1; \
|
||||
G = t13 - z1; \
|
||||
t10 = t4 + t5; \
|
||||
t11 = t5 + t6; \
|
||||
t12 = t6 + t7; \
|
||||
z5 = (t10 - t12) * C1; \
|
||||
z2 = t10 * C2 + z5; \
|
||||
z4 = t12 * C3 + z5; \
|
||||
z3 = t11 * C4; \
|
||||
z11 = t7 + z3; \
|
||||
z13 = t7 - z3; \
|
||||
F = z13 + z2; \
|
||||
D = z13 - z2; \
|
||||
B = z11 + z4; \
|
||||
H = z11 - z4; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Performs float forward discrete cosine transform.
|
||||
*
|
||||
* This takes a tiny block of image data and shoves the information it
|
||||
* represents into the top left corner. It can be reversed using idct().
|
||||
* It matters because iterating the result in a serpentine pattern makes
|
||||
* run-length delta encoding super effective. Furthermore, data downward
|
||||
* rightly may be divided away for lossy compression.
|
||||
*
|
||||
* @cost ~100ns
|
||||
*/
|
||||
void *dct(float M[8][8], float c0, float c1, float c2, float c3, float c4) {
|
||||
unsigned y, x;
|
||||
for (y = 0; y < 8; ++y) {
|
||||
DCT(M[y][0], M[y][1], M[y][2], M[y][3], M[y][4], M[y][5], M[y][6], M[y][7],
|
||||
float, c0, c1, c2, c3, c4);
|
||||
}
|
||||
for (x = 0; x < 8; ++x) {
|
||||
DCT(M[0][x], M[1][x], M[2][x], M[3][x], M[4][x], M[5][x], M[6][x], M[7][x],
|
||||
float, c0, c1, c2, c3, c4);
|
||||
}
|
||||
return M;
|
||||
}
|
||||
|
||||
void *dctjpeg(float M[8][8]) {
|
||||
return dct(M, .707106781f, .382683433f, .541196100f, 1.306562965f,
|
||||
.707106781f);
|
||||
}
|
36
dsp/core/det3.c
Normal file
36
dsp/core/det3.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
|
||||
#define LEIBNIZ_FORMULA(a, b, c, d, e, f, g, h, i) \
|
||||
(a * e * i + b * f * g + c * d * h - c * e * g - b * d * i - a * f * h)
|
||||
|
||||
/**
|
||||
* Computes determinant of 3×3 matrix.
|
||||
* i.e. how much space is inside the cube
|
||||
*
|
||||
* @param 𝐀 is input matrix
|
||||
* @param 𝑑 is det(𝐀)
|
||||
* @return |𝐀| or 0 if degenerate
|
||||
*/
|
||||
double det3(const double A[3][3]) {
|
||||
return LEIBNIZ_FORMULA(A[0][0], A[0][1], A[0][2], A[1][0], A[1][1], A[1][2],
|
||||
A[2][0], A[2][1], A[2][2]);
|
||||
}
|
67
dsp/core/differsumsq.c
Normal file
67
dsp/core/differsumsq.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
|
||||
/**
|
||||
* Computes Σ𝑥ᵢΣ𝑥ⱼΣ𝑥ₖΣ𝑥ₗΣ𝑥ₘΣ𝑥ₙ(δ₁𝑥ᵢ+δ₂𝑥ⱼ+δ₃𝑥ₖ+δ₄𝑥ₗ+δ₅𝑥ₘ+δ₆𝑥ₙ)² over 𝐿..𝐻
|
||||
*
|
||||
* “As soon as an Analytical Engine exists, it will necessarily
|
||||
* guide the future course of the science. Whenever any result
|
||||
* is sought by its aid, the question will then arise — by what
|
||||
* course of calculation can these results be arrived at by the
|
||||
* machine in the shortest time?
|
||||
*
|
||||
* — Charles Babbage (Life of a Philosopher, 1864)
|
||||
*
|
||||
* @see itu.int/rec/R-REC-BT.601/
|
||||
*/
|
||||
double DifferSumSq(const double D[static 6], double L, double H) {
|
||||
double T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T2, T20, T21, T22,
|
||||
T23, T24, T25, T26, T27, T3, T4, T5, T6, T7, T8, T9;
|
||||
T2 = H * H, T3 = (H * H * H), T4 = (H * H * H * H), T5 = (H * H * H * H * H),
|
||||
T6 = (H * H * H * H * H * H), T7 = -10 * H, T8 = (H * H * H * H * H * H * H),
|
||||
T9 = (L * L * L * L * L * L * L * L), T10 = (L * L * L * L * L * L * L),
|
||||
T11 = (L * L * L * L * L * L), T12 = (L * L * L * L * L), T13 = -45 * T2,
|
||||
T14 = (L * L * L * L), T15 = 180 * T3, T16 = 120 * T2, T17 = (L * L * L),
|
||||
T18 = L * L, T19 = 18 * T2, T20 = (H * H * H * H * H * H * H * H);
|
||||
T21 = 45 * T4;
|
||||
T22 = 3 * T9 + (-12 * H - 18) * T10 + (12 * T2 + 54 * H + 45) * T11 +
|
||||
(12 * T3 - T19 - 90 * H - 60) * T12 +
|
||||
(-30 * T4 - 90 * T3 + T13 + 60 * H + 45) * T14 +
|
||||
(12 * T5 + 90 * T4 + T15 + T16 - 18) * T17 +
|
||||
(12 * T6 + 18 * T5 - T21 - 120 * T3 - 90 * T2 - 18 * H + 3) * T18 +
|
||||
(-12 * T8 - 54 * T6 - 90 * T5 - 60 * T4 + T19 + 6 * H) * L + 3 * T20 +
|
||||
18 * T8 + 45 * T6 + 60 * T5 + T21 + 18 * T3 + 3 * T2;
|
||||
T23 =
|
||||
2 * T9 + (T7 - 13) * T10 + (20 * T2 + 55 * H + 36) * T11 +
|
||||
(-22 * T3 - 93 * T2 - 126 * H - 55) * T12 +
|
||||
(20 * T4 + 95 * T3 + 180 * T2 + 155 * H + 50) * T14 +
|
||||
(-22 * T5 - 95 * T4 - T15 - 190 * T2 - 110 * H - 27) * T17 +
|
||||
(20 * T6 + 93 * T5 + 180 * T4 + 190 * T3 + T16 + 45 * H + 8) * T18 +
|
||||
(-10 * T8 - 55 * T6 - 126 * T5 - 155 * T4 - 110 * T3 + T13 + T7 - 1) * L +
|
||||
2 * T20 + 13 * T8 + 36 * T6 + 55 * T5 + 50 * T4 + 27 * T3 + 8 * T2 + H;
|
||||
T24 = T22 * D[3], T25 = T22 * D[2], T26 = T22 * D[1], T27 = T22 * D[0];
|
||||
return (T23 * D[5] * D[5] + (T22 * D[4] + T24 + T25 + T26 + T27) * D[5] +
|
||||
T23 * D[4] * D[4] + (T24 + T25 + T26 + T27) * D[4] +
|
||||
T23 * D[3] * D[3] + (T25 + T26 + T27) * D[3] + T23 * D[2] * D[2] +
|
||||
(T26 + T27) * D[2] + T23 * D[1] * D[1] + T22 * D[0] * D[1] +
|
||||
T23 * D[0] * D[0]) /
|
||||
6;
|
||||
}
|
463
dsp/core/differsumsq8.c
Normal file
463
dsp/core/differsumsq8.c
Normal file
|
@ -0,0 +1,463 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/q.h"
|
||||
|
||||
/**
|
||||
* Computes Σ𝑥ᵢΣ𝑥ⱼΣ𝑥ₖΣ𝑥ₗΣ𝑥ₘΣ𝑥ₙΣ𝑥ₚΣ𝑥ₛ(δ₁𝑥ᵢ+δ₂𝑥ⱼ+δ₃𝑥ₖ+δ₄𝑥ₗ+δ₅𝑥ₘ+δ₆𝑥ₙ+δₚ𝑥ₚ+δₛ𝑥ₛ)²
|
||||
*
|
||||
* “As soon as an Analytical Engine exists, it will necessarily
|
||||
* guide the future course of the science. Whenever any result
|
||||
* is sought by its aid, the question will then arise — by what
|
||||
* course of calculation can these results be arrived at by the
|
||||
* machine in the shortest time?
|
||||
*
|
||||
* — Charles Babbage (Life of a Philosopher, 1864)
|
||||
*
|
||||
*/
|
||||
double DifferSumSq8(const double D[static 8], double L, double H) {
|
||||
double T10, T100, T101, T102, T103, T104, T105, T106, T107, T108, T109, T11;
|
||||
double T110, T111, T112, T113, T114, T115, T116, T117, T118, T119, T12, T120;
|
||||
double T121, T122, T123, T124, T125, T126, T127, T128, T129, T13, T130, T131;
|
||||
double T132, T133, T134, T135, T136, T137, T138, T139, T14, T140, T141, T142;
|
||||
double T143, T144, T145, T146, T147, T148, T149, T15, T150, T151, T152, T153;
|
||||
double T154, T155, T156, T157, T158, T159, T16, T160, T161, T162, T163, T164;
|
||||
double T165, T166, T167, T168, T169, T17, T170, T171, T172, T173, T174, T175;
|
||||
double T176, T177, T178, T179, T18, T180, T181, T182, T183, T184, T185, T186;
|
||||
double T187, T188, T189, T19, T190, T191, T192, T193, T194, T195, T196, T197;
|
||||
double T198, T199, T2, T20, T200, T201, T202, T203, T204, T205, T206, T207;
|
||||
double T208, T209, T21, T210, T211, T212, T213, T214, T215, T216, T217, T218;
|
||||
double T219, T22, T220, T221, T222, T223, T224, T225, T226, T227, T228, T229;
|
||||
double T230, T231, T232, T233, T234, T235, T236, T237, T238, T239, T24, T240;
|
||||
double T241, T242, T243, T244, T245, T246, T247, T248, T249, T25, T250, T251;
|
||||
double T252, T253, T254, T255, T256, T257, T258, T259, T26, T260, T261, T262;
|
||||
double T263, T264, T265, T266, T267, T268, T269, T27, T270, T271, T272, T273;
|
||||
double T274, T275, T276, T277, T278, T279, T28, T280, T281, T282, T283, T284;
|
||||
double T285, T286, T287, T288, T289, T29, T290, T291, T292, T293, T294, T295;
|
||||
double T296, T297, T298, T299, T3, T30, T300, T301, T302, T303, T304, T305;
|
||||
double T307, T308, T309, T31, T310, T311, T312, T313, T314, T315, T316, T317;
|
||||
double T318, T319, T32, T320, T321, T322, T323, T324, T325, T326, T327, T328;
|
||||
double T329, T33, T330, T331, T332, T333, T334, T335, T336, T337, T338, T339;
|
||||
double T34, T340, T341, T342, T343, T344, T345, T346, T347, T348, T349, T35;
|
||||
double T350, T351, T352, T353, T354, T355, T356, T357, T358, T359, T36, T360;
|
||||
double T361, T362, T363, T364, T365, T366, T367, T368, T369, T37, T370, T371;
|
||||
double T372, T373, T374, T375, T376, T377, T378, T379, T38, T380, T381, T382;
|
||||
double T383, T384, T385, T386, T387, T388, T389, T39, T390, T391, T392, T393;
|
||||
double T394, T395, T396, T397, T398, T399, T4, T40, T400, T401, T402, T403;
|
||||
double T405, T406, T407, T41, T42, T43, T44, T45, T46, T47, T48, T49, T5, T50;
|
||||
double T51, T52, T53, T54, T55, T56, T57, T58, T59, T6, T60, T61, T62, T63;
|
||||
double T65, T66, T67, T68, T69, T7, T70, T71, T72, T73, T74, T75, T76, T77;
|
||||
double T79, T8, T80, T81, T82, T83, T84, T85, T86, T87, T88, T89, T9, T90;
|
||||
double T92, T93, T94, T95, T96, T97, T98, T99, T23, T306, T91, T78, T64, T404;
|
||||
T2 = 4 * D[5], T3 = 3 * D[4], T4 = 3 * D[3], T5 = 3 * D[2], T6 = 3 * D[1],
|
||||
T7 = 3 * D[0], T8 = D[7] * D[7], T9 = D[6] * D[6], T10 = -28 * D[5],
|
||||
T11 = -18 * D[4], T12 = -18 * D[3], T13 = -18 * D[2], T14 = -18 * D[1],
|
||||
T15 = -18 * D[0], T16 = D[5] * D[5], T17 = D[4] * D[4], T18 = D[3] * D[3],
|
||||
T19 = D[2] * D[2], T20 = D[1] * D[1], T21 = D[0] * D[0], T22 = -34 * D[5],
|
||||
T23 = -24 * D[4], T24 = -24 * D[3], T25 = -24 * D[2], T26 = -24 * D[1],
|
||||
T27 = -24 * D[0], T28 = 84 * D[5], T29 = 39 * D[4], T30 = 39 * D[3],
|
||||
T31 = 39 * D[2], T32 = 39 * D[1], T33 = 39 * D[0], T34 = 210 * D[5],
|
||||
T35 = 120 * D[4], T36 = 120 * D[3], T37 = 120 * D[2], T38 = 120 * D[1],
|
||||
T39 = 120 * D[0], T40 = 128 * D[5], T41 = 84 * D[4], T42 = 84 * D[3],
|
||||
T43 = 84 * D[2], T44 = 84 * D[1], T45 = 84 * D[0];
|
||||
T46 = -144 * D[5], T47 = (T23 + T24 + T25 + T26 + T27) * D[5],
|
||||
T48 = (T24 + T25 + T26 + T27) * D[4], T49 = (T25 + T26 + T27) * D[3],
|
||||
T50 = (T26 + T27) * D[2], T51 = -24 * D[0] * D[1], T52 = -552 * D[5],
|
||||
T53 = -192 * D[4], T54 = -192 * D[3], T55 = -192 * D[2], T56 = -192 * D[1],
|
||||
T57 = -192 * D[0], T58 = H * H, T59 = -688 * D[5], T60 = -336 * D[4],
|
||||
T61 = -336 * D[3], T62 = -336 * D[2], T63 = -336 * D[1], T64 = -336 * D[0],
|
||||
T65 = -280 * D[5], T66 = -168 * D[4], T67 = -168 * D[3], T68 = -168 * D[2],
|
||||
T69 = -168 * D[1], T70 = -168 * D[0], T71 = 168 * D[5], T72 = -42 * D[4],
|
||||
T73 = -42 * D[3], T74 = -42 * D[2], T75 = -42 * D[1], T76 = -42 * D[0],
|
||||
T77 = (H * H * H), T78 = 336 * D[4], T79 = 336 * D[3], T80 = 336 * D[2],
|
||||
T81 = 336 * D[1], T82 = 336 * D[0], T83 = 1568 * D[5],
|
||||
T84 = 336 * D[0] * D[1], T85 = 1288 * D[5], T86 = 504 * D[4],
|
||||
T87 = 504 * D[3], T88 = 504 * D[2], T89 = 504 * D[1], T90 = 504 * D[0],
|
||||
T91 = 392 * D[5], T92 = 210 * D[4], T93 = 210 * D[3], T94 = 210 * D[2],
|
||||
T95 = 210 * D[1], T96 = 210 * D[0], T97 = 84 * T8, T98 = 168 * D[6],
|
||||
T99 = 84 * T9, T100 = 84 * T16, T101 = (T41 + T42 + T43 + T44 + T45) * D[5],
|
||||
T102 = 84 * T17, T103 = (T42 + T43 + T44 + T45) * D[4], T104 = 84 * T18,
|
||||
T105 = (T43 + T44 + T45) * D[3], T106 = 84 * T19, T107 = (T44 + T45) * D[2],
|
||||
T108 = 84 * T20, T109 = 84 * D[0] * D[1], T110 = 84 * T21, T111 = -924 * D[5],
|
||||
T112 = (T78 + T79 + T80 + T81 + T82) * D[5],
|
||||
T113 = (T79 + T80 + T81 + T82) * D[4], T114 = (T80 + T81 + T82) * D[3],
|
||||
T115 = (T81 + T82) * D[2], T116 = (H * H * H * H), T117 = -2128 * D[5],
|
||||
T118 = -2520 * D[5], T119 = (T66 + T67 + T68 + T69 + T70) * D[5],
|
||||
T120 = (T67 + T68 + T69 + T70) * D[4], T121 = (T68 + T69 + T70) * D[3],
|
||||
T122 = (T69 + T70) * D[2], T123 = -168 * D[0] * D[1], T124 = -1512 * D[5],
|
||||
T125 = -420 * D[4], T126 = -420 * D[3], T127 = -420 * D[2],
|
||||
T128 = -420 * D[1], T129 = -420 * D[0], T130 = -364 * D[5];
|
||||
T131 = T97 + (T98 + T71 + T72 + T73 + T74 + T75 + T76) * D[7] + T99 +
|
||||
(T71 + T72 + T73 + T74 + T75 + T76) * D[6] + T100 +
|
||||
(T72 + T73 + T74 + T75 + T76) * D[5] + T102 +
|
||||
(T73 + T74 + T75 + T76) * D[4] + T104 + (T74 + T75 + T76) * D[3] +
|
||||
T106 + (T75 + T76) * D[2] + T108 - 42 * D[0] * D[1] + T110;
|
||||
T132 = 462 * T8, T133 = 924 * D[6], T134 = 924 * D[5], T135 = 462 * T9,
|
||||
T136 = 462 * T16, T137 = (T60 + T61 + T62 + T63 + T64) * D[5],
|
||||
T138 = 462 * T17, T139 = (T61 + T62 + T63 + T64) * D[4], T140 = 462 * T18,
|
||||
T141 = (T62 + T63 + T64) * D[3], T142 = 462 * T19, T143 = (T63 + T64) * D[2],
|
||||
T144 = 462 * T20, T145 = 462 * T21, T146 = (H * H * H * H * H),
|
||||
T147 = 2240 * D[5], T148 = -840 * D[4], T149 = -840 * D[3],
|
||||
T150 = -840 * D[2], T151 = -840 * D[1], T152 = -840 * D[0],
|
||||
T153 = 3080 * D[5], T154 = (T148 + T149 + T150 + T151 + T152) * D[5],
|
||||
T155 = (T149 + T150 + T151 + T152) * D[4], T156 = (T150 + T151 + T152) * D[3],
|
||||
T157 = (T151 + T152) * D[2], T158 = -840 * D[0] * D[1], T159 = 1260 * T8,
|
||||
T160 = 2520 * D[6], T161 = 2520 * D[5], T162 = 1260 * T9, T163 = 1260 * T16,
|
||||
T164 = 1260 * T17, T165 = 1260 * T18, T166 = 1260 * T19, T167 = 1260 * T20,
|
||||
T168 = 210 * D[0] * D[1], T169 = 1260 * T21, T170 = 168 * D[4],
|
||||
T171 = 168 * D[3], T172 = 168 * D[2], T173 = 168 * D[1], T174 = 168 * D[0],
|
||||
T175 = 1148 * D[5], T176 = 168 * D[0] * D[1], T177 = 224 * D[5];
|
||||
T178 = -72 * T8 + (-144 * D[6] + T46 + T23 + T24 + T25 + T26 + T27) * D[7] -
|
||||
72 * T9 + (T46 + T23 + T24 + T25 + T26 + T27) * D[6] - 72 * T16 + T47 -
|
||||
72 * T17 + T48 - 72 * T18 + T49 - 72 * T19 + T50 - 72 * T20 + T51 -
|
||||
72 * T21;
|
||||
T179 = 420 * T8, T180 = 840 * D[6], T181 = 840 * D[5], T182 = 420 * T9,
|
||||
T183 = 840 * D[5] * D[6], T184 = 420 * T16, T185 = 420 * T17,
|
||||
T186 = 420 * T18, T187 = 420 * T19, T188 = 420 * T20, T189 = 420 * T21,
|
||||
T190 = (H * H * H * H * H * H);
|
||||
T191 = -1064 * T8 +
|
||||
(-2128 * D[6] + T117 + T78 + T79 + T80 + T81 + T82) * D[7] -
|
||||
1064 * T9 + (T117 + T78 + T79 + T80 + T81 + T82) * D[6] - 1064 * T16 +
|
||||
T112 - 1064 * T17 + T113 - 1064 * T18 + T114 - 1064 * T19 + T115 -
|
||||
1064 * T20 + T84 - 1064 * T21;
|
||||
T192 = 1540 * T8, T193 = 3080 * D[6], T194 = 840 * D[4], T195 = 840 * D[3],
|
||||
T196 = 840 * D[2], T197 = 840 * D[1], T198 = 840 * D[0], T199 = 1540 * T9,
|
||||
T200 = 1540 * T16, T201 = 1540 * T17, T202 = 1540 * T18, T203 = 1540 * T19,
|
||||
T204 = 1540 * T20, T205 = 840 * D[0] * D[1], T206 = 1540 * T21,
|
||||
T207 = -2800 * D[5], T208 = (T194 + T195 + T196 + T197 + T198) * D[5],
|
||||
T209 = (T195 + T196 + T197 + T198) * D[4], T210 = (T196 + T197 + T198) * D[3],
|
||||
T211 = (T197 + T198) * D[2], T212 = -1624 * D[5], T213 = -88 * D[5];
|
||||
T214 = 42 * T8 + (84 * D[6] + T28 + T29 + T30 + T31 + T32 + T33) * D[7] +
|
||||
42 * T9 + (T28 + T29 + T30 + T31 + T32 + T33) * D[6] + 42 * T16 +
|
||||
(T29 + T30 + T31 + T32 + T33) * D[5] + 42 * T17 +
|
||||
(T30 + T31 + T32 + T33) * D[4] + 42 * T18 + (T31 + T32 + T33) * D[3] +
|
||||
42 * T19 + (T32 + T33) * D[2] + 42 * T20 + 39 * D[0] * D[1] + 42 * T21;
|
||||
T215 = 276 * T8, T216 = 552 * D[6], T217 = 552 * D[5], T218 = 192 * D[4],
|
||||
T219 = 192 * D[3], T220 = 192 * D[2], T221 = 192 * D[1], T222 = 192 * D[0],
|
||||
T223 = 276 * T9, T224 = 276 * T16, T225 = 276 * T17, T226 = 276 * T18,
|
||||
T227 = 276 * T19, T228 = 276 * T20, T229 = 192 * D[0] * D[1],
|
||||
T230 = 276 * T21, T231 = (H * H * H * H * H * H * H);
|
||||
T232 = 784 * T8 + (1568 * D[6] + T83 + T78 + T79 + T80 + T81 + T82) * D[7] +
|
||||
784 * T9 + (T83 + T78 + T79 + T80 + T81 + T82) * D[6] + 784 * T16 +
|
||||
T112 + 784 * T17 + T113 + 784 * T18 + T114 + 784 * T19 + T115 +
|
||||
784 * T20 + T84 + 784 * T21;
|
||||
T233 = (T170 + T171 + T172 + T173 + T174) * D[5];
|
||||
T234 = (T171 + T172 + T173 + T174) * D[4];
|
||||
T235 = (T172 + T173 + T174) * D[3];
|
||||
T236 = (T173 + T174) * D[2];
|
||||
T237 = T159 + (T160 + T161 - T92 - T93 - T94 - T95 - T96) * D[7] + T162 +
|
||||
(T161 - T92 - T93 - T94 - T95 - T96) * D[6] + T163 +
|
||||
(-T92 - T93 - T94 - T95 - T96) * D[5] + T164 +
|
||||
(-T93 - T94 - T95 - T96) * D[4] + T165 + (-T94 - T95 - T96) * D[3] +
|
||||
T166 + (-T95 - T96) * D[2] + T167 - T168 + T169;
|
||||
T238 = 812 * T8, T239 = 1624 * D[6], T240 = 1624 * D[5], T241 = 812 * T9,
|
||||
T242 = 812 * T16, T243 = 812 * T17, T244 = 812 * T18, T245 = 812 * T19,
|
||||
T246 = 812 * T20, T247 = 812 * T21, T248 = 672 * D[5], T249 = 20 * D[5],
|
||||
T250 = (T3 + T4 + T5 + T6 + T7) * D[5], T251 = (T4 + T5 + T6 + T7) * D[4],
|
||||
T252 = (T5 + T6 + T7) * D[3], T253 = (T6 + T7) * D[2], T254 = 3 * D[0] * D[1];
|
||||
T255 = -14 * T8 + (-28 * D[6] + T10 + T11 + T12 + T13 + T14 + T15) * D[7] -
|
||||
14 * T9 + (T10 + T11 + T12 + T13 + T14 + T15) * D[6] - 14 * T16 +
|
||||
(T11 + T12 + T13 + T14 + T15) * D[5] - 14 * T17 +
|
||||
(T12 + T13 + T14 + T15) * D[4] - 14 * T18 + (T13 + T14 + T15) * D[3] -
|
||||
14 * T19 + (T14 + T15) * D[2] - 14 * T20 - 18 * D[0] * D[1] - 14 * T21;
|
||||
T256 = 105 * T8, T257 = 210 * D[6], T258 = 105 * T9, T259 = 105 * T16,
|
||||
T260 = 105 * T17, T261 = 105 * T18, T262 = 105 * T19, T263 = 105 * T20,
|
||||
T264 = 120 * D[0] * D[1], T265 = 105 * T21,
|
||||
T266 = (H * H * H * H * H * H * H * H);
|
||||
T267 = -344 * T8 + (-688 * D[6] + T59 + T60 + T61 + T62 + T63 + T64) * D[7] -
|
||||
344 * T9 + (T59 + T60 + T61 + T62 + T63 + T64) * D[6] - 344 * T16 +
|
||||
T137 - 344 * T17 + T139 - 344 * T18 + T141 - 344 * T19 + T143 -
|
||||
344 * T20 - T84 - 344 * T21;
|
||||
T268 = 644 * T8, T269 = 1288 * D[6], T270 = 644 * T9, T271 = 644 * T16,
|
||||
T272 = 644 * T17, T273 = 644 * T18, T274 = 644 * T19, T275 = 644 * T20,
|
||||
T276 = 504 * D[0] * D[1], T277 = 644 * T21;
|
||||
T278 = -756 * T8 +
|
||||
(-1512 * D[6] + T124 + T125 + T126 + T127 + T128 + T129) * D[7] -
|
||||
756 * T9 + (T124 + T125 + T126 + T127 + T128 + T129) * D[6] -
|
||||
756 * T16 + (T125 + T126 + T127 + T128 + T129) * D[5] - 756 * T17 +
|
||||
(T126 + T127 + T128 + T129) * D[4] - 756 * T18 +
|
||||
(T127 + T128 + T129) * D[3] - 756 * T19 + (T128 + T129) * D[2] -
|
||||
756 * T20 - 420 * D[0] * D[1] - 756 * T21;
|
||||
T279 = 574 * T8, T280 = 1148 * D[6], T281 = 574 * T9, T282 = 574 * T16,
|
||||
T283 = 574 * T17, T284 = 574 * T18, T285 = 574 * T19, T286 = 574 * T20,
|
||||
T287 = 574 * T21;
|
||||
T288 = -280 * T8 + (-560 * D[6] - 560 * D[5]) * D[7] - 280 * T9 -
|
||||
560 * D[5] * D[6] - 280 * T16 - 280 * T17 - 280 * T18 - 280 * T19 -
|
||||
280 * T20 - 280 * T21;
|
||||
T289 = 24 * D[4], T290 = 24 * D[3], T291 = 24 * D[2], T292 = 24 * D[1],
|
||||
T293 = 24 * D[0], T294 = 24 * D[0] * D[1], T295 = -14 * T8, T296 = -28 * D[6],
|
||||
T297 = -14 * T9, T298 = 6 * D[4], T299 = 6 * D[3], T300 = 6 * D[2],
|
||||
T301 = 6 * D[1], T302 = 6 * D[0], T303 = -14 * T16, T304 = -14 * T17,
|
||||
T305 = -14 * T18, T306 = -14 * T19, T307 = -14 * T20, T308 = -14 * T21;
|
||||
T309 = 2 * T8 + (4 * D[6] + T2 + T3 + T4 + T5 + T6 + T7) * D[7] + 2 * T9 +
|
||||
(T2 + T3 + T4 + T5 + T6 + T7) * D[6] + 2 * T16 + T250 + 2 * T17 +
|
||||
T251 + 2 * T18 + T252 + 2 * T19 + T253 + 2 * T20 + T254 + 2 * T21;
|
||||
T310 = 17 * T8, T311 = 34 * D[6], T312 = 34 * D[5], T313 = 17 * T9,
|
||||
T314 = 17 * T16, T315 = (T289 + T290 + T291 + T292 + T293) * D[5];
|
||||
T316 = 17 * T17, T317 = (T290 + T291 + T292 + T293) * D[4];
|
||||
T318 = 17 * T18, T319 = (T291 + T292 + T293) * D[3];
|
||||
T320 = 17 * T19, T321 = (T292 + T293) * D[2];
|
||||
T322 = 17 * T20, T323 = 17 * T21, T324 = (H * H * H * H * H * H * H * H * H);
|
||||
T325 = 64 * T8,
|
||||
T326 = (128 * D[6] + T40 + T41 + T42 + T43 + T44 + T45) * D[7];
|
||||
T327 = 64 * T9, T328 = (T40 + T41 + T42 + T43 + T44 + T45) * D[6];
|
||||
T329 = 64 * T16, T330 = 64 * T17, T331 = 64 * T18, T332 = 64 * T19,
|
||||
T333 = 64 * T20, T334 = 64 * T21, T335 = 140 * T8, T336 = 280 * D[6],
|
||||
T337 = 280 * D[5], T338 = 140 * T9, T339 = 140 * T16, T340 = 140 * T17,
|
||||
T341 = 140 * T18, T342 = 140 * T19, T343 = 140 * T20, T344 = 140 * T21,
|
||||
T345 = 196 * T8;
|
||||
T346 = (392 * D[6] + T91 + T92 + T93 + T94 + T95 + T96) * D[7];
|
||||
T347 = 196 * T9;
|
||||
T348 = (T91 + T92 + T93 + T94 + T95 + T96) * D[6];
|
||||
T349 = 196 * T16;
|
||||
T350 = (T92 + T93 + T94 + T95 + T96) * D[5];
|
||||
T351 = 196 * T17;
|
||||
T352 = (T93 + T94 + T95 + T96) * D[4];
|
||||
T353 = 196 * T18;
|
||||
T354 = (T94 + T95 + T96) * D[3];
|
||||
T355 = 196 * T19;
|
||||
T356 = (T95 + T96) * D[2];
|
||||
T357 = 196 * T20, T358 = 196 * T21, T359 = 182 * T8, T360 = 364 * D[6],
|
||||
T361 = 364 * D[5], T362 = 182 * T9, T363 = 182 * T16, T364 = 182 * T17,
|
||||
T365 = 182 * T18, T366 = 182 * T19, T367 = 182 * T20, T368 = 182 * T21,
|
||||
T369 = 112 * T8;
|
||||
T370 = (224 * D[6] + T177 + T41 + T42 + T43 + T44 + T45) * D[7];
|
||||
T371 = 112 * T9;
|
||||
T372 = (T177 + T41 + T42 + T43 + T44 + T45) * D[6];
|
||||
T373 = 112 * T16, T374 = 112 * T17, T375 = 112 * T18, T376 = 112 * T19,
|
||||
T377 = 112 * T20, T378 = 112 * T21, T379 = 44 * T8, T380 = 88 * D[6],
|
||||
T381 = 88 * D[5], T382 = 44 * T9, T383 = 44 * T16, T384 = 44 * T17,
|
||||
T385 = 44 * T18, T386 = 44 * T19, T387 = 44 * T20, T388 = 44 * T21,
|
||||
T389 = 10 * T8, T390 = (20 * D[6] + T249 + T3 + T4 + T5 + T6 + T7) * D[7];
|
||||
T391 = 10 * T9, T392 = (T249 + T3 + T4 + T5 + T6 + T7) * D[6];
|
||||
T393 = 10 * T16, T394 = 10 * T17, T395 = 10 * T18, T396 = 10 * T19,
|
||||
T397 = 10 * T20, T398 = 10 * T21, T399 = 2 * D[6], T400 = 2 * D[5],
|
||||
T401 = 2 * D[5] * D[6];
|
||||
T402 = T309 * (L * L * L * L * L * L * L * L * L * L) +
|
||||
(T255 * H - T310 + (-T311 + T22 + T23 + T24 + T25 + T26 + T27) * D[7] -
|
||||
T313 + (T22 + T23 + T24 + T25 + T26 + T27) * D[6] - T314 + T47 -
|
||||
T316 + T48 - T318 + T49 - T320 + T50 - T322 + T51 - T323) *
|
||||
(L * L * L * L * L * L * L * L * L) +
|
||||
(T214 * T58 +
|
||||
(T256 + (T257 + T34 + T35 + T36 + T37 + T38 + T39) * D[7] + T258 +
|
||||
(T34 + T35 + T36 + T37 + T38 + T39) * D[6] + T259 +
|
||||
(T35 + T36 + T37 + T38 + T39) * D[5] + T260 +
|
||||
(T36 + T37 + T38 + T39) * D[4] + T261 + (T37 + T38 + T39) * D[3] +
|
||||
T262 + (T38 + T39) * D[2] + T263 + T264 + T265) *
|
||||
H +
|
||||
T325 + T326 + T327 + T328 + T329 + T101 + T330 + T103 + T331 + T105 +
|
||||
T332 + T107 + T333 + T109 + T334) *
|
||||
(L * L * L * L * L * L * L * L) +
|
||||
(T178 * T77 +
|
||||
(-T215 + (-T216 + T52 + T53 + T54 + T55 + T56 + T57) * D[7] - T223 +
|
||||
(T52 + T53 + T54 + T55 + T56 + T57) * D[6] - T224 +
|
||||
(T53 + T54 + T55 + T56 + T57) * D[5] - T225 +
|
||||
(T54 + T55 + T56 + T57) * D[4] - T226 + (T55 + T56 + T57) * D[3] -
|
||||
T227 + (T56 + T57) * D[2] - T228 - T229 - T230) *
|
||||
T58 +
|
||||
T267 * H - T335 + (-T336 + T65 + T66 + T67 + T68 + T69 + T70) * D[7] -
|
||||
T338 + (T65 + T66 + T67 + T68 + T69 + T70) * D[6] - T339 + T119 -
|
||||
T340 + T120 - T341 + T121 - T342 + T122 - T343 + T123 - T344) *
|
||||
(L * L * L * L * L * L * L);
|
||||
T403 =
|
||||
T402 +
|
||||
(T131 * T116 +
|
||||
(T179 + (T180 + T181) * D[7] + T182 + T183 + T184 + T185 + T186 + T187 +
|
||||
T188 + T189) *
|
||||
T77 +
|
||||
T232 * T58 +
|
||||
(T268 + (T269 + T85 + T86 + T87 + T88 + T89 + T90) * D[7] + T270 +
|
||||
(T85 + T86 + T87 + T88 + T89 + T90) * D[6] + T271 +
|
||||
(T86 + T87 + T88 + T89 + T90) * D[5] + T272 +
|
||||
(T87 + T88 + T89 + T90) * D[4] + T273 + (T88 + T89 + T90) * D[3] +
|
||||
T274 + (T89 + T90) * D[2] + T275 + T276 + T277) *
|
||||
H +
|
||||
T345 + T346 + T347 + T348 + T349 + T350 + T351 + T352 + T353 + T354 +
|
||||
T355 + T356 + T357 + T168 + T358) *
|
||||
(L * L * L * L * L * L) +
|
||||
((-T97 + (-T98 - T71 + T41 + T42 + T43 + T44 + T45) * D[7] - T99 +
|
||||
(-T71 + T41 + T42 + T43 + T44 + T45) * D[6] - T100 + T101 - T102 +
|
||||
T103 - T104 + T105 - T106 + T107 - T108 + T109 - T110) *
|
||||
T146 +
|
||||
(-T132 + (-T133 + T111 + T78 + T79 + T80 + T81 + T82) * D[7] - T135 +
|
||||
(T111 + T78 + T79 + T80 + T81 + T82) * D[6] - T136 + T112 - T138 +
|
||||
T113 - T140 + T114 - T142 + T115 - T144 + T84 - T145) *
|
||||
T116 +
|
||||
T191 * T77 +
|
||||
(-T159 + (-T160 + T118 + T66 + T67 + T68 + T69 + T70) * D[7] - T162 +
|
||||
(T118 + T66 + T67 + T68 + T69 + T70) * D[6] - T163 + T119 - T164 +
|
||||
T120 - T165 + T121 - T166 + T122 - T167 + T123 - T169) *
|
||||
T58 +
|
||||
T278 * H - T359 + (-T360 + T130 + T66 + T67 + T68 + T69 + T70) * D[7] -
|
||||
T362 + (T130 + T66 + T67 + T68 + T69 + T70) * D[6] - T363 + T119 - T364 +
|
||||
T120 - T365 + T121 - T366 + T122 - T367 + T123 - T368) *
|
||||
(L * L * L * L * L);
|
||||
T404 =
|
||||
T403 +
|
||||
(T131 * T190 +
|
||||
(T132 + (T133 + T134 + T60 + T61 + T62 + T63 + T64) * D[7] + T135 +
|
||||
(T134 + T60 + T61 + T62 + T63 + T64) * D[6] + T136 + T137 + T138 +
|
||||
T139 + T140 + T141 + T142 + T143 + T144 - T84 + T145) *
|
||||
T146 +
|
||||
(1120 * T8 +
|
||||
(2240 * D[6] + T147 + T148 + T149 + T150 + T151 + T152) * D[7] +
|
||||
1120 * T9 + (T147 + T148 + T149 + T150 + T151 + T152) * D[6] +
|
||||
1120 * T16 + T154 + 1120 * T17 + T155 + 1120 * T18 + T156 + 1120 * T19 +
|
||||
T157 + 1120 * T20 + T158 + 1120 * T21) *
|
||||
T116 +
|
||||
(T192 + (T193 + T153 + T148 + T149 + T150 + T151 + T152) * D[7] + T199 +
|
||||
(T153 + T148 + T149 + T150 + T151 + T152) * D[6] + T200 + T154 + T201 +
|
||||
T155 + T202 + T156 + T203 + T157 + T204 + T158 + T206) *
|
||||
T77 +
|
||||
T237 * T58 +
|
||||
(T279 + (T280 + T175 + T170 + T171 + T172 + T173 + T174) * D[7] + T281 +
|
||||
(T175 + T170 + T171 + T172 + T173 + T174) * D[6] + T282 + T233 + T283 +
|
||||
T234 + T284 + T235 + T285 + T236 + T286 + T176 + T287) *
|
||||
H +
|
||||
T369 + T370 + T371 + T372 + T373 + T101 + T374 + T103 + T375 + T105 +
|
||||
T376 + T107 + T377 + T109 + T378) *
|
||||
(L * L * L * L) +
|
||||
(T178 * T231 +
|
||||
(-T179 + (-T180 - T181) * D[7] - T182 - T183 - T184 - T185 - T186 -
|
||||
T187 - T188 - T189) *
|
||||
T190 +
|
||||
T191 * T146 +
|
||||
(-T192 + (-T193 - T153 + T194 + T195 + T196 + T197 + T198) * D[7] -
|
||||
T199 + (-T153 + T194 + T195 + T196 + T197 + T198) * D[6] - T200 + T208 -
|
||||
T201 + T209 - T202 + T210 - T203 + T211 - T204 + T205 - T206) *
|
||||
T116 +
|
||||
(-1400 * T8 +
|
||||
(-2800 * D[6] + T207 + T194 + T195 + T196 + T197 + T198) * D[7] -
|
||||
1400 * T9 + (T207 + T194 + T195 + T196 + T197 + T198) * D[6] -
|
||||
1400 * T16 + T208 - 1400 * T17 + T209 - 1400 * T18 + T210 - 1400 * T19 +
|
||||
T211 - 1400 * T20 + T205 - 1400 * T21) *
|
||||
T77 +
|
||||
(-T238 + (-T239 + T212 + T78 + T79 + T80 + T81 + T82) * D[7] - T241 +
|
||||
(T212 + T78 + T79 + T80 + T81 + T82) * D[6] - T242 + T112 - T243 +
|
||||
T113 - T244 + T114 - T245 + T115 - T246 + T84 - T247) *
|
||||
T58 +
|
||||
T288 * H - T379 + (-T380 + T213 + T23 + T24 + T25 + T26 + T27) * D[7] -
|
||||
T382 + (T213 + T23 + T24 + T25 + T26 + T27) * D[6] - T383 + T47 - T384 +
|
||||
T48 - T385 + T49 - T386 + T50 - T387 + T51 - T388) *
|
||||
(L * L * L);
|
||||
T405 =
|
||||
T214 * T266 +
|
||||
(T215 + (T216 + T217 + T218 + T219 + T220 + T221 + T222) * D[7] + T223 +
|
||||
(T217 + T218 + T219 + T220 + T221 + T222) * D[6] + T224 +
|
||||
(T218 + T219 + T220 + T221 + T222) * D[5] + T225 +
|
||||
(T219 + T220 + T221 + T222) * D[4] + T226 + (T220 + T221 + T222) * D[3] +
|
||||
T227 + (T221 + T222) * D[2] + T228 + T229 + T230) *
|
||||
T231 +
|
||||
T232 * T190 +
|
||||
(T159 + (T160 + T161 + T170 + T171 + T172 + T173 + T174) * D[7] + T162 +
|
||||
(T161 + T170 + T171 + T172 + T173 + T174) * D[6] + T163 + T233 + T164 +
|
||||
T234 + T165 + T235 + T166 + T236 + T167 + T176 + T169) *
|
||||
T146 +
|
||||
T237 * T116 +
|
||||
(T238 + (T239 + T240 + T60 + T61 + T62 + T63 + T64) * D[7] + T241 +
|
||||
(T240 + T60 + T61 + T62 + T63 + T64) * D[6] + T242 + T137 + T243 + T139 +
|
||||
T244 + T141 + T245 + T143 + T246 - T84 + T247) *
|
||||
T77 +
|
||||
(336 * T8 + (672 * D[6] + T248 + T66 + T67 + T68 + T69 + T70) * D[7] +
|
||||
336 * T9 + (T248 + T66 + T67 + T68 + T69 + T70) * D[6] + 336 * T16 +
|
||||
T119 + 336 * T17 + T120 + 336 * T18 + T121 + 336 * T19 + T122 +
|
||||
336 * T20 - T176 + 336 * T21) *
|
||||
T58 +
|
||||
(T97 + (T98 + T71 + T23 + T24 + T25 + T26 + T27) * D[7] + T99 +
|
||||
(T71 + T23 + T24 + T25 + T26 + T27) * D[6] + T100 + T47 + T102 + T48 +
|
||||
T104 + T49 + T106 + T50 + T108 + T51 + T110) *
|
||||
H +
|
||||
T389 + T390 + T391;
|
||||
T406 = T255 * T324 +
|
||||
(-T256 + (-T257 - T34 - T35 - T36 - T37 - T38 - T39) * D[7] - T258 +
|
||||
(-T34 - T35 - T36 - T37 - T38 - T39) * D[6] - T259 +
|
||||
(-T35 - T36 - T37 - T38 - T39) * D[5] - T260 +
|
||||
(-T36 - T37 - T38 - T39) * D[4] - T261 + (-T37 - T38 - T39) * D[3] -
|
||||
T262 + (-T38 - T39) * D[2] - T263 - T264 - T265) *
|
||||
T266 +
|
||||
T267 * T231 +
|
||||
(-T268 + (-T269 - T85 - T86 - T87 - T88 - T89 - T90) * D[7] - T270 +
|
||||
(-T85 - T86 - T87 - T88 - T89 - T90) * D[6] - T271 +
|
||||
(-T86 - T87 - T88 - T89 - T90) * D[5] - T272 +
|
||||
(-T87 - T88 - T89 - T90) * D[4] - T273 + (-T88 - T89 - T90) * D[3] -
|
||||
T274 + (-T89 - T90) * D[2] - T275 - T276 - T277) *
|
||||
T190 +
|
||||
T278 * T146 +
|
||||
(-T279 + (-T280 - T175 + T66 + T67 + T68 + T69 + T70) * D[7] - T281 +
|
||||
(-T175 + T66 + T67 + T68 + T69 + T70) * D[6] - T282 + T119 - T283 +
|
||||
T120 - T284 + T121 - T285 + T122 - T286 - T176 - T287) *
|
||||
T116 +
|
||||
T288 * T77 +
|
||||
(-T97 + (-T98 - T71 + T289 + T290 + T291 + T292 + T293) * D[7] - T99 +
|
||||
(-T71 + T289 + T290 + T291 + T292 + T293) * D[6] - T100 + T315 -
|
||||
T102 + T317 - T104 + T319 - T106 + T321 - T108 + T294 - T110) *
|
||||
T58;
|
||||
T407 = T404 +
|
||||
(T405 + T392 + T393 + T250 + T394 + T251 + T395 + T252 + T396 + T253 +
|
||||
T397 + T254 + T398) *
|
||||
L * L +
|
||||
(T406 +
|
||||
(T295 + (T296 + T10 + T298 + T299 + T300 + T301 + T302) * D[7] +
|
||||
T297 + (T10 + T298 + T299 + T300 + T301 + T302) * D[6] + T303 +
|
||||
(T298 + T299 + T300 + T301 + T302) * D[5] + T304 +
|
||||
(T299 + T300 + T301 + T302) * D[4] + T305 +
|
||||
(T300 + T301 + T302) * D[3] + T306 + (T301 + T302) * D[2] + T307 +
|
||||
6 * D[0] * D[1] + T308) *
|
||||
H -
|
||||
T8 + (-T399 - T400) * D[7] - T9 - T401 - T16 - T17 - T18 - T19 - T20 -
|
||||
T21) *
|
||||
L +
|
||||
T309 * (H * H * H * H * H * H * H * H * H * H) +
|
||||
(T310 + (T311 + T312 + T289 + T290 + T291 + T292 + T293) * D[7] +
|
||||
T313 + (T312 + T289 + T290 + T291 + T292 + T293) * D[6] + T314 +
|
||||
T315 + T316 + T317 + T318 + T319 + T320 + T321 + T322 + T294 + T323) *
|
||||
T324 +
|
||||
(T325 + T326 + T327 + T328 + T329 + T101 + T330 + T103 + T331 + T105 +
|
||||
T332 + T107 + T333 + T109 + T334) *
|
||||
T266 +
|
||||
(T335 + (T336 + T337 + T170 + T171 + T172 + T173 + T174) * D[7] +
|
||||
T338 + (T337 + T170 + T171 + T172 + T173 + T174) * D[6] + T339 +
|
||||
T233 + T340 + T234 + T341 + T235 + T342 + T236 + T343 + T176 + T344) *
|
||||
T231 +
|
||||
(T345 + T346 + T347 + T348 + T349 + T350 + T351 + T352 + T353 + T354 +
|
||||
T355 + T356 + T357 + T168 + T358) *
|
||||
T190;
|
||||
return (T407 +
|
||||
(T359 + (T360 + T361 + T170 + T171 + T172 + T173 + T174) * D[7] +
|
||||
T362 + (T361 + T170 + T171 + T172 + T173 + T174) * D[6] + T363 +
|
||||
T233 + T364 + T234 + T365 + T235 + T366 + T236 + T367 + T176 +
|
||||
T368) *
|
||||
T146 +
|
||||
(T369 + T370 + T371 + T372 + T373 + T101 + T374 + T103 + T375 + T105 +
|
||||
T376 + T107 + T377 + T109 + T378) *
|
||||
T116 +
|
||||
(T379 + (T380 + T381 + T289 + T290 + T291 + T292 + T293) * D[7] +
|
||||
T382 + (T381 + T289 + T290 + T291 + T292 + T293) * D[6] + T383 +
|
||||
T315 + T384 + T317 + T385 + T319 + T386 + T321 + T387 + T294 +
|
||||
T388) *
|
||||
T77 +
|
||||
(T389 + T390 + T391 + T392 + T393 + T250 + T394 + T251 + T395 + T252 +
|
||||
T396 + T253 + T397 + T254 + T398) *
|
||||
T58 +
|
||||
(T8 + (T399 + T400) * D[7] + T9 + T401 + T16 + T17 + T18 + T19 + T20 +
|
||||
T21) *
|
||||
H) /
|
||||
6;
|
||||
}
|
35
dsp/core/double2byte.c
Normal file
35
dsp/core/double2byte.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
void *double2byte(long n, const void *p, double weight, double bias) {
|
||||
long i;
|
||||
const double *src;
|
||||
unsigned char *dst;
|
||||
if ((dst = valloc(n * sizeof(unsigned char)))) {
|
||||
for (src = p, i = 0; i < n; ++i) {
|
||||
dst[i] = MIN(255, MAX(0, rint(src[i] * weight + bias)));
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
41
dsp/core/float2short.c
Normal file
41
dsp/core/float2short.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Converts floating point audio samples to pulse code modulation.
|
||||
*
|
||||
* @param rdi is number of sample chunks
|
||||
* @param rsi points to aligned pcm [-32k,+32k] output memory
|
||||
* @param rdx points to aligned float32 [-1,+1] input memory
|
||||
*/
|
||||
void float2short(size_t n, short pcm16[n][8], const float binary32[n][8]) {
|
||||
size_t i, j;
|
||||
float f[8], w[8];
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm16[i][j] =
|
||||
MIN(SHRT_MAX, MAX(SHRT_MIN, floorf(binary32[i][j] * (SHRT_MAX + 1))));
|
||||
}
|
||||
}
|
||||
}
|
40
dsp/core/gamma.c
Normal file
40
dsp/core/gamma.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/gamma.h"
|
||||
#include "libc/math.h"
|
||||
|
||||
double rgb2stdpc(double x, double g) {
|
||||
return COMPANDLUMA_SRGB(x, g);
|
||||
}
|
||||
double rgb2linpc(double x, double g) {
|
||||
return UNCOMPANDLUMA_SRGB(x, g);
|
||||
}
|
||||
|
||||
double rgb2stdtv(double x) {
|
||||
return COMPANDLUMA_BT1886(x);
|
||||
}
|
||||
double rgb2lintv(double x) {
|
||||
return UNCOMPANDLUMA_BT1886(x);
|
||||
}
|
||||
|
||||
double tv2pcgamma(double x, double g) {
|
||||
return rgb2stdpc(rgb2lintv(x), g);
|
||||
}
|
23
dsp/core/gamma.h
Normal file
23
dsp/core/gamma.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_GAMMA_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_GAMMA_H_
|
||||
#include "libc/math.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define COMPANDLUMA(X, ...) COMPANDLUMA_(X, __VA_ARGS__)
|
||||
#define COMPANDLUMA_(X, K1, K2, K3, K4) \
|
||||
((X) > (K3) / (K4) ? (1 + (K2)) * pow((X), 1 / (K1)) - (K2) : (X) * (K4))
|
||||
|
||||
#define UNCOMPANDLUMA(X, ...) UNCOMPANDLUMA_(X, __VA_ARGS__)
|
||||
#define UNCOMPANDLUMA_(X, K1, K2, K3, K4) \
|
||||
((X) > (K3) ? pow(1 / (1 + (K2)) * ((X) + (K2)), K1) : (X) / (K4))
|
||||
|
||||
#define COMPANDLUMA_SRGB_MAGNUM .055, .04045, 12.92
|
||||
#define COMPANDLUMA_SRGB(X, G) COMPANDLUMA(X, G, COMPANDLUMA_SRGB_MAGNUM)
|
||||
#define UNCOMPANDLUMA_SRGB(X, G) UNCOMPANDLUMA(X, G, COMPANDLUMA_SRGB_MAGNUM)
|
||||
|
||||
#define COMPANDLUMA_BT1886_MAGNUM 1 / .45, .099, .081, 4.5
|
||||
#define COMPANDLUMA_BT1886(X) COMPANDLUMA(X, COMPANDLUMA_BT1886_MAGNUM)
|
||||
#define UNCOMPANDLUMA_BT1886(X) UNCOMPANDLUMA(X, COMPANDLUMA_BT1886_MAGNUM)
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_GAMMA_H_ */
|
113
dsp/core/getintegercoefficients.c
Normal file
113
dsp/core/getintegercoefficients.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/q.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Precomputes integers that can replace floating-point operands.
|
||||
*
|
||||
* “G-d made the integers, all else is the work of man.
|
||||
* — Leopold Kronecker
|
||||
*
|
||||
* This function shifts the decimal point to the left:
|
||||
*
|
||||
* 𝑛ᵢ ← ROUND[𝑐ᵢ × 2ᵐ] + φᵢ
|
||||
*
|
||||
* With extra effort to compute φ which is normally all zeroes but gives
|
||||
* us better rounding when it isn't. It's assumed optimized coefficients
|
||||
* will be used like this:
|
||||
*
|
||||
* (Σᵢ𝑥ᵢ𝑛ᵢ + 2⁽ᵐ⁻¹⁾) / 2ᵐ where 𝑥∈[𝐿,𝐻] and 𝑖∈[0,6)
|
||||
*
|
||||
* Intended to compute this
|
||||
*
|
||||
* ROUND[Σᵢ𝑥ᵢ𝑐ᵢ]
|
||||
*
|
||||
* As accurately or approximately as you want it to be. Popular scaling
|
||||
* factors are 7, 15, 16, 22, and 31. Building this code under MODE=tiny
|
||||
* will DCE the math.
|
||||
*
|
||||
* @param N receives optimized integers
|
||||
* @param C provides ideal coefficients
|
||||
* @param M is log₂ scaling factor, e.g. 7
|
||||
* @param L is minimum input data size, e.g. 0
|
||||
* @param H is maximum input data size, e.g. 255
|
||||
* @return sum of errors for all inputs
|
||||
* @see en.wikipedia.org/wiki/Binary_scaling
|
||||
* @see o/tool/build/coefficients.com
|
||||
* @cost ~300ns
|
||||
*/
|
||||
long GetIntegerCoefficients(long N[static 6], const double C[static 6], long M,
|
||||
long L, long H) {
|
||||
int i;
|
||||
int j[6], J[6];
|
||||
int O[6] = {0};
|
||||
int S[3] = {0, -1, +1};
|
||||
double R[6], K[6], D[6], HM, HL, least, error;
|
||||
least = 1;
|
||||
HM = 1L << M;
|
||||
HL = H - L + 1;
|
||||
assert(H >= L);
|
||||
assert(HL <= HM);
|
||||
for (i = 0; i < 6; ++i) {
|
||||
least *= HL;
|
||||
if (fabs(C[i]) > DBL_MIN) {
|
||||
J[i] = ARRAYLEN(S);
|
||||
R[i] = C[i] * HM;
|
||||
K[i] = rint(R[i]);
|
||||
N[i] = K[i];
|
||||
} else {
|
||||
J[i] = 1;
|
||||
R[i] = 0;
|
||||
K[i] = 0;
|
||||
N[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!IsTiny() && least > 1) {
|
||||
for (j[0] = 0; j[0] < J[0]; ++j[0]) {
|
||||
for (j[1] = 0; j[1] < J[1]; ++j[1]) {
|
||||
for (j[2] = 0; j[2] < J[2]; ++j[2]) {
|
||||
for (j[3] = 0; j[3] < J[3]; ++j[3]) {
|
||||
for (j[4] = 0; j[4] < J[4]; ++j[4]) {
|
||||
for (j[5] = 0; j[5] < J[5]; ++j[5]) {
|
||||
for (i = 0; i < ARRAYLEN(J); ++i) {
|
||||
D[i] = S[j[i]] + K[i] - R[i];
|
||||
}
|
||||
if ((error = DifferSumSq(D, L, H) / HM) < least) {
|
||||
least = error;
|
||||
memcpy(O, j, sizeof(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 6; ++i) {
|
||||
N[i] += S[O[i]];
|
||||
}
|
||||
}
|
||||
return lround(least);
|
||||
}
|
83
dsp/core/getintegercoefficients8.c
Normal file
83
dsp/core/getintegercoefficients8.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/q.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Same as GetIntegerCoefficients() but with eight terms.
|
||||
* @cost ~3ms
|
||||
*/
|
||||
long GetIntegerCoefficients8(long N[static 8], const double C[static 8], long M,
|
||||
long L, long H) {
|
||||
int i;
|
||||
int j[8], J[8];
|
||||
int O[8] = {0};
|
||||
int S[3] = {0, -1, +1};
|
||||
double R[8], K[8], D[8], Z, least, error;
|
||||
least = 1;
|
||||
Z = 1L << M;
|
||||
for (i = 0; i < ARRAYLEN(J); ++i) {
|
||||
least *= H - L;
|
||||
if (fabs(C[i]) > DBL_MIN) {
|
||||
J[i] = ARRAYLEN(S);
|
||||
R[i] = C[i] * Z;
|
||||
K[i] = rint(R[i]);
|
||||
N[i] = K[i];
|
||||
} else {
|
||||
J[i] = 1;
|
||||
R[i] = 0;
|
||||
K[i] = 0;
|
||||
N[i] = 0;
|
||||
}
|
||||
}
|
||||
if (least > 1) {
|
||||
for (j[0] = 0; j[0] < J[0]; ++j[0]) {
|
||||
for (j[1] = 0; j[1] < J[1]; ++j[1]) {
|
||||
for (j[2] = 0; j[2] < J[2]; ++j[2]) {
|
||||
for (j[3] = 0; j[3] < J[3]; ++j[3]) {
|
||||
for (j[4] = 0; j[4] < J[4]; ++j[4]) {
|
||||
for (j[5] = 0; j[5] < J[5]; ++j[5]) {
|
||||
for (j[6] = 0; j[6] < J[6]; ++j[6]) {
|
||||
for (j[7] = 0; j[7] < J[7]; ++j[7]) {
|
||||
for (i = 0; i < ARRAYLEN(J); ++i) {
|
||||
D[i] = S[j[i]] + K[i] - R[i];
|
||||
}
|
||||
if ((error = DifferSumSq8(D, L, H) / Z) < least) {
|
||||
least = error;
|
||||
memcpy(O, j, sizeof(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 8; ++i) {
|
||||
N[i] += S[O[i]];
|
||||
}
|
||||
}
|
||||
return lround(least);
|
||||
}
|
12
dsp/core/half.h
Normal file
12
dsp/core/half.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_HALF_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_HALF_H_
|
||||
#include "libc/macros.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Divides integer in half w/ rounding.
|
||||
*/
|
||||
#define HALF(X) (((X) + 1) / (2 / TYPE_INTEGRAL(typeof(X))))
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_HALF_H_ */
|
79
dsp/core/illumination.c
Normal file
79
dsp/core/illumination.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/illumination.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
const double kIlluminantA[3] = {1.0985, 1, 0.35585};
|
||||
const double kIlluminantAD10[3] = {1.11144, 1, 0.35200};
|
||||
const double kIlluminantC[3] = {0.98074, 1, 1.18232};
|
||||
const double kIlluminantCD10[3] = {0.97285, 1, 1.16145};
|
||||
const double kIlluminantD50[3] = {0.96422, 1, 0.82521};
|
||||
const double kIlluminantD50D10[3] = {0.9672, 1, 0.81427};
|
||||
const double kIlluminantD55[3] = {0.95682, 1, 0.92149};
|
||||
const double kIlluminantD55D10[3] = {0.95799, 1, 0.90926};
|
||||
const double kIlluminantD65[3] = {0.95047, 1, 1.08883};
|
||||
const double kIlluminantD65D10[3] = {0.94811, 1, 1.07304};
|
||||
const double kIlluminantD75[3] = {0.94972, 1, 1.22638};
|
||||
const double kIlluminantD75D10[3] = {0.94416, 1, 1.20641};
|
||||
const double kIlluminantF2[3] = {0.99187, 1, 0.67395};
|
||||
const double kIlluminantF2D10[3] = {1.0328, 1, 0.69026};
|
||||
const double kIlluminantF7[3] = {0.95044, 1, 1.08755};
|
||||
const double kIlluminantF7D10[3] = {0.95792, 1, 1.07687};
|
||||
const double kIlluminantF11[3] = {1.00966, 1, 0.6437};
|
||||
const double kIlluminantF11D10[3] = {1.03866, 1, 0.65627};
|
||||
|
||||
/**
|
||||
* System of equations used for changing illumination.
|
||||
*
|
||||
* @see brucelindbloom.com/Eqn_ChromAdapt.html “The Bradford method is
|
||||
* the newest of the three methods, and is considered by most
|
||||
* experts to be the best of them. This is the method used in Adobe
|
||||
* Photoshop. A related article comparing the chromatic adaptation
|
||||
* algorithms may be found here.” ─Quoth Bruce Lindbloom
|
||||
*/
|
||||
const double kBradford[3][3] = {
|
||||
{0.8951, 0.2664, -.1614},
|
||||
{-.7502, 1.7135, 0.0367},
|
||||
{0.0389, -.0685, 1.0296},
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes lightbulb changing coefficients.
|
||||
*
|
||||
* @param R will store result
|
||||
* @param S has intended input illuminant primaries
|
||||
* @param D has desired output illuminant primaries
|
||||
* @return R
|
||||
* @see brucelindbloom.com/Eqn_ChromAdapt.html
|
||||
* @see fluxometer.com/rainbow/
|
||||
*/
|
||||
void *GetChromaticAdaptationMatrix(double R[3][3], const double S[3],
|
||||
const double D[3]) {
|
||||
double M[3][3], T[3][3], U[3][3], V[3], W[3];
|
||||
matvmul3(V, kBradford, S);
|
||||
matvmul3(W, kBradford, D);
|
||||
memset(M, 0, sizeof(M));
|
||||
M[0][0] = W[0] / V[0];
|
||||
M[1][1] = W[1] / V[1];
|
||||
M[2][2] = W[2] / V[2];
|
||||
return matmul3(R, matmul3(T, kBradford, M),
|
||||
inv3(U, kBradford, det3(kBradford)));
|
||||
}
|
31
dsp/core/illumination.h
Normal file
31
dsp/core/illumination.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_ILLUMINANT_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_ILLUMINANT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const double kBradford[3][3];
|
||||
extern const double kIlluminantA[3];
|
||||
extern const double kIlluminantAD10[3];
|
||||
extern const double kIlluminantC[3];
|
||||
extern const double kIlluminantCD10[3];
|
||||
extern const double kIlluminantD50[3];
|
||||
extern const double kIlluminantD50D10[3];
|
||||
extern const double kIlluminantD55[3];
|
||||
extern const double kIlluminantD55D10[3];
|
||||
extern const double kIlluminantD65[3];
|
||||
extern const double kIlluminantD65D10[3];
|
||||
extern const double kIlluminantD75[3];
|
||||
extern const double kIlluminantD75D10[3];
|
||||
extern const double kIlluminantF2[3];
|
||||
extern const double kIlluminantF2D10[3];
|
||||
extern const double kIlluminantF7[3];
|
||||
extern const double kIlluminantF7D10[3];
|
||||
extern const double kIlluminantF11[3];
|
||||
extern const double kIlluminantF11D10[3];
|
||||
|
||||
void *GetChromaticAdaptationMatrix(double[3][3], const double[3],
|
||||
const double[3]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_ILLUMINANT_H_ */
|
46
dsp/core/inv3.c
Normal file
46
dsp/core/inv3.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Computes 𝐀⁻¹ inverted 3×3 matrix, if it exists.
|
||||
*
|
||||
* @param 𝐁 is destination memory
|
||||
* @param 𝐀 is input matrix, which can't overlap 𝐁
|
||||
* @param 𝑑 is |𝐀| the determinant scalar or 0 if degenerate
|
||||
* @return 𝐀⁻¹ stored inside 𝐁 or NaNs if 𝑑=0
|
||||
* @define 𝐀⁻¹=𝐁 such that 𝐀×𝐁=𝐁×𝐀=𝐈ₙ
|
||||
* @see det3()
|
||||
*/
|
||||
void *inv3(double B[restrict 3][3], const double A[restrict 3][3], double d) {
|
||||
d = d ? 1 / d : NAN;
|
||||
B[0][0] = (A[1][1] * A[2][2] - A[2][1] * A[1][2]) * d;
|
||||
B[0][1] = (A[2][1] * A[0][2] - A[0][1] * A[2][2]) * d;
|
||||
B[0][2] = (A[0][1] * A[1][2] - A[1][1] * A[0][2]) * d;
|
||||
B[1][0] = (A[2][0] * A[1][2] - A[1][0] * A[2][2]) * d;
|
||||
B[1][1] = (A[0][0] * A[2][2] - A[2][0] * A[0][2]) * d;
|
||||
B[1][2] = (A[1][0] * A[0][2] - A[0][0] * A[1][2]) * d;
|
||||
B[2][0] = (A[1][0] * A[2][1] - A[2][0] * A[1][1]) * d;
|
||||
B[2][1] = (A[2][0] * A[0][1] - A[0][0] * A[2][1]) * d;
|
||||
B[2][2] = (A[0][0] * A[1][1] - A[1][0] * A[0][1]) * d;
|
||||
return B;
|
||||
}
|
23
dsp/core/ituround.h
Normal file
23
dsp/core/ituround.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_ITUROUND_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_ITUROUND_H_
|
||||
#include "libc/math.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* An ITU recommended rounding function.
|
||||
*
|
||||
* 1. Negative numbers round toward zero
|
||||
* 2. Positive numbers round toward infinity
|
||||
*
|
||||
* @see round(), rint()
|
||||
*/
|
||||
static inline pureconst artificial long ituround(double x) {
|
||||
return floor(x + .5);
|
||||
}
|
||||
|
||||
static inline pureconst artificial int ituroundf(float x) {
|
||||
return floorf(x + .5f);
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_ITUROUND_H_ */
|
47
dsp/core/ks8.h
Normal file
47
dsp/core/ks8.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_KS8_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_KS8_H_
|
||||
#include "libc/macros.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Performs 16-bit scaled rounded madd w/ eight coefficients or fewer.
|
||||
*
|
||||
* (Σᵢ₌₀₋₈𝑘ᵢ𝑥ᵢ + 2ᵐ⁻¹)/2ᵐ
|
||||
*
|
||||
* @note intent is avoiding type promotion
|
||||
*/
|
||||
#define KS8(M, K1, K2, K3, K4, K5, K6, K7, K8, X1, X2, X3, X4, X5, X6, X7, X8) \
|
||||
({ \
|
||||
short x1, x2, x3, x4, x5, x6, x7, x8; \
|
||||
x1 = X1; \
|
||||
x2 = X2; \
|
||||
x3 = X3; \
|
||||
x4 = X4; \
|
||||
x5 = X5; \
|
||||
x6 = X6; \
|
||||
x7 = X7; \
|
||||
x8 = X8; \
|
||||
x1 *= K1; \
|
||||
x2 *= K2; \
|
||||
x3 *= K3; \
|
||||
x4 *= K4; \
|
||||
x5 *= K5; \
|
||||
x6 *= K6; \
|
||||
x7 *= K7; \
|
||||
x8 *= K8; \
|
||||
x1 += x2; \
|
||||
x3 += x4; \
|
||||
x5 += x6; \
|
||||
x7 += x8; \
|
||||
x1 += x3; \
|
||||
x5 += x7; \
|
||||
x1 += x5; \
|
||||
if (M) { \
|
||||
x1 += 1 << MAX(0, M - 1); \
|
||||
x1 >>= M; \
|
||||
} \
|
||||
x1; \
|
||||
})
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_KS8_H_ */
|
43
dsp/core/kss8.h
Normal file
43
dsp/core/kss8.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_KSS8_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_KSS8_H_
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Performs 16-bit scaled rounded saturated madd w/ eight coefficients or fewer.
|
||||
*
|
||||
* (Σᵢ₌₀₋₈𝑘ᵢ𝑥ᵢ + 2ᵐ⁻¹)/2ᵐ
|
||||
*
|
||||
* @note compiler struggles with this
|
||||
*/
|
||||
#define KSS8(M, K1, K2, K3, K4, K5, K6, K7, K8, X1, X2, X3, X4, X5, X6, X7, \
|
||||
X8) \
|
||||
({ \
|
||||
short x1, x2, x3, x4, x5, x6, x7, x8; \
|
||||
x1 = X1, x2 = X2, x3 = X3, x4 = X4; \
|
||||
x5 = X5, x6 = X6, x7 = X7, x8 = X8; \
|
||||
x1 = MIN(SHRT_MAX, MAX(SHRT_MIN, x1 * K1)); \
|
||||
x2 = MIN(SHRT_MAX, MAX(SHRT_MIN, x2 * K2)); \
|
||||
x3 = MIN(SHRT_MAX, MAX(SHRT_MIN, x3 * K3)); \
|
||||
x4 = MIN(SHRT_MAX, MAX(SHRT_MIN, x4 * K4)); \
|
||||
x5 = MIN(SHRT_MAX, MAX(SHRT_MIN, x5 * K5)); \
|
||||
x6 = MIN(SHRT_MAX, MAX(SHRT_MIN, x6 * K6)); \
|
||||
x7 = MIN(SHRT_MAX, MAX(SHRT_MIN, x7 * K7)); \
|
||||
x8 = MIN(SHRT_MAX, MAX(SHRT_MIN, x8 * K8)); \
|
||||
x1 = MIN(SHRT_MAX, MAX(SHRT_MIN, x1 + x2)); \
|
||||
x3 = MIN(SHRT_MAX, MAX(SHRT_MIN, x3 + x4)); \
|
||||
x5 = MIN(SHRT_MAX, MAX(SHRT_MIN, x5 + x6)); \
|
||||
x7 = MIN(SHRT_MAX, MAX(SHRT_MIN, x7 + x8)); \
|
||||
x1 = MIN(SHRT_MAX, MAX(SHRT_MIN, x1 + x3)); \
|
||||
x5 = MIN(SHRT_MAX, MAX(SHRT_MIN, x5 + x7)); \
|
||||
x1 = MIN(SHRT_MAX, MAX(SHRT_MIN, x1 + x5)); \
|
||||
if (M) { \
|
||||
x1 += 1 << MAX(0, M - 1); \
|
||||
x1 >>= M; \
|
||||
} \
|
||||
x1; \
|
||||
})
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_KSS8_H_ */
|
38
dsp/core/matmul3.c
Normal file
38
dsp/core/matmul3.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Multiplies 3×3 matrices.
|
||||
*/
|
||||
void *matmul3(double R[restrict 3][3], const double A[3][3],
|
||||
const double B[3][3]) {
|
||||
int i, j, k;
|
||||
memset(R, 0, sizeof(double) * 3 * 3);
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (j = 0; j < 3; ++j) {
|
||||
for (k = 0; k < 3; ++k) {
|
||||
R[i][j] += A[k][j] * B[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
32
dsp/core/matvmul3.c
Normal file
32
dsp/core/matvmul3.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
|
||||
/**
|
||||
* Computes M×V.
|
||||
*
|
||||
* @see vmatmul3() for noncommutative corollary
|
||||
*/
|
||||
void *matvmul3(double R[restrict 3], const double M[3][3], const double V[3]) {
|
||||
R[0] = V[0] * M[0][0] + V[1] * M[0][1] + V[2] * M[0][2];
|
||||
R[1] = V[0] * M[1][0] + V[1] * M[1][1] + V[2] * M[1][2];
|
||||
R[2] = V[0] * M[2][0] + V[1] * M[2][1] + V[2] * M[2][2];
|
||||
return R;
|
||||
}
|
64
dsp/core/mulaw.S
Normal file
64
dsp/core/mulaw.S
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
#define BIAS 0x84
|
||||
|
||||
/ Encodes audio sample with µ-Law.
|
||||
/
|
||||
/ This is both the highest quality and most widely supported
|
||||
/ telephony codec, whose use was phased out in the 2000's in
|
||||
/ favor of cost-saving GSM audio compression that was so bad
|
||||
/ consumers were willing to pay more cash, for the privilege
|
||||
/ of saving telcos even more money w/ text messaging. Mu Law
|
||||
/ reduces PCM data to half its original size, by diminishing
|
||||
/ audio bands not vocalized by human voice.
|
||||
/
|
||||
/ @param %edi is pcm sample
|
||||
/ @return %eax is uint8_t encoded sample
|
||||
mulaw: .leafprologue
|
||||
.profilable
|
||||
mov $BIAS,%eax
|
||||
xor %edx,%edx
|
||||
test %edi,%edi
|
||||
js 1f
|
||||
lea (%edi,%eax),%eax
|
||||
mov $0xFF,%dl
|
||||
jmp 2f
|
||||
1: sub %edi,%eax
|
||||
mov $0x7F,%dl
|
||||
2: mov %eax,%esi
|
||||
or $0xFF,%sil
|
||||
bsr %esi,%esi
|
||||
sub $7,%esi
|
||||
cmp $8,%esi
|
||||
jge 4f
|
||||
lea 3(%rdx),%ecx
|
||||
sar %cl,%eax
|
||||
and $0xF,%eax
|
||||
shl $4,%esi
|
||||
or %esi,%eax
|
||||
xor %edx,%eax
|
||||
3: .leafepilogue
|
||||
4: xor $0x7F,%dl
|
||||
mov %edx,%eax
|
||||
jmp 3b
|
||||
.endfn mulaw,globl
|
||||
.yoink __FILE__
|
27
dsp/core/q.h
Normal file
27
dsp/core/q.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_Q_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_Q_H_
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* @fileoverview Fixed point arithmetic macros.
|
||||
* @see en.wikipedia.org/wiki/Q_(number_format)
|
||||
*/
|
||||
|
||||
#define F2Q(Q, I) MIN((1 << Q) - 1, roundf((I) * (1.f * ((1 << Q) - 1))))
|
||||
#define Q2F(Q, I) ((I) * (1.f / ((1 << Q) - 1)))
|
||||
#define QRS(Q, X) (((X) + (1 << (Q - 1))) >> Q)
|
||||
#define LQRS(Q, X) (((X) + (1L << (Q - 1))) >> Q)
|
||||
|
||||
double DifferSumSq(const double[static 6], double, double);
|
||||
double DifferSumSq8(const double[static 8], double, double);
|
||||
|
||||
long GetIntegerCoefficients(long[static 6], const double[static 6], long, long,
|
||||
long);
|
||||
long GetIntegerCoefficients8(long[static 8], const double[static 8], long, long,
|
||||
long);
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_Q_H_ */
|
41
dsp/core/sad16x8n.S
Normal file
41
dsp/core/sad16x8n.S
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.align 16
|
||||
|
||||
/ Mixes audio.
|
||||
/
|
||||
/ @param rdi is # aligned int16[16] sample chunks to process
|
||||
/ @param rsi points to aligned pcm s16le input/output memory
|
||||
/ @param rdx points to aligned pcm s16le [0..1] input memory
|
||||
sad16x8n:
|
||||
.leafprologue
|
||||
.profilable
|
||||
test %rdi,%rdi
|
||||
jz 1f
|
||||
shl $3,%rdi
|
||||
0: sub $8,%rdi
|
||||
movdqa (%rsi,%rdi,2),%xmm0
|
||||
paddsw (%rdx,%rdi,2),%xmm0
|
||||
movdqa %xmm0,(%rsi,%rdi,2)
|
||||
jnz 0b
|
||||
1: .leafepilogue
|
||||
.endfn sad16x8n,globl,hidden
|
||||
.yoink __FILE__
|
50
dsp/core/scalevolume.c
Normal file
50
dsp/core/scalevolume.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
* Increases or decreases audio volume.
|
||||
*
|
||||
* @param 𝑝 is two-power w/ effective range [-15,15]
|
||||
*/
|
||||
void scalevolume(size_t n, int16_t pcm[n][8], int p) {
|
||||
/* TODO(jart): This isn't acceptable. */
|
||||
size_t i, j;
|
||||
if (p > 0) {
|
||||
if (p > 15) p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] =
|
||||
MIN(SHRT_MAX, MAX(SHRT_MIN, (int)((unsigned)pcm[i][j] << p)));
|
||||
}
|
||||
}
|
||||
} else if (p < 0) {
|
||||
p = -p;
|
||||
if (p > 15) p = 15;
|
||||
for (i = 0; i < n; ++i) {
|
||||
for (j = 0; j < 8; ++j) {
|
||||
pcm[i][j] = SAR(pcm[i][j], p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
dsp/core/twixt8.h
Normal file
24
dsp/core/twixt8.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef COSMOPOLITAN_DSP_CORE_TWIXT8_H_
|
||||
#define COSMOPOLITAN_DSP_CORE_TWIXT8_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* 8-bit linear interpolation kernel.
|
||||
*/
|
||||
static inline pureconst artificial unsigned char twixt8(unsigned char al,
|
||||
unsigned char bl,
|
||||
unsigned char p) {
|
||||
short bx;
|
||||
bx = bl;
|
||||
bx -= al;
|
||||
bx *= p;
|
||||
bx >>= 8;
|
||||
bx += al;
|
||||
al = bx;
|
||||
return al;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_CORE_TWIXT8_H_ */
|
32
dsp/core/vmatmul3.c
Normal file
32
dsp/core/vmatmul3.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
|
||||
/**
|
||||
* Computes V×M.
|
||||
*
|
||||
* @see matvmul3() for noncommutative corollary
|
||||
*/
|
||||
void *vmatmul3(double R[restrict 3], const double V[3], const double M[3][3]) {
|
||||
R[0] = V[0] * M[0][0] + V[1] * M[1][0] + V[2] * M[2][0];
|
||||
R[1] = V[0] * M[0][1] + V[1] * M[1][1] + V[2] * M[2][1];
|
||||
R[2] = V[0] * M[0][2] + V[1] * M[1][2] + V[2] * M[2][2];
|
||||
return R;
|
||||
}
|
8
dsp/dsp.mk
Normal file
8
dsp/dsp.mk
Normal file
|
@ -0,0 +1,8 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
.PHONY: o/$(MODE)/dsp
|
||||
o/$(MODE)/dsp: o/$(MODE)/dsp/core \
|
||||
o/$(MODE)/dsp/mpeg \
|
||||
o/$(MODE)/dsp/scale \
|
||||
o/$(MODE)/dsp/tty
|
92
dsp/mpeg/README.txt
Normal file
92
dsp/mpeg/README.txt
Normal file
|
@ -0,0 +1,92 @@
|
|||
PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer
|
||||
Dominic Szablewski - https://phoboslab.org
|
||||
|
||||
-- Synopsis
|
||||
|
||||
// This function gets called for each decoded video frame
|
||||
void my_video_callback(plm_t *plm, plm_frame_t *frame, void *user) {
|
||||
// Do something with frame->y.data, frame->cr.data, frame->cb.data
|
||||
}
|
||||
|
||||
// This function gets called for each decoded audio frame
|
||||
void my_audio_callback(plm_t *plm, plm_samples_t *frame, void *user) {
|
||||
// Do something with samples->interleaved
|
||||
}
|
||||
|
||||
// Load a .mpg (MPEG Program Stream) file
|
||||
plm_t *plm = plm_create_with_filename("some-file.mpg");
|
||||
|
||||
// Install the video & audio decode callbacks
|
||||
plm_set_video_decode_callback(plm, my_video_callback, my_data);
|
||||
plm_set_audio_decode_callback(plm, my_audio_callback, my_data);
|
||||
|
||||
|
||||
// Decode
|
||||
do {
|
||||
plm_decode(plm, time_since_last_call);
|
||||
} while (!plm_has_ended(plm));
|
||||
|
||||
// All done
|
||||
plm_destroy(plm);
|
||||
|
||||
|
||||
|
||||
-- Documentation
|
||||
|
||||
This library provides several interfaces to load, demux and decode MPEG video
|
||||
and audio data. A high-level API combines the demuxer, video & audio decoders
|
||||
in an easy to use wrapper.
|
||||
|
||||
Lower-level APIs for accessing the demuxer, video decoder and audio decoder,
|
||||
as well as providing different data sources are also available.
|
||||
|
||||
Interfaces are written in an object orientet style, meaning you create object
|
||||
instances via various different constructor functions (plm_*create()),
|
||||
do some work on them and later dispose them via plm_*destroy().
|
||||
|
||||
plm_* -- the high-level interface, combining demuxer and decoders
|
||||
plm_buffer_* -- the data source used by all interfaces
|
||||
plm_demux_* -- the MPEG-PS demuxer
|
||||
plm_video_* -- the MPEG1 Video ("mpeg1") decoder
|
||||
plm_audio_* -- the MPEG1 Audio Layer II ("mp2") decoder
|
||||
|
||||
|
||||
This library uses malloc(), realloc() and free() to manage memory. Typically
|
||||
all allocation happens up-front when creating the interface. However, the
|
||||
default buffer size may be too small for certain inputs. In these cases plmpeg
|
||||
will realloc() the buffer with a larger size whenever needed. You can configure
|
||||
the default buffer size by defining PLM_BUFFER_DEFAULT_SIZE *before*
|
||||
including this library.
|
||||
|
||||
With the high-level interface you have two options to decode video & audio:
|
||||
|
||||
1) Use plm_decode() and just hand over the delta time since the last call.
|
||||
It will decode everything needed and call your callbacks (specified through
|
||||
plm_set_{video|audio}_decode_callback()) any number of times.
|
||||
|
||||
2) Use plm_decode_video() and plm_decode_audio() to decode exactly one
|
||||
frame of video or audio data at a time. How you handle the synchronization of
|
||||
both streams is up to you.
|
||||
|
||||
If you only want to decode video *or* audio through these functions, you should
|
||||
disable the other stream (plm_set_{video|audio}_enabled(false))
|
||||
|
||||
|
||||
Video data is decoded into a struct with all 3 planes (Y, Cr, Cb) stored in
|
||||
separate buffers. You can either convert this to RGB on the CPU (slow) via the
|
||||
plm_frame_to_rgb() function or do it on the GPU with the following matrix:
|
||||
|
||||
mat4 rec601 = mat4(
|
||||
1.16438, 0.00000, 1.59603, -0.87079,
|
||||
1.16438, -0.39176, -0.81297, 0.52959,
|
||||
1.16438, 2.01723, 0.00000, -1.08139,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
gl_FragColor = vec4(y, cb, cr, 1.0) * rec601;
|
||||
|
||||
Audio data is decoded into a struct with either one single float array with the
|
||||
samples for the left and right channel interleaved, or if the
|
||||
PLM_AUDIO_SEPARATE_CHANNELS is defined *before* including this library, into
|
||||
two separate float arrays - one for each channel.
|
||||
|
||||
See below for detailed the API documentation.
|
22
dsp/mpeg/blockset.h
Normal file
22
dsp/mpeg/blockset.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_BLOCKSET_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_BLOCKSET_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define PLM_BLOCK_SET(DEST, DEST_INDEX, DEST_WIDTH, SOURCE_INDEX, \
|
||||
SOURCE_WIDTH, BLOCK_SIZE, OP) \
|
||||
do { \
|
||||
int dest_scan = DEST_WIDTH - BLOCK_SIZE; \
|
||||
int source_scan = SOURCE_WIDTH - BLOCK_SIZE; \
|
||||
for (int y = 0; y < BLOCK_SIZE; y++) { \
|
||||
for (int x = 0; x < BLOCK_SIZE; x++) { \
|
||||
DEST[DEST_INDEX] = OP; \
|
||||
SOURCE_INDEX++; \
|
||||
DEST_INDEX++; \
|
||||
} \
|
||||
SOURCE_INDEX += source_scan; \
|
||||
DEST_INDEX += dest_scan; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_BLOCKSET_H_ */
|
158
dsp/mpeg/buffer.c
Normal file
158
dsp/mpeg/buffer.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/buffer.h"
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
PL_MPEG (MIT License)\\n\
|
||||
Copyright(c) 2019 Dominic Szablewski\\n\
|
||||
https://phoboslab.org\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/* clang-format off */
|
||||
// -----------------------------------------------------------------------------
|
||||
// plm_buffer implementation
|
||||
|
||||
plm_buffer_t *plm_buffer_create_with_filename(const char *filename) {
|
||||
FILE *fh = fopen(filename, "rb");
|
||||
if (!fh) {
|
||||
return NULL;
|
||||
}
|
||||
fadvise(fileno(fh), 0, 0, MADV_SEQUENTIAL);
|
||||
return plm_buffer_create_with_file(fh, true);
|
||||
}
|
||||
|
||||
plm_buffer_t *plm_buffer_create_with_file(FILE *fh, int close_when_done) {
|
||||
plm_buffer_t *b;
|
||||
b = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE);
|
||||
b->fh = fh;
|
||||
b->close_when_done = close_when_done;
|
||||
b->mode = PLM_BUFFER_MODE_FILE;
|
||||
plm_buffer_set_load_callback(b, plm_buffer_load_file_callback, NULL);
|
||||
return b;
|
||||
}
|
||||
|
||||
plm_buffer_t *plm_buffer_create_with_memory(unsigned char *bytes, size_t length, int free_when_done) {
|
||||
plm_buffer_t *b;
|
||||
b = memalign(alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
||||
memset(b, 0, sizeof(plm_buffer_t));
|
||||
b->capacity = length;
|
||||
b->length = length;
|
||||
b->free_when_done = free_when_done;
|
||||
b->bytes = bytes;
|
||||
b->mode = PLM_BUFFER_MODE_FIXED_MEM;
|
||||
return b;
|
||||
}
|
||||
|
||||
plm_buffer_t * plm_buffer_create_with_capacity(size_t capacity) {
|
||||
plm_buffer_t *b;
|
||||
b = memalign(alignof(plm_buffer_t), sizeof(plm_buffer_t));
|
||||
memset(b, 0, sizeof(plm_buffer_t));
|
||||
b->capacity = capacity;
|
||||
b->free_when_done = true;
|
||||
b->bytes = (unsigned char *)malloc(capacity);
|
||||
b->mode = PLM_BUFFER_MODE_DYNAMIC_MEM;
|
||||
return b;
|
||||
}
|
||||
|
||||
void plm_buffer_destroy(plm_buffer_t *self) {
|
||||
if (self->fh && self->close_when_done) {
|
||||
fclose(self->fh);
|
||||
}
|
||||
if (self->free_when_done) {
|
||||
free(self->bytes);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
size_t plm_buffer_write(plm_buffer_t *self, unsigned char *bytes, size_t length) {
|
||||
if (self->mode == PLM_BUFFER_MODE_FIXED_MEM) {
|
||||
return 0;
|
||||
}
|
||||
// This should be a ring buffer, but instead it just shifts all unread data
|
||||
// to the beginning of the buffer and appends new data at the end. Seems
|
||||
// to be good enough.
|
||||
plm_buffer_discard_read_bytes(self);
|
||||
// Do we have to resize to fit the new data?
|
||||
size_t bytes_available = self->capacity - self->length;
|
||||
if (bytes_available < length) {
|
||||
size_t new_size = self->capacity;
|
||||
do {
|
||||
new_size *= 2;
|
||||
} while (new_size - self->length < length);
|
||||
self->bytes = (unsigned char *)realloc(self->bytes, new_size);
|
||||
self->capacity = new_size;
|
||||
}
|
||||
memcpy(self->bytes + self->length, bytes, length);
|
||||
self->length += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
void plm_buffer_set_load_callback(plm_buffer_t *self, plm_buffer_load_callback fp, void *user) {
|
||||
self->load_callback = fp;
|
||||
self->load_callback_user_data = user;
|
||||
}
|
||||
|
||||
void plm_buffer_rewind(plm_buffer_t *self) {
|
||||
if (self->fh) {
|
||||
fseek(self->fh, 0, SEEK_SET);
|
||||
self->length = 0;
|
||||
}
|
||||
if (self->mode != PLM_BUFFER_MODE_FIXED_MEM) {
|
||||
self->length = 0;
|
||||
}
|
||||
self->bit_index = 0;
|
||||
}
|
||||
|
||||
void plm_buffer_discard_read_bytes(plm_buffer_t *self) {
|
||||
size_t byte_pos = self->bit_index >> 3;
|
||||
if (byte_pos == self->length) {
|
||||
self->bit_index = 0;
|
||||
self->length = 0;
|
||||
}
|
||||
else if (byte_pos > 0) {
|
||||
memmove(self->bytes, self->bytes + byte_pos, self->length - byte_pos);
|
||||
self->bit_index -= byte_pos << 3;
|
||||
self->length -= byte_pos;
|
||||
}
|
||||
}
|
||||
|
||||
void plm_buffer_load_file_callback(plm_buffer_t *self, void *user) {
|
||||
plm_buffer_discard_read_bytes(self);
|
||||
unsigned bytes_available = self->capacity - self->length;
|
||||
unsigned bytes_read = fread(self->bytes + self->length, 1, bytes_available, self->fh);
|
||||
self->length += bytes_read;
|
||||
}
|
163
dsp/mpeg/buffer.h
Normal file
163
dsp/mpeg/buffer.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_BUFFER_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_BUFFER_H_
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct FILE;
|
||||
|
||||
enum plm_buffer_mode {
|
||||
PLM_BUFFER_MODE_FILE,
|
||||
PLM_BUFFER_MODE_FIXED_MEM,
|
||||
PLM_BUFFER_MODE_DYNAMIC_MEM
|
||||
};
|
||||
|
||||
typedef struct plm_buffer_t {
|
||||
unsigned bit_index;
|
||||
unsigned capacity;
|
||||
unsigned length;
|
||||
int free_when_done;
|
||||
int close_when_done;
|
||||
struct FILE *fh;
|
||||
plm_buffer_load_callback load_callback;
|
||||
void *load_callback_user_data;
|
||||
unsigned char *bytes;
|
||||
enum plm_buffer_mode mode;
|
||||
} plm_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
int16_t index;
|
||||
int16_t value;
|
||||
} plm_vlc_t;
|
||||
|
||||
typedef struct {
|
||||
int16_t index;
|
||||
uint16_t value;
|
||||
} plm_vlc_uint_t;
|
||||
|
||||
/* bool plm_buffer_has(plm_buffer_t *, size_t); */
|
||||
/* int plm_buffer_read(plm_buffer_t *, int); */
|
||||
/* void plm_buffer_align(plm_buffer_t *); */
|
||||
/* void plm_buffer_skip(plm_buffer_t *, size_t); */
|
||||
/* int plm_buffer_skip_bytes(plm_buffer_t *, unsigned char); */
|
||||
/* int plm_buffer_next_start_code(plm_buffer_t *); */
|
||||
/* int plm_buffer_find_start_code(plm_buffer_t *, int); */
|
||||
/* int plm_buffer_no_start_code(plm_buffer_t *); */
|
||||
/* int16_t plm_buffer_read_vlc(plm_buffer_t *, const plm_vlc_t *); */
|
||||
/* uint16_t plm_buffer_read_vlc_uint(plm_buffer_t *, const plm_vlc_uint_t *); */
|
||||
|
||||
void plm_buffer_discard_read_bytes(plm_buffer_t *);
|
||||
relegated void plm_buffer_load_file_callback(plm_buffer_t *, void *);
|
||||
|
||||
forceinline bool plm_buffer_has(plm_buffer_t *b, size_t bits) {
|
||||
unsigned have;
|
||||
have = b->length;
|
||||
have <<= 3;
|
||||
have -= b->bit_index;
|
||||
if (bits <= have) {
|
||||
return true;
|
||||
} else {
|
||||
if (b->load_callback) {
|
||||
b->load_callback(b, b->load_callback_user_data);
|
||||
return ((b->length << 3) - b->bit_index) >= bits;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forceinline int plm_buffer_read(plm_buffer_t *self, int count) {
|
||||
if (!plm_buffer_has(self, count)) return 0;
|
||||
int value = 0;
|
||||
while (count) {
|
||||
int current_byte = self->bytes[self->bit_index >> 3];
|
||||
int remaining = 8 - (self->bit_index & 7); // Remaining bits in byte
|
||||
int read = remaining < count ? remaining : count; // Bits in self run
|
||||
int shift = remaining - read;
|
||||
int mask = (0xff >> (8 - read));
|
||||
value = (value << read) | ((current_byte & (mask << shift)) >> shift);
|
||||
self->bit_index += read;
|
||||
count -= read;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
forceinline void plm_buffer_align(plm_buffer_t *self) {
|
||||
self->bit_index = ((self->bit_index + 7) >> 3) << 3;
|
||||
}
|
||||
|
||||
forceinline void plm_buffer_skip(plm_buffer_t *self, size_t count) {
|
||||
if (plm_buffer_has(self, count)) {
|
||||
self->bit_index += count;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline int plm_buffer_skip_bytes(plm_buffer_t *self, unsigned char v) {
|
||||
unsigned skipped;
|
||||
plm_buffer_align(self);
|
||||
skipped = 0;
|
||||
while (plm_buffer_has(self, 8)) {
|
||||
if (v == self->bytes[self->bit_index >> 3]) {
|
||||
self->bit_index += 8;
|
||||
++skipped;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
forceinline int plm_buffer_next_start_code(plm_buffer_t *self) {
|
||||
plm_buffer_align(self);
|
||||
while (plm_buffer_has(self, (5 << 3))) {
|
||||
size_t byte_index = (self->bit_index) >> 3;
|
||||
if (self->bytes[byte_index] == 0x00 &&
|
||||
self->bytes[byte_index + 1] == 0x00 &&
|
||||
self->bytes[byte_index + 2] == 0x01) {
|
||||
self->bit_index = (byte_index + 4) << 3;
|
||||
return self->bytes[byte_index + 3];
|
||||
}
|
||||
self->bit_index += 8;
|
||||
}
|
||||
self->bit_index = (self->length << 3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
forceinline int plm_buffer_find_start_code(plm_buffer_t *self, int code) {
|
||||
int current = 0;
|
||||
while (true) {
|
||||
current = plm_buffer_next_start_code(self);
|
||||
if (current == code || current == -1) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
forceinline int plm_buffer_no_start_code(plm_buffer_t *self) {
|
||||
if (!plm_buffer_has(self, (5 << 3))) {
|
||||
return false;
|
||||
}
|
||||
size_t byte_index = ((self->bit_index + 7) >> 3);
|
||||
return !(self->bytes[byte_index] == 0x00 &&
|
||||
self->bytes[byte_index + 1] == 0x00 &&
|
||||
self->bytes[byte_index + 2] == 0x01);
|
||||
}
|
||||
|
||||
forceinline int16_t plm_buffer_read_vlc(plm_buffer_t *self,
|
||||
const plm_vlc_t *table) {
|
||||
plm_vlc_t state = {0, 0};
|
||||
do {
|
||||
state = table[state.index + plm_buffer_read(self, 1)];
|
||||
} while (state.index > 0);
|
||||
return state.value;
|
||||
}
|
||||
|
||||
forceinline uint16_t plm_buffer_read_vlc_uint(plm_buffer_t *self,
|
||||
const plm_vlc_uint_t *table) {
|
||||
return (uint16_t)plm_buffer_read_vlc(self, (plm_vlc_t *)table);
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_BUFFER_H_ */
|
32
dsp/mpeg/clamp4int256-core.S
Normal file
32
dsp/mpeg/clamp4int256-core.S
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.yoink __FILE__
|
||||
|
||||
clamp4int256$core:
|
||||
.leafprologue
|
||||
pxor %xmm1,%xmm1
|
||||
pmaxsd %xmm1,%xmm0
|
||||
pminsd 0f(%rip),%xmm0
|
||||
.leafepilogue
|
||||
.endfn clamp4int256$core,globl
|
||||
|
||||
.rodata.cst16
|
||||
0: .long 255,255,255,255
|
208
dsp/mpeg/demux.c
Normal file
208
dsp/mpeg/demux.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/buffer.h"
|
||||
#include "dsp/mpeg/demux.h"
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
PL_MPEG (MIT License)\\n\
|
||||
Copyright(c) 2019 Dominic Szablewski\\n\
|
||||
https://phoboslab.org\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/* clang-format off */
|
||||
// ----------------------------------------------------------------------------
|
||||
// plm_demux implementation
|
||||
|
||||
plm_demux_t *plm_demux_create(plm_buffer_t *buffer, int destroy_when_done) {
|
||||
plm_demux_t *self = (plm_demux_t *)malloc(sizeof(plm_demux_t));
|
||||
memset(self, 0, sizeof(plm_demux_t));
|
||||
|
||||
self->buffer = buffer;
|
||||
self->destroy_buffer_when_done = destroy_when_done;
|
||||
|
||||
if (plm_buffer_find_start_code(self->buffer, START_PACK) != -1) {
|
||||
plm_demux_decode_pack_header(self);
|
||||
}
|
||||
if (plm_buffer_find_start_code(self->buffer, START_SYSTEM) != -1) {
|
||||
plm_demux_decode_system_header(self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void plm_demux_destroy(plm_demux_t *self) {
|
||||
if (self->destroy_buffer_when_done) {
|
||||
plm_buffer_destroy(self->buffer);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
int plm_demux_get_num_video_streams(plm_demux_t *self) {
|
||||
return self->num_video_streams;
|
||||
}
|
||||
|
||||
int plm_demux_get_num_audio_streams(plm_demux_t *self) {
|
||||
return self->num_audio_streams;
|
||||
}
|
||||
|
||||
void plm_demux_rewind(plm_demux_t *self) {
|
||||
plm_buffer_rewind(self->buffer);
|
||||
}
|
||||
|
||||
plm_packet_t *plm_demux_decode(plm_demux_t *self) {
|
||||
if (self->current_packet.length) {
|
||||
size_t bits_till_next_packet = self->current_packet.length << 3;
|
||||
if (!plm_buffer_has(self->buffer, bits_till_next_packet)) {
|
||||
return NULL;
|
||||
}
|
||||
plm_buffer_skip(self->buffer, bits_till_next_packet);
|
||||
self->current_packet.length = 0;
|
||||
}
|
||||
|
||||
if (!self->has_pack_header) {
|
||||
if (plm_buffer_find_start_code(self->buffer, START_PACK) != -1) {
|
||||
plm_demux_decode_pack_header(self);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!self->has_system_header) {
|
||||
if (plm_buffer_find_start_code(self->buffer, START_SYSTEM) != -1) {
|
||||
plm_demux_decode_system_header(self);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// pending packet just waiting for data?
|
||||
if (self->next_packet.length) {
|
||||
return plm_demux_get_packet(self);
|
||||
}
|
||||
|
||||
int code;
|
||||
do {
|
||||
code = plm_buffer_next_start_code(self->buffer);
|
||||
if (
|
||||
code == PLM_DEMUX_PACKET_VIDEO_1 ||
|
||||
code == PLM_DEMUX_PACKET_PRIVATE ||
|
||||
(code >= PLM_DEMUX_PACKET_AUDIO_1 && code <= PLM_DEMUX_PACKET_AUDIO_4)
|
||||
) {
|
||||
return plm_demux_decode_packet(self, code);
|
||||
}
|
||||
} while (code != -1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double plm_demux_read_time(plm_demux_t *self) {
|
||||
int64_t clock = plm_buffer_read(self->buffer, 3) << 30;
|
||||
plm_buffer_skip(self->buffer, 1);
|
||||
clock |= plm_buffer_read(self->buffer, 15) << 15;
|
||||
plm_buffer_skip(self->buffer, 1);
|
||||
clock |= plm_buffer_read(self->buffer, 15);
|
||||
plm_buffer_skip(self->buffer, 1);
|
||||
return (double)clock / 90000.0;
|
||||
}
|
||||
|
||||
void plm_demux_decode_pack_header(plm_demux_t *self) {
|
||||
if (plm_buffer_read(self->buffer, 4) != 0x02) {
|
||||
return; // invalid
|
||||
}
|
||||
self->system_clock_ref = plm_demux_read_time(self);
|
||||
plm_buffer_skip(self->buffer, 1);
|
||||
plm_buffer_skip(self->buffer, 22); // mux_rate * 50
|
||||
plm_buffer_skip(self->buffer, 1);
|
||||
|
||||
self->has_pack_header = true;
|
||||
}
|
||||
|
||||
void plm_demux_decode_system_header(plm_demux_t *self) {
|
||||
plm_buffer_skip(self->buffer, 16); // header_length
|
||||
plm_buffer_skip(self->buffer, 24); // rate bound
|
||||
self->num_audio_streams = plm_buffer_read(self->buffer, 6);
|
||||
plm_buffer_skip(self->buffer, 5); // misc flags
|
||||
self->num_video_streams = plm_buffer_read(self->buffer, 5);
|
||||
|
||||
self->has_system_header = true;
|
||||
}
|
||||
|
||||
plm_packet_t *plm_demux_decode_packet(plm_demux_t *self, int start_code) {
|
||||
if (!plm_buffer_has(self->buffer, 8 << 3)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->next_packet.type = start_code;
|
||||
self->next_packet.length = plm_buffer_read(self->buffer, 16);
|
||||
self->next_packet.length -= plm_buffer_skip_bytes(self->buffer, 0xff); // stuffing
|
||||
|
||||
// skip P-STD
|
||||
if (plm_buffer_read(self->buffer, 2) == 0x01) {
|
||||
plm_buffer_skip(self->buffer, 16);
|
||||
self->next_packet.length -= 2;
|
||||
}
|
||||
|
||||
int pts_dts_marker = plm_buffer_read(self->buffer, 2);
|
||||
if (pts_dts_marker == 0x03) {
|
||||
self->next_packet.pts = plm_demux_read_time(self);
|
||||
plm_buffer_skip(self->buffer, 40); // skip dts
|
||||
self->next_packet.length -= 10;
|
||||
}
|
||||
else if (pts_dts_marker == 0x02) {
|
||||
self->next_packet.pts = plm_demux_read_time(self);
|
||||
self->next_packet.length -= 5;
|
||||
}
|
||||
else if (pts_dts_marker == 0x00) {
|
||||
self->next_packet.pts = 0;
|
||||
plm_buffer_skip(self->buffer, 4);
|
||||
self->next_packet.length -= 1;
|
||||
}
|
||||
else {
|
||||
return NULL; // invalid
|
||||
}
|
||||
|
||||
return plm_demux_get_packet(self);
|
||||
}
|
||||
|
||||
plm_packet_t *plm_demux_get_packet(plm_demux_t *self) {
|
||||
if (!plm_buffer_has(self->buffer, self->next_packet.length << 3)) {
|
||||
return NULL;
|
||||
}
|
||||
self->current_packet.data = self->buffer->bytes + (self->buffer->bit_index >> 3);
|
||||
self->current_packet.length = self->next_packet.length;
|
||||
self->current_packet.type = self->next_packet.type;
|
||||
self->current_packet.pts = self->next_packet.pts;
|
||||
self->next_packet.length = 0;
|
||||
return &self->current_packet;
|
||||
}
|
31
dsp/mpeg/demux.h
Normal file
31
dsp/mpeg/demux.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_DEMUX_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_DEMUX_H_
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define START_PACK 0xBA
|
||||
#define START_END 0xB9
|
||||
#define START_SYSTEM 0xBB
|
||||
|
||||
typedef struct plm_demux_t {
|
||||
plm_buffer_t *buffer;
|
||||
int destroy_buffer_when_done;
|
||||
double system_clock_ref;
|
||||
int has_pack_header;
|
||||
int has_system_header;
|
||||
int num_audio_streams;
|
||||
int num_video_streams;
|
||||
plm_packet_t current_packet;
|
||||
plm_packet_t next_packet;
|
||||
} plm_demux_t;
|
||||
|
||||
double plm_demux_read_time(plm_demux_t *self);
|
||||
void plm_demux_decode_pack_header(plm_demux_t *self);
|
||||
void plm_demux_decode_system_header(plm_demux_t *self);
|
||||
plm_packet_t *plm_demux_decode_packet(plm_demux_t *self, int start_code);
|
||||
plm_packet_t *plm_demux_get_packet(plm_demux_t *self);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_DEMUX_H_ */
|
106
dsp/mpeg/idct.c
Normal file
106
dsp/mpeg/idct.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/half.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
PL_MPEG (MIT License)\\n\
|
||||
Copyright(c) 2019 Dominic Szablewski\\n\
|
||||
https://phoboslab.org\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/**
|
||||
* Computes Fixed-Point 8x8 Inverse Discrete Cosine Transform.
|
||||
*
|
||||
* @note discovered by Nasir Ahmed
|
||||
*/
|
||||
void plm_video_idct(int block[8][8]) {
|
||||
int i, j, t1, t2, m0;
|
||||
int b1, b3, b4, b6, b7;
|
||||
int y3, y4, y5, y6, y7;
|
||||
int x0, x1, x2, x3, x4;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
b1 = block[4][i];
|
||||
b3 = block[2][i] + block[6][i];
|
||||
b4 = block[5][i] - block[3][i];
|
||||
t1 = block[1][i] + block[7][i];
|
||||
t2 = block[3][i] + block[5][i];
|
||||
b6 = block[1][i] - block[7][i];
|
||||
b7 = t1 + t2;
|
||||
m0 = block[0][i];
|
||||
x4 = ((b6 * 473 - b4 * 196 + 128) >> 8) - b7;
|
||||
x0 = x4 - (((t1 - t2) * 362 + 128) >> 8);
|
||||
x1 = m0 - b1;
|
||||
x2 = (((block[2][i] - block[6][i]) * 362 + 128) >> 8) - b3;
|
||||
x3 = m0 + b1;
|
||||
y3 = x1 + x2;
|
||||
y4 = x3 + b3;
|
||||
y5 = x1 - x2;
|
||||
y6 = x3 - b3;
|
||||
y7 = -x0 - ((b4 * 473 + b6 * 196 + 128) >> 8);
|
||||
block[0][i] = b7 + y4;
|
||||
block[1][i] = x4 + y3;
|
||||
block[2][i] = y5 - x0;
|
||||
block[3][i] = y6 - y7;
|
||||
block[4][i] = y6 + y7;
|
||||
block[5][i] = x0 + y5;
|
||||
block[6][i] = y3 - x4;
|
||||
block[7][i] = y4 - b7;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
b1 = block[i][4];
|
||||
b3 = block[i][2] + block[i][6];
|
||||
b4 = block[i][5] - block[i][3];
|
||||
t1 = block[i][1] + block[i][7];
|
||||
t2 = block[i][3] + block[i][5];
|
||||
b6 = block[i][1] - block[i][7];
|
||||
b7 = t1 + t2;
|
||||
m0 = block[i][0];
|
||||
x4 = ((b6 * 473 - b4 * 196 + 128) >> 8) - b7;
|
||||
x0 = x4 - (((t1 - t2) * 362 + 128) >> 8);
|
||||
x1 = m0 - b1;
|
||||
x2 = (((block[i][2] - block[i][6]) * 362 + 128) >> 8) - b3;
|
||||
x3 = m0 + b1;
|
||||
y3 = x1 + x2;
|
||||
y4 = x3 + b3;
|
||||
y5 = x1 - x2;
|
||||
y6 = x3 - b3;
|
||||
y7 = -x0 - ((b4 * 473 + b6 * 196 + 128) >> 8);
|
||||
block[i][0] = (b7 + y4 + 128) >> 8;
|
||||
block[i][1] = (x4 + y3 + 128) >> 8;
|
||||
block[i][2] = (y5 - x0 + 128) >> 8;
|
||||
block[i][3] = (y6 - y7 + 128) >> 8;
|
||||
block[i][4] = (y6 + y7 + 128) >> 8;
|
||||
block[i][5] = (x0 + y5 + 128) >> 8;
|
||||
block[i][6] = (y3 - x4 + 128) >> 8;
|
||||
block[i][7] = (y4 - b7 + 128) >> 8;
|
||||
}
|
||||
}
|
10
dsp/mpeg/idct.h
Normal file
10
dsp/mpeg/idct.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_IDCT_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_IDCT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
void plm_video_idct(int *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_IDCT_H_ */
|
171
dsp/mpeg/macroblock.c
Normal file
171
dsp/mpeg/macroblock.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "dsp/mpeg/video.h"
|
||||
#include "libc/log/check.h"
|
||||
|
||||
forceinline void plm_video_process_macroblock(plm_video_t *self,
|
||||
uint8_t *restrict d,
|
||||
uint8_t *restrict s, int motion_h,
|
||||
int motion_v, bool interpolate,
|
||||
unsigned BW) {
|
||||
unsigned si, di, max_address;
|
||||
int y, x, dest_scan, source_scan, dw, hp, vp, odd_h, odd_v;
|
||||
dw = self->mb_width * BW;
|
||||
hp = motion_h >> 1;
|
||||
vp = motion_v >> 1;
|
||||
odd_h = (motion_h & 1) == 1;
|
||||
odd_v = (motion_v & 1) == 1;
|
||||
si = ((self->mb_row * BW) + vp) * dw + (self->mb_col * BW) + hp;
|
||||
di = (self->mb_row * dw + self->mb_col) * BW;
|
||||
max_address = (dw * (self->mb_height * BW - BW + 1) - BW);
|
||||
if (si > max_address || di > max_address) return;
|
||||
d += di;
|
||||
s += si;
|
||||
switch (((interpolate << 2) | (odd_h << 1) | (odd_v)) & 7) {
|
||||
case 0:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
*d++ = (s[0] + s[dw] + 1) >> 1;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
*d++ = (s[0] + s[1] + 1) >> 1;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
*d++ = (s[0] + s[1] + s[dw] + s[dw + 1] + 2) >> 2;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
d[0] = (d[0] + (s[0]) + 1) >> 1;
|
||||
d++;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
d[0] = (d[0] + ((s[0] + s[dw] + 1) >> 1) + 1) >> 1;
|
||||
d++;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
d[0] = (d[0] + ((s[0] + s[1] + 1) >> 1) + 1) >> 1;
|
||||
d++;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
dest_scan = dw - BW;
|
||||
source_scan = dw - BW;
|
||||
for (y = 0; y < BW; y++) {
|
||||
for (x = 0; x < BW; x++) {
|
||||
d[0] = (d[0] + ((s[0] + s[1] + s[dw] + s[dw + 1] + 2) >> 2) + 1) >> 1;
|
||||
d++;
|
||||
s++;
|
||||
}
|
||||
s += source_scan;
|
||||
d += dest_scan;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void plm_video_process_macroblock_8(plm_video_t *self, uint8_t *restrict d,
|
||||
uint8_t *restrict s, int motion_h,
|
||||
int motion_v, bool interpolate) {
|
||||
DCHECK_ALIGNED(8, d);
|
||||
DCHECK_ALIGNED(8, s);
|
||||
plm_video_process_macroblock(self, d, s, motion_h, motion_v, interpolate, 8);
|
||||
}
|
||||
|
||||
void plm_video_process_macroblock_16(plm_video_t *self, uint8_t *restrict d,
|
||||
uint8_t *restrict s, int motion_h,
|
||||
int motion_v, bool interpolate) {
|
||||
DCHECK_ALIGNED(16, d);
|
||||
DCHECK_ALIGNED(16, s);
|
||||
plm_video_process_macroblock(self, d, s, motion_h, motion_v, interpolate, 16);
|
||||
}
|
775
dsp/mpeg/mp2.c
Normal file
775
dsp/mpeg/mp2.c
Normal file
|
@ -0,0 +1,775 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/buffer.h"
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
PL_MPEG (MIT License)\\n\
|
||||
Copyright(c) 2019 Dominic Szablewski\\n\
|
||||
https://phoboslab.org\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/* clang-format off */
|
||||
// -----------------------------------------------------------------------------
|
||||
// plm_audio implementation
|
||||
|
||||
// Based on kjmp2 by Martin J. Fiedler
|
||||
// http://keyj.emphy.de/kjmp2/
|
||||
|
||||
#define PLM_AUDIO_FRAME_SYNC 0x7ff
|
||||
|
||||
#define PLM_AUDIO_MPEG_2_5 0x0
|
||||
#define PLM_AUDIO_MPEG_2 0x2
|
||||
#define PLM_AUDIO_MPEG_1 0x3
|
||||
|
||||
#define PLM_AUDIO_LAYER_III 0x1
|
||||
#define PLM_AUDIO_LAYER_II 0x2
|
||||
#define PLM_AUDIO_LAYER_I 0x3
|
||||
|
||||
#define PLM_AUDIO_MODE_STEREO 0x0
|
||||
#define PLM_AUDIO_MODE_JOINT_STEREO 0x1
|
||||
#define PLM_AUDIO_MODE_DUAL_CHANNEL 0x2
|
||||
#define PLM_AUDIO_MODE_MONO 0x3
|
||||
|
||||
static const unsigned short PLM_AUDIO_SAMPLE_RATE[] = {
|
||||
44100, 48000, 32000, 0, // MPEG-1
|
||||
22050, 24000, 16000, 0 // MPEG-2
|
||||
};
|
||||
|
||||
static const short PLM_AUDIO_BIT_RATE[] = {
|
||||
32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, // MPEG-1
|
||||
8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 // MPEG-2
|
||||
};
|
||||
|
||||
static const int PLM_AUDIO_SCALEFACTOR_BASE[] = {
|
||||
0x02000000, 0x01965FEA, 0x01428A30
|
||||
};
|
||||
|
||||
static const float PLM_AUDIO_SYNTHESIS_WINDOW[] = {
|
||||
0.0, -0.5, -0.5, -0.5, -0.5, -0.5,
|
||||
-0.5, -1.0, -1.0, -1.0, -1.0, -1.5,
|
||||
-1.5, -2.0, -2.0, -2.5, -2.5, -3.0,
|
||||
-3.5, -3.5, -4.0, -4.5, -5.0, -5.5,
|
||||
-6.5, -7.0, -8.0, -8.5, -9.5, -10.5,
|
||||
-12.0, -13.0, -14.5, -15.5, -17.5, -19.0,
|
||||
-20.5, -22.5, -24.5, -26.5, -29.0, -31.5,
|
||||
-34.0, -36.5, -39.5, -42.5, -45.5, -48.5,
|
||||
-52.0, -55.5, -58.5, -62.5, -66.0, -69.5,
|
||||
-73.5, -77.0, -80.5, -84.5, -88.0, -91.5,
|
||||
-95.0, -98.0, -101.0, -104.0, 106.5, 109.0,
|
||||
111.0, 112.5, 113.5, 114.0, 114.0, 113.5,
|
||||
112.0, 110.5, 107.5, 104.0, 100.0, 94.5,
|
||||
88.5, 81.5, 73.0, 63.5, 53.0, 41.5,
|
||||
28.5, 14.5, -1.0, -18.0, -36.0, -55.5,
|
||||
-76.5, -98.5, -122.0, -147.0, -173.5, -200.5,
|
||||
-229.5, -259.5, -290.5, -322.5, -355.5, -389.5,
|
||||
-424.0, -459.5, -495.5, -532.0, -568.5, -605.0,
|
||||
-641.5, -678.0, -714.0, -749.0, -783.5, -817.0,
|
||||
-849.0, -879.5, -908.5, -935.0, -959.5, -981.0,
|
||||
-1000.5, -1016.0, -1028.5, -1037.5, -1042.5, -1043.5,
|
||||
-1040.0, -1031.5, 1018.5, 1000.0, 976.0, 946.5,
|
||||
911.0, 869.5, 822.0, 767.5, 707.0, 640.0,
|
||||
565.5, 485.0, 397.0, 302.5, 201.0, 92.5,
|
||||
-22.5, -144.0, -272.5, -407.0, -547.5, -694.0,
|
||||
-846.0, -1003.0, -1165.0, -1331.5, -1502.0, -1675.5,
|
||||
-1852.5, -2031.5, -2212.5, -2394.0, -2576.5, -2758.5,
|
||||
-2939.5, -3118.5, -3294.5, -3467.5, -3635.5, -3798.5,
|
||||
-3955.0, -4104.5, -4245.5, -4377.5, -4499.0, -4609.5,
|
||||
-4708.0, -4792.5, -4863.5, -4919.0, -4958.0, -4979.5,
|
||||
-4983.0, -4967.5, -4931.5, -4875.0, -4796.0, -4694.5,
|
||||
-4569.5, -4420.0, -4246.0, -4046.0, -3820.0, -3567.0,
|
||||
3287.0, 2979.5, 2644.0, 2280.5, 1888.0, 1467.5,
|
||||
1018.5, 541.0, 35.0, -499.0, -1061.0, -1650.0,
|
||||
-2266.5, -2909.0, -3577.0, -4270.0, -4987.5, -5727.5,
|
||||
-6490.0, -7274.0, -8077.5, -8899.5, -9739.0, -10594.5,
|
||||
-11464.5, -12347.0, -13241.0, -14144.5, -15056.0, -15973.5,
|
||||
-16895.5, -17820.0, -18744.5, -19668.0, -20588.0, -21503.0,
|
||||
-22410.5, -23308.5, -24195.0, -25068.5, -25926.5, -26767.0,
|
||||
-27589.0, -28389.0, -29166.5, -29919.0, -30644.5, -31342.0,
|
||||
-32009.5, -32645.0, -33247.0, -33814.5, -34346.0, -34839.5,
|
||||
-35295.0, -35710.0, -36084.5, -36417.5, -36707.5, -36954.0,
|
||||
-37156.5, -37315.0, -37428.0, -37496.0, 37519.0, 37496.0,
|
||||
37428.0, 37315.0, 37156.5, 36954.0, 36707.5, 36417.5,
|
||||
36084.5, 35710.0, 35295.0, 34839.5, 34346.0, 33814.5,
|
||||
33247.0, 32645.0, 32009.5, 31342.0, 30644.5, 29919.0,
|
||||
29166.5, 28389.0, 27589.0, 26767.0, 25926.5, 25068.5,
|
||||
24195.0, 23308.5, 22410.5, 21503.0, 20588.0, 19668.0,
|
||||
18744.5, 17820.0, 16895.5, 15973.5, 15056.0, 14144.5,
|
||||
13241.0, 12347.0, 11464.5, 10594.5, 9739.0, 8899.5,
|
||||
8077.5, 7274.0, 6490.0, 5727.5, 4987.5, 4270.0,
|
||||
3577.0, 2909.0, 2266.5, 1650.0, 1061.0, 499.0,
|
||||
-35.0, -541.0, -1018.5, -1467.5, -1888.0, -2280.5,
|
||||
-2644.0, -2979.5, 3287.0, 3567.0, 3820.0, 4046.0,
|
||||
4246.0, 4420.0, 4569.5, 4694.5, 4796.0, 4875.0,
|
||||
4931.5, 4967.5, 4983.0, 4979.5, 4958.0, 4919.0,
|
||||
4863.5, 4792.5, 4708.0, 4609.5, 4499.0, 4377.5,
|
||||
4245.5, 4104.5, 3955.0, 3798.5, 3635.5, 3467.5,
|
||||
3294.5, 3118.5, 2939.5, 2758.5, 2576.5, 2394.0,
|
||||
2212.5, 2031.5, 1852.5, 1675.5, 1502.0, 1331.5,
|
||||
1165.0, 1003.0, 846.0, 694.0, 547.5, 407.0,
|
||||
272.5, 144.0, 22.5, -92.5, -201.0, -302.5,
|
||||
-397.0, -485.0, -565.5, -640.0, -707.0, -767.5,
|
||||
-822.0, -869.5, -911.0, -946.5, -976.0, -1000.0,
|
||||
1018.5, 1031.5, 1040.0, 1043.5, 1042.5, 1037.5,
|
||||
1028.5, 1016.0, 1000.5, 981.0, 959.5, 935.0,
|
||||
908.5, 879.5, 849.0, 817.0, 783.5, 749.0,
|
||||
714.0, 678.0, 641.5, 605.0, 568.5, 532.0,
|
||||
495.5, 459.5, 424.0, 389.5, 355.5, 322.5,
|
||||
290.5, 259.5, 229.5, 200.5, 173.5, 147.0,
|
||||
122.0, 98.5, 76.5, 55.5, 36.0, 18.0,
|
||||
1.0, -14.5, -28.5, -41.5, -53.0, -63.5,
|
||||
-73.0, -81.5, -88.5, -94.5, -100.0, -104.0,
|
||||
-107.5, -110.5, -112.0, -113.5, -114.0, -114.0,
|
||||
-113.5, -112.5, -111.0, -109.0, 106.5, 104.0,
|
||||
101.0, 98.0, 95.0, 91.5, 88.0, 84.5,
|
||||
80.5, 77.0, 73.5, 69.5, 66.0, 62.5,
|
||||
58.5, 55.5, 52.0, 48.5, 45.5, 42.5,
|
||||
39.5, 36.5, 34.0, 31.5, 29.0, 26.5,
|
||||
24.5, 22.5, 20.5, 19.0, 17.5, 15.5,
|
||||
14.5, 13.0, 12.0, 10.5, 9.5, 8.5,
|
||||
8.0, 7.0, 6.5, 5.5, 5.0, 4.5,
|
||||
4.0, 3.5, 3.5, 3.0, 2.5, 2.5,
|
||||
2.0, 2.0, 1.5, 1.5, 1.0, 1.0,
|
||||
1.0, 1.0, 0.5, 0.5, 0.5, 0.5,
|
||||
0.5, 0.5
|
||||
};
|
||||
|
||||
// Quantizer lookup, step 1: bitrate classes
|
||||
static const uint8_t PLM_AUDIO_QUANT_LUT_STEP_1[2][16] = {
|
||||
// 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384 <- bitrate
|
||||
{ 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // mono
|
||||
// 16, 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192 <- bitrate / chan
|
||||
{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2 } // stereo
|
||||
};
|
||||
|
||||
// Quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit
|
||||
static const uint8_t PLM_AUDIO_QUANT_TAB_A = (27 | 64); // Table 3-B.2a: high-rate, sblimit = 27
|
||||
static const uint8_t PLM_AUDIO_QUANT_TAB_B = (30 | 64); // Table 3-B.2b: high-rate, sblimit = 30
|
||||
static const uint8_t PLM_AUDIO_QUANT_TAB_C = 8; // Table 3-B.2c: low-rate, sblimit = 8
|
||||
static const uint8_t PLM_AUDIO_QUANT_TAB_D = 12; // Table 3-B.2d: low-rate, sblimit = 12
|
||||
|
||||
static const uint8_t QUANT_LUT_STEP_2[3][3] = {
|
||||
// 44.1 kHz, 48 kHz, 32 kHz
|
||||
{ PLM_AUDIO_QUANT_TAB_C, PLM_AUDIO_QUANT_TAB_C, PLM_AUDIO_QUANT_TAB_D }, // 32 - 48 kbit/sec/ch
|
||||
{ PLM_AUDIO_QUANT_TAB_A, PLM_AUDIO_QUANT_TAB_A, PLM_AUDIO_QUANT_TAB_A }, // 56 - 80 kbit/sec/ch
|
||||
{ PLM_AUDIO_QUANT_TAB_B, PLM_AUDIO_QUANT_TAB_A, PLM_AUDIO_QUANT_TAB_B } // 96+ kbit/sec/ch
|
||||
};
|
||||
|
||||
// Quantizer lookup, step 3: B2 table, subband -> nbal, row index
|
||||
// (upper 4 bits: nbal, lower 4 bits: row index)
|
||||
static const uint8_t PLM_AUDIO_QUANT_LUT_STEP_3[3][32] = {
|
||||
// Low-rate table (3-B.2c and 3-B.2d)
|
||||
{
|
||||
0x44,0x44,
|
||||
0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34
|
||||
},
|
||||
// High-rate table (3-B.2a and 3-B.2b)
|
||||
{
|
||||
0x43,0x43,0x43,
|
||||
0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
|
||||
0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,
|
||||
0x20,0x20,0x20,0x20,0x20,0x20,0x20
|
||||
},
|
||||
// MPEG-2 LSR table (B.2 in ISO 13818-3)
|
||||
{
|
||||
0x45,0x45,0x45,0x45,
|
||||
0x34,0x34,0x34,0x34,0x34,0x34,0x34,
|
||||
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||||
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24
|
||||
}
|
||||
};
|
||||
|
||||
// Quantizer lookup, step 4: table row, allocation[] value -> quant table index
|
||||
static const uint8_t PLM_AUDIO_QUANT_LUT_STEP4[6][16] = {
|
||||
{ 0, 1, 2, 17 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 17 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17 },
|
||||
{ 0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 },
|
||||
{ 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }
|
||||
};
|
||||
|
||||
typedef struct plm_quantizer_spec_t {
|
||||
unsigned short levels;
|
||||
unsigned char group;
|
||||
unsigned char bits;
|
||||
} plm_quantizer_spec_t;
|
||||
|
||||
static const plm_quantizer_spec_t PLM_AUDIO_QUANT_TAB[] = {
|
||||
{ 3, 1, 5 }, // 1
|
||||
{ 5, 1, 7 }, // 2
|
||||
{ 7, 0, 3 }, // 3
|
||||
{ 9, 1, 10 }, // 4
|
||||
{ 15, 0, 4 }, // 5
|
||||
{ 31, 0, 5 }, // 6
|
||||
{ 63, 0, 6 }, // 7
|
||||
{ 127, 0, 7 }, // 8
|
||||
{ 255, 0, 8 }, // 9
|
||||
{ 511, 0, 9 }, // 10
|
||||
{ 1023, 0, 10 }, // 11
|
||||
{ 2047, 0, 11 }, // 12
|
||||
{ 4095, 0, 12 }, // 13
|
||||
{ 8191, 0, 13 }, // 14
|
||||
{ 16383, 0, 14 }, // 15
|
||||
{ 32767, 0, 15 }, // 16
|
||||
{ 65535, 0, 16 } // 17
|
||||
};
|
||||
|
||||
struct plm_audio_t {
|
||||
double time;
|
||||
int samples_decoded;
|
||||
int samplerate_index;
|
||||
int bitrate_index;
|
||||
int version;
|
||||
int layer;
|
||||
int mode;
|
||||
int bound;
|
||||
int v_pos;
|
||||
int next_frame_data_size;
|
||||
plm_buffer_t *buffer;
|
||||
int destroy_buffer_when_done;
|
||||
const plm_quantizer_spec_t *allocation[2][32];
|
||||
uint8_t scale_factor_info[2][32];
|
||||
int scale_factor[2][32][3];
|
||||
int sample[2][32][3];
|
||||
plm_samples_t samples;
|
||||
float D[1024];
|
||||
float V[1024];
|
||||
float U[32];
|
||||
} aligned(64);
|
||||
|
||||
typedef plm_audio_t plm_audio_t;
|
||||
|
||||
int plm_audio_decode_header(plm_audio_t *self);
|
||||
void plm_audio_decode_frame(plm_audio_t *self);
|
||||
const plm_quantizer_spec_t *plm_audio_read_allocation(plm_audio_t *self, int sb, int tab3);
|
||||
void plm_audio_read_samples(plm_audio_t *self, int ch, int sb, int part);
|
||||
void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp);
|
||||
|
||||
plm_audio_t *plm_audio_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done) {
|
||||
plm_audio_t *self = (plm_audio_t *)memalign(alignof(plm_audio_t), sizeof(plm_audio_t));
|
||||
memset(self, 0, sizeof(plm_audio_t));
|
||||
|
||||
self->samples.count = PLM_AUDIO_SAMPLES_PER_FRAME;
|
||||
self->buffer = buffer;
|
||||
self->destroy_buffer_when_done = destroy_when_done;
|
||||
self->samplerate_index = 3; // indicates 0 samplerate
|
||||
|
||||
memcpy(self->D, PLM_AUDIO_SYNTHESIS_WINDOW, 512 * sizeof(float));
|
||||
memcpy(self->D + 512, PLM_AUDIO_SYNTHESIS_WINDOW, 512 * sizeof(float));
|
||||
|
||||
// Decode first header
|
||||
if (plm_buffer_has(self->buffer, 48)) {
|
||||
self->next_frame_data_size = plm_audio_decode_header(self);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void plm_audio_destroy(plm_audio_t *self) {
|
||||
if (self->destroy_buffer_when_done) {
|
||||
plm_buffer_destroy(self->buffer);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
int plm_audio_get_samplerate(plm_audio_t *self) {
|
||||
return PLM_AUDIO_SAMPLE_RATE[self->samplerate_index];
|
||||
}
|
||||
|
||||
double plm_audio_get_time(plm_audio_t *self) {
|
||||
return self->time;
|
||||
}
|
||||
|
||||
void plm_audio_rewind(plm_audio_t *self) {
|
||||
plm_buffer_rewind(self->buffer);
|
||||
self->time = 0;
|
||||
self->samples_decoded = 0;
|
||||
self->next_frame_data_size = 0;
|
||||
|
||||
// TODO: needed?
|
||||
memset(self->V, 0, sizeof(self->V));
|
||||
memset(self->U, 0, sizeof(self->U));
|
||||
}
|
||||
|
||||
plm_samples_t *plm_audio_decode(plm_audio_t *self) {
|
||||
DEBUGF("%s", "plm_audio_decode");
|
||||
// Do we have at least enough information to decode the frame header?
|
||||
if (!self->next_frame_data_size) {
|
||||
if (!plm_buffer_has(self->buffer, 48)) {
|
||||
return NULL;
|
||||
}
|
||||
self->next_frame_data_size = plm_audio_decode_header(self);
|
||||
}
|
||||
|
||||
if (
|
||||
self->next_frame_data_size == 0 ||
|
||||
!plm_buffer_has(self->buffer, self->next_frame_data_size << 3)
|
||||
) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plm_audio_decode_frame(self);
|
||||
self->next_frame_data_size = 0;
|
||||
|
||||
self->samples.time = self->time;
|
||||
|
||||
self->samples_decoded += PLM_AUDIO_SAMPLES_PER_FRAME;
|
||||
self->time = (double)self->samples_decoded /
|
||||
(double)PLM_AUDIO_SAMPLE_RATE[self->samplerate_index];
|
||||
|
||||
return &self->samples;
|
||||
}
|
||||
|
||||
int plm_audio_decode_header(plm_audio_t *self) {
|
||||
// Check for valid header: syncword OK, MPEG-Audio Layer 2
|
||||
plm_buffer_skip_bytes(self->buffer, 0x00);
|
||||
|
||||
int sync = plm_buffer_read(self->buffer, 11);
|
||||
self->version = plm_buffer_read(self->buffer, 2);
|
||||
self->layer = plm_buffer_read(self->buffer, 2);
|
||||
int hasCRC = !plm_buffer_read(self->buffer, 1);
|
||||
|
||||
if (
|
||||
sync != PLM_AUDIO_FRAME_SYNC ||
|
||||
self->version != PLM_AUDIO_MPEG_1 ||
|
||||
self->layer != PLM_AUDIO_LAYER_II
|
||||
) {
|
||||
return false; // Invalid header or unsupported version
|
||||
}
|
||||
|
||||
self->bitrate_index = plm_buffer_read(self->buffer, 4) - 1;
|
||||
if (self->bitrate_index > 13) {
|
||||
return false; // Invalid bit rate or 'free format'
|
||||
}
|
||||
|
||||
self->samplerate_index = plm_buffer_read(self->buffer, 2);
|
||||
if (self->samplerate_index == 3) {
|
||||
return false; // Invalid sample rate
|
||||
}
|
||||
|
||||
if (self->version == PLM_AUDIO_MPEG_2) {
|
||||
self->samplerate_index += 4;
|
||||
self->bitrate_index += 14;
|
||||
}
|
||||
int padding = plm_buffer_read(self->buffer, 1);
|
||||
plm_buffer_skip(self->buffer, 1); // f_private
|
||||
self->mode = plm_buffer_read(self->buffer, 2);
|
||||
|
||||
// Parse the mode_extension, set up the stereo bound
|
||||
self->bound = 0;
|
||||
if (self->mode == PLM_AUDIO_MODE_JOINT_STEREO) {
|
||||
self->bound = (plm_buffer_read(self->buffer, 2) + 1) << 2;
|
||||
}
|
||||
else {
|
||||
plm_buffer_skip(self->buffer, 2);
|
||||
self->bound = (self->mode == PLM_AUDIO_MODE_MONO) ? 0 : 32;
|
||||
}
|
||||
|
||||
// Discard the last 4 bits of the header and the CRC value, if present
|
||||
plm_buffer_skip(self->buffer, 4);
|
||||
if (hasCRC) {
|
||||
plm_buffer_skip(self->buffer, 16);
|
||||
}
|
||||
|
||||
// Compute frame size, check if we have enough data to decode the whole
|
||||
// frame.
|
||||
int bitrate = PLM_AUDIO_BIT_RATE[self->bitrate_index];
|
||||
int samplerate = PLM_AUDIO_SAMPLE_RATE[self->samplerate_index];
|
||||
int frame_size = (144000 * bitrate / samplerate) + padding;
|
||||
return frame_size - (hasCRC ? 6 : 4);
|
||||
}
|
||||
|
||||
void plm_audio_decode_frame(plm_audio_t *self) {
|
||||
// Prepare the quantizer table lookups
|
||||
int tab3 = 0;
|
||||
int sblimit = 0;
|
||||
if (self->version == PLM_AUDIO_MPEG_2) {
|
||||
// MPEG-2 (LSR)
|
||||
tab3 = 2;
|
||||
sblimit = 30;
|
||||
}
|
||||
else {
|
||||
// MPEG-1
|
||||
int tab1 = (self->mode == PLM_AUDIO_MODE_MONO) ? 0 : 1;
|
||||
int tab2 = PLM_AUDIO_QUANT_LUT_STEP_1[tab1][self->bitrate_index];
|
||||
tab3 = QUANT_LUT_STEP_2[tab2][self->samplerate_index];
|
||||
sblimit = tab3 & 63;
|
||||
tab3 >>= 6;
|
||||
}
|
||||
|
||||
if (self->bound > sblimit) {
|
||||
self->bound = sblimit;
|
||||
}
|
||||
|
||||
// Read the allocation information
|
||||
for (int sb = 0; sb < self->bound; sb++) {
|
||||
self->allocation[0][sb] = plm_audio_read_allocation(self, sb, tab3);
|
||||
self->allocation[1][sb] = plm_audio_read_allocation(self, sb, tab3);
|
||||
}
|
||||
|
||||
for (int sb = self->bound; sb < sblimit; sb++) {
|
||||
self->allocation[0][sb] =
|
||||
self->allocation[1][sb] =
|
||||
plm_audio_read_allocation(self, sb, tab3);
|
||||
}
|
||||
|
||||
// Read scale factor selector information
|
||||
int channels = (self->mode == PLM_AUDIO_MODE_MONO) ? 1 : 2;
|
||||
for (int sb = 0; sb < sblimit; sb++) {
|
||||
for (int ch = 0; ch < channels; ch++) {
|
||||
if (self->allocation[ch][sb]) {
|
||||
self->scale_factor_info[ch][sb] = plm_buffer_read(self->buffer, 2);
|
||||
}
|
||||
}
|
||||
if (self->mode == PLM_AUDIO_MODE_MONO) {
|
||||
self->scale_factor_info[1][sb] = self->scale_factor_info[0][sb];
|
||||
}
|
||||
}
|
||||
|
||||
// Read scale factors
|
||||
for (int sb = 0; sb < sblimit; sb++) {
|
||||
for (int ch = 0; ch < channels; ch++) {
|
||||
if (self->allocation[ch][sb]) {
|
||||
int *sf = self->scale_factor[ch][sb];
|
||||
switch (self->scale_factor_info[ch][sb]) {
|
||||
case 0:
|
||||
sf[0] = plm_buffer_read(self->buffer, 6);
|
||||
sf[1] = plm_buffer_read(self->buffer, 6);
|
||||
sf[2] = plm_buffer_read(self->buffer, 6);
|
||||
break;
|
||||
case 1:
|
||||
sf[0] =
|
||||
sf[1] = plm_buffer_read(self->buffer, 6);
|
||||
sf[2] = plm_buffer_read(self->buffer, 6);
|
||||
break;
|
||||
case 2:
|
||||
sf[0] =
|
||||
sf[1] =
|
||||
sf[2] = plm_buffer_read(self->buffer, 6);
|
||||
break;
|
||||
case 3:
|
||||
sf[0] = plm_buffer_read(self->buffer, 6);
|
||||
sf[1] =
|
||||
sf[2] = plm_buffer_read(self->buffer, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self->mode == PLM_AUDIO_MODE_MONO) {
|
||||
self->scale_factor[1][sb][0] = self->scale_factor[0][sb][0];
|
||||
self->scale_factor[1][sb][1] = self->scale_factor[0][sb][1];
|
||||
self->scale_factor[1][sb][2] = self->scale_factor[0][sb][2];
|
||||
}
|
||||
}
|
||||
|
||||
// Coefficient input and reconstruction
|
||||
int out_pos = 0;
|
||||
for (int part = 0; part < 3; part++) {
|
||||
for (int granule = 0; granule < 4; granule++) {
|
||||
|
||||
// Read the samples
|
||||
for (int sb = 0; sb < self->bound; sb++) {
|
||||
plm_audio_read_samples(self, 0, sb, part);
|
||||
plm_audio_read_samples(self, 1, sb, part);
|
||||
}
|
||||
for (int sb = self->bound; sb < sblimit; sb++) {
|
||||
plm_audio_read_samples(self, 0, sb, part);
|
||||
self->sample[1][sb][0] = self->sample[0][sb][0];
|
||||
self->sample[1][sb][1] = self->sample[0][sb][1];
|
||||
self->sample[1][sb][2] = self->sample[0][sb][2];
|
||||
}
|
||||
for (int sb = sblimit; sb < 32; sb++) {
|
||||
self->sample[0][sb][0] = 0;
|
||||
self->sample[0][sb][1] = 0;
|
||||
self->sample[0][sb][2] = 0;
|
||||
self->sample[1][sb][0] = 0;
|
||||
self->sample[1][sb][1] = 0;
|
||||
self->sample[1][sb][2] = 0;
|
||||
}
|
||||
|
||||
// Synthesis loop
|
||||
for (int p = 0; p < 3; p++) {
|
||||
// Shifting step
|
||||
self->v_pos = (self->v_pos - 64) & 1023;
|
||||
|
||||
for (int ch = 0; ch < 2; ch++) {
|
||||
plm_audio_matrix_transform(self->sample[ch], p, self->V, self->v_pos);
|
||||
|
||||
// Build U, windowing, calculate output
|
||||
memset(self->U, 0, sizeof(self->U));
|
||||
|
||||
int d_index = 512 - (self->v_pos >> 1);
|
||||
int v_index = (self->v_pos % 128) >> 1;
|
||||
while (v_index < 1024) {
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
self->U[i] += self->D[d_index++] * self->V[v_index++];
|
||||
}
|
||||
|
||||
v_index += 128 - 32;
|
||||
d_index += 64 - 32;
|
||||
}
|
||||
|
||||
d_index -= (512 - 32);
|
||||
v_index = (128 - 32 + 1024) - v_index;
|
||||
while (v_index < 1024) {
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
self->U[i] += self->D[d_index++] * self->V[v_index++];
|
||||
}
|
||||
|
||||
v_index += 128 - 32;
|
||||
d_index += 64 - 32;
|
||||
}
|
||||
|
||||
// Output samples
|
||||
#ifdef PLM_AUDIO_SEPARATE_CHANNELS
|
||||
float *out_channel = ch == 0
|
||||
? self->samples.left
|
||||
: self->samples.right;
|
||||
for (int j = 0; j < 32; j++) {
|
||||
out_channel[out_pos + j] = self->U[j] / 2147418112.0f;
|
||||
}
|
||||
#else
|
||||
for (int j = 0; j < 32; j++) {
|
||||
self->samples.interleaved[((out_pos + j) << 1) + ch] =
|
||||
self->U[j] / 2147418112.0f;
|
||||
}
|
||||
#endif
|
||||
} // End of synthesis channel loop
|
||||
out_pos += 32;
|
||||
} // End of synthesis sub-block loop
|
||||
|
||||
} // Decoding of the granule finished
|
||||
}
|
||||
|
||||
plm_buffer_align(self->buffer);
|
||||
}
|
||||
|
||||
const plm_quantizer_spec_t *plm_audio_read_allocation(plm_audio_t *self, int sb, int tab3) {
|
||||
int tab4 = PLM_AUDIO_QUANT_LUT_STEP_3[tab3][sb];
|
||||
int qtab = PLM_AUDIO_QUANT_LUT_STEP4[tab4 & 15][plm_buffer_read(self->buffer, tab4 >> 4)];
|
||||
return qtab ? (&PLM_AUDIO_QUANT_TAB[qtab - 1]) : 0;
|
||||
}
|
||||
|
||||
void plm_audio_read_samples(plm_audio_t *self, int ch, int sb, int part) {
|
||||
const plm_quantizer_spec_t *q = self->allocation[ch][sb];
|
||||
int sf = self->scale_factor[ch][sb][part];
|
||||
int *sample = self->sample[ch][sb];
|
||||
int val = 0;
|
||||
|
||||
if (!q) {
|
||||
// No bits allocated for this subband
|
||||
sample[0] = sample[1] = sample[2] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve scalefactor
|
||||
if (sf == 63) {
|
||||
sf = 0;
|
||||
}
|
||||
else {
|
||||
int shift = (sf / 3) | 0;
|
||||
sf = (PLM_AUDIO_SCALEFACTOR_BASE[sf % 3] + ((1u << shift) >> 1)) >> shift;
|
||||
}
|
||||
|
||||
// Decode samples
|
||||
int adj = q->levels;
|
||||
if (q->group) {
|
||||
// Decode grouped samples
|
||||
val = plm_buffer_read(self->buffer, q->bits);
|
||||
sample[0] = val % adj;
|
||||
val /= adj;
|
||||
sample[1] = val % adj;
|
||||
sample[2] = val / adj;
|
||||
}
|
||||
else {
|
||||
// Decode direct samples
|
||||
sample[0] = plm_buffer_read(self->buffer, q->bits);
|
||||
sample[1] = plm_buffer_read(self->buffer, q->bits);
|
||||
sample[2] = plm_buffer_read(self->buffer, q->bits);
|
||||
}
|
||||
|
||||
// Postmultiply samples
|
||||
int scale = 65536 / (adj + 1);
|
||||
adj = ((adj + 1) >> 1) - 1;
|
||||
|
||||
val = (adj - sample[0]) * scale;
|
||||
sample[0] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12;
|
||||
|
||||
val = (adj - sample[1]) * scale;
|
||||
sample[1] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12;
|
||||
|
||||
val = (adj - sample[2]) * scale;
|
||||
sample[2] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12;
|
||||
}
|
||||
|
||||
void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp) {
|
||||
float t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12,
|
||||
t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24,
|
||||
t25, t26, t27, t28, t29, t30, t31, t32, t33;
|
||||
|
||||
t01 = (float)(s[0][ss] + s[31][ss]); t02 = (float)(s[0][ss] - s[31][ss]) * 0.500602998235f;
|
||||
t03 = (float)(s[1][ss] + s[30][ss]); t04 = (float)(s[1][ss] - s[30][ss]) * 0.505470959898f;
|
||||
t05 = (float)(s[2][ss] + s[29][ss]); t06 = (float)(s[2][ss] - s[29][ss]) * 0.515447309923f;
|
||||
t07 = (float)(s[3][ss] + s[28][ss]); t08 = (float)(s[3][ss] - s[28][ss]) * 0.53104259109f;
|
||||
t09 = (float)(s[4][ss] + s[27][ss]); t10 = (float)(s[4][ss] - s[27][ss]) * 0.553103896034f;
|
||||
t11 = (float)(s[5][ss] + s[26][ss]); t12 = (float)(s[5][ss] - s[26][ss]) * 0.582934968206f;
|
||||
t13 = (float)(s[6][ss] + s[25][ss]); t14 = (float)(s[6][ss] - s[25][ss]) * 0.622504123036f;
|
||||
t15 = (float)(s[7][ss] + s[24][ss]); t16 = (float)(s[7][ss] - s[24][ss]) * 0.674808341455f;
|
||||
t17 = (float)(s[8][ss] + s[23][ss]); t18 = (float)(s[8][ss] - s[23][ss]) * 0.744536271002f;
|
||||
t19 = (float)(s[9][ss] + s[22][ss]); t20 = (float)(s[9][ss] - s[22][ss]) * 0.839349645416f;
|
||||
t21 = (float)(s[10][ss] + s[21][ss]); t22 = (float)(s[10][ss] - s[21][ss]) * 0.972568237862f;
|
||||
t23 = (float)(s[11][ss] + s[20][ss]); t24 = (float)(s[11][ss] - s[20][ss]) * 1.16943993343f;
|
||||
t25 = (float)(s[12][ss] + s[19][ss]); t26 = (float)(s[12][ss] - s[19][ss]) * 1.48416461631f;
|
||||
t27 = (float)(s[13][ss] + s[18][ss]); t28 = (float)(s[13][ss] - s[18][ss]) * 2.05778100995f;
|
||||
t29 = (float)(s[14][ss] + s[17][ss]); t30 = (float)(s[14][ss] - s[17][ss]) * 3.40760841847f;
|
||||
t31 = (float)(s[15][ss] + s[16][ss]); t32 = (float)(s[15][ss] - s[16][ss]) * 10.1900081235f;
|
||||
|
||||
t33 = t01 + t31; t31 = (t01 - t31) * 0.502419286188f;
|
||||
t01 = t03 + t29; t29 = (t03 - t29) * 0.52249861494f;
|
||||
t03 = t05 + t27; t27 = (t05 - t27) * 0.566944034816f;
|
||||
t05 = t07 + t25; t25 = (t07 - t25) * 0.64682178336f;
|
||||
t07 = t09 + t23; t23 = (t09 - t23) * 0.788154623451f;
|
||||
t09 = t11 + t21; t21 = (t11 - t21) * 1.06067768599f;
|
||||
t11 = t13 + t19; t19 = (t13 - t19) * 1.72244709824f;
|
||||
t13 = t15 + t17; t17 = (t15 - t17) * 5.10114861869f;
|
||||
t15 = t33 + t13; t13 = (t33 - t13) * 0.509795579104f;
|
||||
t33 = t01 + t11; t01 = (t01 - t11) * 0.601344886935f;
|
||||
t11 = t03 + t09; t09 = (t03 - t09) * 0.899976223136f;
|
||||
t03 = t05 + t07; t07 = (t05 - t07) * 2.56291544774f;
|
||||
t05 = t15 + t03; t15 = (t15 - t03) * 0.541196100146f;
|
||||
t03 = t33 + t11; t11 = (t33 - t11) * 1.30656296488f;
|
||||
t33 = t05 + t03; t05 = (t05 - t03) * 0.707106781187f;
|
||||
t03 = t15 + t11; t15 = (t15 - t11) * 0.707106781187f;
|
||||
t03 += t15;
|
||||
t11 = t13 + t07; t13 = (t13 - t07) * 0.541196100146f;
|
||||
t07 = t01 + t09; t09 = (t01 - t09) * 1.30656296488f;
|
||||
t01 = t11 + t07; t07 = (t11 - t07) * 0.707106781187f;
|
||||
t11 = t13 + t09; t13 = (t13 - t09) * 0.707106781187f;
|
||||
t11 += t13; t01 += t11;
|
||||
t11 += t07; t07 += t13;
|
||||
t09 = t31 + t17; t31 = (t31 - t17) * 0.509795579104f;
|
||||
t17 = t29 + t19; t29 = (t29 - t19) * 0.601344886935f;
|
||||
t19 = t27 + t21; t21 = (t27 - t21) * 0.899976223136f;
|
||||
t27 = t25 + t23; t23 = (t25 - t23) * 2.56291544774f;
|
||||
t25 = t09 + t27; t09 = (t09 - t27) * 0.541196100146f;
|
||||
t27 = t17 + t19; t19 = (t17 - t19) * 1.30656296488f;
|
||||
t17 = t25 + t27; t27 = (t25 - t27) * 0.707106781187f;
|
||||
t25 = t09 + t19; t19 = (t09 - t19) * 0.707106781187f;
|
||||
t25 += t19;
|
||||
t09 = t31 + t23; t31 = (t31 - t23) * 0.541196100146f;
|
||||
t23 = t29 + t21; t21 = (t29 - t21) * 1.30656296488f;
|
||||
t29 = t09 + t23; t23 = (t09 - t23) * 0.707106781187f;
|
||||
t09 = t31 + t21; t31 = (t31 - t21) * 0.707106781187f;
|
||||
t09 += t31; t29 += t09; t09 += t23; t23 += t31;
|
||||
t17 += t29; t29 += t25; t25 += t09; t09 += t27;
|
||||
t27 += t23; t23 += t19; t19 += t31;
|
||||
t21 = t02 + t32; t02 = (t02 - t32) * 0.502419286188f;
|
||||
t32 = t04 + t30; t04 = (t04 - t30) * 0.52249861494f;
|
||||
t30 = t06 + t28; t28 = (t06 - t28) * 0.566944034816f;
|
||||
t06 = t08 + t26; t08 = (t08 - t26) * 0.64682178336f;
|
||||
t26 = t10 + t24; t10 = (t10 - t24) * 0.788154623451f;
|
||||
t24 = t12 + t22; t22 = (t12 - t22) * 1.06067768599f;
|
||||
t12 = t14 + t20; t20 = (t14 - t20) * 1.72244709824f;
|
||||
t14 = t16 + t18; t16 = (t16 - t18) * 5.10114861869f;
|
||||
t18 = t21 + t14; t14 = (t21 - t14) * 0.509795579104f;
|
||||
t21 = t32 + t12; t32 = (t32 - t12) * 0.601344886935f;
|
||||
t12 = t30 + t24; t24 = (t30 - t24) * 0.899976223136f;
|
||||
t30 = t06 + t26; t26 = (t06 - t26) * 2.56291544774f;
|
||||
t06 = t18 + t30; t18 = (t18 - t30) * 0.541196100146f;
|
||||
t30 = t21 + t12; t12 = (t21 - t12) * 1.30656296488f;
|
||||
t21 = t06 + t30; t30 = (t06 - t30) * 0.707106781187f;
|
||||
t06 = t18 + t12; t12 = (t18 - t12) * 0.707106781187f;
|
||||
t06 += t12;
|
||||
t18 = t14 + t26; t26 = (t14 - t26) * 0.541196100146f;
|
||||
t14 = t32 + t24; t24 = (t32 - t24) * 1.30656296488f;
|
||||
t32 = t18 + t14; t14 = (t18 - t14) * 0.707106781187f;
|
||||
t18 = t26 + t24; t24 = (t26 - t24) * 0.707106781187f;
|
||||
t18 += t24; t32 += t18;
|
||||
t18 += t14; t26 = t14 + t24;
|
||||
t14 = t02 + t16; t02 = (t02 - t16) * 0.509795579104f;
|
||||
t16 = t04 + t20; t04 = (t04 - t20) * 0.601344886935f;
|
||||
t20 = t28 + t22; t22 = (t28 - t22) * 0.899976223136f;
|
||||
t28 = t08 + t10; t10 = (t08 - t10) * 2.56291544774f;
|
||||
t08 = t14 + t28; t14 = (t14 - t28) * 0.541196100146f;
|
||||
t28 = t16 + t20; t20 = (t16 - t20) * 1.30656296488f;
|
||||
t16 = t08 + t28; t28 = (t08 - t28) * 0.707106781187f;
|
||||
t08 = t14 + t20; t20 = (t14 - t20) * 0.707106781187f;
|
||||
t08 += t20;
|
||||
t14 = t02 + t10; t02 = (t02 - t10) * 0.541196100146f;
|
||||
t10 = t04 + t22; t22 = (t04 - t22) * 1.30656296488f;
|
||||
t04 = t14 + t10; t10 = (t14 - t10) * 0.707106781187f;
|
||||
t14 = t02 + t22; t02 = (t02 - t22) * 0.707106781187f;
|
||||
t14 += t02; t04 += t14; t14 += t10; t10 += t02;
|
||||
t16 += t04; t04 += t08; t08 += t14; t14 += t28;
|
||||
t28 += t10; t10 += t20; t20 += t02; t21 += t16;
|
||||
t16 += t32; t32 += t04; t04 += t06; t06 += t08;
|
||||
t08 += t18; t18 += t14; t14 += t30; t30 += t28;
|
||||
t28 += t26; t26 += t10; t10 += t12; t12 += t20;
|
||||
t20 += t24; t24 += t02;
|
||||
|
||||
d[dp + 48] = -t33;
|
||||
d[dp + 49] = d[dp + 47] = -t21;
|
||||
d[dp + 50] = d[dp + 46] = -t17;
|
||||
d[dp + 51] = d[dp + 45] = -t16;
|
||||
d[dp + 52] = d[dp + 44] = -t01;
|
||||
d[dp + 53] = d[dp + 43] = -t32;
|
||||
d[dp + 54] = d[dp + 42] = -t29;
|
||||
d[dp + 55] = d[dp + 41] = -t04;
|
||||
d[dp + 56] = d[dp + 40] = -t03;
|
||||
d[dp + 57] = d[dp + 39] = -t06;
|
||||
d[dp + 58] = d[dp + 38] = -t25;
|
||||
d[dp + 59] = d[dp + 37] = -t08;
|
||||
d[dp + 60] = d[dp + 36] = -t11;
|
||||
d[dp + 61] = d[dp + 35] = -t18;
|
||||
d[dp + 62] = d[dp + 34] = -t09;
|
||||
d[dp + 63] = d[dp + 33] = -t14;
|
||||
d[dp + 32] = -t05;
|
||||
d[dp + 0] = t05; d[dp + 31] = -t30;
|
||||
d[dp + 1] = t30; d[dp + 30] = -t27;
|
||||
d[dp + 2] = t27; d[dp + 29] = -t28;
|
||||
d[dp + 3] = t28; d[dp + 28] = -t07;
|
||||
d[dp + 4] = t07; d[dp + 27] = -t26;
|
||||
d[dp + 5] = t26; d[dp + 26] = -t23;
|
||||
d[dp + 6] = t23; d[dp + 25] = -t10;
|
||||
d[dp + 7] = t10; d[dp + 24] = -t15;
|
||||
d[dp + 8] = t15; d[dp + 23] = -t12;
|
||||
d[dp + 9] = t12; d[dp + 22] = -t19;
|
||||
d[dp + 10] = t19; d[dp + 21] = -t20;
|
||||
d[dp + 11] = t20; d[dp + 20] = -t13;
|
||||
d[dp + 12] = t13; d[dp + 19] = -t24;
|
||||
d[dp + 13] = t24; d[dp + 18] = -t31;
|
||||
d[dp + 14] = t31; d[dp + 17] = -t02;
|
||||
d[dp + 15] = t02; d[dp + 16] = 0.0;
|
||||
};
|
||||
|
450
dsp/mpeg/mpeg.h
Normal file
450
dsp/mpeg/mpeg.h
Normal file
|
@ -0,0 +1,450 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_MPEG_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_MPEG_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct FILE;
|
||||
|
||||
typedef struct plm_t plm_t;
|
||||
typedef struct plm_buffer_t plm_buffer_t;
|
||||
typedef struct plm_demux_t plm_demux_t;
|
||||
typedef struct plm_video_t plm_video_t;
|
||||
typedef struct plm_audio_t plm_audio_t;
|
||||
|
||||
/**
|
||||
* Demuxed MPEG PS packet
|
||||
*
|
||||
* The type maps directly to the various MPEG-PES start codes. pts is
|
||||
* the presentation time stamp of the packet in seconds. Not all packets
|
||||
* have a pts value.
|
||||
*/
|
||||
typedef struct plm_packet_t {
|
||||
int type;
|
||||
double pts;
|
||||
size_t length;
|
||||
uint8_t *data;
|
||||
} plm_packet_t;
|
||||
|
||||
/**
|
||||
* Decoded Video Plane
|
||||
*
|
||||
* The byte length of the data is width * height. Note that different
|
||||
* planes have different sizes: the Luma plane (Y) is double the size of
|
||||
* each of the two Chroma planes (Cr, Cb) - i.e. 4 times the byte
|
||||
* length. Also note that the size of the plane does *not* denote the
|
||||
* size of the displayed frame. The sizes of planes are always rounded
|
||||
* up to the nearest macroblock (16px).
|
||||
*/
|
||||
typedef struct plm_plane_t {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
uint8_t *data;
|
||||
} plm_plane_t;
|
||||
|
||||
/**
|
||||
* Decoded Video Frame
|
||||
*
|
||||
* Width and height denote the desired display size of the frame. This
|
||||
* may be different from the internal size of the 3 planes.
|
||||
*/
|
||||
typedef struct plm_frame_t {
|
||||
double time;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
plm_plane_t y;
|
||||
plm_plane_t cr;
|
||||
plm_plane_t cb;
|
||||
} plm_frame_t;
|
||||
|
||||
/**
|
||||
* Callback function type for decoded video frames used by the high-level
|
||||
* plm_* interface
|
||||
*/
|
||||
typedef void (*plm_video_decode_callback)(plm_t *self, plm_frame_t *frame,
|
||||
void *user);
|
||||
|
||||
/**
|
||||
* Decoded Audio Samples
|
||||
*
|
||||
* Samples are stored as normalized (-1, 1) float either interleaved, or if
|
||||
* PLM_AUDIO_SEPARATE_CHANNELS is defined, in two separate arrays.
|
||||
* The `count` is always PLM_AUDIO_SAMPLES_PER_FRAME and just there for
|
||||
* convenience.
|
||||
*/
|
||||
#define PLM_AUDIO_SAMPLES_PER_FRAME 1152
|
||||
|
||||
struct plm_samples_t {
|
||||
double time;
|
||||
unsigned int count;
|
||||
#ifdef PLM_AUDIO_SEPARATE_CHANNELS
|
||||
float left[PLM_AUDIO_SAMPLES_PER_FRAME] aligned(32);
|
||||
float right[PLM_AUDIO_SAMPLES_PER_FRAME] aligned(32);
|
||||
#else
|
||||
float interleaved[PLM_AUDIO_SAMPLES_PER_FRAME * 2] aligned(32);
|
||||
#endif
|
||||
} aligned(32);
|
||||
|
||||
typedef struct plm_samples_t plm_samples_t;
|
||||
|
||||
/**
|
||||
* Callback function type for decoded audio samples used by the high-level
|
||||
* plm_* interface
|
||||
*/
|
||||
typedef void (*plm_audio_decode_callback)(plm_t *self, plm_samples_t *samples,
|
||||
void *user);
|
||||
|
||||
/**
|
||||
* Callback function for plm_buffer when it needs more data
|
||||
*/
|
||||
typedef void (*plm_buffer_load_callback)(plm_buffer_t *self, void *user);
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------------------------------
|
||||
* plm_* public API
|
||||
* High-Level API for loading/demuxing/decoding MPEG-PS data
|
||||
*
|
||||
* Create a plmpeg instance with a filename. Returns NULL if the file could not
|
||||
* be opened.
|
||||
*/
|
||||
plm_t *plm_create_with_filename(const char *filename);
|
||||
|
||||
/**
|
||||
* Create a plmpeg instance with file handle. Pass true to close_when_done
|
||||
* to let plmpeg call fclose() on the handle when plm_destroy() is
|
||||
* called.
|
||||
*/
|
||||
plm_t *plm_create_with_file(struct FILE *fh, int close_when_done);
|
||||
|
||||
/**
|
||||
* Create a plmpeg instance with pointer to memory as source. This assumes the
|
||||
* whole file is in memory. Pass true to free_when_done to let plmpeg call
|
||||
* free() on the pointer when plm_destroy() is called.
|
||||
*/
|
||||
plm_t *plm_create_with_memory(uint8_t *bytes, size_t length,
|
||||
int free_when_done);
|
||||
|
||||
/**
|
||||
* Create a plmpeg instance with a plm_buffer as source. This is also
|
||||
* called internally by all the above constructor functions.
|
||||
*/
|
||||
plm_t *plm_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done);
|
||||
|
||||
/**
|
||||
* Destroy a plmpeg instance and free all data
|
||||
*/
|
||||
void plm_destroy(plm_t *self);
|
||||
|
||||
/**
|
||||
* Get or set whether video decoding is enabled.
|
||||
*/
|
||||
int plm_get_video_enabled(plm_t *self);
|
||||
void plm_set_video_enabled(plm_t *self, int enabled);
|
||||
|
||||
/**
|
||||
* Get or set whether audio decoding is enabled. When enabling, you can set the
|
||||
* desired audio stream (0-3) to decode.
|
||||
*/
|
||||
int plm_get_audio_enabled(plm_t *self);
|
||||
void plm_set_audio_enabled(plm_t *self, int enabled, int stream_index);
|
||||
|
||||
/**
|
||||
* Get the display width/height of the video stream
|
||||
*/
|
||||
int plm_get_width(plm_t *self);
|
||||
int plm_get_height(plm_t *self);
|
||||
|
||||
double plm_get_pixel_aspect_ratio(plm_t *);
|
||||
|
||||
/**
|
||||
* Get the framerate of the video stream in frames per second
|
||||
*/
|
||||
double plm_get_framerate(plm_t *self);
|
||||
|
||||
/**
|
||||
* Get the number of available audio streams in the file
|
||||
*/
|
||||
int plm_get_num_audio_streams(plm_t *self);
|
||||
|
||||
/**
|
||||
* Get the samplerate of the audio stream in samples per second
|
||||
*/
|
||||
int plm_get_samplerate(plm_t *self);
|
||||
|
||||
/**
|
||||
* Get or set the audio lead time in seconds - the time in which audio samples
|
||||
* are decoded in advance (or behind) the video decode time. Default 0.
|
||||
*/
|
||||
double plm_get_audio_lead_time(plm_t *self);
|
||||
void plm_set_audio_lead_time(plm_t *self, double lead_time);
|
||||
|
||||
/**
|
||||
* Get the current internal time in seconds
|
||||
*/
|
||||
double plm_get_time(plm_t *self);
|
||||
|
||||
/**
|
||||
* Rewind all buffers back to the beginning.
|
||||
*/
|
||||
void plm_rewind(plm_t *self);
|
||||
|
||||
/**
|
||||
* Get or set looping. Default false.
|
||||
*/
|
||||
int plm_get_loop(plm_t *self);
|
||||
void plm_set_loop(plm_t *self, int loop);
|
||||
|
||||
/**
|
||||
* Get whether the file has ended. If looping is enabled, this will always
|
||||
* return false.
|
||||
*/
|
||||
int plm_has_ended(plm_t *self);
|
||||
|
||||
/**
|
||||
* Set the callback for decoded video frames used with plm_decode(). If no
|
||||
* callback is set, video data will be ignored and not be decoded.
|
||||
*/
|
||||
void plm_set_video_decode_callback(plm_t *self, plm_video_decode_callback fp,
|
||||
void *user);
|
||||
|
||||
/**
|
||||
* Set the callback for decoded audio samples used with plm_decode(). If no
|
||||
* callback is set, audio data will be ignored and not be decoded.
|
||||
*/
|
||||
void plm_set_audio_decode_callback(plm_t *self, plm_audio_decode_callback fp,
|
||||
void *user);
|
||||
|
||||
/**
|
||||
* Advance the internal timer by seconds and decode video/audio up to
|
||||
* this time. Returns true/false whether anything was decoded.
|
||||
*/
|
||||
int plm_decode(plm_t *self, double seconds);
|
||||
|
||||
/**
|
||||
* Decode and return one video frame. Returns NULL if no frame could be decoded
|
||||
* (either because the source ended or data is corrupt). If you only want to
|
||||
* decode video, you should disable audio via plm_set_audio_enabled().
|
||||
* The returned plm_frame_t is valid until the next call to
|
||||
* plm_decode_video call or until the plm_destroy is called.
|
||||
*/
|
||||
plm_frame_t *plm_decode_video(plm_t *self);
|
||||
|
||||
/**
|
||||
* Decode and return one audio frame. Returns NULL if no frame could be decoded
|
||||
* (either because the source ended or data is corrupt). If you only want to
|
||||
* decode audio, you should disable video via plm_set_video_enabled().
|
||||
* The returned plm_samples_t is valid until the next call to
|
||||
* plm_decode_video or until the plm_destroy is called.
|
||||
*/
|
||||
plm_samples_t *plm_decode_audio(plm_t *self);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* plm_buffer public API
|
||||
* Provides the data source for all other plm_* interfaces
|
||||
*
|
||||
* The default size for buffers created from files or by the high-level API
|
||||
*/
|
||||
#ifndef PLM_BUFFER_DEFAULT_SIZE
|
||||
#define PLM_BUFFER_DEFAULT_SIZE (128 * 1024)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create a buffer instance with a filename. Returns NULL if the file could not
|
||||
* be opened.
|
||||
*/
|
||||
plm_buffer_t *plm_buffer_create_with_filename(const char *filename);
|
||||
|
||||
/**
|
||||
* Create a buffer instance with file handle. Pass true to close_when_done
|
||||
* to let plmpeg call fclose() on the handle when plm_destroy() is
|
||||
* called.
|
||||
*/
|
||||
plm_buffer_t *plm_buffer_create_with_file(struct FILE *fh, int close_when_done);
|
||||
|
||||
/**
|
||||
* Create a buffer instance with a pointer to memory as source. This assumes
|
||||
* the whole file is in memory. Pass 1 to free_when_done to let plmpeg call
|
||||
* free() on the pointer when plm_destroy() is called.
|
||||
*/
|
||||
plm_buffer_t *plm_buffer_create_with_memory(uint8_t *bytes, size_t length,
|
||||
int free_when_done);
|
||||
|
||||
/**
|
||||
* Create an empty buffer with an initial capacity. The buffer will grow
|
||||
* as needed.
|
||||
*/
|
||||
plm_buffer_t *plm_buffer_create_with_capacity(size_t capacity);
|
||||
|
||||
/**
|
||||
* Destroy a buffer instance and free all data
|
||||
*/
|
||||
void plm_buffer_destroy(plm_buffer_t *self);
|
||||
|
||||
/**
|
||||
* Copy data into the buffer. If the data to be written is larger than the
|
||||
* available space, the buffer will realloc() with a larger capacity.
|
||||
* Returns the number of bytes written. This will always be the same as the
|
||||
* passed in length, except when the buffer was created _with_memory() for
|
||||
* which _write() is forbidden.
|
||||
*/
|
||||
size_t plm_buffer_write(plm_buffer_t *self, uint8_t *bytes, size_t length);
|
||||
|
||||
/**
|
||||
* Set a callback that is called whenever the buffer needs more data
|
||||
*/
|
||||
void plm_buffer_set_load_callback(plm_buffer_t *self,
|
||||
plm_buffer_load_callback fp, void *user);
|
||||
|
||||
/**
|
||||
* Rewind the buffer back to the beginning. When loading from a file handle,
|
||||
* this also seeks to the beginning of the file.
|
||||
*/
|
||||
void plm_buffer_rewind(plm_buffer_t *self);
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------------------------------
|
||||
* plm_demux public API
|
||||
* Demux an MPEG Program Stream (PS) data into separate packages
|
||||
*
|
||||
* Various Packet Types
|
||||
*/
|
||||
#define PLM_DEMUX_PACKET_PRIVATE 0xBD
|
||||
#define PLM_DEMUX_PACKET_AUDIO_1 0xC0
|
||||
#define PLM_DEMUX_PACKET_AUDIO_2 0xC1
|
||||
#define PLM_DEMUX_PACKET_AUDIO_3 0xC2
|
||||
#define PLM_DEMUX_PACKET_AUDIO_4 0xC2
|
||||
#define PLM_DEMUX_PACKET_VIDEO_1 0xE0
|
||||
|
||||
/**
|
||||
* Create a demuxer with a plm_buffer as source
|
||||
*/
|
||||
plm_demux_t *plm_demux_create(plm_buffer_t *buffer, int destroy_when_done);
|
||||
|
||||
/**
|
||||
* Destroy a demuxer and free all data
|
||||
*/
|
||||
void plm_demux_destroy(plm_demux_t *self);
|
||||
|
||||
/**
|
||||
* Returns the number of video streams found in the system header.
|
||||
*/
|
||||
int plm_demux_get_num_video_streams(plm_demux_t *self);
|
||||
|
||||
/**
|
||||
* Returns the number of audio streams found in the system header.
|
||||
*/
|
||||
int plm_demux_get_num_audio_streams(plm_demux_t *self);
|
||||
|
||||
/**
|
||||
* Rewinds the internal buffer. See plm_buffer_rewind().
|
||||
*/
|
||||
void plm_demux_rewind(plm_demux_t *self);
|
||||
|
||||
/**
|
||||
* Decode and return the next packet. The returned packet_t is valid until
|
||||
* the next call to plm_demux_decode() or until the demuxer is destroyed.
|
||||
*/
|
||||
plm_packet_t *plm_demux_decode(plm_demux_t *self);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* plm_video public API
|
||||
* Decode MPEG1 Video ("mpeg1") data into raw YCrCb frames
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a video decoder with a plm_buffer as source
|
||||
*/
|
||||
plm_video_t *plm_video_create_with_buffer(plm_buffer_t *buffer,
|
||||
int destroy_when_done);
|
||||
|
||||
/**
|
||||
* Destroy a video decoder and free all data
|
||||
*/
|
||||
void plm_video_destroy(plm_video_t *self);
|
||||
|
||||
/**
|
||||
* Get the framerate in frames per second
|
||||
*/
|
||||
double plm_video_get_framerate(plm_video_t *);
|
||||
|
||||
double plm_video_get_pixel_aspect_ratio(plm_video_t *);
|
||||
|
||||
/**
|
||||
* Get the display width/height
|
||||
*/
|
||||
int plm_video_get_width(plm_video_t *);
|
||||
int plm_video_get_height(plm_video_t *);
|
||||
|
||||
/**
|
||||
* Set "no delay" mode. When enabled, the decoder assumes that the video does
|
||||
* *not* contain any B-Frames. This is useful for reducing lag when streaming.
|
||||
*/
|
||||
void plm_video_set_no_delay(plm_video_t *self, int no_delay);
|
||||
|
||||
/**
|
||||
* Get the current internal time in seconds
|
||||
*/
|
||||
double plm_video_get_time(plm_video_t *self);
|
||||
|
||||
/**
|
||||
* Rewinds the internal buffer. See plm_buffer_rewind().
|
||||
*/
|
||||
void plm_video_rewind(plm_video_t *self);
|
||||
|
||||
/**
|
||||
* Decode and return one frame of video and advance the internal time by
|
||||
* 1/framerate seconds. The returned frame_t is valid until the next call of
|
||||
* plm_video_decode() or until the video decoder is destroyed.
|
||||
*/
|
||||
plm_frame_t *plm_video_decode(plm_video_t *self);
|
||||
|
||||
/**
|
||||
* Convert the YCrCb data of a frame into an interleaved RGB buffer. The buffer
|
||||
* pointed to by *rgb must have a size of (frame->width * frame->height * 3)
|
||||
* bytes.
|
||||
*/
|
||||
void plm_frame_to_rgb(plm_frame_t *frame, uint8_t *rgb);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* plm_audio public API
|
||||
* Decode MPEG-1 Audio Layer II ("mp2") data into raw samples
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create an audio decoder with a plm_buffer as source.
|
||||
*/
|
||||
plm_audio_t *plm_audio_create_with_buffer(plm_buffer_t *buffer,
|
||||
int destroy_when_done);
|
||||
|
||||
/**
|
||||
* Destroy an audio decoder and free all data
|
||||
*/
|
||||
void plm_audio_destroy(plm_audio_t *self);
|
||||
|
||||
/**
|
||||
* Get the samplerate in samples per second
|
||||
*/
|
||||
int plm_audio_get_samplerate(plm_audio_t *self);
|
||||
|
||||
/**
|
||||
* Get the current internal time in seconds
|
||||
*/
|
||||
double plm_audio_get_time(plm_audio_t *self);
|
||||
|
||||
/**
|
||||
* Rewinds the internal buffer. See plm_buffer_rewind().
|
||||
*/
|
||||
void plm_audio_rewind(plm_audio_t *self);
|
||||
|
||||
/**
|
||||
* Decode and return one "frame" of audio and advance the internal time by
|
||||
* (PLM_AUDIO_SAMPLES_PER_FRAME/samplerate) seconds. The returned samples_t
|
||||
* is valid until the next call of plm_audio_decode() or until the audio
|
||||
* decoder is destroyed.
|
||||
*/
|
||||
plm_samples_t *plm_audio_decode(plm_audio_t *self);
|
||||
|
||||
extern long plmpegdecode_latency_;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_MPEG_H_ */
|
69
dsp/mpeg/mpeg.mk
Normal file
69
dsp/mpeg/mpeg.mk
Normal file
|
@ -0,0 +1,69 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += DSP_MPEG
|
||||
|
||||
DSP_MPEG_ARTIFACTS += DSP_MPEG_A
|
||||
DSP_MPEG = $(DSP_MPEG_A_DEPS) $(DSP_MPEG_A)
|
||||
DSP_MPEG_A = o/$(MODE)/dsp/mpeg/mpeg.a
|
||||
DSP_MPEG_A_FILES := $(wildcard dsp/mpeg/*)
|
||||
DSP_MPEG_A_HDRS = $(filter %.h,$(DSP_MPEG_A_FILES))
|
||||
DSP_MPEG_A_SRCS_S = $(filter %.S,$(DSP_MPEG_A_FILES))
|
||||
DSP_MPEG_A_SRCS_C = $(filter %.c,$(DSP_MPEG_A_FILES))
|
||||
|
||||
DSP_MPEG_A_SRCS = \
|
||||
$(DSP_MPEG_A_SRCS_S) \
|
||||
$(DSP_MPEG_A_SRCS_C)
|
||||
|
||||
DSP_MPEG_A_OBJS = \
|
||||
$(DSP_MPEG_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(DSP_MPEG_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(DSP_MPEG_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
DSP_MPEG_A_CHECKS = \
|
||||
$(DSP_MPEG_A).pkg \
|
||||
$(DSP_MPEG_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
DSP_MPEG_A_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_LOG \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_TIME \
|
||||
LIBC_STUBS \
|
||||
LIBC_STR \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_STDIO \
|
||||
LIBC_SYSV \
|
||||
LIBC_MEM \
|
||||
LIBC_LOG \
|
||||
LIBC_FMT \
|
||||
LIBC_UNICODE \
|
||||
|
||||
DSP_MPEG_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(DSP_MPEG_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(DSP_MPEG_A): dsp/mpeg/ \
|
||||
$(DSP_MPEG_A).pkg \
|
||||
$(DSP_MPEG_A_OBJS)
|
||||
|
||||
$(DSP_MPEG_A).pkg: \
|
||||
$(DSP_MPEG_A_OBJS) \
|
||||
$(foreach x,$(DSP_MPEG_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/dsp/mpeg/clamp4int256-k8.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os
|
||||
|
||||
#o/$(MODE)/dsp/mpeg/macroblock.o: \
|
||||
CC = $(CLANG)
|
||||
|
||||
DSP_MPEG_LIBS = $(foreach x,$(DSP_MPEG_ARTIFACTS),$($(x)))
|
||||
DSP_MPEG_SRCS = $(foreach x,$(DSP_MPEG_ARTIFACTS),$($(x)_SRCS))
|
||||
DSP_MPEG_HDRS = $(foreach x,$(DSP_MPEG_ARTIFACTS),$($(x)_HDRS))
|
||||
DSP_MPEG_CHECKS = $(foreach x,$(DSP_MPEG_ARTIFACTS),$($(x)_CHECKS))
|
||||
DSP_MPEG_OBJS = $(foreach x,$(DSP_MPEG_ARTIFACTS),$($(x)_OBJS))
|
||||
$(DSP_MPEG_OBJS): $(BUILD_FILES) dsp/mpeg/mpeg.mk
|
||||
|
||||
.PHONY: o/$(MODE)/dsp/mpeg
|
||||
o/$(MODE)/dsp/mpeg: $(DSP_MPEG_CHECKS)
|
1115
dsp/mpeg/mpeg1.c
Normal file
1115
dsp/mpeg/mpeg1.c
Normal file
File diff suppressed because it is too large
Load diff
337
dsp/mpeg/plm.c
Normal file
337
dsp/mpeg/plm.c
Normal file
|
@ -0,0 +1,337 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
PL_MPEG (MIT License)\\n\
|
||||
Copyright(c) 2019 Dominic Szablewski\\n\
|
||||
https://phoboslab.org\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/* clang-format off */
|
||||
// -----------------------------------------------------------------------------
|
||||
// plm (high-level interface) implementation
|
||||
|
||||
typedef struct plm_t {
|
||||
plm_demux_t *demux;
|
||||
double time;
|
||||
int has_ended;
|
||||
int loop;
|
||||
|
||||
int video_packet_type;
|
||||
plm_buffer_t *video_buffer;
|
||||
plm_video_t *video_decoder;
|
||||
|
||||
int audio_packet_type;
|
||||
double audio_lead_time;
|
||||
plm_buffer_t *audio_buffer;
|
||||
plm_audio_t *audio_decoder;
|
||||
|
||||
plm_video_decode_callback video_decode_callback;
|
||||
void *video_decode_callback_user_data;
|
||||
|
||||
plm_audio_decode_callback audio_decode_callback;
|
||||
void *audio_decode_callback_user_data;
|
||||
} plm_t;
|
||||
|
||||
void plm_handle_end(plm_t *self);
|
||||
void plm_read_video_packet(plm_buffer_t *buffer, void *user);
|
||||
void plm_read_audio_packet(plm_buffer_t *buffer, void *user);
|
||||
void plm_read_packets(plm_t *self, int requested_type);
|
||||
|
||||
plm_t *plm_create_with_filename(const char *filename) {
|
||||
plm_buffer_t *buffer = plm_buffer_create_with_filename(filename);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
return plm_create_with_buffer(buffer, true);
|
||||
}
|
||||
|
||||
plm_t *plm_create_with_file(FILE *fh, int close_when_done) {
|
||||
plm_buffer_t *buffer = plm_buffer_create_with_file(fh, close_when_done);
|
||||
return plm_create_with_buffer(buffer, true);
|
||||
}
|
||||
|
||||
plm_t *plm_create_with_memory(uint8_t *bytes, size_t length, int free_when_done) {
|
||||
plm_buffer_t *buffer = plm_buffer_create_with_memory(bytes, length, free_when_done);
|
||||
return plm_create_with_buffer(buffer, true);
|
||||
}
|
||||
|
||||
plm_t *plm_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done) {
|
||||
plm_t *self = (plm_t *)malloc(sizeof(plm_t));
|
||||
memset(self, 0, sizeof(plm_t));
|
||||
|
||||
self->demux = plm_demux_create(buffer, destroy_when_done);
|
||||
|
||||
// In theory we should check plm_demux_get_num_video_streams() and
|
||||
// plm_demux_get_num_audio_streams() here, but older files typically
|
||||
// do not specify these correcly. So we just assume we have a video and
|
||||
// audio stream and create the decoders.
|
||||
|
||||
self->video_packet_type = PLM_DEMUX_PACKET_VIDEO_1;
|
||||
self->video_buffer = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE);
|
||||
plm_buffer_set_load_callback(self->video_buffer, plm_read_video_packet, self);
|
||||
|
||||
self->audio_packet_type = PLM_DEMUX_PACKET_AUDIO_1;
|
||||
self->audio_buffer = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE);
|
||||
plm_buffer_set_load_callback(self->audio_buffer, plm_read_audio_packet, self);
|
||||
|
||||
self->video_decoder = plm_video_create_with_buffer(self->video_buffer, true);
|
||||
self->audio_decoder = plm_audio_create_with_buffer(self->audio_buffer, true);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void plm_destroy(plm_t *self) {
|
||||
plm_video_destroy(self->video_decoder);
|
||||
plm_audio_destroy(self->audio_decoder);
|
||||
plm_demux_destroy(self->demux);
|
||||
free(self);
|
||||
}
|
||||
|
||||
int plm_get_audio_enabled(plm_t *self) {
|
||||
return (self->audio_packet_type != 0);
|
||||
}
|
||||
|
||||
void plm_set_audio_enabled(plm_t *self, int enabled, int stream_index) {
|
||||
/* int num_streams = plm_demux_get_num_audio_streams(self->demux); */
|
||||
self->audio_packet_type = (enabled && stream_index >= 0 && stream_index < 4)
|
||||
? PLM_DEMUX_PACKET_AUDIO_1 + stream_index
|
||||
: 0;
|
||||
}
|
||||
|
||||
int plm_get_video_enabled(plm_t *self) {
|
||||
return (self->video_packet_type != 0);
|
||||
}
|
||||
|
||||
void plm_set_video_enabled(plm_t *self, int enabled) {
|
||||
self->video_packet_type = (enabled)
|
||||
? PLM_DEMUX_PACKET_VIDEO_1
|
||||
: 0;
|
||||
}
|
||||
|
||||
int plm_get_width(plm_t *self) {
|
||||
return plm_video_get_width(self->video_decoder);
|
||||
}
|
||||
|
||||
double plm_get_pixel_aspect_ratio(plm_t *self) {
|
||||
return plm_video_get_pixel_aspect_ratio(self->video_decoder);
|
||||
}
|
||||
|
||||
int plm_get_height(plm_t *self) {
|
||||
return plm_video_get_height(self->video_decoder);
|
||||
}
|
||||
|
||||
double plm_get_framerate(plm_t *self) {
|
||||
return plm_video_get_framerate(self->video_decoder);
|
||||
}
|
||||
|
||||
int plm_get_num_audio_streams(plm_t *self) {
|
||||
// Some files do not specify the number of audio streams in the system header.
|
||||
// If the reported number of streams is 0, we check if we have a samplerate,
|
||||
// indicating at least one audio stream.
|
||||
int num_streams = plm_demux_get_num_audio_streams(self->demux);
|
||||
return num_streams == 0 && plm_get_samplerate(self) ? 1 : num_streams;
|
||||
}
|
||||
|
||||
int plm_get_samplerate(plm_t *self) {
|
||||
return plm_audio_get_samplerate(self->audio_decoder);
|
||||
}
|
||||
|
||||
double plm_get_audio_lead_time(plm_t *self) {
|
||||
return self->audio_lead_time;
|
||||
}
|
||||
|
||||
void plm_set_audio_lead_time(plm_t *self, double lead_time) {
|
||||
self->audio_lead_time = lead_time;
|
||||
}
|
||||
|
||||
double plm_get_time(plm_t *self) {
|
||||
return self->time;
|
||||
}
|
||||
|
||||
void plm_rewind(plm_t *self) {
|
||||
plm_video_rewind(self->video_decoder);
|
||||
plm_audio_rewind(self->audio_decoder);
|
||||
plm_demux_rewind(self->demux);
|
||||
self->time = 0;
|
||||
}
|
||||
|
||||
int plm_get_loop(plm_t *self) {
|
||||
return self->loop;
|
||||
}
|
||||
|
||||
void plm_set_loop(plm_t *self, int loop) {
|
||||
self->loop = loop;
|
||||
}
|
||||
|
||||
int plm_has_ended(plm_t *self) {
|
||||
return self->has_ended;
|
||||
}
|
||||
|
||||
void plm_set_video_decode_callback(plm_t *self, plm_video_decode_callback fp, void *user) {
|
||||
self->video_decode_callback = fp;
|
||||
self->video_decode_callback_user_data = user;
|
||||
}
|
||||
|
||||
void plm_set_audio_decode_callback(plm_t *self, plm_audio_decode_callback fp, void *user) {
|
||||
self->audio_decode_callback = fp;
|
||||
self->audio_decode_callback_user_data = user;
|
||||
}
|
||||
|
||||
int plm_decode(plm_t *self, double tick) {
|
||||
DEBUGF("%s", "plm_decode");
|
||||
|
||||
int decode_video = (self->video_decode_callback && self->video_packet_type);
|
||||
int decode_audio = (self->audio_decode_callback && self->audio_packet_type);
|
||||
|
||||
if (!decode_video && !decode_audio) {
|
||||
// Nothing to do here
|
||||
return false;
|
||||
}
|
||||
|
||||
int did_decode = false;
|
||||
int video_ended = false;
|
||||
int audio_ended = false;
|
||||
|
||||
double video_target_time = self->time + tick;
|
||||
double audio_target_time = self->time + tick;
|
||||
|
||||
if (self->audio_lead_time > 0 && decode_audio) {
|
||||
video_target_time -= self->audio_lead_time;
|
||||
}
|
||||
else {
|
||||
audio_target_time -= self->audio_lead_time;
|
||||
}
|
||||
|
||||
do {
|
||||
did_decode = false;
|
||||
|
||||
if (decode_video && plm_video_get_time(self->video_decoder) < video_target_time) {
|
||||
plm_frame_t *frame = plm_video_decode(self->video_decoder);
|
||||
if (frame) {
|
||||
self->video_decode_callback(self, frame, self->video_decode_callback_user_data);
|
||||
did_decode = true;
|
||||
}
|
||||
else {
|
||||
video_ended = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (decode_audio && plm_audio_get_time(self->audio_decoder) < audio_target_time) {
|
||||
plm_samples_t *samples = plm_audio_decode(self->audio_decoder);
|
||||
if (samples) {
|
||||
self->audio_decode_callback(self, samples, self->audio_decode_callback_user_data);
|
||||
did_decode = true;
|
||||
}
|
||||
else {
|
||||
audio_ended = true;
|
||||
}
|
||||
}
|
||||
} while (did_decode);
|
||||
|
||||
// We wanted to decode something but failed -> the source must have ended
|
||||
if ((!decode_video || video_ended) && (!decode_audio || audio_ended)) {
|
||||
plm_handle_end(self);
|
||||
}
|
||||
else {
|
||||
self->time += tick;
|
||||
}
|
||||
|
||||
return did_decode ? true : false;
|
||||
}
|
||||
|
||||
plm_frame_t *plm_decode_video(plm_t *self) {
|
||||
if (!self->video_packet_type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plm_frame_t *frame = plm_video_decode(self->video_decoder);
|
||||
if (frame) {
|
||||
self->time = frame->time;
|
||||
}
|
||||
else {
|
||||
plm_handle_end(self);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
plm_samples_t *plm_decode_audio(plm_t *self) {
|
||||
if (!self->audio_packet_type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plm_samples_t *samples = plm_audio_decode(self->audio_decoder);
|
||||
if (samples) {
|
||||
self->time = samples->time;
|
||||
}
|
||||
else {
|
||||
plm_handle_end(self);
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
void plm_handle_end(plm_t *self) {
|
||||
if (self->loop) {
|
||||
plm_rewind(self);
|
||||
}
|
||||
else {
|
||||
self->has_ended = true;
|
||||
}
|
||||
}
|
||||
|
||||
void plm_read_video_packet(plm_buffer_t *buffer, void *user) {
|
||||
plm_t *self = (plm_t *)user;
|
||||
plm_read_packets(self, self->video_packet_type);
|
||||
}
|
||||
|
||||
void plm_read_audio_packet(plm_buffer_t *buffer, void *user) {
|
||||
plm_t *self = (plm_t *)user;
|
||||
plm_read_packets(self, self->audio_packet_type);
|
||||
}
|
||||
|
||||
void plm_read_packets(plm_t *self, int requested_type) {
|
||||
plm_packet_t *packet;
|
||||
while ((packet = plm_demux_decode(self->demux))) {
|
||||
if (packet->type == self->video_packet_type) {
|
||||
plm_buffer_write(self->video_buffer, packet->data, packet->length);
|
||||
}
|
||||
else if (packet->type == self->audio_packet_type) {
|
||||
plm_buffer_write(self->audio_buffer, packet->data, packet->length);
|
||||
}
|
||||
if (packet->type == requested_type) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
88
dsp/mpeg/slowrgb.c
Normal file
88
dsp/mpeg/slowrgb.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
|
||||
│vi: set et ft=c ts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer │
|
||||
│ Dominic Szablewski - https://phoboslab.org │
|
||||
│ │
|
||||
│ The MIT License(MIT) │
|
||||
│ Copyright(c) 2019 Dominic Szablewski │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining │
|
||||
│ a copy of this software and associated documentation files(the │
|
||||
│ "Software"), to deal in the Software without restriction, including │
|
||||
│ without limitation the rights to use, copy, modify, merge, publish, │
|
||||
│ distribute, sublicense, and / or sell copies of the Software, and to │
|
||||
│ permit persons to whom the Software is furnished to do so, subject to │
|
||||
│ the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be │
|
||||
│ included in all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
||||
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
||||
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND │
|
||||
│ NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE │
|
||||
│ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN │
|
||||
│ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN │
|
||||
│ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE │
|
||||
│ SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
PL_MPEG (MIT License)\\n\
|
||||
Copyright(c) 2019 Dominic Szablewski\\n\
|
||||
https://phoboslab.org\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
/**
|
||||
* @see YCbCr2RGB() in tool/viz/lib/ycbcr2rgb.c
|
||||
*/
|
||||
void plm_frame_to_rgb(plm_frame_t *frame, uint8_t *rgb) {
|
||||
// Chroma values are the same for each block of 4 pixels, so we proccess
|
||||
// 2 lines at a time, 2 neighboring pixels each.
|
||||
int w = frame->y.width, w2 = w >> 1;
|
||||
int y_index1 = 0, y_index2 = w, y_next_2_lines = w + (w - frame->width);
|
||||
int c_index = 0, c_next_line = w2 - (frame->width >> 1);
|
||||
int rgb_index1 = 0, rgb_index2 = frame->width * 3,
|
||||
rgb_next_2_lines = frame->width * 3;
|
||||
int cols = frame->width >> 1, rows = frame->height >> 1;
|
||||
int ccb, ccr, r, g, b;
|
||||
uint8_t *y = frame->y.data, *cb = frame->cb.data, *cr = frame->cr.data;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
ccb = cb[c_index];
|
||||
ccr = cr[c_index];
|
||||
c_index++;
|
||||
r = (ccr + ((ccr * 103) >> 8)) - 179;
|
||||
g = ((ccb * 88) >> 8) - 44 + ((ccr * 183) >> 8) - 91;
|
||||
b = (ccb + ((ccb * 198) >> 8)) - 227;
|
||||
// Line 1
|
||||
int y1 = y[y_index1++];
|
||||
int y2 = y[y_index1++];
|
||||
rgb[rgb_index1 + 0] = MAX(0, MIN(255, y1 + r));
|
||||
rgb[rgb_index1 + 1] = MAX(0, MIN(255, y1 - g));
|
||||
rgb[rgb_index1 + 2] = MAX(0, MIN(255, y1 + b));
|
||||
rgb[rgb_index1 + 3] = MAX(0, MIN(255, y2 + r));
|
||||
rgb[rgb_index1 + 4] = MAX(0, MIN(255, y2 - g));
|
||||
rgb[rgb_index1 + 5] = MAX(0, MIN(255, y2 + b));
|
||||
rgb_index1 += 6;
|
||||
// Line 2
|
||||
int y3 = y[y_index2++];
|
||||
int y4 = y[y_index2++];
|
||||
rgb[rgb_index2 + 0] = MAX(0, MIN(255, y3 + r));
|
||||
rgb[rgb_index2 + 1] = MAX(0, MIN(255, y3 - g));
|
||||
rgb[rgb_index2 + 2] = MAX(0, MIN(255, y3 + b));
|
||||
rgb[rgb_index2 + 3] = MAX(0, MIN(255, y4 + r));
|
||||
rgb[rgb_index2 + 4] = MAX(0, MIN(255, y4 - g));
|
||||
rgb[rgb_index2 + 5] = MAX(0, MIN(255, y4 + b));
|
||||
rgb_index2 += 6;
|
||||
}
|
||||
y_index1 += y_next_2_lines;
|
||||
y_index2 += y_next_2_lines;
|
||||
rgb_index1 += rgb_next_2_lines;
|
||||
rgb_index2 += rgb_next_2_lines;
|
||||
c_index += c_next_line;
|
||||
}
|
||||
}
|
62
dsp/mpeg/video.h
Normal file
62
dsp/mpeg/video.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_VIDEO_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_VIDEO_H_
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef struct {
|
||||
int full_px;
|
||||
int is_set;
|
||||
int r_size;
|
||||
int h;
|
||||
int v;
|
||||
} plm_video_motion_t;
|
||||
|
||||
typedef struct plm_video_t {
|
||||
double framerate;
|
||||
double time;
|
||||
double pixel_aspect_ratio;
|
||||
int frames_decoded;
|
||||
int width;
|
||||
int height;
|
||||
int mb_width;
|
||||
int mb_height;
|
||||
int mb_size;
|
||||
int luma_width;
|
||||
int luma_height;
|
||||
int chroma_width;
|
||||
int chroma_height;
|
||||
int start_code;
|
||||
int picture_type;
|
||||
plm_video_motion_t motion_forward;
|
||||
plm_video_motion_t motion_backward;
|
||||
int has_sequence_header;
|
||||
int quantizer_scale;
|
||||
int slice_begin;
|
||||
int macroblock_address;
|
||||
int mb_row;
|
||||
int mb_col;
|
||||
int macroblock_type;
|
||||
int macroblock_intra;
|
||||
int dc_predictor[3];
|
||||
plm_buffer_t *buffer;
|
||||
int destroy_buffer_when_done;
|
||||
plm_frame_t frame_current;
|
||||
plm_frame_t frame_forward;
|
||||
plm_frame_t frame_backward;
|
||||
uint8_t *frames_data;
|
||||
int block_data[64];
|
||||
uint8_t intra_quant_matrix[64];
|
||||
uint8_t non_intra_quant_matrix[64];
|
||||
int has_reference_frame;
|
||||
int assume_no_b_frames;
|
||||
} plm_video_t;
|
||||
|
||||
void plm_video_process_macroblock_8(plm_video_t *, uint8_t *restrict,
|
||||
uint8_t *restrict, int, int, bool);
|
||||
void plm_video_process_macroblock_16(plm_video_t *, uint8_t *restrict,
|
||||
uint8_t *restrict, int, int, bool);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_VIDEO_H_ */
|
139
dsp/mpeg/ycbcrio.c
Normal file
139
dsp/mpeg/ycbcrio.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "dsp/mpeg/ycbcrio.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
static void CheckPlmFrame(const struct plm_frame_t *frame) {
|
||||
CHECK_NE(0, frame->width);
|
||||
CHECK_NE(0, frame->height);
|
||||
CHECK_GE(frame->y.width, frame->width);
|
||||
CHECK_GE(frame->y.height, frame->height);
|
||||
CHECK_EQ(frame->cr.width, frame->cb.width);
|
||||
CHECK_EQ(frame->cr.height, frame->cb.height);
|
||||
CHECK_EQ(frame->y.width, frame->cr.width * 2);
|
||||
CHECK_EQ(frame->y.height, frame->cr.height * 2);
|
||||
CHECK_NOTNULL(frame->y.data);
|
||||
CHECK_NOTNULL(frame->cr.data);
|
||||
CHECK_NOTNULL(frame->cb.data);
|
||||
}
|
||||
|
||||
static size_t GetHeaderBytes(const struct plm_frame_t *frame) {
|
||||
return MAX(sizeof(struct Ycbcrio), ROUNDUP(frame->y.width, 16));
|
||||
}
|
||||
|
||||
static size_t GetPlaneBytes(const struct plm_plane_t *plane) {
|
||||
/*
|
||||
* planes must be 16-byte aligned, but due to their hugeness, and the
|
||||
* recommendation of intel's 6,000 page manual, it makes sense to have
|
||||
* planes on isolated 64kb frames for multiprocessing.
|
||||
*/
|
||||
return ROUNDUP(ROUNDUP(plane->height, 16) * ROUNDUP(plane->width, 16),
|
||||
FRAMESIZE);
|
||||
}
|
||||
|
||||
static size_t CalcMapBytes(const struct plm_frame_t *frame) {
|
||||
return ROUNDUP(GetHeaderBytes(frame) + GetPlaneBytes(&frame->y) +
|
||||
GetPlaneBytes(&frame->cb) + GetPlaneBytes(&frame->cb),
|
||||
FRAMESIZE);
|
||||
}
|
||||
|
||||
static void FixupPointers(struct Ycbcrio *map) {
|
||||
map->frame.y.data = (unsigned char *)map + GetHeaderBytes(&map->frame);
|
||||
map->frame.cr.data = map->frame.y.data + GetPlaneBytes(&map->frame.y);
|
||||
map->frame.cb.data = map->frame.cr.data + GetPlaneBytes(&map->frame.cr);
|
||||
}
|
||||
|
||||
static struct Ycbcrio *YcbcrioOpenNew(const char *path,
|
||||
const struct plm_frame_t *frame) {
|
||||
int fd;
|
||||
size_t size;
|
||||
struct stat st;
|
||||
struct Ycbcrio *map;
|
||||
CheckPlmFrame(frame);
|
||||
size = CalcMapBytes(frame);
|
||||
CHECK_NE(-1, (fd = open(path, O_CREAT | O_RDWR, 0644)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
if (st.st_size < size) {
|
||||
CHECK_NE(-1, ftruncate(fd, size));
|
||||
}
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)));
|
||||
map->magic = YCBCRIO_MAGIC;
|
||||
map->fd = fd;
|
||||
map->size = size;
|
||||
memcpy(&map->frame, frame, sizeof(map->frame));
|
||||
FixupPointers(map);
|
||||
memcpy(&map->frame.y.data, frame->y.data, GetPlaneBytes(&frame->y));
|
||||
memcpy(&map->frame.cb.data, frame->cb.data, GetPlaneBytes(&frame->cb));
|
||||
memcpy(&map->frame.cr.data, frame->cr.data, GetPlaneBytes(&frame->cr));
|
||||
return map;
|
||||
}
|
||||
|
||||
static struct Ycbcrio *YcbcrioOpenExisting(const char *path) {
|
||||
int fd;
|
||||
struct stat st;
|
||||
struct Ycbcrio *map;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDWR)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
CHECK_NE(MAP_FAILED, (map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0)));
|
||||
CHECK_EQ(YCBCRIO_MAGIC, map->magic);
|
||||
CHECK_GE(st.st_size, CalcMapBytes(&map->frame));
|
||||
FixupPointers(map);
|
||||
map->fd = fd;
|
||||
map->size = st.st_size;
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens shareable persistable MPEG video frame memory.
|
||||
*
|
||||
* @param path is a file name
|
||||
* @param frame if NULL means open existing file, otherwise copies new
|
||||
* @param points to pointer returned by YcbcrioOpen() which is cleared
|
||||
* @return memory mapping needing YcbcrioClose()
|
||||
*/
|
||||
struct Ycbcrio *YcbcrioOpen(const char *path, const struct plm_frame_t *frame) {
|
||||
if (frame) {
|
||||
return YcbcrioOpenNew(path, frame);
|
||||
} else {
|
||||
return YcbcrioOpenExisting(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes mapped video frame file.
|
||||
*
|
||||
* @param points to pointer returned by YcbcrioOpen() which is cleared
|
||||
*/
|
||||
void YcbcrioClose(struct Ycbcrio **map) {
|
||||
CHECK_NE(-1, close_s(&(*map)->fd));
|
||||
CHECK_NE(-1, munmap_s(map, (*map)->size));
|
||||
}
|
27
dsp/mpeg/ycbcrio.h
Normal file
27
dsp/mpeg/ycbcrio.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_
|
||||
#define COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_
|
||||
#include "dsp/mpeg/mpeg.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define YCBCRIO_MAGIC bswap_32(0xBCCBCCBCu)
|
||||
|
||||
/**
|
||||
* Mappable persistable MPEG-2 video frame in Y-Cr-Cb colorspace.
|
||||
*/
|
||||
struct Ycbcrio {
|
||||
uint32_t magic;
|
||||
int32_t fd;
|
||||
uint64_t size;
|
||||
plm_frame_t frame;
|
||||
};
|
||||
|
||||
struct Ycbcrio *YcbcrioOpen(const char *, const struct plm_frame_t *)
|
||||
paramsnonnull((1)) vallocesque returnsnonnull;
|
||||
|
||||
void YcbcrioClose(struct Ycbcrio **) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_MPEG_YCBCRIO_H_ */
|
100
dsp/scale/cdecimate2xuint8x8.c
Normal file
100
dsp/scale/cdecimate2xuint8x8.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/scale/scale.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/intrin/packuswb.h"
|
||||
#include "libc/intrin/paddw.h"
|
||||
#include "libc/intrin/palignr.h"
|
||||
#include "libc/intrin/pmaddubsw.h"
|
||||
#include "libc/intrin/psraw.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define TAPS 8
|
||||
#define RATIO 2
|
||||
#define OFFSET 3
|
||||
#define STRIDE 8
|
||||
#define SPREAD (STRIDE * RATIO + TAPS - OFFSET)
|
||||
#define OVERLAP (SPREAD - STRIDE * RATIO)
|
||||
#define LOOKBEHIND OFFSET
|
||||
#define LOOKAHEAD (SPREAD - LOOKBEHIND)
|
||||
#define SCALE 5
|
||||
#define ROUND (1 << (SCALE - 1))
|
||||
|
||||
/**
|
||||
* Performs 2D Motion Picture Convolution Acceleration by Leveraging SSSE3.
|
||||
*
|
||||
* @note H/T John Costella, Jean-Baptiste Joseph Fourier
|
||||
* @note RIP Huixiang Chen
|
||||
*/
|
||||
void *cDecimate2xUint8x8(unsigned long n, unsigned char A[n],
|
||||
const signed char K[8]) {
|
||||
short kRound[8] = {ROUND, ROUND, ROUND, ROUND, ROUND, ROUND, ROUND, ROUND};
|
||||
signed char kMadd1[16] = {K[0], K[1], K[0], K[1], K[0], K[1], K[0], K[1],
|
||||
K[0], K[1], K[0], K[1], K[0], K[1], K[0], K[1]};
|
||||
signed char kMadd2[16] = {K[2], K[3], K[2], K[3], K[2], K[3], K[2], K[3],
|
||||
K[2], K[3], K[2], K[3], K[2], K[3], K[2], K[3]};
|
||||
signed char kMadd3[16] = {K[4], K[5], K[4], K[5], K[4], K[5], K[4], K[5],
|
||||
K[4], K[5], K[4], K[5], K[4], K[5], K[4], K[5]};
|
||||
signed char kMadd4[16] = {K[6], K[7], K[6], K[7], K[6], K[7], K[6], K[7],
|
||||
K[6], K[7], K[6], K[7], K[6], K[7], K[6], K[7]};
|
||||
unsigned char in1[16], in2[16], in3[16], in4[32];
|
||||
unsigned char bv0[16], bv1[16], bv2[16], bv3[16];
|
||||
short wv0[8], wv1[8], wv2[8], wv3[8];
|
||||
unsigned long i, j, v, w, o;
|
||||
if (n >= STRIDE) {
|
||||
i = 0;
|
||||
w = (n + RATIO / 2) / RATIO;
|
||||
memset(in1, A[0], sizeof(in1));
|
||||
memset(in2, A[n - 1], 16);
|
||||
memcpy(in2, A, MIN(16, n));
|
||||
for (; i < w; i += STRIDE) {
|
||||
j = i * RATIO + 16;
|
||||
if (j + 16 <= n) {
|
||||
memcpy(in3, &A[j], 16);
|
||||
} else {
|
||||
memset(in3, A[n - 1], 16);
|
||||
if (j < n) {
|
||||
memcpy(in3, &A[j], n - j);
|
||||
}
|
||||
}
|
||||
palignr(bv0, in2, in1, 13);
|
||||
palignr(bv1, in2, in1, 15);
|
||||
palignr(bv2, in3, in2, 1);
|
||||
palignr(bv3, in3, in2, 3);
|
||||
pmaddubsw(wv0, bv0, kMadd1);
|
||||
pmaddubsw(wv1, bv1, kMadd2);
|
||||
pmaddubsw(wv2, bv2, kMadd3);
|
||||
pmaddubsw(wv3, bv3, kMadd4);
|
||||
paddw(wv0, wv0, kRound);
|
||||
paddw(wv0, wv0, wv1);
|
||||
paddw(wv0, wv0, wv2);
|
||||
paddw(wv0, wv0, wv3);
|
||||
psraw(wv0, wv0, SCALE);
|
||||
packuswb(bv2, wv0, wv0);
|
||||
memcpy(&A[i], bv2, STRIDE);
|
||||
memcpy(in1, in2, 16);
|
||||
memcpy(in2, in3, 16);
|
||||
}
|
||||
}
|
||||
return A;
|
||||
}
|
285
dsp/scale/gyarados.c
Normal file
285
dsp/scale/gyarados.c
Normal file
|
@ -0,0 +1,285 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/c161.h"
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/core/ituround.h"
|
||||
#include "dsp/core/q.h"
|
||||
#include "dsp/core/twixt8.h"
|
||||
#include "dsp/scale/scale.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/dtoa/dtoa.h"
|
||||
#include "tool/viz/lib/knobs.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Gyarados resizes graphics.
|
||||
* @note H/T John Costella, Facebook, Photoshop, Carl Friedrich Gauss
|
||||
* @note Eric Brasseur has an interesting blog post on tip of iceberg
|
||||
* @see Magikarp
|
||||
*/
|
||||
|
||||
#define M 14
|
||||
#define SQR(X) ((X) * (X))
|
||||
|
||||
struct SamplingSolution {
|
||||
int n, s;
|
||||
void *weights;
|
||||
void *indices;
|
||||
};
|
||||
|
||||
static double ComputeWeight(double x) {
|
||||
if (-1.5 < x && x < 1.5) {
|
||||
if (-.5 < x && x < .5) {
|
||||
return .75 - SQR(x);
|
||||
} else if (x < 0) {
|
||||
return .5 * SQR(x + 1.5);
|
||||
} else {
|
||||
return .5 * SQR(x - 1.5);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct SamplingSolution *NewSamplingSolution(long n, long s) {
|
||||
struct SamplingSolution *ss;
|
||||
ss = xcalloc(1, sizeof(struct SamplingSolution));
|
||||
ss->n = n;
|
||||
ss->s = s;
|
||||
ss->weights = xcalloc(n * s, sizeof(short));
|
||||
ss->indices = xcalloc(n * s, sizeof(short));
|
||||
return ss;
|
||||
}
|
||||
|
||||
static bool IsNormalized(int n, double A[n]) {
|
||||
int i;
|
||||
double x;
|
||||
for (x = i = 0; i < n; ++i) x += A[i];
|
||||
return fabs(x - 1) < 1e-4;
|
||||
}
|
||||
|
||||
void FreeSamplingSolution(struct SamplingSolution *ss) {
|
||||
long i;
|
||||
if (ss) {
|
||||
free(ss->indices);
|
||||
free(ss->weights);
|
||||
free(ss);
|
||||
}
|
||||
}
|
||||
|
||||
struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
|
||||
double off, double par) {
|
||||
double *fweights;
|
||||
double sum, hw, w, x, f;
|
||||
short *weights, *indices;
|
||||
struct SamplingSolution *res;
|
||||
long j, i, k, n, min, max, s, N[6];
|
||||
if (!dar) dar = sn, dar /= dn;
|
||||
if (!off) off = (dar - 1) / 2;
|
||||
f = dar < 1 ? 1 / dar : dar;
|
||||
s = 3 * f + 1;
|
||||
fweights = gc(xcalloc(s, sizeof(double)));
|
||||
res = NewSamplingSolution(dn, s);
|
||||
weights = res->weights;
|
||||
indices = res->indices;
|
||||
for (i = 0; i < dn; ++i) {
|
||||
x = off + i * dar;
|
||||
hw = 1.5 * f;
|
||||
min = ceil(x - hw);
|
||||
max = floor(x + hw);
|
||||
n = max - min + 1;
|
||||
CHECK_LE(n, s);
|
||||
for (k = 0, j = min; j <= max; ++j) {
|
||||
fweights[k++] = ComputeWeight((j - x) / (f / par));
|
||||
}
|
||||
for (sum = k = 0; k < n; ++k) sum += fweights[k];
|
||||
for (j = 0; j < n; ++j) fweights[j] *= 1 / sum;
|
||||
DCHECK(IsNormalized(n, fweights));
|
||||
for (j = 0; j < n; ++j) {
|
||||
indices[i * s + j] = MIN(sn - 1, MAX(0, min + j));
|
||||
}
|
||||
for (j = 0; j < n; j += 6) {
|
||||
GetIntegerCoefficients(N, fweights + j, M, 0, 255);
|
||||
for (k = 0; k < MIN(6, n - j); ++k) {
|
||||
weights[i * s + j + k] = N[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *ZeroMatrix(long yw, long xw, int p[yw][xw], long yn, long xn) {
|
||||
long y;
|
||||
for (y = 0; y < yn; ++y) {
|
||||
memset(p[y], 0, xn);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static int Sharpen(int ax, int bx, int cx) {
|
||||
return (-1 * ax + 6 * bx + -1 * cx + 2) / 4;
|
||||
}
|
||||
|
||||
static void GyaradosImpl(long dyw, long dxw, int dst[dyw][dxw], long syw,
|
||||
long sxw, const int src[syw][sxw], long dyn, long dxn,
|
||||
long syn, long sxn, int tmp0[restrict dyn][sxn],
|
||||
int tmp1[restrict dyn][sxn],
|
||||
int tmp2[restrict dyn][dxn], long yfn, long xfn,
|
||||
const short fyi[dyn][yfn], const short fyw[dyn][yfn],
|
||||
const short fxi[dxn][xfn], const short fxw[dxn][xfn],
|
||||
bool sharpen) {
|
||||
long i, j;
|
||||
int eax, dy, dx, sy, sx;
|
||||
for (sx = 0; sx < sxn; ++sx) {
|
||||
for (dy = 0; dy < dyn; ++dy) {
|
||||
for (eax = i = 0; i < yfn; ++i) {
|
||||
eax += fyw[dy][i] * src[fyi[dy][i]][sx];
|
||||
}
|
||||
tmp0[dy][sx] = QRS(M, eax);
|
||||
}
|
||||
}
|
||||
for (dy = 0; dy < dyn; ++dy) {
|
||||
/* TODO: pmulhrsw() would probably make this much faster */
|
||||
for (sx = 0; sx < sxn; ++sx) {
|
||||
tmp1[dy][sx] = sharpen ? Sharpen(tmp0[MIN(dyn - 1, MAX(0, dy - 1))][sx],
|
||||
tmp0[dy][sx],
|
||||
tmp0[MIN(dyn - 1, MAX(0, dy + 1))][sx])
|
||||
: tmp0[dy][sx];
|
||||
}
|
||||
}
|
||||
for (dx = 0; dx < dxn; ++dx) {
|
||||
for (dy = 0; dy < dyn; ++dy) {
|
||||
for (eax = i = 0; i < xfn; ++i) {
|
||||
eax += fxw[dx][i] * tmp1[dy][fxi[dx][i]];
|
||||
}
|
||||
tmp2[dy][dx] = QRS(M, eax);
|
||||
}
|
||||
}
|
||||
for (dx = 0; dx < dxn; ++dx) {
|
||||
for (dy = 0; dy < dyn; ++dy) {
|
||||
dst[dy][dx] = sharpen ? Sharpen(tmp2[dy][MIN(dxn - 1, MAX(0, dx - 1))],
|
||||
tmp2[dy][dx],
|
||||
tmp2[dy][MIN(dxn - 1, MAX(0, dx + 1))])
|
||||
: tmp2[dy][dx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales image.
|
||||
*
|
||||
* @note gyarados is magikarp in its infinite form
|
||||
* @see Magikarp2xY(), Magikarp2xX()
|
||||
*/
|
||||
void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw,
|
||||
const int src[syw][sxw], long dyn, long dxn, long syn, long sxn,
|
||||
struct SamplingSolution *cy, struct SamplingSolution *cx,
|
||||
bool sharpen) {
|
||||
if (dyn > 0 && dxn > 0) {
|
||||
if (syn > 0 && sxn > 0) {
|
||||
CHECK_LE(syn, syw);
|
||||
CHECK_LE(sxn, sxw);
|
||||
CHECK_LE(dyn, dyw);
|
||||
CHECK_LE(dxn, dxw);
|
||||
CHECK_LT(bsrl(syn) + bsrl(sxn), 32);
|
||||
CHECK_LT(bsrl(dyn) + bsrl(dxn), 32);
|
||||
CHECK_LE(dyw, 0x7fff);
|
||||
CHECK_LE(dxw, 0x7fff);
|
||||
CHECK_LE(syw, 0x7fff);
|
||||
CHECK_LE(sxw, 0x7fff);
|
||||
CHECK_LE(dyn, 0x7fff);
|
||||
CHECK_LE(dxn, 0x7fff);
|
||||
CHECK_LE(syn, 0x7fff);
|
||||
CHECK_LE(sxn, 0x7fff);
|
||||
GyaradosImpl(dyw, dxw, dst, syw, sxw, src, dyn, dxn, syn, sxn,
|
||||
gc(xmemalign(64, sizeof(int) * dyn * sxn)),
|
||||
gc(xmemalign(64, sizeof(int) * dyn * sxn)),
|
||||
gc(xmemalign(64, sizeof(int) * dyn * dxn)), cy->s, cx->s,
|
||||
cy->indices, cy->weights, cx->indices, cx->weights, sharpen);
|
||||
} else {
|
||||
ZeroMatrix(dyw, dxw, dst, dyn, dxn);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *GyaradosUint8(long dyw, long dxw, unsigned char dst[dyw][dxw], long syw,
|
||||
long sxw, const unsigned char src[syw][sxw], long dyn,
|
||||
long dxn, long syn, long sxn, long lo, long hi,
|
||||
struct SamplingSolution *cy, struct SamplingSolution *cx,
|
||||
bool sharpen) {
|
||||
static bool once;
|
||||
static int Tin[256];
|
||||
static unsigned char Tout[32768];
|
||||
long i, y, x;
|
||||
int(*tmp)[MAX(dyn, syn)][MAX(dxn, sxn)];
|
||||
if (!once) {
|
||||
for (i = 0; i < ARRAYLEN(Tin); ++i) {
|
||||
Tin[i] = F2Q(15, rgb2linpc(i / 255., 2.4));
|
||||
}
|
||||
for (i = 0; i < ARRAYLEN(Tout); ++i) {
|
||||
Tout[i] = MIN(255, MAX(0, round(rgb2stdpc(Q2F(15, i), 2.4) * 255.)));
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
tmp = xmemalign(64, sizeof(int) * MAX(dyn, syn) * MAX(dxn, sxn));
|
||||
for (y = 0; y < syn; ++y) {
|
||||
for (x = 0; x < sxn; ++x) {
|
||||
(*tmp)[y][x] = Tin[src[y][x]];
|
||||
}
|
||||
}
|
||||
Gyarados(MAX(dyn, syn), MAX(dxn, sxn), *tmp, MAX(dyn, syn), MAX(dxn, sxn),
|
||||
*tmp, dyn, dxn, syn, sxn, cy, cx, sharpen);
|
||||
for (y = 0; y < dyn; ++y) {
|
||||
for (x = 0; x < dxn; ++x) {
|
||||
dst[y][x] = Tout[MIN(32767, MAX(0, (*tmp)[y][x]))];
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *EzGyarados(long dcw, long dyw, long dxw, unsigned char dst[dcw][dyw][dxw],
|
||||
long scw, long syw, long sxw,
|
||||
const unsigned char src[scw][syw][sxw], long c0, long cn,
|
||||
long dyn, long dxn, long syn, long sxn, double ry, double rx,
|
||||
double oy, double ox) {
|
||||
long c;
|
||||
struct SamplingSolution *cy, *cx;
|
||||
cy = ComputeSamplingSolution(dyn, syn, ry, oy, 1);
|
||||
cx = ComputeSamplingSolution(dxn, sxn, rx, ox, 1);
|
||||
for (c = c0; c < cn; ++c) {
|
||||
GyaradosUint8(dyw, dxw, dst[c], syw, sxw, src[c], dyn, dxn, syn, sxn, 0,
|
||||
255, cy, cx, true);
|
||||
}
|
||||
FreeSamplingSolution(cx);
|
||||
FreeSamplingSolution(cy);
|
||||
return dst;
|
||||
}
|
129
dsp/scale/magikarp.c
Normal file
129
dsp/scale/magikarp.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/half.h"
|
||||
#include "dsp/core/ks8.h"
|
||||
#include "dsp/core/kss8.h"
|
||||
#include "dsp/scale/scale.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Magikarp resizes graphics in half very fast.
|
||||
* @note H/T John Costella, Facebook, and Photoshop
|
||||
* @note sharpening is good for luma but not chroma
|
||||
* @see Gyarados
|
||||
*/
|
||||
|
||||
#define CLAMP(X) MIN(255, MAX(0, X))
|
||||
#define MAGIKARP(...) \
|
||||
CLAMP(KS8(5, K[0], K[1], K[2], K[3], K[4], K[5], K[6], K[7], __VA_ARGS__))
|
||||
|
||||
signed char g_magikarp[8];
|
||||
const signed char kMagikarp[8][8] = {
|
||||
{-1, -3, 3, 17, 17, 3, -3, -1}, /* 1331+161 derived w/ one off cas */
|
||||
{-1, -3, 6, 28, 6, -3, -1, 0}, /* due to the convolution theorem? */
|
||||
{0, 0, -11, 53, -11, 0, 0, 0}, /* plus, some random experimenting */
|
||||
{-2, -6, 2, 22, 22, 2, -6, -2}, /* one a line please clang-format? */
|
||||
{-3, -9, 1, 27, 27, 1, -9, -3},
|
||||
};
|
||||
|
||||
signed char g_magkern[8];
|
||||
const signed char kMagkern[8][8] = {
|
||||
{1, 2, 3, 10, 10, 3, 2, 1},
|
||||
{0, 4, 4, 16, 4, 4, 0, 0},
|
||||
{0, 1, 2, 6, 14, 6, 2, 1},
|
||||
{0, 1, 2, 13, 13, 2, 1, 0},
|
||||
};
|
||||
|
||||
void *Magikarp2xX(long ys, long xs, unsigned char p[ys][xs], long yn, long xn) {
|
||||
long y;
|
||||
if (yn && xn > 1) {
|
||||
for (y = 0; y < yn; ++y) {
|
||||
/* gcc/clang both struggle with left-to-right matrix ops */
|
||||
cDecimate2xUint8x8(xn, p[y], g_magikarp);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Magikarp2xY(long ys, long xs, unsigned char p[ys][xs], long yn, long xn) {
|
||||
long y, x, h;
|
||||
signed char K[8];
|
||||
memcpy(K, g_magikarp, sizeof(K));
|
||||
for (h = HALF(yn), y = 0; y < h; ++y) {
|
||||
for (x = 0; x < xn; ++x) {
|
||||
p[y][x] = /* gcc/clang are good at optimizing top-to-bottom matrix ops */
|
||||
MAGIKARP(p[MAX(00 + 0, y * 2 - 3)][x], p[MAX(00 + 0, y * 2 - 2)][x],
|
||||
p[MAX(00 + 0, y * 2 - 1)][x], p[MIN(yn - 1, y * 2 + 0)][x],
|
||||
p[MIN(yn - 1, y * 2 + 1)][x], p[MIN(yn - 1, y * 2 + 2)][x],
|
||||
p[MIN(yn - 1, y * 2 + 3)][x], p[MIN(yn - 1, y * 2 + 4)][x]);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Magkern2xX(long ys, long xs, unsigned char p[ys][xs], long yn, long xn) {
|
||||
long y;
|
||||
if (yn && xn > 1) {
|
||||
for (y = 0; y < yn; ++y) {
|
||||
cDecimate2xUint8x8(xn, p[y], g_magkern);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Magkern2xY(long ys, long xs, unsigned char p[ys][xs], long yn, long xn) {
|
||||
long y, x, h;
|
||||
signed char K[8];
|
||||
memcpy(K, g_magkern, sizeof(K));
|
||||
for (h = HALF(yn), y = 0; y < h; ++y) {
|
||||
for (x = 0; x < xn; ++x) {
|
||||
p[y][x] =
|
||||
MAGIKARP(p[MAX(00 + 0, y * 2 - 3)][x], p[MAX(00 + 0, y * 2 - 2)][x],
|
||||
p[MAX(00 + 0, y * 2 - 1)][x], p[MIN(yn - 1, y * 2 + 0)][x],
|
||||
p[MIN(yn - 1, y * 2 + 1)][x], p[MIN(yn - 1, y * 2 + 2)][x],
|
||||
p[MIN(yn - 1, y * 2 + 3)][x], p[MIN(yn - 1, y * 2 + 4)][x]);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *MagikarpY(long dys, long dxs, unsigned char d[restrict dys][dxs],
|
||||
long sys, long sxs, const unsigned char s[sys][sxs], long yn,
|
||||
long xn, const signed char K[8]) {
|
||||
long y, x;
|
||||
for (y = 0; y < yn; ++y) {
|
||||
for (x = 0; x < xn; ++x) {
|
||||
d[y][x] = MAGIKARP(s[MAX(00 + 0, y - 3)][x], s[MAX(00 + 0, y - 2)][x],
|
||||
s[MAX(00 + 0, y - 1)][x], s[MIN(yn - 1, y + 0)][x],
|
||||
s[MIN(yn - 1, y + 1)][x], s[MIN(yn - 1, y + 2)][x],
|
||||
s[MIN(yn - 1, y + 3)][x], s[MIN(yn - 1, y + 4)][x]);
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
static textstartup void g_magikarp_init() {
|
||||
memcpy(g_magkern, kMagkern[0], sizeof(g_magkern));
|
||||
memcpy(g_magikarp, kMagikarp[0], sizeof(g_magikarp));
|
||||
}
|
||||
const void *const g_magikarp_ctor[] initarray = {g_magikarp_init};
|
41
dsp/scale/scale.c
Normal file
41
dsp/scale/scale.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/half.h"
|
||||
#include "dsp/scale/scale.h"
|
||||
|
||||
void *Scale2xX(long ys, long xs, unsigned char p[ys][xs], long yn, long xn) {
|
||||
long y, x, w;
|
||||
for (w = HALF(xn), y = 0; y < yn; ++y) {
|
||||
for (x = 0; x < w; ++x) {
|
||||
p[y][x] = p[y][x * 2];
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Scale2xY(long ys, long xs, unsigned char p[ys][xs], long yn, long xn) {
|
||||
long y, x, h;
|
||||
for (h = HALF(yn), y = 0; y < h; ++y) {
|
||||
for (x = 0; x < xn; ++x) {
|
||||
p[y][x] = p[y * 2][x];
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
49
dsp/scale/scale.h
Normal file
49
dsp/scale/scale.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef COSMOPOLITAN_DSP_SCALE_SCALE_H_
|
||||
#define COSMOPOLITAN_DSP_SCALE_SCALE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern long gyarados_latency_;
|
||||
|
||||
extern signed char g_magikarp[8];
|
||||
extern signed char g_magkern[8];
|
||||
extern const signed char kMagikarp[8][8];
|
||||
extern const signed char kMagkern[8][8];
|
||||
|
||||
struct SamplingSolution;
|
||||
void FreeSamplingSolution(struct SamplingSolution *);
|
||||
struct SamplingSolution *ComputeSamplingSolution(long, long, double, double,
|
||||
double);
|
||||
|
||||
void *Scale2xX(long ys, long xs, unsigned char[ys][xs], long, long);
|
||||
void *Scale2xY(long ys, long xs, unsigned char[ys][xs], long, long);
|
||||
void *Magikarp2xX(long ys, long xs, unsigned char[ys][xs], long, long);
|
||||
void *Magikarp2xY(long ys, long xs, unsigned char[ys][xs], long, long);
|
||||
void *Magkern2xX(long ys, long xs, unsigned char[ys][xs], long, long);
|
||||
void *Magkern2xY(long ys, long xs, unsigned char[ys][xs], long, long);
|
||||
void *MagikarpY(long dys, long dxs, unsigned char d[restrict dys][dxs],
|
||||
long sys, long sxs, const unsigned char s[sys][sxs], long yn,
|
||||
long xn, const signed char K[8]);
|
||||
|
||||
void *GyaradosUint8(long dyw, long dxw, unsigned char dst[dyw][dxw], long syw,
|
||||
long sxw, const unsigned char src[syw][sxw], long dyn,
|
||||
long dxn, long syn, long sxn, long lo, long hi,
|
||||
struct SamplingSolution *cy, struct SamplingSolution *cx,
|
||||
bool sharpen);
|
||||
void *EzGyarados(long dcw, long dyw, long dxw, unsigned char dst[dcw][dyw][dxw],
|
||||
long scw, long syw, long sxw,
|
||||
const unsigned char src[scw][syw][sxw], long c0, long cn,
|
||||
long dyn, long dxn, long syn, long sxn, double ry, double rx,
|
||||
double oy, double ox);
|
||||
|
||||
void Decimate2xUint8x8(unsigned long n, unsigned char[n * 2],
|
||||
const signed char[static 8]);
|
||||
void *cDecimate2xUint8x8(unsigned long n, unsigned char[n * 2],
|
||||
const signed char[8]);
|
||||
|
||||
void *transpose(long yn, long xn, const unsigned char[yn][xn]);
|
||||
extern void (*const transpose88b)(unsigned char[8][8]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_SCALE_SCALE_H_ */
|
58
dsp/scale/scale.mk
Normal file
58
dsp/scale/scale.mk
Normal file
|
@ -0,0 +1,58 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += DSP_SCALE
|
||||
|
||||
DSP_SCALE_ARTIFACTS += DSP_SCALE_A
|
||||
DSP_SCALE = $(DSP_SCALE_A_DEPS) $(DSP_SCALE_A)
|
||||
DSP_SCALE_A = o/$(MODE)/dsp/scale/scale.a
|
||||
DSP_SCALE_A_FILES := $(wildcard dsp/scale/*)
|
||||
DSP_SCALE_A_HDRS = $(filter %.h,$(DSP_SCALE_A_FILES))
|
||||
DSP_SCALE_A_SRCS_S = $(filter %.S,$(DSP_SCALE_A_FILES))
|
||||
DSP_SCALE_A_SRCS_C = $(filter %.c,$(DSP_SCALE_A_FILES))
|
||||
|
||||
DSP_SCALE_A_SRCS = \
|
||||
$(DSP_SCALE_A_SRCS_S) \
|
||||
$(DSP_SCALE_A_SRCS_C)
|
||||
|
||||
DSP_SCALE_A_OBJS = \
|
||||
$(DSP_SCALE_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(DSP_SCALE_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(DSP_SCALE_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
DSP_SCALE_A_CHECKS = \
|
||||
$(DSP_SCALE_A).pkg \
|
||||
$(DSP_SCALE_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
DSP_SCALE_A_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
LIBC_INTRIN \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_TIME \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_LOG \
|
||||
LIBC_MEM \
|
||||
LIBC_X \
|
||||
LIBC_STUBS
|
||||
|
||||
DSP_SCALE_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(DSP_SCALE_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(DSP_SCALE_A): dsp/scale/ \
|
||||
$(DSP_SCALE_A).pkg \
|
||||
$(DSP_SCALE_A_OBJS)
|
||||
|
||||
$(DSP_SCALE_A).pkg: \
|
||||
$(DSP_SCALE_A_OBJS) \
|
||||
$(foreach x,$(DSP_SCALE_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
DSP_SCALE_LIBS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)))
|
||||
DSP_SCALE_SRCS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)_SRCS))
|
||||
DSP_SCALE_HDRS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)_HDRS))
|
||||
DSP_SCALE_CHECKS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)_CHECKS))
|
||||
DSP_SCALE_OBJS = $(foreach x,$(DSP_SCALE_ARTIFACTS),$($(x)_OBJS))
|
||||
$(DSP_SCALE_OBJS): $(BUILD_FILES) dsp/scale/scale.mk
|
||||
|
||||
.PHONY: o/$(MODE)/dsp/scale
|
||||
o/$(MODE)/dsp/scale: $(DSP_SCALE_CHECKS)
|
33
dsp/tty/altbuf.c
Normal file
33
dsp/tty/altbuf.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to flip to alternate display page.
|
||||
*
|
||||
* The alternate buffer trick lets one restore the console exactly as it
|
||||
* was, once the program is done running.
|
||||
*/
|
||||
int ttyenablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049h"); }
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to restore blinking box thing.
|
||||
*/
|
||||
int ttydisablealtbuf(int ttyfd) { return ttysend(ttyfd, "\e[?1049l"); }
|
46
dsp/tty/config.c
Normal file
46
dsp/tty/config.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* Applies configuration to teletypewriter.
|
||||
*
|
||||
* @param opt_out_oldconf is only modified if successful
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see ttyconfig(), ttyrestore()
|
||||
*/
|
||||
int ttyconfig(int ttyfd, ttyconf_f fn, int64_t arg,
|
||||
const struct termios *opt_out_oldconf) {
|
||||
struct termios conf[2];
|
||||
if (tcgetattr(ttyfd, &conf[0]) != -1 &&
|
||||
fn(memcpy(&conf[1], &conf[0], sizeof(conf[0])), arg) != -1 &&
|
||||
tcsetattr(ttyfd, TCSAFLUSH, &conf[1]) != -1) {
|
||||
if (opt_out_oldconf) {
|
||||
memcpy(opt_out_oldconf, &conf[0], sizeof(conf[0]));
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
77
dsp/tty/describe.c
Normal file
77
dsp/tty/describe.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
#define BUFFY 48
|
||||
|
||||
static char *ttydescriber(char *b, const struct TtyIdent *ti) {
|
||||
switch (ti->id) {
|
||||
case 0:
|
||||
snprintf(b, BUFFY, "%s %d", "putty", ti->version);
|
||||
break;
|
||||
case 1:
|
||||
if (ti->version > 1000) {
|
||||
snprintf(b, BUFFY, "%s %d", "gnome terminal", ti->version);
|
||||
} else {
|
||||
snprintf(b, BUFFY, "%s %d", "mlterm", ti->version);
|
||||
}
|
||||
break;
|
||||
case kTtyIdScreen:
|
||||
snprintf(b, BUFFY, "%s %d", "gnu screen", ti->version);
|
||||
break;
|
||||
case 77:
|
||||
snprintf(b, BUFFY, "%s %d", "redhat mintty", ti->version);
|
||||
break;
|
||||
case 41:
|
||||
snprintf(b, BUFFY, "%s %d", "xterm", ti->version);
|
||||
break;
|
||||
case 82:
|
||||
snprintf(b, BUFFY, "%s %d", "rxvt", ti->version);
|
||||
break;
|
||||
default:
|
||||
snprintf(b, BUFFY, "%s %d %d", "unknown teletypewriter no.", ti->id,
|
||||
ti->version);
|
||||
break;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes educated guess about name of teletypewriter.
|
||||
*/
|
||||
char *ttydescribe(char *out, size_t size, const struct TtyIdent *ti) {
|
||||
char b1[BUFFY], b2[BUFFY];
|
||||
if (ti) {
|
||||
ttydescriber(b1, ti);
|
||||
if (ti->next) {
|
||||
snprintf(out, size, "%s%s%s", ttydescriber(b2, ti->next), " inside ", b1);
|
||||
} else {
|
||||
snprintf(out, size, "%s", b1);
|
||||
}
|
||||
} else {
|
||||
snprintf(out, size, "%s", "no tty");
|
||||
}
|
||||
return out;
|
||||
}
|
53
dsp/tty/hidecursor.c
Normal file
53
dsp/tty/hidecursor.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/consolecursorinfo.h"
|
||||
|
||||
static int ttysetcursor(int fd, bool visible) {
|
||||
struct NtConsoleCursorInfo ntcursor;
|
||||
char code[8] = "\e[?25l";
|
||||
if (isterminalinarticulate()) return 0;
|
||||
if (visible) code[5] = 'h';
|
||||
if (SupportsWindows()) {
|
||||
GetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
ntcursor.bVisible = visible;
|
||||
SetConsoleCursorInfo(GetStdHandle(kNtStdOutputHandle), &ntcursor);
|
||||
}
|
||||
return ttysend(fd, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to hide blinking box.
|
||||
*/
|
||||
int ttyhidecursor(int fd) {
|
||||
return ttysetcursor(fd, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to restore blinking box.
|
||||
*/
|
||||
int ttyshowcursor(int fd) {
|
||||
return ttysetcursor(fd, true);
|
||||
}
|
95
dsp/tty/ident.c
Normal file
95
dsp/tty/ident.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/poll.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static int ttyident_probe(struct TtyIdent *ti, int ttyinfd, int ttyoutfd,
|
||||
const char *msg) {
|
||||
ssize_t rc;
|
||||
size_t got;
|
||||
char buf[64];
|
||||
int id, version;
|
||||
if ((rc = write(ttyoutfd, msg, strlen(msg))) != -1) {
|
||||
TryAgain:
|
||||
if ((rc = read(ttyinfd, buf, sizeof(buf))) != -1) {
|
||||
buf[min((got = (size_t)rc), sizeof(buf) - 1)] = '\0';
|
||||
if (sscanf(buf, "\e[>%d;%d", &id, &version) >= 1) {
|
||||
ti->id = id;
|
||||
ti->version = version;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = eio();
|
||||
}
|
||||
} else if (errno == EINTR) {
|
||||
goto TryAgain;
|
||||
} else if (errno == EAGAIN) {
|
||||
if (poll((struct pollfd[]){{ttyinfd, POLLIN}}, 1, 100) != 0) {
|
||||
goto TryAgain;
|
||||
} else {
|
||||
rc = etimedout();
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies teletypewriter.
|
||||
*
|
||||
* For example, we can tell if process is running in a GNU Screen
|
||||
* session Gnome Terminal.
|
||||
*
|
||||
* @return object if TTY responds, or NULL w/ errno
|
||||
* @see ttyidentclear()
|
||||
*/
|
||||
int ttyident(struct TtyIdent *ti, int ttyinfd, int ttyoutfd) {
|
||||
int rc;
|
||||
struct termios old;
|
||||
struct TtyIdent outer;
|
||||
rc = -1;
|
||||
if (!IsWindows()) {
|
||||
if (ttyconfig(ttyinfd, ttysetrawdeadline, 3, &old) != -1) {
|
||||
if (ttyident_probe(ti, ttyinfd, ttyoutfd, "\e[>c") != -1) {
|
||||
rc = 0;
|
||||
memset(&outer, 0, sizeof(outer));
|
||||
if (ti->id == 83 /* GNU Screen */ && (ti->next || weaken(malloc)) &&
|
||||
ttyident_probe(&outer, ttyinfd, ttyoutfd, "\eP\e[>c\e\\") != -1 &&
|
||||
(ti->next = (ti->next ? ti->next
|
||||
: weaken(malloc)(sizeof(struct TtyIdent))))) {
|
||||
memcpy(ti->next, &outer, sizeof(outer));
|
||||
} else {
|
||||
free_s(&ti->next);
|
||||
}
|
||||
}
|
||||
ttyrestore(ttyinfd, &old);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
43
dsp/tty/identclear.c
Normal file
43
dsp/tty/identclear.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static void ttyidentfree(struct TtyIdent *ti) {
|
||||
if (ti) {
|
||||
assert(ti != ti->next);
|
||||
ttyidentfree(ti->next);
|
||||
free_s(&ti);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys TtyIdent object.
|
||||
*
|
||||
* @see ttyident()
|
||||
*/
|
||||
void ttyidentclear(struct TtyIdent *ti) {
|
||||
assert(ti != ti->next);
|
||||
ttyidentfree(ti->next);
|
||||
memset(ti, 0, sizeof(*ti));
|
||||
}
|
33
dsp/tty/internal.h
Normal file
33
dsp/tty/internal.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef COSMOPOLITAN_DSP_TTY_INTERNAL_H_
|
||||
#define COSMOPOLITAN_DSP_TTY_INTERNAL_H_
|
||||
#include "dsp/tty/ttyrgb.h"
|
||||
#include "libc/bits/xmmintrin.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct TtyRgb rgb2tty24f_(__m128);
|
||||
struct TtyRgb rgb2ttyf2i_(__m128);
|
||||
struct TtyRgb rgb2ttyi2f_(int, int, int);
|
||||
struct TtyRgb rgb2ansi_(int, int, int);
|
||||
struct TtyRgb rgb2ansihash_(int, int, int);
|
||||
struct TtyRgb rgb2xterm24_(int, int, int);
|
||||
struct TtyRgb rgb2xterm256gray_(__m128);
|
||||
struct TtyRgb tty2rgb_(struct TtyRgb);
|
||||
struct TtyRgb tty2rgb24_(struct TtyRgb);
|
||||
__m128 tty2rgbf_(struct TtyRgb);
|
||||
__m128 tty2rgbf24_(struct TtyRgb);
|
||||
|
||||
char *setbg16_(char *, struct TtyRgb);
|
||||
char *setfg16_(char *, struct TtyRgb);
|
||||
char *setbgfg16_(char *, struct TtyRgb, struct TtyRgb);
|
||||
char *setbg256_(char *, struct TtyRgb);
|
||||
char *setfg256_(char *, struct TtyRgb);
|
||||
char *setbgfg256_(char *, struct TtyRgb, struct TtyRgb);
|
||||
char *setbg24_(char *, struct TtyRgb);
|
||||
char *setfg24_(char *, struct TtyRgb);
|
||||
char *setbgfg24_(char *, struct TtyRgb, struct TtyRgb);
|
||||
struct TtyRgb rgb2ansi8_(int, int, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_TTY_INTERNAL_H_ */
|
51
dsp/tty/itoa8.c
Normal file
51
dsp/tty/itoa8.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
struct Itoa8 kItoa8;
|
||||
|
||||
static nooptimize textstartup void itoa8init(void) {
|
||||
size_t i;
|
||||
uint8_t z;
|
||||
char p[4];
|
||||
/*102*/
|
||||
for (i = 0; i < 256; ++i) {
|
||||
memset(p, 0, sizeof(p));
|
||||
if (i < 10) {
|
||||
z = 1;
|
||||
p[0] = '0' + i;
|
||||
} else if (i < 100) {
|
||||
z = 2;
|
||||
p[0] = '0' + i / 10;
|
||||
p[1] = '0' + i % 10;
|
||||
} else {
|
||||
z = 3;
|
||||
p[0] = '0' + i / 100;
|
||||
p[1] = '0' + i % 100 / 10;
|
||||
p[2] = '0' + i % 100 % 10;
|
||||
}
|
||||
kItoa8.size[i] = z;
|
||||
memcpy(&kItoa8.data[i], p, sizeof(p));
|
||||
}
|
||||
}
|
||||
|
||||
INITIALIZER(301, _init_itoa8, itoa8init());
|
21
dsp/tty/itoa8.h
Normal file
21
dsp/tty/itoa8.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_DSP_TTY_ITOA8_H_
|
||||
#define COSMOPOLITAN_DSP_TTY_ITOA8_H_
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Itoa8 {
|
||||
uint8_t size[256];
|
||||
uint32_t data[256];
|
||||
};
|
||||
|
||||
extern struct Itoa8 kItoa8;
|
||||
|
||||
forceinline char *itoa8(char *p, uint8_t c) {
|
||||
memcpy(p, &kItoa8.data[c], 4);
|
||||
return p + kItoa8.size[c];
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_TTY_ITOA8_H_ */
|
29
dsp/tty/kcgapalette.c
Normal file
29
dsp/tty/kcgapalette.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "dsp/tty/quant.h"
|
||||
|
||||
const ttypalette_t kCgaPalette = {
|
||||
[0][0] = {0, 0, 0, 0}, /* normal black: \e[30m (or \e[38;5;0m) */
|
||||
[1][0] = {85, 85, 85, 8}, /* bright black: \e[90m (or \e[38;5;8m) */
|
||||
[0][1] = {170, 0, 0, 1}, /* normal red: \e[31m */
|
||||
[1][1] = {255, 85, 85, 9}, /* bright red: \e[91m (or \e[1;31m) */
|
||||
[0][2] = {0, 170, 0, 2}, /* normal green: \e[32m */
|
||||
[1][2] = {85, 255, 85, 10}, /* bright green: \e[92m */
|
||||
[0][3] = {170, 85, 0, 3}, /* normal yellow: \e[33m */
|
||||
[1][3] = {255, 255, 85, 11}, /* bright yellow: \e[93m */
|
||||
[0][4] = {0, 0, 170, 4}, /* normal blue: \e[34m */
|
||||
[1][4] = {85, 85, 255, 12}, /* bright blue: \e[94m */
|
||||
[0][5] = {170, 0, 170, 5}, /* normal magenta: \e[35m */
|
||||
[1][5] = {255, 85, 255, 13}, /* bright magenta: \e[95m */
|
||||
[0][6] = {0, 170, 170, 6}, /* normal cyan: \e[36m */
|
||||
[1][6] = {85, 255, 255, 14}, /* bright cyan: \e[96m */
|
||||
[0][7] = {170, 170, 170, 7}, /* normal white: \e[37m */
|
||||
[1][7] = {255, 255, 255, 15}, /* bright white: \e[97m */
|
||||
};
|
29
dsp/tty/ktangopalette.c
Normal file
29
dsp/tty/ktangopalette.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "dsp/tty/quant.h"
|
||||
|
||||
const ttypalette_t kTangoPalette = {
|
||||
[0][0] = {0x2E, 0x34, 0x36, 0}, /* aluminium1 */
|
||||
[1][0] = {0x55, 0x57, 0x53, 8},
|
||||
[0][1] = {0xCC, 0x00, 0x00, 1}, /* scarietred */
|
||||
[1][1] = {0xEF, 0x29, 0x29, 9},
|
||||
[0][2] = {0x4E, 0x9A, 0x06, 2}, /* chameleon */
|
||||
[1][2] = {0x8A, 0xE2, 0x34, 10},
|
||||
[0][3] = {0xC4, 0xA0, 0x00, 3}, /* butter */
|
||||
[1][3] = {0xFC, 0xE9, 0x4F, 11},
|
||||
[0][4] = {0x34, 0x65, 0xA4, 4}, /* skyblue */
|
||||
[1][4] = {0x72, 0x9F, 0xCF, 12},
|
||||
[0][5] = {0x75, 0x50, 0x7B, 5}, /* plum */
|
||||
[1][5] = {0xAD, 0x7F, 0xA8, 13},
|
||||
[0][6] = {0x06, 0x98, 0x9A, 6}, /* cyan */
|
||||
[1][6] = {0x34, 0xE2, 0xE2, 14},
|
||||
[0][7] = {0xD3, 0xD7, 0xCF, 7}, /* aluminium2 */
|
||||
[1][7] = {0xEE, 0xEE, 0xEC, 15},
|
||||
};
|
22
dsp/tty/kxtermcubesteps.c
Normal file
22
dsp/tty/kxtermcubesteps.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
|
||||
const uint8_t kXtermCubeSteps[] = {0, 0137, 0207, 0257, 0327, 0377};
|
29
dsp/tty/kxtermpalette.c
Normal file
29
dsp/tty/kxtermpalette.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "dsp/tty/quant.h"
|
||||
|
||||
const ttypalette_t kXtermPalette = {
|
||||
[0][0] = {0, 0, 0, 0}, /* normal black: \e[30m (or \e[38;5;0m) */
|
||||
[1][0] = {127, 127, 127, 8}, /* bright black: \e[90m (or \e[38;5;8m) */
|
||||
[0][1] = {205, 0, 0, 1}, /* normal red: \e[31m */
|
||||
[1][1] = {255, 0, 0, 9}, /* bright red: \e[91m (or \e[1;31m) */
|
||||
[0][2] = {0, 205, 0, 2}, /* normal green: \e[32m */
|
||||
[1][2] = {0, 255, 0, 10}, /* bright green: \e[92m */
|
||||
[0][3] = {205, 205, 0, 3}, /* normal yellow: \e[33m */
|
||||
[1][3] = {255, 255, 0, 11}, /* bright yellow: \e[93m */
|
||||
[0][4] = {0, 0, 238, 4}, /* normal blue: \e[34m */
|
||||
[1][4] = {92, 92, 255, 12}, /* bright blue: \e[94m */
|
||||
[0][5] = {205, 0, 205, 5}, /* normal magenta: \e[35m */
|
||||
[1][5] = {255, 0, 255, 13}, /* bright magenta: \e[95m */
|
||||
[0][6] = {0, 205, 205, 6}, /* normal cyan: \e[36m */
|
||||
[1][6] = {0, 255, 255, 14}, /* bright cyan: \e[96m */
|
||||
[0][7] = {229, 229, 229, 7}, /* normal white: \e[37m */
|
||||
[1][7] = {255, 255, 255, 15}, /* bright white: \e[97m */
|
||||
};
|
29
dsp/tty/mpsadbw.S
Normal file
29
dsp/tty/mpsadbw.S
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
/ TODO(jart): write me
|
||||
|
||||
movdqa a,%xmm0
|
||||
mpsadbw $0,inv,%xmm0
|
||||
|
||||
.rodata.cst32
|
||||
a: .byte 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
|
||||
inv: .byte 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
|
84
dsp/tty/quant.h
Normal file
84
dsp/tty/quant.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef DSP_TTY_QUANT_H_
|
||||
#define DSP_TTY_QUANT_H_
|
||||
#include "dsp/tty/ttyrgb.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/xmmintrin.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define TL 0
|
||||
#define TR 1
|
||||
#define BL 2
|
||||
#define BR 3
|
||||
|
||||
typedef __m128 (*tty2rgbf_f)(struct TtyRgb);
|
||||
typedef char *(*setbg_f)(char *, struct TtyRgb);
|
||||
typedef char *(*setbgfg_f)(char *, struct TtyRgb, struct TtyRgb);
|
||||
typedef char *(*setfg_f)(char *, struct TtyRgb);
|
||||
typedef struct TtyRgb (*rgb2tty_f)(int, int, int);
|
||||
typedef struct TtyRgb (*rgb2ttyf_f)(__m128);
|
||||
typedef struct TtyRgb (*tty2rgb_f)(struct TtyRgb);
|
||||
typedef struct TtyRgb ttypalette_t[2][8];
|
||||
|
||||
struct TtyQuant {
|
||||
enum TtyQuantizationAlgorithm {
|
||||
kTtyQuantAnsi,
|
||||
kTtyQuantTrue,
|
||||
kTtyQuantXterm256,
|
||||
} alg;
|
||||
enum TtyBlocksSelection {
|
||||
kTtyBlocksUnicode,
|
||||
kTtyBlocksCp437,
|
||||
} blocks;
|
||||
enum TtyQuantizationChannels {
|
||||
kTtyQuantGrayscale = 1,
|
||||
kTtyQuantRgb = 3,
|
||||
} chans;
|
||||
unsigned min;
|
||||
unsigned max;
|
||||
setbg_f setbg;
|
||||
setfg_f setfg;
|
||||
setbgfg_f setbgfg;
|
||||
rgb2tty_f rgb2tty;
|
||||
rgb2ttyf_f rgb2ttyf;
|
||||
tty2rgb_f tty2rgb;
|
||||
tty2rgbf_f tty2rgbf;
|
||||
const ttypalette_t *palette;
|
||||
};
|
||||
|
||||
extern const ttypalette_t kCgaPalette;
|
||||
extern const ttypalette_t kXtermPalette;
|
||||
extern const ttypalette_t kTangoPalette;
|
||||
|
||||
extern const uint8_t kXtermCubeSteps[6];
|
||||
extern double g_xterm256_gamma;
|
||||
extern struct TtyRgb g_ansi2rgb_[256];
|
||||
extern struct TtyQuant g_ttyquant_;
|
||||
extern const uint8_t kXtermXlat[2][256];
|
||||
|
||||
void ttyquantinit(enum TtyQuantizationAlgorithm, enum TtyQuantizationChannels,
|
||||
enum TtyBlocksSelection);
|
||||
|
||||
extern char *ttyraster(char *, const struct TtyRgb *, size_t, size_t,
|
||||
struct TtyRgb, struct TtyRgb);
|
||||
|
||||
#define ttyquant() (&g_ttyquant_)
|
||||
#define TTYQUANT() VEIL("r", &g_ttyquant_)
|
||||
#define rgb2tty(...) (ttyquant()->rgb2tty(__VA_ARGS__))
|
||||
#define tty2rgb(...) (ttyquant()->tty2rgb(__VA_ARGS__))
|
||||
#define rgb2ttyf(...) (ttyquant()->rgb2ttyf(__VA_ARGS__))
|
||||
#define tty2rgbf(...) (ttyquant()->tty2rgbf(__VA_ARGS__))
|
||||
#define setbg(...) (ttyquant()->setbg(__VA_ARGS__))
|
||||
#define setfg(...) (ttyquant()->setfg(__VA_ARGS__))
|
||||
#define setbgfg(...) (ttyquant()->setbgfg(__VA_ARGS__))
|
||||
|
||||
forceinline bool ttyeq(struct TtyRgb x, struct TtyRgb y) {
|
||||
return x.r == y.r && x.g == y.g && x.b == y.b;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* DSP_TTY_QUANT_H_ */
|
78
dsp/tty/quantinit.c
Normal file
78
dsp/tty/quantinit.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/internal.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
struct TtyQuant g_ttyquant_;
|
||||
|
||||
/**
|
||||
* Chooses xterm quantization mode.
|
||||
*/
|
||||
optimizesize textstartup void ttyquantinit(enum TtyQuantizationAlgorithm alg,
|
||||
enum TtyQuantizationChannels chans,
|
||||
enum TtyBlocksSelection blocks) {
|
||||
switch (alg) {
|
||||
case kTtyQuantAnsi:
|
||||
TTYQUANT()->rgb2tty = rgb2ansi_;
|
||||
TTYQUANT()->rgb2ttyf = rgb2ttyf2i_;
|
||||
TTYQUANT()->tty2rgb = tty2rgb_;
|
||||
TTYQUANT()->tty2rgbf = tty2rgbf_;
|
||||
TTYQUANT()->setbg = setbg16_;
|
||||
TTYQUANT()->setfg = setfg16_;
|
||||
TTYQUANT()->setbgfg = setbgfg16_;
|
||||
TTYQUANT()->min = 0;
|
||||
TTYQUANT()->max = 16;
|
||||
break;
|
||||
case kTtyQuantTrue:
|
||||
TTYQUANT()->rgb2tty = rgb2xterm24_;
|
||||
TTYQUANT()->rgb2ttyf = rgb2tty24f_;
|
||||
TTYQUANT()->tty2rgb = tty2rgb24_;
|
||||
TTYQUANT()->tty2rgbf = tty2rgbf24_;
|
||||
TTYQUANT()->setbg = setbg24_;
|
||||
TTYQUANT()->setfg = setfg24_;
|
||||
TTYQUANT()->setbgfg = setbgfg24_;
|
||||
TTYQUANT()->min = 16;
|
||||
TTYQUANT()->max = 256;
|
||||
break;
|
||||
case kTtyQuantXterm256:
|
||||
TTYQUANT()->rgb2tty = rgb2ansi_;
|
||||
TTYQUANT()->rgb2ttyf = rgb2ttyf2i_;
|
||||
TTYQUANT()->tty2rgb = tty2rgb_;
|
||||
TTYQUANT()->tty2rgbf = tty2rgbf_;
|
||||
TTYQUANT()->setbg = setbg256_;
|
||||
TTYQUANT()->setfg = setfg256_;
|
||||
TTYQUANT()->setbgfg = setbgfg256_;
|
||||
TTYQUANT()->min = 16;
|
||||
TTYQUANT()->max = 256;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
TTYQUANT()->chans = chans;
|
||||
TTYQUANT()->alg = alg;
|
||||
TTYQUANT()->blocks = blocks;
|
||||
}
|
||||
|
||||
INITIALIZER(400, _init_ttyquant,
|
||||
ttyquantinit(kTtyQuantXterm256, kTtyQuantRgb, kTtyBlocksUnicode));
|
29
dsp/tty/restore.c
Normal file
29
dsp/tty/restore.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* Puts teletypewriter back into previous configuration.
|
||||
*/
|
||||
int ttyrestore(int ttyoutfd, const struct termios *conf) {
|
||||
return tcsetattr(ttyoutfd, TCSADRAIN, conf);
|
||||
}
|
129
dsp/tty/rgb2ansi.c
Normal file
129
dsp/tty/rgb2ansi.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/core/core.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define CUTOFF_VALUE 200
|
||||
|
||||
#define DIST(X, Y) ((X) - (Y))
|
||||
#define SQR(X) ((X) * (X))
|
||||
#define SUM(X, Y, Z) ((X) + (Y) + (Z))
|
||||
|
||||
static const uint8_t kXtermCube[] = {0, 0137, 0207, 0257, 0327, 0377};
|
||||
struct TtyRgb g_ansi2rgb_[256];
|
||||
static uint8_t g_quant[256];
|
||||
static uint8_t g_rindex[256];
|
||||
static uint8_t g_gindex[256];
|
||||
static uint8_t g_bindex[256];
|
||||
double g_xterm256_gamma;
|
||||
|
||||
struct TtyRgb tty2rgb_(struct TtyRgb rgbxt) {
|
||||
return g_ansi2rgb_[rgbxt.xt];
|
||||
}
|
||||
|
||||
__m128 tty2rgbf_(struct TtyRgb rgbxt) {
|
||||
rgbxt = g_ansi2rgb_[rgbxt.xt];
|
||||
return (__m128){(int)rgbxt.r, (int)rgbxt.g, (int)rgbxt.b} / 255;
|
||||
}
|
||||
|
||||
static int rgb2xterm256_(int r, int g, int b) {
|
||||
int cerr, gerr, ir, ig, ib, gray, grai, cr, cg, cb, gv;
|
||||
gray = round(r * .299 + g * .587 + b * .114);
|
||||
grai = gray > 238 ? 23 : (gray - 3) / 10;
|
||||
ir = r < 48 ? 0 : r < 115 ? 1 : (r - 35) / 40;
|
||||
ig = g < 48 ? 0 : g < 115 ? 1 : (g - 35) / 40;
|
||||
ib = b < 48 ? 0 : b < 115 ? 1 : (b - 35) / 40;
|
||||
cr = kXtermCube[ir];
|
||||
cg = kXtermCube[ig];
|
||||
cb = kXtermCube[ib];
|
||||
gv = 8 + 10 * grai;
|
||||
cerr = SQR(DIST(cr, r)) + SQR(DIST(cg, g)) + SQR(DIST(cb, b));
|
||||
gerr = SQR(DIST(gv, r)) + SQR(DIST(gv, g)) + SQR(DIST(gv, b));
|
||||
if (cerr <= gerr) {
|
||||
return 16 + 36 * ir + 6 * ig + ib;
|
||||
} else {
|
||||
return 232 + grai;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quantizes RGB to ANSI w/ euclidean distance in 3D color space.
|
||||
*/
|
||||
struct TtyRgb rgb2ansi_(int r, int g, int b) {
|
||||
uint32_t d, least;
|
||||
size_t c, best, min, max;
|
||||
r = MAX(MIN(r, 255), 0);
|
||||
g = MAX(MIN(g, 255), 0);
|
||||
b = MAX(MIN(b, 255), 0);
|
||||
min = ttyquant()->min;
|
||||
max = ttyquant()->max;
|
||||
if (min == 16 && max == 256) {
|
||||
return (struct TtyRgb){r, g, b, rgb2xterm256_(r, g, b)};
|
||||
} else {
|
||||
least = UINT32_MAX;
|
||||
best = 0;
|
||||
for (c = min; c < max; c++) {
|
||||
d = SUM(SQR(DIST(g_ansi2rgb_[c].r, r)), SQR(DIST(g_ansi2rgb_[c].g, g)),
|
||||
SQR(DIST(g_ansi2rgb_[c].b, b)));
|
||||
if (d < least) {
|
||||
least = d;
|
||||
best = c;
|
||||
}
|
||||
}
|
||||
return (struct TtyRgb){r, g, b, best};
|
||||
}
|
||||
}
|
||||
|
||||
static int uncube(int x) {
|
||||
return x < 48 ? 0 : x < 115 ? 1 : (x - 35) / 40;
|
||||
}
|
||||
|
||||
static optimizesize textstartup void xterm2rgbsetup_(void) {
|
||||
uint8_t c, y;
|
||||
uint32_t i, j;
|
||||
memcpy(g_ansi2rgb_, &kCgaPalette, sizeof(kCgaPalette));
|
||||
for (i = 0; i < 256; ++i) {
|
||||
j = uncube(i);
|
||||
g_quant[i] = kXtermCube[j];
|
||||
g_rindex[i] = j * 36;
|
||||
g_gindex[i] = j * 6;
|
||||
g_bindex[i] = j + 16;
|
||||
}
|
||||
for (i = 16; i < 232; ++i) {
|
||||
g_ansi2rgb_[i].r = kXtermCube[((i - 020) / 044) % 06];
|
||||
g_ansi2rgb_[i].g = kXtermCube[((i - 020) / 06) % 06];
|
||||
g_ansi2rgb_[i].b = kXtermCube[(i - 020) % 06];
|
||||
g_ansi2rgb_[i].xt = i;
|
||||
}
|
||||
for (i = 232, c = 8; i < 256; i++, c += 10) {
|
||||
g_ansi2rgb_[i].r = c;
|
||||
g_ansi2rgb_[i].g = c;
|
||||
g_ansi2rgb_[i].b = c;
|
||||
g_ansi2rgb_[i].xt = i;
|
||||
}
|
||||
}
|
||||
|
||||
INITIALIZER(301, _init_ansi2rgb, xterm2rgbsetup_());
|
29
dsp/tty/rgb2ttyf2i.c
Normal file
29
dsp/tty/rgb2ttyf2i.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/bits/xmmintrin.h"
|
||||
|
||||
struct TtyRgb rgb2ttyf2i_(__m128 rgb) {
|
||||
__v4si i4;
|
||||
rgb *= 255;
|
||||
/* i4 = __builtin_ia32_cvtps2dq(rgb); */
|
||||
asm("cvttps2dq\t%0,%1" : "+%x"(rgb), "=x"(i4));
|
||||
return rgb2tty(i4[0], i4[1], i4[2]);
|
||||
}
|
26
dsp/tty/rgb2ttyi2f.c
Normal file
26
dsp/tty/rgb2ttyi2f.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
struct TtyRgb rgb2ttyi2f_(int r, int g, int b) {
|
||||
return rgb2ttyf((__m128){r, g, b} / 255);
|
||||
}
|
26
dsp/tty/rgb2xterm24.c
Normal file
26
dsp/tty/rgb2xterm24.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
struct TtyRgb rgb2xterm24_(int r, int g, int b) {
|
||||
return (struct TtyRgb){MAX(MIN(r, 255), 0), MAX(MIN(g, 255), 0),
|
||||
MAX(MIN(b, 255), 0), 0};
|
||||
}
|
42
dsp/tty/rgb2xterm24f.c
Normal file
42
dsp/tty/rgb2xterm24f.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/math.h"
|
||||
|
||||
/*
|
||||
struct TtyRgb rgb2tty24f_(__m128 rgb) {
|
||||
const __v4si kMax = {255, 255, 255, 255};
|
||||
const __v4si kMin = {0, 0, 0, 0};
|
||||
struct TtyRgb res;
|
||||
__v4si rgb255;
|
||||
rgb255 = _mm_min_ps(_mm_max_ps(_mm_cvtps_epi32(rgb * 255), kMin), kMax);
|
||||
res = (struct TtyRgb){rgb255[0], rgb255[1], rgb255[2], rgb255[3]};
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
struct TtyRgb rgb2tty24f_(__m128 rgb) {
|
||||
const __m128 kMax = {1, 1, 1, 1};
|
||||
const __m128 kMin = {0, 0, 0, 0};
|
||||
struct TtyRgb res;
|
||||
rgb = _mm_min_ps(_mm_max_ps(rgb, kMin), kMax) * 255;
|
||||
res = (struct TtyRgb){rgb[0], rgb[1], rgb[2], rgb[3]};
|
||||
return res;
|
||||
}
|
71
dsp/tty/rgb2xterm256.c
Normal file
71
dsp/tty/rgb2xterm256.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/rgb2xterm256.h"
|
||||
|
||||
/* 1bc */
|
||||
forceinline int sqr(int x) { return x * x; }
|
||||
/* forceinline int dst6(int x) { return x * x; } */
|
||||
int rgb2xterm256v2(int r, int g, int b) {
|
||||
static const int i2cv[] = {0, 0137, 0207, 0257, 0327, 0377, 0377};
|
||||
#define v2ci(v) (v < 060 ? 0 : v < 0163 ? 01 : (v - 043) / 050)
|
||||
#define dst6(A, B, C, a, b, c) (sqr(A - a) + sqr(B - b) + sqr(C - c))
|
||||
int ir = v2ci(r);
|
||||
int ig = v2ci(g);
|
||||
int ib = v2ci(b);
|
||||
int avg = (r + g + b) / 3;
|
||||
int cr = i2cv[ir];
|
||||
int cg = i2cv[ig];
|
||||
int cb = i2cv[ib];
|
||||
int gidx = avg > 238 ? 23 : (avg - 3) / 10;
|
||||
int gv = 8 + 10 * gidx;
|
||||
int cerr = dst6(cr, cg, cb, r, g, b);
|
||||
int gerr = dst6(gv, gv, gv, r, g, b);
|
||||
return cerr <= gerr ? 16 + (36 * ir + 6 * ig + ib) : 232 + gidx;
|
||||
#undef dst6
|
||||
#undef cidx
|
||||
#undef v2ci
|
||||
}
|
||||
|
||||
/* 1e3 */
|
||||
// Convert RGB24 to xterm-256 8-bit value
|
||||
// For simplicity, assume RGB space is perceptually uniform.
|
||||
// There are 5 places where one of two outputs needs to be chosen when
|
||||
// input is the exact middle:
|
||||
// - The r/g/b channels and the gray value: choose higher value output
|
||||
// - If gray and color have same distance from input - choose color
|
||||
int rgb2xterm256(uint8_t r, uint8_t g, uint8_t b) {
|
||||
// Calculate the nearest 0-based color index at 16 .. 231
|
||||
#define v2ci(v) (v < 48 ? 0 : v < 115 ? 1 : (v - 35) / 40)
|
||||
int ir = v2ci(r), ig = v2ci(g), ib = v2ci(b); // 0..5 each
|
||||
#define color_index() (36 * ir + 6 * ig + ib) /* 0..215, lazy eval */
|
||||
// Calculate the nearest 0-based gray index at 232 .. 255
|
||||
int average = (r + g + b) / 3;
|
||||
int gray_index = average > 238 ? 23 : (average - 3) / 10; // 0..23
|
||||
// Calculate the represented colors back from the index
|
||||
static const int i2cv[6] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
|
||||
int cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib]; // r/g/b, 0..255 each
|
||||
int gv = 8 + 10 * gray_index; // same value for r/g/b, 0..255
|
||||
// Return the one which is nearer to the original input rgb value
|
||||
#define dist_square(A, B, C, a, b, c) \
|
||||
((A - a) * (A - a) + (B - b) * (B - b) + (C - c) * (C - c))
|
||||
int color_err = dist_square(cr, cg, cb, r, g, b);
|
||||
int gray_err = dist_square(gv, gv, gv, r, g, b);
|
||||
return color_err <= gray_err ? 16 + color_index() : 232 + gray_index;
|
||||
}
|
11
dsp/tty/rgb2xterm256.h
Normal file
11
dsp/tty/rgb2xterm256.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_DSP_TTY_RGB2XTERM256_H_
|
||||
#define COSMOPOLITAN_DSP_TTY_RGB2XTERM256_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int rgb2xterm256(uint8_t, uint8_t, uint8_t);
|
||||
int rgb2xterm256v2(int, int, int);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_TTY_RGB2XTERM256_H_ */
|
30
dsp/tty/savecursor.c
Normal file
30
dsp/tty/savecursor.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to push current position.
|
||||
*/
|
||||
int ttysavecursor(int ttyfd) { return ttysend(ttyfd, "\e[s"); }
|
||||
|
||||
/**
|
||||
* Asks teletypewriter to pop previous position.
|
||||
*/
|
||||
int ttyrestorecursor(int ttyfd) { return ttysend(ttyfd, "\e[u"); }
|
30
dsp/tty/send.c
Normal file
30
dsp/tty/send.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Sends data to teletypewriter.
|
||||
*
|
||||
* This function blocks until the full amount is transmitted.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int ttysend(int fd, const char *str) { return ttywrite(fd, str, strlen(str)); }
|
41
dsp/tty/sendtitle.c
Normal file
41
dsp/tty/sendtitle.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Changes text in title bar of pseudo-teletypewriter window.
|
||||
*
|
||||
* @param title is trustworthy text without any BEL characters
|
||||
* @param ti comes from ttyident() and null means no-op
|
||||
*/
|
||||
int ttysendtitle(int ttyfd, const char *title, const struct TtyIdent *ti) {
|
||||
if (ti) {
|
||||
if (ti->id == kTtyIdScreen) {
|
||||
return ttysend(ttyfd, gc(xstrcat("\eP\e]0;", title, "\a\e\\")));
|
||||
} else {
|
||||
return ttysend(ttyfd, gc(xstrcat("\e]0;", title, "\a")));
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
25
dsp/tty/setansipalette.c
Normal file
25
dsp/tty/setansipalette.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
void setansipalette(ttypalette_t palette) {
|
||||
memcpy(g_ansi2rgb_, palette, sizeof(struct TtyRgb) * 2 * 8);
|
||||
}
|
43
dsp/tty/setbgfg16.c
Normal file
43
dsp/tty/setbgfg16.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
static char *ansitoa(char *p, unsigned xt, unsigned base) {
|
||||
if (xt >= 8) xt -= 8, base += 60;
|
||||
return itoa8(p, xt + base);
|
||||
}
|
||||
|
||||
static char *setansibgfg(char *p, unsigned bg, unsigned fg) {
|
||||
*p++ = '\e';
|
||||
*p++ = '[';
|
||||
if (bg != -1u) p = ansitoa(p, bg, 40);
|
||||
if (bg != -1u && fg != -1u) *p++ = ';';
|
||||
if (fg != -1u) p = ansitoa(p, fg, 30);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
char *setbg16_(char *p, struct TtyRgb bg) { return setansibgfg(p, bg.xt, -1u); }
|
||||
char *setfg16_(char *p, struct TtyRgb fg) { return setansibgfg(p, -1u, fg.xt); }
|
||||
char *setbgfg16_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
|
||||
return setansibgfg(p, bg.xt, fg.xt);
|
||||
}
|
54
dsp/tty/setbgfg24.c
Normal file
54
dsp/tty/setbgfg24.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static char *rgbcpy(char *p, struct TtyRgb bg) {
|
||||
memcpy(p, ";2;\0", 4);
|
||||
p = itoa8(p + 3, bg.r);
|
||||
*p++ = ';';
|
||||
p = itoa8(p, bg.g);
|
||||
*p++ = ';';
|
||||
return itoa8(p, bg.b);
|
||||
}
|
||||
|
||||
char *setbg24_(char *p, struct TtyRgb bg) {
|
||||
memcpy(p, "\e[48", 4);
|
||||
p = rgbcpy(p + 4, bg);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
char *setfg24_(char *p, struct TtyRgb fg) {
|
||||
memcpy(p, "\e[38", 4);
|
||||
p = rgbcpy(p + 4, fg);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
char *setbgfg24_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
|
||||
memcpy(p, "\e[48", 4);
|
||||
p = rgbcpy(p + 4, bg);
|
||||
memcpy(p, ";38\0", 4);
|
||||
p = rgbcpy(p + 3, fg);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
48
dsp/tty/setbgfg256.c
Normal file
48
dsp/tty/setbgfg256.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/itoa8.h"
|
||||
#include "dsp/tty/quant.h"
|
||||
|
||||
char *setbg256_(char *p, struct TtyRgb bg) {
|
||||
memcpy(p, "\e[48", 4);
|
||||
memcpy(p + 4, ";5;\0", 4);
|
||||
p = itoa8(p + 7, bg.xt);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
char *setfg256_(char *p, struct TtyRgb fg) {
|
||||
memcpy(p, "\e[38", 4);
|
||||
memcpy(p + 4, ";5;\0", 4);
|
||||
p = itoa8(p + 7, fg.xt);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
||||
|
||||
char *setbgfg256_(char *p, struct TtyRgb bg, struct TtyRgb fg) {
|
||||
memcpy(p, "\e[48", 4);
|
||||
memcpy(p + 4, ";5;\0", 4);
|
||||
p = itoa8(p + 7, bg.xt);
|
||||
memcpy(p, ";38;", 4);
|
||||
memcpy(p + 4, "5;\0", 4);
|
||||
p = itoa8(p + 6, fg.xt);
|
||||
*p++ = 'm';
|
||||
return p;
|
||||
}
|
52
dsp/tty/setraw.c
Normal file
52
dsp/tty/setraw.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* Enables direct teletypewriter communication.
|
||||
*
|
||||
* @see ttyconfig(), ttyrestore()
|
||||
*/
|
||||
int ttysetraw(struct termios *conf, int64_t flags) {
|
||||
conf->c_iflag &= ~(INPCK | ISTRIP | PARMRK | INLCR | IGNCR | ICRNL | IXON);
|
||||
conf->c_lflag &= ~(IEXTEN | ICANON);
|
||||
conf->c_cflag &= ~(CSIZE | PARENB);
|
||||
conf->c_cflag |= CS8;
|
||||
conf->c_iflag |= IUTF8;
|
||||
/* if (flags & kTtyLfToCrLf) { */
|
||||
/* /\* conf->c_oflag &= ~(OLCUC | OCRNL | ONLRET | OFILL | OFDEL); *\/ */
|
||||
/* /\* conf->c_oflag |= ONLCR | ONOCR; *\/ */
|
||||
/* conf->c_oflag |= ONLCR; */
|
||||
/* } else { */
|
||||
/* conf->c_oflag &= ~OPOST; */
|
||||
/* } */
|
||||
if (!(flags & kTtySigs)) {
|
||||
conf->c_iflag &= ~(IGNBRK | BRKINT);
|
||||
conf->c_lflag &= ~(ISIG);
|
||||
}
|
||||
if (flags & kTtyEcho) {
|
||||
conf->c_lflag |= ECHO | ECHONL;
|
||||
} else {
|
||||
conf->c_lflag &= ~(ECHO | ECHONL);
|
||||
}
|
||||
return 0;
|
||||
}
|
34
dsp/tty/setrawdeadline.c
Normal file
34
dsp/tty/setrawdeadline.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* Enables direct teletypewriter communication w/ read timeouts.
|
||||
* @see ttyconfig(), ttyrestore()
|
||||
*/
|
||||
int ttysetrawdeadline(struct termios *conf, int64_t deciseconds) {
|
||||
assert(0 < deciseconds && deciseconds < 256);
|
||||
conf->c_cc[VMIN] = 0;
|
||||
conf->c_cc[VTIME] = deciseconds;
|
||||
return ttysetraw(conf, 0);
|
||||
}
|
33
dsp/tty/setrawmode.c
Normal file
33
dsp/tty/setrawmode.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
|
||||
/**
|
||||
* Enables blocking raw mode for teletypewriter w/ recommended settings.
|
||||
* @see ttyconfig(), ttyrestore()
|
||||
*/
|
||||
int ttysetrawmode(struct termios *conf, int64_t flags) {
|
||||
conf->c_cc[VMIN] = 1;
|
||||
conf->c_cc[VTIME] = 1;
|
||||
return ttysetraw(conf, flags);
|
||||
}
|
59
dsp/tty/tty.h
Normal file
59
dsp/tty/tty.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef COSMOPOLITAN_DSP_TTY_TTY_H_
|
||||
#define COSMOPOLITAN_DSP_TTY_TTY_H_
|
||||
|
||||
#define kTtyIdScreen 83
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct FILE;
|
||||
struct termios;
|
||||
|
||||
struct TtyIdent {
|
||||
int id; /* first number sent back by \e[>c */
|
||||
int version; /* second number sent back by \e[>c */
|
||||
struct TtyIdent *next; /* yo dawg */
|
||||
};
|
||||
|
||||
struct TtyCursor {
|
||||
int y;
|
||||
int x;
|
||||
int bg;
|
||||
int fg;
|
||||
};
|
||||
|
||||
enum TtyRawFlags {
|
||||
kTtyEcho = 1 << 0, /* echo input */
|
||||
kTtyCursor = 1 << 1, /* show cursor */
|
||||
kTtySigs = 1 << 2, /* auto raise() on CTRL+C, CTRL+Z, and CTRL+\ */
|
||||
kTtyLfToCrLf = 1 << 3, /* enables unix newline magic */
|
||||
};
|
||||
|
||||
typedef int (*ttyconf_f)(struct termios *, int64_t);
|
||||
|
||||
int ttyraw(enum TtyRawFlags);
|
||||
int ttyhidecursor(int);
|
||||
int ttyshowcursor(int);
|
||||
int ttysavecursor(int);
|
||||
int ttyrestorecursor(int);
|
||||
int ttyenablealtbuf(int);
|
||||
int ttydisablealtbuf(int);
|
||||
int ttysend(int, const char *);
|
||||
int ttywrite(int, const void *, size_t);
|
||||
int ttysendtitle(int, const char *, const struct TtyIdent *);
|
||||
int ttyident(struct TtyIdent *, int, int);
|
||||
void ttyidentclear(struct TtyIdent *);
|
||||
char *ttydescribe(char *, size_t, const struct TtyIdent *);
|
||||
int ttyconfig(int, ttyconf_f, int64_t, const struct termios *);
|
||||
int ttyrestore(int, const struct termios *);
|
||||
int ttysetrawdeadline(struct termios *, int64_t);
|
||||
int ttysetrawmode(struct termios *, int64_t);
|
||||
int ttysetraw(struct termios *, int64_t);
|
||||
char *ttymove(struct TtyCursor *, char *, int, int)
|
||||
paramsnonnull() returnsnonnull;
|
||||
void ttyhisto(uint32_t[hasatleast 256], uint8_t[hasatleast 256],
|
||||
const uint8_t *, const uint8_t *, size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_DSP_TTY_TTY_H_ */
|
70
dsp/tty/tty.mk
Normal file
70
dsp/tty/tty.mk
Normal file
|
@ -0,0 +1,70 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += DSP_TTY
|
||||
|
||||
DSP_TTY_ARTIFACTS += DSP_TTY_A
|
||||
DSP_TTY = $(DSP_TTY_A_DEPS) $(DSP_TTY_A)
|
||||
DSP_TTY_A = o/$(MODE)/dsp/tty/tty.a
|
||||
DSP_TTY_A_FILES := $(wildcard dsp/tty/*)
|
||||
DSP_TTY_A_HDRS = $(filter %.h,$(DSP_TTY_A_FILES))
|
||||
DSP_TTY_A_SRCS_S = $(filter %.S,$(DSP_TTY_A_FILES))
|
||||
DSP_TTY_A_SRCS_C = $(filter %.c,$(DSP_TTY_A_FILES))
|
||||
|
||||
DSP_TTY_A_SRCS = \
|
||||
$(DSP_TTY_A_SRCS_S) \
|
||||
$(DSP_TTY_A_SRCS_C)
|
||||
|
||||
DSP_TTY_A_OBJS = \
|
||||
$(DSP_TTY_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(DSP_TTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(DSP_TTY_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
DSP_TTY_A_CHECKS = \
|
||||
$(DSP_TTY_A).pkg \
|
||||
$(DSP_TTY_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
DSP_TTY_A_DIRECTDEPS = \
|
||||
DSP_CORE \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS \
|
||||
LIBC_FMT \
|
||||
LIBC_LOG \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_STR \
|
||||
LIBC_STDIO \
|
||||
LIBC_STUBS \
|
||||
LIBC_SOCK \
|
||||
LIBC_SYSV \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_TIME \
|
||||
LIBC_X \
|
||||
LIBC_UNICODE
|
||||
|
||||
DSP_TTY_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(DSP_TTY_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(DSP_TTY_A): dsp/tty/ \
|
||||
$(DSP_TTY_A).pkg \
|
||||
$(DSP_TTY_A_OBJS)
|
||||
|
||||
$(DSP_TTY_A).pkg: \
|
||||
$(DSP_TTY_A_OBJS) \
|
||||
$(foreach x,$(DSP_TTY_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/dsp/tty/ttyraster.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
$(MATHEMATICAL)
|
||||
|
||||
DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)))
|
||||
DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS))
|
||||
DSP_TTY_HDRS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_HDRS))
|
||||
DSP_TTY_CHECKS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_CHECKS))
|
||||
DSP_TTY_OBJS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_OBJS))
|
||||
$(DSP_TTY_OBJS): $(BUILD_FILES) dsp/tty/tty.mk
|
||||
|
||||
.PHONY: o/$(MODE)/dsp/tty
|
||||
o/$(MODE)/dsp/tty: $(DSP_TTY_CHECKS)
|
24
dsp/tty/tty2rgb24.c
Normal file
24
dsp/tty/tty2rgb24.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/quant.h"
|
||||
|
||||
struct TtyRgb tty2rgb24_(struct TtyRgb rgbxt) {
|
||||
return rgbxt;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue