42 Commits
Author SHA1 Message Date
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
23 changed files with 372 additions and 155 deletions
+2 -1
View File
@@ -68,7 +68,8 @@ valgrind: build/$(TARGET)
.PHONY: full-clean .PHONY: full-clean
full-clean: full-clean:
git clean -f -x git clean -f -x
rm -rf **/**/.deps rm -rf */*/.deps
rm -rf */.deps
.PHONY: test-release .PHONY: test-release
test-release: clean full-clean test-release: clean full-clean
-1
View File
@@ -11,7 +11,6 @@ AC_CHECK_HEADERS([stdlib.h])
AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/mman.h]) AC_CHECK_HEADERS([sys/mman.h])
AC_CHECK_HEADERS([sys/stat.h]) AC_CHECK_HEADERS([sys/stat.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([sys/types.h]) AC_CHECK_HEADERS([sys/types.h])
AC_CHECK_HEADERS([sys/wait.h]) AC_CHECK_HEADERS([sys/wait.h])
+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); tmp_value = (unsigned long long)atoll(value);
if (tmp_value >= UINT_MAX) { if (tmp_value > UINT_MAX) {
invalid_value(arg, value); invalid_value(arg, value);
} }
@@ -159,8 +159,14 @@ void args_parse(Parameters *params, int argc, char **argv) {
puts(PACKAGE " " VERSION); puts(PACKAGE " " VERSION);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else if (is_arg(arg, "-p") || is_arg(arg, "--project")) { } 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); strlcpy(params->project_path, value, STR_LEN);
} else if (is_arg(arg, "-c") || is_arg(arg, "--config")) { } 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); strlcpy(params->config_file, value, STR_LEN);
} else if (is_arg(arg, "-hr") || is_arg(arg, "--hot-reload")) { } else if (is_arg(arg, "-hr") || is_arg(arg, "--hot-reload")) {
params->hot_reload = true; params->hot_reload = true;
@@ -218,6 +224,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
log_error("maximum video input reached"); log_error("maximum video input reached");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (strlen(value) == 0) {
invalid_value(arg, value);
}
strlcpy(params->video_in.values[params->video_in.length++], value, strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN); STR_LEN);
} else if (is_arg(arg, "-vb") || is_arg(arg, "--video-buffers")) { } 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) { 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--) { for (unsigned int i = offsets.length - 1; i > 0; i--) {
if (*index >= offsets.values[i]) { if (*index >= offsets.values[i]) {
*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 *line;
char *rest; char *rest;
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash, config->map = NULL;
item_compare, NULL, NULL);
file_read(&file, path); file_read(&file, path);
@@ -78,6 +77,9 @@ void config_file_read(ConfigFile *config, const char *path) {
return; return;
} }
config->map = hashmap_new(sizeof(ConfigFileItem), 0, 0, 0, item_hash,
item_compare, NULL, NULL);
config->error = false; config->error = false;
line = strtok_r(file.content, "\n", &rest); 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); 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);
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
#ifndef CONSTANTS_H #ifndef CONSTANTS_H
#define CONSTANTS_H #define CONSTANTS_H
static char *vertex_shader_text = static const char *vertex_shader_text =
"#version 460\n" "#version 460\n"
"const mat4 mvp = " "const mat4 mvp = "
"{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n" "{{2.,0.,0.,0.},{0.,2.,0.,0.},{0.,0.,2.,0.},{-1.,-1.,1.,1.}};\n"
+17 -3
View File
@@ -26,6 +26,7 @@ bool file_should_update(const File *file) {
bool file_update(File *file) { bool file_update(File *file) {
long length; long length;
size_t read_length;
FILE *file_pointer; FILE *file_pointer;
// free remaining data // free remaining data
@@ -47,6 +48,12 @@ bool file_update(File *file) {
// read file length // read file length
fseek(file_pointer, 0, SEEK_END); fseek(file_pointer, 0, SEEK_END);
length = ftell(file_pointer); 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 // init buffer
fseek(file_pointer, 0, SEEK_SET); fseek(file_pointer, 0, SEEK_SET);
file->content = malloc(length + 1); file->content = malloc(length + 1);
@@ -57,7 +64,13 @@ bool file_update(File *file) {
return false; return false;
} }
// read file // 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 // close file
fclose(file_pointer); fclose(file_pointer);
// append null byte // append null byte
@@ -117,8 +130,9 @@ void file_write(const char *path, const StringArray *lines) {
fclose(file_pointer); fclose(file_pointer);
} }
void file_free(const File *file) { void file_free(File *file) {
if (!file->error) { if (!file->error && file->content != NULL) {
free(file->content); 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_dump(const char *path, const char *content);
void file_free(const File *file); void file_free(File *file);
#endif /* FILE_H */ #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++) { for (unsigned int i = 0; i < init_params.video_in.length; i++) {
video_init(&video_captures.values[i], init_params.video_in.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, true);
if (!video_captures.values[i].error) { if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width; 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, Context *context, int input_index,
bool trace_fps) { bool trace_fps) {
pthread_t thread; pthread_t thread;
struct VideoBackgroundReadArgs *process_args = VideoBackgroundReadArgs *process_args =
(struct VideoBackgroundReadArgs *)malloc( (VideoBackgroundReadArgs *)malloc(sizeof(VideoBackgroundReadArgs));
sizeof(struct VideoBackgroundReadArgs));
process_args->capture = video_capture; process_args->capture = video_capture;
process_args->context = context; process_args->context = context;
process_args->input_index = input_index; process_args->input_index = input_index;
process_args->trace_fps = trace_fps; process_args->trace_fps = trace_fps;
pthread_create(&thread, NULL, video_background_read, (void *)process_args); if (pthread_create(&thread, NULL, video_background_read,
pthread_detach(thread); (void *)process_args) == 0) {
pthread_detach(thread);
} else {
log_error("background video acquisition failed to start");
free(process_args);
}
} }
static void * static void *
@@ -121,7 +125,7 @@ background_reconnect_video_captures(__attribute__((unused)) void *args) {
if (video_captures.values[i].disconnected) { if (video_captures.values[i].disconnected) {
video_free(&video_captures.values[i]); video_free(&video_captures.values[i]);
video_init(&video_captures.values[i], init_params.video_in.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) { if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width; context.input_resolutions[i][0] = video_captures.values[i].width;
@@ -147,8 +151,12 @@ static void start_video_captures() {
} }
} }
if (init_params.video_reconnect) { if (init_params.video_reconnect) {
pthread_create(&thread, NULL, background_reconnect_video_captures, NULL); if (pthread_create(&thread, NULL, background_reconnect_video_captures,
pthread_detach(thread); 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() { static void start_state_background_write() {
pthread_t thread; pthread_t thread;
struct StateBackgroundWriteArgs *process_args = StateBackgroundWriteArgs *process_args =
(struct StateBackgroundWriteArgs *)malloc( (StateBackgroundWriteArgs *)malloc(sizeof(StateBackgroundWriteArgs));
sizeof(struct StateBackgroundWriteArgs));
process_args->context = &context; process_args->context = &context;
process_args->state_config = project.state_config; process_args->state_config = project.state_config;
process_args->midi = &midi; process_args->midi = &midi;
pthread_create(&thread, NULL, state_background_write, process_args); if (pthread_create(&thread, NULL, state_background_write, process_args) ==
pthread_detach(thread); 0) {
pthread_detach(thread);
} else {
log_error("background writing failed to start");
free(process_args);
}
} }
static void start_midi_background_listen() { static void start_midi_background_listen() {
pthread_t thread; pthread_t thread;
struct MidiBackgroundListenArgs *process_args = MidiBackgroundListenArgs *process_args =
(struct MidiBackgroundListenArgs *)malloc( (MidiBackgroundListenArgs *)malloc(sizeof(MidiBackgroundListenArgs));
sizeof(struct MidiBackgroundListenArgs));
process_args->device = &midi; process_args->device = &midi;
process_args->context = &context; process_args->context = &context;
process_args->event_callback = midi_callback; process_args->event_callback = midi_callback;
pthread_create(&thread, NULL, midi_background_listen, process_args); if (pthread_create(&thread, NULL, midi_background_listen, process_args) ==
pthread_detach(thread); 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) { 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) { while (!context.stop) {
sleep(1); sleep(1);
if (!midi.connected) { 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) { if (midi.connected) {
start_midi_background_listen(); start_midi_background_listen();
} }
@@ -231,15 +248,18 @@ static void *background_reconnect_midi(__attribute__((unused)) void *args) {
static void init_midi() { static void init_midi() {
pthread_t thread; 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) { if (midi.connected) {
start_midi_background_listen(); start_midi_background_listen();
} }
if (init_params.midi_reconnect) { if (init_params.midi_reconnect) {
pthread_create(&thread, NULL, background_reconnect_midi, NULL); if (pthread_create(&thread, NULL, background_reconnect_midi, NULL) == 0) {
pthread_detach(thread); 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); window_startup(error_callback);
context.tex_resolution[0] = params->internal_size;
context.tex_resolution[1] = params->internal_size; context.tex_resolution[1] = params->internal_size;
if (params->output) { if (params->output) {
@@ -363,8 +384,6 @@ static void shutdown() {
state_save(&context, project.state_config); state_save(&context, project.state_config);
} }
shaders_free(&program);
if (window_output != NULL) { if (window_output != NULL) {
window_use(window_output, &context); window_use(window_output, &context);
@@ -377,6 +396,8 @@ static void shutdown() {
shaders_free_window(&program, init_params.output); shaders_free_window(&program, init_params.output);
} }
shaders_free(&program);
#ifdef VIDEO_IN #ifdef VIDEO_IN
free_video_captures(); free_video_captures();
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
+32 -8
View File
@@ -6,19 +6,36 @@
#include "config.h" #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); strlcpy(device->name, name, STR_LEN);
device->connected = false;
device->input = NULL; device->input = NULL;
device->output = NULL; device->output = NULL;
snd_rawmidi_open(&device->input, &device->output, name, SND_RAWMIDI_NONBLOCK); if (!log_error) {
snd_lib_log_set_handler(snd_no_log);
}
device->connected = device->input != NULL && device->output != NULL; device->connected = snd_rawmidi_open(&device->input, &device->output, name,
SND_RAWMIDI_SYNC) == 0 &&
if (device->connected) { device->input != NULL && device->output != NULL;
log_info("(%s) MIDI open", name); if (log_error) {
if (device->connected) {
log_info("(%s) MIDI open", name);
} else {
log_warn("(%s) MIDI open failed", name);
}
} else { } else {
log_warn("(%s) MIDI open failed", name); snd_lib_log_set_handler(snd_lib_vlog);
} }
} }
@@ -45,7 +62,7 @@ void midi_close(MidiDevice *device) {
} }
void *midi_background_listen(void *args) { void *midi_background_listen(void *args) {
MidiBackgroundReadArgs *process_args = (MidiBackgroundReadArgs *)args; MidiBackgroundListenArgs *process_args = (MidiBackgroundListenArgs *)args;
MidiDevice *device = process_args->device; MidiDevice *device = process_args->device;
Context *context = process_args->context; Context *context = process_args->context;
@@ -57,6 +74,12 @@ void *midi_background_listen(void *args) {
snd_rawmidi_info_malloc(&info); 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) { while (!context->stop && snd_rawmidi_info(device->output, info) == 0) {
bytes_read = snd_rawmidi_read(device->input, buffer, 3); bytes_read = snd_rawmidi_read(device->input, buffer, 3);
if (bytes_read == 3) { if (bytes_read == 3) {
@@ -73,5 +96,6 @@ void *midi_background_listen(void *args) {
log_info("(%s) background acquisition stopped after error", device->name); log_info("(%s) background acquisition stopped after error", device->name);
midi_close(device); midi_close(device);
} }
free(process_args);
pthread_exit(NULL); pthread_exit(NULL);
} }
+1 -1
View File
@@ -3,7 +3,7 @@
#ifndef MIDI_H #ifndef MIDI_H
#define 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_write(MidiDevice device, unsigned char code, unsigned char value);
void *midi_background_listen(void *args); void *midi_background_listen(void *args);
void midi_close(MidiDevice *device); void midi_close(MidiDevice *device);
+9 -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, include_end - project->fragment_shaders[i][0].content,
tmp_file.content); tmp_file.content);
free(project->fragment_shaders[i][0].content);
project->fragment_shaders[i][0].content = new_content; project->fragment_shaders[i][0].content = new_content;
file_free(&tmp_file); file_free(&tmp_file);
@@ -102,6 +104,12 @@ void project_init(Project *project, const char *project_path,
project->sub_counts.length = project->frag_count; 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++) { for (unsigned int i = 0; i < project->frag_count; i++) {
project->sub_counts.values[i] = 0; project->sub_counts.values[i] = 0;
if (!read_fragment_shader_file(project, frag_prefix, i)) { if (!read_fragment_shader_file(project, frag_prefix, i)) {
@@ -134,7 +142,7 @@ 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++) { for (unsigned int i = 0; i < project->frag_count; i++) {
file_free(&project->fragment_shaders[i][0]); file_free(&project->fragment_shaders[i][0]);
} }
+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_reload(Project *project, void (*reload_callback)(unsigned int));
void project_free(const Project *project); void project_free(Project *project);
#endif /* PROJECT_H */ #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; static unsigned long long const multiplier = 6364136223846793005u;
// https://en.wikipedia.org/wiki/Permuted_congruential_generator // 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 long long x = mcg_state;
unsigned count = (unsigned)(x >> 61); unsigned count = (unsigned)(x >> 61);
@@ -15,9 +15,9 @@ static unsigned long rand(void) {
void rand_set_seed(unsigned long long seed) { void rand_set_seed(unsigned long long seed) {
mcg_state = 2 * seed + 1; mcg_state = 2 * seed + 1;
(void)rand(); (void)fast_rand();
} }
unsigned int rand_uint(const unsigned int max) { 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> #include <GLFW/glfw3native.h>
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
static const GLuint unused_uniform = (GLuint)-1; static const GLint UNUSED_UNIFORM = -1;
static bool check_glerror_ro(const char *context) { static bool check_glerror_ro(const char *context) {
unsigned int code; unsigned int code;
@@ -66,7 +66,7 @@ static bool check_eglerror_ro(const char *context) {
code = eglGetError(); code = eglGetError();
if (code > 0 && code != EGL_SUCCESS) { if (code != EGL_SUCCESS) {
log_warn("EGL Error: %04x (%s)", code, context); log_warn("EGL Error: %04x (%s)", code, context);
return true; return true;
} }
@@ -411,7 +411,7 @@ static bool compile_shader(GLuint shader_id, const char *name,
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params); glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status_params);
check_glerror_ro("compile_shader/glGetShaderiv"); 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"); check_glerror_ro("compile_shader/glGetShaderInfoLog");
if (status_params == GL_FALSE) { if (status_params == GL_FALSE) {
@@ -462,6 +462,8 @@ static bool init_single_program(ShaderProgram *program, unsigned int i,
unsigned int index2; unsigned int index2;
char name[STR_LEN]; char name[STR_LEN];
const char *prefix; const char *prefix;
GLint link_status;
char link_log[STR_LEN];
program->programs[i] = glCreateProgram(); program->programs[i] = glCreateProgram();
if (check_glerror(program, "init_single_program/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; 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 // create uniforms pointers
program->itime_locations[i] = glGetUniformLocation( program->itime_locations[i] = glGetUniformLocation(
program->programs[i], 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) { static void write_uniform_1f(GLint location, float value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform1f(location, value); glUniform1f(location, value);
} }
} }
static void write_uniform_1i(GLuint location, unsigned int value) { static void write_uniform_1i(GLint location, unsigned int value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform1i(location, (const GLint)value); glUniform1i(location, (const GLint)value);
} }
} }
static void write_uniform_2f(GLuint location, const vec2 *value) { static void write_uniform_2f(GLint location, const vec2 *value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform2fv(location, 1, (const GLfloat *)value); 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) { const vec3 *value) {
if (location != unused_uniform) { if (location != UNUSED_UNIFORM) {
glUniform3fv(location, count, (const GLfloat *)value); 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 * if (program->sub_locations[i * program->sub_variant_count *
program->sub_type_count + program->sub_type_count +
j * program->sub_variant_count + k] != j * program->sub_variant_count + k] !=
unused_uniform) { UNUSED_UNIFORM) {
subroutines[subcount++] = subroutines[subcount++] =
program->sub_locations[i * program->sub_variant_count * program->sub_locations[i * program->sub_variant_count *
program->sub_type_count + program->sub_type_count +
@@ -935,6 +950,12 @@ void shaders_free(const ShaderProgram *program) {
} }
check_glerror_ro("shaders_free/glDeleteProgram"); 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); glDeleteFramebuffers(program->frag_count, program->frame_buffers);
check_glerror_ro("shaders_free/glDeleteFramebuffers"); 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", snprintf(lines.values[lines.length++], STR_LEN, "tempo=%d",
(unsigned int)context->tempo.tempo); (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); 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", snprintf(lines.values[lines.length++], STR_LEN, "selected=%d",
context->selected); 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++) { for (unsigned int i = 0; i < context->state.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i, snprintf(lines.values[lines.length++], STR_LEN, "seed_%d=%d", i,
context->seeds[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, snprintf(lines.values[lines.length++], STR_LEN, "state_%d=%d", i,
context->state.values[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++) { for (unsigned int i = 0; i < state_config.group_active_counts.length; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i, snprintf(lines.values[lines.length++], STR_LEN, "active_%d=%d", i,
context->active[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++) { for (unsigned int i = 0; i < state_config.value_count; i++) {
snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i, snprintf(lines.values[lines.length++], STR_LEN, "value_%d_x=%d", i,
(unsigned int)(context->values[i][0] * MIDI_MAX)); (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, snprintf(lines.values[lines.length++], STR_LEN, "value_%d_y=%d", i,
(unsigned int)(context->values[i][1] * MIDI_MAX)); (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, snprintf(lines.values[lines.length++], STR_LEN, "value_%d_z=%d", i,
(unsigned int)(context->values[i][2] * MIDI_MAX)); (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); 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) { void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
unsigned int offset; unsigned int offset;
unsigned int count; unsigned int count;
unsigned int length;
char name[STR_LEN]; char name[STR_LEN];
state_config->select_page_codes.length = length = config_file_get_int(config, "SELECT_PAGE_COUNT", 0);
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++) { for (unsigned int i = 0; i < state_config->select_page_codes.length; i++) {
snprintf(name, STR_LEN, "SELECT_PAGE_%d", i + 1); 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); config_file_get_int(config, name, UNSET_MIDI_CODE);
} }
state_config->select_item_codes.length = length = config_file_get_int(config, "SELECT_ITEM_COUNT", 0);
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++) { for (unsigned int i = 0; i < state_config->select_item_codes.length; i++) {
snprintf(name, STR_LEN, "SELECT_ITEM_%d", i + 1); 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->state_max = state_config->select_page_codes.length *
state_config->select_item_codes.length; state_config->select_item_codes.length;
state_config->select_frag_codes.length = length = config_file_get_int(config, "FRAG_COUNT", 1);
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++) { for (unsigned int i = 0; i < state_config->select_frag_codes.length; i++) {
snprintf(name, STR_LEN, "SELECT_FRAG_%d", i + 1); 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); 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_counts.length = state_config->group_counts.length =
state_config->group_active_offsets.length = state_config->group_active_offsets.length =
state_config->group_offsets.length = state_config->group_offsets.length =
state_config->values_offsets.length = state_config->values_offsets.length = length;
config_file_get_int(config, "GROUP_COUNT", 0);
count = 0; count = 0;
for (unsigned int i = 0; i < state_config->group_active_counts.length; i++) { 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; state_config->value_count = offset;
length = count * 3;
if (length > ARRAY_SIZE) {
length = ARRAY_SIZE;
}
state_config->codes.length = count * 3; state_config->codes.length = count * 3;
for (unsigned int i = 0; i < state_config->group_counts.length; i++) { for (unsigned int i = 0; i < state_config->group_counts.length; i++) {
offset = state_config->group_offsets.values[i]; offset = state_config->group_offsets.values[i];
for (unsigned int j = 0; j < state_config->group_counts.values[i]; j++) { 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); if ((offset + j) * 3 < ARRAY_SIZE) {
state_config->codes.values[(offset + j) * 3] = snprintf(name, STR_LEN, "GROUP_%d_%d_X", i + 1, j + 1);
config_file_get_int(config, name, UNSET_MIDI_CODE); 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); if ((offset + j) * 3 + 1 < ARRAY_SIZE) {
state_config->codes.values[(offset + j) * 3 + 1] = snprintf(name, STR_LEN, "GROUP_%d_%d_Y", i + 1, j + 1);
config_file_get_int(config, name, UNSET_MIDI_CODE); 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); if ((offset + j) * 3 + 2 < ARRAY_SIZE) {
state_config->codes.values[(offset + j) * 3 + 2] = snprintf(name, STR_LEN, "GROUP_%d_%d_Z", i + 1, j + 1);
config_file_get_int(config, name, UNSET_MIDI_CODE); state_config->codes.values[(offset + j) * 3 + 2] =
config_file_get_int(config, name, UNSET_MIDI_CODE);
}
} }
} }
state_config->fader_codes.length = length = config_file_get_int(config, "FADER_COUNT", 0);
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++) { for (unsigned int i = 0; i < state_config->fader_codes.length; i++) {
snprintf(name, STR_LEN, "FADER_%d", i + 1); 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); config_file_get_int(config, "KEY_TEMPO_UP", 1265);
if (config_file_has(config, "KEY_LOAD_COUNT")) { if (config_file_has(config, "KEY_LOAD_COUNT")) {
state_config->key_load.length = length = config_file_get_int(config, "KEY_LOAD_COUNT", 0);
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++) { for (unsigned int i = 0; i < state_config->key_load.length; i++) {
snprintf(name, STR_LEN, "KEY_LOAD_%d", i + 1); 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")) { if (config_file_has(config, "KEY_SAVE_COUNT")) {
state_config->key_save.length = length = config_file_get_int(config, "KEY_SAVE_COUNT", 0);
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++) { for (unsigned int i = 0; i < state_config->key_save.length; i++) {
snprintf(name, STR_LEN, "KEY_SAVE_%d", i + 1); 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 (code == state_config.key_autorand) {
if (value > 0) { if (value > 0) {
log_info((context->auto_random ? "[%d] Auto Random OFF"
: "[%d] Auto Random ON"),
code);
context->auto_random = !context->auto_random; context->auto_random = !context->auto_random;
log_info("[%d] Auto Random %s", code,
context->auto_random ? "ON" : "OFF");
} }
return true; return true;
} }
@@ -552,7 +619,7 @@ static bool compute_event(Context *context, StateConfig state_config,
if (context->tempo.tempo > 0) { if (context->tempo.tempo > 0) {
tempo_set(&context->tempo, context->tempo.tempo - 1); 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; return true;
} }
@@ -643,6 +710,7 @@ void *state_background_write(void *args) {
} }
log_info("(state) background writing stopped by main thread"); log_info("(state) background writing stopped by main thread");
free(process_args);
pthread_exit(NULL); pthread_exit(NULL);
} }
+9 -1
View File
@@ -15,7 +15,7 @@ unsigned int string_trim(char *str) {
start = 0; start = 0;
end = strnlen(str, STR_LEN) - 1; end = strnlen(str, STR_LEN) - 1;
if (end == 0) { if (end <= 0) {
return 0; return 0;
} }
@@ -62,11 +62,19 @@ char *string_replace_at(const char *src, unsigned int from, unsigned int to,
unsigned long rpl_len; unsigned long rpl_len;
char *dst; char *dst;
if (to < from) {
return "";
}
src_len = strnlen(src, STR_LEN * STR_LEN); src_len = strnlen(src, STR_LEN * STR_LEN);
rpl_len = strnlen(rpl, STR_LEN * STR_LEN); rpl_len = strnlen(rpl, STR_LEN * STR_LEN);
dst = malloc(src_len - (to - from) + rpl_len + 1); dst = malloc(src_len - (to - from) + rpl_len + 1);
if (dst == NULL) {
return "";
}
strlcpy(dst, src, from + 1); strlcpy(dst, src, from + 1);
strlcpy(dst + from, rpl, rpl_len + 1); strlcpy(dst + from, rpl, rpl_len + 1);
strlcpy(dst + from + rpl_len, src + to, src_len - to + 1); strlcpy(dst + from + rpl_len, src + to, src_len - to + 1);
+6 -12
View File
@@ -1,19 +1,13 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <sys/time.h> #include <time.h>
#include "types.h" #include "types.h"
#include "config.h" #include "config.h"
#include "tempo.h" #include "tempo.h"
static long now() { static long now_ms() { return 1000 * clock() / CLOCKS_PER_SEC; }
struct timeval now;
gettimeofday(&now, NULL);
return now.tv_sec * 1000 + now.tv_usec / 1000;
}
static void reset_tap_chain(Tempo *tempo, long t) { static void reset_tap_chain(Tempo *tempo, long t) {
tempo->last_reset = 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) { void tempo_init(Tempo *tempo, float value) {
long t; long t;
t = now(); t = now_ms();
reset_tap_chain(tempo, t); reset_tap_chain(tempo, t);
@@ -105,7 +99,7 @@ void tempo_set(Tempo *tempo, float value) {
long t; long t;
long progress; long progress;
t = now(); t = now_ms();
progress = (t - tempo->last_reset) % tempo->beat_length; progress = (t - tempo->last_reset) % tempo->beat_length;
@@ -118,7 +112,7 @@ void tempo_set(Tempo *tempo, float value) {
void tempo_tap(Tempo *tempo) { void tempo_tap(Tempo *tempo) {
long t; long t;
t = now(); t = now_ms();
if (!is_chain_active(*tempo, t)) { if (!is_chain_active(*tempo, t)) {
reset_tap_chain(tempo, t); reset_tap_chain(tempo, t);
@@ -130,7 +124,7 @@ void tempo_tap(Tempo *tempo) {
double tempo_total(const Tempo *tempo) { double tempo_total(const Tempo *tempo) {
long t; long t;
t = now(); t = now_ms();
return (double)(t - tempo->last_reset) / (double)tempo->beat_length; 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" #include "types.h"
@@ -7,24 +8,22 @@
void timer_init(Timer *timer, const unsigned int target) { void timer_init(Timer *timer, const unsigned int target) {
timer->counter = 0; timer->counter = 0;
timer->target = target; timer->target = target;
timer->start = clock();
gettimeofday(&timer->start, NULL);
} }
bool timer_inc(Timer *timer) { bool timer_inc(Timer *timer) {
timer->counter += 1; timer->counter += 1;
return timer->counter >= timer->target; return timer->counter == UINT_MAX || timer->counter >= timer->target;
} }
double timer_reset(Timer *timer) { double timer_reset(Timer *timer) {
struct timeval stop; clock_t stop;
double secs; double secs;
double per_secs; double per_secs;
gettimeofday(&stop, NULL); stop = clock();
secs = (double)(stop.tv_usec - timer->start.tv_usec) / 1000000 + secs = (double)(stop - timer->start) / CLOCKS_PER_SEC;
(double)(stop.tv_sec - timer->start.tv_sec);
per_secs = (double)timer->counter / secs; per_secs = (double)timer->counter / secs;
timer->start = stop; timer->start = stop;
+23 -23
View File
@@ -100,34 +100,34 @@ typedef struct ShaderProgram {
GLuint frame_buffers[ARRAY_SIZE]; GLuint frame_buffers[ARRAY_SIZE];
GLuint fragment_shaders[ARRAY_SIZE]; GLuint fragment_shaders[ARRAY_SIZE];
GLuint itime_locations[ARRAY_SIZE]; GLint itime_locations[ARRAY_SIZE];
GLuint itempo_locations[ARRAY_SIZE]; GLint itempo_locations[ARRAY_SIZE];
GLuint ibeats_locations[ARRAY_SIZE]; GLint ibeats_locations[ARRAY_SIZE];
GLuint ifps_locations[ARRAY_SIZE]; GLint ifps_locations[ARRAY_SIZE];
GLuint ires_locations[ARRAY_SIZE]; GLint ires_locations[ARRAY_SIZE];
GLuint itexres_locations[ARRAY_SIZE]; GLint itexres_locations[ARRAY_SIZE];
GLuint iinres_locations[ARRAY_SIZE]; GLint iinres_locations[ARRAY_SIZE];
GLuint iinfmt_locations[ARRAY_SIZE]; GLint iinfmt_locations[ARRAY_SIZE];
GLuint iinfps_locations[ARRAY_SIZE]; GLint iinfps_locations[ARRAY_SIZE];
GLuint idemo_locations[ARRAY_SIZE]; GLint idemo_locations[ARRAY_SIZE];
GLuint iautorand_locations[ARRAY_SIZE]; GLint iautorand_locations[ARRAY_SIZE];
GLuint iautorandcycle_locations[ARRAY_SIZE]; GLint iautorandcycle_locations[ARRAY_SIZE];
GLuint iseed_locations[ARRAY_SIZE]; GLint iseed_locations[ARRAY_SIZE];
GLuint istate_locations[ARRAY_SIZE]; GLint istate_locations[ARRAY_SIZE];
GLuint ipage_locations[ARRAY_SIZE]; GLint ipage_locations[ARRAY_SIZE];
GLuint iselected_locations[ARRAY_SIZE]; GLint iselected_locations[ARRAY_SIZE];
GLuint iactive_locations[ARRAY_SIZE]; GLint iactive_locations[ARRAY_SIZE];
UintArray midi_lengths; 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_type_count;
unsigned int sub_variant_count; unsigned int sub_variant_count;
GLuint sub_locations[ARRAY_SIZE]; GLint sub_locations[ARRAY_SIZE];
unsigned int active_count; unsigned int active_count;
@@ -232,7 +232,7 @@ typedef struct MidiBackgroundListenArgs {
MidiDevice *device; MidiDevice *device;
Context *context; Context *context;
void (*event_callback)(unsigned char code, unsigned char value); void (*event_callback)(unsigned char code, unsigned char value);
} MidiBackgroundReadArgs; } MidiBackgroundListenArgs;
// state.c // state.c
@@ -279,7 +279,7 @@ typedef struct StateBackgroundWriteArgs {
// timer.c // timer.c
typedef struct Timer { typedef struct Timer {
struct timeval start; clock_t start;
unsigned int counter; unsigned int counter;
unsigned int target; unsigned int target;
} Timer; } Timer;
+56 -17
View File
@@ -70,14 +70,18 @@ static void ioctl_error(VideoCapture *video_capture, const char *operation,
video_capture->error = true; 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); strlcpy(video_capture->name, name, STR_LEN);
video_capture->error = false; video_capture->error = false;
video_capture->fd = -1; video_capture->fd = -1;
video_capture->buf_count = 0;
video_capture->fd = open(name, O_RDWR | O_NONBLOCK); video_capture->fd = open(name, O_RDWR | O_NONBLOCK);
if (video_capture->fd == -1) { 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; 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); log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
video_capture->buf_count = 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; return true;
} }
@@ -262,7 +269,7 @@ static bool open_stream(VideoCapture *video_capture) {
return true; 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) { struct v4l2_buffer *buf, unsigned int index) {
memset(buf, 0, sizeof(*buf)); memset(buf, 0, sizeof(*buf));
@@ -270,15 +277,24 @@ static void create_image_buffer(const VideoCapture *video_capture,
buf->memory = V4L2_MEMORY_MMAP; buf->memory = V4L2_MEMORY_MMAP;
buf->index = index; 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; unsigned int i;
for (i = 0; i < video_capture->buf_count; 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) { 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, if (ioctl(video_capture->fd, VIDIOC_DQBUF,
&video_capture->buf[video_capture->buf_index]) != -1) { &video_capture->buf[video_capture->buf_index]) != -1) {
ioctl(video_capture->fd, VIDIOC_QBUF, if (ioctl(video_capture->fd, VIDIOC_QBUF,
&video_capture->buf[video_capture->buf_index]); &video_capture->buf[video_capture->buf_index]) == -1) {
video_capture->buf_index = video_capture->error = true;
(video_capture->buf_index + 1) % video_capture->buf_count; return false;
return true; } 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) { 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, 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,
open_device(video_capture, name); bool log_error) {
open_device(video_capture, name, log_error);
if (video_capture->error) { if (video_capture->error) {
return; return;
} }
if (!check_caps(video_capture)) { if (!check_caps(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!get_available_sizes(video_capture, preferred_height)) { if (!get_available_sizes(video_capture, preferred_height)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!set_format(video_capture)) { if (!set_format(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!request_buffers(video_capture, buffer_count)) { if (!request_buffers(video_capture, buffer_count)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!export_buffers(video_capture)) { if (!export_buffers(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; return;
} }
if (!open_stream(video_capture)) { if (!open_stream(video_capture)) {
video_capture->error = true;
video_free(video_capture);
return; 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) { void *video_background_read(void *args) {
@@ -377,19 +414,21 @@ void *video_background_read(void *args) {
video_capture->disconnected = true; video_capture->disconnected = true;
context->input_formats[input_index] = 0; context->input_formats[input_index] = 0;
} }
free(process_args);
pthread_exit(NULL); pthread_exit(NULL);
} }
void video_free(const VideoCapture *video_capture) { void video_free(const VideoCapture *video_capture) {
unsigned int i; unsigned int i;
close_stream(video_capture);
for (i = 0; i < video_capture->buf_count; i++) { 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) { if (video_capture->fd != -1) {
close_stream(video_capture);
close(video_capture->fd); close(video_capture->fd);
} }
} }
+2 -1
View File
@@ -6,7 +6,8 @@
#ifdef VIDEO_IN #ifdef VIDEO_IN
void video_init(VideoCapture *video_capture, const char *name, 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); 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); glfwGetFramebufferSize(window, &width, &height);
context->resolution[0] = width; context->resolution[0] = width;
context->resolution[1] = height; context->resolution[1] = height;
context->tex_resolution[0] = if (height > 0) {
(int)(context->tex_resolution[1] * context->resolution[0] / context->tex_resolution[0] =
context->resolution[1]); (int)(context->tex_resolution[1] * width / height);
}
} }
void window_close(Window *window) { void window_close(Window *window) {