49 Commits

Author SHA1 Message Date
klemek fddb11dbe3 forge (steel) v1.1.2
Clang Build CI / run-video (push) Successful in 1m31s
Clang Build CI / run-no-video (push) Successful in 1m31s
Clang Build CI / build-release (push) Successful in 1m42s
Clang Lint CI / lint-no-video (push) Successful in 2m29s
Clang Lint CI / lint-video (push) Successful in 2m29s
2026-05-16 19:04:47 +02:00
klemek 591bfbe0aa fix: remove not backward compatible snd_lib_log_set_handler
Clang Lint CI / lint-no-video (push) Successful in 55s
Clang Build CI / run-no-video (push) Successful in 1m36s
Clang Build CI / run-video (push) Successful in 1m37s
Clang Build CI / build-release (push) Successful in 1m57s
Clang Lint CI / lint-video (push) Successful in 2m5s
2026-05-16 18:56:45 +02:00
klemek b01314778d docs: add comment for project_free
Clang Lint CI / lint-no-video (push) Failing after 3m4s
Clang Build CI / run-no-video (push) Failing after 3m49s
Clang Build CI / run-video (push) Failing after 3m48s
Clang Build CI / build-release (push) Failing after 4m3s
Clang Lint CI / lint-video (push) Failing after 1m26s
2026-05-16 18:49:44 +02:00
klemek cbdf4c768d fix: const vertex_shader_text
Clang Build CI / build-release (push) Has been cancelled
Clang Build CI / run-no-video (push) Has been cancelled
Clang Build CI / run-video (push) Has been cancelled
Clang Lint CI / lint-video (push) Has been cancelled
Clang Lint CI / lint-no-video (push) Has been cancelled
2026-05-16 18:48:26 +02:00
klemek 9787f468e8 fix: dont shadow stdlib rand 2026-05-16 18:47:51 +02:00
klemek 2a8bd612b3 fix: unnecessary structs 2026-05-16 18:47:16 +02:00
klemek ba44237661 fix: MidiBackgroundListenArgs bad typedef 2026-05-16 18:46:34 +02:00
klemek efb13bb9ea fix: auto random debug string bad practice 2026-05-16 18:45:18 +02:00
klemek d89de9d6dd fix: check_eglerror_ro dead code 2026-05-16 18:42:17 +02:00
klemek 6ff0246f42 fix: GLint uniform location instead of GLuint 2026-05-16 18:40:52 +02:00
klemek c45b5ef405 fix: glGetShaderInfoLog with invalid parameters 2026-05-16 18:38:05 +02:00
klemek 12942267d2 fix: dont allow empty values in string args 2026-05-16 18:35:32 +02:00
klemek 15fb29b673 fix: boundary check in parse_uint 2026-05-16 18:32:44 +02:00
klemek 39e1fcc709 fix: set gl context before freeing shaders 2026-05-16 18:32:08 +02:00
klemek 3ae3b23c2a fix: add default value for tex_resolution width 2026-05-16 18:30:28 +02:00
klemek 61c88aae2a fix: check pthread_create return code 2026-05-16 18:29:38 +02:00
klemek fcb2baf84a fix: check return_code of snd_rawmidi_open 2026-05-16 18:26:37 +02:00
klemek 8e7be2258f fix: handle division by 0 in window_use 2026-05-16 18:24:36 +02:00
klemek dcb334ff81 fix: handle VIDIOC_QBUF error while reading video 2026-05-16 18:22:48 +02:00
klemek aab770ba3d fix: free video capture on early init error 2026-05-16 18:19:17 +02:00
klemek 6a7c9b3aab fix: bound timer counter to uint max on fail 2026-05-16 18:10:31 +02:00
klemek 3b6d4d642d fix: use clock instead of timeofday 2026-05-16 18:09:06 +02:00
klemek 988cf799b4 fix: config_file_read handle file error before hashmap_new 2026-05-16 17:54:05 +02:00
klemek a92cca33ad fix: state_parse_config clamp lengths to ARRAY_SIZE 2026-05-16 17:51:40 +02:00
klemek fd9f94d48a fix: save_to_file array size bound check 2026-05-16 17:51:36 +02:00
klemek 859dfc4307 fix: log tempo error 2026-05-16 17:37:49 +02:00
klemek a85a75f93d fix: sync midi read/write 2026-05-16 17:36:50 +02:00
klemek 7e1328aab0 fix: check for snd_rawmidi_info_malloc 2026-05-16 17:35:21 +02:00
klemek 7cce5babc2 fix: don't log errors while reconnecting 2026-05-16 17:12:40 +02:00
klemek 9969230cd9 fix: free process args in pthread 2026-05-16 16:44:34 +02:00
klemek fb77d8e893 fix: revert project files free (already freed in init) 2026-05-16 16:22:39 +02:00
klemek 0fd78bf4cc fix: unsigned comparison 2026-05-16 16:02:53 +02:00
klemek 20e3d39963 fix: init_single_program check linking status 2026-05-16 16:00:39 +02:00
klemek aa8d6c85c0 fix: shaders_free glDeleteShader 2026-05-16 15:55:18 +02:00
klemek b9fd36debd fix: project files free 2026-05-16 15:52:39 +02:00
klemek 7e8eb187d8 fix: parse_fragment_shader_file free content before overwrite 2026-05-16 15:49:22 +02:00
klemek bd61cb0a2d fix: config_file_read dont initialize hashmap on file error 2026-05-16 15:40:03 +02:00
klemek fe1fc9864c fix: string_replace_at check args validity 2026-05-16 15:39:17 +02:00
klemek 233b75e854 fix: string_replace_at check malloc 2026-05-16 15:38:19 +02:00
klemek 910c122c8d fix: unsigned overflow in string_trim 2026-05-16 15:36:09 +02:00
klemek fbd73ebf4c fix: handle partial reads 2026-05-16 15:34:09 +02:00
klemek 43ce38f2f4 fix: file free dangling pointer 2026-05-16 15:31:30 +02:00
klemek ca3e523f93 fix: ftell failure handling 2026-05-16 13:26:40 +02:00
klemek c68bebfd7c fix: unsigned underflow on empty array 2026-05-16 13:25:02 +02:00
klemek 2843e5e863 fix: better full-clean 2026-05-16 00:36:28 +02:00
klemek 433cf61a91 forge (steel) v1.1.1
Clang Build CI / run-no-video (push) Successful in 1m18s
Clang Build CI / build-release (push) Successful in 1m30s
Clang Build CI / run-video (push) Successful in 1m26s
Clang Lint CI / lint-no-video (push) Successful in 1m22s
Clang Lint CI / lint-video (push) Successful in 1m17s
2026-05-16 00:33:24 +02:00
klemek fe3316f730 feat: better src 4 2026-05-16 00:32:41 +02:00
klemek 96f97d81df fix: update default project with internal buffer swap 2026-05-15 16:36:57 +02:00
klemek 365fee352e tools: better clean 2026-05-15 00:24:16 +02:00
39 changed files with 711 additions and 399 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ build build project into build/forge
run run project with test args
demo run project with demo mode
valgrind valgrind analysis
clean-release remove autoconf/automake files
full-clean remove build files and untracked files
test-release try to build release
release-% make full release of version %
release-arch make arch-linux release package
+14 -9
View File
@@ -7,7 +7,7 @@ SHELL := /bin/bash
clean:
@rm -rf build
build:
build/$(TARGET):
@mkdir -p build
gcc \
src/*.h src/*.c \
@@ -25,6 +25,9 @@ build:
-o build/$(TARGET) \
-g -Og
.PHONY: build
build: build/$(TARGET)
.PHONY: build-no-video
build-no-video:
@mkdir -p build
@@ -48,26 +51,28 @@ format:
clang-format -i src/*
.PHONY: run
run: build
run: build/$(TARGET)
./build/$(TARGET) $(RUN_ARGS)
.PHONY: sample
sample: build
./build/$(TARGET) --project=sample
sample: build/$(TARGET)
./build/$(TARGET) --project=sample $(RUN_ARGS)
.PHONY: valgrind
valgrind: build
valgrind: build/$(TARGET)
valgrind \
--show-realloc-size-zero=no \
--undef-value-errors=no \
./build/$(TARGET) $(RUN_ARGS)
.PHONY: clean-release
clean-release:
.PHONY: full-clean
full-clean:
git clean -f -x
rm -rf */*/.deps
rm -rf */.deps
.PHONY: test-release
test-release: clean clean-release
test-release: clean full-clean
aclocal
autoconf
automake --add-missing
@@ -77,7 +82,7 @@ test-release: clean clean-release
cp $(TARGET)-steel-*.tar.gz build/
.PHONY: release-%
release-%: clean clean-release
release-%: clean full-clean
git pull origin main
sed -i -E "s/[0-9]+\\.[0-9]+\\.[0-9]+/$*/g" configure.ac
aclocal
+2 -2
View File
@@ -1,12 +1,12 @@
pkgname=forge-steel
pkgver=1.1.0
pkgver=1.1.2
pkgrel=1
pkgdesc="Fusion Of Real Time Generative Effects"
arch=('i686' 'pentium4' 'x86_64' 'arm' 'armv7h' 'armv6h' 'aarch64' 'riscv64')
depends=('glfw>=1:3', 'v4l-utils>=1.32', 'alsa-lib>=1.2', 'libglvnd>=1.7')
url="https://git.klemek.fr/klemek/forge-steel"
source=("${pkgname}-steel-${pkgver}.tar.gz::https://git.klemek.fr/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
sha256sums=('794fb0f170cff19872acfba8a556e2a08c55a78e497ac0b330eca6db65343529')
sha256sums=('cf4b280fba47d649ab33596d43872a70dd443ed6d15dc587b9dac4e5db294e06')
srcdir=build
backup=("usr/share/${pkgname}")
+1 -1
View File
@@ -247,7 +247,7 @@ Working with pages and items, you can use the following predefined sources and e
| **1** | **0** | Feedback + Thru | _Hue_ | _Saturation_ | _Light_ | Thru | _Hue_ | _Saturation_ | _Light_ |
| | **1** | Lines | _Thick. / Dezoom_ | _Rotation_ | _Distortion_ | Feedback + Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
| | **2** | Dots | _Zoom_ | _Rotation_ | _Lens_ | Shift | _Zoom / Dezoom_ | _X Shift_ | _Y Shift_ |
| | **3** | Circuit | _Zoom_ | _H. connect_ | _V. connect_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
| | **3** | Bacteria | _Zoom_ | _Details_ | _Delta details_ | Colorize | _Black Color_ | _White Color_ | _Shift_ |
| | **4** | Noise | _Zoom_ | _Voronoi dist._ | _Details_ | Quantize | _Pixel Size_ | _Bit Depth_ | _Blur_ |
| **2** | **5** | Video In 1 + Thru | _Hue_ | _Saturation_ | _Light_ | Dithering | _Pixel Size_ | _Bit Depth_ | _Blur_ |
| | **6** | CP437 | _Zoom_ | _Charset_ | _Char. Delta_ | TV | _Lens_ | _Horz. Noise_ | _Dezoom_ |
+1 -2
View File
@@ -1,4 +1,4 @@
AC_INIT([forge], [steel-1.1.0], [klemek.dev@proton.me])
AC_INIT([forge], [steel-1.1.2], [klemek.dev@proton.me])
AM_INIT_AUTOMAKE
AC_PROG_CC
@@ -11,7 +11,6 @@ AC_CHECK_HEADERS([stdlib.h])
AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/mman.h])
AC_CHECK_HEADERS([sys/stat.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/types.h])
AC_CHECK_HEADERS([sys/wait.h])
+7 -7
View File
@@ -115,13 +115,13 @@ FRAG_FILE_PREFIX=frag
FRAG_COUNT=10
# To which texture will the shader fragX.glsl will render to
FRAG_1_OUT=5
FRAG_2_OUT=6
FRAG_3_OUT=7
FRAG_4_OUT=8
FRAG_5_OUT=9
FRAG_6_OUT=10
FRAG_7_OUT=11
FRAG_1_OUT=3
FRAG_2_OUT=4
FRAG_3_OUT=5
FRAG_4_OUT=6
FRAG_5_OUT=7
FRAG_6_OUT=8
FRAG_7_OUT=9
FRAG_8_OUT=0
# Which fragment shader renders to output window
FRAG_OUTPUT=9
+3 -8
View File
@@ -2,8 +2,8 @@
// VIDEO 1
// -----------
// IN: 1+3 (RAW IN A)
// OUT: 5 (IN A)
// IN: 1 (RAW IN A)
// OUT: 3 (IN A)
in vec2 vUV;
out vec4 fragColor;
@@ -14,16 +14,11 @@ uniform sampler2D iTex0;
uniform sampler2D iTex1;
uniform sampler2D iTex3;
uniform int iInputFormat1;
uniform int iInputSwap1;
uniform vec2 iInputResolution1;
void main() {
if (iInputFormat1 == YUYV_FOURCC) {
if (iInputSwap1 > 0) {
fragColor = yuyvTex(iTex3, vUV, int(iInputResolution1.x));
} else {
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
}
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
} else {
fragColor = texture(iTex0, vUV);
}
+94 -22
View File
@@ -9,13 +9,13 @@ out vec4 fragColor;
#include inc_debug.glsl
uniform sampler2D iTex0;
uniform sampler2D iTex3;
uniform sampler2D iTex4;
uniform sampler2D iTex5;
uniform sampler2D iTex6;
uniform sampler2D iTex7;
uniform sampler2D iTex8;
uniform sampler2D iTex9;
uniform sampler2D iTex10;
uniform sampler2D iTex11;
uniform int iFPS;
uniform int iInputFPS1;
uniform int iInputFPS2;
@@ -26,19 +26,91 @@ float s(vec2 uv, float x0, float y0) {
}
const int texts[12][5] = {
{0x49, 0x4E, 0x20, 0x41, 0x00}, // IN A
{0x49, 0x4E, 0x20, 0x42, 0x00}, // IN B
{0x53, 0x52, 0x43, 0x20, 0x41}, // SRC A
{0x53, 0x52, 0x43, 0x20, 0x42}, // SRC B
{0x46, 0x58, 0x20, 0x41, 0x00}, // FX A
{0x46, 0x58, 0x20, 0x42, 0x00}, // FX B
{0x41, 0x2B, 0x42, 0x00, 0x00}, // A+B
{0x4D, 0x46, 0x58, 0x00, 0x00}, // MFX
{0x46, 0x50, 0x53, 0x00, 0x00}, // FPS
{0x4F, 0x46, 0x46, 0x00, 0x00}, // OFF
{0x44, 0x45, 0x4D, 0x4F, 0x00}, // DEMO
{0x4C, 0x49, 0x56, 0x45, 0x00}, // LIVE
};
{
0x49,
0x4E,
0x20,
0x41,
0x00
}, // IN A
{
0x49,
0x4E,
0x20,
0x42,
0x00
}, // IN B
{
0x53,
0x52,
0x43,
0x20,
0x41
}, // SRC A
{
0x53,
0x52,
0x43,
0x20,
0x42
}, // SRC B
{
0x46,
0x58,
0x20,
0x41,
0x00
}, // FX A
{
0x46,
0x58,
0x20,
0x42,
0x00
}, // FX B
{
0x41,
0x2B,
0x42,
0x00,
0x00
}, // A+B
{
0x4D,
0x46,
0x58,
0x00,
0x00
}, // MFX
{
0x46,
0x50,
0x53,
0x00,
0x00
}, // FPS
{
0x4F,
0x46,
0x46,
0x00,
0x00
}, // OFF
{
0x44,
0x45,
0x4D,
0x4F,
0x00
}, // DEMO
{
0x4C,
0x49,
0x56,
0x45,
0x00
}, // LIVE
};
void main() {
vec2 uv0 = vUV.st;
@@ -50,14 +122,14 @@ void main() {
vec4 c = vec4(0);
c += s(uv2, 1, 2) * texture(iTex7, uv2);
c += s(uv2, 2, 2) * texture(iTex9, uv2);
c += s(uv2, 1, 2) * texture(iTex5, uv2);
c += s(uv2, 2, 2) * texture(iTex7, uv2);
c += s(uv2, 1, 0) * texture(iTex8, uv2);
c += s(uv2, 2, 0) * texture(iTex10, uv2);
c += s(uv2, 1, 0) * texture(iTex6, uv2);
c += s(uv2, 2, 0) * texture(iTex8, uv2);
c += s(uv2, 0, 1) * debug(mod(uv2, 1));
c += s(uv2, 1, 1) * texture(iTex11, uv2);
c += s(uv2, 1, 1) * texture(iTex9, uv2);
c += s(uv2, 2, 1) * texture(iTex0, uv2);
float sel = 0;
@@ -77,7 +149,7 @@ void main() {
t += write_5(uv3, vec2(-37, 28), texts[0]);
if (iInputFormat1 == YUYV_FOURCC) {
c += s(uv2, 0, 2) * texture(iTex5, uv2);
c += s(uv2, 0, 2) * texture(iTex3, uv2);
f += rect(uv3, vec2(-35, 26.75), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-37.6, 26.1), iInputFPS1, 2);
t += write_5(uv3, vec2(-35.1, 26.1), texts[8]);
@@ -90,7 +162,7 @@ void main() {
t += write_5(uv3, vec2(-37, -12), texts[1]);
if (iInputFormat2 == YUYV_FOURCC) {
c += s(uv2, 0, 0) * texture(iTex6, uv2);
c += s(uv2, 0, 0) * texture(iTex4, uv2);
f += rect(uv3, vec2(-35, -13.25), vec2(2.8, 0.7));
t += write_int(uv3, vec2(-37.6, -13.9), iInputFPS2, 2);
t += write_5(uv3, vec2(-35.1, -13.9), texts[8]);
+3 -8
View File
@@ -2,8 +2,8 @@
// VIDEO 2
// -----------
// IN: 2+4 (RAW IN B)
// OUT: 6 (IN B)
// IN: 2 (RAW IN B)
// OUT: 4 (IN B)
in vec2 vUV;
out vec4 fragColor;
@@ -14,16 +14,11 @@ uniform sampler2D iTex0;
uniform sampler2D iTex2;
uniform sampler2D iTex4;
uniform int iInputFormat2;
uniform int iInputSwap2;
uniform vec2 iInputResolution2;
void main() {
if (iInputFormat2 == YUYV_FOURCC) {
if (iInputSwap2 > 0) {
fragColor = yuyvTex(iTex4, vUV, int(iInputResolution2.x));
} else {
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
}
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
} else {
fragColor = texture(iTex0, vUV);
}
+1 -1
View File
@@ -3,7 +3,7 @@
// SRC A
// -----------
// OUT: 7 (FX A)
// OUT: 5 (FX A)
in vec2 vUV;
out vec4 fragColor;
+1 -1
View File
@@ -2,7 +2,7 @@
// SRC B
// -----------
// OUT: 8 (FX B)
// OUT: 6 (FX B)
in vec2 vUV;
out vec4 fragColor;
+5 -5
View File
@@ -2,20 +2,20 @@
// FX A
// -------------
// IN: 7 (SRC A)
// IN: 9 (FX A)
// OUT: 9 (A+B)
// IN: 5 (SRC A)
// IN: 7 (FX A)
// OUT: 7 (A+B)
in vec2 vUV;
out vec4 fragColor;
#include inc_fx.glsl
uniform sampler2D iTex5;
uniform sampler2D iTex7;
uniform sampler2D iTex9;
uniform int iSeed5;
uniform vec3 iGroup2_1[7];
void main() {
fragColor = fx_stage(vUV, iTex7, iTex9, iSeed5, iGroup2_1[0], iGroup2_1[1].xy, iGroup2_1[2], iGroup2_1[3].xy, iGroup2_1[4], iGroup2_1[5].xy, iGroup2_1[6]);
fragColor = fx_stage(vUV, iTex5, iTex7, iSeed5, iGroup2_1[0], iGroup2_1[1].xy, iGroup2_1[2], iGroup2_1[3].xy, iGroup2_1[4], iGroup2_1[5].xy, iGroup2_1[6]);
}
+5 -5
View File
@@ -2,20 +2,20 @@
// FX B
// -------------
// IN: 8 (SRC B)
// IN: 10 (FX B)
// OUT: 10 (A+B)
// IN: 6 (SRC B)
// IN: 8 (FX B)
// OUT: 8 (A+B)
in vec2 vUV;
out vec4 fragColor;
#include inc_fx.glsl
uniform sampler2D iTex6;
uniform sampler2D iTex8;
uniform sampler2D iTex10;
uniform int iSeed6;
uniform vec3 iGroup2_2[7];
void main() {
fragColor = fx_stage(vUV, iTex8, iTex10, iSeed6, iGroup2_2[0], iGroup2_2[1].xy, iGroup2_2[2], iGroup2_2[3].xy, iGroup2_2[4], iGroup2_2[5].xy, iGroup2_2[6]);
fragColor = fx_stage(vUV, iTex6, iTex8, iSeed6, iGroup2_2[0], iGroup2_2[1].xy, iGroup2_2[2], iGroup2_2[3].xy, iGroup2_2[4], iGroup2_2[5].xy, iGroup2_2[6]);
}
+7 -7
View File
@@ -2,9 +2,9 @@
// A+B
// ------------
// IN: 9 (FX A)
// IN: 10 (FX B)
// OUT: 11 (MFX)
// IN: 7 (FX A)
// IN: 8 (FX B)
// OUT: 9 (MFX)
in vec2 vUV;
out vec4 fragColor;
@@ -13,8 +13,8 @@ out vec4 fragColor;
#include inc_functions.glsl
uniform int iDemo;
uniform sampler2D iTex9;
uniform sampler2D iTex10;
uniform sampler2D iTex7;
uniform sampler2D iTex8;
uniform int iSeed7;
uniform vec3 iGroup3_1[2];
@@ -22,8 +22,8 @@ void main() {
float mix_value = magic(iGroup3_1[1].xy, vec3(1, 0, 0), iSeed7);
bool mix_type = magic_trigger(vec3(iGroup3_1[0].x, 0, 0), iSeed7 + 10);
vec4 color_a = texture(iTex9, vUV);
vec4 color_b = texture(iTex10, vUV);
vec4 color_a = texture(iTex7, vUV);
vec4 color_b = texture(iTex8, vUV);
float k = mean(color_a);
+3 -3
View File
@@ -2,7 +2,7 @@
// MFX
// ------------
// IN: 11 (A+B)
// IN: 9 (A+B)
// IN: 0 (OUT)
// OUT: 0 (OUT)
@@ -11,7 +11,7 @@ out vec4 fragColor;
#include inc_fx.glsl
uniform sampler2D iTex11;
uniform sampler2D iTex9;
uniform sampler2D iTex0;
uniform int iSeed8;
uniform vec3 iGroup2_3[7];
@@ -20,7 +20,7 @@ uniform int iDemo;
uniform int iAutoRand;
void main() {
vec4 color = fx_stage(vUV, iTex11, iTex0, iSeed8, iGroup2_3[0], iGroup2_3[1].xy, iGroup2_3[2], iGroup2_3[3].xy, iGroup2_3[4], iGroup2_3[5].xy, iGroup2_3[6]);
vec4 color = fx_stage(vUV, iTex9, iTex0, iSeed8, iGroup2_3[0], iGroup2_3[1].xy, iGroup2_3[2], iGroup2_3[3].xy, iGroup2_3[4], iGroup2_3[5].xy, iGroup2_3[6]);
if (iDemo < 1 && iAutoRand < 1) {
color = mix(color, vec4(0), iGroup3_1[0].y);
+55 -49
View File
@@ -24,48 +24,48 @@ float iestep(float x, float y) {
}
float ease(float x) {
return 0.5 - cos(max(min(x, 1.0), 0.0)*PI) * 0.5;
return 0.5 - cos(max(min(x, 1.0), 0.0) * PI) * 0.5;
}
vec2 ease(vec2 x) {
return 0.5 - cos(max(min(x, 1.0), 0.0)*PI) * 0.5;
return 0.5 - cos(max(min(x, 1.0), 0.0) * PI) * 0.5;
}
vec3 ease(vec3 x) {
return 0.5 - cos(max(min(x, 1.0), 0.0)*PI) * 0.5;
return 0.5 - cos(max(min(x, 1.0), 0.0) * PI) * 0.5;
}
float saw(float x){
return abs(mod(x+1,2)-1);
float saw(float x) {
return abs(mod(x + 1, 2) - 1);
}
vec2 saw(vec2 x){
return abs(mod(x+1,2)-1);
vec2 saw(vec2 x) {
return abs(mod(x + 1, 2) - 1);
}
vec3 saw(vec3 x){
return abs(mod(x+1,2)-1);
vec3 saw(vec3 x) {
return abs(mod(x + 1, 2) - 1);
}
float cmod(float x, float k){
float cmod(float x, float k) {
return mod(x + k * 0.5, k) - k * 0.5;
}
vec2 cmod(vec2 x, float k){
vec2 cmod(vec2 x, float k) {
return mod(x + k * 0.5, k) - k * 0.5;
}
vec3 cmod(vec3 x, float k){
vec3 cmod(vec3 x, float k) {
return mod(x + k * 0.5, k) - k * 0.5;
}
// COLORS
vec3 col(float x){
vec3 col(float x) {
return vec3(
.5*(sin(x*2.*PI)+1.),
.5*(sin(x*2.*PI+2.*PI/3.)+1.),
.5*(sin(x*2.*PI-2.*PI/3.)+1.)
.5 * (sin(x * 2. * PI) + 1.),
.5 * (sin(x * 2. * PI + 2. * PI / 3.) + 1.),
.5 * (sin(x * 2. * PI - 2. * PI / 3.) + 1.)
);
}
@@ -83,8 +83,7 @@ vec3 shift3(vec3 c, float f) {
vec3 mix3(vec3 c1, vec3 c2, vec3 c3, float x) {
return istep(0.5, x) * mix(c1, c2, x * 2)
+ step(0.5, x) * mix(c2, c3, x * 2 - 1)
;
+ step(0.5, x) * mix(c2, c3, x * 2 - 1);
}
vec3 mix4(vec3 c1, vec3 c2, vec3 c3, vec3 c4, float x) {
@@ -98,8 +97,7 @@ vec3 mix5(vec3 c1, vec3 c2, vec3 c3, vec3 c4, vec3 c5, float x) {
return istep(0.25, x) * mix(c1, c2, x * 4)
+ step(0.25, x) * istep(0.5, x) * mix(c2, c3, x * 4 - 1)
+ step(0.5, x) * istep(0.75, x) * mix(c3, c4, x * 4 - 2)
+ step(0.75, x) * mix(c4, c5, x * 4 - 3)
;
+ step(0.75, x) * mix(c4, c5, x * 4 - 3);
}
vec3 mix6(vec3 c1, vec3 c2, vec3 c3, vec3 c4, vec3 c5, vec3 c6, float x) {
@@ -107,8 +105,7 @@ vec3 mix6(vec3 c1, vec3 c2, vec3 c3, vec3 c4, vec3 c5, vec3 c6, float x) {
+ step(0.2, x) * istep(0.4, x) * mix(c2, c3, x * 5 - 1)
+ step(0.4, x) * istep(0.6, x) * mix(c3, c4, x * 5 - 2)
+ step(0.6, x) * istep(0.8, x) * mix(c4, c5, x * 5 - 3)
+ step(0.8, x) * mix(c5, c6, x * 5 - 4)
;
+ step(0.8, x) * mix(c5, c6, x * 5 - 4);
}
float mean(vec3 v)
@@ -123,10 +120,10 @@ float mean(vec4 v)
// OTHER
mat2 rot(float angle){
mat2 rot(float angle) {
return mat2(
cos(angle*2.*PI),-sin(angle*2.*PI),
sin(angle*2.*PI),cos(angle*2.*PI)
cos(angle * 2. * PI), -sin(angle * 2. * PI),
sin(angle * 2. * PI), cos(angle * 2. * PI)
);
}
@@ -141,18 +138,18 @@ vec2 kal(vec2 uv, float n) {
float q = 3.0 / (2.0 * PI);
t = abs(mod(t + PI / (n), 2 * PI / n) - PI / (n));
return length(uv) * vec2(
cos(t),
sin(t)
);
cos(t),
sin(t)
);
}
vec2 kal2(vec2 uv, float n) {
float t = atan(uv.y, uv.x) + PI * 0.5;
float t2 = abs(mod(t + PI / n, 2 * PI / n) - PI / n);
return length(uv) * vec2(
cos(t2),
sin(t2)
);
cos(t2),
sin(t2)
);
}
// NOISE
@@ -182,15 +179,15 @@ float v_index(vec2 uv) {
return floor(uv.x) + floor(uv.y) * 45;
}
vec2 v_pos(float i) {
int iTimeId = int(iBeats);
float iTimeV = iBeats - iTimeId;
vec2 v_pos(float i, int seed, float time) {
int iTimeId = int(time);
float iTimeV = time - iTimeId;
float x0 = rand(i + 823 + iTimeId);
float y0 = rand(i + 328 + iTimeId);
float x0 = rand(i + seed + iTimeId);
float y0 = rand(i + seed + 10 + iTimeId);
float x1 = rand(i + 823 + iTimeId + 1);
float y1 = rand(i + 328 + iTimeId + 1);
float x1 = rand(i + seed + iTimeId + 1);
float y1 = rand(i + seed + 10 + iTimeId + 1);
return vec2(
mix(x0, x1, ease(ease(iTimeV))),
@@ -198,7 +195,7 @@ vec2 v_pos(float i) {
);
}
vec4 voronoi(vec2 uv, float dist) {
vec4 voronoi(vec2 uv, float dist, int seed, float time) {
vec4 o = vec4(0, 0, 2, 0);
vec4 t = vec4(0, 0, 2, 0);
float d, i;
@@ -207,7 +204,7 @@ vec4 voronoi(vec2 uv, float dist) {
for (int dy = -1; dy <= 1; dy++) {
uv2 = vec2(floor(uv.x) + dx, floor(uv.y) + dy);
i = v_index(uv2);
p = uv2 + v_pos(i) * dist;
p = uv2 + v_pos(i, seed, time) * dist;
d = length(p - uv);
if (d < o.z) {
t = o;
@@ -260,9 +257,9 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
if (abs(p.y) > abs(p.x)) {
k = vec2(
uv.x - p.x * uv.y / p.y,
uv.y / p.y
);
uv.x - p.x * uv.y / p.y,
uv.y / p.y
);
return step(k.x, thick * 0.5)
* step(-k.x, thick * 0.5)
@@ -270,9 +267,9 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
* (1 - step(k.y, 0));
} else {
k = vec2(
uv.x / p.x,
uv.y - p.y * uv.x / p.x
);
uv.x / p.x,
uv.y - p.y * uv.x / p.x
);
return step(k.y, thick * 0.5)
* step(-k.y, thick * 0.5)
@@ -281,7 +278,16 @@ float line(vec2 uv, vec2 p1, vec2 p2, float thick) {
}
}
const mat2x2 ISOMETRIC_MATRIX = {{0.5, 1}, {0.5, -1}};
const mat2x2 ISOMETRIC_MATRIX = {
{
0.5,
1
},
{
0.5,
-1
}
};
vec2 iso(vec2 p) {
return p * ISOMETRIC_MATRIX;
@@ -302,14 +308,14 @@ vec2 iso(vec3 uv) {
vec4 reframe(sampler2D tex, vec2 uv)
{
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
uv = saw(uv);
return texture(tex, uv);
}
vec4 reframe_b(sampler2D tex, vec2 uv)
{
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
uv = uv * vec2(iResolution.y / iResolution.x, 1) + .5;
return texture(tex, uv);
}
+141 -113
View File
@@ -101,7 +101,139 @@ subroutine ( src_stage_sub ) vec4 src_3(vec2 vUV, int seed, vec3 b1, vec2 f1, ve
return vec4(f);
}
// SRC 4 : circuit
// // SRC 4 : circuit
// subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
// {
// // start
// vec2 uv0 = vUV.st;
// float ratio = iResolution.x / iResolution.y;
// vec2 uv1 = (uv0 - .5) * vec2(ratio, 1);
// // controls
// float z = 10 + magic(f1, b1, 123) * 20;
// float h = magic(f2, b2, seed + 20) * 0.8 + 0.1;
// float v = magic_reverse(f3, b3, seed + 30) * 0.8 + 0.1;
// // logic
// uv1 *= z;
// uv1 += iBeats;
// float s0 = rand(floor(mod(uv1, 1000))) * 1000;
// float s1 = rand(floor(mod(uv1 + vec2(0, 1), 1000))) * 1000;
// float s2 = rand(floor(mod(uv1 - vec2(1, 0), 1000))) * 1000;
// bool up = rand(s1 + 1) < h;
// bool left = rand(s2 + 2) < v;
// bool down = rand(s0 + 1) < h;
// bool right = rand(s0 + 2) < v;
// bool up_down = up && down;
// bool left_right = left && right;
// uv1 = mod(uv1, 1.0) - 0.5;
// const float t = 0.1;
// float f = 0;
// int c = 0;
// if (up) {
// f += stripe(uv1.x, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.y);
// c += 1;
// }
// if (down) {
// f += stripe(uv1.x, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.y);
// c += 1;
// }
// if (left) {
// f += stripe(uv1.y, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.x);
// c += 1;
// }
// if (right) {
// f += stripe(uv1.y, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.x);
// c += 1;
// }
// if (c == 1) {
// f += istep(t, length(uv1));
// }
// f = min(f, 1);
// if ((up_down ^^ left_right) && c == 2) {
// if (up_down) {
// uv1.xy = uv1.yx;
// }
// if (rand(s0 + 3) < 0.5) {
// uv1.x = -uv1.x;
// }
// float k = rand(s0 + 4) * 60;
// f -= rect(uv1, vec2(0), vec2(t * 3, t));
// f = max(0, f);
// if (k < 10) { // resistor
// f += line(uv1, vec2(-t * 3.25, -t * 0.5), vec2(-t * 2.5, t * 2), t * 0.75);
// f += line(uv1, vec2(-t * 2.5, t * 2), vec2(-t * 1.5, -t * 2), t * 0.75);
// f += line(uv1, vec2(-t * 1.5, -t * 2), vec2(-t * 0.5, t * 2), t * 0.75);
// f += line(uv1, vec2(-t * 0.5, t * 2), vec2(t * 0.5, -t * 2), t * 0.75);
// f += line(uv1, vec2(t * 0.5, -t * 2), vec2(t * 1.5, t * 2), t * 0.75);
// f += line(uv1, vec2(t * 1.5, t * 2), vec2(t * 2.5, -t * 2), t * 0.75);
// f += line(uv1, vec2(t * 2.5, -t * 2), vec2(t * 3.25, t * 0.5), t * 0.75);
// } else if (k < 20) { // capacitor
// f += rect(uv1, vec2(-t * 2, 0), vec2(t, t * 0.5));
// f += rect(uv1, vec2(t * 2, 0), vec2(t, t * 0.5));
// f += rect(uv1, vec2(t, 0), vec2(t * 0.5, t * 3.5));
// f += rect(uv1, vec2(-t, 0), vec2(t * 0.5, t * 3.5));
// } else if (k < 30) { // diode
// f += line(uv1, vec2(-t * 2, t * 2.5), vec2(t * 2, 0), t);
// f += line(uv1, vec2(-t * 2, -t * 2.5), vec2(t * 2, 0), t);
// f += rect(uv1, vec2(t * 2.5, 0), vec2(t * 0.5, t * 3));
// f += rect(uv1, vec2(-t * 2.5, 0), vec2(t * 0.5, t * 3));
// } else if (k < 40) { // lamp
// f += istep(t * 3.5, length(uv1));
// f -= istep(t * 2.5, length(uv1));
// f += line(uv1, vec2(-t * 2), vec2(t * 2), t);
// f += line(uv1, vec2(-t * 2, t * 2), vec2(t * 2, -t * 2), t);
// } else if (k < 50) { // inductor
// f += istep(t * 2, length(uv1 - vec2(t * 2.5, 0)));
// f += istep(t * 2, length(uv1 - vec2(0, 0)));
// f += istep(t * 2, length(uv1 - vec2(-t * 2.5, 0)));
// f -= 2 * istep(t, length(uv1 - vec2(t * 2.5, 0)));
// f -= 2 * istep(t, length(uv1 - vec2(0, 0)));
// f -= 2 * istep(t, length(uv1 - vec2(-t * 2.5, 0)));
// f *= step(-t * 0.5, uv1.y);
// } else if (k < 60) { // switch
// f += istep(t, length(uv1 - vec2(t * 2.5, 0)));
// f += istep(t, length(uv1 + vec2(t * 2.5, 0)));
// f += line(uv1, vec2(t * 2, 0), vec2(-t * 2.5, t * (k < 55 ? 3 : 1)), t);
// }
// } else if (c == 3) {
// if (left_right) {
// uv1.xy = uv1.yx;
// if (up) {
// uv1.x = -uv1.x;
// }
// } else if (right) {
// uv1.x = -uv1.x;
// }
// float k = rand(s0 + 4) * 20;
// if (k < 10) {
// f -= rect(uv1, vec2(0), vec2(t * 3));
// f = max(0, f);
// f += rect(uv1, vec2(-t * 3, 0), vec2(t * 0.5, t * 3));
// f += line(uv1, vec2(t * 0.25, t * 3.25), vec2(-t * 3, t), t);
// f += line(uv1, vec2(t * 0.25, -t * 3.25), vec2(-t * 3, -t), t);
// }
// }
// return vec4(f);
// }
// SRC 4 : bacteria
subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3)
{
// start
@@ -112,123 +244,19 @@ subroutine ( src_stage_sub ) vec4 src_4(vec2 vUV, int seed, vec3 b1, vec2 f1, ve
// controls
float z = 10 + magic(f1, b1, 123) * 20;
float h = magic(f2, b2, seed + 20) * 0.8 + 0.1;
float v = magic_reverse(f3, b3, seed + 30) * 0.8 + 0.1;
float zoom = 2 + magic(f1, b1, seed + 10) * 20;
float details = 5 * magic(f2, b2, seed + 20);
float delta = magic(f3, b3, seed + 30);
// logic
uv1 *= z;
uv1 += iBeats;
uv1 *= zoom;
float s0 = rand(floor(mod(uv1, 1000))) * 1000;
float s1 = rand(floor(mod(uv1 + vec2(0, 1), 1000))) * 1000;
float s2 = rand(floor(mod(uv1 - vec2(1, 0), 1000))) * 1000;
vec4 data = voronoi(uv1, 1, seed + 40, iBeats * 0.25);
bool up = rand(s1 + 1) < h;
bool left = rand(s2 + 2) < v;
bool down = rand(s0 + 1) < h;
bool right = rand(s0 + 2) < v;
bool up_down = up && down;
bool left_right = left && right;
float f = ease(data.x) + ease(data.y);
uv1 = mod(uv1, 1.0) - 0.5;
const float t = 0.1;
float f = 0;
int c = 0;
if (up) {
f += stripe(uv1.x, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.y);
c += 1;
}
if (down) {
f += stripe(uv1.x, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.y);
c += 1;
}
if (left) {
f += stripe(uv1.y, -t * 0.5, t * 0.5) * istep(t * 0.5, uv1.x);
c += 1;
}
if (right) {
f += stripe(uv1.y, -t * 0.5, t * 0.5) * step(-t * 0.5, uv1.x);
c += 1;
}
if (c == 1) {
f += istep(t, length(uv1));
}
f = min(f, 1);
if ((up_down ^^ left_right) && c == 2) {
if (up_down) {
uv1.xy = uv1.yx;
}
if (rand(s0 + 3) < 0.5) {
uv1.x = -uv1.x;
}
float k = rand(s0 + 4) * 60;
f -= rect(uv1, vec2(0), vec2(t * 3, t));
f = max(0, f);
if (k < 10) { // resistor
f += line(uv1, vec2(-t * 3.25, -t * 0.5), vec2(-t * 2.5, t * 2), t * 0.75);
f += line(uv1, vec2(-t * 2.5, t * 2), vec2(-t * 1.5, -t * 2), t * 0.75);
f += line(uv1, vec2(-t * 1.5, -t * 2), vec2(-t * 0.5, t * 2), t * 0.75);
f += line(uv1, vec2(-t * 0.5, t * 2), vec2(t * 0.5, -t * 2), t * 0.75);
f += line(uv1, vec2(t * 0.5, -t * 2), vec2(t * 1.5, t * 2), t * 0.75);
f += line(uv1, vec2(t * 1.5, t * 2), vec2(t * 2.5, -t * 2), t * 0.75);
f += line(uv1, vec2(t * 2.5, -t * 2), vec2(t * 3.25, t * 0.5), t * 0.75);
} else if (k < 20) { // capacitor
f += rect(uv1, vec2(-t * 2, 0), vec2(t, t * 0.5));
f += rect(uv1, vec2(t * 2, 0), vec2(t, t * 0.5));
f += rect(uv1, vec2(t, 0), vec2(t * 0.5, t * 3.5));
f += rect(uv1, vec2(-t, 0), vec2(t * 0.5, t * 3.5));
} else if (k < 30) { // diode
f += line(uv1, vec2(-t * 2, t * 2.5), vec2(t * 2, 0), t);
f += line(uv1, vec2(-t * 2, -t * 2.5), vec2(t * 2, 0), t);
f += rect(uv1, vec2(t * 2.5, 0), vec2(t * 0.5, t * 3));
f += rect(uv1, vec2(-t * 2.5, 0), vec2(t * 0.5, t * 3));
} else if (k < 40) { // lamp
f += istep(t * 3.5, length(uv1));
f -= istep(t * 2.5, length(uv1));
f += line(uv1, vec2(-t * 2), vec2(t * 2), t);
f += line(uv1, vec2(-t * 2, t * 2), vec2(t * 2, -t * 2), t);
} else if (k < 50) { // inductor
f += istep(t * 2, length(uv1 - vec2(t * 2.5, 0)));
f += istep(t * 2, length(uv1 - vec2(0, 0)));
f += istep(t * 2, length(uv1 - vec2(-t * 2.5, 0)));
f -= 2 * istep(t, length(uv1 - vec2(t * 2.5, 0)));
f -= 2 * istep(t, length(uv1 - vec2(0, 0)));
f -= 2 * istep(t, length(uv1 - vec2(-t * 2.5, 0)));
f *= step(-t * 0.5, uv1.y);
} else if (k < 60) { // switch
f += istep(t, length(uv1 - vec2(t * 2.5, 0)));
f += istep(t, length(uv1 + vec2(t * 2.5, 0)));
f += line(uv1, vec2(t * 2, 0), vec2(-t * 2.5, t * (k < 55 ? 3 : 1)), t);
}
} else if (c == 3) {
if (left_right) {
uv1.xy = uv1.yx;
if (up) {
uv1.x = -uv1.x;
}
} else if (right) {
uv1.x = -uv1.x;
}
float k = rand(s0 + 4) * 20;
if (k < 10) {
f -= rect(uv1, vec2(0), vec2(t * 3));
f = max(0, f);
f += rect(uv1, vec2(-t * 3, 0), vec2(t * 0.5, t * 3));
f += line(uv1, vec2(t * 0.25, t * 3.25), vec2(-t * 3, t), t);
f += line(uv1, vec2(t * 0.25, -t * 3.25), vec2(-t * 3, -t), t);
}
}
f = saw(f * (1 + data.x * details) - delta * 2.0);
return vec4(f);
}
@@ -254,7 +282,7 @@ subroutine ( src_stage_sub ) vec4 src_5(vec2 vUV, int seed, vec3 b1, vec2 f1, ve
vec2 uv2 = uv1;
uv2 *= zoom * 20 + 3;
uv2.x += iBeats;
vec4 data = voronoi(uv2, voronoi_distort);
vec4 data = voronoi(uv2, voronoi_distort, seed + 50, iBeats);
float f = data.x / (data.x + data.y);
f = sin(f * PI * (details * 20)) * 0.5 + 1;
int nf = int(noise_factor * 6);
Binary file not shown.
+10 -1
View File
@@ -114,7 +114,7 @@ static unsigned int parse_uint(const char *arg, const char *value) {
tmp_value = (unsigned long long)atoll(value);
if (tmp_value >= UINT_MAX) {
if (tmp_value > UINT_MAX) {
invalid_value(arg, value);
}
@@ -159,8 +159,14 @@ void args_parse(Parameters *params, int argc, char **argv) {
puts(PACKAGE " " VERSION);
exit(EXIT_SUCCESS);
} else if (is_arg(arg, "-p") || is_arg(arg, "--project")) {
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->project_path, value, STR_LEN);
} else if (is_arg(arg, "-c") || is_arg(arg, "--config")) {
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->config_file, value, STR_LEN);
} else if (is_arg(arg, "-hr") || is_arg(arg, "--hot-reload")) {
params->hot_reload = true;
@@ -218,6 +224,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
log_error("maximum video input reached");
exit(EXIT_FAILURE);
}
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN);
} else if (is_arg(arg, "-vb") || is_arg(arg, "--video-buffers")) {
+4
View File
@@ -13,6 +13,10 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value) {
}
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index) {
if (offsets.length == 0) {
return 0;
}
for (unsigned int i = offsets.length - 1; i > 0; i--) {
if (*index >= offsets.values[i]) {
*index -= offsets.values[i];
+9 -3
View File
@@ -68,8 +68,7 @@ void config_file_read(ConfigFile *config, const char *path) {
char *line;
char *rest;
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash,
item_compare, NULL, NULL);
config->map = NULL;
file_read(&file, path);
@@ -78,6 +77,9 @@ void config_file_read(ConfigFile *config, const char *path) {
return;
}
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash,
item_compare, NULL, NULL);
config->error = false;
line = strtok_r(file.content, "\n", &rest);
@@ -138,4 +140,8 @@ unsigned int config_file_get_int(const ConfigFile *config, const char *key,
return (unsigned int)atoi(item->value);
}
void config_file_free(const ConfigFile *config) { hashmap_free(config->map); }
void config_file_free(const ConfigFile *config) {
if (config->map != NULL) {
hashmap_free(config->map);
}
}
+2 -2
View File
@@ -3,7 +3,7 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
static char *vertex_shader_text =
static const char *vertex_shader_text =
"#version 460\n"
"const mat4 mvp = "
"{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n"
@@ -19,4 +19,4 @@ static const Vertex vertices[6] = {{{0.0f, 0.0f}}, {{0.0f, 1.0f}},
{{1.0f, 1.0f}}, {{0.0f, 0.0f}},
{{1.0f, 1.0f}}, {{1.0f, 0.0f}}};
#endif /* CONSTANTS_H */
#endif /* CONSTANTS_H */
+17 -3
View File
@@ -26,6 +26,7 @@ bool file_should_update(const File *file) {
bool file_update(File *file) {
long length;
size_t read_length;
FILE *file_pointer;
// free remaining data
@@ -47,6 +48,12 @@ bool file_update(File *file) {
// read file length
fseek(file_pointer, 0, SEEK_END);
length = ftell(file_pointer);
if (length == -1L) {
file->error = true;
fclose(file_pointer);
log_error("Cannot get file length for '%s'", file->path);
return false;
}
// init buffer
fseek(file_pointer, 0, SEEK_SET);
file->content = malloc(length + 1);
@@ -57,7 +64,13 @@ bool file_update(File *file) {
return false;
}
// read file
fread(file->content, sizeof(char), length, file_pointer);
read_length = fread(file->content, sizeof(char), length, file_pointer);
if (read_length != (unsigned)length) {
file->error = true;
fclose(file_pointer);
log_error("Cannot read complete file '%s'", file->path);
return false;
}
// close file
fclose(file_pointer);
// append null byte
@@ -117,8 +130,9 @@ void file_write(const char *path, const StringArray *lines) {
fclose(file_pointer);
}
void file_free(const File *file) {
if (!file->error) {
void file_free(File *file) {
if (!file->error && file->content != NULL) {
free(file->content);
file->content = NULL;
}
}
+1 -1
View File
@@ -13,6 +13,6 @@ void file_write(const char *path, const StringArray *lines);
void file_dump(const char *path, const char *content);
void file_free(const File *file);
void file_free(File *file);
#endif /* FILE_H */
+46 -25
View File
@@ -85,7 +85,7 @@ static void init_inputs() {
for (unsigned int i = 0; i < init_params.video_in.length; i++) {
video_init(&video_captures.values[i], init_params.video_in.values[i],
init_params.video_size, init_params.video_buffers);
init_params.video_size, init_params.video_buffers, true);
if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width;
@@ -101,15 +101,19 @@ static void start_video_background_read(VideoCapture *video_capture,
Context *context, int input_index,
bool trace_fps) {
pthread_t thread;
struct VideoBackgroundReadArgs *process_args =
(struct VideoBackgroundReadArgs *)malloc(
sizeof(struct VideoBackgroundReadArgs));
VideoBackgroundReadArgs *process_args =
(VideoBackgroundReadArgs *)malloc(sizeof(VideoBackgroundReadArgs));
process_args->capture = video_capture;
process_args->context = context;
process_args->input_index = input_index;
process_args->trace_fps = trace_fps;
pthread_create(&thread, NULL, video_background_read, (void *)process_args);
pthread_detach(thread);
if (pthread_create(&thread, NULL, video_background_read,
(void *)process_args) == 0) {
pthread_detach(thread);
} else {
log_error("background video acquisition failed to start");
free(process_args);
}
}
static void *
@@ -121,7 +125,7 @@ background_reconnect_video_captures(__attribute__((unused)) void *args) {
if (video_captures.values[i].disconnected) {
video_free(&video_captures.values[i]);
video_init(&video_captures.values[i], init_params.video_in.values[i],
init_params.video_size, init_params.video_buffers);
init_params.video_size, init_params.video_buffers, false);
if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width;
@@ -147,8 +151,12 @@ static void start_video_captures() {
}
}
if (init_params.video_reconnect) {
pthread_create(&thread, NULL, background_reconnect_video_captures, NULL);
pthread_detach(thread);
if (pthread_create(&thread, NULL, background_reconnect_video_captures,
NULL) == 0) {
pthread_detach(thread);
} else {
log_info("background video capture reconnect failed to start");
}
}
}
@@ -192,26 +200,34 @@ static void midi_callback(unsigned char code, unsigned char value) {
static void start_state_background_write() {
pthread_t thread;
struct StateBackgroundWriteArgs *process_args =
(struct StateBackgroundWriteArgs *)malloc(
sizeof(struct StateBackgroundWriteArgs));
StateBackgroundWriteArgs *process_args =
(StateBackgroundWriteArgs *)malloc(sizeof(StateBackgroundWriteArgs));
process_args->context = &context;
process_args->state_config = project.state_config;
process_args->midi = &midi;
pthread_create(&thread, NULL, state_background_write, process_args);
pthread_detach(thread);
if (pthread_create(&thread, NULL, state_background_write, process_args) ==
0) {
pthread_detach(thread);
} else {
log_error("background writing failed to start");
free(process_args);
}
}
static void start_midi_background_listen() {
pthread_t thread;
struct MidiBackgroundListenArgs *process_args =
(struct MidiBackgroundListenArgs *)malloc(
sizeof(struct MidiBackgroundListenArgs));
MidiBackgroundListenArgs *process_args =
(MidiBackgroundListenArgs *)malloc(sizeof(MidiBackgroundListenArgs));
process_args->device = &midi;
process_args->context = &context;
process_args->event_callback = midi_callback;
pthread_create(&thread, NULL, midi_background_listen, process_args);
pthread_detach(thread);
if (pthread_create(&thread, NULL, midi_background_listen, process_args) ==
0) {
pthread_detach(thread);
} else {
log_error("background midi acquisition failed to start");
free(process_args);
}
}
static void *background_reconnect_midi(__attribute__((unused)) void *args) {
@@ -219,7 +235,8 @@ static void *background_reconnect_midi(__attribute__((unused)) void *args) {
while (!context.stop) {
sleep(1);
if (!midi.connected) {
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"),
false);
if (midi.connected) {
start_midi_background_listen();
}
@@ -231,15 +248,18 @@ static void *background_reconnect_midi(__attribute__((unused)) void *args) {
static void init_midi() {
pthread_t thread;
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"));
midi_open(&midi, config_file_get_str(&project.config, "MIDI_HW", "hw"), true);
if (midi.connected) {
start_midi_background_listen();
}
if (init_params.midi_reconnect) {
pthread_create(&thread, NULL, background_reconnect_midi, NULL);
pthread_detach(thread);
if (pthread_create(&thread, NULL, background_reconnect_midi, NULL) == 0) {
pthread_detach(thread);
} else {
log_error("background midi reconnect failed to start");
}
}
}
@@ -266,6 +286,7 @@ static bool init(const Parameters *params) {
window_startup(error_callback);
context.tex_resolution[0] = params->internal_size;
context.tex_resolution[1] = params->internal_size;
if (params->output) {
@@ -363,8 +384,6 @@ static void shutdown() {
state_save(&context, project.state_config);
}
shaders_free(&program);
if (window_output != NULL) {
window_use(window_output, &context);
@@ -377,6 +396,8 @@ static void shutdown() {
shaders_free_window(&program, init_params.output);
}
shaders_free(&program);
#ifdef VIDEO_IN
free_video_captures();
#endif /* VIDEO_IN */
+28 -10
View File
@@ -6,19 +6,30 @@
#include "config.h"
void midi_open(MidiDevice *device, const char *name) {
void snd_no_log(__attribute__((unused)) int prio,
__attribute__((unused)) int interface,
__attribute__((unused)) const char *file,
__attribute__((unused)) int line,
__attribute__((unused)) const char *function,
__attribute__((unused)) int errcode,
__attribute__((unused)) const char *fmt,
__attribute__((unused)) va_list arg) {}
void midi_open(MidiDevice *device, const char *name, bool log_error) {
strlcpy(device->name, name, STR_LEN);
device->connected = false;
device->input = NULL;
device->output = NULL;
snd_rawmidi_open(&device->input, &device->output, name, SND_RAWMIDI_NONBLOCK);
device->connected = device->input != NULL && device->output != NULL;
if (device->connected) {
log_info("(%s) MIDI open", name);
} else {
log_warn("(%s) MIDI open failed", name);
device->connected = snd_rawmidi_open(&device->input, &device->output, name,
SND_RAWMIDI_SYNC) == 0 &&
device->input != NULL && device->output != NULL;
if (log_error) {
if (device->connected) {
log_info("(%s) MIDI open", name);
} else {
log_warn("(%s) MIDI open failed", name);
}
}
}
@@ -45,7 +56,7 @@ void midi_close(MidiDevice *device) {
}
void *midi_background_listen(void *args) {
MidiBackgroundReadArgs *process_args = (MidiBackgroundReadArgs *)args;
MidiBackgroundListenArgs *process_args = (MidiBackgroundListenArgs *)args;
MidiDevice *device = process_args->device;
Context *context = process_args->context;
@@ -57,6 +68,12 @@ void *midi_background_listen(void *args) {
snd_rawmidi_info_malloc(&info);
if (info == NULL) {
log_error("(%s) failed to allocate MIDI info", device->name);
free(process_args);
pthread_exit(NULL);
}
while (!context->stop && snd_rawmidi_info(device->output, info) == 0) {
bytes_read = snd_rawmidi_read(device->input, buffer, 3);
if (bytes_read == 3) {
@@ -73,5 +90,6 @@ void *midi_background_listen(void *args) {
log_info("(%s) background acquisition stopped after error", device->name);
midi_close(device);
}
free(process_args);
pthread_exit(NULL);
}
+1 -1
View File
@@ -3,7 +3,7 @@
#ifndef MIDI_H
#define MIDI_H
void midi_open(MidiDevice *device, const char *name);
void midi_open(MidiDevice *device, const char *name, bool log_error);
void midi_write(MidiDevice device, unsigned char code, unsigned char value);
void *midi_background_listen(void *args);
void midi_close(MidiDevice *device);
+10 -1
View File
@@ -48,6 +48,8 @@ static bool parse_fragment_shader_file(Project *project, unsigned int i) {
include_end - project->fragment_shaders[i][0].content,
tmp_file.content);
free(project->fragment_shaders[i][0].content);
project->fragment_shaders[i][0].content = new_content;
file_free(&tmp_file);
@@ -102,6 +104,12 @@ void project_init(Project *project, const char *project_path,
project->sub_counts.length = project->frag_count;
for (unsigned int i = 0; i < project->frag_count; i++) {
for (unsigned int j = 0; j < MAX_SUB_FILE + 1; j++) {
project->fragment_shaders[i][j].content = NULL;
}
}
for (unsigned int i = 0; i < project->frag_count; i++) {
project->sub_counts.values[i] = 0;
if (!read_fragment_shader_file(project, frag_prefix, i)) {
@@ -134,9 +142,10 @@ void project_reload(Project *project, void (*reload_callback)(unsigned int)) {
}
}
void project_free(const Project *project) {
void project_free(Project *project) {
for (unsigned int i = 0; i < project->frag_count; i++) {
file_free(&project->fragment_shaders[i][0]);
// other sub files contents are freed at parse_fragment_shader_file
}
config_file_free(&project->config);
+1 -1
View File
@@ -8,6 +8,6 @@ void project_init(Project *project, const char *project_path,
void project_reload(Project *project, void (*reload_callback)(unsigned int));
void project_free(const Project *project);
void project_free(Project *project);
#endif /* PROJECT_H */
+3 -3
View File
@@ -4,7 +4,7 @@ static unsigned long long mcg_state = 0xcafef00dd15ea5e5u; // Must be odd
static unsigned long long const multiplier = 6364136223846793005u;
// https://en.wikipedia.org/wiki/Permuted_congruential_generator
static unsigned long rand(void) {
static unsigned long fast_rand(void) {
unsigned long long x = mcg_state;
unsigned count = (unsigned)(x >> 61);
@@ -15,9 +15,9 @@ static unsigned long rand(void) {
void rand_set_seed(unsigned long long seed) {
mcg_state = 2 * seed + 1;
(void)rand();
(void)fast_rand();
}
unsigned int rand_uint(const unsigned int max) {
return max == 0 ? 0 : (unsigned int)(rand() % max);
return max == 0 ? 0 : (unsigned int)(fast_rand() % max);
}
+33 -12
View File
@@ -24,7 +24,7 @@
#include <GLFW/glfw3native.h>
#endif /* VIDEO_IN */
static const GLuint unused_uniform = (GLuint)-1;
static const GLint UNUSED_UNIFORM = -1;
static bool check_glerror_ro(const char *context) {
unsigned int code;
@@ -66,7 +66,7 @@ static bool check_eglerror_ro(const char *context) {
code = eglGetError();
if (code > 0 && code != EGL_SUCCESS) {
if (code != EGL_SUCCESS) {
log_warn("EGL Error: %04x (%s)", code, context);
return true;
}
@@ -411,7 +411,7 @@ static bool compile_shader(GLuint shader_id, const char *name,
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
check_glerror_ro("compile_shader/glGetShaderiv");
glGetShaderInfoLog(shader_id, 1024, NULL, (GLchar *)&log);
glGetShaderInfoLog(shader_id, STR_LEN, NULL, (GLchar *)log);
check_glerror_ro("compile_shader/glGetShaderInfoLog");
if (status_params == GL_FALSE) {
@@ -462,6 +462,8 @@ static bool init_single_program(ShaderProgram *program, unsigned int i,
unsigned int index2;
char name[STR_LEN];
const char *prefix;
GLint link_status;
char link_log[STR_LEN];
program->programs[i] = glCreateProgram();
if (check_glerror(program, "init_single_program/glCreateProgram")) {
@@ -479,6 +481,19 @@ static bool init_single_program(ShaderProgram *program, unsigned int i,
return false;
}
glGetProgramiv(program->programs[i], GL_LINK_STATUS, &link_status);
if (check_glerror(program, "init_single_program/glGetProgramiv")) {
return false;
}
if (link_status != GL_TRUE) {
glGetProgramInfoLog(program->programs[i], STR_LEN, NULL, link_log);
if (check_glerror(program, "init_single_program/glGetProgramInfoLog")) {
return false;
}
log_error("Program %d link error: %s", i + 1, link_log);
return false;
}
// create uniforms pointers
program->itime_locations[i] = glGetUniformLocation(
program->programs[i],
@@ -651,27 +666,27 @@ static void update_viewport(ShaderProgram *program, const Context *context) {
}
}
static void write_uniform_1f(GLuint location, float value) {
if (location != unused_uniform) {
static void write_uniform_1f(GLint location, float value) {
if (location != UNUSED_UNIFORM) {
glUniform1f(location, value);
}
}
static void write_uniform_1i(GLuint location, unsigned int value) {
if (location != unused_uniform) {
static void write_uniform_1i(GLint location, unsigned int value) {
if (location != UNUSED_UNIFORM) {
glUniform1i(location, (const GLint)value);
}
}
static void write_uniform_2f(GLuint location, const vec2 *value) {
if (location != unused_uniform) {
static void write_uniform_2f(GLint location, const vec2 *value) {
if (location != UNUSED_UNIFORM) {
glUniform2fv(location, 1, (const GLfloat *)value);
}
}
static void write_uniform_multi_3f(GLuint location, unsigned int count,
static void write_uniform_multi_3f(GLint location, unsigned int count,
const vec3 *value) {
if (location != unused_uniform) {
if (location != UNUSED_UNIFORM) {
glUniform3fv(location, count, (const GLfloat *)value);
}
}
@@ -759,7 +774,7 @@ static void use_program(const ShaderProgram *program, int i, bool output,
if (program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
j * program->sub_variant_count + k] !=
unused_uniform) {
UNUSED_UNIFORM) {
subroutines[subcount++] =
program->sub_locations[i * program->sub_variant_count *
program->sub_type_count +
@@ -935,6 +950,12 @@ void shaders_free(const ShaderProgram *program) {
}
check_glerror_ro("shaders_free/glDeleteProgram");
glDeleteShader(program->vertex_shader);
for (unsigned int i = 0; i < program->frag_count; i++) {
glDeleteShader(program->fragment_shaders[i]);
}
check_glerror_ro("shaders_free/glDeleteShader");
glDeleteFramebuffers(program->frag_count, program->frame_buffers);
check_glerror_ro("shaders_free/glDeleteFramebuffers");
+95 -27
View File
@@ -184,29 +184,65 @@ static void save_to_file(const Context *context, StateConfig state_config,
snprintf(lines.values[lines.length++], STR_LEN, "tempo=%d",
(unsigned int)context->tempo.tempo);
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
snprintf(lines.values[lines.length++], STR_LEN, "page=%d", context->page);
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
snprintf(lines.values[lines.length++], STR_LEN, "selected=%d",
context->selected);
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
for (unsigned int i = 0; i < context->state.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i,
context->seeds[i]);
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
snprintf(lines.values[lines.length++], STR_LEN, "state_%d=%d", i,
context->state.values[i]);
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
}
for (unsigned int i = 0; i < state_config.group_active_counts.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i,
context->active[i]);
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
}
for (unsigned int i = 0; i < state_config.value_count; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i,
(unsigned int)(context->values[i][0] * MIDI_MAX));
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_y=%d", i,
(unsigned int)(context->values[i][1] * MIDI_MAX));
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_z=%d", i,
(unsigned int)(context->values[i][2] * MIDI_MAX));
if (lines.length > ARRAY_SIZE) {
log_error("Too many values to save");
return;
}
}
file_write(state_file, &lines);
@@ -234,10 +270,14 @@ static void save_to_index_file(const Context *context, StateConfig state_config,
void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
unsigned int offset;
unsigned int count;
unsigned int length;
char name[STR_LEN];
state_config->select_page_codes.length =
config_file_get_int(config, "SELECT_PAGE_COUNT", 0);
length = config_file_get_int(config, "SELECT_PAGE_COUNT", 0);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->select_page_codes.length = length;
for (unsigned int i = 0; i < state_config->select_page_codes.length; i++) {
snprintf(name, STR_LEN, "SELECT_PAGE_%d", i + 1);
@@ -245,8 +285,11 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
config_file_get_int(config, name, UNSET_MIDI_CODE);
}
state_config->select_item_codes.length =
config_file_get_int(config, "SELECT_ITEM_COUNT", 0);
length = config_file_get_int(config, "SELECT_ITEM_COUNT", 0);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->select_item_codes.length = length;
for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
snprintf(name, STR_LEN, "SELECT_ITEM_%d", i + 1);
@@ -257,8 +300,11 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
state_config->state_max = state_config->select_page_codes.length *
state_config->select_item_codes.length;
state_config->select_frag_codes.length =
config_file_get_int(config, "FRAG_COUNT", 1);
length = config_file_get_int(config, "FRAG_COUNT", 1);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->select_frag_codes.length = length;
for (unsigned int i = 0; i < state_config->select_frag_codes.length; i++) {
snprintf(name, STR_LEN, "SELECT_FRAG_%d", i + 1);
@@ -266,11 +312,14 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
config_file_get_int(config, name, UNSET_MIDI_CODE);
}
length = config_file_get_int(config, "GROUP_COUNT", 0);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->group_active_counts.length = state_config->group_counts.length =
state_config->group_active_offsets.length =
state_config->group_offsets.length =
state_config->values_offsets.length =
config_file_get_int(config, "GROUP_COUNT", 0);
state_config->values_offsets.length = length;
count = 0;
for (unsigned int i = 0; i < state_config->group_active_counts.length; i++) {
@@ -307,27 +356,40 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
state_config->value_count = offset;
length = count * 3;
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->codes.length = count * 3;
for (unsigned int i = 0; i < state_config->group_counts.length; i++) {
offset = state_config->group_offsets.values[i];
for (unsigned int j = 0; j < state_config->group_counts.values[i]; j++) {
snprintf(name, STR_LEN, "GROUP_%d_%d_X", i + 1, j + 1);
state_config->codes.values[(offset + j) * 3] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
if ((offset + j) * 3 < ARRAY_SIZE) {
snprintf(name, STR_LEN, "GROUP_%d_%d_X", i + 1, j + 1);
state_config->codes.values[(offset + j) * 3] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
}
snprintf(name, STR_LEN, "GROUP_%d_%d_Y", i + 1, j + 1);
state_config->codes.values[(offset + j) * 3 + 1] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
if ((offset + j) * 3 + 1 < ARRAY_SIZE) {
snprintf(name, STR_LEN, "GROUP_%d_%d_Y", i + 1, j + 1);
state_config->codes.values[(offset + j) * 3 + 1] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
}
snprintf(name, STR_LEN, "GROUP_%d_%d_Z", i + 1, j + 1);
state_config->codes.values[(offset + j) * 3 + 2] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
if ((offset + j) * 3 + 2 < ARRAY_SIZE) {
snprintf(name, STR_LEN, "GROUP_%d_%d_Z", i + 1, j + 1);
state_config->codes.values[(offset + j) * 3 + 2] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
}
}
}
state_config->fader_codes.length =
config_file_get_int(config, "FADER_COUNT", 0);
length = config_file_get_int(config, "FADER_COUNT", 0);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->fader_codes.length = length;
for (unsigned int i = 0; i < state_config->fader_codes.length; i++) {
snprintf(name, STR_LEN, "FADER_%d", i + 1);
@@ -358,8 +420,11 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
config_file_get_int(config, "KEY_TEMPO_UP", 1265);
if (config_file_has(config, "KEY_LOAD_COUNT")) {
state_config->key_load.length =
config_file_get_int(config, "KEY_LOAD_COUNT", 0);
length = config_file_get_int(config, "KEY_LOAD_COUNT", 0);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->key_load.length = length;
for (unsigned int i = 0; i < state_config->key_load.length; i++) {
snprintf(name, STR_LEN, "KEY_LOAD_%d", i + 1);
@@ -380,8 +445,11 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
}
if (config_file_has(config, "KEY_SAVE_COUNT")) {
state_config->key_save.length =
config_file_get_int(config, "KEY_SAVE_COUNT", 0);
length = config_file_get_int(config, "KEY_SAVE_COUNT", 0);
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->key_save.length = length;
for (unsigned int i = 0; i < state_config->key_save.length; i++) {
snprintf(name, STR_LEN, "KEY_SAVE_%d", i + 1);
@@ -513,10 +581,9 @@ static bool compute_event(Context *context, StateConfig state_config,
if (code == state_config.key_autorand) {
if (value > 0) {
log_info((context->auto_random ? "[%d] Auto Random OFF"
: "[%d] Auto Random ON"),
code);
context->auto_random = !context->auto_random;
log_info("[%d] Auto Random %s", code,
context->auto_random ? "ON" : "OFF");
}
return true;
}
@@ -552,7 +619,7 @@ static bool compute_event(Context *context, StateConfig state_config,
if (context->tempo.tempo > 0) {
tempo_set(&context->tempo, context->tempo.tempo - 1);
}
log_info("[%d] Tempo: %f", code, context->tempo);
log_info("[%d] Tempo: %f", code, context->tempo.tempo);
}
return true;
}
@@ -643,6 +710,7 @@ void *state_background_write(void *args) {
}
log_info("(state) background writing stopped by main thread");
free(process_args);
pthread_exit(NULL);
}
+9 -1
View File
@@ -15,7 +15,7 @@ unsigned int string_trim(char *str) {
start = 0;
end = strnlen(str, STR_LEN) - 1;
if (end == 0) {
if (end <= 0) {
return 0;
}
@@ -62,11 +62,19 @@ char *string_replace_at(const char *src, unsigned int from, unsigned int to,
unsigned long rpl_len;
char *dst;
if (to < from) {
return "";
}
src_len = strnlen(src, STR_LEN * STR_LEN);
rpl_len = strnlen(rpl, STR_LEN * STR_LEN);
dst = malloc(src_len - (to - from) + rpl_len + 1);
if (dst == NULL) {
return "";
}
strlcpy(dst, src, from + 1);
strlcpy(dst + from, rpl, rpl_len + 1);
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
+6 -12
View File
@@ -1,19 +1,13 @@
#include <math.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include "types.h"
#include "config.h"
#include "tempo.h"
static long now() {
struct timeval now;
gettimeofday(&now, NULL);
return now.tv_sec * 1000 + now.tv_usec / 1000;
}
static long now_ms() { return 1000 * clock() / CLOCKS_PER_SEC; }
static void reset_tap_chain(Tempo *tempo, long t) {
tempo->last_reset = t;
@@ -93,7 +87,7 @@ static void add_tap_to_chain(Tempo *tempo, long t) {
void tempo_init(Tempo *tempo, float value) {
long t;
t = now();
t = now_ms();
reset_tap_chain(tempo, t);
@@ -105,7 +99,7 @@ void tempo_set(Tempo *tempo, float value) {
long t;
long progress;
t = now();
t = now_ms();
progress = (t - tempo->last_reset) % tempo->beat_length;
@@ -118,7 +112,7 @@ void tempo_set(Tempo *tempo, float value) {
void tempo_tap(Tempo *tempo) {
long t;
t = now();
t = now_ms();
if (!is_chain_active(*tempo, t)) {
reset_tap_chain(tempo, t);
@@ -130,7 +124,7 @@ void tempo_tap(Tempo *tempo) {
double tempo_total(const Tempo *tempo) {
long t;
t = now();
t = now_ms();
return (double)(t - tempo->last_reset) / (double)tempo->beat_length;
}
+7 -8
View File
@@ -1,4 +1,5 @@
#include <sys/time.h>
#include <limits.h>
#include <time.h>
#include "types.h"
@@ -7,24 +8,22 @@
void timer_init(Timer *timer, const unsigned int target) {
timer->counter = 0;
timer->target = target;
gettimeofday(&timer->start, NULL);
timer->start = clock();
}
bool timer_inc(Timer *timer) {
timer->counter += 1;
return timer->counter >= timer->target;
return timer->counter == UINT_MAX || timer->counter >= timer->target;
}
double timer_reset(Timer *timer) {
struct timeval stop;
clock_t stop;
double secs;
double per_secs;
gettimeofday(&stop, NULL);
stop = clock();
secs = (double)(stop.tv_usec - timer->start.tv_usec) / 1000000 +
(double)(stop.tv_sec - timer->start.tv_sec);
secs = (double)(stop - timer->start) / CLOCKS_PER_SEC;
per_secs = (double)timer->counter / secs;
timer->start = stop;
+23 -23
View File
@@ -100,34 +100,34 @@ typedef struct ShaderProgram {
GLuint frame_buffers[ARRAY_SIZE];
GLuint fragment_shaders[ARRAY_SIZE];
GLuint itime_locations[ARRAY_SIZE];
GLuint itempo_locations[ARRAY_SIZE];
GLuint ibeats_locations[ARRAY_SIZE];
GLuint ifps_locations[ARRAY_SIZE];
GLuint ires_locations[ARRAY_SIZE];
GLuint itexres_locations[ARRAY_SIZE];
GLuint iinres_locations[ARRAY_SIZE];
GLuint iinfmt_locations[ARRAY_SIZE];
GLuint iinfps_locations[ARRAY_SIZE];
GLuint idemo_locations[ARRAY_SIZE];
GLuint iautorand_locations[ARRAY_SIZE];
GLuint iautorandcycle_locations[ARRAY_SIZE];
GLuint iseed_locations[ARRAY_SIZE];
GLuint istate_locations[ARRAY_SIZE];
GLuint ipage_locations[ARRAY_SIZE];
GLuint iselected_locations[ARRAY_SIZE];
GLuint iactive_locations[ARRAY_SIZE];
GLint itime_locations[ARRAY_SIZE];
GLint itempo_locations[ARRAY_SIZE];
GLint ibeats_locations[ARRAY_SIZE];
GLint ifps_locations[ARRAY_SIZE];
GLint ires_locations[ARRAY_SIZE];
GLint itexres_locations[ARRAY_SIZE];
GLint iinres_locations[ARRAY_SIZE];
GLint iinfmt_locations[ARRAY_SIZE];
GLint iinfps_locations[ARRAY_SIZE];
GLint idemo_locations[ARRAY_SIZE];
GLint iautorand_locations[ARRAY_SIZE];
GLint iautorandcycle_locations[ARRAY_SIZE];
GLint iseed_locations[ARRAY_SIZE];
GLint istate_locations[ARRAY_SIZE];
GLint ipage_locations[ARRAY_SIZE];
GLint iselected_locations[ARRAY_SIZE];
GLint iactive_locations[ARRAY_SIZE];
UintArray midi_lengths;
GLuint igroup_locations[ARRAY_SIZE];
GLint igroup_locations[ARRAY_SIZE];
GLuint vpos_locations[ARRAY_SIZE];
GLint vpos_locations[ARRAY_SIZE];
GLuint textures_locations[ARRAY_SIZE];
GLint textures_locations[ARRAY_SIZE];
unsigned int sub_type_count;
unsigned int sub_variant_count;
GLuint sub_locations[ARRAY_SIZE];
GLint sub_locations[ARRAY_SIZE];
unsigned int active_count;
@@ -232,7 +232,7 @@ typedef struct MidiBackgroundListenArgs {
MidiDevice *device;
Context *context;
void (*event_callback)(unsigned char code, unsigned char value);
} MidiBackgroundReadArgs;
} MidiBackgroundListenArgs;
// state.c
@@ -279,7 +279,7 @@ typedef struct StateBackgroundWriteArgs {
// timer.c
typedef struct Timer {
struct timeval start;
clock_t start;
unsigned int counter;
unsigned int target;
} Timer;
+56 -17
View File
@@ -70,14 +70,18 @@ static void ioctl_error(VideoCapture *video_capture, const char *operation,
video_capture->error = true;
}
static void open_device(VideoCapture *video_capture, const char *name) {
static void open_device(VideoCapture *video_capture, const char *name,
bool log_error) {
strlcpy(video_capture->name, name, STR_LEN);
video_capture->error = false;
video_capture->fd = -1;
video_capture->buf_count = 0;
video_capture->fd = open(name, O_RDWR | O_NONBLOCK);
if (video_capture->fd == -1) {
log_warn("(%s) Cannot open device", name);
if (log_error) {
log_warn("(%s) Cannot open device", name);
}
video_capture->error = true;
}
}
@@ -211,6 +215,9 @@ static bool request_buffers(VideoCapture *video_capture,
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
video_capture->buf_count = reqbuf.count;
for (unsigned int i = 0; i < reqbuf.count; i++) {
video_capture->exp_fd[i] = -1;
}
return true;
}
@@ -262,7 +269,7 @@ static bool open_stream(VideoCapture *video_capture) {
return true;
}
static void create_image_buffer(const VideoCapture *video_capture,
static bool create_image_buffer(VideoCapture *video_capture,
struct v4l2_buffer *buf, unsigned int index) {
memset(buf, 0, sizeof(*buf));
@@ -270,15 +277,24 @@ static void create_image_buffer(const VideoCapture *video_capture,
buf->memory = V4L2_MEMORY_MMAP;
buf->index = index;
ioctl(video_capture->fd, VIDIOC_QBUF, buf);
if (ioctl(video_capture->fd, VIDIOC_QBUF, buf) == -1) {
ioctl_error(video_capture, "VIDIOC_QBUF", "Could not enqueue buffer");
return false;
}
return true;
}
static void create_image_buffers(VideoCapture *video_capture) {
static bool create_image_buffers(VideoCapture *video_capture) {
unsigned int i;
for (i = 0; i < video_capture->buf_count; i++) {
create_image_buffer(video_capture, &video_capture->buf[i], i);
if (!create_image_buffer(video_capture, &video_capture->buf[i], i)) {
return false;
}
}
return true;
}
static void close_stream(const VideoCapture *video_capture) {
@@ -290,11 +306,15 @@ static unsigned int read_video(VideoCapture *video_capture) {
if (ioctl(video_capture->fd, VIDIOC_DQBUF,
&video_capture->buf[video_capture->buf_index]) != -1) {
ioctl(video_capture->fd, VIDIOC_QBUF,
&video_capture->buf[video_capture->buf_index]);
video_capture->buf_index =
(video_capture->buf_index + 1) % video_capture->buf_count;
return true;
if (ioctl(video_capture->fd, VIDIOC_QBUF,
&video_capture->buf[video_capture->buf_index]) == -1) {
video_capture->error = true;
return false;
} else {
video_capture->buf_index =
(video_capture->buf_index + 1) % video_capture->buf_count;
return true;
}
}
if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) {
@@ -305,38 +325,55 @@ static unsigned int read_video(VideoCapture *video_capture) {
}
void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height, unsigned int buffer_count) {
open_device(video_capture, name);
unsigned int preferred_height, unsigned int buffer_count,
bool log_error) {
open_device(video_capture, name, log_error);
if (video_capture->error) {
return;
}
if (!check_caps(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!get_available_sizes(video_capture, preferred_height)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!set_format(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!request_buffers(video_capture, buffer_count)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!export_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
if (!open_stream(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
create_image_buffers(video_capture);
if (!create_image_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return;
}
}
void *video_background_read(void *args) {
@@ -377,19 +414,21 @@ void *video_background_read(void *args) {
video_capture->disconnected = true;
context->input_formats[input_index] = 0;
}
free(process_args);
pthread_exit(NULL);
}
void video_free(const VideoCapture *video_capture) {
unsigned int i;
close_stream(video_capture);
for (i = 0; i < video_capture->buf_count; i++) {
close(video_capture->exp_fd[i]);
if (video_capture->exp_fd[i] != -1) {
close(video_capture->exp_fd[i]);
}
}
if (video_capture->fd != -1) {
close_stream(video_capture);
close(video_capture->fd);
}
}
+2 -1
View File
@@ -6,7 +6,8 @@
#ifdef VIDEO_IN
void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height, unsigned int buffer_count);
unsigned int preferred_height, unsigned int buffer_count,
bool log_error);
void *video_background_read(void *args);
+4 -3
View File
@@ -131,9 +131,10 @@ void window_use(Window *window, Context *context) {
glfwGetFramebufferSize(window, &width, &height);
context->resolution[0] = width;
context->resolution[1] = height;
context->tex_resolution[0] =
(int)(context->tex_resolution[1] * context->resolution[0] /
context->resolution[1]);
if (height > 0) {
context->tex_resolution[0] =
(int)(context->tex_resolution[1] * width / height);
}
}
void window_close(Window *window) {