diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 7d5c1707..20d367aa 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -24,9 +24,9 @@ jobs: with: version: 2.0.10 - name: Setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: - python-version: 2.7 + python-version: 3.9 - name: make run: make - name: make check 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 375efe8d..8dd7ca4c 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 @@ -198,7 +198,7 @@ check: tests ## run test patches and unit tests @cp FaustSource/*.h TestPatches/FaustTest && unset PATCHNAME PATCHCLASS PATCHFILE && $(MAKE) PATCHSOURCE=TestPatches/FaustTest PATCHNAME=Faust clean patch web run # @unset PATCHNAME PATCHCLASS PATCHFILE SOULCLASS SOULFILE SOULHPP && $(MAKE) PATCHSOURCE=TestPatches/SoulTest SOUL=SineSynth clean patch web run # SOUL is not installed for CI @unset PATCHNAME PATCHCLASS PATCHFILE && $(MAKE) PATCHSOURCE=TestPatches/SoulTest PATCHNAME=Soul clean patch web run - @pip install -r Tools/hvcc/requirements.txt && unset PATCHNAME PATCHCLASS PATCHFILE && $(MAKE) PATCHSOURCE=TestPatches/HeavyTest HEAVY=HeavyTest clean patch web run + @pip install hvcc && unset PATCHNAME PATCHCLASS PATCHFILE && $(MAKE) PATCHSOURCE=TestPatches/HeavyTest HEAVY=HeavyTest clean patch web run help: ## show this help @echo 'Usage: make [target] ...' diff --git a/README.md b/README.md index 0b2385bc..198b1a55 100644 --- a/README.md +++ b/README.md @@ -32,18 +32,18 @@ This has been done on a Ubuntu server 18.04 Either install gcc-arm-none-eabi system-wide and ensure the binaries are in your path, or edit OwlProgram/compile.mk and point TOOLROOT to where arm-none-eabi binaries are installed. - TOOLROOT = /usr/bin/ + 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 python python-enum34 python-jinja2 python-nose2 - $ git clone https://github.com/pingdynasty/hvcc.git + $ sudo apt install python3 python3-pip + $ pip3 install hvcc To compile patches in native format (e.g. for testing) you will also need the gcc compiler: $ sudo apt install gcc - -Compile FirmwareSender + +Compile FirmwareSender FirmwareSender makes it possible to use `load` and `store` make targets, or by invoking FirmwareSender directly to load/store a compiled patch to the device using sysex codes. @@ -53,7 +53,7 @@ FirmwareSender makes it possible to use `load` and `store` make targets, or by i $ make $ cp build/FirmwareSender ../../../OwlProgram/Tools $ cd ../../../ - + ## Make targets * make libs: build library archives * make patch: build patch binary @@ -145,7 +145,7 @@ Note: use OWL parameters in Maximilian by adding maxiParam objects to your patch ## Using FirmwareSender -If you prefer to build the patch first and send it later to the device you can +If you prefer to build the patch first and send it later to the device you can do it like this from the main directory of OwlProgram (this will store in slot 6) Tools/FirmwareSender -in ./Build/patch.bin -out "OWL-MIDI*" -store 6 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 0b5c331d..00000000 --- a/Tools/build_send_receive_constants.py +++ /dev/null @@ -1,101 +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__)) -sys.path.append('%s/hvcc' % dir_path) -import core.hv2ir.HeavyLangObject as 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'].iteritems(): - # 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'].iteritems(): - 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 5be25202..83deb916 100644 --- a/heavy.mk +++ b/heavy.mk @@ -1,10 +1,8 @@ HEAVYFILE ?= $(HEAVY).pd HEAVYNAME ?= owl -HEAVYSRC ?= $(BUILDROOT)/HeavySource HEAVYDIR ?= $(BUILD)/Heavy -HEAVYARGS ?= -g c -n $(HEAVYNAME) -p $(HEAVYDIR) -o $(BUILD) -HVCC ?= $(BUILDROOT)/Tools/hvcc/hvcc.py -HVCC_OWL ?= $(BUILDROOT)/Tools/build_send_receive_constants.py +HEAVYARGS ?= -g owl -n $(HEAVYNAME) -p $(HEAVYDIR) -o $(BUILD) +HVCC ?= hvcc $(HEAVYDIR)/_main.pd: $(PATCHSOURCE)/$(HEAVYFILE) @mkdir -p $(HEAVYDIR) @@ -12,9 +10,6 @@ $(HEAVYDIR)/_main.pd: $(PATCHSOURCE)/$(HEAVYFILE) @cp -f $< $@ $(BUILD)/Source/Heavy_owl.h: $(HEAVYDIR)/_main.pd - @python2.7 $(HVCC) $(HEAVYDIR)/_main.pd $(HEAVYARGS) - @mv -f $(BUILD)/c/* $(BUILD)/Source - @cp -f $(HEAVYSRC)/HvUtils.h $(HEAVYSRC)/HvMessage.c $(BUILD)/Source - @python2.7 $(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