diff --git a/audio/chuck/Makefile b/audio/chuck/Makefile new file mode 100644 index 0000000..5d3a0f3 --- /dev/null +++ b/audio/chuck/Makefile @@ -0,0 +1,40 @@ +COMMENT = strongly-timed music programming language + +DIST_TUPLE = github ccrma chuck chuck-1.5.5.7 . +PKGNAME = chuck-1.5.5.7 +CATEGORIES = audio +REVISION = 0 + +HOMEPAGE = https://chuck.stanford.edu/ + +# Dual-licensed: MIT or GPLv2+ +PERMIT_PACKAGE = Yes + +WANTLIB += ${COMPILER_LIBCXX} c m pthread sndfile sndio + +COMPILER = base-clang + +LIB_DEPENDS = audio/libsndfile + +BUILD_DEPENDS = devel/bison + +USE_GMAKE = Yes + +WRKDIST = ${WRKDIR}/chuck-chuck-1.5.5.7 +WRKSRC = ${WRKDIST}/src + +MAKE_FILE = makefile +ALL_TARGET = openbsd-sndio +MAKE_FLAGS += CC="${CC}" CXX="${CXX}" YACC=${LOCALBASE}/bin/bison \ + CFLAGS="${CFLAGS} -I${WRKSRC} -I${WRKSRC}/core -I${WRKSRC}/core/lo -I${LOCALBASE}/include -D__OPENBSD_SNDIO__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__ -D__DISABLE_HID__" \ + LDFLAGS="${LDFLAGS} -L${LOCALBASE}/lib -lsndio -lstdc++ -lm -lsndfile -lpthread" + +NO_TEST = Yes + +pre-build: + ${INSTALL} -m 644 ${FILESDIR}/makefile.sndio ${WRKSRC}/core/makefile.x/makefile.sndio + +do-install: + ${INSTALL_PROGRAM} ${WRKSRC}/chuck ${PREFIX}/bin/chuck + +.include diff --git a/audio/chuck/distinfo b/audio/chuck/distinfo new file mode 100644 index 0000000..53e7ffc --- /dev/null +++ b/audio/chuck/distinfo @@ -0,0 +1,2 @@ +SHA256 (ccrma-chuck-chuck-1.5.5.7.tar.gz) = BWEe9laQNXvCcpXhcwFlBg0cFGTC1nXY1V+4sYwLbWk= +SIZE (ccrma-chuck-chuck-1.5.5.7.tar.gz) = 22405823 diff --git a/audio/chuck/files/makefile.sndio b/audio/chuck/files/makefile.sndio new file mode 100644 index 0000000..7b234be --- /dev/null +++ b/audio/chuck/files/makefile.sndio @@ -0,0 +1,5 @@ +# compiler flags +CFLAGS+= -D__OPENBSD_SNDIO__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__ -D__DISABLE_HID__ -I/usr/local/include + +# linker / library flags +LDFLAGS+= -lsndio -lstdc++ -lm -L/usr/local/lib -lsndfile -lpthread diff --git a/audio/chuck/patches/patch-src_core_chuck_compile_cpp b/audio/chuck/patches/patch-src_core_chuck_compile_cpp new file mode 100644 index 0000000..41954d6 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_chuck_compile_cpp @@ -0,0 +1,13 @@ +Index: src/core/chuck_compile.cpp +--- src/core/chuck_compile.cpp.orig ++++ src/core/chuck_compile.cpp +@@ -1198,6 +1198,9 @@ t_CKBOOL Chuck_Compiler::bind( f_ck_query query_func, + // commit what is in the type checker at this point + env->global()->commit(); + ++ // preserve all operator overloads currently in registry | added 1.5.5.8 (ben) ++ env->op_registry.preserve(); ++ + // pop indent level + EM_poplog(); + diff --git a/audio/chuck/patches/patch-src_core_chuck_cpp b/audio/chuck/patches/patch-src_core_chuck_cpp new file mode 100644 index 0000000..6275d52 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_chuck_cpp @@ -0,0 +1,16 @@ +Index: src/core/chuck.cpp +--- src/core/chuck.cpp.orig ++++ src/core/chuck.cpp +@@ -1531,10 +1531,10 @@ void ChucK::globalCleanup() + // midirw_detach(); + //#endif // __DISABLE_MIDI__ + +- #ifndef __ALTER_HID__ ++ #if !defined(__ALTER_HID__) && !defined(__DISABLE_HID__) + // shutdown HID + HidInManager::cleanup( 100 ); +- #endif // __ALTER_HID__ ++ #endif // __ALTER_HID__ && __DISABLE_HID__ + + #ifndef __DISABLE_SERIAL__ + // shutdown serial diff --git a/audio/chuck/patches/patch-src_core_chuck_def_h b/audio/chuck/patches/patch-src_core_chuck_def_h new file mode 100644 index 0000000..08a7c0a --- /dev/null +++ b/audio/chuck/patches/patch-src_core_chuck_def_h @@ -0,0 +1,28 @@ +Index: src/core/chuck_def.h +--- src/core/chuck_def.h.orig ++++ src/core/chuck_def.h +@@ -49,7 +49,7 @@ + // 1.5.0.0 (ge) | moved to chuck.h for at-a-glance visibility + // 1.5.2.0 (ge) | moved to chuck_def.h for chugins headers streamlining + //----------------------------------------------------------------------------- +-#define CHUCK_VERSION_STRING "1.5.5.7 (chai)" ++#define CHUCK_VERSION_STRING "1.5.5.8-dev (chai)" + //----------------------------------------------------------------------------- + + +@@ -261,13 +261,13 @@ typedef struct { SAMPLE re ; SAMPLE im ; } t_CKCOMPLEX + // platform: linux + // related macros: __LINUX_ALSA__ __LINUX_PULSE__ __LINUX_OSS__ __LINUX_JACK__ __UNIX_JACK__ + //------------------------------------------- +-#if defined(__linux__) || defined(__FreeBSD__) ++#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + //------------------------------------------- + #ifndef __PLATFORM_LINUX__ + #define __PLATFORM_LINUX__ + #endif + //------------------------------------------- +-#endif // defined(__linux__) || defined(__FreeBSD__) ++#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + //------------------------------------------- + + diff --git a/audio/chuck/patches/patch-src_core_chuck_errmsg_h b/audio/chuck/patches/patch-src_core_chuck_errmsg_h new file mode 100644 index 0000000..a4e31f4 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_chuck_errmsg_h @@ -0,0 +1,11 @@ +Index: src/core/chuck_errmsg.h +--- src/core/chuck_errmsg.h.orig ++++ src/core/chuck_errmsg.h +@@ -37,6 +37,7 @@ + #define __CHUCK_ERRORMSG_H__ + + #include "chuck_def.h" ++#include + #include + + diff --git a/audio/chuck/patches/patch-src_core_chuck_lang_cpp b/audio/chuck/patches/patch-src_core_chuck_lang_cpp new file mode 100644 index 0000000..e411fc5 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_chuck_lang_cpp @@ -0,0 +1,15 @@ +Index: src/core/chuck_lang.cpp +--- src/core/chuck_lang.cpp.orig ++++ src/core/chuck_lang.cpp +@@ -3823,7 +3823,10 @@ static void typeGetTypes( + for( t_CKINT i = 0; i < types.size(); i++ ) + { + // check special +- t_CKBOOL special = (types[i]->base_name.length()>0 && types[i]->base_name[0] == '@'); ++ // 1.5.5.8 (ge) account for "auto" ++ t_CKBOOL special = (types[i]->base_name.length()>0 && ++ (types[i]->base_name[0] == '@' || ++ types[i]->xid == te_auto) ); + // if not requesting special types + if( !isSpecial && (special == TRUE) ) continue; + // check origin diff --git a/audio/chuck/patches/patch-src_core_lo_config_h b/audio/chuck/patches/patch-src_core_lo_config_h new file mode 100644 index 0000000..1379d5c --- /dev/null +++ b/audio/chuck/patches/patch-src_core_lo_config_h @@ -0,0 +1,16 @@ +Index: src/core/lo/config.h +--- src/core/lo/config.h.orig ++++ src/core/lo/config.h +@@ -1,5 +1,5 @@ + +-#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) ++#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + // 1.5.0.7 (ge) since this is in the lo/ sub-directory, + // and does not include chuck_def.h, directly check platform macros + // #if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) +@@ -205,4 +205,4 @@ + /* Define to `unsigned int' if does not define. */ + /* #undef size_t */ + +-#endif // defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) ++#endif // defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) diff --git a/audio/chuck/patches/patch-src_core_makefile b/audio/chuck/patches/patch-src_core_makefile new file mode 100644 index 0000000..6ccedca --- /dev/null +++ b/audio/chuck/patches/patch-src_core_makefile @@ -0,0 +1,25 @@ +Index: src/core/makefile +--- src/core/makefile.orig ++++ src/core/makefile +@@ -4,8 +4,8 @@ current: + @echo " make linux-alsa, make linux-jack, make linux-pulse, linux-all," + @echo " make mac, make mac-ub, make cygwin, make win32, or make vanilla" + +-.PHONY: mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa vanilla cygwin osx-rl test +-mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa vanilla cygwin osx-rl: chuck-core ++.PHONY: mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa openbsd-sndio vanilla cygwin osx-rl test ++mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa openbsd-sndio vanilla cygwin osx-rl: chuck-core + + win32: + make -f makefile.win32 +@@ -75,6 +75,10 @@ endif + + ifneq (,$(strip $(filter linux-alsa,$(MAKECMDGOALS)))) + include makefile.x/makefile.alsa ++endif ++ ++ifneq (,$(strip $(filter openbsd-sndio,$(MAKECMDGOALS)))) ++include makefile.x/makefile.sndio + endif + + ifneq (,$(strip $(filter vanilla,$(MAKECMDGOALS)))) diff --git a/audio/chuck/patches/patch-src_core_makefile_x_makefile_jack b/audio/chuck/patches/patch-src_core_makefile_x_makefile_jack new file mode 100644 index 0000000..63546f1 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_makefile_x_makefile_jack @@ -0,0 +1,12 @@ +Index: src/core/makefile.x/makefile.jack +--- src/core/makefile.x/makefile.jack.orig ++++ src/core/makefile.x/makefile.jack +@@ -1,6 +1,6 @@ + # compiler flags +-CFLAGS+= -D__UNIX_JACK__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__ ++CFLAGS+= -D__UNIX_JACK__ -fno-strict-aliasing -D__CK_SNDFILE_NATIVE__ -D__DISABLE_HID__ + CFLAGS+= $(shell pkg-config --cflags jack) + + # linker / library flags +-LDFLAGS+= -lasound $(shell pkg-config --libs jack) -lstdc++ -ldl -lm -lsndfile -lpthread ++LDFLAGS+= $(shell pkg-config --libs jack) -lstdc++ -lm -lsndfile -lpthread diff --git a/audio/chuck/patches/patch-src_core_ugen_stk_h b/audio/chuck/patches/patch-src_core_ugen_stk_h new file mode 100644 index 0000000..cc93721 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_ugen_stk_h @@ -0,0 +1,21 @@ +Index: src/core/ugen_stk.h +--- src/core/ugen_stk.h.orig ++++ src/core/ugen_stk.h +@@ -81,6 +81,17 @@ t_CKBOOL stk_detach( Chuck_Carrier * carrier ); + #if !defined(__STK_H) + #define __STK_H + ++// undef OpenBSD/BSD endian macros that clash with Stk member function names ++#ifdef swap16 ++#undef swap16 ++#endif ++#ifdef swap32 ++#undef swap32 ++#endif ++#ifdef swap64 ++#undef swap64 ++#endif ++ + #include + #include + diff --git a/audio/chuck/patches/patch-src_core_ulib_math_cpp b/audio/chuck/patches/patch-src_core_ulib_math_cpp new file mode 100644 index 0000000..2021654 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_ulib_math_cpp @@ -0,0 +1,57 @@ +Index: src/core/ulib_math.cpp +--- src/core/ulib_math.cpp.orig ++++ src/core/ulib_math.cpp +@@ -581,6 +581,13 @@ DLL_QUERY libmath_query( Chuck_DL_Query * QUERY ) + QUERY->add_svar( QUERY, "complex", "j", TRUE, &g_i ); + QUERY->doc_var( QUERY, "The complex number sqrt(-1)." ); + ++ // spherical harmonics | (added) 1.5.5.8 by everett 2026 ++ QUERY->add_sfun( QUERY, sh_impl, "float[]", "sh" ); ++ QUERY->add_arg( QUERY, "int", "order" ); ++ QUERY->add_arg( QUERY, "float", "azimuth" ); ++ QUERY->add_arg( QUERY, "float", "zenith" ); ++ QUERY->doc_func(QUERY, "Returns an array of size (N+1)^2, containing ACN ordered spherical harmonics."); ++ + // add examples + // QUERY->add_ex( QUERY, "map.ck" ); + // QUERY->add_ex( QUERY, "math-help.ck" ); +@@ -1435,5 +1442,38 @@ CK_DLL_SFUN( map2_impl ) + + // std::cerr << v << " " << x1 << " " << y1 << " " << x2 << " " << y2 << std::endl; + // remap +- RETURN->v_float = x2 + (v-x1)/(y1-x1)*(y2-x2); ++ RETURN->v_float = x2 + (v - x1) / (y1 - x1) * (y2 - x2); ++} ++ ++// spherical harmonics implementation | (added) 1.5.5.8 by everett 2026 ++CK_DLL_SFUN( sh_impl ) ++{ ++ t_CKINT order = GET_NEXT_INT(ARGS); ++ t_CKFLOAT direction = GET_NEXT_FLOAT(ARGS); ++ t_CKFLOAT elevation = GET_NEXT_FLOAT(ARGS); ++ t_CKFLOAT * coord = new t_CKFLOAT[(order + 1) * (order + 1) + 1]; ++ if( order <= 5 ) ++ { ++ t_CKUINT size = (order + 1) * (order + 1); ++ // moved memory ownership to ck_SH emc 2/26 (memory was previously allocated by ck_SH() and deleted by sh_impl) ++ ck_SH( coord,order, direction, elevation, 0 ); ++ // Create a float[] array ++ Chuck_DL_Api::Object returnarray = API->object->create( SHRED, API->type->lookup(VM, "float[]"), false ); ++ Chuck_ArrayFloat * coordinatearray = (Chuck_ArrayFloat *)returnarray; ++ for( t_CKINT i = 0; i < size; i++ ) ++ { ++ API->object->array_float_push_back(coordinatearray, coord[i]); ++ } ++ // set return value ++ RETURN->v_object = coordinatearray; ++ } ++ else ++ { ++ // throw exception ++ API->vm->throw_exception("Math.sh() : InvalidSHOrder", "only up to 5th order currently supported", nullptr); ++ RETURN->v_int = 0; ++ } ++ ++ // clean up ++ CK_SAFE_DELETE_ARRAY( coord ); + } diff --git a/audio/chuck/patches/patch-src_core_ulib_math_h b/audio/chuck/patches/patch-src_core_ulib_math_h new file mode 100644 index 0000000..2e5f178 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_ulib_math_h @@ -0,0 +1,13 @@ +Index: src/core/ulib_math.h +--- src/core/ulib_math.h.orig ++++ src/core/ulib_math.h +@@ -119,7 +119,7 @@ CK_DLL_SFUN( euclidean4d_impl ); + CK_DLL_SFUN( map_impl ); + CK_DLL_SFUN( map2_impl ); + +- +- ++// spherical harmonics | (added) 1.5.5.8 by everett 2026 ++CK_DLL_SFUN( sh_impl ); + + #endif diff --git a/audio/chuck/patches/patch-src_core_util_hid_cpp b/audio/chuck/patches/patch-src_core_util_hid_cpp new file mode 100644 index 0000000..ef1d7ff --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_hid_cpp @@ -0,0 +1,65 @@ +Index: src/core/util_hid.cpp +--- src/core/util_hid.cpp.orig ++++ src/core/util_hid.cpp +@@ -6368,7 +6368,7 @@ int Keyboard_close( int js ) + + + +-#elif defined(__PLATFORM_LINUX__) ++#elif defined(__PLATFORM_LINUX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) + /***************************************************************************** + Linux general HID support + *****************************************************************************/ +@@ -7805,6 +7805,34 @@ const char * Keyboard_name( int k ) + #endif + + ++// OpenBSD/NetBSD: HID not supported; provide no-op stubs ++#if (defined(__OpenBSD__) || defined(__NetBSD__)) && defined(__PLATFORM_LINUX__) ++void Hid_init() {} ++void Hid_quit() {} ++void Joystick_init() {} ++void Joystick_quit() {} ++int Joystick_count() { return 0; } ++int Joystick_open(int) { return -1; } ++int Joystick_close(int) { return -1; } ++const char * Joystick_name(int) { return NULL; } ++void Keyboard_init() {} ++void Keyboard_quit() {} ++int Keyboard_count() { return 0; } ++int Keyboard_open(int) { return -1; } ++int Keyboard_close(int) { return -1; } ++const char * Keyboard_name(int) { return NULL; } ++void Mouse_init() {} ++void Mouse_quit() {} ++int Mouse_count() { return 0; } ++int Mouse_open(int) { return -1; } ++int Mouse_close(int) { return -1; } ++const char * Mouse_name(int) { return NULL; } ++void Hid_poll() {} ++t_CKINT TiltSensor_setPollRate(t_CKINT) { return 0; } ++t_CKINT TiltSensor_getPollRate() { return 0; } ++#endif // OpenBSD/NetBSD stubs ++ ++ + #ifdef __PLATFORM_WINDOWS__ + + // multiple monitors info: +@@ -7904,7 +7932,7 @@ t_CKVEC2 ck_get_mouse_xy_normalize() + + // t_CKFLOAT screenWidth = GetSystemMetrics( SM_CXVIRTUALSCREEN ); + // t_CKFLOAT screenHeight = GetSystemMetrics( SM_CYVIRTUALSCREEN ); +-#elif defined(__PLATFORM_LINUX__) ++#elif defined(__PLATFORM_LINUX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) + + #if defined(__USE_X11__) + // stuff to query +@@ -7973,7 +8001,7 @@ t_CKVEC2 ck_get_mouse_xy_absolute() + retval.x = pt.x; + retval.y = pt.y; + } +-#elif defined(__PLATFORM_LINUX__) ++#elif defined(__PLATFORM_LINUX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) + + #if defined(__USE_X11__) + // stuff to query diff --git a/audio/chuck/patches/patch-src_core_util_math_cpp b/audio/chuck/patches/patch-src_core_util_math_cpp new file mode 100644 index 0000000..7c39fb4 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_math_cpp @@ -0,0 +1,148 @@ +Index: src/core/util_math.cpp +--- src/core/util_math.cpp.orig ++++ src/core/util_math.cpp +@@ -368,5 +368,143 @@ t_CKFLOAT ck_vec3_magnitude( const t_CKVEC3 & v ) + //----------------------------------------------------------------------------- + t_CKFLOAT ck_vec4_magnitude( const t_CKVEC4 & v ) + { +- return ::sqrt( v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w ); ++ return ::sqrt( v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w ); ++} ++ ++ ++ ++ ++//----------------------------------------------------------------------------- ++// name: ck_factorial32() ++// desc: factorial calculator function (for 32 bit) ++// author: everett m. carpenter | 1.5.5.8 ++// modified for 32-bit (ge, nick) ++//----------------------------------------------------------------------------- ++t_CKINT ck_factorial32( t_CKINT n ) ++{ ++ // 12! is the largest factorial that can fit in a 32-bit integer ++ if( n < 0 || n > 12 ) return -1; ++ ++ t_CKINT result = 1; ++ for( t_CKINT i = 1; i <= n; i++ ) ++ { result = i * result; } ++ ++ return result; ++} ++ ++ ++ ++ ++//----------------------------------------------------------------------------- ++// name: ck_associated_legendre() ++// desc: closed form associated legendre polynomials of some order l ++// author: everett m. carpenter | 1.5.5.8 ++//----------------------------------------------------------------------------- ++t_CKFLOAT ck_associated_legendre( const t_CKINT m, const t_CKINT l, const t_CKFLOAT x ) ++{ ++ // check bounds ++ if (l < 0 || l > 5) return 0.0; ++ if (abs(m) > l) return 0.0; ++ ++ float x2 = x * x; // x^2 ++ float x3 = x2 * x; // x^3 ++ float x4 = x2 * x2; // x^4 ++ float cf = 1.0 - x2; // pops up in every associated legendre ++ float sqrtcf = sqrt(cf);; // also pops up everywhere ++ t_CKINT absm = abs(m); // assume m is positive, then apply -m case at end ++ float result = 0.f; ++ float flip = 1.f; ++ ++ if (m < 0) flip = (float)(pow(-1.0, absm) * (ck_factorial32(l - absm) / ck_factorial32(l + absm))); ++ ++ switch (l) // order and absm ++ { ++ case(0): ++ { result = 1.0; break; } ++ case(1): ++ { ++ if (absm == 0) { result = x; } ++ else if (absm == 1) { result = -sqrtcf; } ++ break; ++ } ++ case(2): ++ { ++ if (absm == 0) { result = 0.5 * (3.0 * x2 - 1); } ++ else if (absm == 1) { result = -3.0 * x * sqrtcf; } ++ else if (absm == 2) { result = 3.0 * cf; } ++ break; ++ } ++ case(3): ++ { ++ if (absm == 0) { result = 0.5 * (5.0 * x3 - 3.0 * x); } ++ else if (absm == 1) { result = 1.5 * (1.0 - 5.0 * x2) * sqrtcf; } ++ else if (absm == 2) { result = 15.0 * x * cf; } ++ else if (absm == 3) { result = -15.0 * sqrtcf * cf; } ++ break; ++ } ++ case(4): ++ { ++ if (absm == 0) { result = 0.125 * (35.0 * x4 - 30.0 * x2 + 3.0); } ++ else if (absm == 1) { result = -2.5 * (7.0 * x3 - 3.0 * x) * sqrtcf; } ++ else if (absm == 2) { result = 7.5 * (7.0 * x2 - 1) * cf; } ++ else if (absm == 3) { result = -105.0 * x * sqrtcf * cf; } ++ else if (absm == 4) { result = 105.0 * cf * cf; } ++ break; ++ } ++ case(5): ++ { ++ if (absm == 0) { result = 0.125 * (63.0 * x3 * x2 - 70 * x3 + 15 * x); } ++ else if (absm == 1) { result = -1.875 * sqrtcf * (21.0 * x4 - 14 * x2 + 1); } ++ else if (absm == 2) { result = 52.5 * x * cf * (3.0 * x2 - 1.0); } ++ else if (absm == 3) { result = -52.5 * cf * sqrtcf * (9.0 * x2 - 1.0); } ++ else if (absm == 4) { result = 945.0 * x * cf * cf; } ++ else if (absm == 5) { result = -945.0 * sqrtcf * cf * cf; } ++ break; ++ } ++ } ++ ++ return pow(-1.0, m) * result * flip; ++} ++ ++ ++ ++ ++//----------------------------------------------------------------------------- ++// name: ck_SN3D ++// desc: normalization calculator for spherical harmonics ++// author: everett m. carpenter | 1.5.5.8 ++//----------------------------------------------------------------------------- ++t_CKFLOAT ck_SN3D( const t_CKUINT order, const t_CKINT degree ) // calculate SN3D value ++{ ++ int d = (degree == 0) ? 1 : 0; // kronecker delta ++ float ratio = static_cast(ck_factorial32(order - abs(degree))) / static_cast(ck_factorial32(order + abs(degree))); // ratio of factorials ++ return sqrtf((2.f - d) * ratio); ++} ++ ++ ++ ++ ++//----------------------------------------------------------------------------- ++// name: ck_SH() ++// desc: calculation of spherical harmonics according to some order and normalization ++// author: everett m. carpenter | 1.5.5.8 ++//----------------------------------------------------------------------------- ++void ck_SH( t_CKFLOAT * output, const t_CKUINT order_, const t_CKFLOAT azimuth_, const t_CKFLOAT zenith_, const t_CKBOOL n3d ) ++{ ++ float azimuth_shift = (azimuth_) * 0.01745329252; // degree 2 rad ++ float zenith_shift = (90.f - zenith_) * 0.01745329252; ++ float coszeni = cosf(zenith_shift); ++ t_CKINT size = (order_ + 1) * (order_ + 1); ++ for (int order = 0; order <= (int)order_; order++) ++ { ++ if (order == 0) ++ output[0] = ck_SN3D(order, 0); ++ for (int degree = -order; degree <= order; degree++) ++ { ++ float n = n3d ? sqrtf(2 * order + 1) * ck_SN3D(order, degree) : ck_SN3D(order, degree); // normalization term if n3d bool = TRUE, return N3D else SN3D ++ float p = (ck_associated_legendre((int)abs(degree), (int)order, coszeni)); ++ float r = (degree < 0) ? sinf(abs(degree) * (azimuth_shift)) : cosf(degree * (azimuth_shift)); // degree positive? Re(exp(i*azimuth*degree)) degree negative? Im(exp(i*azimuth*degree)) ++ output[(order * order) + order + degree] = n * p * r; ++ } ++ } + } diff --git a/audio/chuck/patches/patch-src_core_util_math_h b/audio/chuck/patches/patch-src_core_util_math_h new file mode 100644 index 0000000..307eb81 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_math_h @@ -0,0 +1,18 @@ +Index: src/core/util_math.h +--- src/core/util_math.h.orig ++++ src/core/util_math.h +@@ -112,8 +112,12 @@ t_CKFLOAT ck_vec2_phase( const t_CKVEC2 & v ); + t_CKFLOAT ck_vec3_magnitude( const t_CKVEC3 & v ); + // magnitude of vec4 + t_CKFLOAT ck_vec4_magnitude( const t_CKVEC4 & v ); +- +- ++// integer factorial (for up to 12! which is the largest factorial that can fit inside a 32-bit integer) ++t_CKINT ck_factorial32( t_CKINT n ); ++// associated legendre for spherical harmonics | (added) 1.5.5.8 by everett 2026 ++t_CKFLOAT ck_associated_legendre( const t_CKINT m, const t_CKINT l, const t_CKFLOAT x ); ++// spherical harmonics | (added) 1.5.5.8 by everett 2026 ++void ck_SH( t_CKFLOAT* output, const t_CKUINT order_, const t_CKFLOAT azimuth_, const t_CKFLOAT zenith_, const t_CKBOOL n3d ); + + #if defined (__cplusplus) || defined(_cplusplus) + } diff --git a/audio/chuck/patches/patch-src_core_util_network_c b/audio/chuck/patches/patch-src_core_util_network_c new file mode 100644 index 0000000..c9607bc --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_network_c @@ -0,0 +1,21 @@ +Index: src/core/util_network.c +--- src/core/util_network.c.orig ++++ src/core/util_network.c +@@ -173,7 +173,7 @@ t_CKBOOL ck_connect( ck_socket sock, const char * host + t_CKINT ret; + struct hostent * host; + +-#ifdef __PLATFORM_WINDOWS__ ++#if defined( __PLATFORM_WINDOWS__ ) || defined( __ANDROID__ ) + memset( &sock->sock_in, 0, sizeof(struct sockaddr_in) ); + #else + bzero( &sock->sock_in, sizeof(struct sockaddr_in) ); +@@ -218,7 +218,7 @@ t_CKBOOL ck_bind( ck_socket sock, int port ) + { + int ret; + +-#ifdef __PLATFORM_WINDOWS__ ++#if defined( __PLATFORM_WINDOWS__ ) || defined( __ANDROID__ ) + memset( &sock->sock_in, 0, sizeof(struct sockaddr_in) ); + #else + bzero( &sock->sock_in, sizeof(struct sockaddr_in) ); diff --git a/audio/chuck/patches/patch-src_core_util_platforms_cpp b/audio/chuck/patches/patch-src_core_util_platforms_cpp new file mode 100644 index 0000000..122f5b1 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_platforms_cpp @@ -0,0 +1,12 @@ +Index: src/core/util_platforms.cpp +--- src/core/util_platforms.cpp.orig ++++ src/core/util_platforms.cpp +@@ -461,7 +461,7 @@ int ck_gettimeofday( long * tv_sec, long * tv_usec, vo + // timeval + timeval tv; + // call on through +- int retval = gettimeofday( &tv, tzp ); ++ int retval = gettimeofday( &tv, (struct timezone *)tzp ); + // check it + if( retval ) return retval; + // set return values diff --git a/audio/chuck/patches/patch-src_core_util_platforms_h b/audio/chuck/patches/patch-src_core_util_platforms_h new file mode 100644 index 0000000..7924338 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_platforms_h @@ -0,0 +1,12 @@ +Index: src/core/util_platforms.h +--- src/core/util_platforms.h.orig ++++ src/core/util_platforms.h +@@ -102,7 +102,7 @@ int ck_gettimeofday( long * tv_sec, long * tv_usec, vo + #define CHUCK_PLATFORM_STRING "android" + #elif defined(__PLATFORM_CYGWIN__) + #define CHUCK_PLATFORM_STRING "cygwin" // not sure if needed, as cygwin implies windows +-#elif ++#else + #define CHUCK_PLATFORM_STRING "unknown" + #endif + diff --git a/audio/chuck/patches/patch-src_core_util_string_cpp b/audio/chuck/patches/patch-src_core_util_string_cpp new file mode 100644 index 0000000..cf10fb3 --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_string_cpp @@ -0,0 +1,42 @@ +Index: src/core/util_string.cpp +--- src/core/util_string.cpp.orig ++++ src/core/util_string.cpp +@@ -570,18 +570,26 @@ t_CKBOOL extract_args( const string & token, + //----------------------------------------------------------------------------- + #if !defined(__PLATFORM_WINDOWS__) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(__CHIP_MODE__) + ++#include ++#if !defined(__OpenBSD__) && !defined(__NetBSD__) + #include ++#endif + //----------------------------------------------------------------------------- + // name: expandTildePath() + // desc: expand ~ path, does not care whether path is valid or not + //----------------------------------------------------------------------------- + std::string expandTildePath( const std::string & path ) + { ++ std::string exp; ++#if defined(__OpenBSD__) || defined(__NetBSD__) ++ // wordexp not available; use glob with GLOB_TILDE for tilde expansion ++ glob_t g; ++ if( glob(path.c_str(), GLOB_TILDE | GLOB_NOCHECK, NULL, &g) == 0 && g.gl_pathc > 0 ) ++ exp = g.gl_pathv[0]; ++ globfree( &g ); ++#else + // wordexp result + wordexp_t we; +- // the result +- std::string exp; +- + // "perform shell-style word expansions" + if( wordexp(path.c_str(), &we, 0 ) == 0 ) // success + { +@@ -594,7 +602,7 @@ std::string expandTildePath( const std::string & path + // free up + wordfree( &we ); + } +- ++#endif + // if still empty for any reason, default to original + if( exp == "" ) exp = path; + diff --git a/audio/chuck/patches/patch-src_core_util_thread_cpp b/audio/chuck/patches/patch-src_core_util_thread_cpp new file mode 100644 index 0000000..9cbd6ec --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_thread_cpp @@ -0,0 +1,113 @@ +Index: src/core/util_thread.cpp +--- src/core/util_thread.cpp.orig ++++ src/core/util_thread.cpp +@@ -66,7 +66,8 @@ XThread::XThread( ) + //----------------------------------------------------------------------------- + XThread::~XThread( ) + { +-#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + // can't self-terminate (much like the Terminator) + bool is_self_thread = (thread == pthread_self()); + #elif defined(__PLATFORM_WINDOWS__) +@@ -78,7 +79,8 @@ XThread::~XThread( ) + if( thread != 0 && !is_self_thread ) + { + // TODO: find an alternative for Android? +-#if defined(__PLATFORM_APPLE__) || ( defined(__PLATFORM_LINUX__) && !defined(__ANDROID__) ) || defined(__WINDOWS_PTHREAD__) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || ( defined(__PLATFORM_LINUX__) && !defined(__ANDROID__) ) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + // log + EM_log( CK_LOG_FINER, "cancelling thread [0x%x] from [0x%x]...", getID(thread), getID(pthread_self()) ); + pthread_cancel(thread); +@@ -104,7 +106,8 @@ bool XThread::start( THREAD_FUNCTION routine, void * p + { + bool result = false; + +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + if( pthread_create( &thread, NULL, *routine, ptr ) == 0 ) + { + EM_log( CK_LOG_FINER, "starting thread [0x%x] from [0x%x]...", thread, getID(pthread_self()) ); +@@ -134,7 +137,8 @@ bool XThread::wait( long milliseconds, bool cancel ) + bool result = false; + + // TODO: find an alternative for Android? +-#if( defined(__PLATFORM_APPLE__) || ( defined(__PLATFORM_LINUX__) && !defined(__ANDROID__) ) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || ( defined(__PLATFORM_LINUX__) && !defined(__ANDROID__) ) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + // cancel the thread? + if( cancel ) pthread_cancel( thread ); + // wait for the thread to terminate +@@ -164,7 +168,8 @@ bool XThread::wait( long milliseconds, bool cancel ) + void XThread :: test( ) + { + // TODO: find an alternative for Android? +-#if ( defined(__PLATFORM_APPLE__) || ( defined(__PLATFORM_LINUX__) && !defined(__ANDROID__) ) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || ( defined(__PLATFORM_LINUX__) && !defined(__ANDROID__) ) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + pthread_testcancel(); + #endif + } +@@ -178,7 +183,8 @@ void XThread :: test( ) + //----------------------------------------------------------------------------- + t_CKUINT XThread::getID( THREAD_HANDLE t ) + { +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + return (t_CKUINT)t; + #elif defined(__PLATFORM_WINDOWS__) + return (t_CKUINT)GetThreadId( (HANDLE)t ); +@@ -194,7 +200,8 @@ t_CKUINT XThread::getID( THREAD_HANDLE t ) + //----------------------------------------------------------------------------- + XMutex::XMutex( ) + { +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + pthread_mutex_init(&mutex, NULL); + #elif defined(__PLATFORM_WINDOWS__) + InitializeCriticalSection(&mutex); +@@ -210,7 +217,8 @@ XMutex::XMutex( ) + //----------------------------------------------------------------------------- + XMutex::~XMutex( ) + { +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + pthread_mutex_destroy( &mutex ); + #elif defined(__PLATFORM_WINDOWS__) + DeleteCriticalSection(&mutex); +@@ -226,7 +234,8 @@ XMutex::~XMutex( ) + //----------------------------------------------------------------------------- + void XMutex::acquire( ) + { +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + pthread_mutex_lock(&mutex); + #elif defined(__PLATFORM_WINDOWS__) + EnterCriticalSection(&mutex); +@@ -242,7 +251,8 @@ void XMutex::acquire( ) + //----------------------------------------------------------------------------- + void XMutex::release( ) + { +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++ // 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + pthread_mutex_unlock(&mutex); + #elif defined(__PLATFORM_WINDOWS__) + LeaveCriticalSection(&mutex); +@@ -440,7 +450,8 @@ void XWriteThread::flush_data_buffer() + // name: write_cb() + // desc: thread function + //----------------------------------------------------------------------------- +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++// 1.5.5.8 (ben, ge) added emscripten since it uses POSIX ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + void * XWriteThread::write_cb(void * _thiss) + #elif defined(__PLATFORM_WINDOWS__) + unsigned XWriteThread::write_cb(void * _thiss) diff --git a/audio/chuck/patches/patch-src_core_util_thread_h b/audio/chuck/patches/patch-src_core_util_thread_h new file mode 100644 index 0000000..bb1cf4a --- /dev/null +++ b/audio/chuck/patches/patch-src_core_util_thread_h @@ -0,0 +1,22 @@ +Index: src/core/util_thread.h +--- src/core/util_thread.h.orig ++++ src/core/util_thread.h +@@ -44,7 +44,8 @@ class FastCircularBuffer; + template class CircularBuffer; + + +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) ++ // 1.5.5.8 (ben, ge) added emscripten above since it uses POSIX + #include + #define THREAD_TYPE + typedef pthread_t THREAD_HANDLE; +@@ -188,7 +189,7 @@ class XWriteThread (private) + void flush_data_buffer(); + + // callback +-#if ( defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) ) ++#if defined(__PLATFORM_APPLE__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) || defined(__PLATFORM_EMSCRIPTEN__) + static void * write_cb( void * _thiss ); + #elif defined(__PLATFORM_WINDOWS__) + static unsigned THREAD_TYPE write_cb( void * _thiss ); diff --git a/audio/chuck/patches/patch-src_host_RtAudio_RtAudio_cpp b/audio/chuck/patches/patch-src_host_RtAudio_RtAudio_cpp new file mode 100644 index 0000000..1d81d11 --- /dev/null +++ b/audio/chuck/patches/patch-src_host_RtAudio_RtAudio_cpp @@ -0,0 +1,631 @@ +Index: src/host/RtAudio/RtAudio.cpp +--- src/host/RtAudio/RtAudio.cpp.orig ++++ src/host/RtAudio/RtAudio.cpp +@@ -109,6 +109,7 @@ const char* rtaudio_api_names[][2] = { + { "alsa" , "ALSA" }, + { "pulse" , "Pulse" }, + { "oss" , "OpenSoundSystem" }, ++ { "sndio" , "sndio" }, + { "jack" , "Jack" }, + { "core" , "CoreAudio" }, + { "wasapi" , "WASAPI" }, +@@ -135,6 +136,9 @@ extern "C" const RtAudio::Api rtaudio_compiled_apis[] + #if defined(__LINUX_OSS__) + RtAudio::LINUX_OSS, + #endif ++#if defined(__OPENBSD_SNDIO__) ++ RtAudio::OPENBSD_SNDIO, ++#endif + #if defined(__WINDOWS_ASIO__) + RtAudio::WINDOWS_ASIO, + #endif +@@ -216,6 +220,10 @@ void RtAudio :: openRtApi( RtAudio::Api api ) + if ( api == LINUX_OSS ) + rtapi_ = new RtApiOss(); + #endif ++#if defined(__OPENBSD_SNDIO__) ++ if ( api == OPENBSD_SNDIO ) ++ rtapi_ = new RtApiSndio(); ++#endif + #if defined(__WINDOWS_ASIO__) + if ( api == WINDOWS_ASIO ) + rtapi_ = new RtApiAsio(); +@@ -10387,6 +10395,598 @@ static void *ossCallbackHandler( void *ptr ) + //******************** End of __LINUX_OSS__ *********************// + #endif + ++#if defined(__OPENBSD_SNDIO__) ++ ++#include ++#include ++#include ++#include ++ ++static void *sndioCallbackHandler( void *ptr ); ++ ++struct SndioHandle { ++ struct sio_hdl *handle; ++ bool xrun[2]; // [0]=output underflow, [1]=input overflow ++ ++ SndioHandle() : handle(nullptr) { xrun[0] = false; xrun[1] = false; } ++}; ++ ++static void sndioXrunCb( void *arg ) ++{ ++ SndioHandle *h = (SndioHandle *) arg; ++ h->xrun[0] = true; ++ h->xrun[1] = true; ++} ++ ++RtApiSndio :: RtApiSndio() {} ++ ++RtApiSndio :: ~RtApiSndio() ++{ ++ if ( stream_.state != STREAM_CLOSED ) closeStream(); ++} ++ ++unsigned int RtApiSndio :: getDeviceCount( void ) ++{ ++ return 1; ++} ++ ++RtAudio::DeviceInfo RtApiSndio :: getDeviceInfo( unsigned int device ) ++{ ++ RtAudio::DeviceInfo info; ++ info.probed = false; ++ ++ if ( device != 0 ) { ++ errorText_ = "RtApiSndio::getDeviceInfo: invalid device ID!"; ++ error( RTAUDIO_INVALID_DEVICE ); ++ return info; ++ } ++ ++ // Advertise default capabilities; actual negotiation happens in probeDeviceOpen. ++ // We do not require sndiod to be running at probe time. ++ info.name = "sndio default"; ++ info.outputChannels = 2; ++ info.inputChannels = 2; ++ info.duplexChannels = 2; ++ info.isDefaultOutput = true; ++ info.isDefaultInput = true; ++ ++ // sndio accepts most standard sample rates ++ static const unsigned int rates[] = { ++ 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 0 ++ }; ++ for ( int i = 0; rates[i]; i++ ) { ++ info.sampleRates.push_back( rates[i] ); ++ if ( rates[i] == 48000 ) ++ info.preferredSampleRate = 48000; ++ } ++ ++ info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32; ++ info.probed = true; ++ return info; ++} ++ ++bool RtApiSndio :: probeDeviceOpen( unsigned int device, StreamMode mode, ++ unsigned int channels, ++ unsigned int firstChannel, ++ unsigned int sampleRate, ++ RtAudioFormat format, ++ unsigned int *bufferSize, ++ RtAudio::StreamOptions *options ) ++{ ++ if ( device != 0 ) { ++ errorText_ = "RtApiSndio::probeDeviceOpen: only device 0 is supported."; ++ return FAILURE; ++ } ++ if ( firstChannel != 0 ) { ++ errorText_ = "RtApiSndio::probeDeviceOpen: channel offset not supported."; ++ return FAILURE; ++ } ++ ++ SndioHandle *handle = (SndioHandle *) stream_.apiHandle; ++ ++ // When adding INPUT to an already-open OUTPUT stream (going duplex), reuse the ++ // existing play-only sndio handle instead of closing and reopening as ++ // SIO_PLAY|SIO_REC. sndiod's default sub-device ("-m play -s default") is ++ // play-only: a duplex open succeeds but the record clock never ticks, so ++ // sio_write stalls after the initial pre-fill. Keeping the play-only handle ++ // lets the poll-with-timeout path in callbackEvent() substitute silence for ++ // input without blocking. True duplex recording requires a sndiod sub-device ++ // configured with "-m play,rec" or "-m rec". ++ if ( mode == INPUT && stream_.mode == OUTPUT && handle && handle->handle ) { ++ // Set up INPUT bookkeeping using the same format/params as OUTPUT. ++ stream_.deviceFormat[INPUT] = stream_.deviceFormat[OUTPUT]; ++ stream_.nUserChannels[INPUT] = channels; ++ stream_.nDeviceChannels[INPUT] = channels; ++ stream_.deviceInterleaved[INPUT] = true; ++ ++ stream_.doConvertBuffer[INPUT] = false; ++ stream_.doByteSwap[INPUT] = false; ++ if ( stream_.userFormat != stream_.deviceFormat[INPUT] ) ++ stream_.doConvertBuffer[INPUT] = true; ++ if ( stream_.nUserChannels[INPUT] < stream_.nDeviceChannels[INPUT] ) ++ stream_.doConvertBuffer[INPUT] = true; ++ if ( stream_.userInterleaved != stream_.deviceInterleaved[INPUT] && ++ stream_.nUserChannels[INPUT] > 1 ) ++ stream_.doConvertBuffer[INPUT] = true; ++ ++ unsigned long bufBytes = stream_.nUserChannels[INPUT] * stream_.bufferSize * ++ formatBytes( stream_.userFormat ); ++ stream_.userBuffer[INPUT] = (char *) calloc( bufBytes, 1 ); ++ if ( !stream_.userBuffer[INPUT] ) { ++ errorText_ = "RtApiSndio::probeDeviceOpen: error allocating input buffer."; ++ return FAILURE; ++ } ++ ++ if ( stream_.doConvertBuffer[INPUT] ) { ++ unsigned long devBytes = stream_.nDeviceChannels[INPUT] * ++ formatBytes( stream_.deviceFormat[INPUT] ) * ++ stream_.bufferSize; ++ if ( !stream_.deviceBuffer || devBytes > ++ stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) ++ * stream_.bufferSize ) { ++ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); ++ stream_.deviceBuffer = (char *) calloc( devBytes, 1 ); ++ if ( !stream_.deviceBuffer ) { ++ free( stream_.userBuffer[INPUT] ); ++ stream_.userBuffer[INPUT] = nullptr; ++ errorText_ = "RtApiSndio::probeDeviceOpen: error allocating device buffer."; ++ return FAILURE; ++ } ++ } ++ setConvertInfo( INPUT, firstChannel ); ++ } ++ ++ stream_.device[INPUT] = device; ++ stream_.mode = DUPLEX; ++ return SUCCESS; ++ } ++ ++ // Normal path: open a new sndio device handle. ++ unsigned int sioMode = ( mode == OUTPUT ) ? SIO_PLAY : SIO_REC; struct sio_hdl *hdl = sio_open( SIO_DEVANY, sioMode, 0 ); if ( !hdl ) { ++ errorText_ = "RtApiSndio::probeDeviceOpen: error opening sndio device."; ++ goto error; ++ } ++ ++ // Map RtAudio format to sndio encoding ++ stream_.userFormat = format; ++ { ++ unsigned int bits, bps; ++ ++ if ( format == RTAUDIO_SINT8 ) { ++ bits = 8; bps = 1; ++ stream_.deviceFormat[mode] = RTAUDIO_SINT8; ++ } else if ( format == RTAUDIO_SINT16 ) { ++ bits = 16; bps = 2; ++ stream_.deviceFormat[mode] = RTAUDIO_SINT16; ++ } else if ( format == RTAUDIO_SINT24 ) { ++ bits = 24; bps = 4; ++ stream_.deviceFormat[mode] = RTAUDIO_SINT24; ++ } else if ( format == RTAUDIO_SINT32 ) { ++ bits = 32; bps = 4; ++ stream_.deviceFormat[mode] = RTAUDIO_SINT32; ++ } else { ++ // Float formats not natively supported: use SINT16, RtAudio converts ++ bits = 16; bps = 2; ++ stream_.deviceFormat[mode] = RTAUDIO_SINT16; ++ } ++ ++ struct sio_par par; ++ sio_initpar( &par ); ++ par.bits = bits; ++ par.bps = bps; ++ par.sig = 1; ++ par.le = SIO_LE_NATIVE; ++ par.rate = sampleRate; ++ par.round = *bufferSize; ++ par.appbufsz = *bufferSize * 4; ++ par.pchan = ( mode == OUTPUT ) ? channels : 0; ++ par.rchan = ( mode == INPUT ) ? channels : 0; if ( !sio_setpar( hdl, &par ) ) { ++ sio_close( hdl ); ++ errorText_ = "RtApiSndio::probeDeviceOpen: error setting stream parameters."; ++ return FAILURE; ++ } if ( !sio_getpar( hdl, &par ) ) { ++ sio_close( hdl ); ++ errorText_ = "RtApiSndio::probeDeviceOpen: error getting stream parameters."; ++ return FAILURE; ++ } ++ ++ if ( par.rate != sampleRate ) { ++ sio_close( hdl ); ++ errorStream_ << "RtApiSndio::probeDeviceOpen: sample rate " << sampleRate ++ << " not supported (got " << par.rate << ")."; ++ errorText_ = errorStream_.str(); ++ return FAILURE; ++ } ++ ++ *bufferSize = par.round; ++ stream_.bufferSize = *bufferSize; ++ stream_.nBuffers = par.appbufsz / par.round; ++ stream_.sampleRate = sampleRate; ++ } // end format/par scope ++ ++ stream_.nUserChannels[mode] = channels; ++ stream_.nDeviceChannels[mode] = channels; ++ ++ stream_.userInterleaved = true; ++ stream_.deviceInterleaved[mode] = true; ++ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) ++ stream_.userInterleaved = false; ++ ++ stream_.doConvertBuffer[mode] = false; ++ stream_.doByteSwap[mode] = false; ++ if ( stream_.userFormat != stream_.deviceFormat[mode] ) ++ stream_.doConvertBuffer[mode] = true; ++ if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] ) ++ stream_.doConvertBuffer[mode] = true; ++ if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] && ++ stream_.nUserChannels[mode] > 1 ) ++ stream_.doConvertBuffer[mode] = true; ++ ++ // Allocate or reuse SndioHandle ++ if ( !handle ) { ++ try { ++ handle = new SndioHandle; ++ } ++ catch ( std::bad_alloc& ) { ++ sio_close( hdl ); ++ errorText_ = "RtApiSndio::probeDeviceOpen: error allocating SndioHandle."; ++ goto error; ++ } ++ stream_.apiHandle = (void *) handle; ++ } ++ handle->handle = hdl; ++ sio_onxrun( hdl, sndioXrunCb, handle ); ++ ++ // Allocate user buffer ++ { ++ unsigned long bufBytes = stream_.nUserChannels[mode] * *bufferSize * ++ formatBytes( stream_.userFormat ); ++ stream_.userBuffer[mode] = (char *) calloc( bufBytes, 1 ); ++ if ( !stream_.userBuffer[mode] ) { ++ errorText_ = "RtApiSndio::probeDeviceOpen: error allocating user buffer."; ++ goto error; ++ } ++ } ++ ++ if ( stream_.doConvertBuffer[mode] ) { ++ bool makeBuffer = true; ++ unsigned long bufBytes = stream_.nDeviceChannels[mode] * ++ formatBytes( stream_.deviceFormat[mode] ); ++ if ( mode == INPUT ) { ++ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) { ++ unsigned long bytesOut = stream_.nDeviceChannels[0] * ++ formatBytes( stream_.deviceFormat[0] ); ++ if ( bufBytes <= bytesOut ) makeBuffer = false; ++ } ++ } ++ if ( makeBuffer ) { ++ bufBytes *= *bufferSize; ++ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); ++ stream_.deviceBuffer = (char *) calloc( bufBytes, 1 ); ++ if ( !stream_.deviceBuffer ) { ++ errorText_ = "RtApiSndio::probeDeviceOpen: error allocating device buffer."; ++ goto error; ++ } ++ } ++ } ++ ++ stream_.device[mode] = device; ++ stream_.state = STREAM_STOPPED; ++ ++ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); ++ ++ // Setup mode and callback thread ++ if ( stream_.mode == OUTPUT && mode == INPUT ) { ++ stream_.mode = DUPLEX; ++ } else { ++ stream_.mode = mode; ++ ++ stream_.callbackInfo.object = (void *) this; ++ ++ pthread_attr_t attr; ++ pthread_attr_init( &attr ); ++ pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); ++ pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); ++ ++ stream_.callbackInfo.isRunning = true; ++ int result = pthread_create( &stream_.callbackInfo.thread, &attr, ++ sndioCallbackHandler, &stream_.callbackInfo ); ++ pthread_attr_destroy( &attr ); ++ if ( result ) { ++ stream_.callbackInfo.isRunning = false; ++ errorText_ = "RtApiSndio::probeDeviceOpen: error creating callback thread!"; ++ goto error; ++ } ++ } ++ ++ return SUCCESS; ++ ++ error: ++ // If a callback thread is already running (e.g., from a prior OUTPUT pass ++ // that succeeded before this INPUT/DUPLEX pass failed), stop it now so the ++ // thread doesn't access the handle after we free it below. ++ if ( stream_.callbackInfo.isRunning ) { ++ stream_.callbackInfo.isRunning = false; ++ // Thread spins in 5ms nanosleep when state != RUNNING; it will exit promptly. ++ pthread_join( stream_.callbackInfo.thread, nullptr ); ++ } ++ if ( handle ) { ++ if ( handle->handle ) sio_close( handle->handle ); ++ delete handle; ++ stream_.apiHandle = nullptr; ++ } ++ for ( int i = 0; i < 2; i++ ) { ++ if ( stream_.userBuffer[i] ) { ++ free( stream_.userBuffer[i] ); ++ stream_.userBuffer[i] = nullptr; ++ } ++ } ++ if ( stream_.deviceBuffer ) { ++ free( stream_.deviceBuffer ); ++ stream_.deviceBuffer = nullptr; ++ } ++ stream_.state = STREAM_CLOSED; ++ return FAILURE; ++} ++ ++void RtApiSndio :: closeStream() ++{ ++ if ( stream_.state == STREAM_CLOSED ) { ++ errorText_ = "RtApiSndio::closeStream(): no open stream to close!"; ++ error( RTAUDIO_WARNING ); ++ return; ++ } ++ ++ SndioHandle *handle = (SndioHandle *) stream_.apiHandle; ++ stream_.callbackInfo.isRunning = false; ++ ++ MUTEX_LOCK( &stream_.mutex ); ++ stream_.state = STREAM_CLOSED; ++ MUTEX_UNLOCK( &stream_.mutex ); ++ ++ // Join FIRST: thread may be in poll/sio_write (up to 23ms timeout). ++ // Only call sio_stop/sio_close after join; sio is not thread-safe. ++ pthread_join( stream_.callbackInfo.thread, nullptr ); ++ if ( handle ) { ++ if ( handle->handle ) { ++ sio_stop( handle->handle ); ++ sio_close( handle->handle ); ++ } ++ delete handle; ++ stream_.apiHandle = nullptr; ++ } ++ ++ for ( int i = 0; i < 2; i++ ) { ++ if ( stream_.userBuffer[i] ) { ++ free( stream_.userBuffer[i] ); ++ stream_.userBuffer[i] = nullptr; ++ } ++ } ++ if ( stream_.deviceBuffer ) { ++ free( stream_.deviceBuffer ); ++ stream_.deviceBuffer = nullptr; ++ } ++ ++ clearStreamInfo(); ++} ++ ++RtAudioErrorType RtApiSndio :: startStream() ++{ ++ if ( stream_.state != STREAM_STOPPED ) { ++ if ( stream_.state == STREAM_RUNNING ) ++ errorText_ = "RtApiSndio::startStream(): stream already running!"; ++ else ++ errorText_ = "RtApiSndio::startStream(): stream is stopping or closed!"; ++ return error( RTAUDIO_WARNING ); ++ } ++ ++ SndioHandle *handle = (SndioHandle *) stream_.apiHandle; ++ ++ MUTEX_LOCK( &stream_.mutex ); if ( !sio_start( handle->handle ) ) { ++ MUTEX_UNLOCK( &stream_.mutex ); ++ errorText_ = "RtApiSndio::startStream(): error starting sndio stream."; ++ return error( RTAUDIO_SYSTEM_ERROR ); ++ } stream_.state = STREAM_RUNNING; ++ MUTEX_UNLOCK( &stream_.mutex ); ++ return RTAUDIO_NO_ERROR; ++} ++ ++RtAudioErrorType RtApiSndio :: stopStream() ++{ ++ if ( stream_.state != STREAM_RUNNING && stream_.state != STREAM_STOPPING ) { ++ if ( stream_.state == STREAM_STOPPED ) ++ errorText_ = "RtApiSndio::stopStream(): stream already stopped!"; ++ else ++ errorText_ = "RtApiSndio::stopStream(): stream is closed!"; ++ return error( RTAUDIO_WARNING ); ++ } ++ ++ MUTEX_LOCK( &stream_.mutex ); ++ ++ if ( stream_.state == STREAM_STOPPED ) { ++ MUTEX_UNLOCK( &stream_.mutex ); ++ return RTAUDIO_NO_ERROR; ++ } ++ ++ SndioHandle *handle = (SndioHandle *) stream_.apiHandle; ++ ++ // Do NOT call sio_stop() here: stopStream() may be called from any thread, ++ // including while the callback thread holds the sio handle in sio_write(). ++ // sio is not thread-safe; concurrent sio_stop()+sio_write() causes hangs. ++ // Instead, just set state=STOPPED; closeStream() calls sio_stop() after ++ // pthread_join() ensures no concurrent sio I/O. ++ stream_.state = STREAM_STOPPED; ++ MUTEX_UNLOCK( &stream_.mutex ); ++ return RTAUDIO_NO_ERROR; ++} ++ ++RtAudioErrorType RtApiSndio :: abortStream() ++{ ++ if ( stream_.state != STREAM_RUNNING ) { ++ if ( stream_.state == STREAM_STOPPED ) ++ errorText_ = "RtApiSndio::abortStream(): stream already stopped!"; ++ else ++ errorText_ = "RtApiSndio::abortStream(): stream is stopping or closed!"; ++ return error( RTAUDIO_WARNING ); ++ } ++ ++ MUTEX_LOCK( &stream_.mutex ); ++ // Same thread-safety rule as stopStream(): no sio_stop() here. ++ // closeStream() will call sio_stop() after pthread_join(). ++ stream_.state = STREAM_STOPPED; ++ MUTEX_UNLOCK( &stream_.mutex ); ++ return RTAUDIO_NO_ERROR; ++} ++ ++void RtApiSndio :: callbackEvent() ++{ ++ SndioHandle *handle = (SndioHandle *) stream_.apiHandle; ++ ++ if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_CLOSED ) { ++ // Spin-wait briefly when stopped to avoid busy-looping ++ struct timespec ts = { 0, 5000000 }; // 5 ms ++ nanosleep( &ts, nullptr ); ++ return; ++ } ++ ++ if ( stream_.state != STREAM_RUNNING ) return; ++ ++ // Invoke user callback ++ int doStopStream = 0; ++ RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; ++ double streamTime = getStreamTime(); ++ RtAudioStreamStatus status = 0; ++ if ( stream_.mode != INPUT && handle->xrun[0] ) { ++ status |= RTAUDIO_OUTPUT_UNDERFLOW; ++ handle->xrun[0] = false; ++ } ++ if ( stream_.mode != OUTPUT && handle->xrun[1] ) { ++ status |= RTAUDIO_INPUT_OVERFLOW; ++ handle->xrun[1] = false; ++ } ++ ++ { static int _cb_pre=0; if(++_cb_pre<=3) { fprintf(stderr,"[sndio-dbg] invoking user callback #%d\n",_cb_pre); fflush(stderr); } } ++ doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], ++ stream_.bufferSize, streamTime, status, ++ stream_.callbackInfo.userData ); ++ if ( doStopStream == 2 ) { ++ abortStream(); ++ return; ++ } ++ ++ // Perform I/O outside the mutex so closeStream() can set state and call ++ // sio_stop() to unblock a thread waiting in sio_read/sio_write. ++ if ( stream_.state != STREAM_RUNNING ) { ++ RtApi::tickStreamTime(); ++ return; ++ } ++ ++ { ++ char *buffer; ++ int samples; ++ RtAudioFormat format; ++ size_t nbytes, written; ++ ++ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { ++ if ( stream_.doConvertBuffer[0] ) { ++ buffer = stream_.deviceBuffer; ++ convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] ); ++ samples = stream_.bufferSize * stream_.nDeviceChannels[0]; ++ format = stream_.deviceFormat[0]; ++ } else { ++ buffer = stream_.userBuffer[0]; ++ samples = stream_.bufferSize * stream_.nUserChannels[0]; ++ format = stream_.userFormat; ++ } ++ if ( stream_.doByteSwap[0] ) ++ byteSwapBuffer( buffer, samples, format ); ++ ++ nbytes = samples * formatBytes( format ); ++ ++ // Use poll with a timeout so sio_write() cannot block indefinitely. ++ // This is critical for clean shutdown: stopStream() calls sio_stop() ++ // which stops the device clock, so POLLOUT may never fire again after ++ // that point. Two buffer periods is plenty under normal operation. ++ { ++ int timeoutMs = (int)( 2000.0 * stream_.bufferSize / stream_.sampleRate ) + 10; ++ struct pollfd pfd[8]; ++ { static int _cb_n=0; if(++_cb_n<=5||_cb_n%100==0) { fprintf(stderr,"[sndio-dbg] callbackEvent #%d pre-poll\n",_cb_n); fflush(stderr); } } ++ int nfds = sio_pollfd( handle->handle, pfd, POLLOUT ); ++ int ready = ( nfds > 0 ) ? poll( pfd, nfds, timeoutMs ) : 0; ++ written = 0; ++ { static int _pb=0; if(++_pb<=10||_pb%50==0) { int rev = (ready>0)?sio_revents(handle->handle,pfd):0; fprintf(stderr,"[sndio-dbg] poll#%d nfds=%d ready=%d rev=0x%x POLLOUT=%d\n",_pb,nfds,ready,rev,!!(rev&POLLOUT)); fflush(stderr); } } ++ if ( ready > 0 && ( sio_revents( handle->handle, pfd ) & POLLOUT ) ) ++ written = sio_write( handle->handle, buffer, nbytes ); ++ } ++ if ( written != nbytes ) { ++ handle->xrun[0] = true; ++ errorText_ = "RtApiSndio::callbackEvent: audio write error."; ++ error( RTAUDIO_WARNING ); ++ } ++ } ++ ++ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) { ++ if ( stream_.doConvertBuffer[1] ) { ++ buffer = stream_.deviceBuffer; ++ samples = stream_.bufferSize * stream_.nDeviceChannels[1]; ++ format = stream_.deviceFormat[1]; ++ } else { ++ buffer = stream_.userBuffer[1]; ++ samples = stream_.bufferSize * stream_.nUserChannels[1]; ++ format = stream_.userFormat; ++ } ++ ++ nbytes = samples * formatBytes( format ); ++ ++ // Use poll with a timeout so we don't block forever on play-only devices. ++ // Two buffer periods (in ms) is enough for normal operation. ++ int timeoutMs = (int)( 2000.0 * stream_.bufferSize / stream_.sampleRate ) + 10; ++ struct pollfd pfd[8]; ++ int nfds = sio_pollfd( handle->handle, pfd, POLLIN ); ++ int ready = ( nfds > 0 ) ? poll( pfd, nfds, timeoutMs ) : 0; ++ ++ size_t got = 0; ++ if ( ready > 0 && ( sio_revents( handle->handle, pfd ) & POLLIN ) ) ++ got = sio_read( handle->handle, buffer, nbytes ); ++ ++ if ( got != nbytes ) { ++ if ( got == 0 ) ++ memset( buffer, 0, nbytes ); // play-only device: substitute silence ++ else { ++ handle->xrun[1] = true; ++ errorText_ = "RtApiSndio::callbackEvent: audio read error."; ++ error( RTAUDIO_WARNING ); ++ } ++ } ++ if ( got > 0 ) { ++ if ( stream_.doByteSwap[1] ) ++ byteSwapBuffer( buffer, samples, format ); ++ if ( stream_.doConvertBuffer[1] ) ++ convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); ++ } ++ } ++ } ++ ++ RtApi::tickStreamTime(); ++ if ( doStopStream == 1 ) stopStream(); ++} ++ ++static void *sndioCallbackHandler( void *ptr ) ++{ ++ CallbackInfo *info = (CallbackInfo *) ptr; ++ RtApiSndio *object = (RtApiSndio *) info->object; ++ bool *isRunning = &info->isRunning; ++ ++ while ( *isRunning == true ) { ++ pthread_testcancel(); ++ object->callbackEvent(); ++ } ++ ++ pthread_exit( nullptr ); ++} ++ ++//******************** End of __OPENBSD_SNDIO__ *********************// ++#endif + + // *************************************************** // + // diff --git a/audio/chuck/patches/patch-src_host_RtAudio_RtAudio_h b/audio/chuck/patches/patch-src_host_RtAudio_RtAudio_h new file mode 100644 index 0000000..6986fdc --- /dev/null +++ b/audio/chuck/patches/patch-src_host_RtAudio_RtAudio_h @@ -0,0 +1,50 @@ +Index: src/host/RtAudio/RtAudio.h +--- src/host/RtAudio/RtAudio.h.orig ++++ src/host/RtAudio/RtAudio.h +@@ -255,6 +255,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio + LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */ + LINUX_PULSE, /*!< The Linux PulseAudio API. */ + LINUX_OSS, /*!< The Linux Open Sound System API. */ ++ OPENBSD_SNDIO, /*!< The OpenBSD sndio API. */ + UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */ + MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */ + WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */ +@@ -1144,6 +1145,38 @@ class RtApiOss: public RtApi (public) + private: + + bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, ++ unsigned int firstChannel, unsigned int sampleRate, ++ RtAudioFormat format, unsigned int *bufferSize, ++ RtAudio::StreamOptions *options ) /* override */; ++}; ++ ++#endif ++ ++#if defined(__OPENBSD_SNDIO__) ++ ++class RtApiSndio: public RtApi ++{ ++public: ++ ++ RtApiSndio(); ++ ~RtApiSndio(); ++ RtAudio::Api getCurrentApi() /* override */ { return RtAudio::OPENBSD_SNDIO; } ++ unsigned int getDeviceCount( void ) /* override */; ++ RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) /* override */; ++ void closeStream( void ) /* override */; ++ RtAudioErrorType startStream( void ) /* override */; ++ RtAudioErrorType stopStream( void ) /* override */; ++ RtAudioErrorType abortStream( void ) /* override */; ++ ++ // This function is intended for internal use only. It must be ++ // public because it is called by the internal callback handler, ++ // which is not a member of RtAudio. External use of this function ++ // will most likely produce highly undesirable results! ++ void callbackEvent( void ); ++ ++ private: ++ ++ bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, + unsigned int firstChannel, unsigned int sampleRate, + RtAudioFormat format, unsigned int *bufferSize, + RtAudio::StreamOptions *options ) /* override */; diff --git a/audio/chuck/patches/patch-src_host_chuck_audio_cpp b/audio/chuck/patches/patch-src_host_chuck_audio_cpp new file mode 100644 index 0000000..13753b5 --- /dev/null +++ b/audio/chuck/patches/patch-src_host_chuck_audio_cpp @@ -0,0 +1,31 @@ +Index: src/host/chuck_audio.cpp +--- src/host/chuck_audio.cpp.orig ++++ src/host/chuck_audio.cpp +@@ -147,6 +147,10 @@ static RtAudio::Api driverNameToApi( const char * driv + if( driverLower == "oss" ) + api = RtAudio::LINUX_OSS; + #endif ++ #if defined(__OPENBSD_SNDIO__) ++ if( driverLower == "sndio" ) ++ api = RtAudio::OPENBSD_SNDIO; ++ #endif + #if defined(__UNIX_JACK__) + if( driverLower == "jack" ) + api = RtAudio::UNIX_JACK; +@@ -184,6 +188,8 @@ static RtAudio::Api driverNameToApi( const char * driv + api = RtAudio::LINUX_OSS; + #elif defined(__PLATFORM_LINUX__) && defined(__UNIX_JACK__) + api = RtAudio::UNIX_JACK; ++ #elif defined(__OPENBSD_SNDIO__) ++ api = RtAudio::OPENBSD_SNDIO; + #elif defined(__MACOSX_CORE__) + api = RtAudio::MACOSX_CORE; + #endif +@@ -206,6 +212,7 @@ static const char * apiToDriverName( RtAudio::Api api + "ALSA", + "Pulse", + "OSS", ++ "sndio", + "Jack", + "CoreAudio", + "WASAPI", diff --git a/audio/chuck/patches/patch-src_host_chuck_main_cpp b/audio/chuck/patches/patch-src_host_chuck_main_cpp new file mode 100644 index 0000000..104aeac --- /dev/null +++ b/audio/chuck/patches/patch-src_host_chuck_main_cpp @@ -0,0 +1,24 @@ +Index: src/host/chuck_main.cpp +--- src/host/chuck_main.cpp.orig ++++ src/host/chuck_main.cpp +@@ -1213,7 +1213,9 @@ t_CKBOOL go( int argc, const char ** argv ) + #endif // __DISABLE_MIDI__ + + // probe HID devices ++ #ifndef __DISABLE_HID__ + HidInManager::probeHidIn(); ++ #endif // __DISABLE_HID__ + + // restore log level + the_chuck->setLogLevel( log_level ); +@@ -1493,8 +1495,10 @@ t_CKBOOL go( int argc, const char ** argv ) + + //------------------------- HID RELATED SETUP ----------------------------- + #ifndef __ALTER_HID__ ++ #ifndef __DISABLE_HID__ + // pre-load hid + if( load_hid ) HidInManager::init(); ++ #endif // __DISABLE_HID__ + #endif // __ALTER_HID__ + + diff --git a/audio/chuck/patches/patch-src_makefile b/audio/chuck/patches/patch-src_makefile new file mode 100644 index 0000000..bf087ba --- /dev/null +++ b/audio/chuck/patches/patch-src_makefile @@ -0,0 +1,42 @@ +Index: src/makefile +--- src/makefile.orig ++++ src/makefile +@@ -16,7 +16,7 @@ CK_HOST_DIR=host + # where to find RtAudio + RTAUDIO_DIR=RtAudio + # chuck version +-CK_VERSION=1.5.5.7 ++CK_VERSION=1.5.5.8-dev + + + ########################## DEFAULT MAKE TARGET ################################ +@@ -24,6 +24,7 @@ CK_VERSION=1.5.5.7 + current: + @echo "[chuck build]: please use one of the following configurations:" + @echo " make linux-alsa, make linux-jack, make linux-pulse, linux-all," ++ @echo " make openbsd-sndio," + @echo " make mac, make mac-ub, make web, make win32" + + +@@ -80,8 +81,8 @@ host-web/webchuck/js/webchuck.js: $(EMSCRIPTENSRCS) $( + # https://github.com/ccrma/chuck#readme + + # make targets +-.PHONY: mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa test +-mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa: chuck ++.PHONY: mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa openbsd-sndio test ++mac mac-ub osx linux-all linux linux-pulse linux-jack linux-alsa openbsd-sndio: chuck + + win32: + @echo "for Windows build, see visual-studio/chuck.sln" +@@ -173,6 +174,10 @@ endif + + ifneq (,$(strip $(filter linux-alsa,$(MAKECMDGOALS)))) + include $(CK_CORE_DIR)/makefile.x/makefile.alsa ++endif ++ ++ifneq (,$(strip $(filter openbsd-sndio,$(MAKECMDGOALS)))) ++include $(CK_CORE_DIR)/makefile.x/makefile.sndio + endif + + # ifneq (,$(strip $(filter cygwin,$(MAKECMDGOALS)))) diff --git a/audio/chuck/peg b/audio/chuck/peg new file mode 100644 index 0000000..e69de29 diff --git a/audio/chuck/pkg/DESCR b/audio/chuck/pkg/DESCR new file mode 100644 index 0000000..3b1e198 --- /dev/null +++ b/audio/chuck/pkg/DESCR @@ -0,0 +1,15 @@ +ChucK is a strongly-timed, concurrent, and on-the-fly music programming +language. It is compiled in real-time, on-the-fly, and allows code to be +added and modified while the program is running, without stopping or +restarting. It is used for synthesis, composition, performance, and +analysis. + +ChucK presents a unique time-based, concurrent programming model that's +precise and expressive (with regards to time), dynamic (with regards to +concurrency), and interactive (with regards to interface). It is open-source +and freely available. + +On OpenBSD, ChucK uses the JACK audio server for output. Start jackd (via +sndio or another backend) before running chuck. + +Website: https://chuck.stanford.edu/ diff --git a/audio/chuck/pkg/PLIST b/audio/chuck/pkg/PLIST new file mode 100644 index 0000000..7f892c6 --- /dev/null +++ b/audio/chuck/pkg/PLIST @@ -0,0 +1 @@ +bin/chuck