summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--b.c185
-rwxr-xr-xbuild-aux/compile348
-rwxr-xr-xbuild-aux/depcomp791
-rwxr-xr-xbuild-aux/install-sh541
-rwxr-xr-xbuild-aux/missing215
-rw-r--r--configure.ac54
-rw-r--r--src/Makefile.am60
-rw-r--r--src/adsr.c2
-rw-r--r--src/archive/wavetable.c2
-rw-r--r--src/b.h898
-rw-r--r--src/biquad_filter.c71
-rw-r--r--src/control.c16
-rw-r--r--src/control.h8
-rw-r--r--src/filter.c1
-rw-r--r--src/gen.h17
-rw-r--r--src/lowpass.c1
-rw-r--r--src/midi.c57
-rw-r--r--src/midi.h2
-rw-r--r--src/notes.h3
-rw-r--r--src/osc.c5
-rw-r--r--src/osc_digisaw.c1
-rw-r--r--src/osc_sound.c14
-rw-r--r--src/osc_tri.c2
-rw-r--r--src/oscillator.h22
-rw-r--r--src/raygui.h8
-rw-r--r--src/sound.c85
-rw-r--r--src/sound.h5
-rw-r--r--src/stats.h10
-rw-r--r--src/synth.c24
-rw-r--r--src/synth_engine.h35
-rw-r--r--src/synth_engine_v2.c378
-rw-r--r--src/synth_gui.c179
-rw-r--r--src/synth_math.h22
-rw-r--r--src/types.h38
-rw-r--r--src/web.c257
-rw-r--r--src/web.h12
36 files changed, 2214 insertions, 2155 deletions
diff --git a/b.c b/b.c
new file mode 100644
index 0000000..8eae71f
--- /dev/null
+++ b/b.c
@@ -0,0 +1,185 @@
+#define B_IMPLEMENTATION
+#include "src/b.h"
+#include <libgen.h>
+
+#define BUILD_DIR "build/"
+
+int debug_level = 5;
+
+void
+debug_or_release(B_Cmd* cmd)
+{
+ if (debug_level == 0)
+ b_cmd_append(cmd, "-O3", "-s", "-DNDEBUG");
+ else if (debug_level == 1)
+ b_cmd_append(cmd, "-O2", "-ggdb", "-DVKDEBUG");
+ else if (debug_level == 2)
+ b_cmd_append(cmd, "-O1", "-ggdb", "-DVKDEBUG");
+ else {
+ //b_cmd_append(cmd, "-O0", "-ggdb", "-DVKDEBUG", "-pg");
+ b_cmd_append(cmd, "-O0", "-ggdb", "-DVKDEBUG");
+ b_cmd_append(cmd, "-fsanitize=address");
+ }
+}
+
+void
+inlcude_dirs(B_Cmd* cmd)
+{
+ b_cmd_append(cmd, "-I./src/");
+}
+
+void
+cflags(B_Cmd* cmd)
+{
+ b_cmd_append(cmd, "-Wall", "-Wextra");
+
+ debug_or_release(cmd);
+
+ b_cmd_append(cmd, "-march=native");
+ b_cmd_append(cmd, "-fno-math-errno", "-funroll-loops");
+ b_cmd_append(cmd, "-flto", "-pthread");
+ b_cmd_append(cmd, "-lportaudio", "-lrt", "-lm", "-lasound", "-lraylib", "-lportmidi", "-ljack", "-lfftw3f", "-lsndfile", "-lconfig", "-lmicrohttpd", "-lpthread", "-lwebsockets");
+
+ inlcude_dirs(cmd);
+}
+
+void cxxflags(B_Cmd *cmd)
+{
+ b_cmd_append(cmd, "-Wall", "-Wextra");
+ b_cmd_append(cmd, "-Wno-string-plus-int", "-Wno-nullability-completeness", "-Wno-unused-function", "-Wno-missing-field-initializers", "-Wno-unused-parameter", "-Wno-unused-variable");
+
+ debug_or_release(cmd);
+
+ b_cmd_append(cmd, "-march=native");
+ b_cmd_append(cmd, "-fno-math-errno", "-funroll-loops");
+ b_cmd_append(cmd, "-flto", "-pthread");
+
+ inlcude_dirs(cmd);
+ //b_cmd_append(cmd, "-O3");
+}
+
+void cxx(B_Cmd *cmd)
+{
+ b_cmd_append(cmd, "clang");
+ cxxflags(cmd);
+}
+
+void cc(B_Cmd *cmd)
+{
+ b_cmd_append(cmd, "clang");
+ cflags(cmd);
+}
+
+void libs(B_Cmd *cmd)
+{
+ b_cmd_append(cmd, "-lSDL2", "-lm", "-lvulkan", "-lshaderc_shared", "-lstdc++");
+}
+
+bool
+build_c(bool force,
+ B_Cmd* cmd,
+ const char** input_paths,
+ size_t input_paths_len,
+ const char** dep_paths,
+ size_t dep_paths_len,
+ const char* output_path)
+{
+ int rebuild_is_needed =
+ b_needs_rebuild(output_path, input_paths, input_paths_len);
+
+ int dep_rebuild = 0;
+ if (rebuild_is_needed == 0)
+ dep_rebuild = b_needs_rebuild(output_path, dep_paths, dep_paths_len);
+
+ if (rebuild_is_needed < 0 || dep_rebuild < 0) return false;
+
+ if (force || rebuild_is_needed || dep_rebuild) {
+ cmd->count = 0;
+ cc(cmd);
+ b_cmd_append(cmd, "-o", output_path);
+ b_da_append_many(cmd, input_paths, input_paths_len);
+ libs(cmd);
+ return b_cmd_run_sync(*cmd);
+ }
+
+ b_log(B_INFO, "%s is up-to-date", output_path);
+ return true;
+}
+
+int
+main(int argc, char *argv[])
+{
+ B_GO_REBUILD_URSELF(argc, argv);
+
+ const char *program_name = b_shift_args(&argc, &argv);
+
+ bool force = false;
+
+ while (argc > 0) {
+ const char *flag = b_shift_args(&argc, &argv);
+ if (strcmp(flag, "-f") == 0) {
+ force = true;
+ } else {
+ b_log(B_ERROR, "Unknown flag `%s`", flag);
+ return 1;
+ }
+ }
+
+ const char *synth_deps[] = {
+ "src/adsr.h",
+ "src/b.h",
+ "src/control.h",
+ "src/filter.h",
+ "src/generator.h",
+ "src/gen.h",
+ "src/lowpass.h",
+ "src/midi.h",
+ "src/notes.h",
+ "src/osc.h",
+ "src/pa_memorybarrier.h",
+ "src/pa_ringbuffer.h",
+ "src/raygui.h",
+ "src/sound.h",
+ "src/stats.h",
+ "src/synth_common.h",
+ "src/synth_engine.h",
+ "src/synth_gui.h",
+ "src/synth_math.h",
+ "src/types.h",
+ "src/web.h",
+ };
+
+ const char* synth_paths[] = {
+ "src/adsr.c",
+ "src/control.c",
+ "src/filter.c",
+// "src/generator.c",
+// "src/gtk.c",
+ "src/lowpass.c",
+ "src/midi.c",
+ "src/osc.c",
+ "src/osc_digisaw.c",
+ "src/osc_saw.c",
+ "src/osc_sin.c",
+ "src/osc_sound.c",
+ "src/osc_sqr.c",
+ "src/osc_tri.c",
+ "src/osc_weird.c",
+ "src/pa_ringbuffer.c",
+ "src/sound.c",
+ "src/synth.c",
+ "src/synth_engine_v2.c",
+ "src/synth_gui.c",
+ "src/web.c",
+ };
+
+ B_Cmd cmd = {0};
+
+ b_mkdir_if_not_exists(BUILD_DIR);
+
+ if (!build_c(force, &cmd, synth_paths, B_ARRAY_LEN(synth_paths), synth_deps,
+ B_ARRAY_LEN(synth_deps), BUILD_DIR "synth"))
+ return 1;
+
+ return 0;
+}
diff --git a/build-aux/compile b/build-aux/compile
deleted file mode 100755
index df363c8..0000000
--- a/build-aux/compile
+++ /dev/null
@@ -1,348 +0,0 @@
-#! /bin/sh
-# Wrapper for compilers which do not understand '-c -o'.
-
-scriptversion=2018-03-07.03; # UTC
-
-# Copyright (C) 1999-2021 Free Software Foundation, Inc.
-# Written by Tom Tromey <tromey@cygnus.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# This file is maintained in Automake, please report
-# bugs to <bug-automake@gnu.org> or send patches to
-# <automake-patches@gnu.org>.
-
-nl='
-'
-
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent tools from complaining about whitespace usage.
-IFS=" "" $nl"
-
-file_conv=
-
-# func_file_conv build_file lazy
-# Convert a $build file to $host form and store it in $file
-# Currently only supports Windows hosts. If the determined conversion
-# type is listed in (the comma separated) LAZY, no conversion will
-# take place.
-func_file_conv ()
-{
- file=$1
- case $file in
- / | /[!/]*) # absolute file, and not a UNC file
- if test -z "$file_conv"; then
- # lazily determine how to convert abs files
- case `uname -s` in
- MINGW*)
- file_conv=mingw
- ;;
- CYGWIN* | MSYS*)
- file_conv=cygwin
- ;;
- *)
- file_conv=wine
- ;;
- esac
- fi
- case $file_conv/,$2, in
- *,$file_conv,*)
- ;;
- mingw/*)
- file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
- ;;
- cygwin/* | msys/*)
- file=`cygpath -m "$file" || echo "$file"`
- ;;
- wine/*)
- file=`winepath -w "$file" || echo "$file"`
- ;;
- esac
- ;;
- esac
-}
-
-# func_cl_dashL linkdir
-# Make cl look for libraries in LINKDIR
-func_cl_dashL ()
-{
- func_file_conv "$1"
- if test -z "$lib_path"; then
- lib_path=$file
- else
- lib_path="$lib_path;$file"
- fi
- linker_opts="$linker_opts -LIBPATH:$file"
-}
-
-# func_cl_dashl library
-# Do a library search-path lookup for cl
-func_cl_dashl ()
-{
- lib=$1
- found=no
- save_IFS=$IFS
- IFS=';'
- for dir in $lib_path $LIB
- do
- IFS=$save_IFS
- if $shared && test -f "$dir/$lib.dll.lib"; then
- found=yes
- lib=$dir/$lib.dll.lib
- break
- fi
- if test -f "$dir/$lib.lib"; then
- found=yes
- lib=$dir/$lib.lib
- break
- fi
- if test -f "$dir/lib$lib.a"; then
- found=yes
- lib=$dir/lib$lib.a
- break
- fi
- done
- IFS=$save_IFS
-
- if test "$found" != yes; then
- lib=$lib.lib
- fi
-}
-
-# func_cl_wrapper cl arg...
-# Adjust compile command to suit cl
-func_cl_wrapper ()
-{
- # Assume a capable shell
- lib_path=
- shared=:
- linker_opts=
- for arg
- do
- if test -n "$eat"; then
- eat=
- else
- case $1 in
- -o)
- # configure might choose to run compile as 'compile cc -o foo foo.c'.
- eat=1
- case $2 in
- *.o | *.[oO][bB][jJ])
- func_file_conv "$2"
- set x "$@" -Fo"$file"
- shift
- ;;
- *)
- func_file_conv "$2"
- set x "$@" -Fe"$file"
- shift
- ;;
- esac
- ;;
- -I)
- eat=1
- func_file_conv "$2" mingw
- set x "$@" -I"$file"
- shift
- ;;
- -I*)
- func_file_conv "${1#-I}" mingw
- set x "$@" -I"$file"
- shift
- ;;
- -l)
- eat=1
- func_cl_dashl "$2"
- set x "$@" "$lib"
- shift
- ;;
- -l*)
- func_cl_dashl "${1#-l}"
- set x "$@" "$lib"
- shift
- ;;
- -L)
- eat=1
- func_cl_dashL "$2"
- ;;
- -L*)
- func_cl_dashL "${1#-L}"
- ;;
- -static)
- shared=false
- ;;
- -Wl,*)
- arg=${1#-Wl,}
- save_ifs="$IFS"; IFS=','
- for flag in $arg; do
- IFS="$save_ifs"
- linker_opts="$linker_opts $flag"
- done
- IFS="$save_ifs"
- ;;
- -Xlinker)
- eat=1
- linker_opts="$linker_opts $2"
- ;;
- -*)
- set x "$@" "$1"
- shift
- ;;
- *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
- func_file_conv "$1"
- set x "$@" -Tp"$file"
- shift
- ;;
- *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
- func_file_conv "$1" mingw
- set x "$@" "$file"
- shift
- ;;
- *)
- set x "$@" "$1"
- shift
- ;;
- esac
- fi
- shift
- done
- if test -n "$linker_opts"; then
- linker_opts="-link$linker_opts"
- fi
- exec "$@" $linker_opts
- exit 1
-}
-
-eat=
-
-case $1 in
- '')
- echo "$0: No command. Try '$0 --help' for more information." 1>&2
- exit 1;
- ;;
- -h | --h*)
- cat <<\EOF
-Usage: compile [--help] [--version] PROGRAM [ARGS]
-
-Wrapper for compilers which do not understand '-c -o'.
-Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
-arguments, and rename the output as expected.
-
-If you are trying to build a whole package this is not the
-right script to run: please start by reading the file 'INSTALL'.
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
- exit $?
- ;;
- -v | --v*)
- echo "compile $scriptversion"
- exit $?
- ;;
- cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
- icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
- func_cl_wrapper "$@" # Doesn't return...
- ;;
-esac
-
-ofile=
-cfile=
-
-for arg
-do
- if test -n "$eat"; then
- eat=
- else
- case $1 in
- -o)
- # configure might choose to run compile as 'compile cc -o foo foo.c'.
- # So we strip '-o arg' only if arg is an object.
- eat=1
- case $2 in
- *.o | *.obj)
- ofile=$2
- ;;
- *)
- set x "$@" -o "$2"
- shift
- ;;
- esac
- ;;
- *.c)
- cfile=$1
- set x "$@" "$1"
- shift
- ;;
- *)
- set x "$@" "$1"
- shift
- ;;
- esac
- fi
- shift
-done
-
-if test -z "$ofile" || test -z "$cfile"; then
- # If no '-o' option was seen then we might have been invoked from a
- # pattern rule where we don't need one. That is ok -- this is a
- # normal compilation that the losing compiler can handle. If no
- # '.c' file was seen then we are probably linking. That is also
- # ok.
- exec "$@"
-fi
-
-# Name of file we expect compiler to create.
-cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
-
-# Create the lock directory.
-# Note: use '[/\\:.-]' here to ensure that we don't use the same name
-# that we are using for the .o file. Also, base the name on the expected
-# object file name, since that is what matters with a parallel build.
-lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
-while true; do
- if mkdir "$lockdir" >/dev/null 2>&1; then
- break
- fi
- sleep 1
-done
-# FIXME: race condition here if user kills between mkdir and trap.
-trap "rmdir '$lockdir'; exit 1" 1 2 15
-
-# Run the compile.
-"$@"
-ret=$?
-
-if test -f "$cofile"; then
- test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
-elif test -f "${cofile}bj"; then
- test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
-fi
-
-rmdir "$lockdir"
-exit $ret
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC0"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/build-aux/depcomp b/build-aux/depcomp
deleted file mode 100755
index 715e343..0000000
--- a/build-aux/depcomp
+++ /dev/null
@@ -1,791 +0,0 @@
-#! /bin/sh
-# depcomp - compile a program generating dependencies as side-effects
-
-scriptversion=2018-03-07.03; # UTC
-
-# Copyright (C) 1999-2021 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
-
-case $1 in
- '')
- echo "$0: No command. Try '$0 --help' for more information." 1>&2
- exit 1;
- ;;
- -h | --h*)
- cat <<\EOF
-Usage: depcomp [--help] [--version] PROGRAM [ARGS]
-
-Run PROGRAMS ARGS to compile a file, generating dependencies
-as side-effects.
-
-Environment variables:
- depmode Dependency tracking mode.
- source Source file read by 'PROGRAMS ARGS'.
- object Object file output by 'PROGRAMS ARGS'.
- DEPDIR directory where to store dependencies.
- depfile Dependency file to output.
- tmpdepfile Temporary file to use when outputting dependencies.
- libtool Whether libtool is used (yes/no).
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
- exit $?
- ;;
- -v | --v*)
- echo "depcomp $scriptversion"
- exit $?
- ;;
-esac
-
-# Get the directory component of the given path, and save it in the
-# global variables '$dir'. Note that this directory component will
-# be either empty or ending with a '/' character. This is deliberate.
-set_dir_from ()
-{
- case $1 in
- */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
- *) dir=;;
- esac
-}
-
-# Get the suffix-stripped basename of the given path, and save it the
-# global variable '$base'.
-set_base_from ()
-{
- base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
-}
-
-# If no dependency file was actually created by the compiler invocation,
-# we still have to create a dummy depfile, to avoid errors with the
-# Makefile "include basename.Plo" scheme.
-make_dummy_depfile ()
-{
- echo "#dummy" > "$depfile"
-}
-
-# Factor out some common post-processing of the generated depfile.
-# Requires the auxiliary global variable '$tmpdepfile' to be set.
-aix_post_process_depfile ()
-{
- # If the compiler actually managed to produce a dependency file,
- # post-process it.
- if test -f "$tmpdepfile"; then
- # Each line is of the form 'foo.o: dependency.h'.
- # Do two passes, one to just change these to
- # $object: dependency.h
- # and one to simply output
- # dependency.h:
- # which is needed to avoid the deleted-header problem.
- { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
- sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
- } > "$depfile"
- rm -f "$tmpdepfile"
- else
- make_dummy_depfile
- fi
-}
-
-# A tabulation character.
-tab=' '
-# A newline character.
-nl='
-'
-# Character ranges might be problematic outside the C locale.
-# These definitions help.
-upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
-lower=abcdefghijklmnopqrstuvwxyz
-digits=0123456789
-alpha=${upper}${lower}
-
-if test -z "$depmode" || test -z "$source" || test -z "$object"; then
- echo "depcomp: Variables source, object and depmode must be set" 1>&2
- exit 1
-fi
-
-# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
-depfile=${depfile-`echo "$object" |
- sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
-tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
-
-rm -f "$tmpdepfile"
-
-# Avoid interferences from the environment.
-gccflag= dashmflag=
-
-# Some modes work just like other modes, but use different flags. We
-# parameterize here, but still list the modes in the big case below,
-# to make depend.m4 easier to write. Note that we *cannot* use a case
-# here, because this file can only contain one case statement.
-if test "$depmode" = hp; then
- # HP compiler uses -M and no extra arg.
- gccflag=-M
- depmode=gcc
-fi
-
-if test "$depmode" = dashXmstdout; then
- # This is just like dashmstdout with a different argument.
- dashmflag=-xM
- depmode=dashmstdout
-fi
-
-cygpath_u="cygpath -u -f -"
-if test "$depmode" = msvcmsys; then
- # This is just like msvisualcpp but w/o cygpath translation.
- # Just convert the backslash-escaped backslashes to single forward
- # slashes to satisfy depend.m4
- cygpath_u='sed s,\\\\,/,g'
- depmode=msvisualcpp
-fi
-
-if test "$depmode" = msvc7msys; then
- # This is just like msvc7 but w/o cygpath translation.
- # Just convert the backslash-escaped backslashes to single forward
- # slashes to satisfy depend.m4
- cygpath_u='sed s,\\\\,/,g'
- depmode=msvc7
-fi
-
-if test "$depmode" = xlc; then
- # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
- gccflag=-qmakedep=gcc,-MF
- depmode=gcc
-fi
-
-case "$depmode" in
-gcc3)
-## gcc 3 implements dependency tracking that does exactly what
-## we want. Yay! Note: for some reason libtool 1.4 doesn't like
-## it if -MD -MP comes after the -MF stuff. Hmm.
-## Unfortunately, FreeBSD c89 acceptance of flags depends upon
-## the command line argument order; so add the flags where they
-## appear in depend2.am. Note that the slowdown incurred here
-## affects only configure: in makefiles, %FASTDEP% shortcuts this.
- for arg
- do
- case $arg in
- -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
- *) set fnord "$@" "$arg" ;;
- esac
- shift # fnord
- shift # $arg
- done
- "$@"
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- mv "$tmpdepfile" "$depfile"
- ;;
-
-gcc)
-## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
-## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
-## (see the conditional assignment to $gccflag above).
-## There are various ways to get dependency output from gcc. Here's
-## why we pick this rather obscure method:
-## - Don't want to use -MD because we'd like the dependencies to end
-## up in a subdir. Having to rename by hand is ugly.
-## (We might end up doing this anyway to support other compilers.)
-## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
-## -MM, not -M (despite what the docs say). Also, it might not be
-## supported by the other compilers which use the 'gcc' depmode.
-## - Using -M directly means running the compiler twice (even worse
-## than renaming).
- if test -z "$gccflag"; then
- gccflag=-MD,
- fi
- "$@" -Wp,"$gccflag$tmpdepfile"
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
- echo "$object : \\" > "$depfile"
- # The second -e expression handles DOS-style file names with drive
- # letters.
- sed -e 's/^[^:]*: / /' \
- -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the "deleted header file" problem.
-## The problem is that when a header file which appears in a .P file
-## is deleted, the dependency causes make to die (because there is
-## typically no way to rebuild the header). We avoid this by adding
-## dummy dependencies for each header file. Too bad gcc doesn't do
-## this for us directly.
-## Some versions of gcc put a space before the ':'. On the theory
-## that the space means something, we add a space to the output as
-## well. hp depmode also adds that space, but also prefixes the VPATH
-## to the object. Take care to not repeat it in the output.
-## Some versions of the HPUX 10.20 sed can't process this invocation
-## correctly. Breaking it into two sed invocations is a workaround.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
- | sed -e 's/$/ :/' >> "$depfile"
- rm -f "$tmpdepfile"
- ;;
-
-hp)
- # This case exists only to let depend.m4 do its work. It works by
- # looking at the text of this script. This case will never be run,
- # since it is checked for above.
- exit 1
- ;;
-
-sgi)
- if test "$libtool" = yes; then
- "$@" "-Wp,-MDupdate,$tmpdepfile"
- else
- "$@" -MDupdate "$tmpdepfile"
- fi
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
-
- if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
- echo "$object : \\" > "$depfile"
- # Clip off the initial element (the dependent). Don't try to be
- # clever and replace this with sed code, as IRIX sed won't handle
- # lines with more than a fixed number of characters (4096 in
- # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
- # the IRIX cc adds comments like '#:fec' to the end of the
- # dependency line.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
- | tr "$nl" ' ' >> "$depfile"
- echo >> "$depfile"
- # The second pass generates a dummy entry for each header file.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
- >> "$depfile"
- else
- make_dummy_depfile
- fi
- rm -f "$tmpdepfile"
- ;;
-
-xlc)
- # This case exists only to let depend.m4 do its work. It works by
- # looking at the text of this script. This case will never be run,
- # since it is checked for above.
- exit 1
- ;;
-
-aix)
- # The C for AIX Compiler uses -M and outputs the dependencies
- # in a .u file. In older versions, this file always lives in the
- # current directory. Also, the AIX compiler puts '$object:' at the
- # start of each line; $object doesn't have directory information.
- # Version 6 uses the directory in both cases.
- set_dir_from "$object"
- set_base_from "$object"
- if test "$libtool" = yes; then
- tmpdepfile1=$dir$base.u
- tmpdepfile2=$base.u
- tmpdepfile3=$dir.libs/$base.u
- "$@" -Wc,-M
- else
- tmpdepfile1=$dir$base.u
- tmpdepfile2=$dir$base.u
- tmpdepfile3=$dir$base.u
- "$@" -M
- fi
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
- exit $stat
- fi
-
- for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
- do
- test -f "$tmpdepfile" && break
- done
- aix_post_process_depfile
- ;;
-
-tcc)
- # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
- # FIXME: That version still under development at the moment of writing.
- # Make that this statement remains true also for stable, released
- # versions.
- # It will wrap lines (doesn't matter whether long or short) with a
- # trailing '\', as in:
- #
- # foo.o : \
- # foo.c \
- # foo.h \
- #
- # It will put a trailing '\' even on the last line, and will use leading
- # spaces rather than leading tabs (at least since its commit 0394caf7
- # "Emit spaces for -MD").
- "$@" -MD -MF "$tmpdepfile"
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
- # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
- # We have to change lines of the first kind to '$object: \'.
- sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
- # And for each line of the second kind, we have to emit a 'dep.h:'
- # dummy dependency, to avoid the deleted-header problem.
- sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
- rm -f "$tmpdepfile"
- ;;
-
-## The order of this option in the case statement is important, since the
-## shell code in configure will try each of these formats in the order
-## listed in this file. A plain '-MD' option would be understood by many
-## compilers, so we must ensure this comes after the gcc and icc options.
-pgcc)
- # Portland's C compiler understands '-MD'.
- # Will always output deps to 'file.d' where file is the root name of the
- # source file under compilation, even if file resides in a subdirectory.
- # The object file name does not affect the name of the '.d' file.
- # pgcc 10.2 will output
- # foo.o: sub/foo.c sub/foo.h
- # and will wrap long lines using '\' :
- # foo.o: sub/foo.c ... \
- # sub/foo.h ... \
- # ...
- set_dir_from "$object"
- # Use the source, not the object, to determine the base name, since
- # that's sadly what pgcc will do too.
- set_base_from "$source"
- tmpdepfile=$base.d
-
- # For projects that build the same source file twice into different object
- # files, the pgcc approach of using the *source* file root name can cause
- # problems in parallel builds. Use a locking strategy to avoid stomping on
- # the same $tmpdepfile.
- lockdir=$base.d-lock
- trap "
- echo '$0: caught signal, cleaning up...' >&2
- rmdir '$lockdir'
- exit 1
- " 1 2 13 15
- numtries=100
- i=$numtries
- while test $i -gt 0; do
- # mkdir is a portable test-and-set.
- if mkdir "$lockdir" 2>/dev/null; then
- # This process acquired the lock.
- "$@" -MD
- stat=$?
- # Release the lock.
- rmdir "$lockdir"
- break
- else
- # If the lock is being held by a different process, wait
- # until the winning process is done or we timeout.
- while test -d "$lockdir" && test $i -gt 0; do
- sleep 1
- i=`expr $i - 1`
- done
- fi
- i=`expr $i - 1`
- done
- trap - 1 2 13 15
- if test $i -le 0; then
- echo "$0: failed to acquire lock after $numtries attempts" >&2
- echo "$0: check lockdir '$lockdir'" >&2
- exit 1
- fi
-
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
- # Each line is of the form `foo.o: dependent.h',
- # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
- # Do two passes, one to just change these to
- # `$object: dependent.h' and one to simply `dependent.h:'.
- sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
- # Some versions of the HPUX 10.20 sed can't process this invocation
- # correctly. Breaking it into two sed invocations is a workaround.
- sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
- | sed -e 's/$/ :/' >> "$depfile"
- rm -f "$tmpdepfile"
- ;;
-
-hp2)
- # The "hp" stanza above does not work with aCC (C++) and HP's ia64
- # compilers, which have integrated preprocessors. The correct option
- # to use with these is +Maked; it writes dependencies to a file named
- # 'foo.d', which lands next to the object file, wherever that
- # happens to be.
- # Much of this is similar to the tru64 case; see comments there.
- set_dir_from "$object"
- set_base_from "$object"
- if test "$libtool" = yes; then
- tmpdepfile1=$dir$base.d
- tmpdepfile2=$dir.libs/$base.d
- "$@" -Wc,+Maked
- else
- tmpdepfile1=$dir$base.d
- tmpdepfile2=$dir$base.d
- "$@" +Maked
- fi
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile1" "$tmpdepfile2"
- exit $stat
- fi
-
- for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
- do
- test -f "$tmpdepfile" && break
- done
- if test -f "$tmpdepfile"; then
- sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
- # Add 'dependent.h:' lines.
- sed -ne '2,${
- s/^ *//
- s/ \\*$//
- s/$/:/
- p
- }' "$tmpdepfile" >> "$depfile"
- else
- make_dummy_depfile
- fi
- rm -f "$tmpdepfile" "$tmpdepfile2"
- ;;
-
-tru64)
- # The Tru64 compiler uses -MD to generate dependencies as a side
- # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
- # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
- # dependencies in 'foo.d' instead, so we check for that too.
- # Subdirectories are respected.
- set_dir_from "$object"
- set_base_from "$object"
-
- if test "$libtool" = yes; then
- # Libtool generates 2 separate objects for the 2 libraries. These
- # two compilations output dependencies in $dir.libs/$base.o.d and
- # in $dir$base.o.d. We have to check for both files, because
- # one of the two compilations can be disabled. We should prefer
- # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
- # automatically cleaned when .libs/ is deleted, while ignoring
- # the former would cause a distcleancheck panic.
- tmpdepfile1=$dir$base.o.d # libtool 1.5
- tmpdepfile2=$dir.libs/$base.o.d # Likewise.
- tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
- "$@" -Wc,-MD
- else
- tmpdepfile1=$dir$base.d
- tmpdepfile2=$dir$base.d
- tmpdepfile3=$dir$base.d
- "$@" -MD
- fi
-
- stat=$?
- if test $stat -ne 0; then
- rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
- exit $stat
- fi
-
- for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
- do
- test -f "$tmpdepfile" && break
- done
- # Same post-processing that is required for AIX mode.
- aix_post_process_depfile
- ;;
-
-msvc7)
- if test "$libtool" = yes; then
- showIncludes=-Wc,-showIncludes
- else
- showIncludes=-showIncludes
- fi
- "$@" $showIncludes > "$tmpdepfile"
- stat=$?
- grep -v '^Note: including file: ' "$tmpdepfile"
- if test $stat -ne 0; then
- rm -f "$tmpdepfile"
- exit $stat
- fi
- rm -f "$depfile"
- echo "$object : \\" > "$depfile"
- # The first sed program below extracts the file names and escapes
- # backslashes for cygpath. The second sed program outputs the file
- # name when reading, but also accumulates all include files in the
- # hold buffer in order to output them again at the end. This only
- # works with sed implementations that can handle large buffers.
- sed < "$tmpdepfile" -n '
-/^Note: including file: *\(.*\)/ {
- s//\1/
- s/\\/\\\\/g
- p
-}' | $cygpath_u | sort -u | sed -n '
-s/ /\\ /g
-s/\(.*\)/'"$tab"'\1 \\/p
-s/.\(.*\) \\/\1:/
-H
-$ {
- s/.*/'"$tab"'/
- G
- p
-}' >> "$depfile"
- echo >> "$depfile" # make sure the fragment doesn't end with a backslash
- rm -f "$tmpdepfile"
- ;;
-
-msvc7msys)
- # This case exists only to let depend.m4 do its work. It works by
- # looking at the text of this script. This case will never be run,
- # since it is checked for above.
- exit 1
- ;;
-
-#nosideeffect)
- # This comment above is used by automake to tell side-effect
- # dependency tracking mechanisms from slower ones.
-
-dashmstdout)
- # Important note: in order to support this mode, a compiler *must*
- # always write the preprocessed file to stdout, regardless of -o.
- "$@" || exit $?
-
- # Remove the call to Libtool.
- if test "$libtool" = yes; then
- while test "X$1" != 'X--mode=compile'; do
- shift
- done
- shift
- fi
-
- # Remove '-o $object'.
- IFS=" "
- for arg
- do
- case $arg in
- -o)
- shift
- ;;
- $object)
- shift
- ;;
- *)
- set fnord "$@" "$arg"
- shift # fnord
- shift # $arg
- ;;
- esac
- done
-
- test -z "$dashmflag" && dashmflag=-M
- # Require at least two characters before searching for ':'
- # in the target name. This is to cope with DOS-style filenames:
- # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
- "$@" $dashmflag |
- sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
- rm -f "$depfile"
- cat < "$tmpdepfile" > "$depfile"
- # Some versions of the HPUX 10.20 sed can't process this sed invocation
- # correctly. Breaking it into two sed invocations is a workaround.
- tr ' ' "$nl" < "$tmpdepfile" \
- | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
- | sed -e 's/$/ :/' >> "$depfile"
- rm -f "$tmpdepfile"
- ;;
-
-dashXmstdout)
- # This case only exists to satisfy depend.m4. It is never actually
- # run, as this mode is specially recognized in the preamble.
- exit 1
- ;;
-
-makedepend)
- "$@" || exit $?
- # Remove any Libtool call
- if test "$libtool" = yes; then
- while test "X$1" != 'X--mode=compile'; do
- shift
- done
- shift
- fi
- # X makedepend
- shift
- cleared=no eat=no
- for arg
- do
- case $cleared in
- no)
- set ""; shift
- cleared=yes ;;
- esac
- if test $eat = yes; then
- eat=no
- continue
- fi
- case "$arg" in
- -D*|-I*)
- set fnord "$@" "$arg"; shift ;;
- # Strip any option that makedepend may not understand. Remove
- # the object too, otherwise makedepend will parse it as a source file.
- -arch)
- eat=yes ;;
- -*|$object)
- ;;
- *)
- set fnord "$@" "$arg"; shift ;;
- esac
- done
- obj_suffix=`echo "$object" | sed 's/^.*\././'`
- touch "$tmpdepfile"
- ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
- rm -f "$depfile"
- # makedepend may prepend the VPATH from the source file name to the object.
- # No need to regex-escape $object, excess matching of '.' is harmless.
- sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
- # Some versions of the HPUX 10.20 sed can't process the last invocation
- # correctly. Breaking it into two sed invocations is a workaround.
- sed '1,2d' "$tmpdepfile" \
- | tr ' ' "$nl" \
- | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
- | sed -e 's/$/ :/' >> "$depfile"
- rm -f "$tmpdepfile" "$tmpdepfile".bak
- ;;
-
-cpp)
- # Important note: in order to support this mode, a compiler *must*
- # always write the preprocessed file to stdout.
- "$@" || exit $?
-
- # Remove the call to Libtool.
- if test "$libtool" = yes; then
- while test "X$1" != 'X--mode=compile'; do
- shift
- done
- shift
- fi
-
- # Remove '-o $object'.
- IFS=" "
- for arg
- do
- case $arg in
- -o)
- shift
- ;;
- $object)
- shift
- ;;
- *)
- set fnord "$@" "$arg"
- shift # fnord
- shift # $arg
- ;;
- esac
- done
-
- "$@" -E \
- | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
- -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
- | sed '$ s: \\$::' > "$tmpdepfile"
- rm -f "$depfile"
- echo "$object : \\" > "$depfile"
- cat < "$tmpdepfile" >> "$depfile"
- sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
- rm -f "$tmpdepfile"
- ;;
-
-msvisualcpp)
- # Important note: in order to support this mode, a compiler *must*
- # always write the preprocessed file to stdout.
- "$@" || exit $?
-
- # Remove the call to Libtool.
- if test "$libtool" = yes; then
- while test "X$1" != 'X--mode=compile'; do
- shift
- done
- shift
- fi
-
- IFS=" "
- for arg
- do
- case "$arg" in
- -o)
- shift
- ;;
- $object)
- shift
- ;;
- "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
- set fnord "$@"
- shift
- shift
- ;;
- *)
- set fnord "$@" "$arg"
- shift
- shift
- ;;
- esac
- done
- "$@" -E 2>/dev/null |
- sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
- rm -f "$depfile"
- echo "$object : \\" > "$depfile"
- sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
- echo "$tab" >> "$depfile"
- sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
- rm -f "$tmpdepfile"
- ;;
-
-msvcmsys)
- # This case exists only to let depend.m4 do its work. It works by
- # looking at the text of this script. This case will never be run,
- # since it is checked for above.
- exit 1
- ;;
-
-none)
- exec "$@"
- ;;
-
-*)
- echo "Unknown depmode $depmode" 1>&2
- exit 1
- ;;
-esac
-
-exit 0
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC0"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/build-aux/install-sh b/build-aux/install-sh
deleted file mode 100755
index ec298b5..0000000
--- a/build-aux/install-sh
+++ /dev/null
@@ -1,541 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2020-11-14.01; # UTC
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# 'make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-tab=' '
-nl='
-'
-IFS=" $tab$nl"
-
-# Set DOITPROG to "echo" to test this script.
-
-doit=${DOITPROG-}
-doit_exec=${doit:-exec}
-
-# Put in absolute file names if you don't have them in your path;
-# or use environment vars.
-
-chgrpprog=${CHGRPPROG-chgrp}
-chmodprog=${CHMODPROG-chmod}
-chownprog=${CHOWNPROG-chown}
-cmpprog=${CMPPROG-cmp}
-cpprog=${CPPROG-cp}
-mkdirprog=${MKDIRPROG-mkdir}
-mvprog=${MVPROG-mv}
-rmprog=${RMPROG-rm}
-stripprog=${STRIPPROG-strip}
-
-posix_mkdir=
-
-# Desired mode of installed file.
-mode=0755
-
-# Create dirs (including intermediate dirs) using mode 755.
-# This is like GNU 'install' as of coreutils 8.32 (2020).
-mkdir_umask=22
-
-backupsuffix=
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-is_target_a_directory=possibly
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
- --help display this help and exit.
- --version display version info and exit.
-
- -c (ignored)
- -C install only if different (preserve data modification time)
- -d create directories instead of installing files.
- -g GROUP $chgrpprog installed files to GROUP.
- -m MODE $chmodprog installed files to MODE.
- -o USER $chownprog installed files to USER.
- -p pass -p to $cpprog.
- -s $stripprog installed files.
- -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
- -t DIRECTORY install into DIRECTORY.
- -T report an error if DSTFILE is a directory.
-
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
- RMPROG STRIPPROG
-
-By default, rm is invoked with -f; when overridden with RMPROG,
-it's up to you to specify -f if you want it.
-
-If -S is not specified, no backups are attempted.
-
-Email bug reports to bug-automake@gnu.org.
-Automake home page: https://www.gnu.org/software/automake/
-"
-
-while test $# -ne 0; do
- case $1 in
- -c) ;;
-
- -C) copy_on_change=true;;
-
- -d) dir_arg=true;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift;;
-
- --help) echo "$usage"; exit $?;;
-
- -m) mode=$2
- case $mode in
- *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
-
- -o) chowncmd="$chownprog $2"
- shift;;
-
- -p) cpprog="$cpprog -p";;
-
- -s) stripcmd=$stripprog;;
-
- -S) backupsuffix="$2"
- shift;;
-
- -t)
- is_target_a_directory=always
- dst_arg=$2
- # Protect names problematic for 'test' and other utilities.
- case $dst_arg in
- -* | [=\(\)!]) dst_arg=./$dst_arg;;
- esac
- shift;;
-
- -T) is_target_a_directory=never;;
-
- --version) echo "$0 $scriptversion"; exit $?;;
-
- --) shift
- break;;
-
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
-
- *) break;;
- esac
- shift
-done
-
-# We allow the use of options -d and -T together, by making -d
-# take the precedence; this is for compatibility with GNU install.
-
-if test -n "$dir_arg"; then
- if test -n "$dst_arg"; then
- echo "$0: target directory not allowed when installing a directory." >&2
- exit 1
- fi
-fi
-
-if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
- # When -d is used, all remaining arguments are directories to create.
- # When -t is used, the destination is already specified.
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dst_arg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dst_arg"
- shift # fnord
- fi
- shift # arg
- dst_arg=$arg
- # Protect names problematic for 'test' and other utilities.
- case $dst_arg in
- -* | [=\(\)!]) dst_arg=./$dst_arg;;
- esac
- done
-fi
-
-if test $# -eq 0; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call 'install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
-fi
-
-if test -z "$dir_arg"; then
- if test $# -gt 1 || test "$is_target_a_directory" = always; then
- if test ! -d "$dst_arg"; then
- echo "$0: $dst_arg: Is not a directory." >&2
- exit 1
- fi
- fi
-fi
-
-if test -z "$dir_arg"; then
- do_exit='(exit $ret); exit $ret'
- trap "ret=129; $do_exit" 1
- trap "ret=130; $do_exit" 2
- trap "ret=141; $do_exit" 13
- trap "ret=143; $do_exit" 15
-
- # Set umask so as not to create temps with too-generous modes.
- # However, 'strip' requires both read and write access to temps.
- case $mode in
- # Optimize common cases.
- *644) cp_umask=133;;
- *755) cp_umask=22;;
-
- *[0-7])
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw='% 200'
- fi
- cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
- *)
- if test -z "$stripcmd"; then
- u_plus_rw=
- else
- u_plus_rw=,u+rw
- fi
- cp_umask=$mode$u_plus_rw;;
- esac
-fi
-
-for src
-do
- # Protect names problematic for 'test' and other utilities.
- case $src in
- -* | [=\(\)!]) src=./$src;;
- esac
-
- if test -n "$dir_arg"; then
- dst=$src
- dstdir=$dst
- test -d "$dstdir"
- dstdir_status=$?
- # Don't chown directories that already exist.
- if test $dstdir_status = 0; then
- chowncmd=""
- fi
- else
-
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
-
- if test -z "$dst_arg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
- dst=$dst_arg
-
- # If destination is a directory, append the input filename.
- if test -d "$dst"; then
- if test "$is_target_a_directory" = never; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
- fi
- dstdir=$dst
- dstbase=`basename "$src"`
- case $dst in
- */) dst=$dst$dstbase;;
- *) dst=$dst/$dstbase;;
- esac
- dstdir_status=0
- else
- dstdir=`dirname "$dst"`
- test -d "$dstdir"
- dstdir_status=$?
- fi
- fi
-
- case $dstdir in
- */) dstdirslash=$dstdir;;
- *) dstdirslash=$dstdir/;;
- esac
-
- obsolete_mkdir_used=false
-
- if test $dstdir_status != 0; then
- case $posix_mkdir in
- '')
- # With -d, create the new directory with the user-specified mode.
- # Otherwise, rely on $mkdir_umask.
- if test -n "$dir_arg"; then
- mkdir_mode=-m$mode
- else
- mkdir_mode=
- fi
-
- posix_mkdir=false
- # The $RANDOM variable is not portable (e.g., dash). Use it
- # here however when possible just to lower collision chance.
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-
- trap '
- ret=$?
- rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
- exit $ret
- ' 0
-
- # Because "mkdir -p" follows existing symlinks and we likely work
- # directly in world-writeable /tmp, make sure that the '$tmpdir'
- # directory is successfully created first before we actually test
- # 'mkdir -p'.
- if (umask $mkdir_umask &&
- $mkdirprog $mkdir_mode "$tmpdir" &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
- then
- if test -z "$dir_arg" || {
- # Check for POSIX incompatibilities with -m.
- # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
- # other-writable bit of parent directory when it shouldn't.
- # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
- test_tmpdir="$tmpdir/a"
- ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
- fi
- trap '' 0;;
- esac
-
- if
- $posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
- )
- then :
- else
-
- # mkdir does not conform to POSIX,
- # or it failed possibly due to a race condition. Create the
- # directory the slow way, step by step, checking for races as we go.
-
- case $dstdir in
- /*) prefix='/';;
- [-=\(\)!]*) prefix='./';;
- *) prefix='';;
- esac
-
- oIFS=$IFS
- IFS=/
- set -f
- set fnord $dstdir
- shift
- set +f
- IFS=$oIFS
-
- prefixes=
-
- for d
- do
- test X"$d" = X && continue
-
- prefix=$prefix$d
- if test -d "$prefix"; then
- prefixes=
- else
- if $posix_mkdir; then
- (umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
- # Don't fail if two instances are running concurrently.
- test -d "$prefix" || exit 1
- else
- case $prefix in
- *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
- *) qprefix=$prefix;;
- esac
- prefixes="$prefixes '$qprefix'"
- fi
- fi
- prefix=$prefix/
- done
-
- if test -n "$prefixes"; then
- # Don't fail if two instances are running concurrently.
- (umask $mkdir_umask &&
- eval "\$doit_exec \$mkdirprog $prefixes") ||
- test -d "$dstdir" || exit 1
- obsolete_mkdir_used=true
- fi
- fi
- fi
-
- if test -n "$dir_arg"; then
- { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
- { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
- test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
- else
-
- # Make a couple of temp file names in the proper directory.
- dsttmp=${dstdirslash}_inst.$$_
- rmtmp=${dstdirslash}_rm.$$_
-
- # Trap to clean up those temp files at exit.
- trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
-
- # Copy the file name to the temp name.
- (umask $cp_umask &&
- { test -z "$stripcmd" || {
- # Create $dsttmp read-write so that cp doesn't create it read-only,
- # which would cause strip to fail.
- if test -z "$doit"; then
- : >"$dsttmp" # No need to fork-exec 'touch'.
- else
- $doit touch "$dsttmp"
- fi
- }
- } &&
- $doit_exec $cpprog "$src" "$dsttmp") &&
-
- # and set any options; do chmod last to preserve setuid bits.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
- { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
- { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
- { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-
- # If -C, don't bother to copy if it wouldn't change the file.
- if $copy_on_change &&
- old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
- new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
- set -f &&
- set X $old && old=:$2:$4:$5:$6 &&
- set X $new && new=:$2:$4:$5:$6 &&
- set +f &&
- test "$old" = "$new" &&
- $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
- then
- rm -f "$dsttmp"
- else
- # If $backupsuffix is set, and the file being installed
- # already exists, attempt a backup. Don't worry if it fails,
- # e.g., if mv doesn't support -f.
- if test -n "$backupsuffix" && test -f "$dst"; then
- $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
- fi
-
- # Rename the file to the real destination.
- $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-
- # The rename failed, perhaps because mv can't rename something else
- # to itself, or perhaps because mv is so ancient that it does not
- # support -f.
- {
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- test ! -f "$dst" ||
- $doit $rmcmd "$dst" 2>/dev/null ||
- { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
- } ||
- { echo "$0: cannot unlink or rename $dst" >&2
- (exit 1); exit 1
- }
- } &&
-
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dst"
- }
- fi || exit 1
-
- trap '' 0
- fi
-done
-
-# Local variables:
-# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC0"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/build-aux/missing b/build-aux/missing
deleted file mode 100755
index 1fe1611..0000000
--- a/build-aux/missing
+++ /dev/null
@@ -1,215 +0,0 @@
-#! /bin/sh
-# Common wrapper for a few potentially missing GNU programs.
-
-scriptversion=2018-03-07.03; # UTC
-
-# Copyright (C) 1996-2021 Free Software Foundation, Inc.
-# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-if test $# -eq 0; then
- echo 1>&2 "Try '$0 --help' for more information"
- exit 1
-fi
-
-case $1 in
-
- --is-lightweight)
- # Used by our autoconf macros to check whether the available missing
- # script is modern enough.
- exit 0
- ;;
-
- --run)
- # Back-compat with the calling convention used by older automake.
- shift
- ;;
-
- -h|--h|--he|--hel|--help)
- echo "\
-$0 [OPTION]... PROGRAM [ARGUMENT]...
-
-Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
-to PROGRAM being missing or too old.
-
-Options:
- -h, --help display this help and exit
- -v, --version output version information and exit
-
-Supported PROGRAM values:
- aclocal autoconf autoheader autom4te automake makeinfo
- bison yacc flex lex help2man
-
-Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
-'g' are ignored when checking the name.
-
-Send bug reports to <bug-automake@gnu.org>."
- exit $?
- ;;
-
- -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
- echo "missing $scriptversion (GNU Automake)"
- exit $?
- ;;
-
- -*)
- echo 1>&2 "$0: unknown '$1' option"
- echo 1>&2 "Try '$0 --help' for more information"
- exit 1
- ;;
-
-esac
-
-# Run the given program, remember its exit status.
-"$@"; st=$?
-
-# If it succeeded, we are done.
-test $st -eq 0 && exit 0
-
-# Also exit now if we it failed (or wasn't found), and '--version' was
-# passed; such an option is passed most likely to detect whether the
-# program is present and works.
-case $2 in --version|--help) exit $st;; esac
-
-# Exit code 63 means version mismatch. This often happens when the user
-# tries to use an ancient version of a tool on a file that requires a
-# minimum version.
-if test $st -eq 63; then
- msg="probably too old"
-elif test $st -eq 127; then
- # Program was missing.
- msg="missing on your system"
-else
- # Program was found and executed, but failed. Give up.
- exit $st
-fi
-
-perl_URL=https://www.perl.org/
-flex_URL=https://github.com/westes/flex
-gnu_software_URL=https://www.gnu.org/software
-
-program_details ()
-{
- case $1 in
- aclocal|automake)
- echo "The '$1' program is part of the GNU Automake package:"
- echo "<$gnu_software_URL/automake>"
- echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
- echo "<$gnu_software_URL/autoconf>"
- echo "<$gnu_software_URL/m4/>"
- echo "<$perl_URL>"
- ;;
- autoconf|autom4te|autoheader)
- echo "The '$1' program is part of the GNU Autoconf package:"
- echo "<$gnu_software_URL/autoconf/>"
- echo "It also requires GNU m4 and Perl in order to run:"
- echo "<$gnu_software_URL/m4/>"
- echo "<$perl_URL>"
- ;;
- esac
-}
-
-give_advice ()
-{
- # Normalize program name to check for.
- normalized_program=`echo "$1" | sed '
- s/^gnu-//; t
- s/^gnu//; t
- s/^g//; t'`
-
- printf '%s\n' "'$1' is $msg."
-
- configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
- case $normalized_program in
- autoconf*)
- echo "You should only need it if you modified 'configure.ac',"
- echo "or m4 files included by it."
- program_details 'autoconf'
- ;;
- autoheader*)
- echo "You should only need it if you modified 'acconfig.h' or"
- echo "$configure_deps."
- program_details 'autoheader'
- ;;
- automake*)
- echo "You should only need it if you modified 'Makefile.am' or"
- echo "$configure_deps."
- program_details 'automake'
- ;;
- aclocal*)
- echo "You should only need it if you modified 'acinclude.m4' or"
- echo "$configure_deps."
- program_details 'aclocal'
- ;;
- autom4te*)
- echo "You might have modified some maintainer files that require"
- echo "the 'autom4te' program to be rebuilt."
- program_details 'autom4te'
- ;;
- bison*|yacc*)
- echo "You should only need it if you modified a '.y' file."
- echo "You may want to install the GNU Bison package:"
- echo "<$gnu_software_URL/bison/>"
- ;;
- lex*|flex*)
- echo "You should only need it if you modified a '.l' file."
- echo "You may want to install the Fast Lexical Analyzer package:"
- echo "<$flex_URL>"
- ;;
- help2man*)
- echo "You should only need it if you modified a dependency" \
- "of a man page."
- echo "You may want to install the GNU Help2man package:"
- echo "<$gnu_software_URL/help2man/>"
- ;;
- makeinfo*)
- echo "You should only need it if you modified a '.texi' file, or"
- echo "any other file indirectly affecting the aspect of the manual."
- echo "You might want to install the Texinfo package:"
- echo "<$gnu_software_URL/texinfo/>"
- echo "The spurious makeinfo call might also be the consequence of"
- echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
- echo "want to install GNU make:"
- echo "<$gnu_software_URL/make/>"
- ;;
- *)
- echo "You might have modified some files without having the proper"
- echo "tools for further handling them. Check the 'README' file, it"
- echo "often tells you about the needed prerequisites for installing"
- echo "this package. You may also peek at any GNU archive site, in"
- echo "case some other package contains this missing '$1' program."
- ;;
- esac
-}
-
-give_advice "$1" | sed -e '1s/^/WARNING: /' \
- -e '2,$s/^/ /' >&2
-
-# Propagate the correct exit status (expected to be 127 for a program
-# not found, 63 for a program that failed due to version mismatch).
-exit $st
-
-# Local variables:
-# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC0"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index ebf1d63..0000000
--- a/configure.ac
+++ /dev/null
@@ -1,54 +0,0 @@
-# Must init the autoconf setup
-# The first parameter is project name
-# second is version number
-# third is bug report address
-AC_INIT([synth],[0.0.1])
-
-# Safety checks in case user overwritten --srcdir
-AC_CONFIG_SRCDIR([src/synth.c])
-
-# Store the auxiliary build tools (e.g., install-sh, config.sub, config.guess)
-# in this dir (build-aux)
-AC_CONFIG_AUX_DIR([build-aux])
-
-# Init automake, and specify this program use relaxed structures.
-# i.e. this program doesn't follow the gnu coding standards, and doesn't have
-# ChangeLog, COPYING, AUTHORS, INSTALL, README etc. files.
-AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects dist-xz])
-
-AC_PROG_CC
-
-#PKG_CHECK_MODULES([CHECK], [check >= 0.9.6])
-
-# Set default cflags
-#: ${CFLAGS="-O3 -pedantic"}
-
-# Checks for header files.
-dnl AC_CHECK_HEADERS([stdlib.h])
-AC_CHECK_HEADERS([raylib.h])
-AC_CHECK_HEADERS([portaudio.h])
-AC_CHECK_HEADERS([portmidi.h])
-
-dnl AC_CHECK_FUNCS([memset])
-dnl AC_CHECK_FUNCS([strcasecmp])
-dnl AC_CHECK_FUNCS([strdup])
-dnl AC_CHECK_FUNCS([strerror])
-dnl AC_CHECK_FUNCS([strstr])
-dnl AC_CHECK_FUNCS([strtol])
-dnl AC_CHECK_HEADERS([stdint.h])
-dnl #AC_FUNC_MALLOC
-dnl #AC_FUNC_REALLOC
-dnl AC_TYPE_INT32_T
-dnl AC_TYPE_SIZE_T
-dnl AC_TYPE_UINT32_T
-dnl AC_TYPE_UINT64_T
-dnl AC_TYPE_UINT8_T
-
-# Tells automake to create a Makefile
-# See https://www.gnu.org/software/automake/manual/html_node/Requirements.html
-AC_CONFIG_FILES([Makefile
- src/Makefile])
-
-dnl AC_REQUIRE_AUX_FILE([tap-driver.sh])
-# Generate the output
-AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index edec1b1..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,60 +0,0 @@
-#bin_PROGRAMS = food cookbook cook synth
-bin_PROGRAMS = synth # gtk
-
-common_sources = adsr.c \
- adsr.h \
- control.c \
- control.h \
- filter.c \
- filter.h \
- lowpass.c \
- lowpass.h \
- Makefile.am \
- midi.c \
- midi.h \
- notes.h \
- osc.c \
- osc.h \
- osc_tri.c \
- osc_sin.c \
- osc_digisaw.c \
- osc_saw.c \
- osc_weird.c \
- osc_sqr.c \
- osc_sound.c \
- pa_ringbuffer.c \
- pa_ringbuffer.h \
- pa_memorybarrier.h \
- raygui.h \
- sound.c \
- sound.h \
- synth_common.h \
- synth_engine_v2.c \
- synth_engine.h \
- synth_gui.c \
- synth_gui.h \
- synth_math.h
-
-gtk_sources =
-
-# -fwhole-program allows cross-file inlining, but only works when you put all
-# the source files on one gcc command-line. -flto is another way to get the
-# same effect. (Link-Time Optimization). clang supports -flto but not
-# -fwhole-program.
-
-# If your program doesn't depend on strict FP rounding
-# behaviour, use -ffast-math. If it does, you can usually still use
-# -fno-math-errno and stuff like that, without enabling
-# -funsafe-math-optimizations. Some FP code can get big speedups from
-# fast-math, like auto-vectorization.
-AM_CFLAGS = -O3 -march=native -fno-math-errno -funroll-loops -flto -pthread
-
-synth_SOURCES = synth.c $(common_sources)
-synth_LDADD = -lportaudio -lrt -lm -lasound -lraylib -lportmidi -ljack -lfftw3f -lsndfile -lconfig
-
-# gtk_SOURCES = gtk.c $(common_sources) $(gtk_sources)
-# gtk_LDADD = -lportaudio -lrt -lm -lasound -lraylib -lportmidi -ljack -lfftw3f -lsndfile -lconfig -lgtk-4 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgraphene-1.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0
-# gtk_CFLAGS = -I/usr/include/gtk-4.0 -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/sysprof-6 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/fribidi -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/graphene-1.0 -I/usr/lib/graphene-1.0/include -mfpmath=sse -msse -msse2 -pthread
-#cookbook_SOURCES = cookbook.c $(common_sources)
-#cookbook_SOURCES = cookbook.c $(common_sources)
-#cook_SOURCES = cook.c $(common_sources)
diff --git a/src/adsr.c b/src/adsr.c
index 439d7b1..1ba5b38 100644
--- a/src/adsr.c
+++ b/src/adsr.c
@@ -52,7 +52,7 @@ fix_adsr(adsr_t *adsr, float noteOn, float noteOff, unsigned long long elapsed,
// convert to samples
unsigned long long attack = adsr->a * SAMPLE_RATE + 1;
unsigned long long decay = adsr->d * SAMPLE_RATE + 1;
- unsigned long long sustain = adsr->s * SAMPLE_RATE + 1;
+ //unsigned long long sustain = adsr->s * SAMPLE_RATE + 1;
unsigned long long release = adsr->r * SAMPLE_RATE + 1;
float mod = 0.0f;
diff --git a/src/archive/wavetable.c b/src/archive/wavetable.c
index ab3308a..c953493 100644
--- a/src/archive/wavetable.c
+++ b/src/archive/wavetable.c
@@ -108,7 +108,7 @@ wvt_init()
wvt_tri_data.data = (float *) malloc(sizeof(float) * 2);
wvt_tri_data.data[0] = -1.0f;
wvt_tri_data.data[1] = 1.0f;
- wvt_sound_init("/home/gramanas/code/synth-project/waves/test1.wav");
+ wvt_sound_init("/home/grm/code/synth-project/waves/test1.wav");
}
diff --git a/src/b.h b/src/b.h
new file mode 100644
index 0000000..0b3bf2e
--- /dev/null
+++ b/src/b.h
@@ -0,0 +1,898 @@
+// This is an attempt on build library for building C with C akin to nob.h from
+// tsoding which is itself based on https://github.com/tsoding/nobuild
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef B_H_
+#define B_H_
+
+#define B_ASSERT assert
+#define B_REALLOC realloc
+#define B_FREE free
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#define B_ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
+#define B_ARRAY_GET(array, index) \
+ (B_ASSERT(index >= 0), B_ASSERT(index < B_ARRAY_LEN(array)), array[index])
+
+typedef enum {
+ B_INFO,
+ B_CMD,
+ B_BUILDING,
+ B_CHANGE,
+ B_WARNING,
+ B_ERROR,
+} B_Log_Level;
+
+void b_log(B_Log_Level level, const char *fmt, ...);
+
+// It is an equivalent of shift command from bash. It basically pops a command line
+// argument from the beginning.
+char *b_shift_args(int *argc, char ***argv);
+
+typedef struct {
+ const char **items;
+ size_t count;
+ size_t capacity;
+} B_File_Paths;
+
+typedef enum {
+ B_FILE_REGULAR = 0,
+ B_FILE_DIRECTORY,
+ B_FILE_SYMLINK,
+ B_FILE_OTHER,
+} B_File_Type;
+
+bool b_mkdir_if_not_exists(const char *path);
+bool b_copy_file(const char *src_path, const char *dst_path);
+bool b_copy_directory_recursively(const char *src_path, const char *dst_path);
+bool b_read_entire_dir(const char *parent, B_File_Paths *children);
+bool b_write_entire_file(const char *path, const void *data, size_t size);
+B_File_Type b_get_file_type(const char *path);
+
+#define b_return_defer(value) do { result = (value); goto defer; } while(0)
+
+// Initial capacity of a dynamic array
+#define B_DA_INIT_CAP 256
+
+// Append an item to a dynamic array
+#define b_da_append(da, item) \
+ do { \
+ if ((da)->count >= (da)->capacity) { \
+ (da)->capacity = (da)->capacity == 0 ? B_DA_INIT_CAP : (da)->capacity*2; \
+ (da)->items = B_REALLOC((da)->items, (da)->capacity*sizeof(*(da)->items)); \
+ B_ASSERT((da)->items != NULL && "Buy more RAM lol"); \
+ } \
+ \
+ (da)->items[(da)->count++] = (item); \
+ } while (0)
+
+#define b_da_free(da) B_FREE((da).items)
+
+// Append several items to a dynamic array
+#define b_da_append_many(da, new_items, new_items_count) \
+ do { \
+ if ((da)->count + (new_items_count) > (da)->capacity) { \
+ if ((da)->capacity == 0) { \
+ (da)->capacity = B_DA_INIT_CAP; \
+ } \
+ while ((da)->count + (new_items_count) > (da)->capacity) { \
+ (da)->capacity *= 2; \
+ } \
+ (da)->items = B_REALLOC((da)->items, (da)->capacity*sizeof(*(da)->items)); \
+ B_ASSERT((da)->items != NULL && "Buy more RAM lol"); \
+ } \
+ memcpy((da)->items + (da)->count, (new_items), (new_items_count)*sizeof(*(da)->items)); \
+ (da)->count += (new_items_count); \
+ } while (0)
+
+typedef struct {
+ char *items;
+ size_t count;
+ size_t capacity;
+} B_String_Builder;
+
+bool b_read_entire_file(const char *path, B_String_Builder *sb);
+
+// Append a sized buffer to a string builder
+#define b_sb_append_buf(sb, buf, size) b_da_append_many(sb, buf, size)
+
+// Append a NULL-terminated string to a string builder
+#define b_sb_append_cstr(sb, cstr) \
+ do { \
+ const char *s = (cstr); \
+ size_t n = strlen(s); \
+ b_da_append_many(sb, s, n); \
+ } while (0)
+
+// Append a single NULL character at the end of a string builder. So then you can
+// use it a NULL-terminated C string
+#define b_sb_append_null(sb) b_da_append_many(sb, "", 1)
+
+// Free the memory allocated by a string builder
+#define b_sb_free(sb) B_FREE((sb).items)
+
+// Process handle
+typedef int B_Proc;
+#define B_INVALID_PROC (-1)
+
+typedef struct {
+ B_Proc *items;
+ size_t count;
+ size_t capacity;
+} B_Procs;
+
+bool b_procs_wait(B_Procs procs);
+
+// Wait until the process has finished
+bool b_proc_wait(B_Proc proc);
+
+// A command - the main workhorse of B. B is all about building commands an running them
+typedef struct {
+ const char **items;
+ size_t count;
+ size_t capacity;
+} B_Cmd;
+
+// Render a string representation of a command into a string builder. Keep in mind the the
+// string builder is not NULL-terminated by default. Use b_sb_append_null if you plan to
+// use it as a C string.
+void b_cmd_render(B_Cmd cmd, B_String_Builder *render);
+
+#define b_cmd_append(cmd, ...) \
+ b_da_append_many(cmd, ((const char*[]){__VA_ARGS__}), (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*)))
+
+// Free all the memory allocated by command arguments
+#define b_cmd_free(cmd) B_FREE(cmd.items)
+
+// Run command asynchronously
+B_Proc b_cmd_run_async(B_Cmd cmd);
+
+// Run command synchronously
+bool b_cmd_run_sync(B_Cmd cmd);
+
+#ifndef B_TEMP_CAPACITY
+#define B_TEMP_CAPACITY (8*1024*1024)
+#endif // B_TEMP_CAPACITY
+char *b_temp_strdup(const char *cstr);
+void *b_temp_alloc(size_t size);
+char *b_temp_sprintf(const char *format, ...);
+void b_temp_reset(void);
+size_t b_temp_save(void);
+void b_temp_rewind(size_t checkpoint);
+
+int is_path1_modified_after_path2(const char *path1, const char *path2);
+bool b_rename(const char *old_path, const char *new_path);
+int b_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count);
+int b_needs_rebuild1(const char *output_path, const char *input_path);
+int b_file_exists(const char *file_path);
+
+// TODO: add MinGW support for Go Rebuild Urselfâ„¢ Technology
+#ifndef B_REBUILD_URSELF
+# if _WIN32
+# if defined(__GNUC__)
+# define B_REBUILD_URSELF(binary_path, source_path) "gcc", "-o", binary_path, source_path
+# elif defined(__clang__)
+# define B_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
+# elif defined(_MSC_VER)
+# define B_REBUILD_URSELF(binary_path, source_path) "cl.exe", b_temp_sprintf("/Fe:%s", (binary_path)), source_path
+# endif
+# else
+# if defined(__clang__)
+# define B_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
+# else
+# define B_REBUILD_URSELF(binary_path, source_path) "cc", "-o", binary_path, source_path
+# endif
+# endif
+#endif
+
+// Go Rebuild Urselfâ„¢ Technology
+//
+// How to use it:
+// int main(int argc, char** argv) {
+// GO_REBUILD_URSELF(argc, argv);
+// // actual work
+// return 0;
+// }
+//
+// After your added this macro every time you run ./build it will detect
+// that you modified its original source code and will try to rebuild itself
+// before doing any actual work. So you only need to bootstrap your build system
+// once.
+//
+// The modification is detected by comparing the last modified times of the executable
+// and its source code. The same way the make utility usually does it.
+//
+// The rebuilding is done by using the REBUILD_URSELF macro which you can redefine
+// if you need a special way of bootstraping your build system. (which I personally
+// do not recommend since the whole idea of build is to keep the process of bootstrapping
+// as simple as possible and doing all of the actual work inside of the build)
+//
+#define B_GO_REBUILD_URSELF(argc, argv) \
+ do { \
+ const char *source_path = __FILE__; \
+ assert(argc >= 1); \
+ const char *binary_path = argv[0]; \
+ \
+ int rebuild_is_needed = b_needs_rebuild(binary_path, &source_path, 1); \
+ if (rebuild_is_needed < 0) exit(1); \
+ if (rebuild_is_needed) { \
+ B_String_Builder sb = {0}; \
+ b_sb_append_cstr(&sb, binary_path); \
+ b_sb_append_cstr(&sb, ".old"); \
+ b_sb_append_null(&sb); \
+ \
+ if (!b_rename(binary_path, sb.items)) exit(1); \
+ B_Cmd rebuild = {0}; \
+ b_cmd_append(&rebuild, B_REBUILD_URSELF(binary_path, source_path)); \
+ bool rebuild_succeeded = b_cmd_run_sync(rebuild); \
+ b_cmd_free(rebuild); \
+ if (!rebuild_succeeded) { \
+ b_rename(sb.items, binary_path); \
+ exit(1); \
+ } \
+ \
+ B_Cmd cmd = {0}; \
+ b_da_append_many(&cmd, argv, argc); \
+ if (!b_cmd_run_sync(cmd)) exit(1); \
+ exit(0); \
+ } \
+ } while(0)
+// The implementation idea is stolen from https://github.com/zhiayang/nabs
+
+typedef struct {
+ size_t count;
+ const char *data;
+} B_String_View;
+
+const char *b_temp_sv_to_cstr(B_String_View sv);
+
+B_String_View b_sv_chop_by_delim(B_String_View *sv, char delim);
+B_String_View b_sv_trim(B_String_View sv);
+bool b_sv_eq(B_String_View a, B_String_View b);
+B_String_View b_sv_from_cstr(const char *cstr);
+B_String_View b_sv_from_parts(const char *data, size_t count);
+
+// printf macros for String_View
+#ifndef SV_Fmt
+#define SV_Fmt "%.*s"
+#endif // SV_Fmt
+#ifndef SV_Arg
+#define SV_Arg(sv) (int) (sv).count, (sv).data
+#endif // SV_Arg
+// USAGE:
+// String_View name = ...;
+// printf("Name: "SV_Fmt"\n", SV_Arg(name));
+
+/* file.c */
+/* file.h + */
+/* -------- */
+/* file.o */
+
+/* temlp.h */
+/* f1.c */
+/* f2.c */
+/* f3.c + */
+/* ------ */
+/* templ.o */
+
+/* prog.c */
+/* obj1.o */
+/* obj2.o + */
+/* -------- */
+/* prog */
+
+
+
+#endif // B_H_
+
+#ifdef B_IMPLEMENTATION
+
+static size_t b_temp_size = 0;
+static char b_temp[B_TEMP_CAPACITY] = {0};
+
+bool b_mkdir_if_not_exists(const char *path)
+{
+ int result = mkdir(path, 0755);
+ if (result < 0) {
+ if (errno == EEXIST) {
+ //b_log(B_INFO, "directory `%s` already exists", path);
+ return true;
+ }
+ b_log(B_ERROR, "could not create directory `%s`: %s", path, strerror(errno));
+ return false;
+ }
+
+ b_log(B_INFO, "created directory `%s`", path);
+ return true;
+}
+
+bool b_copy_file(const char *src_path, const char *dst_path)
+{
+ b_log(B_INFO, "copying %s -> %s", src_path, dst_path);
+
+ int src_fd = -1;
+ int dst_fd = -1;
+ size_t buf_size = 32*1024;
+ char *buf = B_REALLOC(NULL, buf_size);
+ B_ASSERT(buf != NULL && "Buy more RAM lol!!");
+ bool result = true;
+
+ src_fd = open(src_path, O_RDONLY);
+ if (src_fd < 0) {
+ b_log(B_ERROR, "Could not open file %s: %s", src_path, strerror(errno));
+ b_return_defer(false);
+ }
+
+ struct stat src_stat;
+ if (fstat(src_fd, &src_stat) < 0) {
+ b_log(B_ERROR, "Could not get mode of file %s: %s", src_path, strerror(errno));
+ b_return_defer(false);
+ }
+
+ dst_fd = open(dst_path, O_CREAT | O_TRUNC | O_WRONLY, src_stat.st_mode);
+ if (dst_fd < 0) {
+ b_log(B_ERROR, "Could not create file %s: %s", dst_path, strerror(errno));
+ b_return_defer(false);
+ }
+
+ for (;;) {
+ ssize_t n = read(src_fd, buf, buf_size);
+ if (n == 0) break;
+ if (n < 0) {
+ b_log(B_ERROR, "Could not read from file %s: %s", src_path, strerror(errno));
+ b_return_defer(false);
+ }
+ char *buf2 = buf;
+ while (n > 0) {
+ ssize_t m = write(dst_fd, buf2, n);
+ if (m < 0) {
+ b_log(B_ERROR, "Could not write to file %s: %s", dst_path, strerror(errno));
+ b_return_defer(false);
+ }
+ n -= m;
+ buf2 += m;
+ }
+ }
+
+defer:
+ free(buf);
+ close(src_fd);
+ close(dst_fd);
+ return result;
+}
+
+void b_cmd_render(B_Cmd cmd, B_String_Builder *render)
+{
+ for (size_t i = 0; i < cmd.count; ++i) {
+ const char *arg = cmd.items[i];
+ if (arg == NULL) break;
+ if (i > 0) b_sb_append_cstr(render, " ");
+ if (!strchr(arg, ' ')) {
+ b_sb_append_cstr(render, arg);
+ } else {
+ b_da_append(render, '\'');
+ b_sb_append_cstr(render, arg);
+ b_da_append(render, '\'');
+ }
+ }
+}
+
+B_Proc b_cmd_run_async(B_Cmd cmd)
+{
+ if (cmd.count < 1) {
+ b_log(B_ERROR, "Could not run empty command");
+ return B_INVALID_PROC;
+ }
+
+ B_String_Builder sb = {0};
+ b_cmd_render(cmd, &sb);
+ b_sb_append_null(&sb);
+ b_log(B_CMD, "%s", sb.items);
+ b_sb_free(sb);
+ memset(&sb, 0, sizeof(sb));
+
+ pid_t cpid = fork();
+ if (cpid < 0) {
+ b_log(B_ERROR, "Could not fork child process: %s", strerror(errno));
+ return B_INVALID_PROC;
+ }
+
+ if (cpid == 0) {
+ // NOTE: This leaks a bit of memory in the child process.
+ // But do we actually care? It's a one off leak anyway...
+ B_Cmd cmd_null = {0};
+ b_da_append_many(&cmd_null, cmd.items, cmd.count);
+ b_cmd_append(&cmd_null, NULL);
+
+ if (execvp(cmd.items[0], (char * const*) cmd_null.items) < 0) {
+ b_log(B_ERROR, "Could not exec child process: %s", strerror(errno));
+ exit(1);
+ }
+ B_ASSERT(0 && "unreachable");
+ }
+
+ return cpid;
+}
+
+bool b_procs_wait(B_Procs procs)
+{
+ bool success = true;
+ for (size_t i = 0; i < procs.count; ++i) {
+ success = b_proc_wait(procs.items[i]) && success;
+ }
+ return success;
+}
+
+bool b_proc_wait(B_Proc proc)
+{
+ if (proc == B_INVALID_PROC) return false;
+
+ for (;;) {
+ int wstatus = 0;
+ if (waitpid(proc, &wstatus, 0) < 0) {
+ b_log(B_ERROR, "could not wait on command (pid %d): %s", proc, strerror(errno));
+ return false;
+ }
+
+ if (WIFEXITED(wstatus)) {
+ int exit_status = WEXITSTATUS(wstatus);
+ if (exit_status != 0) {
+ b_log(B_ERROR, "command exited with exit code %d", exit_status);
+ return false;
+ }
+
+ break;
+ }
+
+ if (WIFSIGNALED(wstatus)) {
+ b_log(B_ERROR, "command process was terminated by %s", strsignal(WTERMSIG(wstatus)));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool b_cmd_run_sync(B_Cmd cmd)
+{
+ B_Proc p = b_cmd_run_async(cmd);
+ if (p == B_INVALID_PROC) return false;
+ return b_proc_wait(p);
+}
+
+char *b_shift_args(int *argc, char ***argv)
+{
+ B_ASSERT(*argc > 0);
+ char *result = **argv;
+ (*argv) += 1;
+ (*argc) -= 1;
+ return result;
+}
+
+void b_log(B_Log_Level level, const char *fmt, ...)
+{
+ switch (level) {
+ case B_INFO:
+ fprintf(stderr, "[INFO] ");
+ break;
+ case B_CMD:
+ fprintf(stderr, "[CMD] ");
+ break;
+ case B_BUILDING:
+ fprintf(stderr, "[BUILDING] ");
+ break;
+ case B_CHANGE:
+ fprintf(stderr, "[CHANGE] ");
+ break;
+ case B_WARNING:
+ fprintf(stderr, "[WARNING] ");
+ break;
+ case B_ERROR:
+ fprintf(stderr, "[ERROR] ");
+ break;
+ default:
+ B_ASSERT(0 && "unreachable");
+ }
+
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+bool b_read_entire_dir(const char *parent, B_File_Paths *children)
+{
+ bool result = true;
+ DIR *dir = NULL;
+
+ dir = opendir(parent);
+ if (dir == NULL) {
+ b_log(B_ERROR, "Could not open directory %s: %s", parent, strerror(errno));
+ b_return_defer(false);
+ }
+
+ errno = 0;
+ struct dirent *ent = readdir(dir);
+ while (ent != NULL) {
+ b_da_append(children, b_temp_strdup(ent->d_name));
+ ent = readdir(dir);
+ }
+
+ if (errno != 0) {
+ b_log(B_ERROR, "Could not read directory %s: %s", parent, strerror(errno));
+ b_return_defer(false);
+ }
+
+defer:
+ if (dir) closedir(dir);
+ return result;
+}
+
+bool b_write_entire_file(const char *path, const void *data, size_t size)
+{
+ bool result = true;
+
+ FILE *f = fopen(path, "wb");
+ if (f == NULL) {
+ b_log(B_ERROR, "Could not open file %s for writing: %s\n", path, strerror(errno));
+ b_return_defer(false);
+ }
+
+ // len
+ // v
+ // aaaaaaaaaa
+ // ^
+ // data
+
+ const char *buf = data;
+ while (size > 0) {
+ size_t n = fwrite(buf, 1, size, f);
+ if (ferror(f)) {
+ b_log(B_ERROR, "Could not write into file %s: %s\n", path, strerror(errno));
+ b_return_defer(false);
+ }
+ size -= n;
+ buf += n;
+ }
+
+defer:
+ if (f) fclose(f);
+ return result;
+}
+
+B_File_Type b_get_file_type(const char *path)
+{
+ struct stat statbuf;
+ if (stat(path, &statbuf) < 0) {
+ b_log(B_ERROR, "Could not get stat of %s: %s", path, strerror(errno));
+ return -1;
+ }
+
+ switch (statbuf.st_mode & S_IFMT) {
+ case S_IFDIR: return B_FILE_DIRECTORY;
+ case S_IFREG: return B_FILE_REGULAR;
+ case S_IFLNK: return B_FILE_SYMLINK;
+ default: return B_FILE_OTHER;
+ }
+}
+
+bool b_copy_directory_recursively(const char *src_path, const char *dst_path)
+{
+ bool result = true;
+ B_File_Paths children = {0};
+ B_String_Builder src_sb = {0};
+ B_String_Builder dst_sb = {0};
+ size_t temp_checkpoint = b_temp_save();
+
+ B_File_Type type = b_get_file_type(src_path);
+ if (type < 0) return false;
+
+ switch (type) {
+ case B_FILE_DIRECTORY: {
+ if (!b_mkdir_if_not_exists(dst_path)) b_return_defer(false);
+ if (!b_read_entire_dir(src_path, &children)) b_return_defer(false);
+
+ for (size_t i = 0; i < children.count; ++i) {
+ if (strcmp(children.items[i], ".") == 0) continue;
+ if (strcmp(children.items[i], "..") == 0) continue;
+
+ src_sb.count = 0;
+ b_sb_append_cstr(&src_sb, src_path);
+ b_sb_append_cstr(&src_sb, "/");
+ b_sb_append_cstr(&src_sb, children.items[i]);
+ b_sb_append_null(&src_sb);
+
+ dst_sb.count = 0;
+ b_sb_append_cstr(&dst_sb, dst_path);
+ b_sb_append_cstr(&dst_sb, "/");
+ b_sb_append_cstr(&dst_sb, children.items[i]);
+ b_sb_append_null(&dst_sb);
+
+ if (!b_copy_directory_recursively(src_sb.items, dst_sb.items)) {
+ b_return_defer(false);
+ }
+ }
+ } break;
+
+ case B_FILE_REGULAR: {
+ if (!b_copy_file(src_path, dst_path)) {
+ b_return_defer(false);
+ }
+ } break;
+
+ case B_FILE_SYMLINK: {
+ b_log(B_WARNING, "TODO: Copying symlinks is not supported yet");
+ } break;
+
+ case B_FILE_OTHER: {
+ b_log(B_ERROR, "Unsupported type of file %s", src_path);
+ b_return_defer(false);
+ } break;
+
+ default: B_ASSERT(0 && "unreachable");
+ }
+
+defer:
+ b_temp_rewind(temp_checkpoint);
+ b_da_free(src_sb);
+ b_da_free(dst_sb);
+ b_da_free(children);
+ return result;
+}
+
+char *b_temp_strdup(const char *cstr)
+{
+ size_t n = strlen(cstr);
+ char *result = b_temp_alloc(n + 1);
+ B_ASSERT(result != NULL && "Increase B_TEMP_CAPACITY");
+ memcpy(result, cstr, n);
+ result[n] = '\0';
+ return result;
+}
+
+void *b_temp_alloc(size_t size)
+{
+ if (b_temp_size + size > B_TEMP_CAPACITY) return NULL;
+ void *result = &b_temp[b_temp_size];
+ b_temp_size += size;
+ return result;
+}
+
+char *b_temp_sprintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ int n = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+
+ B_ASSERT(n >= 0);
+ char *result = b_temp_alloc(n + 1);
+ B_ASSERT(result != NULL && "Extend the size of the temporary allocator");
+ // TODO: use proper arenas for the temporary allocator;
+ va_start(args, format);
+ vsnprintf(result, n + 1, format, args);
+ va_end(args);
+
+ return result;
+}
+
+void b_temp_reset(void)
+{
+ b_temp_size = 0;
+}
+
+size_t b_temp_save(void)
+{
+ return b_temp_size;
+}
+
+void b_temp_rewind(size_t checkpoint)
+{
+ b_temp_size = checkpoint;
+}
+
+const char *b_temp_sv_to_cstr(B_String_View sv)
+{
+ char *result = b_temp_alloc(sv.count + 1);
+ B_ASSERT(result != NULL && "Extend the size of the temporary allocator");
+ memcpy(result, sv.data, sv.count);
+ result[sv.count] = '\0';
+ return result;
+}
+
+int b_needs_rebuild(const char *output_path, const char **input_paths, size_t input_paths_count)
+{
+ struct stat statbuf = {0};
+
+ if (stat(output_path, &statbuf) < 0) {
+ // NOTE: if output does not exist it 100% must be rebuilt
+ if (errno == ENOENT) {
+ b_log(B_BUILDING, "%s", output_path);
+ return 1;
+ }
+ b_log(B_ERROR, "could not stat %s: %s", output_path, strerror(errno));
+ return -1;
+ }
+ int output_path_time = statbuf.st_mtime;
+
+ for (size_t i = 0; i < input_paths_count; ++i) {
+ const char *input_path = input_paths[i];
+ if (stat(input_path, &statbuf) < 0) {
+ // NOTE: non-existing input is an error cause it is needed for building in the first place
+ b_log(B_ERROR, "could not stat %s: %s", input_path, strerror(errno));
+ return -1;
+ }
+ int input_path_time = statbuf.st_mtime;
+ // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild
+ if (input_path_time > output_path_time) {
+ b_log(B_CHANGE, "%s", input_path);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int b_needs_rebuild1(const char *output_path, const char *input_path)
+{
+ return b_needs_rebuild(output_path, &input_path, 1);
+}
+
+bool b_rename(const char *old_path, const char *new_path)
+{
+ b_log(B_INFO, "renaming %s -> %s", old_path, new_path);
+ if (rename(old_path, new_path) < 0) {
+ b_log(B_ERROR, "could not rename %s to %s: %s", old_path, new_path, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+bool b_read_entire_file(const char *path, B_String_Builder *sb)
+{
+ bool result = true;
+
+ FILE *f = fopen(path, "rb");
+ if (f == NULL) b_return_defer(false);
+ if (fseek(f, 0, SEEK_END) < 0) b_return_defer(false);
+ long m = ftell(f);
+ if (m < 0) b_return_defer(false);
+ if (fseek(f, 0, SEEK_SET) < 0) b_return_defer(false);
+
+ size_t new_count = sb->count + m;
+ if (new_count > sb->capacity) {
+ sb->items = realloc(sb->items, new_count);
+ B_ASSERT(sb->items != NULL && "Buy more RAM lool!!");
+ sb->capacity = new_count;
+ }
+
+ fread(sb->items + sb->count, m, 1, f);
+ if (ferror(f)) {
+ // TODO: Afaik, ferror does not set errno. So the error reporting in defer is not correct in this case.
+ b_return_defer(false);
+ }
+ sb->count = new_count;
+
+defer:
+ if (!result) b_log(B_ERROR, "Could not read file %s: %s", path, strerror(errno));
+ if (f) fclose(f);
+ return result;
+}
+
+B_String_View b_sv_chop_by_delim(B_String_View *sv, char delim)
+{
+ size_t i = 0;
+ while (i < sv->count && sv->data[i] != delim) {
+ i += 1;
+ }
+
+ B_String_View result = b_sv_from_parts(sv->data, i);
+
+ if (i < sv->count) {
+ sv->count -= i + 1;
+ sv->data += i + 1;
+ } else {
+ sv->count -= i;
+ sv->data += i;
+ }
+
+ return result;
+}
+
+B_String_View b_sv_from_parts(const char *data, size_t count)
+{
+ B_String_View sv;
+ sv.count = count;
+ sv.data = data;
+ return sv;
+}
+
+B_String_View b_sv_trim_left(B_String_View sv)
+{
+ size_t i = 0;
+ while (i < sv.count && isspace(sv.data[i])) {
+ i += 1;
+ }
+
+ return b_sv_from_parts(sv.data + i, sv.count - i);
+}
+
+B_String_View b_sv_trim_right(B_String_View sv)
+{
+ size_t i = 0;
+ while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) {
+ i += 1;
+ }
+
+ return b_sv_from_parts(sv.data, sv.count - i);
+}
+
+B_String_View b_sv_trim(B_String_View sv)
+{
+ return b_sv_trim_right(b_sv_trim_left(sv));
+}
+
+B_String_View b_sv_from_cstr(const char *cstr)
+{
+ return b_sv_from_parts(cstr, strlen(cstr));
+}
+
+bool b_sv_eq(B_String_View a, B_String_View b)
+{
+ if (a.count != b.count) {
+ return false;
+ } else {
+ return memcmp(a.data, b.data, a.count) == 0;
+ }
+}
+
+// RETURNS:
+// 0 - file does not exists
+// 1 - file exists
+// -1 - error while checking if file exists. The error is logged
+int b_file_exists(const char *file_path)
+{
+ struct stat statbuf;
+ if (stat(file_path, &statbuf) < 0) {
+ if (errno == ENOENT) return 0;
+ b_log(B_ERROR, "Could not check if file %s exists: %s", file_path, strerror(errno));
+ return -1;
+ }
+ return 1;
+}
+
+#endif
diff --git a/src/biquad_filter.c b/src/biquad_filter.c
new file mode 100644
index 0000000..ae33a4c
--- /dev/null
+++ b/src/biquad_filter.c
@@ -0,0 +1,71 @@
+//#include "biquad_filter.h"
+
+typedef struct biquad_filter_t {
+ // Filter coefficients
+ double b0, b1, b2; // Feedforward coefficients
+ double a1, a2; // Feedback coefficients
+
+ // Delay buffers (history of input and output)
+ double x1, x2; // Previous input samples
+ double y1, y2; // Previous output samples
+} biquad_filter_t;
+
+void
+biquad_calculate_coefficients(biquad_filter_t* filter, double freq, double Q, double sampleRate, char type)
+{
+ double omega = 2.0 * M_PI * freq / sampleRate;
+ double alpha = sin(omega) / (2.0 * Q);
+ double cos_omega = cos(omega);
+
+ // Initialize coefficients based on filter type
+ switch (type) {
+ case 'l': // Low-pass filter
+ filter->b0 = (1.0 - cos_omega) / 2.0;
+ filter->b1 = 1.0 - cos_omega;
+ filter->b2 = filter->b0;
+ filter->a1 = -2.0 * cos_omega;
+ filter->a2 = 1.0 - alpha;
+ break;
+ case 'h': // High-pass filter
+ filter->b0 = (1.0 + cos_omega) / 2.0;
+ filter->b1 = -(1.0 + cos_omega);
+ filter->b2 = filter->b0;
+ filter->a1 = -2.0 * cos_omega;
+ filter->a2 = 1.0 - alpha;
+ break;
+ case 'b': // Band-pass filter
+ filter->b0 = alpha;
+ filter->b1 = 0.0;
+ filter->b2 = -alpha;
+ filter->a1 = -2.0 * cos_omega;
+ filter->a2 = 1.0 - alpha;
+ break;
+ default:
+ exit(EXIT_FAILURE); // Unsupported filter type
+ }
+
+ // Normalize coefficients
+ double a0 = 1.0 + alpha;
+ filter->b0 /= a0;
+ filter->b1 /= a0;
+ filter->b2 /= a0;
+ filter->a1 /= a0;
+ filter->a2 /= a0;
+}
+
+double
+biquad_process(biquad_filter_t* filter, double input)
+{
+ double output = filter->b0 * input +
+ filter->b1 * filter->x1 +
+ filter->b2 * filter->x2 -
+ filter->a1 * filter->y1 -
+ filter->a2 * filter->y2;
+
+ filter->x2 = filter->x1;
+ filter->x1 = input;
+ filter->y2 = filter->y1;
+ filter->y1 = output;
+
+ return output;
+}
diff --git a/src/control.c b/src/control.c
index d952f7f..44aadc9 100644
--- a/src/control.c
+++ b/src/control.c
@@ -34,6 +34,22 @@ cc_fix(cc_t *cc)
}
void
+cc_set(cc_t *cc, float value)
+{
+ float new_value;
+ if (value >= cc->max) {
+ new_value = cc->max;
+ } else if (value <= cc->min) {
+ new_value = cc->min;
+ } else {
+ new_value = value;
+ }
+
+ // calculate mod
+ cc->mod = new_value - cc->target;
+}
+
+void
cc_reset(cc_t *cc)
{
cc->target = cc->def;
diff --git a/src/control.h b/src/control.h
index 45e87ed..8fbcdfd 100644
--- a/src/control.h
+++ b/src/control.h
@@ -24,7 +24,7 @@ typedef struct cc_t {
float step;
float def;
float value; /* active value (start for interpolation) */
- float mod; /* stores the modified value before it is set as target */
+ float mod; /* stores the amount a value needs to change to reach new target */
float target; /* target value (end for interpolation) */
} cc_t;
@@ -53,6 +53,12 @@ typedef struct cc_t {
int cc_step(cc_t *cc, int steps);
/**
+ Set the cc to the target value,
+ do so using mod. respects min/max etc
+ */
+void cc_set(cc_t *cc, float value);
+
+/**
Reset the cc to defaults
*/
void cc_reset(cc_t *cc);
diff --git a/src/filter.c b/src/filter.c
index 69d7bb6..9dfc19e 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -34,6 +34,7 @@
void update_bw_low_pass_filter(BWLowPass* filter, FTR_PRECISION s, FTR_PRECISION f, FTR_PRECISION q)
{
+ (void)q;
FTR_PRECISION a = TAN((FTR_PRECISION)(M_PI * f / s));
FTR_PRECISION a2 = a * a;
FTR_PRECISION r;
diff --git a/src/gen.h b/src/gen.h
new file mode 100644
index 0000000..64de944
--- /dev/null
+++ b/src/gen.h
@@ -0,0 +1,17 @@
+#ifndef GEN_H
+#define GEN_H
+
+#include "synth_engine.h"
+
+typedef struct {
+ osc_t ** osc;
+ int osci;
+ osc_t ** lfo;
+ int lfoi;
+ adsr_t ** asdr;
+ int adsri;
+} gen_t;
+
+float gen(synth_t * synth, midi_note_t * note, osc_t * osc, sample_rate);
+
+#endif /* GEN_H */
diff --git a/src/lowpass.c b/src/lowpass.c
index 0ec53be..b0abda5 100644
--- a/src/lowpass.c
+++ b/src/lowpass.c
@@ -274,6 +274,7 @@ void prewarp(
double *a0, double *a1, double *a2,
double fc, double fs)
{
+ (void)a0;
double wp, pi;
pi = 4.0 * atan(1.0);
diff --git a/src/midi.c b/src/midi.c
index 389a670..5a556e9 100644
--- a/src/midi.c
+++ b/src/midi.c
@@ -46,6 +46,7 @@ void midi_decode(uint32_t msg, synth_t * synth) {
case 0x0B:
printf("Control Change: channel=%d, controller=%d, value=%d\n", channel, data1, data2);
int x = data2 < 64 ? 1 : -1;
+ int val;
switch (data1) {
case 0:
cc_step(&synth->cc_adsr_a, x);
@@ -94,6 +95,7 @@ void midi_decode(uint32_t msg, synth_t * synth) {
if (synth->geni < 6) synth->geni++;
break;
default:
+ break;
}
break;
case 0x0C:
@@ -103,7 +105,7 @@ void midi_decode(uint32_t msg, synth_t * synth) {
printf("Channel Pressure: channel=%d, pressure=%d\n", channel, data1);
break;
case 0x0E:
- int val = ((data2 << 7) | data1) - 8192;
+ val = ((data2 << 7) | data1) - 8192;
printf("Pitch Bend: channel=%d, value=%d\n", channel, val);
float pitch;
float semitones = 2;
@@ -126,6 +128,7 @@ void midi_decode(uint32_t msg, synth_t * synth) {
int enable = 0;
void
midiCallback(PtTimestamp timestamp, void *userData) {
+ (void)timestamp;
midi_t * m = (midi_t *)userData;
if (!m->stream) return;
@@ -156,12 +159,19 @@ init_midi(midi_t *m, synth_t *synth)
printf("midi devs: %d\n", Pm_CountDevices());
const PmDeviceInfo *info;
- int i;
+ int i, c=0;
for (i = 0; i < Pm_CountDevices(); i++) {
info = Pm_GetDeviceInfo(i);
+ if (!info->input) {
+ continue;
+ }
printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s) -- %d\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf, Pm_GetDefaultInputDeviceID());
+ if (synth->midi_device_id == c) {
+ break;
+ }
+ c++;
//if (!strcmp("MPK225 MIDI", info->name) && !info->input) break;
- if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break;
+ //if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break;
//if (!strcmp("CH345 MIDI 1", info->name) && info->input == 1) break;
//if (!strcmp("Midi Through Port-0", info->name) && info->input == 1) break;
//if (!strcmp("DigitalKBD MIDI 1", info->name) && info->input == 1) break;
@@ -178,6 +188,47 @@ init_midi(midi_t *m, synth_t *synth)
enable = 1;
}
+int
+get_midi_device_id(const char * name)
+{
+ int i, c=0;
+ const PmDeviceInfo *info;
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ info = Pm_GetDeviceInfo(i);
+ if (!info->input) {
+ continue;
+ }
+ if (!strcmp(name, info->name)) {
+ return c;
+ }
+ c++;
+ }
+ return -1;
+}
+
+char *
+get_midi_devices()
+{
+ //Pm_Initialize();
+ int i;
+ char *ret = (char *)malloc(sizeof(char) * 4096);
+ strcpy(ret, "");
+ const PmDeviceInfo *info;
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ info = Pm_GetDeviceInfo(i);
+ if (!info->input) {
+ continue;
+ }
+ printf("!!!!!!!!!!!!!!!!!!!!!!!!! ==> %s ========\n", info->name);
+ strcat(ret, info->name);
+ strcat(ret, ";");
+ }
+ ret[strlen(ret) - 1] = '\0';
+ //Pm_Terminate();
+
+ return ret;
+}
+
void
terminate_midi(midi_t *m)
{
diff --git a/src/midi.h b/src/midi.h
index fd9b749..004e824 100644
--- a/src/midi.h
+++ b/src/midi.h
@@ -13,5 +13,7 @@ typedef struct midi_t {
void init_midi(midi_t *midi, synth_t *synth);
void terminate_midi(midi_t *midi);
+int get_midi_device_id(const char * name);
+char * get_midi_devices();
#endif /* MIDI_H */
diff --git a/src/notes.h b/src/notes.h
index ed6b3e6..bab7117 100644
--- a/src/notes.h
+++ b/src/notes.h
@@ -16,7 +16,8 @@ static float note_B[] = {30.87, 61.74, 123.47, 246.94, 493.88, 987.77, 1975.53,
static float *notes[12] = {note_C, note_Db, note_D, note_Eb, note_E, note_F, note_Gb, note_G, note_Ab, note_A, note_Bb, note_B };
-static char *
+// do I really want inline? used to be static
+inline char *
int_to_note(int n)
{
switch (n) {
diff --git a/src/osc.c b/src/osc.c
index c3c5d48..16e6894 100644
--- a/src/osc.c
+++ b/src/osc.c
@@ -57,7 +57,7 @@ osc_load_wav(osc_t * osc, const char * path)
{
SNDFILE* file;
SF_INFO fileInfo;
- int numSamplesRead;
+ int numSamplesRead = 0;
// Open the WAV file
file = sf_open(path, SFM_READ, &fileInfo);
@@ -81,7 +81,8 @@ osc_load_wav(osc_t * osc, const char * path)
// Read the WAV file into the buffer
numSamplesRead = sf_readf_float(file, osc->data, fileInfo.frames);
-
+ (void)numSamplesRead;
+
/* float max = -1000; */
/* float min = 1000; */
/* for (int i = 0; i < numSamplesRead; i++) { */
diff --git a/src/osc_digisaw.c b/src/osc_digisaw.c
index b71a9e3..bd1d8a4 100644
--- a/src/osc_digisaw.c
+++ b/src/osc_digisaw.c
@@ -28,6 +28,7 @@ digisaw(int index)
else if (index == 18) return 0.8f;
else if (index == 19) return 0.9f;
else if (index == 20) return 1.0f;
+ return 0;
}
float
diff --git a/src/osc_sound.c b/src/osc_sound.c
index e919e96..fbf8860 100644
--- a/src/osc_sound.c
+++ b/src/osc_sound.c
@@ -18,13 +18,13 @@ float
osc_sound(float offset)
{
if (!OSC_sound.len) {
- // osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/test_lick.wav");
- //osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/Free Wavetables[128]/FM Synthesis[128-44.1khz-16bit]/FM Sq- NotPM.wav");
- //osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/Free Wavetables[2048]/Melda Oscillator[2048-44.1khz-32bit]/Melda SKEW.wav");
- //osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/Free Wavetables[2048]/Filter Sweep[2048-44.1khz-32bit]/SweepSaw.wav");
- //osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/Free Wavetables[2048]/Additive Synth[2048-44.1khz-32bit]/Add Synth7.wav");
- //osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/Free Wavetables[2048]/Korg Analog Synth PhaseShift[2048-44.1khz-32bit]/MS 20 Saw MPS.wav");
- osc_load_wav(&OSC_sound, "/home/gramanas/code/synth-project/waves/Free Wavetables[2048]/Korg Analog Synth PhaseShift[2048-44.1khz-32bit]/MonoPoly Saw PS1.wav");
+ // osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/test_lick.wav");
+ //osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/Free Wavetables[128]/FM Synthesis[128-44.1khz-16bit]/FM Sq- NotPM.wav");
+ //osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/Free Wavetables[2048]/Melda Oscillator[2048-44.1khz-32bit]/Melda SKEW.wav");
+ //osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/Free Wavetables[2048]/Filter Sweep[2048-44.1khz-32bit]/SweepSaw.wav");
+ //osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/Free Wavetables[2048]/Additive Synth[2048-44.1khz-32bit]/Add Synth7.wav");
+ //osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/Free Wavetables[2048]/Korg Analog Synth PhaseShift[2048-44.1khz-32bit]/MS 20 Saw MPS.wav");
+ osc_load_wav(&OSC_sound, "/home/grm/code/synth-project/waves/Free Wavetables[2048]/Korg Analog Synth PhaseShift[2048-44.1khz-32bit]/MonoPoly Saw PS1.wav");
OSC_sound.start = wvt_size*0;
OSC_sound.len = OSC_sound.start + wvt_size;
}
diff --git a/src/osc_tri.c b/src/osc_tri.c
index f0c9951..35abe7f 100644
--- a/src/osc_tri.c
+++ b/src/osc_tri.c
@@ -14,6 +14,7 @@ tri(int index)
else if (index == 2) return 0.0f;
else if (index == 3) return -1.0f;
//else return 0.0f;
+ return 0;
}
float
@@ -55,7 +56,6 @@ make_tri(const char * name)
{
osc_t * osc = (osc_t *)malloc(sizeof(osc_t));
- int len = strlen(name);
strncpy(osc->name, name, 16);
osc->data = NULL;
osc->len = 2;
diff --git a/src/oscillator.h b/src/oscillator.h
new file mode 100644
index 0000000..945d1e3
--- /dev/null
+++ b/src/oscillator.h
@@ -0,0 +1,22 @@
+struct oscillator {
+ int type;
+ char name[128];
+
+}
+
+struct sin_oscillator {
+ struct oscillator osc;
+
+}
+
+
+
+
+get_next_sample(osc_handle, sample_rate, time?)
+
+
+
+
+pa_callback // sound system callback to get next FRAMES_PER_BUFFER frames
+|__ get_frame // creates a single frame -> corresponding to X samples where X is the number of channels (2 for our stereo case)
+ |__ make_sample
diff --git a/src/raygui.h b/src/raygui.h
index 833725d..01e9c5b 100644
--- a/src/raygui.h
+++ b/src/raygui.h
@@ -1500,6 +1500,7 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
#define RAYGUI_TABBAR_ITEM_WIDTH 160
GuiState state = guiState;
+ (void)state;
int closing = -1;
Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height };
@@ -2411,6 +2412,7 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
int textLength = (int)strlen(text); // Length in bytes (UTF-8 string)
int byteSize = 0;
const char *textUTF8 = CodepointToUTF8(codepoint, &byteSize);
+ (void)textUTF8;
// Introduce characters
if ((textLength + byteSize) < textSize)
@@ -2908,6 +2910,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, in
// Color Panel control
Color GuiColorPanel(Rectangle bounds, const char *text, Color color)
{
+ (void)text;
const Color colWhite = { 255, 255, 255, 255 };
const Color colBlack = { 0, 0, 0, 255 };
@@ -2989,6 +2992,7 @@ Color GuiColorPanel(Rectangle bounds, const char *text, Color color)
// NOTE: Returns alpha value normalized [0..1]
float GuiColorBarAlpha(Rectangle bounds, const char *text, float alpha)
{
+ (void)text;
#if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE)
#define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10
#endif
@@ -3058,6 +3062,7 @@ float GuiColorBarAlpha(Rectangle bounds, const char *text, float alpha)
// float GuiColorBarLuminance() [BLACK->WHITE]
float GuiColorBarHue(Rectangle bounds, const char *text, float hue)
{
+ (void)text;
GuiState state = guiState;
Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + hue/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) };
@@ -3126,6 +3131,7 @@ float GuiColorBarHue(Rectangle bounds, const char *text, float hue)
// NOTE: bounds define GuiColorPanel() size
Color GuiColorPicker(Rectangle bounds, const char *text, Color color)
{
+ (void)text;
color = GuiColorPanel(bounds, NULL, color);
Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
@@ -3288,6 +3294,7 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co
// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
Vector2 GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs)
{
+ (void)text;
// Grid lines alpha amount
#if !defined(RAYGUI_GRID_ALPHA)
#define RAYGUI_GRID_ALPHA 0.15f
@@ -3946,6 +3953,7 @@ const char **GetTextLines(const char *text, int *count)
int len = 0;
*count = 1;
int lineSize = 0; // Stores current line size, not returned
+ (void)lineSize;
for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
{
diff --git a/src/sound.c b/src/sound.c
index 57baa6b..04b3f9b 100644
--- a/src/sound.c
+++ b/src/sound.c
@@ -1,27 +1,77 @@
#include "sound.h"
+#include <portaudio.h>
static void
StreamFinished( void* synthData )
{
- synth_t *synth = (synth_t *) synthData;
+ (void)synthData;
}
-void
-init_sound(synth_t * synth, PaStreamCallback *streamCallback)
+int
+get_soundcard_id(const char * name)
{
Pa_Initialize();
+ int i, c=0;
+ const PaDeviceInfo *deviceInfo;
+ for( i=0; i< Pa_GetDeviceCount(); i++ ) {
+ deviceInfo = Pa_GetDeviceInfo(i);
+ if (deviceInfo->maxOutputChannels == 0) {
+ continue;
+ }
+ if (!strcmp(name, deviceInfo->name)) {
+ Pa_Terminate();
+ return c;
+ }
+ c++;
+ }
+ Pa_Terminate();
+ return -1;
+}
+char *
+get_soundcards()
+{
+ Pa_Initialize();
int i;
+ const PaDeviceInfo *deviceInfo;
+ char *ret = (char *)malloc(sizeof(char) * 4096);
+ strcpy(ret, "");
+ for( i=0; i< Pa_GetDeviceCount(); i++ ) {
+ deviceInfo = Pa_GetDeviceInfo(i);
+ if (deviceInfo->maxOutputChannels == 0) {
+ continue;
+ }
+ strcat(ret, deviceInfo->name);
+ strcat(ret, ";");
+ }
+ ret[strlen(ret) - 1] = '\0';
+ Pa_Terminate();
+
+ return ret;
+}
+
+void
+init_sound(synth_t * synth, PaStreamCallback *streamCallback, const int device_id)
+{
+ printf("Before\n");
+ Pa_Initialize();
+ printf("after init\n");
+
+ int i, c=0;
const PaDeviceInfo *deviceInfo;
for( i=0; i< Pa_GetDeviceCount(); i++ ) {
- deviceInfo = Pa_GetDeviceInfo( i );
+ deviceInfo = Pa_GetDeviceInfo(i);
+ if (deviceInfo->maxOutputChannels == 0) {
+ continue;
+ }
//if (!strcmp("HyperX Cloud II Wireless: USB Audio (hw:2,0)", deviceInfo->name)) break;
- printf("dev: %s || %f\n", deviceInfo->name, deviceInfo->defaultSampleRate);
+ printf("dev: %s || %f || %d channels\n", deviceInfo->name, deviceInfo->defaultSampleRate, deviceInfo->maxOutputChannels);
//if (!strcmp("HDA Intel PCH: ALC1220 Analog (hw:0,0)", deviceInfo->name)) break;
- if (!strcmp("pulse", deviceInfo->name)) break;
+ if (c == device_id) break;
+ c++;
}
-
+
PaStreamParameters outputParameters;
outputParameters.device = i; Pa_GetDefaultOutputDevice(); /* default output device */
@@ -31,15 +81,20 @@ init_sound(synth_t * synth, PaStreamCallback *streamCallback)
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
- Pa_OpenStream(&(synth->stream),
- NULL, /* no input */
- &outputParameters,
- SAMPLE_RATE,
- FRAMES_PER_BUFFER,
- paClipOff | paDitherOff, /* we won't output out of range samples so don't bother clipping them */
- streamCallback,
- synth );
+ PaError err;
+ err = Pa_OpenStream(&(synth->stream),
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff | paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ streamCallback,
+ synth );
+ if (err != paNoError) {
+ printf("Error opening stream with %s!!!!!", Pa_GetDeviceInfo(outputParameters.device)->name);
+ }
+
Pa_SetStreamFinishedCallback(synth->stream, &StreamFinished);
Pa_StartStream(synth->stream);
diff --git a/src/sound.h b/src/sound.h
index 9e0c066..384c775 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -9,7 +9,10 @@
/* #define SAMPLE_RATE (44100) */
/* #define FRAMES_PER_BUFFER (256) */
-void init_sound(synth_t * synth, PaStreamCallback *streamCallback);
+void init_sound(synth_t * synth, PaStreamCallback *streamCallback, const int device_id);
+
+char *get_soundcards();
+int get_soundcard_id(const char * name);
void destroy_sound(synth_t * synth);
diff --git a/src/stats.h b/src/stats.h
new file mode 100644
index 0000000..a537a44
--- /dev/null
+++ b/src/stats.h
@@ -0,0 +1,10 @@
+#ifndef STATS_H
+#define STATS_H
+
+typedef struct stats_t {
+ uint64_t osc_calls;
+} stats_t;
+
+void print_stats(stats_t * stats);
+
+#endif /* STATS_H */
diff --git a/src/synth.c b/src/synth.c
index f7ae019..1b5187b 100644
--- a/src/synth.c
+++ b/src/synth.c
@@ -23,33 +23,19 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/* audio */
-#include <string.h>
-#include <portaudio.h>
-
-#include <portmidi.h>
-
-/* graphics */
-#include "synth_gui.h"
-
-/* synth */
#include "synth_engine.h"
-#include "midi.h"
-
-#define NUM_SECONDS (1)
-
-#define WAVE_SIZE (44100)
+#include "synth_gui.h"
+#include "web.h"
int
main(void) {
- midi_t midi;
-
synth_t * synth = init_synth();
- init_midi(&midi, synth);
+ init_web(synth);
+
rayrun(synth);
- terminate_midi(&midi);
+ free_web();
free_synth(synth);
return 0;
diff --git a/src/synth_engine.h b/src/synth_engine.h
index 3b0b238..5ff7d8d 100644
--- a/src/synth_engine.h
+++ b/src/synth_engine.h
@@ -64,6 +64,8 @@ typedef struct {
int tmp_index;
} synth_viz;
+struct midi_t;
+
typedef struct {
PaStream *stream;
@@ -71,7 +73,7 @@ typedef struct {
cc_t * ccs[128];
int cci;
-
+
cc_t cc_pitch;
cc_t cc_cutoff;
cc_t cc_resonance;
@@ -83,7 +85,15 @@ typedef struct {
cc_t cc_adsr_s;
cc_t cc_adsr_r;
cc_t cc_gain;
-
+
+ cc_t cc_f_adsr_a;
+ cc_t cc_f_adsr_peak;
+ cc_t cc_f_adsr_d;
+ cc_t cc_f_adsr_s;
+ cc_t cc_f_adsr_r;
+
+ int autogain;
+
float x;
midi_note_t midi_note[MIDI_NOTES];
@@ -91,6 +101,7 @@ typedef struct {
int midi_active_n;
adsr_t adsr;
+ adsr_t f_adsr;
lfo_t lfo;
@@ -102,8 +113,12 @@ typedef struct {
cc_t cc_del_time;
cc_t cc_del_feedback;
unsigned long long counter;
-
+
+ int f_adsr_enabled;
int filter;
+ int biquad;
+ char biquad_type;
+
int clamp;
int modifiers[16];
@@ -117,11 +132,21 @@ typedef struct {
int active;
int sound_active;
-
+
+ int soundcard_id;
+ int midi_device_id;
+
synth_viz viz;
+
+ struct midi_t * midi;
} synth_t;
synth_t * init_synth();
-void free_synth(synth_t * synth);
+void free_synth(synth_t *synth);
+void change_soundcard(synth_t *synth);
+void change_midi_device(synth_t *synth);
+
+int save_synth(synth_t *synth, const char *path);
+int load_synth(synth_t *synth, const char *path);
#endif /* SYNTH_ENGINE_H */
diff --git a/src/synth_engine_v2.c b/src/synth_engine_v2.c
index bfd1d4a..ad1be72 100644
--- a/src/synth_engine_v2.c
+++ b/src/synth_engine_v2.c
@@ -4,14 +4,17 @@
#include "filter.h"
#include "control.h"
#include "sound.h"
+#include "midi.h"
#include "osc.h"
+#include <libconfig.h>
#include <string.h>
#include <time.h>
float
gen0(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_sin(midi_note->wvt_index);
midi_note->wvt_index = osc_sin_next(f, midi_note->wvt_index);
return sample;
@@ -20,6 +23,7 @@ gen0(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen1(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_saw(midi_note->wvt_index);
midi_note->wvt_index = osc_saw_next(f, midi_note->wvt_index);
return sample;
@@ -28,6 +32,7 @@ gen1(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen2(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_weird(midi_note->wvt_index);
midi_note->wvt_index = osc_weird_next(f, midi_note->wvt_index);
return sample;
@@ -36,6 +41,7 @@ gen2(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen3(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_tri(midi_note->wvt_index);
midi_note->wvt_index = osc_tri_next(f, midi_note->wvt_index);
return sample;
@@ -44,6 +50,7 @@ gen3(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen4(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_sound(midi_note->wvt_index);
midi_note->wvt_index = osc_sound_next(f, midi_note->wvt_index);
return sample;
@@ -52,6 +59,7 @@ gen4(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen5(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_digisaw(midi_note->wvt_index);
midi_note->wvt_index = osc_digisaw_next(f, midi_note->wvt_index);
return sample;
@@ -60,6 +68,7 @@ gen5(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen6(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_sqr(midi_note->wvt_index);
midi_note->wvt_index = osc_sqr_next(f, midi_note->wvt_index);
return sample;
@@ -106,23 +115,60 @@ notes_active(synth_t *synth)
}
#define CC_GET(name) cc_iget(&synth->cc_##name, frame, FRAMES_PER_BUFFER)
+#define CC_SET(name, value) synth->cc_##name.mod = value - synth->cc_##name.target
float prev_sample = 0.0f;
-float
+#include "biquad_filter.c"
+
+biquad_filter_t biquad = {0};
+
+
+void
do_fliter(synth_t *synth, float *sample, unsigned int sample_rate, int frame)
{
- if (synth->filter) {
- // ALLL THE FILTERS
- float cutoff = CC_GET(cutoff);
- float reso = CC_GET(resonance);
+ synth->f_adsr.a = CC_GET(f_adsr_a);
+ synth->f_adsr.peak = CC_GET(f_adsr_peak);
+ synth->f_adsr.d = CC_GET(f_adsr_d);
+ synth->f_adsr.s = CC_GET(f_adsr_s);
+ synth->f_adsr.r = CC_GET(f_adsr_r);
+
+ // ALLL THE FILTERS
+ float cutoff = CC_GET(cutoff);
+ float reso = CC_GET(resonance);
+
+ if (synth->f_adsr_enabled) {
+ midi_note_t *note;
+ if (synth->midi_active_n != 0) {
+ float latest = 0;
+ for (int i = 0; i < synth->midi_active_n; i++) {
+ // reverse this and set latest to a big number for the first note played to take precedence
+ if (synth->midi_active[i]->noteOn > latest) {
+ latest = synth->midi_active[i]->noteOn;
+ note = synth->midi_active[i];
+ }
+ }
+
+ cutoff = 50 + cutoff * fix_adsr(&synth->f_adsr,
+ note->noteOn,
+ note->noteOff,
+ note->elapsed,
+ note->noteOffSample);
+ }
+ }
+ if (synth->filter) {
if (cutoff == 0) cutoff = 0.001;
lpf_update(reso, cutoff, sample_rate);
*sample = lpf_filter(*sample);
- update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, cutoff, reso);
- *sample = bw_low_pass(synth->fff, *sample);
+ /* update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, cutoff, reso); */
+ /* *sample = bw_low_pass(synth->fff, *sample); */
+ }
+ if (synth->biquad) {
+ //if (synth->cc_cutoff.mod || synth->cc_resonance.mod) //RUN ONLY WHEN THERE ARE CHANGES
+ biquad_calculate_coefficients(&biquad, cutoff, reso, sample_rate, synth->biquad_type);
+ *sample = biquad_process(&biquad, *sample);
}
}
@@ -161,6 +207,19 @@ get_max_sample(synth_t *synth, int test_size)
return max;
}
+# include <stdint.h> // uint32_t
+
+float Q_rsqrt(float number)
+{
+ union {
+ float f;
+ uint32_t i;
+ } conv = { .f = number };
+ conv.i = 0x5f3759df - (conv.i >> 1);
+ conv.f *= 1.5F - (number * 0.5F * conv.f * conv.f);
+ return conv.f;
+}
+
float
make_sample(synth_t * synth, unsigned int sample_rate, int frame)
{
@@ -174,7 +233,7 @@ make_sample(synth_t * synth, unsigned int sample_rate, int frame)
rms += synth->midi_active[i]->velocity * synth->midi_active[i]->velocity;
}
- rms = sqrt(rms / (float)synth->midi_active_n);
+ rms = 1.0 / Q_rsqrt(rms / (float)synth->midi_active_n);
//float max = get_max_sample(synth, 20);
synth->adsr.a = CC_GET(adsr_a);
@@ -202,15 +261,23 @@ make_sample(synth_t * synth, unsigned int sample_rate, int frame)
sample_rate);
}
+
/* filter */
do_fliter(synth, &sample, sample_rate, frame);
+
sample = CC_GET(gain) * sample;
// band stop for high freqs
//sample = bw_band_stop(synth->fff2, sample);
-
- if (synth->clamp) sample = clamp(sample, -1, 1);
+
+ //if (synth->clamp) sample = clamp(sample, -1, 1);
+
+ // autogain
+ if (synth->autogain && (sample >= 1 || sample <= -1)) {
+ synth->cc_gain.target *= 0.999;
+ }
+
//printf("CLICK! %f\n", fabsf(prev_sample) - fabsf(sample));
//if (fabsf(fabsf(prev_sample) - fabsf(sample)) > 0.03) printf("CLICK! (diff: %f)\n", fabsf(prev_sample) - fabsf(sample));
prev_sample = sample;
@@ -232,6 +299,7 @@ increment_synth(synth_t *synth)
{
synth->lfo.elapsed++;
synth->adsr.elapsed++;
+ synth->f_adsr.elapsed++;
for (int i = 0; i < synth->midi_active_n; i++) {
if (synth->midi_active[i])
@@ -239,23 +307,28 @@ increment_synth(synth_t *synth)
}
}
+float prev = 0;
+
void
-get_frame(void *outputBuffer, synth_t *synth, int i)
+get_frame(void *outputBuffer, synth_t *synth, int frame)
{
- float *out = (float*)outputBuffer + 2 * i;
- float s = 0.0f;
+ float *out = (float*)outputBuffer + (2 * frame);
+ float sample = 0.0f;
if (!notes_active(synth)) {
+ synth->f_adsr.elapsed = 0;
synth->active = 0;
+ // auto gain test
+ //synth->cc_gain.target = 1;
}
if (!synth->delay) {
synth->counter = 0;
}
- s = make_sample(synth, SAMPLE_RATE, i);
+ sample = make_sample(synth, SAMPLE_RATE, frame);
synth->counter++;
- if (synth->counter >= (int)(synth->cc_del_time.target * SAMPLE_RATE)) {
+ if (synth->counter >= (unsigned long long)(synth->cc_del_time.target * SAMPLE_RATE)) {
int idx = (synth->deli - (int)(synth->cc_del_time.target * SAMPLE_RATE)) % (SAMPLE_RATE * 10);
float tmp;
if (idx >= 0) {
@@ -264,18 +337,60 @@ get_frame(void *outputBuffer, synth_t *synth, int i)
tmp = synth->del[SAMPLE_RATE * 10 + idx];
}
- s = clamp(s + synth->cc_del_feedback.target * tmp, -1, 1);
+ sample = clamp(sample + synth->cc_del_feedback.target * tmp, -1, 1);
}
- add_to_delay(synth, s);
- *out++ = s;
- *out++ = s;
+ add_to_delay(synth, sample);
+
+
+
+ //sample = clamp(sample, -1, 1);
+
+ *out++ = sample;
+ *out++ = sample;
+
+ if (sample > 1.0f || sample < -1.0f)
+ printf("%f\n", sample);
+ if (prev != 0.0f && fabs(prev - sample) > 0.5f) {
+ printf("%.2f --> %.2f\n", prev, sample);
+ }
+ prev = sample;
// move time
increment_synth(synth);
// viz
- PaUtil_WriteRingBuffer(&synth->viz.wave_buffer, &s, 1);
+ PaUtil_WriteRingBuffer(&synth->viz.wave_buffer, &sample, 1);
+}
+
+/* void */
+/* smooth_buffer1(float *buffer) */
+/* { */
+/* return; */
+/* } */
+void smooth_buffer(float *buffer, int frames_per_buffer, float smooth_factor) {
+ if (smooth_factor < 0.0f || smooth_factor > 1.0f) {
+ printf("Invalid smooth factor. It should be between 0 and 1.\n");
+ return;
+ }
+
+ float prev_sample_ch1 = buffer[0]; // First sample for channel 1
+ float prev_sample_ch2 = buffer[1]; // First sample for channel 2
+
+ for (int i = 0; i < frames_per_buffer; i++) {
+ int ch1_index = 2 * i; // Index for channel 1
+ int ch2_index = 2 * i + 1; // Index for channel 2
+
+ // Smooth channel 1
+ buffer[ch1_index] = (1.0f - smooth_factor) * buffer[ch1_index] +
+ smooth_factor * prev_sample_ch1;
+ prev_sample_ch1 = buffer[ch1_index];
+
+ // Smooth channel 2
+ buffer[ch2_index] = (1.0f - smooth_factor) * buffer[ch2_index] +
+ smooth_factor * prev_sample_ch2;
+ prev_sample_ch2 = buffer[ch2_index];
+ }
}
@@ -292,7 +407,6 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
if (!synth->sound_active) return 0; //paContinue;
float buffer[2 * FRAMES_PER_BUFFER];
- float buffer2[2 * FRAMES_PER_BUFFER];
(void) timeInfo;
(void) statusFlags;
@@ -305,14 +419,15 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
cc_prep(synth->ccs[i]);
}
// fill buffer
- for( unsigned long i=0; i<framesPerBuffer; i++ ) {
+ for( unsigned long frame=0; frame<framesPerBuffer; frame++ ) {
// use iget inside
- get_frame(buffer, synth, i);
+ get_frame(buffer, synth, frame);
}
+ smooth_buffer(buffer, framesPerBuffer, 0.1f);
+
// output buffer
for( unsigned long i=0; i<framesPerBuffer * 2; i += 2 ) {
- // use iget inside
*out++ = buffer[i];
*out++ = buffer[i+1];
}
@@ -330,13 +445,6 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
return paContinue;
}
-void
-m_init_synth(synth_t * synth)
-{
- synth = (synth_t *)malloc(sizeof(synth_t));
-
-}
-
synth_t *
init_synth(void)
{
@@ -345,8 +453,9 @@ init_synth(void)
synth->cci = 0;
// CC(SYNTH, NAME, MIN, MAX, STEP, DEF)
- CC(synth->cc_cutoff, "cutoff", 10, 22000, 30, 5000);
- CC(synth->cc_resonance, "resonance", 1, 10, .02, 1);
+ CC(synth->cc_cutoff, "cutoff", 50, 22000, 30, 5000);
+ //CC(synth->cc_resonance, "resonance", 1, 10, .02, 1);
+ CC(synth->cc_resonance, "resonance", 0.01, 10, .02, 0.5);
CC(synth->cc_lfo_freq, "lfo_freq", 1, 1000, 2, 1);
CC(synth->cc_lfo_amp, "lfo_amp", 0, 1, .01f, 0);
CC(synth->cc_pitch, "pitch", -3, 4, 0.01f, 1);
@@ -359,7 +468,14 @@ init_synth(void)
CC(synth->cc_del_feedback, "feedback", 0, 1, 0.01f, 0.5f);
CC(synth->cc_gain, "gain", 0, 1, 0.01f, 0.5f);
- //synth->modi = 0;
+ CC(synth->cc_f_adsr_a, "fattack", 0, 3, 0.01f, 0.00);
+ CC(synth->cc_f_adsr_peak, "fpeak", 0, 1, 0.01f, 1.00);
+ CC(synth->cc_f_adsr_d, "fdecay", 0, 2, 0.01f, 0.3);
+ CC(synth->cc_f_adsr_s, "fsustain", 0, 1.0f, 0.01f, 0.7f);
+ CC(synth->cc_f_adsr_r, "frelease", 0, 5, 0.01f, 0.2f);
+
+ // synth->modi = 0;
+ synth->autogain = 1;
synth->x = 1;
@@ -370,6 +486,13 @@ init_synth(void)
synth->adsr.r = 0.4;
synth->adsr.elapsed = 0;
+ synth->f_adsr.a = 0.00001f;
+ synth->f_adsr.peak = 1.0f;
+ synth->f_adsr.d = 0.3;
+ synth->f_adsr.s = 0.7;
+ synth->f_adsr.r = 0.4;
+ synth->f_adsr.elapsed = 0;
+
synth->lfo.freq = 1.0f;
synth->lfo.amp = 0.0f;
synth->lfo.elapsed = 0;
@@ -394,9 +517,12 @@ init_synth(void)
synth->delay = 0;
synth->del = (float *) calloc(sizeof(float), SAMPLE_RATE * 30);
synth->deli = 0;
- synth->counter;
+ synth->counter = 0;
+ synth->f_adsr_enabled = 0;
synth->filter = 1;
+ synth->biquad = 0;
+ synth->biquad_type = 'l';
synth->clamp = 1;
synth->gen[0] = gen0;
@@ -414,9 +540,6 @@ init_synth(void)
synth->fff = create_bw_low_pass_filter(2, SAMPLE_RATE, 400);
synth->fff2 = create_bw_band_stop_filter(8, SAMPLE_RATE, 15000, 22000);
- synth->sound_active = 0;
- init_sound(synth, sound_gen);
-
synth->viz.rate_divider = 15;
// for (int i = 0; i < RING_SIZE; i++) synth->viz.wave_buffer_data[i] = 0;
synth->viz.wave_buffer_data = (float *)calloc(sizeof(float), RING_SIZE);
@@ -441,6 +564,16 @@ init_synth(void)
synth->wvt_pos = 0;
+
+
+ synth->sound_active = 0;
+ synth->soundcard_id = get_soundcard_id("default");
+ init_sound(synth, sound_gen, synth->soundcard_id);
+
+ synth->midi = (midi_t *)malloc(sizeof(midi_t));
+ synth->midi_device_id = get_midi_device_id("Midi Through Port-0");
+ init_midi(synth->midi, synth);
+
return synth;
}
@@ -448,6 +581,7 @@ void
free_synth(synth_t * synth)
{
destroy_sound(synth);
+ terminate_midi(synth->midi);
free(synth->viz.wave_buffer_data);
free(synth->viz.fft_buffer_data);
@@ -456,6 +590,8 @@ free_synth(synth_t * synth)
free(synth->viz.fft_input_buffer);
free(synth->viz.fft_output_buffer);
free(synth->viz.fft_smooth_buffer);
+
+ free(synth->midi);
free_bw_low_pass(synth->fff);
free_bw_band_stop(synth->fff2);
@@ -463,3 +599,169 @@ free_synth(synth_t * synth)
free(synth->del);
free(synth);
}
+
+void
+change_soundcard(synth_t *synth)
+{
+ destroy_sound(synth);
+ synth->sound_active = 0;
+ init_sound(synth, sound_gen, synth->soundcard_id);
+}
+
+void
+change_midi_device(synth_t *synth)
+{
+ terminate_midi(synth->midi);
+ free(synth->midi);
+
+ synth->midi = (midi_t *)malloc(sizeof(midi_t));
+ init_midi(synth->midi, synth);
+}
+
+int
+load_synth(synth_t *synth, const char *path)
+{
+ (void)path;
+ config_t cfg;
+ const char *str;
+ double FLOAT;
+
+ config_init(&cfg);
+
+ /* Read the file. If there is an error, report it and exit. */
+ if(! config_read_file(&cfg, "TEST.cfg"))
+ {
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
+ config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ return(EXIT_FAILURE);
+ }
+
+ /* Get the store name. */
+ if(config_lookup_string(&cfg, "synth.name", &str))
+ printf("LOADING: %s ----\n---\n", str);
+ else
+ fprintf(stderr, "No 'synth.name' setting in configuration file.\n");
+
+ config_lookup_int(&cfg, "synth.generator", &synth->geni);
+
+ config_lookup_float(&cfg, "synth.adsr.a", &FLOAT);
+ synth->cc_adsr_a.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.peak", &FLOAT);
+ synth->cc_adsr_peak.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.d", &FLOAT);
+ synth->cc_adsr_d.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.s", &FLOAT);
+ synth->cc_adsr_s.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.r", &FLOAT);
+ synth->cc_adsr_r.target = FLOAT;
+
+ config_lookup_int(&cfg, "synth.delay.enable", &synth->delay);
+ config_lookup_float(&cfg, "synth.delay.time", &FLOAT);
+ synth->cc_del_time.target = FLOAT;
+ config_lookup_float(&cfg, "synth.delay.feedback", &FLOAT);
+ synth->cc_del_feedback.target = FLOAT;
+
+ config_lookup_int(&cfg, "synth.filter.enable", &synth->filter);
+ config_lookup_float(&cfg, "synth.filter.cutoff", &FLOAT);
+ synth->cc_cutoff.target = FLOAT;
+ config_lookup_float(&cfg, "synth.filter.resonance", &FLOAT);
+ synth->cc_resonance.target = FLOAT;
+
+ config_lookup_float(&cfg, "synth.lfo.freq", &FLOAT);
+ synth->cc_lfo_freq.target = FLOAT;
+ config_lookup_float(&cfg, "synth.lfo.amp", &FLOAT);
+ synth->cc_lfo_amp.target = FLOAT;
+
+ config_lookup_int(&cfg, "synth.autogain", &synth->autogain);
+ config_lookup_float(&cfg, "synth.gain", &FLOAT);
+ synth->cc_gain.target = FLOAT;
+
+ config_destroy(&cfg);
+ return(EXIT_SUCCESS);
+}
+
+int
+save_synth(synth_t *synth, const char *path)
+{
+ (void)path;
+
+ static const char *output_file = "TEST.cfg";
+
+ config_t cfg;
+ config_setting_t *root, *setting, *group, *adsr, *delay, *lfo, *filter;
+
+ config_init(&cfg);
+ root = config_root_setting(&cfg);
+
+ /* Add some settings to the configuration. */
+ group = config_setting_add(root, "synth", CONFIG_TYPE_GROUP);
+
+ setting = config_setting_add(group, "name", CONFIG_TYPE_STRING);
+ config_setting_set_string(setting, "example synth name");
+
+ setting = config_setting_add(group, "generator", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->geni);
+
+ adsr = config_setting_add(group, "adsr", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(adsr, "a", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_a.target);
+ setting = config_setting_add(adsr, "peak", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_peak.target);
+ setting = config_setting_add(adsr, "d", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_d.target);
+ setting = config_setting_add(adsr, "s", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_s.target);
+ setting = config_setting_add(adsr, "r", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_r.target);
+
+ delay = config_setting_add(group, "delay", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(delay, "enable", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->delay);
+ setting = config_setting_add(delay, "time", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_del_time.target);
+ setting = config_setting_add(delay, "feedback", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_del_feedback.target);
+
+ filter = config_setting_add(group, "filter", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(filter, "enable", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->filter);
+ setting = config_setting_add(filter, "cutoff", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_cutoff.target);
+ setting = config_setting_add(filter, "resonance", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_resonance.target);
+
+ lfo = config_setting_add(group, "lfo", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(lfo, "freq", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_lfo_freq.target);
+ setting = config_setting_add(lfo, "amp", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_lfo_amp.target);
+
+ setting = config_setting_add(group, "autogain", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->autogain);
+ setting = config_setting_add(group, "gain", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_gain.target);
+
+
+ /* array = config_setting_add(root, "numbers", CONFIG_TYPE_ARRAY); */
+
+ /* for(i = 0; i < 10; ++i) */
+ /* { */
+ /* setting = config_setting_add(array, NULL, CONFIG_TYPE_INT); */
+ /* config_setting_set_int(setting, 10 * i); */
+ /* } */
+
+ /* Write out the new configuration. */
+ if(! config_write_file(&cfg, output_file))
+ {
+ fprintf(stderr, "Error while writing file.\n");
+ config_destroy(&cfg);
+ return(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, "New configuration successfully written to: %s\n",
+ output_file);
+
+ config_destroy(&cfg);
+ return(EXIT_SUCCESS);
+}
diff --git a/src/synth_gui.c b/src/synth_gui.c
index 85a5be2..6f8e06b 100644
--- a/src/synth_gui.c
+++ b/src/synth_gui.c
@@ -1,4 +1,5 @@
#include "synth_gui.h"
+#include <portaudio.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h"
//#include "raylib.h"
@@ -24,8 +25,9 @@ draw_text(synth_t * synth, int x, int y)
DrawRectangleLines(x - 6, y - 3, 120, 3 + (count * offset) + 3, GRAY);
}
+
void
-mouse(synth_t *synth, PaStream *stream)
+mouse(synth_t *synth)
{
float m = GetMouseWheelMove();
int x = 0;
@@ -72,11 +74,11 @@ mouse(synth_t *synth, PaStream *stream)
}
void
-keyboard(synth_t * synth, PaStream *stream)
+keyboard(synth_t * synth)
{
int keys[] = {KEY_Q, KEY_TWO, KEY_W, KEY_THREE, KEY_E, KEY_R, KEY_FIVE, KEY_T, KEY_SIX, KEY_Y, KEY_SEVEN, KEY_U, KEY_I, KEY_NINE, KEY_O, KEY_ZERO, KEY_P, KEY_LEFT_BRACKET, KEY_EQUAL, KEY_RIGHT_BRACKET, 0};
- float note;
+ //float note;
for (int i = 0; keys[i]; i++) {
if (IsKeyPressed(keys[i])) {
@@ -108,7 +110,7 @@ keyboard(synth_t * synth, PaStream *stream)
if (IsKeyReleased(keys[i])) {
synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream);
synth->midi_note[i].noteOffSample = synth->midi_note[i].elapsed;
- note = notes[i % 12][(synth->octave + (i / 12)) % 8];
+ //note = notes[i % 12][(synth->octave + (i / 12)) % 8];
}
}
@@ -244,19 +246,19 @@ draw_adsr(synth_t *synth, int x, int y, int width, int height)
int x_prev = x;
for (int i = 0; i < synth->midi_active_n; i++) {
int rec_y = y + height - 1 +
- 4.5 * floor( (WIDTH / 24) *
+ 4.5 * floor( (width / 24) *
- fix_adsr(&synth->adsr,
synth->midi_active[i]->noteOn,
synth->midi_active[i]->noteOff,
synth->midi_active[i]->elapsed,
synth->midi_active[i]->noteOffSample));
- int rec_width = (WIDTH - x - x) / synth->midi_active_n;
- int rec_height = HEIGHT - rec_y;
+ int rec_width = width / synth->midi_active_n;
+ int rec_height = rec_y;
int red, green, blue;
frequencyToColor(synth->midi_active[i]->freq * 25, &red, &green, &blue);
- DrawRectangleGradientV(x_prev, rec_y - 10, rec_width, rec_height, ColorAlpha(BLUE, .2) ,ColorAlpha((Color) {red, green, blue}, .2));
+ DrawRectangleGradientV(x_prev, rec_y - 10, rec_width, rec_height, ColorAlpha(BLUE, .2) ,ColorAlpha((Color) {red, green, blue, 1}, .2));
//DrawRectangleGradientV(x_prev, rec_y - 10, rec_width, rec_height, ColorAlpha(GREEN, .2) ,ColorAlpha(RED, .2));
//DrawRectangleLines(x_prev, rec_y - 10, rec_width, rec_height, GRAY);
x_prev += rec_width;
@@ -291,8 +293,8 @@ draw_wave(synth_t *synth, int x, int y, int width, int height)
void
draw_fft(synth_t *synth, int x, int y, int width, int height)
{
- int viz_size = width * synth->viz.rate_divider;
- int fft_output_len = viz_size / 2 + 1;
+ size_t viz_size = width * synth->viz.rate_divider;
+ size_t fft_output_len = viz_size / 2 + 1;
fftwf_complex* output = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fft_output_len);
@@ -348,7 +350,7 @@ draw_fft(synth_t *synth, int x, int y, int width, int height)
y + height,
};
float thick = cell_width/3*sqrtf(t);
- DrawLineEx(startPos, endPos, thick, BLUE);
+ DrawLineEx(startPos, endPos, thick, color);
}
fftwf_free(output);
@@ -438,7 +440,7 @@ draw_adsr_graph(synth_t * synth, int x, int y, int width, int height)
0, // note Off
(float)i/width * total_samples,
0);
- } else if (i < a + d + s + r) { // draw release
+ } else if (r && i < a + d + s + r) { // draw release
point = fix_adsr(&adsr,
0, // note On
1, // note Off
@@ -453,7 +455,6 @@ draw_adsr_graph(synth_t * synth, int x, int y, int width, int height)
DrawPixel(i + x , y + height - adsr_graph[i], RED);
}
- int off_idx = a + d + s;
for (int i = 0; i < synth->midi_active_n; i++) {
midi_note_t * note = synth->midi_active[i];
int elapsed_samples = note->elapsed;
@@ -482,7 +483,7 @@ draw_signals(synth_t * synth, int x, int y, int width, int height)
DrawRectangleLines(x, y, width, height, WHITE);
if (synth->viz.wave_enabled || synth->viz.spectrum_enabled)
- synth->viz.rate_divider = GuiSlider((Rectangle){ x + (width / 2) / 2, y - 12, width / 2, 12 }, "", NULL, synth->viz.rate_divider , 1, 150);
+ synth->viz.rate_divider = GuiSlider((Rectangle){ x + (width / 2.0) / 2, y - 12, width / 2.0, 12 }, "", NULL, synth->viz.rate_divider , 1, 150);
int viz_size = width * synth->viz.rate_divider;
@@ -529,30 +530,33 @@ draw_signals(synth_t * synth, int x, int y, int width, int height)
draw_adsr_graph(synth, x + 20, y + 20, width - 40, height - 40);
}
}
+
char * flag = NULL;
+char * flag_circle = NULL;
void
draw_cc_circle(cc_t * cc, int x, int y, int width, int height) {
//DrawRectangleLines(x, y, width, height, WHITE);
if (CheckCollisionPointRec(GetMousePosition(), (Rectangle){x, y, width, height})) {
if (IsMouseButtonPressed(0)) {
- flag = cc->name;
+ flag_circle = cc->name;
}
}
- if (IsMouseButtonDown(0) && flag == cc->name) {
+ if (IsMouseButtonDown(0) && flag_circle == cc->name) {
Vector2 dx = GetMouseDelta();
int x = 1;
if (IsKeyDown(KEY_LEFT_SHIFT)) {
x = 3;
+ // test x that steps cc in 10 segments
+ x = (cc->max - cc->min) / (10 * cc->step);
}
if (dx.y < 0) cc_step(cc, 1*x);
if (dx.y > 0) cc_step(cc, -1*x);
}
- if (IsMouseButtonReleased(0) && flag == cc->name) {
- flag = 0;
+ if (IsMouseButtonReleased(0) && flag_circle == cc->name) {
+ flag_circle = 0;
}
-
int min = 110;
int max = 110 + (360+70 - 110) * (cc->target) / (cc->max - cc->min);
@@ -572,7 +576,8 @@ map(float value, float start1, float end1, float start2, float end2) {
return start2 + (end2 - start2) * ((value - start1) / (end1 - start1));
}
-
+#define CC_SET(cc, value) cc->mod = value - cc->target
+#include "web.h"
void
draw_cc_hbar(cc_t * cc, int x, int y, int width, int height) {
char buf1[32], buf2[32];
@@ -586,18 +591,24 @@ draw_cc_hbar(cc_t * cc, int x, int y, int width, int height) {
}
if (IsMouseButtonDown(0) && flag == cc->name) {
if (p.x < x) {
- cc->target = cc->min;
+ //cc->target = cc->min;
+ cc_set(cc, cc->min);
} else if (p.x >= x + width) {
- cc->target = cc->max;
+ //cc->target = cc->max;
+ cc_set(cc, cc->max);
} else {
- cc->target = (cc->min + (cc->max - cc->min) * ((((p.x - x) * (float)1/width) - 0) / (1 - 0)));
+ //cc->target = (cc->min + (cc->max - cc->min) * ((((p.x - x) * (float)1/width) - 0) / (1 - 0)));
+ cc_set(cc, (cc->min + (cc->max - cc->min) * ((((p.x - x) * (float)1/width) - 0) / (1 - 0))));
}
+ char tmp[128] = "";
+ sprintf(tmp, "%f", cc->value);
+ ws_send_message(tmp);
}
if (IsMouseButtonReleased(0) && flag == cc->name) {
flag = 0;
}
- int current = width * (cc->target - cc->min) / (cc->max - cc->min) + cc->min;
+ //int current = width * (cc->target - cc->min) / (cc->max - cc->min) + cc->min;
int fill_width = map(cc->target, cc->min, cc->max, 0, width - 2);
@@ -614,7 +625,7 @@ draw_cc_hbar(cc_t * cc, int x, int y, int width, int height) {
void
draw_cc_vbar(cc_t * cc, int x, int y, int width, int height) {
char buf1[32], buf2[32];
- int current = height * (cc->target - cc->min) / (cc->max - cc->min) + cc->min - 1;
+ //int current = height * (cc->target - cc->min) / (cc->max - cc->min) + cc->min - 1;
Vector2 p = GetMousePosition();
@@ -625,11 +636,14 @@ draw_cc_vbar(cc_t * cc, int x, int y, int width, int height) {
}
if (IsMouseButtonDown(0) && flag == cc->name) {
if (p.y < y) {
- cc->target = cc->max;
+ //cc->target = cc->max;
+ cc_set(cc, cc->max);
} else if (p.y >= y + height) {
- cc->target = cc->min;
+ //cc->target = cc->min;
+ cc_set(cc, cc->min);
} else {
- cc->target = cc->min + cc->max - (cc->min + (cc->max - cc->min) * ((((p.y - y) * (float)1/height) - 0) / (1 - 0)));
+ //cc->target = cc->min + cc->max - (cc->min + (cc->max - cc->min) * ((((p.y - y) * (float)1/height) - 0) / (1 - 0)));
+ cc_set(cc, (cc->min + cc->max - (cc->min + (cc->max - cc->min) * ((((p.y - y) * (float)1/height) - 0) / (1 - 0)))));
}
}
if (IsMouseButtonReleased(0) && flag == cc->name) {
@@ -654,16 +668,21 @@ draw_bars(synth_t * synth, int x, int y, int width, int height, int offset)
{
int count = 0;
- draw_cc_hbar(&synth->cc_adsr_a, x, y + count++ * (height + offset), width, height);
- draw_cc_hbar(&synth->cc_adsr_peak, x, y + count++ * (height + offset), width, height);
- draw_cc_hbar(&synth->cc_adsr_d, x, y + count++ * (height + offset), width, height);
- draw_cc_hbar(&synth->cc_adsr_s, x, y + count++ * (height + offset), width, height);
- draw_cc_hbar(&synth->cc_adsr_r, x, y + count++ * (height + offset), width, height);
- draw_cc_hbar(&synth->cc_gain, x, y + count++ * (height + offset), width, height);
+ draw_cc_hbar(&synth->cc_adsr_a , x, y + count++ * (height + offset), width, height);
+ synth->f_adsr_enabled = GuiCheckBox((Rectangle){ x + width + offset, y + (count - 1) * (height + offset), height, 16 }, "", synth->f_adsr_enabled);
+ draw_cc_hbar(&synth->cc_adsr_peak , x, y + count++ * (height + offset), width, height);
+ draw_cc_hbar(&synth->cc_adsr_d , x, y + count++ * (height + offset), width, height);
+ draw_cc_hbar(&synth->cc_adsr_s , x, y + count++ * (height + offset), width, height);
+ draw_cc_hbar(&synth->cc_adsr_r , x, y + count++ * (height + offset), width, height);
+ draw_cc_hbar(&synth->cc_gain, x, y + count++ * (height + offset), width, height);
+ synth->autogain = GuiCheckBox((Rectangle){ x + width + offset, y + (count - 1) * (height + offset), height, 16 }, "", synth->autogain);
draw_cc_hbar(&synth->cc_del_feedback, x, y + count++ * (height + offset), width, height);
- draw_cc_hbar(&synth->cc_del_time, x, y + count++ * (height + offset), width, height);
+ draw_cc_hbar(&synth->cc_del_time , x, y + count++ * (height + offset), width, height);
}
+#include "sound.h"
+#include "midi.h"
+
void
rayrun(synth_t *synth){
PaTime current_time = 0;
@@ -671,18 +690,40 @@ rayrun(synth_t *synth){
osc_sound(0);
+ char *midi_devices = get_midi_devices();
+ //char *midi_devices = "test1;test2;test3";
+ char *soundcards = get_soundcards();
+ int old_soundcard_id = synth->soundcard_id;
+ int old_midi_device_id = synth->midi_device_id;
+
InitWindow(WIDTH, HEIGHT, "Raylib synth");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
while (!WindowShouldClose()) {
- keyboard(synth, synth->stream);
- mouse(synth, synth->stream);
+ keyboard(synth);
+ mouse(synth);
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(BLACK);
- draw_cc_circle(&synth->cc_pitch, 30, 250, 30, 30);
+ int fb = 0;
+ int foffset = 9;
+ draw_cc_circle(&synth->cc_adsr_a, 30 + (30 + foffset) * fb++, 180, 30, 30);
+ draw_cc_circle(&synth->cc_adsr_peak, 30 + (30 + foffset) * fb++, 180, 30, 30);
+ draw_cc_circle(&synth->cc_adsr_d, 30 + (30 + foffset) * fb++, 180, 30, 30);
+ draw_cc_circle(&synth->cc_adsr_s, 30 + (30 + foffset) * fb++, 180, 30, 30);
+ draw_cc_circle(&synth->cc_adsr_r, 30 + (30 + foffset) * fb++, 180, 30, 30);
+
+ draw_cc_circle(&synth->cc_pitch, 30, 220, 30, 30);
+
+ fb = 0;
+ draw_cc_circle(&synth->cc_f_adsr_a, 30 + (30 + foffset) * fb++, 260, 30, 30);
+ draw_cc_circle(&synth->cc_f_adsr_peak, 30 + (30 + foffset) * fb++, 260, 30, 30);
+ draw_cc_circle(&synth->cc_f_adsr_d, 30 + (30 + foffset) * fb++, 260, 30, 30);
+ draw_cc_circle(&synth->cc_f_adsr_s, 30 + (30 + foffset) * fb++, 260, 30, 30);
+ draw_cc_circle(&synth->cc_f_adsr_r, 30 + (30 + foffset) * fb++, 260, 30, 30);
+
draw_cc_hbar(&synth->cc_cutoff, 30, 300, 256, 24);
draw_cc_vbar(&synth->cc_resonance, 330, 20, 24, 256);
//draw_cc_vbar(&synth->cc_adsr_s, 30, 250, 30, 30);
@@ -691,20 +732,32 @@ rayrun(synth_t *synth){
// GUI
char buf[64];
snprintf(buf, sizeof buf, "%d", synth->wvt_pos);
- synth->wvt_pos = GuiSlider((Rectangle){WIDTH / 2 - 108, 150 + 42 + 42, 216, 24 }, "", buf, synth->wvt_pos , 0, 127);
+ synth->wvt_pos = GuiSlider((Rectangle){WIDTH / 2.0 - 108, 150 + 42 + 42, 216, 24 }, "", buf, synth->wvt_pos , 0, 127);
set_sound_start(synth->wvt_pos*2048);
set_sound_len(synth->wvt_pos*2048 + 2048);
draw_bars(synth, 20, 20, 200, 16, 3);
draw_text(synth, WIDTH / 2 - 108, 20);
- if ( GuiButton((Rectangle){ WIDTH / 2 - 108, 150 - 6 - 6 + 42, 216, 6 }, "")) {
+ if ( GuiButton((Rectangle){ WIDTH / 2.0 - 108, 150 - 6 - 6 + 42, 216, 6 }, "")) {
synth->x = 1;
}
snprintf(buf, sizeof buf, "%.1f", synth->x);
- synth->x = GuiSlider((Rectangle){ WIDTH / 2 - 108, 150 + 42, 216, 24 }, "x", buf, synth->x , 0.0f, 2.0f);
+ synth->x = GuiSlider((Rectangle){ WIDTH / 2.0 - 108, 150 + 42, 216, 24 }, "x", buf, synth->x , 0.0f, 2.0f);
- synth->filter = GuiToggle((Rectangle){ WIDTH - 100 - 50 - 100 - 50 , 50 , 100, 24 }, "FILTER", synth->filter);
+ synth->filter = GuiToggle((Rectangle){ WIDTH - 100 - 50 - 100 - 50 , 50 , 46, 24 }, "LP", synth->filter);
+ synth->biquad = GuiToggle((Rectangle){ WIDTH - 100 - 50 - 100 - 50 + 46 + 8 , 50 , 46, 24 }, "bq", synth->biquad);
+ if (synth->biquad) {
+ if (GuiToggle((Rectangle){WIDTH - 100 - 50 - 100 - 50 , 50 + 24 + 6 + 24 + 6, 24, 24}, "l", synth->biquad_type == 'l')) {
+ synth->biquad_type = 'l';
+ }
+ if (GuiToggle((Rectangle){WIDTH - 100 - 50 - 100 - 50 + 24 + 8, 50 + 24 + 6 + 24 + 6, 24, 24}, "b", synth->biquad_type == 'b')) {
+ synth->biquad_type = 'b';
+ }
+ if (GuiToggle((Rectangle){WIDTH - 100 - 50 - 100 - 50 + 24 + 8 + 24 + 8 , 50 + 24 + 6 + 24 + 6, 24, 24}, "h", synth->biquad_type == 'h')) {
+ synth->biquad_type = 'h';
+ }
+ }
GuiSpinner((Rectangle){ WIDTH - 100 - 50 , 50, 100, 24 }, "oct: ", &(synth->octave), 0, 7, 0);
snprintf(buf, sizeof buf, "generator %d --> ", synth->geni);
@@ -712,6 +765,17 @@ rayrun(synth_t *synth){
synth->clamp = GuiToggle((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6, 100, 24 }, "clamp", synth->clamp);
synth->delay = GuiToggle((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6 + 24 + 6, 100, 24 }, "delay", synth->delay);
+
+ if ( GuiButton((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6, 100, 24 }, "SAVE!")) {
+ save_synth(synth, "asdas");
+ }
+
+ if ( GuiButton((Rectangle){ WIDTH - 100 - 50, 50 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6, 100, 24 }, "LOAD!")) {
+ load_synth(synth, "asdas");
+ }
+
+ static int edit_midi = 0;
+ static int edit_sound = 0;
// signals
draw_signals(synth, 20, 390, WIDTH - 2*20, 200);
@@ -722,6 +786,34 @@ rayrun(synth_t *synth){
/* snprintf(buf, sizeof buf, "stream time: %f", Pa_GetStreamTime(synth->stream)); */
/* DrawText(buf, WIDTH / 2 -300, HEIGHT - 300, 11, LIGHTGRAY); */
+ // midi dev
+ if (GuiDropdownBox(
+ (Rectangle){WIDTH - 200 - 50,
+ 50 + 24 + 6 + 24 + 6 + 24 + 6 + 24 + 6 , 200,
+ 24},
+ midi_devices, &synth->midi_device_id, edit_midi)) {
+ edit_midi = !edit_midi;
+ }
+
+ if (old_midi_device_id != synth->midi_device_id) {
+ old_midi_device_id = synth->midi_device_id;
+ change_midi_device(synth);
+ }
+
+ // audio dev
+ if (GuiDropdownBox(
+ (Rectangle){WIDTH - 300 - 50,
+ 12, 300,
+ 24},
+ soundcards, &synth->soundcard_id, edit_sound)) {
+ edit_sound = !edit_sound;
+ }
+
+ if (old_soundcard_id != synth->soundcard_id) {
+ old_soundcard_id = synth->soundcard_id;
+ change_soundcard(synth);
+ }
+
EndDrawing();
//----------------------------------------------------------------------------------
@@ -729,6 +821,9 @@ rayrun(synth_t *synth){
//printf("%f :: %ld\n", current_time - prev_time, phase);
prev_time = current_time;
+ (void)prev_time;
}
+ free(soundcards);
+ free(midi_devices);
CloseWindow();
}
diff --git a/src/synth_math.h b/src/synth_math.h
index 2dd9f83..029ed74 100644
--- a/src/synth_math.h
+++ b/src/synth_math.h
@@ -3,19 +3,23 @@
#include <stddef.h>
-static long long
+// do I really want inline? used to be static
+inline long long
gcd(long long a, long long b)
{
- long long rem;
- rem=a-(a/b*b);
- if(rem==0)
- return b;
- else
- gcd(b,rem);
+ long long rem;
+ rem=a-(a/b*b);
+ if(rem==0)
+ return b;
+ else
+ gcd(b, rem);
+
+ // unreachable
+ return 0;
}
// Function to return LCM of two numbers
-static long long
+inline long long
lcm(long long a, long long b)
{
return (a / gcd(a, b)) * b;
@@ -30,7 +34,7 @@ clamp(float f, int min, int max)
}
/* 1d convolution */
-static void
+inline void
convole(float *signal, float *filter,
size_t signal_size, size_t filter_size, float *out) {
for (size_t i = 0; i < filter_size + signal_size; i++) {
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..f5648b9
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,38 @@
+#ifndef SYNTH_TYPES_H
+#define SYNTH_TYPES_H
+
+typedef struct {
+ void * data;
+ int size;
+ int cap;
+} list_t;
+
+list_t a[128];
+
+/* void */
+/* ll_add(llist * l, void * data) { */
+/* llist * tmp = l; */
+/* int i = 0; */
+/* do { */
+/* if (!tmp->data) { */
+/* break; */
+/* } */
+/* i++; */
+/* tmp = l->next; */
+/* } while (d); */
+/* tmp->data = data; */
+/* tmp->id = i; */
+/* } */
+
+/*
+ I need a list
+ - O(1) length calculation
+ - O(1) access for each element
+
+
+
+
+
+ */
+
+#endif /* SYNTH_TYPES_H */
diff --git a/src/web.c b/src/web.c
new file mode 100644
index 0000000..e23d8b2
--- /dev/null
+++ b/src/web.c
@@ -0,0 +1,257 @@
+#include "web.h"
+
+#include <libwebsockets.h>
+#include <pthread.h>
+#include <microhttpd.h>
+#include <unistd.h>
+
+
+#define HTTP_PORT 9966
+#define WS_PORT 9967
+
+static struct lws *client_wsi = NULL;
+synth_t * synthx;
+struct MHD_Daemon *server;
+pthread_t server_thread;
+#define BUFFER_SIZE 1024 * 4
+char message_buffer[BUFFER_SIZE];
+
+// Function to handle slider changes
+void handle_slider_change(void *cls, int value) {
+ synth_t *synth = (synth_t*)cls;
+ printf("Slider changed: %d\n", value);
+ cc_set(&synth->cc_cutoff, value);
+}
+
+void handle_button_click(void *cls) {
+ printf("Button clicked!!!");
+ synth_t *synth = (synth_t*)cls;
+
+ int i = 5;
+ //printf("Note On : %s[%d] %fHz\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8, note);
+ synth->midi_note[i].freq = 16.35160 * pow(2, (synth->octave + i / 12.0));
+ //synth->midi_note[i].freq = notes[i % 12][(synth->octave + (i / 12)) % 8];
+ synth->midi_note[i].channel = -1;
+ synth->midi_note[i].noteOn = Pa_GetStreamTime(synth->stream);
+ synth->midi_note[i].noteOff = 0;
+ synth->midi_note[i].velocity = 1.0;
+ synth->midi_note[i].elapsed = 0;
+ synth->midi_note[i].active = 1;
+ int flag = 1;
+ for (int j = 0; j < synth->midi_active_n; j++) {
+ if (synth->midi_active[j] == &synth->midi_note[i]) {
+ flag = 0;
+ }
+ }
+ if (flag) {
+ synth->midi_active[synth->midi_active_n++] = &synth->midi_note[i];
+ }
+
+ //synth->adsr.elapsed = 0;
+ synth->active = 1;
+
+ usleep(500000);
+
+ synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream);
+ synth->midi_note[i].noteOffSample = synth->midi_note[i].elapsed;
+
+}
+
+
+const char *html_header =
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n"
+ "\r\n";
+
+// HTML page with a slider
+const char *html_content =
+ "<!DOCTYPE html>\n"
+ "<html>\n"
+ "<head>\n"
+ "<title>C SYNTH WEB!</title>\n"
+ "</head>\n"
+ "<body>\n"
+ "<input id='slider' style='width: 100%; height: 200px;' type='range' min='1' max='22000' />\n"
+ "<button onclick='onButtonClick()'>Trigger</button>\n"
+ "<button id='but'>ws</button>\n"
+ "<script>\n"
+ "const ws = new WebSocket('ws://10.0.0.10:9967');\n"
+ "const slider = document.getElementById('slider');\n"
+ "const but = document.getElementById('but');\n"
+ "\n"
+ "slider.oninput = function() { ws.send(slider.value); };\n"
+ "\n"
+ "but.onclick = function() { ws.send('THIS IS A TEST DONT KILL ME'); };\n"
+ "\n"
+ "ws.onmessage = function(event) {\n"
+ " console.log('Message from server: ' + event.data);\n"
+ " slider.value = parseInt(event.data);"
+ "};\n"
+ "ws.onopen = function() {\n"
+ " console.log('Connected to WebSocket server');\n"
+ "};\n"
+ "ws.onerror = function(error) {\n"
+ " console.error('WebSocket error: ' + error);\n"
+ "};\n"
+ "</script>\n"
+ "</body>\n"
+ "</html>\n";
+
+// HTTP request handler
+enum MHD_Result handle_request(void *cls, struct MHD_Connection *connection,
+ const char *url, const char *method,
+ const char *version, const char *upload_data,
+ size_t *upload_data_size, void **con_cls) {
+ struct MHD_Response *response;
+ enum MHD_Result ret;
+
+ if (strcmp(url, "/slider") == 0 && strcmp(method, "GET") == 0) {
+ const char *value_str = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "value");
+ if (value_str) {
+ int value = atoi(value_str);
+ handle_slider_change(cls, value);
+ }
+ response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+ }
+
+ if (strcmp(url, "/button") == 0 && strcmp(method, "GET") == 0) {
+ handle_button_click(cls);
+ response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+ }
+
+ response = MHD_create_response_from_buffer(strlen(html_content), (void *)html_content, MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+ MHD_destroy_response(response);
+ return ret;
+}
+
+// Callback to handle WebSocket events
+static int callback_ws(struct lws *wsi, enum lws_callback_reasons reason,
+ void *user, void *in, size_t len) {
+ char buf[10000] = "";
+ char tmp[10000] = "";
+ switch (reason) {
+ case LWS_CALLBACK_ESTABLISHED: { // When a connection is established
+ client_wsi = wsi; // Store the WebSocket connection for later use
+ printf("WebSocket connection established with client: %p\n", wsi);
+ /* const char *msg = "Hello, Client!"; */
+ /* printf("Sending message: %s\n", msg); */
+ /* int n = lws_write(wsi, (unsigned char *)msg, strlen(msg), LWS_WRITE_TEXT); */
+ /* if (n < 0) { */
+ /* printf("Error sending message, error code: %d\n", n); */
+ /* } */
+ break;
+ }
+ case LWS_CALLBACK_RECEIVE: { // When a message is received
+ char buffer[128];
+ snprintf(buffer, sizeof(buffer), "%.*s", (int)len, (char *)in);
+ printf("Received slider value: %s\n", buffer);
+ //lws_write(wsi, (unsigned char *)in, len, LWS_WRITE_TEXT);
+ int value = atoi(buffer);
+ handle_slider_change(synthx, value);
+ break;
+ }
+ case LWS_CALLBACK_SERVER_WRITEABLE: {
+ printf("\nLWS_CALLBACK_SERVER_WRITEABLE\n\n");
+ /* size_t msg_len = strlen(message_buffer); */
+ /* unsigned char buffer[LWS_PRE + BUFFER_SIZE]; */
+ /* memcpy(&buffer[LWS_PRE], message_buffer, msg_len); */
+ /* lws_write(wsi, (unsigned char *)buffer, strlen(buffer), LWS_WRITE_TEXT); */
+ break;
+ }
+ case LWS_CALLBACK_HTTP: {
+ snprintf(tmp, sizeof(tmp), html_header, strlen(html_content));
+ strcpy(buf, tmp);
+ printf("\nHTTP?!\n\n%s\n", tmp);
+ strcat(buf, html_content);
+ lws_write(wsi, (unsigned char *)buf, strlen(buf), LWS_WRITE_HTTP);
+ return -1;
+ break;
+ }
+ case LWS_CALLBACK_CLOSED: {
+ printf("WebSocket connection closed with client: %p\n", wsi);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+// Thread function to run the WebSocket server
+void *websocket_server_thread(void *arg) {
+ struct lws_context_creation_info info;
+ struct lws_context *context;
+ struct lws_protocols protocols[] = {
+ //{ "http-only", callback_http, 0, 0 },
+ { "ws", callback_ws, 0, 128 },
+ { NULL, NULL, 0, 0 } // Terminator
+ };
+
+ memset(&info, 0, sizeof(info));
+ info.port = WS_PORT;
+ //info.user = arg;
+ info.protocols = protocols;
+ info.pt_serv_buf_size = 32 * 1024;
+ info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
+
+ context = lws_create_context(&info);
+ if (!context) {
+ fprintf(stderr, "lws_create_context failed\n");
+ return NULL;
+ }
+
+ printf("WebSocket server running on ws://localhost:%d\n", WS_PORT);
+
+ while (1) {
+ lws_service(context, 1000); // Service WebSocket events
+ }
+
+ lws_context_destroy(context);
+ return NULL;
+}
+
+void
+init_web(synth_t * synth)
+{
+ synthx = synth;
+ // Start the HTTP server
+ server = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, HTTP_PORT, NULL, NULL, &handle_request, (void *)synth, MHD_OPTION_END);
+ if (server == NULL) {
+ fprintf(stderr, "Failed to start server\n");
+ return;
+ }
+
+ // Create a new thread for the WebSocket server
+ if (pthread_create(&server_thread, NULL, websocket_server_thread, NULL) != 0) {
+ fprintf(stderr, "Failed to create server thread\n");
+ return;
+ }
+}
+
+void
+free_web()
+{
+ MHD_stop_daemon(server);
+}
+
+void ws_send_message(const char *message) {
+ if (client_wsi != NULL) {
+ /* strcpy(message_buffer, message); */
+ /* lws_callback_on_writable(client_wsi); */
+ size_t msg_len = strlen(message);
+ unsigned char buffer[LWS_PRE + BUFFER_SIZE];
+ memcpy(&buffer[LWS_PRE], message, msg_len);
+ lws_write(client_wsi, &buffer[LWS_PRE], msg_len, LWS_WRITE_TEXT);
+ printf("[WS]: Sent <<%s>>\n", message);
+
+ //lws_write(client_wsi, (unsigned char *)message, strlen(message), LWS_WRITE_TEXT);
+ }
+}
diff --git a/src/web.h b/src/web.h
new file mode 100644
index 0000000..8c5edd4
--- /dev/null
+++ b/src/web.h
@@ -0,0 +1,12 @@
+#ifndef WEB_H
+#define WEB_H
+
+#include "synth_engine.h"
+
+void init_web(synth_t * synth);
+void free_web();
+void ws_send_message(const char *message);
+
+
+
+#endif /* WEB_H */