diff --git a/.gitmodules b/.gitmodules index cc3821de..8ea2ad3c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,7 +2,3 @@ path = Libraries/DaisySP url = https://github.com/electro-smith/DaisySP.git branch = master -[submodule "Tools/hvcc"] - path = Tools/hvcc - url = https://github.com/pingdynasty/hvcc.git - branch = develop diff --git a/HeavySource/HvMessage.c b/HeavySource/HvMessage.c deleted file mode 100644 index 87667af7..00000000 --- a/HeavySource/HvMessage.c +++ /dev/null @@ -1,214 +0,0 @@ -/** - * Copyright (c) 2014,2015,2016 Enzien Audio Ltd. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "HvMessage.h" -#include "message.h" -#include - -HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp) { - m->timestamp = timestamp; - m->numElements = (hv_uint16_t) numElements; - m->numBytes = (hv_uint16_t) msg_getCoreSize(numElements); - return m; -} - -HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f) { - m->timestamp = timestamp; - m->numElements = 1; - m->numBytes = sizeof(HvMessage); - msg_setFloat(m, 0, f); - return m; -} - -HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp) { - m->timestamp = timestamp; - m->numElements = 1; - m->numBytes = sizeof(HvMessage); - msg_setBang(m, 0); - return m; -} - -HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s) { - m->timestamp = timestamp; - m->numElements = 1; - m->numBytes = sizeof(HvMessage) + (hv_uint16_t) hv_strlen(s); - msg_setSymbol(m, 0, s); - return m; -} - -HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h) { - m->timestamp = timestamp; - m->numElements = 1; - m->numBytes = sizeof(HvMessage); - msg_setHash(m, 0, h); - return m; -} - -void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len) { - HvMessage *r = (HvMessage *) buffer; - - hv_size_t len_r = msg_getCoreSize(msg_getNumElements(m)); - - // assert that the message is not already larger than the length of the buffer - hv_assert(len_r <= len); - - // copy the basic message to the buffer - hv_memcpy(r, m, len_r); - - char *p = buffer + len_r; // points to the end of the base message - for (int i = 0; i < msg_getNumElements(m); ++i) { - if (msg_isSymbol(m,i)) { - const hv_size_t symLen = (hv_size_t) hv_strlen(msg_getSymbol(m,i)) + 1; // include the trailing null char - hv_assert(len_r + symLen <= len); // stay safe! - hv_strncpy(p, msg_getSymbol(m,i), symLen); - msg_setSymbol(r, i, p); - p += symLen; - len_r += symLen; - } - } - - r->numBytes = (hv_uint16_t) len_r; // update the message size in memory -} - -// the message is serialised such that all symbol elements are placed in order at the end of the buffer -HvMessage *msg_copy(const HvMessage *m) { - const hv_uint32_t heapSize = msg_getSize(m); - char *r = (char *) hv_malloc(heapSize); - hv_assert(r != NULL); - msg_copyToBuffer(m, r, heapSize); - return (HvMessage *) r; -} - -void msg_free(HvMessage *m) { - hv_free(m); // because heap messages are serialised in memory, a simple call to free releases the message -} - -bool msg_hasFormat(const HvMessage *m, const char *fmt) { - hv_assert(fmt != NULL); - const int n = msg_getNumElements(m); - for (int i = 0; i < n; ++i) { - switch (fmt[i]) { - case 'b': if (!msg_isBang(m, i)) return false; break; - case 'f': if (!msg_isFloat(m, i)) return false; break; - case 'h': if (!msg_isHash(m, i)) return false; break; - case 's': if (!msg_isSymbol(m, i)) return false; break; - default: return false; - } - } - return (fmt[n] == '\0'); -} - -bool msg_compareSymbol(const HvMessage *m, int i, const char *s) { - switch (msg_getType(m,i)) { - case HV_MSG_SYMBOL: return !hv_strcmp(msg_getSymbol(m, i), s); - case HV_MSG_HASH: return (msg_getHash(m,i) == hv_string_to_hash(s)); - default: return false; - } -} - -bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n) { - if (i_m < msg_getNumElements(m) && i_n < msg_getNumElements(n)) { - if (msg_getType(m, i_m) == msg_getType(n, i_n)) { - switch (msg_getType(m, i_m)) { - case HV_MSG_BANG: return true; - case HV_MSG_FLOAT: return (msg_getFloat(m, i_m) == msg_getFloat(n, i_n)); - case HV_MSG_SYMBOL: return msg_compareSymbol(m, i_m, msg_getSymbol(n, i_n)); - case HV_MSG_HASH: return msg_getHash(m,i_m) == msg_getHash(n,i_n); - default: break; - } - } - } - return false; -} - -void msg_setElementToFrom(HvMessage *n, int i_n, const HvMessage *const m, int i_m) { - switch (msg_getType(m, i_m)) { - case HV_MSG_BANG: msg_setBang(n, i_n); break; - case HV_MSG_FLOAT: msg_setFloat(n, i_n, msg_getFloat(m, i_m)); break; - case HV_MSG_SYMBOL: msg_setSymbol(n, i_n, msg_getSymbol(m, i_m)); break; - case HV_MSG_HASH: msg_setHash(n, i_n, msg_getHash(m, i_m)); - default: break; - } -} - -hv_uint32_t msg_getHash(const HvMessage *const m, int i) { - hv_assert(i < msg_getNumElements(m)); // invalid index - switch (msg_getType(m,i)) { - case HV_MSG_BANG: return 0xFFFFFFFF; - case HV_MSG_FLOAT: { - float f = msg_getFloat(m,i); - return *((hv_uint32_t *) &f); - } - case HV_MSG_SYMBOL: return hv_string_to_hash(msg_getSymbol(m,i)); - case HV_MSG_HASH: return (&(m->elem)+i)->data.h; - default: return 0; - } -} - -char *msg_toString(const HvMessage *m) { - hv_assert(msg_getNumElements(m) > 0); - int *len = (int *) hv_alloca(msg_getNumElements(m)*sizeof(int)); - int size = 0; // the total length of our final buffer - - // loop through every element in our list of atoms - // first loop figures out how long our buffer should be - for (int i = 0; i < msg_getNumElements(m); i++) { - // length of our string is each atom plus a space, or \0 on the end - switch (msg_getType(m, i)) { - case HV_MSG_BANG: len[i] = 5; break; - case HV_MSG_FLOAT: len[i] = strnlen(msg_ftoa(msg_getFloat(m, i), 10), 16)+1; break; - case HV_MSG_SYMBOL: len[i] = strnlen(msg_getSymbol(m, i), 16)+1; break; - case HV_MSG_HASH: len[i] = strnlen(msg_itoa(msg_getHash(m, i), 16), 8)+3; break; - default: break; - } - size += len[i]; - } - - hv_assert(size > 0); - - // now we do the piecewise concatenation into our final string - // the final buffer we will pass back after concatenating all strings - user should free it - char *finalString = (char *) hv_malloc(size*sizeof(char)); - char* dst = finalString; - for (int i = 0; i < msg_getNumElements(m); i++) { - // put a string representation of each atom into the final string - char* ptr; - switch (msg_getType(m, i)) { - case HV_MSG_BANG: - dst = stpcpy(dst, "bang"); - break; - case HV_MSG_FLOAT: - ptr = msg_ftoa(msg_getFloat(m, i), 10); - dst = stpcpy(dst, ptr); - break; - case HV_MSG_SYMBOL: - ptr = (char*)msg_getSymbol(m, i); - dst = stpcpy(dst, ptr); - break; - case HV_MSG_HASH: - ptr = msg_itoa(msg_getHash(m, i), 16); - dst = stpcpy(dst, "0x"); - dst = stpcpy(dst, ptr); - break; - default: - break; - } - dst = stpcpy(dst, " "); - } - hv_assert(dst - finalString == size); - finalString[size-1] = '\0'; // ensure that the string is null terminated - return finalString; -} diff --git a/HeavySource/HvUtils.h b/HeavySource/HvUtils.h deleted file mode 100644 index 16c97ced..00000000 --- a/HeavySource/HvUtils.h +++ /dev/null @@ -1,352 +0,0 @@ -/** - * Copyright (c) 2014,2015,2016 Enzien Audio Ltd. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _HEAVY_UTILS_H_ -#define _HEAVY_UTILS_H_ - -// platform definitions -#if _WIN32 || _WIN64 - #define HV_WIN 1 -#ifdef _MSC_VER - #define HV_MSVC 1 -#endif -#elif __APPLE__ - #define HV_APPLE 1 -#elif __ANDROID__ - #define HV_ANDROID 1 -#elif __unix__ || __unix - #define HV_UNIX 1 -#else - #warning Could not detect platform. Assuming Unix-like. -#endif - -#ifdef EMSCRIPTEN -#define HV_EMSCRIPTEN 1 -#endif - -// basic includes -#include -#ifdef ARM_CORTEX -#include -#else -#include -#include -#endif - - -// type definitions -#include -#include -#define hv_uint8_t uint8_t -#define hv_int16_t int16_t -#define hv_uint16_t uint16_t -#define hv_int32_t int32_t -#define hv_uint32_t uint32_t -#define hv_uint64_t uint64_t -#define hv_size_t size_t -#define hv_uintptr_t uintptr_t - -// SIMD-specific includes -#if !(HV_SIMD_NONE || HV_SIMD_NEON || HV_SIMD_SSE || HV_SIMD_AVX) - #define HV_SIMD_NEON __ARM_NEON__ - #define HV_SIMD_SSE (__SSE__ && __SSE2__ && __SSE3__ && __SSSE3__ && __SSE4_1__) - #define HV_SIMD_AVX (__AVX__ && HV_SIMD_SSE) -#endif -#ifndef HV_SIMD_FMA - #define HV_SIMD_FMA __FMA__ -#endif - -#if HV_SIMD_AVX || HV_SIMD_SSE - #include -#elif HV_SIMD_NEON - #include -#endif - -#if HV_SIMD_NEON // NEON - #define HV_N_SIMD 4 - #define hv_bufferf_t float32x4_t - #define hv_bufferi_t int32x4_t - #define hv_bInf_t float32x4_t - #define hv_bOutf_t float32x4_t* - #define hv_bIni_t int32x4_t - #define hv_bOuti_t int32x4_t* - #define VIf(_x) (_x) - #define VOf(_x) (&_x) - #define VIi(_x) (_x) - #define VOi(_x) (&_x) -#elif HV_SIMD_AVX // AVX - #define HV_N_SIMD 8 - #define hv_bufferf_t __m256 - #define hv_bufferi_t __m256i - #define hv_bInf_t __m256 - #define hv_bOutf_t __m256* - #define hv_bIni_t __m256i - #define hv_bOuti_t __m256i* - #define VIf(_x) (_x) - #define VOf(_x) (&_x) - #define VIi(_x) (_x) - #define VOi(_x) (&_x) -#elif HV_SIMD_SSE // SSE - #define HV_N_SIMD 4 - #define hv_bufferf_t __m128 - #define hv_bufferi_t __m128i - #define hv_bInf_t __m128 - #define hv_bOutf_t __m128* - #define hv_bIni_t __m128i - #define hv_bOuti_t __m128i* - #define VIf(_x) (_x) - #define VOf(_x) (&_x) - #define VIi(_x) (_x) - #define VOi(_x) (&_x) -#else // DEFAULT - #define HV_N_SIMD 1 - #undef HV_SIMD_NONE - #define HV_SIMD_NONE 1 - #define hv_bufferf_t float - #define hv_bufferi_t int - #define hv_bInf_t float - #define hv_bOutf_t float* - #define hv_bIni_t int - #define hv_bOuti_t int* - #define VIf(_x) (_x) - #define VOf(_x) (&_x) - #define VIi(_x) (_x) - #define VOi(_x) (&_x) -#endif - -#define HV_N_SIMD_MASK (HV_N_SIMD-1) - -// Strings -#include -#define hv_strlen(a) strlen(a) -#define hv_strncpy(a, b, c) strncpy(a, b, c) -#define hv_strcmp(a, b) strcmp(a, b) -#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__) - -// Memory management -#ifndef ARM_CORTEX -#define hv_realloc(a, b) realloc(a, b) -#endif // ARM_CORTEX -#define hv_memcpy(a, b, c) memcpy(a, b, c) -#define hv_memclear(a, b) memset(a, 0, b) -#if HV_MSVC - #include - #define hv_alloca(_n) _alloca(_n) - #if HV_SIMD_AVX - #define hv_malloc(_n) _aligned_malloc(_n, 32) - #define hv_realloc(a, b) _aligned_realloc(a, b, 32) - #define hv_free(x) _aligned_free(x) - #elif HV_SIMD_SSE || HV_SIMD_NEON - #define hv_malloc(_n) _aligned_malloc(_n, 16) - #define hv_realloc(a, b) _aligned_realloc(a, b, 16) - #define hv_free(x) _aligned_free(x) - #else // HV_SIMD_NONE - #define hv_malloc(_n) malloc(_n) - #define hv_free(_n) free(_n) - #endif -#elif HV_APPLE - #define hv_alloca(_n) alloca(_n) - #define hv_realloc(a, b) realloc(a, b) - #if HV_SIMD_AVX - #include - #define hv_malloc(_n) _mm_malloc(_n, 32) - #define hv_free(x) _mm_free(x) - #elif HV_SIMD_SSE - #include - #define hv_malloc(_n) _mm_malloc(_n, 16) - #define hv_free(x) _mm_free(x) - #elif HV_SIMD_NEON - // malloc on ios always has 16-byte alignment - #define hv_malloc(_n) malloc(_n) - #define hv_free(x) free(x) - #else // HV_SIMD_NONE - #define hv_malloc(_n) malloc(_n) - #define hv_free(x) free(x) - #endif -#elif defined ARM_CORTEX - #include - #define hv_alloca(_n) alloca(_n) - #define hv_malloc(_n) pvPortMalloc(_n) - #define hv_free(_n) vPortFree(_n) - #define hv_realloc(a, b) pvPortRealloc(a, b) -#else - #include - #define hv_alloca(_n) alloca(_n) - #if HV_SIMD_AVX - #define hv_malloc(_n) aligned_alloc(32, _n) - #define hv_free(x) free(x) - #elif HV_SIMD_SSE || HV_SIMD_NEON - #define hv_malloc(_n) aligned_alloc(16, _n) - #define hv_free(x) free(x) - #else // HV_SIMD_NONE - #define hv_malloc(_n) malloc(_n) - #define hv_free(_n) free(_n) - #endif -#endif - -// Assert -#ifdef ARM_CORTEX -#include "message.h" -#define hv_assert(e) ASSERT((e), "Heavy assertion failed") -#else -#include -#define hv_assert(e) assert(e) -#endif - -// Export and Inline -#if HV_MSVC -#define HV_EXPORT __declspec(dllexport) -#define inline __inline -#define HV_FORCE_INLINE __forceinline -#else -#define HV_EXPORT -#define HV_FORCE_INLINE inline __attribute__((always_inline)) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - // Returns a 32-bit hash of any string. Returns 0 if string is NULL. - hv_uint32_t hv_string_to_hash(const char *str); -#ifdef __cplusplus -} -#endif - -// Math -#ifndef ARM_CORTEX -#include -#endif - -static inline hv_size_t __hv_utils_max_ui(hv_size_t x, hv_size_t y) { return (x > y) ? x : y; } -static inline hv_size_t __hv_utils_min_ui(hv_size_t x, hv_size_t y) { return (x < y) ? x : y; } -static inline hv_int32_t __hv_utils_max_i(hv_int32_t x, hv_int32_t y) { return (x > y) ? x : y; } -static inline hv_int32_t __hv_utils_min_i(hv_int32_t x, hv_int32_t y) { return (x < y) ? x : y; } - -#define hv_max_ui(a, b) __hv_utils_max_ui(a, b) -#define hv_min_ui(a, b) __hv_utils_min_ui(a, b) -#define hv_max_i(a, b) __hv_utils_max_i(a, b) -#define hv_min_i(a, b) __hv_utils_min_i(a, b) -#define hv_max_f(a, b) fmaxf(a, b) -#define hv_min_f(a, b) fminf(a, b) -#define hv_max_d(a, b) fmax(a, b) -#define hv_min_d(a, b) fmin(a, b) -#ifdef ARM_CORTEX -#define hv_sin_f(a) arm_sin_f32(a) -#define hv_cos_f(a) arm_cos_f32(a) -#define hv_sqrt_f(a) arm_sqrtf(a) -#define hv_pow_f(a, b) fast_powf(a, b) -#define hv_exp_f(a) fast_expf(a) -#define hv_log_f(a) fast_logf(a) -#else -#define hv_sin_f(a) sinf(a) -#define hv_cos_f(a) cosf(a) -#define hv_sqrt_f(a) sqrtf(a) -#define hv_pow_f(a, b) powf(a, b) -#define hv_exp_f(a) expf(a) -#define hv_log_f(a) logf(a) -#endif -#define hv_sinh_f(a) sinhf(a) -#define hv_cosh_f(a) coshf(a) -#define hv_tan_f(a) tanf(a) -#define hv_tanh_f(a) tanhf(a) -#define hv_asin_f(a) asinf(a) -#define hv_asinh_f(a) asinhf(a) -#define hv_acos_f(a) acosf(a) -#define hv_acosh_f(a) acoshf(a) -#define hv_atan_f(a) atanf(a) -#define hv_atanh_f(a) atanhf(a) -#define hv_atan2_f(a, b) atan2f(a, b) -#define hv_abs_f(a) fabsf(a) -#if HV_ANDROID - // NOTE(mhroth): for whatever silly reason, log2f is not defined! - #define hv_log2_f(a) (1.44269504088896f*logf(a)) -#else - #define hv_log2_f(a) log2f(a) -#endif // HV_ANDROID -#define hv_log10_f(a) log10f(a) -#define hv_ceil_f(a) ceilf(a) -#define hv_floor_f(a) floorf(a) -#define hv_round_f(a) roundf(a) -#if HV_EMSCRIPTEN || defined ARM_CORTEX -#define hv_fma_f(a, b, c) ((a*b)+c) // emscripten does not support fmaf (yet?). Inefficient on ARM Cortex M -#else -#define hv_fma_f(a, b, c) fmaf(a, b, c) -#endif -#if HV_MSVC - // finds ceil(log2(x)) - #include - static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) { - unsigned long z = 0; - _BitScanReverse(&z, x); - return (hv_uint32_t) (z+1); - } -#else - static inline hv_uint32_t __hv_utils_min_max_log2(hv_uint32_t x) { - return (hv_uint32_t) (32 - __builtin_clz(x-1)); - } -#endif -#define hv_min_max_log2(a) __hv_utils_min_max_log2(a) - -// Atomics -#if HV_WIN - #include - #define hv_atomic_bool volatile LONG - #define HV_SPINLOCK_ACQUIRE(_x) while (InterlockedCompareExchange(&_x, true, false)) { } - #define HV_SPINLOCK_TRY(_x) return !InterlockedCompareExchange(&_x, true, false) - #define HV_SPINLOCK_RELEASE(_x) (_x = false) -#elif HV_ANDROID - // Android support for atomics isn't that great, we'll do it manually - // https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html - #define hv_atomic_bool hv_uint8_t - #define HV_SPINLOCK_ACQUIRE(_x) while (__sync_lock_test_and_set(&_x, 1)) - #define HV_SPINLOCK_TRY(_x) return !__sync_lock_test_and_set(&_x, 1) - #define HV_SPINLOCK_RELEASE(_x) __sync_lock_release(&_x) -#elif defined ARM_CORTEX || HV_EMSCRIPTEN - /* no spinlock if we don't have pre-emptive scheduling */ - #define hv_atomic_bool volatile bool - #define HV_SPINLOCK_ACQUIRE(_x) { extern volatile bool _msgLock; _msgLock = true; } - #define HV_SPINLOCK_TRY(_x) { extern volatile bool _msgLock; return !_msgLock; } - #define HV_SPINLOCK_RELEASE(_x) { extern volatile bool _msgLock; _msgLock = false; } -#elif __cplusplus - #include - #define hv_atomic_bool std::atomic_flag - #define HV_SPINLOCK_ACQUIRE(_x) while (_x.test_and_set(std::memory_order_acquire)) - #define HV_SPINLOCK_TRY(_x) return !_x.test_and_set(std::memory_order_acquire) - #define HV_SPINLOCK_RELEASE(_x) _x.clear(std::memory_order_release) -#elif defined(__has_include) - #if __has_include() - #include - #define hv_atomic_bool atomic_flag - #define HV_SPINLOCK_ACQUIRE(_x) while (atomic_flag_test_and_set_explicit(&_x, memory_order_acquire)) - #define HV_SPINLOCK_TRY(_x) return !atomic_flag_test_and_set_explicit(&_x, memory_order_acquire) - #define HV_SPINLOCK_RELEASE(_x) atomic_flag_clear_explicit(memory_order_release) - #endif -#endif - -#ifndef hv_atomic_bool - #define hv_atomic_bool volatile bool - #define HV_SPINLOCK_ACQUIRE(_x) \ - while (_x) {} \ - _x = true; - #define HV_SPINLOCK_TRY(_x) \ - if (!_x) { \ - _x = true; \ - return true; \ - } else return false; - #define HV_SPINLOCK_RELEASE(_x) (_x = false) -#endif - -#endif // _HEAVY_UTILS_H_ diff --git a/Makefile b/Makefile index 49890508..0987f9c8 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ else ifdef HEAVY # options for Heavy PD compilation PATCHNAME ?= $(HEAVY) PATCHCLASS ?= HeavyPatch -PATCHFILE ?= HeavyPatch.hpp +PATCHFILE ?= HeavyOWL_owl.hpp DEPS += heavy else ifdef GEN # options for Max/MSP Gen compilation @@ -76,13 +76,13 @@ TEST_FILES = $(notdir $(wildcard $(BUILDROOT)/TestPatches/*TestPatch.hpp)) TESTS = $(filter-out ShortFastFourierTest, $(TEST_FILES:%Patch.hpp=%)) export BUILD BUILDROOT TARGET -export PATCHNAME PATCHCLASS PATCHSOURCE +export PATCHNAME PATCHCLASS PATCHSOURCE export PATCHFILE PATCHIN PATCHOUT export HEAVYTOKEN HEAVYSERVICETOKEN HEAVY export SOUL SOULCLASS SOULFILE SOULHPP export CONFIG PLATFORM -DEPS += $(BUILD)/registerpatch.cpp $(BUILD)/registerpatch.h $(BUILD)/Source/startup.s +DEPS += $(BUILD)/registerpatch.cpp $(BUILD)/registerpatch.h $(BUILD)/Source/startup.s all: libs patch web diff --git a/README.md b/README.md index fdd47d0d..a3e5778d 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ Either install gcc-arm-none-eabi system-wide and ensure the binaries are in your TOOLROOT = /usr/bin/ -To compile puredata patches you need `hvcc`, the Heavy compiler. +To compile puredata patches you need `hvcc`, the Heavy compiler, in your path. $ sudo apt install python3 python3-pip - $ sudo pip3 install hvcc + $ pip3 install hvcc To compile patches in native format (e.g. for testing) you will also need the gcc compiler: diff --git a/Tools/HeavyPatch.tpl.hpp b/Tools/HeavyPatch.tpl.hpp deleted file mode 100644 index eff864bc..00000000 --- a/Tools/HeavyPatch.tpl.hpp +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef __HeavyPatch_hpp__ -#define __HeavyPatch_hpp__ - -#include "Patch.h" -#include "basicmaths.h" -#include "HvHeavy.h" -#include "Heavy_owl.hpp" -#include "Heavy_owl_constants.h" - -#define BUTTON_Push PUSHBUTTON -#define BUTTON_B1 BUTTON_A -#define BUTTON_B2 BUTTON_B -#define BUTTON_B3 BUTTON_C -#define BUTTON_B4 BUTTON_D -#define BUTTON_B5 BUTTON_E -#define BUTTON_B6 BUTTON_F -#define BUTTON_B7 BUTTON_G -#define BUTTON_B8 BUTTON_H - -#define HV_HASH_NOTEIN 0x67e37ca3 -#define HV_HASH_CTLIN 0x41be0f9c -#define HV_HASH_BENDIN 0x3083f0f7 -#define HV_HASH_TOUCHIN 0x553925bd -#define HV_HASH_PGMIN 0x2e1ea03d - -#define HV_HASH_NOTEOUT 0xd1d4ac2 -#define HV_HASH_CTLOUT 0xe5e2a040 -#define HV_HASH_BENDOUT 0xe8458013 -#define HV_HASH_TOUCHOUT 0x476d4387 -#define HV_HASH_PGMOUT 0x8753e39e - -#define HEAVY_MESSAGE_POOL_SIZE 4 // in kB (default 10kB) -#define HEAVY_MESSAGE_IN_QUEUE_SIZE 1 // in kB (default 2kB) -#define HEAVY_MESSAGE_OUT_QUEUE_SIZE 0 // in kB (default 0kB) - -extern "C" { - volatile bool _msgLock = false; - static bool isButtonPressed(PatchButtonId bid){ - return getProgramVector()->buttons & (1<buttons |= 1<buttons &= ~(1<setUserData(this); - context->setPrintHook(&owlPrintHook); - context->setSendHook(&owlSendHook); - {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if button == False %} - // {{name}} - registerParameter(PARAMETER_{{param}}, HV_NAME_CHANNEL_{{param}}); - {% if defvalue != None %} - setParameterValue(PARAMETER_{{param}}, HV_DEFAULT_CHANNEL_{{param}}); - {% endif %} - {% endfor %} - } - - ~HeavyPatch() { - delete context; - } - - uint16_t getButtonValue(PatchButtonId bid, const HvMessage *m){ - if(hv_msg_getNumElements(m) > 0 && hv_msg_isFloat(m, 0)) - return hv_msg_getFloat(m, 0) > 0.5 ? 4095 : 0; - else - return isButtonPressed(bid) ? 0 : 4095; // toggle - } - - void sendCallback(uint32_t sendHash, const HvMessage *m){ - switch(sendHash){ - case HV_HASH_NOTEOUT: - { - uint8_t note = hv_msg_getFloat(m, 0); - uint8_t velocity = hv_msg_getFloat(m, 1); - uint8_t ch = hv_msg_getFloat(m, 2); - // debugMessage("noteout", note, velocity, ch); - sendMidi(MidiMessage::note(ch, note, velocity)); - } - break; - case HV_HASH_CTLOUT: - { - uint8_t value = hv_msg_getFloat(m, 0); - uint8_t cc = hv_msg_getFloat(m, 1); - uint8_t ch = hv_msg_getFloat(m, 2); - // debugMessage("ctlout", value, cc, ch); - sendMidi(MidiMessage::cc(ch, cc, value)); - } - break; - case HV_HASH_BENDOUT: - { - uint16_t value = hv_msg_getFloat(m, 0); - uint8_t ch = hv_msg_getFloat(m, 1); - // debugMessage("bendout", value, ch); - sendMidi(MidiMessage::pb(ch, value)); - } - break; - case HV_HASH_TOUCHOUT: - sendMidi(MidiMessage::cp((uint8_t)hv_msg_getFloat(m, 1), (uint8_t)hv_msg_getFloat(m, 0))); - break; - case HV_HASH_PGMOUT: - sendMidi(MidiMessage::pc((uint8_t)hv_msg_getFloat(m, 1), (uint8_t)hv_msg_getFloat(m, 0))); - break; - {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if typ == 'SEND'%} - {% if button == True %} - // Button {{name}} - case HV_HASH_{{typ}}_CHANNEL_{{param}}: - setButton(BUTTON_{{param}}, (hv_msg_getFloat(m, 0)-HV_MIN_CHANNEL_{{param}})/ - (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}}) > 0.5); - {% else %} - // Parameter {{name}} - case HV_HASH_{{typ}}_CHANNEL_{{param}}: - setParameterValue(PARAMETER_{{param}}, (hv_msg_getFloat(m, 0)-HV_MIN_CHANNEL_{{param}})/ - (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}})); - {% endif %} - break; - {% endfor %} - default: - break; - } - } - - void processMidi(MidiMessage msg){ - // sendMessageToReceiverV parses format and loops over args, see HeavyContext.cpp - switch(msg.getStatus()){ - case CONTROL_CHANGE: - context->sendMessageToReceiverV - (HV_HASH_CTLIN, 0, "fff", - (float)msg.getControllerValue(), // value - (float)msg.getControllerNumber(), // controller number - (float)msg.getChannel()); - break; - case NOTE_ON: - context->sendMessageToReceiverV - (HV_HASH_NOTEIN, 0, "fff", - (float)msg.getNote(), // pitch - (float)msg.getVelocity(), // velocity - (float)msg.getChannel()); - break; - case NOTE_OFF: - context->sendMessageToReceiverV - (HV_HASH_NOTEIN, 0, "fff", - (float)msg.getNote(), // pitch - 0.0f, // velocity - (float)msg.getChannel()); - break; - case CHANNEL_PRESSURE: - context->sendMessageToReceiverV - (HV_HASH_TOUCHIN, 0, "ff", - (float)msg.getChannelPressure(), - (float)msg.getChannel()); - break; - case PITCH_BEND_CHANGE: - context->sendMessageToReceiverV - (HV_HASH_BENDIN, 0, "ff", - (float)msg.getPitchBend(), - (float)msg.getChannel()); - break; - case PROGRAM_CHANGE: - context->sendMessageToReceiverV - (HV_HASH_PGMIN, 0, "ff", - (float)msg.getProgramChange(), - (float)msg.getChannel()); - break; - default: - break; - } - } - - void buttonChanged(PatchButtonId bid, uint16_t value, uint16_t samples){ - if(_msgLock) - return; - switch(bid){ - {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if typ == 'RECV' and button == True %} - // {{name}} - case BUTTON_{{param}}: - context->sendFloatToReceiver(HV_HASH_{{typ}}_CHANNEL_{{param}}, isButtonPressed(BUTTON_{{param}})* - (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}})+HV_MIN_CHANNEL_{{param}}); - break; - {% endfor %} - default: - break; - } - } - - void processAudio(AudioBuffer &buffer) { - _msgLock = true; - {% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata if typ == 'RECV' and button == False %} - // {{name}} - context->sendFloatToReceiver(HV_HASH_{{typ}}_CHANNEL_{{param}}, getParameterValue(PARAMETER_{{param}})* - (HV_MAX_CHANNEL_{{param}}-HV_MIN_CHANNEL_{{param}})+HV_MIN_CHANNEL_{{param}}); - {% endfor %} - - _msgLock = false; - float* outputs[] = {buffer.getSamples(LEFT_CHANNEL), buffer.getSamples(RIGHT_CHANNEL)}; - context->process(outputs, outputs, getBlockSize()); - } - -private: - HeavyContext* context; -}; - -static void owlSendHook(HeavyContextInterface* ctxt, - const char *receiverName, - uint32_t sendHash, - const HvMessage *m){ - HeavyPatch* patch = (HeavyPatch*)ctxt->getUserData(); - patch->sendCallback(sendHash, m); -} - -#endif // __HeavyPatch_hpp__ diff --git a/Tools/Heavy_owl_constants.tpl.h b/Tools/Heavy_owl_constants.tpl.h deleted file mode 100644 index db938caa..00000000 --- a/Tools/Heavy_owl_constants.tpl.h +++ /dev/null @@ -1,10 +0,0 @@ -{% for param, name, typ, namehash, minvalue, maxvalue, defvalue, button in jdata %} -// {{param}} {{name}} {{typ}} {{namehash}} -#define HV_NAME_CHANNEL_{{param}} "{{name}}" -#define HV_HASH_{{typ}}_CHANNEL_{{param}} {{namehash}} -#define HV_MIN_CHANNEL_{{param}} {{minvalue}} -#define HV_MAX_CHANNEL_{{param}} {{maxvalue}} -{% if defvalue != None %} -#define HV_DEFAULT_CHANNEL_{{param}} {{(defvalue-minvalue)/(maxvalue-minvalue)}} -{% endif %} -{% endfor %} diff --git a/Tools/build_send_receive_constants.py b/Tools/build_send_receive_constants.py deleted file mode 100755 index deef7c42..00000000 --- a/Tools/build_send_receive_constants.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import sys - -import argparse -import json -from collections import OrderedDict as odict - -import os -dir_path = os.path.dirname(os.path.realpath(__file__)) -from hvcc.core.hv2ir import HeavyLangObject - -heavy_hash = HeavyLangObject.HeavyLangObject.get_hash - -import jinja2 - -OWL_BUTTONS = ['Push', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8'] - -def get_template(path): - templateLoader = jinja2.FileSystemLoader(searchpath=dir_path) - templateEnv = jinja2.Environment(loader=templateLoader) - template = templateEnv.get_template(path) - return template - -def main(): - parser = argparse.ArgumentParser( - description="Generates the constants file for send_receive puredata objects.") - - parser.add_argument( - "infilename", - help="Input ir file", - ) - - parser.add_argument( - "outfilename", - help="Output file", - default="Heavy_owl_constants.h" - ) - - args = parser.parse_args() - jdata = list() - - # Read receive and send object data - with open(args.infilename, mode="r") as f: - ir = json.load(f) - - for name, v in ir['control']['receivers'].items(): - # skip __hv_init and similar - if name.startswith("__"): - continue - - # If a name has been specified - if 'owl' in v['attributes'] and v['attributes']['owl'] is not None: - key = v['attributes']['owl'] - jdata.append((key, name, 'RECV', "0x%x" % heavy_hash(name), - v['attributes']['min'], - v['attributes']['max'], - v['attributes']['default'], - key in OWL_BUTTONS)) - - elif name.startswith('Channel-'): - key = name.split('Channel-', 1)[1] - jdata.append((key, name, 'RECV', "0x%x" % heavy_hash(name), - 0, 1, None, key in OWL_BUTTONS)) - - for k, v in ir['objects'].items(): - try: - if v['type'] == '__send': - name = v['args']['name'] - if 'owl' in v['args']['attributes'] and v['args']['attributes']['owl'] is not None: - key = v['args']['attributes']['owl'] - jdata.append((key, name+'>', 'SEND', "0x%x" % heavy_hash(name), - v['args']['attributes']['min'], - v['args']['attributes']['max'], - v['args']['attributes']['default'], - key in OWL_BUTTONS)) - elif name.startswith('Channel-'): - key = name.split('Channel-', 1)[1] - jdata.append((key, name+'>', 'SEND', "0x%x" % heavy_hash(name), - 0, 1, None, key in OWL_BUTTONS)) - except: - pass - - # TODO, check that there is not channel defined both as input and output - - # Write to files - with open(args.outfilename, mode="w") as f: - template = get_template("Heavy_owl_constants.tpl.h") - outputText = template.render(jdata=jdata) # this is where to put args to the template renderer - f.write(outputText) - - HeavyPatchpath = "/".join(args.outfilename.split("/")[:-1]) + '/HeavyPatch.hpp' - with open(HeavyPatchpath, mode="w") as f: - template = get_template("HeavyPatch.tpl.hpp") - outputText = template.render(jdata=jdata) # this is where to put args to the template renderer - f.write(outputText) - -if __name__ == '__main__': - main() diff --git a/Tools/hvcc b/Tools/hvcc deleted file mode 160000 index 548f94c5..00000000 --- a/Tools/hvcc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 548f94c57617a51a2f4cd6bd1643f7291d61dc40 diff --git a/heavy.mk b/heavy.mk index 3ec2367f..4e431cb7 100644 --- a/heavy.mk +++ b/heavy.mk @@ -2,7 +2,7 @@ HEAVYFILE ?= $(HEAVY).pd HEAVYNAME ?= owl HEAVYSRC ?= $(BUILDROOT)/HeavySource HEAVYDIR ?= $(BUILD)/Heavy -HEAVYARGS ?= -g c -n $(HEAVYNAME) -p $(HEAVYDIR) -o $(BUILD) +HEAVYARGS ?= -g owl -n $(HEAVYNAME) -p $(HEAVYDIR) -o $(BUILD) HVCC ?= hvcc HVCC_OWL ?= $(BUILDROOT)/Tools/build_send_receive_constants.py @@ -12,9 +12,6 @@ $(HEAVYDIR)/_main.pd: $(PATCHSOURCE)/$(HEAVYFILE) @cp -f $< $@ $(BUILD)/Source/Heavy_owl.h: $(HEAVYDIR)/_main.pd - @$(HVCC) $(HEAVYDIR)/_main.pd $(HEAVYARGS) - @mv -f $(BUILD)/c/* $(BUILD)/Source - @cp -f $(HEAVYSRC)/HvUtils.h $(HEAVYSRC)/HvMessage.c $(BUILD)/Source - @python3 $(HVCC_OWL) $(BUILD)/ir/owl.heavy.ir.json $(BUILD)/Source/Heavy_$(HEAVYNAME)_constants.h + $(HVCC) $(HEAVYDIR)/_main.pd $(HEAVYARGS) heavy: $(BUILD)/Source/Heavy_owl.h