test
This commit is contained in:
parent
e986b0955f
commit
25b8a4b489
47
Makefile
Normal file
47
Makefile
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/make -f
|
||||
# Makefile for DISTRHO Plugins #
|
||||
# ---------------------------- #
|
||||
# Created by falkTX
|
||||
#
|
||||
# Modified by Wasted Audio
|
||||
#
|
||||
|
||||
DPFER_PATH = dpf
|
||||
|
||||
include ${DPFER_PATH}/Makefile.base.mk
|
||||
|
||||
all: libs plugin gen
|
||||
|
||||
define MISSING_SUBMODULES_ERROR
|
||||
|
||||
Cannot find DGL! Please run "make submodules" to clone the missing submodules, then retry building the plugin.
|
||||
|
||||
endef
|
||||
|
||||
# --------------------------------------------------------------
|
||||
submodules:
|
||||
git submodule update --init --recursive
|
||||
|
||||
libs:
|
||||
|
||||
plugin: libs
|
||||
$(MAKE) all -C delay_simple/plugin/source
|
||||
|
||||
gen: plugins ${DPFER_PATH}/utils/lv2_ttl_generator
|
||||
@$(CURDIR)/${DPFER_PATH}/utils/generate-ttl.sh
|
||||
ifeq ($(MACOS),true)
|
||||
@$(CURDIR)/${DPFER_PATH}/utils/generate-vst-bundles.sh
|
||||
endif
|
||||
|
||||
dpf/utils/lv2_ttl_generator:
|
||||
$(MAKE) -C ${DPFER_PATH}/utils/lv2-ttl-generator
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
clean:
|
||||
$(MAKE) clean -C ${DPFER_PATH}/utils/lv2-ttl-generator
|
||||
$(MAKE) clean -C plugin/source
|
||||
|
||||
# --------------------------------------------------------------
|
||||
|
||||
.PHONY: plugins
|
||||
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Heavy DPF examples
|
||||
---
|
||||
This repository contains example Heavy wrappers for the Distrho Plugin Format.
|
||||
|
||||
## Audio Effects
|
||||
|
||||
* Delay: Simple
|
||||
* Delay: Advanced #todo
|
||||
* Distortion: Simple #todo
|
||||
* Distortion: Advanced #todo
|
||||
27
delay_simple/README.md
Normal file
27
delay_simple/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Distrho Plugin Format
|
||||
|
||||
This output is for the Distrho Plugin Format ([DPF](https://github.com/DISTRHO/DPF)), and can be used to build LV2, VST2 and jack standalone versions of your Heavy code.
|
||||
|
||||
# Build Instructions
|
||||
|
||||
Make sure you have a (recent) DPF in the root of your output directory
|
||||
|
||||
```bash
|
||||
$ cd <out_dir>
|
||||
$ git clone https://github.com/DISTRHO/DPF.git dpf
|
||||
```
|
||||
|
||||
Then compile the plugins from the source folder:
|
||||
|
||||
```bash
|
||||
$ make
|
||||
```
|
||||
|
||||
This will result in an `bin/` folder with all binary assets.
|
||||
|
||||
* LV2 - move `bin/<plugin>.lv2/` folder to your local `~/.lv2/` dir
|
||||
* VST2 - move `bin/<plugin>-vst.so`, can be placed directly into your `~/.vst/` dir
|
||||
|
||||
## Jack
|
||||
|
||||
The Jack binary can be executed in place and used to test functionality `./bin/<plugin>`. Currently there is no UI, so this is not recommended. You will have to be running jack in order to use this.
|
||||
264
delay_simple/c/HeavyContext.cpp
Normal file
264
delay_simple/c/HeavyContext.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HeavyContext.hpp"
|
||||
#include "HvTable.h"
|
||||
|
||||
void defaultSendHook(HeavyContextInterface *context,
|
||||
const char *sendName, hv_uint32_t sendHash, const HvMessage *msg) {
|
||||
HeavyContext *thisContext = reinterpret_cast<HeavyContext *>(context);
|
||||
const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(msg) - sizeof(HvMessage);
|
||||
ReceiverMessagePair *p = reinterpret_cast<ReceiverMessagePair *>(hLp_getWriteBuffer(&thisContext->outQueue, numBytes));
|
||||
if (p != nullptr) {
|
||||
p->receiverHash = sendHash;
|
||||
msg_copyToBuffer(msg, (char *) &p->msg, msg_getSize(msg));
|
||||
hLp_produce(&thisContext->outQueue, numBytes);
|
||||
} else {
|
||||
hv_assert(false &&
|
||||
"::defaultSendHook - The out message queue is full and cannot accept more messages until they "
|
||||
"have been processed. Try increasing the outQueueKb size in the new_with_options() constructor.");
|
||||
}
|
||||
}
|
||||
|
||||
HeavyContext::HeavyContext(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) :
|
||||
sampleRate(sampleRate) {
|
||||
|
||||
hv_assert(sampleRate > 0.0); // sample rate must be positive
|
||||
hv_assert(poolKb > 0);
|
||||
hv_assert(inQueueKb > 0);
|
||||
hv_assert(outQueueKb >= 0);
|
||||
|
||||
blockStartTimestamp = 0;
|
||||
printHook = nullptr;
|
||||
userData = nullptr;
|
||||
|
||||
// if outQueueKb is positive, then the outQueue is allocated and the default sendhook is set.
|
||||
// Otherwise outQueue and the sendhook are set to NULL.
|
||||
sendHook = (outQueueKb > 0) ? &defaultSendHook : nullptr;
|
||||
|
||||
HV_SPINLOCK_RELEASE(inQueueLock);
|
||||
HV_SPINLOCK_RELEASE(outQueueLock);
|
||||
|
||||
numBytes = sizeof(HeavyContext);
|
||||
|
||||
numBytes += mq_initWithPoolSize(&mq, poolKb);
|
||||
numBytes += hLp_init(&inQueue, inQueueKb * 1024);
|
||||
numBytes += hLp_init(&outQueue, outQueueKb * 1024); // outQueueKb value of 0 sets everything to NULL
|
||||
}
|
||||
|
||||
HeavyContext::~HeavyContext() {
|
||||
mq_free(&mq);
|
||||
hLp_free(&inQueue);
|
||||
hLp_free(&outQueue);
|
||||
}
|
||||
|
||||
bool HeavyContext::sendBangToReceiver(hv_uint32_t receiverHash) {
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithBang(m, 0);
|
||||
bool success = sendMessageToReceiver(receiverHash, 0.0, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendFloatToReceiver(hv_uint32_t receiverHash, float f) {
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(m, 0, f);
|
||||
bool success = sendMessageToReceiver(receiverHash, 0.0, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendSymbolToReceiver(hv_uint32_t receiverHash, const char *s) {
|
||||
hv_assert(s != nullptr);
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithSymbol(m, 0, (char *) s);
|
||||
bool success = sendMessageToReceiver(receiverHash, 0.0, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
|
||||
hv_assert(delayMs >= 0.0);
|
||||
hv_assert(format != nullptr);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int numElem = (int) hv_strlen(format);
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
|
||||
msg_init(m, numElem, blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*getSampleRate()/1000.0));
|
||||
for (int i = 0; i < numElem; i++) {
|
||||
switch (format[i]) {
|
||||
case 'b': msg_setBang(m, i); break;
|
||||
case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
|
||||
case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
|
||||
case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
bool success = sendMessageToReceiver(receiverHash, delayMs, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
|
||||
hv_assert(delayMs >= 0.0);
|
||||
hv_assert(m != nullptr);
|
||||
|
||||
const hv_uint32_t timestamp = blockStartTimestamp +
|
||||
(hv_uint32_t) (hv_max_d(0.0, delayMs)*(getSampleRate()/1000.0));
|
||||
|
||||
ReceiverMessagePair *p = nullptr;
|
||||
HV_SPINLOCK_ACQUIRE(inQueueLock);
|
||||
const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(m) - sizeof(HvMessage);
|
||||
p = (ReceiverMessagePair *) hLp_getWriteBuffer(&inQueue, numBytes);
|
||||
if (p != nullptr) {
|
||||
p->receiverHash = receiverHash;
|
||||
msg_copyToBuffer(m, (char *) &p->msg, msg_getSize(m));
|
||||
msg_setTimestamp(&p->msg, timestamp);
|
||||
hLp_produce(&inQueue, numBytes);
|
||||
} else {
|
||||
hv_assert(false &&
|
||||
"::sendMessageToReceiver - The input message queue is full and cannot accept more messages until they "
|
||||
"have been processed. Try increasing the inQueueKb size in the new_with_options() constructor.");
|
||||
}
|
||||
HV_SPINLOCK_RELEASE(inQueueLock);
|
||||
return (p != nullptr);
|
||||
}
|
||||
|
||||
bool HeavyContext::cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
return mq_removeMessage(&mq, m, sendMessage);
|
||||
}
|
||||
|
||||
HvMessage *HeavyContext::scheduleMessageForObject(const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex) {
|
||||
HvMessage *n = mq_addMessageByTimestamp(&mq, m, letIndex, sendMessage);
|
||||
return n;
|
||||
}
|
||||
|
||||
float *HeavyContext::getBufferForTable(hv_uint32_t tableHash) {
|
||||
HvTable *t = getTableForHash(tableHash);
|
||||
if (t != nullptr) {
|
||||
return hTable_getBuffer(t);
|
||||
} else return nullptr;
|
||||
}
|
||||
|
||||
int HeavyContext::getLengthForTable(hv_uint32_t tableHash) {
|
||||
HvTable *t = getTableForHash(tableHash);
|
||||
if (t != nullptr) {
|
||||
return hTable_getLength(t);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
bool HeavyContext::setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
|
||||
HvTable *t = getTableForHash(tableHash);
|
||||
if (t != nullptr) {
|
||||
hTable_resize(t, newSampleLength);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
void HeavyContext::lockAcquire() {
|
||||
HV_SPINLOCK_ACQUIRE(inQueueLock);
|
||||
}
|
||||
|
||||
bool HeavyContext::lockTry() {
|
||||
HV_SPINLOCK_TRY(inQueueLock);
|
||||
}
|
||||
|
||||
void HeavyContext::lockRelease() {
|
||||
HV_SPINLOCK_RELEASE(inQueueLock);
|
||||
}
|
||||
|
||||
void HeavyContext::setInputMessageQueueSize(int inQueueKb) {
|
||||
hv_assert(inQueueKb > 0);
|
||||
hLp_free(&inQueue);
|
||||
hLp_init(&inQueue, inQueueKb*1024);
|
||||
}
|
||||
|
||||
void HeavyContext::setOutputMessageQueueSize(int outQueueKb) {
|
||||
hv_assert(outQueueKb > 0);
|
||||
hLp_free(&outQueue);
|
||||
hLp_init(&outQueue, outQueueKb*1024);
|
||||
}
|
||||
|
||||
bool HeavyContext::getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) {
|
||||
*destinationHash = 0;
|
||||
ReceiverMessagePair *p = nullptr;
|
||||
hv_assert((sendHook == &defaultSendHook) &&
|
||||
"::getNextSentMessage - this function won't do anything if the msg outQueue "
|
||||
"size is 0, or you've overriden the default sendhook.");
|
||||
if (sendHook == &defaultSendHook) {
|
||||
HV_SPINLOCK_ACQUIRE(outQueueLock);
|
||||
if (hLp_hasData(&outQueue)) {
|
||||
hv_uint32_t numBytes = 0;
|
||||
p = reinterpret_cast<ReceiverMessagePair *>(hLp_getReadBuffer(&outQueue, &numBytes));
|
||||
hv_assert((p != nullptr) && "::getNextSentMessage - something bad happened.");
|
||||
hv_assert(numBytes >= sizeof(ReceiverMessagePair));
|
||||
hv_assert((numBytes <= msgLengthBytes) &&
|
||||
"::getNextSentMessage - the sent message is bigger than the message "
|
||||
"passed to handle it.");
|
||||
*destinationHash = p->receiverHash;
|
||||
hv_memcpy(outMsg, &p->msg, numBytes);
|
||||
hLp_consume(&outQueue);
|
||||
}
|
||||
HV_SPINLOCK_RELEASE(outQueueLock);
|
||||
}
|
||||
return (p != nullptr);
|
||||
}
|
||||
|
||||
hv_uint32_t HeavyContext::getHashForString(const char *str) {
|
||||
return hv_string_to_hash(str);
|
||||
}
|
||||
|
||||
HvTable *_hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return reinterpret_cast<HeavyContext *>(c)->getTableForHash(tableHash);
|
||||
}
|
||||
|
||||
void _hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
|
||||
hv_assert(c != nullptr);
|
||||
reinterpret_cast<HeavyContext *>(c)->scheduleMessageForReceiver(receiverHash, m);
|
||||
}
|
||||
|
||||
HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex) {
|
||||
hv_assert(c != nullptr);
|
||||
HvMessage *n = reinterpret_cast<HeavyContext *>(c)->scheduleMessageForObject(
|
||||
m, sendMessage, letIndex);
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
return _hv_table_get(c, tableHash);
|
||||
}
|
||||
|
||||
void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
|
||||
_hv_scheduleMessageForReceiver(c, receiverHash, m);
|
||||
}
|
||||
|
||||
HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex) {
|
||||
return _hv_scheduleMessageForObject(c, m, sendMessage, letIndex);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
107
delay_simple/c/HeavyContext.hpp
Normal file
107
delay_simple/c/HeavyContext.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTEXT_H_
|
||||
#define _HEAVY_CONTEXT_H_
|
||||
|
||||
#include "HeavyContextInterface.hpp"
|
||||
#include "HvLightPipe.h"
|
||||
#include "HvMessageQueue.h"
|
||||
#include "HvMath.h"
|
||||
|
||||
struct HvTable;
|
||||
|
||||
class HeavyContext : public HeavyContextInterface {
|
||||
|
||||
public:
|
||||
HeavyContext(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
|
||||
virtual ~HeavyContext();
|
||||
|
||||
int getSize() override { return (int) numBytes; }
|
||||
|
||||
double getSampleRate() override { return sampleRate; }
|
||||
|
||||
hv_uint32_t getCurrentSample() override { return blockStartTimestamp; }
|
||||
float samplesToMilliseconds(hv_uint32_t numSamples) override { return (float) (1000.0*numSamples/sampleRate); }
|
||||
hv_uint32_t millisecondsToSamples(float ms) override { return (hv_uint32_t) (hv_max_f(0.0f,ms)*sampleRate/1000.0); }
|
||||
|
||||
void setUserData(void *x) override { userData = x; }
|
||||
void *getUserData() override { return userData; }
|
||||
|
||||
// hook management
|
||||
void setSendHook(HvSendHook_t *f) override { sendHook = f; }
|
||||
HvSendHook_t *getSendHook() override { return sendHook; }
|
||||
|
||||
void setPrintHook(HvPrintHook_t *f) override { printHook = f; }
|
||||
HvPrintHook_t *getPrintHook() override { return printHook; }
|
||||
|
||||
// message scheduling
|
||||
bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) override;
|
||||
bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) override;
|
||||
bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) override;
|
||||
bool sendBangToReceiver(hv_uint32_t receiverHash) override;
|
||||
bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) override;
|
||||
bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) override;
|
||||
|
||||
// table manipulation
|
||||
float *getBufferForTable(hv_uint32_t tableHash) override;
|
||||
int getLengthForTable(hv_uint32_t tableHash) override;
|
||||
bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) override;
|
||||
|
||||
// lock control
|
||||
void lockAcquire() override;
|
||||
bool lockTry() override;
|
||||
void lockRelease() override;
|
||||
|
||||
// message queue management
|
||||
void setInputMessageQueueSize(int inQueueKb) override;
|
||||
void setOutputMessageQueueSize(int outQueueKb) override;
|
||||
bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLength) override;
|
||||
|
||||
// utility functions
|
||||
static hv_uint32_t getHashForString(const char *str);
|
||||
|
||||
protected:
|
||||
virtual HvTable *getTableForHash(hv_uint32_t tableHash) = 0;
|
||||
friend HvTable *_hv_table_get(HeavyContextInterface *, hv_uint32_t);
|
||||
|
||||
virtual void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) = 0;
|
||||
friend void _hv_scheduleMessageForReceiver(HeavyContextInterface *, hv_uint32_t, HvMessage *);
|
||||
|
||||
HvMessage *scheduleMessageForObject(const HvMessage *,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int);
|
||||
friend HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *, const HvMessage *,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int);
|
||||
|
||||
friend void defaultSendHook(HeavyContextInterface *, const char *, hv_uint32_t, const HvMessage *);
|
||||
|
||||
// object state
|
||||
double sampleRate;
|
||||
hv_uint32_t blockStartTimestamp;
|
||||
hv_size_t numBytes;
|
||||
HvMessageQueue mq;
|
||||
HvSendHook_t *sendHook;
|
||||
HvPrintHook_t *printHook;
|
||||
void *userData;
|
||||
HvLightPipe inQueue;
|
||||
HvLightPipe outQueue;
|
||||
hv_atomic_bool inQueueLock;
|
||||
hv_atomic_bool outQueueLock;
|
||||
};
|
||||
|
||||
#endif // _HEAVY_CONTEXT_H_
|
||||
291
delay_simple/c/HeavyContextInterface.hpp
Normal file
291
delay_simple/c/HeavyContextInterface.hpp
Normal file
@ -0,0 +1,291 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTEXT_INTERFACE_H_
|
||||
#define _HEAVY_CONTEXT_INTERFACE_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifndef _HEAVY_DECLARATIONS_
|
||||
#define _HEAVY_DECLARATIONS_
|
||||
|
||||
class HeavyContextInterface;
|
||||
struct HvMessage;
|
||||
|
||||
typedef enum {
|
||||
HV_PARAM_TYPE_PARAMETER_IN,
|
||||
HV_PARAM_TYPE_PARAMETER_OUT,
|
||||
HV_PARAM_TYPE_EVENT_IN,
|
||||
HV_PARAM_TYPE_EVENT_OUT
|
||||
} HvParameterType;
|
||||
|
||||
typedef struct HvParameterInfo {
|
||||
const char *name; // the human readable parameter name
|
||||
hv_uint32_t hash; // an integer identified used by heavy for this parameter
|
||||
HvParameterType type; // type of this parameter
|
||||
float minVal; // the minimum value of this parameter
|
||||
float maxVal; // the maximum value of this parameter
|
||||
float defaultVal; // the default value of this parameter
|
||||
} HvParameterInfo;
|
||||
|
||||
typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
|
||||
typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
|
||||
|
||||
#endif // _HEAVY_DECLARATIONS_
|
||||
|
||||
|
||||
|
||||
class HeavyContextInterface {
|
||||
|
||||
public:
|
||||
HeavyContextInterface() {}
|
||||
virtual ~HeavyContextInterface() {};
|
||||
|
||||
/** Returns the read-only user-assigned name of this patch. */
|
||||
virtual const char *getName() = 0;
|
||||
|
||||
/** Returns the number of input channels with which this context has been configured. */
|
||||
virtual int getNumInputChannels() = 0;
|
||||
|
||||
/** Returns the number of output channels with which this context has been configured. */
|
||||
virtual int getNumOutputChannels() = 0;
|
||||
|
||||
/**
|
||||
* Returns the total size in bytes of the context.
|
||||
* This value may change if tables are resized.
|
||||
*/
|
||||
virtual int getSize() = 0;
|
||||
|
||||
/** Returns the sample rate with which this context has been configured. */
|
||||
virtual double getSampleRate() = 0;
|
||||
|
||||
/** Returns the current patch time in samples. This value is always exact. */
|
||||
virtual hv_uint32_t getCurrentSample() = 0;
|
||||
virtual float samplesToMilliseconds(hv_uint32_t numSamples) = 0;
|
||||
|
||||
/** Converts milliseconds to samples. Input is limited to non-negative range. */
|
||||
virtual hv_uint32_t millisecondsToSamples(float ms) = 0;
|
||||
|
||||
/** Sets a user-definable value. This value is never manipulated by Heavy. */
|
||||
virtual void setUserData(void *x) = 0;
|
||||
|
||||
/** Returns the user-defined data. */
|
||||
virtual void *getUserData() = 0;
|
||||
|
||||
/**
|
||||
* Set the send hook. The function is called whenever a message is sent to any send object.
|
||||
* Messages returned by this function should NEVER be freed. If the message must persist, call
|
||||
* hv_msg_copy() first.
|
||||
*/
|
||||
virtual void setSendHook(HvSendHook_t *f) = 0;
|
||||
|
||||
/** Returns the send hook, or NULL if unset. */
|
||||
virtual HvSendHook_t *getSendHook() = 0;
|
||||
|
||||
/** Set the print hook. The function is called whenever a message is sent to a print object. */
|
||||
virtual void setPrintHook(HvPrintHook_t *f) = 0;
|
||||
|
||||
/** Returns the print hook, or NULL if unset. */
|
||||
virtual HvPrintHook_t *getPrintHook() = 0;
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [[LLLL][RRRR]]
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
virtual int process(float **inputBuffers, float **outputBuffer, int n) = 0;
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LLLLRRRR]
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
virtual int processInline(float *inputBuffers, float *outputBuffer, int n) = 0;
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LRLRLRLR]
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
virtual int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) = 0;
|
||||
|
||||
/**
|
||||
* Sends a formatted message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) = 0;
|
||||
|
||||
/**
|
||||
* Sends a formatted message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* A convenience function to send a float to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) = 0;
|
||||
|
||||
/**
|
||||
* A convenience function to send a bang to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendBangToReceiver(hv_uint32_t receiverHash) = 0;
|
||||
|
||||
/**
|
||||
* A convenience function to send a symbol to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) = 0;
|
||||
|
||||
/**
|
||||
* Cancels a previously scheduled message.
|
||||
*
|
||||
* @param sendMessage May be NULL.
|
||||
*/
|
||||
virtual bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)=nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Returns information about each parameter such as name, hash, and range.
|
||||
* The total number of parameters is always returned.
|
||||
*
|
||||
* @param index The parameter index.
|
||||
* @param info A pointer to a HvParameterInfo struct. May be null.
|
||||
*
|
||||
* @return The total number of parameters.
|
||||
*/
|
||||
virtual int getParameterInfo(int index, HvParameterInfo *info) = 0;
|
||||
|
||||
/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
|
||||
virtual float *getBufferForTable(hv_uint32_t tableHash) = 0;
|
||||
|
||||
/** Returns the length of this table in samples. */
|
||||
virtual int getLengthForTable(hv_uint32_t tableHash) = 0;
|
||||
|
||||
/**
|
||||
* Resizes the table to the given length.
|
||||
*
|
||||
* Existing contents are copied to the new table. Remaining space is cleared
|
||||
* if the table is longer than the original, truncated otherwise.
|
||||
*
|
||||
* @param tableHash The table identifier.
|
||||
* @param newSampleLength The new length of the table, in samples.
|
||||
*
|
||||
* @return False if the table could not be found. True otherwise.
|
||||
*/
|
||||
virtual bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) = 0;
|
||||
|
||||
/**
|
||||
* Acquire the input message queue lock.
|
||||
*
|
||||
* This function will block until the message lock as been acquired.
|
||||
* Typical applications will not require the use of this function.
|
||||
*/
|
||||
virtual void lockAcquire() = 0;
|
||||
|
||||
/**
|
||||
* Try to acquire the input message queue lock.
|
||||
*
|
||||
* If the lock has been acquired, hv_lock_release() must be called to release it.
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @return Returns true if the lock has been acquired, false otherwise.
|
||||
*/
|
||||
virtual bool lockTry() = 0;
|
||||
|
||||
/**
|
||||
* Release the input message queue lock.
|
||||
*
|
||||
* Typical applications will not require the use of this function.
|
||||
*/
|
||||
virtual void lockRelease() = 0;
|
||||
|
||||
/**
|
||||
* Set the size of the input message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
*
|
||||
* @param inQueueKb Must be positive i.e. at least one.
|
||||
*/
|
||||
virtual void setInputMessageQueueSize(int inQueueKb) = 0;
|
||||
|
||||
/**
|
||||
* Set the size of the output message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
* Only the default sendhook uses the outgoing message queue. If the default
|
||||
* sendhook is not being used, then this function is not useful.
|
||||
*
|
||||
* @param outQueueKb Must be postive i.e. at least one.
|
||||
*/
|
||||
virtual void setOutputMessageQueueSize(int outQueueKb) = 0;
|
||||
|
||||
/**
|
||||
* Get the next message in the outgoing queue, will also consume the message.
|
||||
* Returns false if there are no messages.
|
||||
*
|
||||
* @param destinationHash a hash of the name of the receiver the message was sent to.
|
||||
* @param outMsg message pointer that is filled by the next message contents.
|
||||
* @param msgLengthBytes max length of outMsg in bytes.
|
||||
*
|
||||
* @return True if there is a message in the outgoing queue.
|
||||
*/
|
||||
virtual bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) = 0;
|
||||
|
||||
/** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
|
||||
static hv_uint32_t getHashForString(const char *str);
|
||||
};
|
||||
|
||||
#endif // _HEAVY_CONTEXT_INTERFACE_H_
|
||||
659
delay_simple/c/Heavy_delay_simple.cpp
Normal file
659
delay_simple/c/Heavy_delay_simple.cpp
Normal file
@ -0,0 +1,659 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Heavy_delay_simple.hpp"
|
||||
|
||||
#include <new>
|
||||
|
||||
#define Context(_c) static_cast<Heavy_delay_simple *>(_c)
|
||||
|
||||
|
||||
/*
|
||||
* C Functions
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
HV_EXPORT HeavyContextInterface *hv_delay_simple_new(double sampleRate) {
|
||||
// allocate aligned memory
|
||||
void *ptr = hv_malloc(sizeof(Heavy_delay_simple));
|
||||
// ensure non-null
|
||||
if (!ptr) return nullptr;
|
||||
// call constructor
|
||||
new(ptr) Heavy_delay_simple(sampleRate);
|
||||
return Context(ptr);
|
||||
}
|
||||
|
||||
HV_EXPORT HeavyContextInterface *hv_delay_simple_new_with_options(double sampleRate,
|
||||
int poolKb, int inQueueKb, int outQueueKb) {
|
||||
// allocate aligned memory
|
||||
void *ptr = hv_malloc(sizeof(Heavy_delay_simple));
|
||||
// ensure non-null
|
||||
if (!ptr) return nullptr;
|
||||
// call constructor
|
||||
new(ptr) Heavy_delay_simple(sampleRate, poolKb, inQueueKb, outQueueKb);
|
||||
return Context(ptr);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_delay_simple_free(HeavyContextInterface *instance) {
|
||||
// call destructor
|
||||
Context(instance)->~Heavy_delay_simple();
|
||||
// free memory
|
||||
hv_free(instance);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Class Functions
|
||||
*/
|
||||
|
||||
Heavy_delay_simple::Heavy_delay_simple(double sampleRate, int poolKb, int inQueueKb, int outQueueKb)
|
||||
: HeavyContext(sampleRate, poolKb, inQueueKb, outQueueKb) {
|
||||
numBytes += sTabread_init(&sTabread_OJVVdLuf, &hTable_TFqOKFso, true);
|
||||
numBytes += sTabwrite_init(&sTabwrite_kTfJPrs1, &hTable_TFqOKFso);
|
||||
numBytes += cVar_init_f(&cVar_4cpXTaBY, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_fRPZcVCt, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_Om7ifKfd, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_LnHfGF8V, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_mOyup5ir, 0.0f);
|
||||
numBytes += cDelay_init(this, &cDelay_OFD5iAqe, 0.0f);
|
||||
numBytes += cDelay_init(this, &cDelay_EI4kKdvf, 0.0f);
|
||||
numBytes += hTable_init(&hTable_TFqOKFso, 256);
|
||||
numBytes += cTabhead_init(&cTabhead_zhu6BFdy, &hTable_TFqOKFso);
|
||||
numBytes += cVar_init_s(&cVar_nONxuBGP, "del-delay1012");
|
||||
numBytes += cDelay_init(this, &cDelay_FTWI9Lbr, 0.0f);
|
||||
numBytes += cDelay_init(this, &cDelay_4Y58Ksfn, 0.0f);
|
||||
numBytes += cBinop_init(&cBinop_kd9uMvnd, 0.0f); // __mul
|
||||
numBytes += cBinop_init(&cBinop_99kJjPmN, 0.0f); // __sub
|
||||
numBytes += cBinop_init(&cBinop_khIQbSXe, 0.0f); // __max
|
||||
numBytes += cBinop_init(&cBinop_HsqyfMPx, 0.0f); // __sub
|
||||
numBytes += sVarf_init(&sVarf_DXN3F4mN, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_o7lB6W7R, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_4RDRwlaL, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_vL8TEPN9, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_eLw9NCKn, 0.0f, 0.0f, false);
|
||||
|
||||
// schedule a message to trigger all loadbangs via the __hv_init receiver
|
||||
scheduleMessageForReceiver(0xCE5CC65B, msg_initWithBang(HV_MESSAGE_ON_STACK(1), 0));
|
||||
}
|
||||
|
||||
Heavy_delay_simple::~Heavy_delay_simple() {
|
||||
hTable_free(&hTable_TFqOKFso);
|
||||
}
|
||||
|
||||
HvTable *Heavy_delay_simple::getTableForHash(hv_uint32_t tableHash) {switch (tableHash) {
|
||||
case 0x4678FF81: return &hTable_TFqOKFso; // del-delay1012
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) {
|
||||
switch (receiverHash) {
|
||||
case 0x36377AA9: { // Delay_Feedback
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_LQwqfjMo_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xEE78D101: { // Delay_Time
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_UQL9KHRi_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0x5EFB46D2: { // Dry_Volume
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_SIoX2X2C_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0x677821DA: { // Gain
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_eGza5oBR_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xEA49B5A: { // Wet_Volume
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_ex2b75Oc_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xCE5CC65B: { // __hv_init
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_AJBhI0kX_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xD8A3CB65: { // dfeed1
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_iG7Q7Uzr_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xAEFD47D3: { // dryvol
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_kJYDDgog_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0x37BBAC62: { // dtime1
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_kE9u8lIG_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xCA9AE94A: { // dvol1
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_pzAN0z6v_sendMessage);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
int Heavy_delay_simple::getParameterInfo(int index, HvParameterInfo *info) {
|
||||
if (info != nullptr) {
|
||||
switch (index) {
|
||||
case 0: {
|
||||
info->name = "Delay_Feedback";
|
||||
info->hash = 0x36377AA9;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.25f;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
info->name = "Delay_Time";
|
||||
info->hash = 0xEE78D101;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 5000.0f;
|
||||
info->defaultVal = 500.0f;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
info->name = "Dry_Volume";
|
||||
info->hash = 0x5EFB46D2;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.75f;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
info->name = "Gain";
|
||||
info->hash = 0x677821DA;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.75f;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
info->name = "Wet_Volume";
|
||||
info->hash = 0xEA49B5A;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.75f;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
info->name = "invalid parameter index";
|
||||
info->hash = 0;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 0.0f;
|
||||
info->defaultVal = 0.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Send Function Implementations
|
||||
*/
|
||||
|
||||
|
||||
void Heavy_delay_simple::cVar_4cpXTaBY_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_wldZJDJM_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_fRPZcVCt_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_dFhbvIPr_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_Om7ifKfd_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_4A35hG1G_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_LnHfGF8V_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_eLw9NCKn, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_mOyup5ir_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_jiugLxbD_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_hdrV3jKk_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "samplerate");
|
||||
cSystem_onMessage(_c, NULL, 0, m, &cSystem_B288dglo_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSystem_B288dglo_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_DIVIDE, 1000.0f, 0, m, &cBinop_NAf7xjjy_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_OFD5iAqe_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_OFD5iAqe, m);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_EI4kKdvf, 0, m, &cDelay_EI4kKdvf_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_OFD5iAqe, 0, m, &cDelay_OFD5iAqe_sendMessage);
|
||||
sTabwrite_onMessage(_c, &Context(_c)->sTabwrite_kTfJPrs1, 1, m, NULL);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_EI4kKdvf_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_EI4kKdvf, m);
|
||||
cMsg_o1Fk4mWr_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_4MyuHNhK_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_clwxczYs_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::hTable_TFqOKFso_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_DlDeZMFB_sendMessage(_c, 0, m);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_OFD5iAqe, 2, m, &cDelay_OFD5iAqe_sendMessage);
|
||||
cCast_onMessage(_c, HV_CAST_BANG, 0, m, &cCast_g87DeymK_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_clwxczYs_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(2);
|
||||
msg_init(m, 2, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "resize");
|
||||
msg_setElementToFrom(m, 1, n, 0);
|
||||
hTable_onMessage(_c, &Context(_c)->hTable_TFqOKFso, 0, m, &hTable_TFqOKFso_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_NAf7xjjy_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_MULTIPLY, 5000.0f, 0, m, &cBinop_4MyuHNhK_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_o1Fk4mWr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "mirror");
|
||||
hTable_onMessage(_c, &Context(_c)->hTable_TFqOKFso, 0, m, &hTable_TFqOKFso_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cCast_g87DeymK_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_OFD5iAqe, 0, m, &cDelay_OFD5iAqe_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_DlDeZMFB_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setFloat(m, 0, static_cast<float>(HV_N_SIMD));
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_EI4kKdvf, 2, m, &cDelay_EI4kKdvf_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cTabhead_zhu6BFdy_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_99kJjPmN, HV_BINOP_SUBTRACT, 0, m, &cBinop_99kJjPmN_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_c68iDIVD_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "samplerate");
|
||||
cSystem_onMessage(_c, NULL, 0, m, &cSystem_LlBI3RTT_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSystem_LlBI3RTT_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_DIVIDE, 1000.0f, 0, m, &cBinop_qp875S9R_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_nONxuBGP_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_2Y6gSDxh_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_FTWI9Lbr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_FTWI9Lbr, m);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 0, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
sTabread_onMessage(_c, &Context(_c)->sTabread_OJVVdLuf, 0, m, &sTabread_OJVVdLuf_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_4Y58Ksfn_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_4Y58Ksfn, m);
|
||||
sTabread_onMessage(_c, &Context(_c)->sTabread_OJVVdLuf, 0, m, &sTabread_OJVVdLuf_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 0, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::sTabread_OJVVdLuf_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_HsqyfMPx, HV_BINOP_SUBTRACT, 0, m, &cBinop_HsqyfMPx_sendMessage);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_kd9uMvnd_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_khIQbSXe, HV_BINOP_MAX, 0, m, &cBinop_khIQbSXe_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_qp875S9R_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_kd9uMvnd, HV_BINOP_MULTIPLY, 0, m, &cBinop_kd9uMvnd_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_99kJjPmN_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_60hMCcpx_sendMessage(_c, 0, m);
|
||||
sTabread_onMessage(_c, &Context(_c)->sTabread_OJVVdLuf, 0, m, &sTabread_OJVVdLuf_sendMessage);
|
||||
cCast_onMessage(_c, HV_CAST_BANG, 0, m, &cCast_zoAHkSwC_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSystem_kPqFOU4H_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_HsqyfMPx, HV_BINOP_SUBTRACT, 1, m, &cBinop_HsqyfMPx_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 2, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_2Y6gSDxh_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(3);
|
||||
msg_init(m, 3, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "table");
|
||||
msg_setElementToFrom(m, 1, n, 0);
|
||||
msg_setSymbol(m, 2, "size");
|
||||
cSystem_onMessage(_c, NULL, 0, m, &cSystem_kPqFOU4H_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_60hMCcpx_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "clear");
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_FTWI9Lbr, 0, m, &cDelay_FTWI9Lbr_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 0, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_2y7SxePc_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setFloat(m, 0, static_cast<float>(HV_N_SIMD));
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_khIQbSXe, HV_BINOP_MAX, 1, m, &cBinop_khIQbSXe_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_khIQbSXe_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_99kJjPmN, HV_BINOP_SUBTRACT, 1, m, &cBinop_99kJjPmN_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cCast_zoAHkSwC_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_FTWI9Lbr, 0, m, &cDelay_FTWI9Lbr_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_H69XkGIL_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_FTWI9Lbr, 2, m, &cDelay_FTWI9Lbr_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_HsqyfMPx_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_MULTIPLY, -1.0f, 0, m, &cBinop_H69XkGIL_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cCast_spzeS2Y3_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_nONxuBGP, 0, m, &cVar_nONxuBGP_sendMessage);
|
||||
cMsg_c68iDIVD_sendMessage(_c, 0, m);
|
||||
cTabhead_onMessage(_c, &Context(_c)->cTabhead_zhu6BFdy, 0, m, &cTabhead_zhu6BFdy_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_wldZJDJM_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_kE9u8lIG_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_dFhbvIPr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_pzAN0z6v_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_4A35hG1G_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_iG7Q7Uzr_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_jiugLxbD_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_kJYDDgog_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_kE9u8lIG_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_kd9uMvnd, HV_BINOP_MULTIPLY, 1, m, &cBinop_kd9uMvnd_sendMessage);
|
||||
cCast_onMessage(_c, HV_CAST_BANG, 0, m, &cCast_spzeS2Y3_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_pzAN0z6v_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_o7lB6W7R, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_iG7Q7Uzr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_4RDRwlaL, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_kJYDDgog_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_vL8TEPN9, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_AJBhI0kX_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_hdrV3jKk_sendMessage(_c, 0, m);
|
||||
cMsg_2y7SxePc_sendMessage(_c, 0, m);
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_nONxuBGP, 0, m, &cVar_nONxuBGP_sendMessage);
|
||||
cMsg_c68iDIVD_sendMessage(_c, 0, m);
|
||||
cTabhead_onMessage(_c, &Context(_c)->cTabhead_zhu6BFdy, 0, m, &cTabhead_zhu6BFdy_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_eGza5oBR_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_LnHfGF8V, 0, m, &cVar_LnHfGF8V_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_SIoX2X2C_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_mOyup5ir, 0, m, &cVar_mOyup5ir_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_UQL9KHRi_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_4cpXTaBY, 0, m, &cVar_4cpXTaBY_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_ex2b75Oc_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_fRPZcVCt, 0, m, &cVar_fRPZcVCt_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_LQwqfjMo_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_Om7ifKfd, 0, m, &cVar_Om7ifKfd_sendMessage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Context Process Implementation
|
||||
*/
|
||||
|
||||
int Heavy_delay_simple::process(float **inputBuffers, float **outputBuffers, int n) {
|
||||
while (hLp_hasData(&inQueue)) {
|
||||
hv_uint32_t numBytes = 0;
|
||||
ReceiverMessagePair *p = reinterpret_cast<ReceiverMessagePair *>(hLp_getReadBuffer(&inQueue, &numBytes));
|
||||
hv_assert(numBytes >= sizeof(ReceiverMessagePair));
|
||||
scheduleMessageForReceiver(p->receiverHash, &p->msg);
|
||||
hLp_consume(&inQueue);
|
||||
}
|
||||
const int n4 = n & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD
|
||||
|
||||
// temporary signal vars
|
||||
hv_bufferf_t Bf0, Bf1, Bf2, Bf3;
|
||||
|
||||
// input and output vars
|
||||
hv_bufferf_t O0, O1;
|
||||
hv_bufferf_t I0, I1;
|
||||
|
||||
// declare and init the zero buffer
|
||||
hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO));
|
||||
|
||||
hv_uint32_t nextBlock = blockStartTimestamp;
|
||||
for (int n = 0; n < n4; n += HV_N_SIMD) {
|
||||
|
||||
// process all of the messages for this block
|
||||
nextBlock += HV_N_SIMD;
|
||||
while (mq_hasMessageBefore(&mq, nextBlock)) {
|
||||
MessageNode *const node = mq_peek(&mq);
|
||||
node->sendMessage(this, node->let, node->m);
|
||||
mq_pop(&mq);
|
||||
}
|
||||
|
||||
// load input buffers
|
||||
__hv_load_f(inputBuffers[0]+n, VOf(I0));
|
||||
__hv_load_f(inputBuffers[1]+n, VOf(I1));
|
||||
|
||||
// zero output buffers
|
||||
__hv_zero_f(VOf(O0));
|
||||
__hv_zero_f(VOf(O1));
|
||||
|
||||
// process all signal functions
|
||||
__hv_add_f(VIf(I0), VIf(I1), VOf(Bf0));
|
||||
__hv_varread_f(&sVarf_eLw9NCKn, VOf(Bf1));
|
||||
__hv_mul_f(VIf(Bf0), VIf(Bf1), VOf(Bf1));
|
||||
__hv_tabread_f(&sTabread_OJVVdLuf, VOf(Bf0));
|
||||
__hv_varread_f(&sVarf_o7lB6W7R, VOf(Bf2));
|
||||
__hv_varread_f(&sVarf_vL8TEPN9, VOf(Bf3));
|
||||
__hv_mul_f(VIf(Bf1), VIf(Bf3), VOf(Bf3));
|
||||
__hv_fma_f(VIf(Bf0), VIf(Bf2), VIf(Bf3), VOf(Bf3));
|
||||
__hv_varread_f(&sVarf_DXN3F4mN, VOf(Bf2));
|
||||
__hv_add_f(VIf(Bf1), VIf(Bf2), VOf(Bf2));
|
||||
__hv_tabwrite_f(&sTabwrite_kTfJPrs1, VIf(Bf2));
|
||||
__hv_varread_f(&sVarf_4RDRwlaL, VOf(Bf2));
|
||||
__hv_mul_f(VIf(Bf0), VIf(Bf2), VOf(Bf2));
|
||||
__hv_varwrite_f(&sVarf_DXN3F4mN, VIf(Bf2));
|
||||
__hv_add_f(VIf(Bf3), VIf(O0), VOf(O0));
|
||||
__hv_add_f(VIf(Bf3), VIf(O1), VOf(O1));
|
||||
|
||||
// save output vars to output buffer
|
||||
__hv_store_f(outputBuffers[0]+n, VIf(O0));
|
||||
__hv_store_f(outputBuffers[1]+n, VIf(O1));
|
||||
}
|
||||
|
||||
blockStartTimestamp = nextBlock;
|
||||
|
||||
return n4; // return the number of frames processed
|
||||
}
|
||||
|
||||
int Heavy_delay_simple::processInline(float *inputBuffers, float *outputBuffers, int n4) {
|
||||
hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD
|
||||
|
||||
// define the heavy input buffer for 2 channel(s)
|
||||
float **const bIn = reinterpret_cast<float **>(hv_alloca(2*sizeof(float *)));
|
||||
bIn[0] = inputBuffers+(0*n4);
|
||||
bIn[1] = inputBuffers+(1*n4);
|
||||
|
||||
// define the heavy output buffer for 2 channel(s)
|
||||
float **const bOut = reinterpret_cast<float **>(hv_alloca(2*sizeof(float *)));
|
||||
bOut[0] = outputBuffers+(0*n4);
|
||||
bOut[1] = outputBuffers+(1*n4);
|
||||
|
||||
int n = process(bIn, bOut, n4);
|
||||
return n;
|
||||
}
|
||||
|
||||
int Heavy_delay_simple::processInlineInterleaved(float *inputBuffers, float *outputBuffers, int n4) {
|
||||
hv_assert(n4 & ~HV_N_SIMD_MASK); // ensure that n4 is a multiple of HV_N_SIMD
|
||||
|
||||
// define the heavy input buffer for 2 channel(s), uninterleave
|
||||
float *const bIn = reinterpret_cast<float *>(hv_alloca(2*n4*sizeof(float)));
|
||||
#if HV_SIMD_SSE || HV_SIMD_AVX
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
__m128 a = _mm_load_ps(inputBuffers+i); // LRLR
|
||||
__m128 b = _mm_load_ps(inputBuffers+4+i); // LRLR
|
||||
__m128 x = _mm_shuffle_ps(a, b, _MM_SHUFFLE(2,0,2,0)); // LLLL
|
||||
__m128 y = _mm_shuffle_ps(a, b, _MM_SHUFFLE(3,1,3,1)); // RRRR
|
||||
_mm_store_ps(bIn+j, x);
|
||||
_mm_store_ps(bIn+n4+j, y);
|
||||
}
|
||||
#elif HV_SIMD_NEON
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
float32x4x2_t a = vld2q_f32(inputBuffers+i); // load and uninterleave
|
||||
vst1q_f32(bIn+j, a.val[0]);
|
||||
vst1q_f32(bIn+n4+j, a.val[1]);
|
||||
}
|
||||
#else // HV_SIMD_NONE
|
||||
for (int j = 0; j < n4; ++j) {
|
||||
bIn[0*n4+j] = inputBuffers[0+2*j];
|
||||
bIn[1*n4+j] = inputBuffers[1+2*j];
|
||||
}
|
||||
#endif
|
||||
|
||||
// define the heavy output buffer for 2 channel(s)
|
||||
float *const bOut = reinterpret_cast<float *>(hv_alloca(2*n4*sizeof(float)));
|
||||
|
||||
int n = processInline(bIn, bOut, n4);
|
||||
|
||||
// interleave the heavy output into the output buffer
|
||||
#if HV_SIMD_AVX
|
||||
for (int i = 0, j = 0; j < n4; j += 8, i += 16) {
|
||||
__m256 x = _mm256_load_ps(bOut+j); // LLLLLLLL
|
||||
__m256 y = _mm256_load_ps(bOut+n4+j); // RRRRRRRR
|
||||
__m256 a = _mm256_unpacklo_ps(x, y); // LRLRLRLR
|
||||
__m256 b = _mm256_unpackhi_ps(x, y); // LRLRLRLR
|
||||
_mm256_store_ps(outputBuffers+i, a);
|
||||
_mm256_store_ps(outputBuffers+8+i, b);
|
||||
}
|
||||
#elif HV_SIMD_SSE
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
__m128 x = _mm_load_ps(bOut+j); // LLLL
|
||||
__m128 y = _mm_load_ps(bOut+n4+j); // RRRR
|
||||
__m128 a = _mm_unpacklo_ps(x, y); // LRLR
|
||||
__m128 b = _mm_unpackhi_ps(x, y); // LRLR
|
||||
_mm_store_ps(outputBuffers+i, a);
|
||||
_mm_store_ps(outputBuffers+4+i, b);
|
||||
}
|
||||
#elif HV_SIMD_NEON
|
||||
// https://community.arm.com/groups/processors/blog/2012/03/13/coding-for-neon--part-5-rearranging-vectors
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
float32x4_t x = vld1q_f32(bOut+j);
|
||||
float32x4_t y = vld1q_f32(bOut+n4+j);
|
||||
float32x4x2_t z = {x, y};
|
||||
vst2q_f32(outputBuffers+i, z); // interleave and store
|
||||
}
|
||||
#else // HV_SIMD_NONE
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < n4; ++j) {
|
||||
outputBuffers[i+2*j] = bOut[i*n4+j];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
85
delay_simple/c/Heavy_delay_simple.h
Normal file
85
delay_simple/c/Heavy_delay_simple.h
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HEAVY_DELAY_SIMPLE_H_
|
||||
#define _HEAVY_DELAY_SIMPLE_H_
|
||||
|
||||
#include "HvHeavy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Context
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
HV_DELAY_SIMPLE_PARAM_IN_DELAY_FEEDBACK = 0x36377AA9, // Delay_Feedback
|
||||
HV_DELAY_SIMPLE_PARAM_IN_DELAY_TIME = 0xEE78D101, // Delay_Time
|
||||
HV_DELAY_SIMPLE_PARAM_IN_DRY_VOLUME = 0x5EFB46D2, // Dry_Volume
|
||||
HV_DELAY_SIMPLE_PARAM_IN_GAIN = 0x677821DA, // Gain
|
||||
HV_DELAY_SIMPLE_PARAM_IN_WET_VOLUME = 0xEA49B5A, // Wet_Volume
|
||||
} Hv_delay_simple_ParameterIn;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new patch instance.
|
||||
* Sample rate should be positive and in Hertz, e.g. 44100.0.
|
||||
*/
|
||||
HeavyContextInterface *hv_delay_simple_new(double sampleRate);
|
||||
|
||||
/**
|
||||
* Creates a new patch instance.
|
||||
* @param sampleRate Sample rate should be positive (> 0) and in Hertz, e.g. 48000.0.
|
||||
* @param poolKb Pool size is in kilobytes, and determines the maximum amount of memory
|
||||
* allocated to messages at any time. By default this is 10 KB.
|
||||
* @param inQueueKb The size of the input message queue in kilobytes. It determines the
|
||||
* amount of memory dedicated to holding scheduled messages between calls to
|
||||
* process(). Default is 2 KB.
|
||||
* @param outQueueKb The size of the output message queue in kilobytes. It determines the
|
||||
* amount of memory dedicated to holding scheduled messages to the default sendHook.
|
||||
* See getNextSentMessage() for info on accessing these messages. Default is 0 KB.
|
||||
*/
|
||||
HeavyContextInterface *hv_delay_simple_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb);
|
||||
|
||||
/**
|
||||
* Free the patch instance.
|
||||
*/
|
||||
void hv_delay_simple_free(HeavyContextInterface *instance);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_DELAY_SIMPLE_H_
|
||||
162
delay_simple/c/Heavy_delay_simple.hpp
Normal file
162
delay_simple/c/Heavy_delay_simple.hpp
Normal file
@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HEAVY_CONTEXT_DELAY_SIMPLE_HPP_
|
||||
#define _HEAVY_CONTEXT_DELAY_SIMPLE_HPP_
|
||||
|
||||
// object includes
|
||||
#include "HeavyContext.hpp"
|
||||
#include "HvControlTabhead.h"
|
||||
#include "HvSignalVar.h"
|
||||
#include "HvTable.h"
|
||||
#include "HvControlBinop.h"
|
||||
#include "HvSignalTabwrite.h"
|
||||
#include "HvControlDelay.h"
|
||||
#include "HvMath.h"
|
||||
#include "HvSignalTabread.h"
|
||||
#include "HvControlSystem.h"
|
||||
#include "HvControlVar.h"
|
||||
#include "HvControlCast.h"
|
||||
|
||||
class Heavy_delay_simple : public HeavyContext {
|
||||
|
||||
public:
|
||||
Heavy_delay_simple(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
|
||||
~Heavy_delay_simple();
|
||||
|
||||
const char *getName() override { return "delay_simple"; }
|
||||
int getNumInputChannels() override { return 2; }
|
||||
int getNumOutputChannels() override { return 2; }
|
||||
|
||||
int process(float **inputBuffers, float **outputBuffer, int n) override;
|
||||
int processInline(float *inputBuffers, float *outputBuffer, int n) override;
|
||||
int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) override;
|
||||
|
||||
int getParameterInfo(int index, HvParameterInfo *info) override;
|
||||
struct Parameter {
|
||||
struct In {
|
||||
enum ParameterIn : hv_uint32_t {
|
||||
DELAY_FEEDBACK = 0x36377AA9, // Delay_Feedback
|
||||
DELAY_TIME = 0xEE78D101, // Delay_Time
|
||||
DRY_VOLUME = 0x5EFB46D2, // Dry_Volume
|
||||
GAIN = 0x677821DA, // Gain
|
||||
WET_VOLUME = 0xEA49B5A, // Wet_Volume
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
private:
|
||||
HvTable *getTableForHash(hv_uint32_t tableHash) override;
|
||||
void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) override;
|
||||
|
||||
// static sendMessage functions
|
||||
static void cVar_4cpXTaBY_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_fRPZcVCt_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_Om7ifKfd_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_LnHfGF8V_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_mOyup5ir_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_hdrV3jKk_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSystem_B288dglo_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_OFD5iAqe_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_EI4kKdvf_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_4MyuHNhK_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void hTable_TFqOKFso_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_clwxczYs_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_NAf7xjjy_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_o1Fk4mWr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cCast_g87DeymK_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_DlDeZMFB_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cTabhead_zhu6BFdy_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_c68iDIVD_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSystem_LlBI3RTT_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_nONxuBGP_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_FTWI9Lbr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_4Y58Ksfn_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void sTabread_OJVVdLuf_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_kd9uMvnd_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_qp875S9R_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_99kJjPmN_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSystem_kPqFOU4H_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_2Y6gSDxh_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_60hMCcpx_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_2y7SxePc_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_khIQbSXe_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cCast_zoAHkSwC_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_H69XkGIL_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_HsqyfMPx_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cCast_spzeS2Y3_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_wldZJDJM_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_dFhbvIPr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_4A35hG1G_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_jiugLxbD_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_kE9u8lIG_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_pzAN0z6v_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_iG7Q7Uzr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_kJYDDgog_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_AJBhI0kX_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_eGza5oBR_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_SIoX2X2C_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_UQL9KHRi_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_ex2b75Oc_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_LQwqfjMo_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
|
||||
// objects
|
||||
SignalTabread sTabread_OJVVdLuf;
|
||||
SignalTabwrite sTabwrite_kTfJPrs1;
|
||||
ControlVar cVar_4cpXTaBY;
|
||||
ControlVar cVar_fRPZcVCt;
|
||||
ControlVar cVar_Om7ifKfd;
|
||||
ControlVar cVar_LnHfGF8V;
|
||||
ControlVar cVar_mOyup5ir;
|
||||
ControlDelay cDelay_OFD5iAqe;
|
||||
ControlDelay cDelay_EI4kKdvf;
|
||||
ControlBinop cBinop_4MyuHNhK;
|
||||
HvTable hTable_TFqOKFso;
|
||||
ControlBinop cBinop_NAf7xjjy;
|
||||
ControlTabhead cTabhead_zhu6BFdy;
|
||||
ControlVar cVar_nONxuBGP;
|
||||
ControlDelay cDelay_FTWI9Lbr;
|
||||
ControlDelay cDelay_4Y58Ksfn;
|
||||
ControlBinop cBinop_kd9uMvnd;
|
||||
ControlBinop cBinop_qp875S9R;
|
||||
ControlBinop cBinop_99kJjPmN;
|
||||
ControlBinop cBinop_khIQbSXe;
|
||||
ControlBinop cBinop_H69XkGIL;
|
||||
ControlBinop cBinop_HsqyfMPx;
|
||||
SignalVarf sVarf_DXN3F4mN;
|
||||
SignalVarf sVarf_o7lB6W7R;
|
||||
SignalVarf sVarf_4RDRwlaL;
|
||||
SignalVarf sVarf_vL8TEPN9;
|
||||
SignalVarf sVarf_eLw9NCKn;
|
||||
};
|
||||
|
||||
#endif // _HEAVY_CONTEXT_DELAY_SIMPLE_HPP_
|
||||
100
delay_simple/c/HvControlBinop.c
Normal file
100
delay_simple/c/HvControlBinop.c
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlBinop.h"
|
||||
|
||||
hv_size_t cBinop_init(ControlBinop *o, float k) {
|
||||
o->k = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float cBinop_perform_op(BinopType op, float f, float k) {
|
||||
switch (op) {
|
||||
case HV_BINOP_ADD: return f + k;
|
||||
case HV_BINOP_SUBTRACT: return f - k;
|
||||
case HV_BINOP_MULTIPLY: return f * k;
|
||||
case HV_BINOP_DIVIDE: return (k != 0.0f) ? (f/k) : 0.0f;
|
||||
case HV_BINOP_INT_DIV: {
|
||||
const int ik = (int) k;
|
||||
return (ik != 0) ? (float) (((int) f) / ik) : 0.0f;
|
||||
}
|
||||
case HV_BINOP_MOD_BIPOLAR: {
|
||||
const int ik = (int) k;
|
||||
return (ik != 0) ? (float) (((int) f) % ik) : 0.0f;
|
||||
}
|
||||
case HV_BINOP_MOD_UNIPOLAR: {
|
||||
f = (k == 0.0f) ? 0.0f : (float) ((int) f % (int) k);
|
||||
return (f < 0.0f) ? f + hv_abs_f(k) : f;
|
||||
}
|
||||
case HV_BINOP_BIT_LEFTSHIFT: return (float) (((int) f) << ((int) k));
|
||||
case HV_BINOP_BIT_RIGHTSHIFT: return (float) (((int) f) >> ((int) k));
|
||||
case HV_BINOP_BIT_AND: return (float) ((int) f & (int) k);
|
||||
case HV_BINOP_BIT_XOR: return (float) ((int) f ^ (int) k);
|
||||
case HV_BINOP_BIT_OR: return (float) ((int) f | (int) k);
|
||||
case HV_BINOP_EQ: return (f == k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_NEQ: return (f != k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_LOGICAL_AND: return ((f == 0.0f) || (k == 0.0f)) ? 0.0f : 1.0f;
|
||||
case HV_BINOP_LOGICAL_OR: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : 1.0f;
|
||||
case HV_BINOP_LESS_THAN: return (f < k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_LESS_THAN_EQL: return (f <= k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_GREATER_THAN: return (f > k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_GREATER_THAN_EQL: return (f >= k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_MAX: return hv_max_f(f, k);
|
||||
case HV_BINOP_MIN: return hv_min_f(f, k);
|
||||
case HV_BINOP_POW: return (f > 0.0f) ? hv_pow_f(f, k) : 0.0f;
|
||||
case HV_BINOP_ATAN2: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : hv_atan2_f(f, k);
|
||||
default: return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void cBinop_onMessage(HeavyContextInterface *_c, ControlBinop *o, BinopType op, int letIn,
|
||||
const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
// Note(joe): supporting Pd's ability to perform operations of packs
|
||||
// of floats is likely to not be supported in the future.
|
||||
if (msg_isFloat(m, 1)) o->k = msg_getFloat(m, 1);
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
float f = cBinop_perform_op(op, msg_getFloat(m, 0), o->k);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), f);
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
o->k = msg_getFloat(m, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void cBinop_k_onMessage(HeavyContextInterface *_c, void *o, BinopType op, float k,
|
||||
int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
// NOTE(mhroth): Heavy does not support sending bangs to binop objects to return the previous output
|
||||
float f = (msg_isFloat(m, 1)) ? msg_getFloat(m, 1) : k;
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
f = cBinop_perform_op(op, msg_getFloat(m, 0), f);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), f);
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
}
|
||||
71
delay_simple/c/HvControlBinop.h
Normal file
71
delay_simple/c/HvControlBinop.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_BINOP_H_
|
||||
#define _HEAVY_CONTROL_BINOP_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum BinopType {
|
||||
HV_BINOP_ADD,
|
||||
HV_BINOP_SUBTRACT,
|
||||
HV_BINOP_MULTIPLY,
|
||||
HV_BINOP_DIVIDE,
|
||||
HV_BINOP_INT_DIV,
|
||||
HV_BINOP_MOD_BIPOLAR,
|
||||
HV_BINOP_MOD_UNIPOLAR,
|
||||
HV_BINOP_BIT_LEFTSHIFT,
|
||||
HV_BINOP_BIT_RIGHTSHIFT,
|
||||
HV_BINOP_BIT_AND,
|
||||
HV_BINOP_BIT_XOR,
|
||||
HV_BINOP_BIT_OR,
|
||||
HV_BINOP_EQ,
|
||||
HV_BINOP_NEQ,
|
||||
HV_BINOP_LOGICAL_AND,
|
||||
HV_BINOP_LOGICAL_OR,
|
||||
HV_BINOP_LESS_THAN,
|
||||
HV_BINOP_LESS_THAN_EQL,
|
||||
HV_BINOP_GREATER_THAN,
|
||||
HV_BINOP_GREATER_THAN_EQL,
|
||||
HV_BINOP_MAX,
|
||||
HV_BINOP_MIN,
|
||||
HV_BINOP_POW,
|
||||
HV_BINOP_ATAN2
|
||||
} BinopType;
|
||||
|
||||
typedef struct ControlBinop {
|
||||
float k;
|
||||
} ControlBinop;
|
||||
|
||||
hv_size_t cBinop_init(ControlBinop *o, float k);
|
||||
|
||||
void cBinop_onMessage(HeavyContextInterface *_c, ControlBinop *o, BinopType op, int letIn,
|
||||
const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
void cBinop_k_onMessage(HeavyContextInterface *_c, void *o, BinopType op, float k,
|
||||
int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_BINOP_H_
|
||||
60
delay_simple/c/HvControlCast.c
Normal file
60
delay_simple/c/HvControlCast.c
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlCast.h"
|
||||
|
||||
void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (castType) {
|
||||
case HV_CAST_BANG: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithBang(n, msg_getTimestamp(m));
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_CAST_FLOAT: {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), msg_getFloat(m, 0));
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HV_CAST_SYMBOL: {
|
||||
switch (msg_getType(m, 0)) {
|
||||
case HV_MSG_BANG: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithSymbol(n, msg_getTimestamp(m), "bang");
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_FLOAT: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithSymbol(n, msg_getTimestamp(m), "float");
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL: {
|
||||
sendMessage(_c, 0, m);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
39
delay_simple/c/HvControlCast.h
Normal file
39
delay_simple/c/HvControlCast.h
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_CAST_H_
|
||||
#define _HEAVY_CONTROL_CAST_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum CastType {
|
||||
HV_CAST_BANG,
|
||||
HV_CAST_FLOAT,
|
||||
HV_CAST_SYMBOL
|
||||
} CastType;
|
||||
|
||||
void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_CAST_H_
|
||||
92
delay_simple/c/HvControlDelay.c
Normal file
92
delay_simple/c/HvControlDelay.c
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlDelay.h"
|
||||
|
||||
hv_size_t cDelay_init(HeavyContextInterface *_c, ControlDelay *o, float delayMs) {
|
||||
o->delay = hv_millisecondsToSamples(_c, delayMs);
|
||||
hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cDelay_onMessage(HeavyContextInterface *_c, ControlDelay *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (msg_compareSymbol(m, 0, "flush")) {
|
||||
// send all messages immediately
|
||||
for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) {
|
||||
HvMessage *n = o->msgs[i];
|
||||
if (n != NULL) {
|
||||
msg_setTimestamp(n, msg_getTimestamp(m)); // update the timestamp to now
|
||||
sendMessage(_c, 0, n); // send the message
|
||||
hv_cancelMessage(_c, n, sendMessage); // then clear it
|
||||
// NOTE(mhroth): there may be a problem here if a flushed message causes a clear message to return
|
||||
// to this object in the same step
|
||||
}
|
||||
}
|
||||
hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *));
|
||||
} else if (msg_compareSymbol(m, 0, "clear")) {
|
||||
// cancel (clear) all (pending) messages
|
||||
for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) {
|
||||
HvMessage *n = o->msgs[i];
|
||||
if (n != NULL) {
|
||||
hv_cancelMessage(_c, n, sendMessage);
|
||||
}
|
||||
}
|
||||
hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *));
|
||||
} else {
|
||||
hv_uint32_t ts = msg_getTimestamp(m);
|
||||
msg_setTimestamp((HvMessage *) m, ts+o->delay); // update the timestamp to set the delay
|
||||
int i;
|
||||
for (i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) {
|
||||
if (o->msgs[i] == NULL) {
|
||||
o->msgs[i] = hv_scheduleMessageForObject(_c, m, sendMessage, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hv_assert((i < __HV_DELAY_MAX_MESSAGES) && // scheduled message limit reached
|
||||
"[__delay] cannot track any more messages. Try increasing the size of __HV_DELAY_MAX_MESSAGES.");
|
||||
msg_setTimestamp((HvMessage *) m, ts); // return to the original timestamp
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isFloat(m,0)) {
|
||||
// set delay in milliseconds (cannot be negative!)
|
||||
o->delay = hv_millisecondsToSamples(_c, msg_getFloat(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
if (msg_isFloat(m,0)) {
|
||||
// set delay in samples (cannot be negative!)
|
||||
o->delay = (hv_uint32_t) hv_max_f(0.0f, msg_getFloat(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void cDelay_clearExecutingMessage(ControlDelay *o, const HvMessage *m) {
|
||||
for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; ++i) {
|
||||
if (o->msgs[i] == m) {
|
||||
o->msgs[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
delay_simple/c/HvControlDelay.h
Normal file
44
delay_simple/c/HvControlDelay.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_DELAY_H_
|
||||
#define _HEAVY_CONTROL_DELAY_H_
|
||||
|
||||
#define __HV_DELAY_MAX_MESSAGES 8
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ControlDelay {
|
||||
hv_uint32_t delay; // delay in samples
|
||||
HvMessage *msgs[__HV_DELAY_MAX_MESSAGES];
|
||||
} ControlDelay;
|
||||
|
||||
hv_size_t cDelay_init(HeavyContextInterface *_c, ControlDelay *o, float delayMs);
|
||||
|
||||
void cDelay_onMessage(HeavyContextInterface *_c, ControlDelay *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
void cDelay_clearExecutingMessage(ControlDelay *o, const HvMessage *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_DELAY_H_
|
||||
46
delay_simple/c/HvControlSystem.c
Normal file
46
delay_simple/c/HvControlSystem.c
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlSystem.h"
|
||||
|
||||
void cSystem_onMessage(HeavyContextInterface *_c, void *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
if (msg_compareSymbol(m, 0, "samplerate")) {
|
||||
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getSampleRate(_c));
|
||||
} else if (msg_compareSymbol(m, 0, "numInputChannels")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getNumInputChannels(_c));
|
||||
} else if (msg_compareSymbol(m, 0, "numOutputChannels")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getNumOutputChannels(_c));
|
||||
} else if (msg_compareSymbol(m, 0, "currentTime")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) msg_getTimestamp(m));
|
||||
} else if (msg_compareSymbol(m, 0, "table")) {
|
||||
// NOTE(mhroth): no need to check message format for symbols as table lookup will fail otherwise
|
||||
HvTable *table = hv_table_get(_c, msg_getHash(m,1));
|
||||
if (table != NULL) {
|
||||
if (msg_compareSymbol(m, 2, "length")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getLength(table));
|
||||
} else if (msg_compareSymbol(m, 2, "size")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(table));
|
||||
} else if (msg_compareSymbol(m, 2, "head")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(table));
|
||||
} else return;
|
||||
} else return;
|
||||
} else return;
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
33
delay_simple/c/HvControlSystem.h
Normal file
33
delay_simple/c/HvControlSystem.h
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_SYSTEM_H_
|
||||
#define _HEAVY_CONTROL_SYSTEM_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cSystem_onMessage(HeavyContextInterface *_c, void *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_SYSTEM_H_
|
||||
45
delay_simple/c/HvControlTabhead.c
Normal file
45
delay_simple/c/HvControlTabhead.c
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlTabhead.h"
|
||||
|
||||
hv_size_t cTabhead_init(ControlTabhead *o, HvTable *table) {
|
||||
o->table = table;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cTabhead_onMessage(HeavyContextInterface *_c, ControlTabhead *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (msg_getType(m,0) == HV_MSG_BANG) {
|
||||
// get current head of table
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(o->table));
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
// set a new table
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
39
delay_simple/c/HvControlTabhead.h
Normal file
39
delay_simple/c/HvControlTabhead.h
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_TABHEAD_H_
|
||||
#define _HEAVY_CONTROL_TABHEAD_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ControlTabhead {
|
||||
struct HvTable *table;
|
||||
} ControlTabhead;
|
||||
|
||||
hv_size_t cTabhead_init(ControlTabhead *o, struct HvTable *table);
|
||||
|
||||
void cTabhead_onMessage(HeavyContextInterface *_c, ControlTabhead *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_TABHEAD_H_
|
||||
83
delay_simple/c/HvControlVar.c
Normal file
83
delay_simple/c/HvControlVar.c
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlVar.h"
|
||||
|
||||
hv_size_t cVar_init_f(ControlVar *o, float k) {
|
||||
o->e.type = HV_MSG_FLOAT;
|
||||
o->e.data.f = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hv_size_t cVar_init_s(ControlVar *o, const char *s) {
|
||||
o->e.type = HV_MSG_HASH;
|
||||
o->e.data.h = hv_string_to_hash(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cVar_free(ControlVar *o) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void cVar_onMessage(HeavyContextInterface *_c, ControlVar *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_BANG: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
if (o->e.type == HV_MSG_FLOAT) msg_initWithFloat(n, msg_getTimestamp(m), o->e.data.f);
|
||||
else if (o->e.type == HV_MSG_HASH) msg_initWithHash(n, msg_getTimestamp(m), o->e.data.h);
|
||||
else return;
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_FLOAT: {
|
||||
o->e.type = HV_MSG_FLOAT;
|
||||
o->e.data.f = msg_getFloat(m,0);
|
||||
sendMessage(_c, 0, m);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL:
|
||||
case HV_MSG_HASH: {
|
||||
o->e.type = HV_MSG_HASH;
|
||||
o->e.data.h = msg_getHash(m,0);
|
||||
sendMessage(_c, 0, m);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_FLOAT: {
|
||||
o->e.type = HV_MSG_FLOAT;
|
||||
o->e.data.f = msg_getFloat(m,0);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL:
|
||||
case HV_MSG_HASH: {
|
||||
o->e.type = HV_MSG_HASH;
|
||||
o->e.data.h = msg_getHash(m,0);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
43
delay_simple/c/HvControlVar.h
Normal file
43
delay_simple/c/HvControlVar.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_VAR_H_
|
||||
#define _HEAVY_CONTROL_VAR_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ControlVar {
|
||||
Element e; // type is only every HV_MSG_FLOAT or HV_MSG_HASH
|
||||
} ControlVar;
|
||||
|
||||
hv_size_t cVar_init_f(ControlVar *o, float k);
|
||||
|
||||
hv_size_t cVar_init_s(ControlVar *o, const char *s);
|
||||
|
||||
void cVar_free(ControlVar *o);
|
||||
|
||||
void cVar_onMessage(HeavyContextInterface *_c, ControlVar *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_VAR_H_
|
||||
318
delay_simple/c/HvHeavy.cpp
Normal file
318
delay_simple/c/HvHeavy.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HeavyContext.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Table
|
||||
#endif
|
||||
|
||||
HV_EXPORT bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->setLengthForTable(tableHash, newSampleLength);
|
||||
}
|
||||
|
||||
HV_EXPORT float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getBufferForTable(tableHash);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getLengthForTable(tableHash);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Message
|
||||
#endif
|
||||
|
||||
HV_EXPORT hv_size_t hv_msg_getByteSize(hv_uint32_t numElements) {
|
||||
return msg_getCoreSize(numElements);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) {
|
||||
msg_init(m, numElements, timestamp);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_size_t hv_msg_getNumElements(const HvMessage *m) {
|
||||
return msg_getNumElements(m);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *m) {
|
||||
return msg_getTimestamp(m);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
|
||||
msg_setTimestamp(m, timestamp);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i) {
|
||||
return msg_isBang(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setBang(HvMessage *m, int i) {
|
||||
msg_setBang(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i) {
|
||||
return msg_isFloat(m, i);
|
||||
}
|
||||
|
||||
HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i) {
|
||||
return msg_getFloat(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f) {
|
||||
msg_setFloat(m,i,f);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i) {
|
||||
return msg_isSymbol(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT const char *hv_msg_getSymbol(const HvMessage *const m, int i) {
|
||||
return msg_getSymbol(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s) {
|
||||
msg_setSymbol(m,i,s);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i) {
|
||||
return msg_isHash(m, i);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i) {
|
||||
return msg_getHash(m, i);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) {
|
||||
return msg_hasFormat(m, fmt);
|
||||
}
|
||||
|
||||
HV_EXPORT char *hv_msg_toString(const HvMessage *const m) {
|
||||
return msg_toString(m);
|
||||
}
|
||||
|
||||
HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m) {
|
||||
return msg_copy(m);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_free(HvMessage *m) {
|
||||
msg_free(m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Common
|
||||
#endif
|
||||
|
||||
HV_EXPORT int hv_getSize(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return (int) c->getSize();
|
||||
}
|
||||
|
||||
HV_EXPORT double hv_getSampleRate(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getSampleRate();
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_getNumInputChannels(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getNumInputChannels();
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_getNumOutputChannels(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getNumOutputChannels();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setPrintHook(f);
|
||||
}
|
||||
|
||||
HV_EXPORT HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getPrintHook();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setSendHook(f);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_stringToHash(const char *s) {
|
||||
return hv_string_to_hash(s);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendBangToReceiver(receiverHash);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, float x) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendFloatToReceiver(receiverHash, x);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendSymbolToReceiver(receiverHash, s);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendMessageToReceiverV(
|
||||
HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
|
||||
hv_assert(c != nullptr);
|
||||
hv_assert(delayMs >= 0.0);
|
||||
hv_assert(format != nullptr);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int numElem = (int) hv_strlen(format);
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
|
||||
msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0));
|
||||
for (int i = 0; i < numElem; i++) {
|
||||
switch (format[i]) {
|
||||
case 'b': msg_setBang(m, i); break;
|
||||
case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
|
||||
case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
|
||||
case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return c->sendMessageToReceiver(receiverHash, delayMs, m);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendMessageToReceiver(
|
||||
HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendMessageToReceiver(receiverHash, delayMs, m);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
hv_assert(c != nullptr);
|
||||
c->cancelMessage(m, sendMessage);
|
||||
}
|
||||
|
||||
HV_EXPORT const char *hv_getName(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getName();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setUserData(HeavyContextInterface *c, void *userData) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setUserData(userData);
|
||||
}
|
||||
|
||||
HV_EXPORT void *hv_getUserData(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getUserData();
|
||||
}
|
||||
|
||||
HV_EXPORT double hv_getCurrentTime(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return (double) c->samplesToMilliseconds(c->getCurrentSample());
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getCurrentSample();
|
||||
}
|
||||
|
||||
HV_EXPORT float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->samplesToMilliseconds(numSamples);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->millisecondsToSamples(ms);
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getParameterInfo(index, info);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_lock_acquire(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
c->lockAcquire();
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_lock_try(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->lockTry();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_lock_release(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
c->lockRelease();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setInputMessageQueueSize(inQueueKb);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setOutputMessageQueueSize(outQueueKb);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength) {
|
||||
hv_assert(c != nullptr);
|
||||
hv_assert(destinationHash != nullptr);
|
||||
hv_assert(outMsg != nullptr);
|
||||
return c->getNextSentMessage(destinationHash, outMsg, msgLength);
|
||||
}
|
||||
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Common
|
||||
#endif
|
||||
|
||||
HV_EXPORT int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->process(inputBuffers, outputBuffers, n);
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->processInline(inputBuffers, outputBuffers, n);
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->processInlineInterleaved(inputBuffers, outputBuffers, n);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_delete(HeavyContextInterface *c) {
|
||||
delete c;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
413
delay_simple/c/HvHeavy.h
Normal file
413
delay_simple/c/HvHeavy.h
Normal file
@ -0,0 +1,413 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_H_
|
||||
#define _HEAVY_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _HEAVY_DECLARATIONS_
|
||||
#define _HEAVY_DECLARATIONS_
|
||||
|
||||
#ifdef __cplusplus
|
||||
class HeavyContextInterface;
|
||||
#else
|
||||
typedef struct HeavyContextInterface HeavyContextInterface;
|
||||
#endif
|
||||
|
||||
typedef struct HvMessage HvMessage;
|
||||
|
||||
typedef enum {
|
||||
HV_PARAM_TYPE_PARAMETER_IN,
|
||||
HV_PARAM_TYPE_PARAMETER_OUT,
|
||||
HV_PARAM_TYPE_EVENT_IN,
|
||||
HV_PARAM_TYPE_EVENT_OUT
|
||||
} HvParameterType;
|
||||
|
||||
typedef struct HvParameterInfo {
|
||||
const char *name; // the human readable parameter name
|
||||
hv_uint32_t hash; // an integer identified used by heavy for this parameter
|
||||
HvParameterType type; // type of this parameter
|
||||
float minVal; // the minimum value of this parameter
|
||||
float maxVal; // the maximum value of this parameter
|
||||
float defaultVal; // the default value of this parameter
|
||||
} HvParameterInfo;
|
||||
|
||||
typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
|
||||
typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
|
||||
|
||||
#endif // _HEAVY_DECLARATIONS_
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Context
|
||||
#endif
|
||||
|
||||
/** Deletes a patch instance. */
|
||||
void hv_delete(HeavyContextInterface *c);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Process
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [[LLLL][RRRR]]
|
||||
* This function support in-place processing.
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n);
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LLLLRRRR]
|
||||
* This function support in-place processing.
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LRLRLRLR]
|
||||
* This function support in-place processing.
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Common
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the total size in bytes of the context.
|
||||
* This value may change if tables are resized.
|
||||
*/
|
||||
int hv_getSize(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the sample rate with which this context has been configured. */
|
||||
double hv_getSampleRate(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the number of input channels with which this context has been configured. */
|
||||
int hv_getNumInputChannels(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the number of output channels with which this context has been configured. */
|
||||
int hv_getNumOutputChannels(HeavyContextInterface *c);
|
||||
|
||||
/** Set the print hook. The function is called whenever a message is sent to a print object. */
|
||||
void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f);
|
||||
|
||||
/** Returns the print hook, or NULL. */
|
||||
HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Set the send hook. The function is called whenever a message is sent to any send object.
|
||||
* Messages returned by this function should NEVER be freed. If the message must persist, call
|
||||
* hv_msg_copy() first.
|
||||
*/
|
||||
void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f);
|
||||
|
||||
/** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
|
||||
hv_uint32_t hv_stringToHash(const char *s);
|
||||
|
||||
/**
|
||||
* A convenience function to send a bang to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash);
|
||||
|
||||
/**
|
||||
* A convenience function to send a float to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, const float x);
|
||||
|
||||
/**
|
||||
* A convenience function to send a symbol to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s);
|
||||
|
||||
/**
|
||||
* Sends a formatted message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendMessageToReceiverV(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...);
|
||||
|
||||
/**
|
||||
* Sends a message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendMessageToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m);
|
||||
|
||||
/**
|
||||
* Cancels a previously scheduled message.
|
||||
*
|
||||
* @param sendMessage May be NULL.
|
||||
*/
|
||||
void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Returns the read-only user-assigned name of this patch. */
|
||||
const char *hv_getName(HeavyContextInterface *c);
|
||||
|
||||
/** Sets a user-definable value. This value is never manipulated by Heavy. */
|
||||
void hv_setUserData(HeavyContextInterface *c, void *userData);
|
||||
|
||||
/** Returns the user-defined data. */
|
||||
void *hv_getUserData(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the current patch time in milliseconds. This value may have rounding errors. */
|
||||
double hv_getCurrentTime(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the current patch time in samples. This value is always exact. */
|
||||
hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Returns information about each parameter such as name, hash, and range.
|
||||
* The total number of parameters is always returned.
|
||||
*
|
||||
* @param index The parameter index.
|
||||
* @param info A pointer to a HvParameterInfo struct. May be null.
|
||||
*
|
||||
* @return The total number of parameters.
|
||||
*/
|
||||
int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info);
|
||||
|
||||
/** */
|
||||
float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples);
|
||||
|
||||
/** Converts milliseconds to samples. Input is limited to non-negative range. */
|
||||
hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms);
|
||||
|
||||
/**
|
||||
* Acquire the input message queue lock.
|
||||
*
|
||||
* This function will block until the message lock as been acquired.
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
*/
|
||||
void hv_lock_acquire(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Try to acquire the input message queue lock.
|
||||
*
|
||||
* If the lock has been acquired, hv_lock_release() must be called to release it.
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
*
|
||||
* @return Returns true if the lock has been acquired, false otherwise.
|
||||
*/
|
||||
bool hv_lock_try(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Release the input message queue lock.
|
||||
*
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
*/
|
||||
void hv_lock_release(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Set the size of the input message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
* @param inQueueKb Must be positive i.e. at least one.
|
||||
*/
|
||||
void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb);
|
||||
|
||||
/**
|
||||
* Set the size of the output message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
* Only the default sendhook uses the outgoing message queue. If the default
|
||||
* sendhook is not being used, then this function is not useful.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
* @param outQueueKb Must be postive i.e. at least one.
|
||||
*/
|
||||
void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb);
|
||||
|
||||
/**
|
||||
* Get the next message in the outgoing queue, will also consume the message.
|
||||
* Returns false if there are no messages.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
* @param destinationHash a hash of the name of the receiver the message was sent to.
|
||||
* @param outMsg message pointer that is filled by the next message contents.
|
||||
* @param msgLength length of outMsg in bytes.
|
||||
*
|
||||
* @return True if there is a message in the outgoing queue.
|
||||
*/
|
||||
bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Message
|
||||
#endif
|
||||
|
||||
typedef struct HvMessage HvMessage;
|
||||
|
||||
/** Returns the total size in bytes of a HvMessage with a number of elements on the heap. */
|
||||
unsigned long hv_msg_getByteSize(hv_uint32_t numElements);
|
||||
|
||||
/** Initialise a HvMessage structure with the number of elements and a timestamp (in samples). */
|
||||
void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp);
|
||||
|
||||
/** Returns the number of elements in this message. */
|
||||
unsigned long hv_msg_getNumElements(const HvMessage *m);
|
||||
|
||||
/** Returns the time at which this message exists (in samples). */
|
||||
hv_uint32_t hv_msg_getTimestamp(const HvMessage *m);
|
||||
|
||||
/** Set the time at which this message should be executed (in samples). */
|
||||
void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp);
|
||||
|
||||
/** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isBang(const HvMessage *const m, int i);
|
||||
|
||||
/** Sets the indexed element to a bang. Index is not bounds checked. */
|
||||
void hv_msg_setBang(HvMessage *m, int i);
|
||||
|
||||
/** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isFloat(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns the indexed element as a float value. Index is not bounds checked. */
|
||||
float hv_msg_getFloat(const HvMessage *const m, int i);
|
||||
|
||||
/** Sets the indexed element to float value. Index is not bounds checked. */
|
||||
void hv_msg_setFloat(HvMessage *m, int i, float f);
|
||||
|
||||
/** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isSymbol(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns the indexed element as a symbol value. Index is not bounds checked. */
|
||||
const char *hv_msg_getSymbol(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isHash(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns the indexed element as a hash value. Index is not bounds checked. */
|
||||
hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i);
|
||||
|
||||
/** Sets the indexed element to symbol value. Index is not bounds checked. */
|
||||
void hv_msg_setSymbol(HvMessage *m, int i, const char *s);
|
||||
|
||||
/**
|
||||
* Returns true if the message has the given format, in number of elements and type. False otherwise.
|
||||
* Valid element types are:
|
||||
* 'b': bang
|
||||
* 'f': float
|
||||
* 's': symbol
|
||||
*
|
||||
* For example, a message with three floats would have a format of "fff". A single bang is "b".
|
||||
* A message with two symbols is "ss". These types can be mixed and matched in any way.
|
||||
*/
|
||||
bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt);
|
||||
|
||||
/**
|
||||
* Returns a basic string representation of the message.
|
||||
* The character array MUST be deallocated by the caller.
|
||||
*/
|
||||
char *hv_msg_toString(const HvMessage *const m);
|
||||
|
||||
/** Copy a message onto the stack. The message persists. */
|
||||
HvMessage *hv_msg_copy(const HvMessage *const m);
|
||||
|
||||
/** Free a copied message. */
|
||||
void hv_msg_free(HvMessage *m);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Table
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Resizes the table to the given length.
|
||||
*
|
||||
* Existing contents are copied to the new table. Remaining space is cleared
|
||||
* if the table is longer than the original, truncated otherwise.
|
||||
*
|
||||
* @param tableHash The table identifier.
|
||||
* @param newSampleLength The new length of the table, in samples. Must be positive.
|
||||
*
|
||||
* @return False if the table could not be found. True otherwise.
|
||||
*/
|
||||
bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength);
|
||||
|
||||
/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
|
||||
float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash);
|
||||
|
||||
/** Returns the length of this table in samples. */
|
||||
hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_H_
|
||||
51
delay_simple/c/HvHeavyInternal.h
Normal file
51
delay_simple/c/HvHeavyInternal.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_INTERNAL_H_
|
||||
#define _HEAVY_INTERNAL_H_
|
||||
|
||||
#include "HvHeavy.h"
|
||||
#include "HvUtils.h"
|
||||
#include "HvTable.h"
|
||||
#include "HvMessage.h"
|
||||
#include "HvMath.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
136
delay_simple/c/HvLightPipe.c
Normal file
136
delay_simple/c/HvLightPipe.c
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvLightPipe.h"
|
||||
|
||||
#if __SSE__ || HV_SIMD_SSE
|
||||
#include <xmmintrin.h>
|
||||
#define hv_sfence() _mm_sfence()
|
||||
#elif __arm__ || HV_SIMD_NEON
|
||||
#if __ARM_ACLE
|
||||
#include <arm_acle.h>
|
||||
// https://msdn.microsoft.com/en-us/library/hh875058.aspx#BarrierRestrictions
|
||||
// http://doxygen.reactos.org/d8/d47/armintr_8h_a02be7ec76ca51842bc90d9b466b54752.html
|
||||
#define hv_sfence() __dmb(0xE) /* _ARM_BARRIER_ST */
|
||||
#elif defined(__GNUC__)
|
||||
#define hv_sfence() __asm__ volatile ("dmb 0xE":::"memory")
|
||||
#else
|
||||
// http://stackoverflow.com/questions/19965076/gcc-memory-barrier-sync-synchronize-vs-asm-volatile-memory
|
||||
#define hv_sfence() __sync_synchronize()
|
||||
#endif
|
||||
#elif HV_WIN
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208(v=vs.85).aspx
|
||||
#define hv_sfence() _WriteBarrier()
|
||||
#else
|
||||
#define hv_sfence() __asm__ volatile("" : : : "memory")
|
||||
#endif
|
||||
|
||||
#define HLP_STOP 0
|
||||
#define HLP_LOOP 0xFFFFFFFF
|
||||
#define HLP_SET_UINT32_AT_BUFFER(a, b) (*((hv_uint32_t *) (a)) = (b))
|
||||
#define HLP_GET_UINT32_AT_BUFFER(a) (*((hv_uint32_t *) (a)))
|
||||
|
||||
hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes) {
|
||||
if (numBytes > 0) {
|
||||
q->buffer = (char *) hv_malloc(numBytes);
|
||||
hv_assert(q->buffer != NULL);
|
||||
HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
|
||||
} else {
|
||||
q->buffer = NULL;
|
||||
}
|
||||
q->writeHead = q->buffer;
|
||||
q->readHead = q->buffer;
|
||||
q->len = numBytes;
|
||||
q->remainingBytes = numBytes;
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
void hLp_free(HvLightPipe *q) {
|
||||
hv_free(q->buffer);
|
||||
}
|
||||
|
||||
hv_uint32_t hLp_hasData(HvLightPipe *q) {
|
||||
hv_uint32_t x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
if (x == HLP_LOOP) {
|
||||
q->readHead = q->buffer;
|
||||
x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t bytesToWrite) {
|
||||
char *const readHead = q->readHead;
|
||||
char *const oldWriteHead = q->writeHead;
|
||||
const hv_uint32_t totalByteRequirement = bytesToWrite + 2*sizeof(hv_uint32_t);
|
||||
|
||||
// check if there is enough space to write the data in the remaining
|
||||
// length of the buffer
|
||||
if (totalByteRequirement <= q->remainingBytes) {
|
||||
char *const newWriteHead = oldWriteHead + sizeof(hv_uint32_t) + bytesToWrite;
|
||||
|
||||
// check if writing would overwrite existing data in the pipe (return NULL if so)
|
||||
if ((oldWriteHead < readHead) && (newWriteHead >= readHead)) return NULL;
|
||||
else return (oldWriteHead + sizeof(hv_uint32_t));
|
||||
} else {
|
||||
// there isn't enough space, try looping around to the start
|
||||
if (totalByteRequirement <= q->len) {
|
||||
if ((oldWriteHead < readHead) || ((q->buffer + totalByteRequirement) > readHead)) {
|
||||
return NULL; // overwrite condition
|
||||
} else {
|
||||
q->writeHead = q->buffer;
|
||||
q->remainingBytes = q->len;
|
||||
HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
|
||||
hv_sfence();
|
||||
HLP_SET_UINT32_AT_BUFFER(oldWriteHead, HLP_LOOP);
|
||||
return q->buffer + sizeof(hv_uint32_t);
|
||||
}
|
||||
} else {
|
||||
return NULL; // there isn't enough space to write the data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes) {
|
||||
hv_assert(q->remainingBytes >= (numBytes + 2*sizeof(hv_uint32_t)));
|
||||
q->remainingBytes -= (sizeof(hv_uint32_t) + numBytes);
|
||||
char *const oldWriteHead = q->writeHead;
|
||||
q->writeHead += (sizeof(hv_uint32_t) + numBytes);
|
||||
HLP_SET_UINT32_AT_BUFFER(q->writeHead, HLP_STOP);
|
||||
|
||||
// save everything before this point to memory
|
||||
hv_sfence();
|
||||
|
||||
// then save this
|
||||
HLP_SET_UINT32_AT_BUFFER(oldWriteHead, numBytes);
|
||||
}
|
||||
|
||||
char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes) {
|
||||
*numBytes = HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
char *const readBuffer = q->readHead + sizeof(hv_uint32_t);
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
void hLp_consume(HvLightPipe *q) {
|
||||
hv_assert(HLP_GET_UINT32_AT_BUFFER(q->readHead) != HLP_STOP);
|
||||
q->readHead += sizeof(hv_uint32_t) + HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
}
|
||||
|
||||
void hLp_reset(HvLightPipe *q) {
|
||||
q->writeHead = q->buffer;
|
||||
q->readHead = q->buffer;
|
||||
q->remainingBytes = q->len;
|
||||
memset(q->buffer, 0, q->len);
|
||||
}
|
||||
104
delay_simple/c/HvLightPipe.h
Normal file
104
delay_simple/c/HvLightPipe.h
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_LIGHTPIPE_H_
|
||||
#define _HEAVY_LIGHTPIPE_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This pipe assumes that there is only one producer thread and one consumer
|
||||
* thread. This data structure does not support any other configuration.
|
||||
*/
|
||||
typedef struct HvLightPipe {
|
||||
char *buffer;
|
||||
char *writeHead;
|
||||
char *readHead;
|
||||
hv_uint32_t len;
|
||||
hv_uint32_t remainingBytes; // total bytes from write head to end
|
||||
} HvLightPipe;
|
||||
|
||||
/**
|
||||
* Initialise the pipe with a given length, in bytes.
|
||||
* @return Returns the size of the pipe in bytes.
|
||||
*/
|
||||
hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes);
|
||||
|
||||
/**
|
||||
* Frees the internal buffer.
|
||||
* @param q The light pipe.
|
||||
*/
|
||||
void hLp_free(HvLightPipe *q);
|
||||
|
||||
/**
|
||||
* Indicates if data is available for reading.
|
||||
* @param q The light pipe.
|
||||
*
|
||||
* @return Returns the number of bytes available for reading. Zero if no bytes
|
||||
* are available.
|
||||
*/
|
||||
hv_uint32_t hLp_hasData(HvLightPipe *q);
|
||||
|
||||
/**
|
||||
* Returns a pointer to a location in the pipe where numBytes can be written.
|
||||
*
|
||||
* @param numBytes The number of bytes to be written.
|
||||
* @return A pointer to a location where those bytes can be written. Returns
|
||||
* NULL if no more space is available. Successive calls to this
|
||||
* function may eventually return a valid pointer because the readhead
|
||||
* has been advanced on another thread.
|
||||
*/
|
||||
char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t numBytes);
|
||||
|
||||
/**
|
||||
* Indicates to the pipe how many bytes have been written.
|
||||
*
|
||||
* @param numBytes The number of bytes written. In general this should be the
|
||||
* same value as was passed to the preceeding call to
|
||||
* hLp_getWriteBuffer().
|
||||
*/
|
||||
void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes);
|
||||
|
||||
/**
|
||||
* Returns the current read buffer, indicating the number of bytes available
|
||||
* for reading.
|
||||
* @param q The light pipe.
|
||||
* @param numBytes This value will be filled with the number of bytes available
|
||||
* for reading.
|
||||
*
|
||||
* @return A pointer to the read buffer.
|
||||
*/
|
||||
char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes);
|
||||
|
||||
/**
|
||||
* Indicates that the next set of bytes have been read and are no longer needed.
|
||||
* @param q The light pipe.
|
||||
*/
|
||||
void hLp_consume(HvLightPipe *q);
|
||||
|
||||
// resets the queue to it's initialised state
|
||||
// This should be done when only one thread is accessing the pipe.
|
||||
void hLp_reset(HvLightPipe *q);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_LIGHTPIPE_H_
|
||||
724
delay_simple/c/HvMath.h
Normal file
724
delay_simple/c/HvMath.h
Normal file
@ -0,0 +1,724 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_MATH_H_
|
||||
#define _HEAVY_MATH_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
// https://software.intel.com/sites/landingpage/IntrinsicsGuide/
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html
|
||||
// http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html
|
||||
|
||||
static inline void __hv_zero_f(hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_setzero_ps();
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_setzero_ps();
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vdupq_n_f32(0.0f);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_zero_i(hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_setzero_si256();
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_setzero_si128();
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vdupq_n_s32(0);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_load_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_load_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vld1q_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = *bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) {
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_store_ps(bOut, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_store_ps(bOut, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(bOut, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_log2_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
// https://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||
__m128i a = _mm_castps_si128(bIn);
|
||||
__m128i b = _mm_srli_epi32(a, 23);
|
||||
__m128i c = _mm_sub_epi32(b, _mm_set1_epi32(127)); // exponent (int)
|
||||
__m128 d = _mm_cvtepi32_ps(c); // exponent (float)
|
||||
__m128i e = _mm_or_si128(_mm_andnot_si128(_mm_set1_epi32(0xFF800000), a), _mm_set1_epi32(0x3F800000));
|
||||
__m128 f = _mm_castsi128_ps(e); // 1+m (float)
|
||||
__m128 g = _mm_add_ps(d, f); // e + 1 + m
|
||||
__m128 h = _mm_add_ps(g, _mm_set1_ps(-0.9569643f)); // e + 1 + m + (sigma-1)
|
||||
*bOut = h;
|
||||
#elif HV_SIMD_NEON
|
||||
int32x4_t a = vreinterpretq_s32_f32(bIn);
|
||||
int32x4_t b = vshrq_n_s32(a, 23);
|
||||
int32x4_t c = vsubq_s32(b, vdupq_n_s32(127));
|
||||
float32x4_t d = vcvtq_f32_s32(c);
|
||||
int32x4_t e = vorrq_s32(vbicq_s32(a, vdupq_n_s32(0xFF800000)), vdupq_n_s32(0x3F800000));
|
||||
float32x4_t f = vreinterpretq_f32_s32(e);
|
||||
float32x4_t g = vaddq_f32(d, f);
|
||||
float32x4_t h = vaddq_f32(g, vdupq_n_f32(-0.9569643f));
|
||||
*bOut = h;
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 1.442695040888963f * hv_log_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOTE(mhroth): this is a pretty ghetto implementation
|
||||
static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_set_ps(
|
||||
hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]),
|
||||
hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0]));
|
||||
#elif HV_SIMD_SSE
|
||||
const float *const b = (float *) &bIn;
|
||||
*bOut = _mm_set_ps(hv_cos_f(b[3]), hv_cos_f(b[2]), hv_cos_f(b[1]), hv_cos_f(b[0]));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])};
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_cos_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_acos_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_acos_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_acos_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_acos_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_cosh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_cosh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_cosh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_cosh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_acosh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_acosh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_acosh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_acosh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_sin_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_sin_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_sin_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_sin_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_asin_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_asin_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_asin_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_asin_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_sinh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_sinh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_sinh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_sinh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_asinh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_asinh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_asinh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_asinh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_tan_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_tan_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_tan_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_tan_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_atan_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_atan_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_atan_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_atan_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_atan2_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_atan2_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_atan2_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_atan2_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_tanh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_tanh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_tanh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_tanh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_atanh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_atanh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_atanh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_atanh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_sqrt_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_sqrt_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
const float32x4_t y = vrsqrteq_f32(bIn);
|
||||
*bOut = vmulq_f32(bIn, vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y)); // numerical results may be inexact
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_sqrt_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_rsqrt_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_rsqrt_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
const float32x4_t y = vrsqrteq_f32(bIn);
|
||||
*bOut = vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y); // numerical results may be inexact
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 1.0f/hv_sqrt_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vabsq_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_abs_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_neg_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_xor_ps(bIn, _mm256_set1_ps(-0.0f));
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_xor_ps(bIn, _mm_set1_ps(-0.0f));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vnegq_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn * -1.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
|
||||
_mm256_store_ps(b, bIn);
|
||||
*bOut = _mm256_set_ps(
|
||||
hv_exp_f(b[7]), hv_exp_f(b[6]), hv_exp_f(b[5]), hv_exp_f(b[4]),
|
||||
hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
|
||||
#elif HV_SIMD_SSE
|
||||
float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
|
||||
_mm_store_ps(b, bIn);
|
||||
*bOut = _mm_set_ps(hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = (float32x4_t) {
|
||||
hv_exp_f(bIn[0]),
|
||||
hv_exp_f(bIn[1]),
|
||||
hv_exp_f(bIn[2]),
|
||||
hv_exp_f(bIn[3])};
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_exp_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_ceil_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_ceil_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vrndpq_f32(bIn);
|
||||
#else
|
||||
// A slow NEON implementation of __hv_ceil_f() is being used because
|
||||
// the necessary intrinsic cannot be found. It is only available in ARMv8.
|
||||
*bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])};
|
||||
#endif // vrndpq_f32
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_ceil_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_floor_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_floor_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vrndmq_f32(bIn);
|
||||
#else
|
||||
// A slow implementation of __hv_floor_f() is being used because
|
||||
// the necessary intrinsic cannot be found. It is only available from ARMv8.
|
||||
*bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])};
|
||||
#endif // vrndmq_f32
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_floor_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
// __add~f
|
||||
static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_add_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_add_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vaddq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 + bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __add~i
|
||||
static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_add_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vaddq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 + bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __sub~f
|
||||
static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_sub_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_sub_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vsubq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 - bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __mul~f
|
||||
static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_mul_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_mul_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmulq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 * bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __*~i
|
||||
static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_mullo_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmulq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 * bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __cast~if
|
||||
static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cvtepi32_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cvtepi32_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vcvtq_f32_s32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (float) bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __cast~fi
|
||||
static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cvtps_epi32(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cvtps_epi32(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vcvtq_s32_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (int) bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m256 a = _mm256_cmp_ps(bIn1, _mm256_setzero_ps(), _CMP_EQ_OQ);
|
||||
__m256 b = _mm256_div_ps(bIn0, bIn1);
|
||||
*bOut = _mm256_andnot_ps(a, b);
|
||||
#elif HV_SIMD_SSE
|
||||
__m128 a = _mm_cmpeq_ps(bIn1, _mm_setzero_ps());
|
||||
__m128 b = _mm_div_ps(bIn0, bIn1);
|
||||
*bOut = _mm_andnot_ps(a, b);
|
||||
#elif HV_SIMD_NEON
|
||||
uint32x4_t a = vceqq_f32(bIn1, vdupq_n_f32(0.0f));
|
||||
float32x4_t b = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); // NOTE(mhroth): numerical results may be inexact
|
||||
*bOut = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(b), a));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_min_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_min_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vminq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_min_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_min_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vminq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_min_i(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_max_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_max_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmaxq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_max_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_max_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmaxq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_max_i(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
float *b = (float *) hv_alloca(16*sizeof(float));
|
||||
_mm256_store_ps(b, bIn0);
|
||||
_mm256_store_ps(b+8, bIn1);
|
||||
*bOut = _mm256_set_ps(
|
||||
hv_pow_f(b[7], b[7]),
|
||||
hv_pow_f(b[6], b[6]),
|
||||
hv_pow_f(b[5], b[5]),
|
||||
hv_pow_f(b[4], b[4]),
|
||||
hv_pow_f(b[3], b[3]),
|
||||
hv_pow_f(b[2], b[2]),
|
||||
hv_pow_f(b[1], b[1]),
|
||||
hv_pow_f(b[0], b[0]));
|
||||
#elif HV_SIMD_SSE
|
||||
float *b = (float *) hv_alloca(8*sizeof(float));
|
||||
_mm_store_ps(b, bIn0);
|
||||
_mm_store_ps(b+4, bIn1);
|
||||
*bOut = _mm_set_ps(
|
||||
hv_pow_f(b[3], b[7]),
|
||||
hv_pow_f(b[2], b[6]),
|
||||
hv_pow_f(b[1], b[5]),
|
||||
hv_pow_f(b[0], b[4]));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = (float32x4_t) {
|
||||
hv_pow_f(bIn0[0], bIn1[0]),
|
||||
hv_pow_f(bIn0[1], bIn1[1]),
|
||||
hv_pow_f(bIn0[2], bIn1[2]),
|
||||
hv_pow_f(bIn0[3], bIn1[3])};
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_pow_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmpgt_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 > bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmpge_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmplt_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 < bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmple_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmpneq_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1)));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 != bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_or_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_or_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
|
||||
#else // HV_SIMD_NONE
|
||||
if (bIn0 == 0.0f && bIn1 == 0.0f) *bOut = 0.0f;
|
||||
else if (bIn0 == 0.0f) *bOut = bIn1;
|
||||
else if (bIn1 == 0.0f) *bOut = bIn0;
|
||||
else hv_assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_and_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_and_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
|
||||
#else // HV_SIMD_NONE
|
||||
if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f;
|
||||
else if (bIn0 == 1.0f) *bOut = bIn1;
|
||||
else if (bIn1 == 1.0f) *bOut = bIn0;
|
||||
else hv_assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_andnot_f(hv_bInf_t bIn0_mask, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_andnot_ps(bIn0_mask, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_andnot_ps(bIn0_mask, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(bIn1), vreinterpretq_s32_f32(bIn0_mask)));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0_mask == 0.0f) ? bIn1 : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
// bOut = (bIn0 * bIn1) + bIn2
|
||||
static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_SSE
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vfmaq_f32(bIn2, bIn0, bIn1);
|
||||
#else
|
||||
// NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
|
||||
*bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2);
|
||||
#endif
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_fma_f(bIn0, bIn1, bIn2);
|
||||
#endif
|
||||
}
|
||||
|
||||
// bOut = (bIn0 * bIn1) - bIn2
|
||||
static inline void __hv_fms_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm256_fmsub_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm256_sub_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_SSE
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm_fmsub_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm_sub_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vfmsq_f32(bIn2, bIn0, bIn1);
|
||||
#else
|
||||
// NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
|
||||
*bOut = vsubq_f32(vmulq_f32(bIn0, bIn1), bIn2);
|
||||
#endif
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 * bIn1) - bIn2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _HEAVY_MATH_H_
|
||||
199
delay_simple/c/HvMessage.c
Normal file
199
delay_simple/c/HvMessage.c
Normal file
@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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"
|
||||
|
||||
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] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break;
|
||||
case HV_MSG_FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break;
|
||||
case HV_MSG_SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break;
|
||||
case HV_MSG_HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; 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));
|
||||
hv_assert(finalString != NULL);
|
||||
int pos = 0;
|
||||
for (int i = 0; i < msg_getNumElements(m); i++) {
|
||||
// put a string representation of each atom into the final string
|
||||
switch (msg_getType(m, i)) {
|
||||
case HV_MSG_BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break;
|
||||
case HV_MSG_FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break;
|
||||
case HV_MSG_SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break;
|
||||
case HV_MSG_HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break;
|
||||
default: break;
|
||||
}
|
||||
pos += len[i];
|
||||
finalString[pos-1] = 32; // ASCII space
|
||||
}
|
||||
finalString[size-1] = '\0'; // ensure that the string is null terminated
|
||||
return finalString;
|
||||
}
|
||||
183
delay_simple/c/HvMessage.h
Normal file
183
delay_simple/c/HvMessage.h
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_MESSAGE_H_
|
||||
#define _HEAVY_MESSAGE_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum ElementType {
|
||||
HV_MSG_BANG = 0,
|
||||
HV_MSG_FLOAT = 1,
|
||||
HV_MSG_SYMBOL = 2,
|
||||
HV_MSG_HASH = 3
|
||||
} ElementType;
|
||||
|
||||
typedef struct Element {
|
||||
ElementType type;
|
||||
union {
|
||||
float f; // float
|
||||
const char *s; // symbol
|
||||
hv_uint32_t h; // hash
|
||||
} data;
|
||||
} Element;
|
||||
|
||||
typedef struct HvMessage {
|
||||
hv_uint32_t timestamp; // the sample at which this message should be processed
|
||||
hv_uint16_t numElements;
|
||||
hv_uint16_t numBytes; // the total number of bytes that this message occupies in memory, including strings
|
||||
Element elem;
|
||||
} HvMessage;
|
||||
|
||||
typedef struct ReceiverMessagePair {
|
||||
hv_uint32_t receiverHash;
|
||||
HvMessage msg;
|
||||
} ReceiverMessagePair;
|
||||
|
||||
#define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getCoreSize(_x))
|
||||
|
||||
/** Returns the number of bytes that this message consumes in memory, not including strings. */
|
||||
static inline hv_size_t msg_getCoreSize(hv_size_t numElements) {
|
||||
hv_assert(numElements > 0);
|
||||
return sizeof(HvMessage) + ((numElements-1) * sizeof(Element));
|
||||
}
|
||||
|
||||
HvMessage *msg_copy(const HvMessage *m);
|
||||
|
||||
/** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */
|
||||
void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len);
|
||||
|
||||
void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM);
|
||||
|
||||
/** Frees a message on the heap. Does nothing if argument is NULL. */
|
||||
void msg_free(HvMessage *m);
|
||||
|
||||
HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp);
|
||||
|
||||
HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f);
|
||||
|
||||
HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp);
|
||||
|
||||
HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s);
|
||||
|
||||
HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h);
|
||||
|
||||
static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) {
|
||||
return m->timestamp;
|
||||
}
|
||||
|
||||
static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
|
||||
m->timestamp = timestamp;
|
||||
}
|
||||
|
||||
static inline int msg_getNumElements(const HvMessage *m) {
|
||||
return (int) m->numElements;
|
||||
}
|
||||
|
||||
/** Returns the total number of bytes this message consumes in memory. */
|
||||
static inline hv_uint32_t msg_getSize(const HvMessage *m) {
|
||||
return m->numBytes;
|
||||
}
|
||||
|
||||
static inline ElementType msg_getType(const HvMessage *m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
return (&(m->elem)+index)->type;
|
||||
}
|
||||
|
||||
static inline void msg_setBang(HvMessage *m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
(&(m->elem)+index)->type = HV_MSG_BANG;
|
||||
(&(m->elem)+index)->data.s = NULL;
|
||||
}
|
||||
|
||||
static inline bool msg_isBang(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_BANG) : false;
|
||||
}
|
||||
|
||||
static inline void msg_setFloat(HvMessage *m, int index, float f) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
(&(m->elem)+index)->type = HV_MSG_FLOAT;
|
||||
(&(m->elem)+index)->data.f = f;
|
||||
}
|
||||
|
||||
static inline float msg_getFloat(const HvMessage *const m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
return (&(m->elem)+index)->data.f;
|
||||
}
|
||||
|
||||
static inline bool msg_isFloat(const HvMessage *const m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_FLOAT) : false;
|
||||
}
|
||||
|
||||
static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
(&(m->elem)+index)->type = HV_MSG_HASH;
|
||||
(&(m->elem)+index)->data.h = h;
|
||||
}
|
||||
|
||||
static inline bool msg_isHash(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_HASH) : false;
|
||||
}
|
||||
|
||||
/** Returns true if the element is a hash or symbol. False otherwise. */
|
||||
static inline bool msg_isHashLike(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HV_MSG_HASH) || (msg_getType(m, index) == HV_MSG_SYMBOL)) : false;
|
||||
}
|
||||
|
||||
/** Returns a 32-bit hash of the given element. */
|
||||
hv_uint32_t msg_getHash(const HvMessage *const m, int i);
|
||||
|
||||
static inline void msg_setSymbol(HvMessage *m, int index, const char *s) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
hv_assert(s != NULL);
|
||||
(&(m->elem)+index)->type = HV_MSG_SYMBOL;
|
||||
(&(m->elem)+index)->data.s = s;
|
||||
// NOTE(mhroth): if the same message container is reused and string reset,
|
||||
// then the message size will be overcounted
|
||||
m->numBytes += (hv_uint16_t) (hv_strlen(s) + 1); // also count '\0'
|
||||
}
|
||||
|
||||
static inline const char *msg_getSymbol(const HvMessage *m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
return (&(m->elem)+index)->data.s;
|
||||
}
|
||||
|
||||
static inline bool msg_isSymbol(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_SYMBOL) : false;
|
||||
}
|
||||
|
||||
bool msg_compareSymbol(const HvMessage *m, int i, const char *s);
|
||||
|
||||
/** Returns 1 if the element i_m of message m is equal to element i_n of message n. */
|
||||
bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n);
|
||||
|
||||
bool msg_hasFormat(const HvMessage *m, const char *fmt);
|
||||
|
||||
/**
|
||||
* Create a string representation of the message. Suitable for use by the print object.
|
||||
* The resulting string must be freed by the caller.
|
||||
*/
|
||||
char *msg_toString(const HvMessage *msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_MESSAGE_H_
|
||||
144
delay_simple/c/HvMessagePool.c
Normal file
144
delay_simple/c/HvMessagePool.c
Normal file
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvMessagePool.h"
|
||||
#include "HvMessage.h"
|
||||
|
||||
// the number of bytes reserved at a time from the pool
|
||||
#define MP_BLOCK_SIZE_BYTES 512
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - MessageList
|
||||
#endif
|
||||
|
||||
typedef struct MessageListNode {
|
||||
char *p;
|
||||
struct MessageListNode *next;
|
||||
} MessageListNode;
|
||||
|
||||
static inline bool ml_hasAvailable(HvMessagePoolList *ml) {
|
||||
return (ml->head != NULL);
|
||||
}
|
||||
|
||||
static char *ml_pop(HvMessagePoolList *ml) {
|
||||
MessageListNode *n = ml->head;
|
||||
ml->head = n->next;
|
||||
n->next = ml->pool;
|
||||
ml->pool = n;
|
||||
char *const p = n->p;
|
||||
n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Push a MessageListNode with the given pointer onto the head of the queue. */
|
||||
static void ml_push(HvMessagePoolList *ml, void *p) {
|
||||
MessageListNode *n = NULL;
|
||||
if (ml->pool != NULL) {
|
||||
// take an empty MessageListNode from the pool
|
||||
n = ml->pool;
|
||||
ml->pool = n->next;
|
||||
} else {
|
||||
// a MessageListNode is not available, allocate one
|
||||
n = (MessageListNode *) hv_malloc(sizeof(MessageListNode));
|
||||
hv_assert(n != NULL);
|
||||
}
|
||||
n->p = (char *) p;
|
||||
n->next = ml->head;
|
||||
ml->head = n; // push to the front of the queue
|
||||
}
|
||||
|
||||
static void ml_free(HvMessagePoolList *ml) {
|
||||
if (ml != NULL) {
|
||||
while (ml_hasAvailable(ml)) {
|
||||
ml_pop(ml);
|
||||
}
|
||||
while (ml->pool != NULL) {
|
||||
MessageListNode *n = ml->pool;
|
||||
ml->pool = n->next;
|
||||
hv_free(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - HvMessagePool
|
||||
#endif
|
||||
|
||||
static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) {
|
||||
return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0);
|
||||
}
|
||||
|
||||
hv_size_t mp_init(HvMessagePool *mp, hv_size_t numKB) {
|
||||
mp->bufferSize = numKB * 1024;
|
||||
mp->buffer = (char *) hv_malloc(mp->bufferSize);
|
||||
hv_assert(mp->buffer != NULL);
|
||||
mp->bufferIndex = 0;
|
||||
|
||||
// initialise all message lists
|
||||
for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
|
||||
mp->lists[i].head = NULL;
|
||||
mp->lists[i].pool = NULL;
|
||||
}
|
||||
|
||||
return mp->bufferSize;
|
||||
}
|
||||
|
||||
void mp_free(HvMessagePool *mp) {
|
||||
hv_free(mp->buffer);
|
||||
for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
|
||||
ml_free(&mp->lists[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_freeMessage(HvMessagePool *mp, HvMessage *m) {
|
||||
const hv_size_t b = msg_getSize(m); // the number of bytes that a message occupies in memory
|
||||
const hv_size_t i = mp_messagelistIndexForSize(b); // the HvMessagePoolList index in the pool
|
||||
HvMessagePoolList *ml = &mp->lists[i];
|
||||
const hv_size_t chunkSize = 32 << i;
|
||||
hv_memclear(m, chunkSize); // clear the chunk, just in case
|
||||
ml_push(ml, m);
|
||||
}
|
||||
|
||||
HvMessage *mp_addMessage(HvMessagePool *mp, const HvMessage *m) {
|
||||
const hv_size_t b = msg_getSize(m);
|
||||
// determine the message list index to allocate data from based on the msg size
|
||||
// smallest chunk size is 32 bytes
|
||||
const hv_size_t i = mp_messagelistIndexForSize(b);
|
||||
|
||||
hv_assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment
|
||||
HvMessagePoolList *ml = &mp->lists[i];
|
||||
const hv_size_t chunkSize = 32 << i;
|
||||
|
||||
if (ml_hasAvailable(ml)) {
|
||||
char *buf = ml_pop(ml);
|
||||
msg_copyToBuffer(m, buf, chunkSize);
|
||||
return (HvMessage *) buf;
|
||||
} else {
|
||||
// if no appropriately sized buffer is immediately available, increase the size of the used buffer
|
||||
const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES;
|
||||
hv_assert((newIndex <= mp->bufferSize) &&
|
||||
"The message pool buffer size has been exceeded. The context cannot store more messages. "
|
||||
"Try using the new_with_options() initialiser with a larger pool size (default is 10KB).");
|
||||
|
||||
for (hv_size_t j = mp->bufferIndex; j < newIndex; j += chunkSize) {
|
||||
ml_push(ml, mp->buffer + j); // push new nodes onto the list with chunk pointers
|
||||
}
|
||||
mp->bufferIndex = newIndex;
|
||||
char *buf = ml_pop(ml);
|
||||
msg_copyToBuffer(m, buf, chunkSize);
|
||||
return (HvMessage *) buf;
|
||||
}
|
||||
}
|
||||
67
delay_simple/c/HvMessagePool.h
Normal file
67
delay_simple/c/HvMessagePool.h
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 _MESSAGE_POOL_H_
|
||||
#define _MESSAGE_POOL_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#define MP_NUM_MESSAGE_LISTS 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct HvMessagePoolList {
|
||||
struct MessageListNode *head; // list of currently available blocks
|
||||
struct MessageListNode *pool; // list of currently used blocks
|
||||
} HvMessagePoolList;
|
||||
|
||||
typedef struct HvMessagePool {
|
||||
char *buffer; // the buffer of all messages
|
||||
hv_size_t bufferSize; // in bytes
|
||||
hv_size_t bufferIndex; // the number of total reserved bytes
|
||||
|
||||
HvMessagePoolList lists[MP_NUM_MESSAGE_LISTS];
|
||||
} HvMessagePool;
|
||||
|
||||
/**
|
||||
* The HvMessagePool is a basic memory management system. It reserves a large block of memory at initialisation
|
||||
* and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are
|
||||
* further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a HvMessagePoolList (MPL).
|
||||
* An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes
|
||||
* that point at each subblock (e.g. each 32-byte block of a 512-block chunk).
|
||||
*
|
||||
* HvMessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html
|
||||
*/
|
||||
|
||||
hv_size_t mp_init(struct HvMessagePool *mp, hv_size_t numKB);
|
||||
|
||||
void mp_free(struct HvMessagePool *mp);
|
||||
|
||||
/**
|
||||
* Adds a message to the pool and returns a pointer to the copy. Returns NULL
|
||||
* if no space was available in the pool.
|
||||
*/
|
||||
struct HvMessage *mp_addMessage(struct HvMessagePool *mp, const struct HvMessage *m);
|
||||
|
||||
void mp_freeMessage(struct HvMessagePool *mp, struct HvMessage *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _MESSAGE_POOL_H_
|
||||
215
delay_simple/c/HvMessageQueue.c
Normal file
215
delay_simple/c/HvMessageQueue.c
Normal file
@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvMessageQueue.h"
|
||||
|
||||
hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB) {
|
||||
hv_assert(poolSizeKB > 0);
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
q->pool = NULL;
|
||||
return mp_init(&q->mp, poolSizeKB);
|
||||
}
|
||||
|
||||
void mq_free(HvMessageQueue *q) {
|
||||
mq_clear(q);
|
||||
while (q->pool != NULL) {
|
||||
MessageNode *n = q->pool;
|
||||
q->pool = q->pool->next;
|
||||
hv_free(n);
|
||||
}
|
||||
mp_free(&q->mp);
|
||||
}
|
||||
|
||||
static MessageNode *mq_getOrCreateNodeFromPool(HvMessageQueue *q) {
|
||||
if (q->pool == NULL) {
|
||||
// if necessary, create a new empty node
|
||||
q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode));
|
||||
hv_assert(q->pool != NULL);
|
||||
q->pool->next = NULL;
|
||||
}
|
||||
MessageNode *node = q->pool;
|
||||
q->pool = q->pool->next;
|
||||
return node;
|
||||
}
|
||||
|
||||
int mq_size(HvMessageQueue *q) {
|
||||
int size = 0;
|
||||
MessageNode *n = q->head;
|
||||
while (n != NULL) {
|
||||
++size;
|
||||
n = n->next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
MessageNode *node = mq_getOrCreateNodeFromPool(q);
|
||||
node->m = mp_addMessage(&q->mp, m);
|
||||
node->let = let;
|
||||
node->sendMessage = sendMessage;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
if (q->tail != NULL) {
|
||||
// the list already contains elements
|
||||
q->tail->next = node;
|
||||
node->prev = q->tail;
|
||||
q->tail = node;
|
||||
} else {
|
||||
// the list is empty
|
||||
node->prev = NULL;
|
||||
q->head = node;
|
||||
q->tail = node;
|
||||
}
|
||||
return mq_node_getMessage(node);
|
||||
}
|
||||
|
||||
HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (mq_hasMessage(q)) {
|
||||
MessageNode *n = mq_getOrCreateNodeFromPool(q);
|
||||
n->m = mp_addMessage(&q->mp, m);
|
||||
n->let = let;
|
||||
n->sendMessage = sendMessage;
|
||||
|
||||
if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) {
|
||||
// the message occurs before the current head
|
||||
n->next = q->head;
|
||||
q->head->prev = n;
|
||||
n->prev = NULL;
|
||||
q->head = n;
|
||||
} else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) {
|
||||
// the message occurs after the current tail
|
||||
n->next = NULL;
|
||||
n->prev = q->tail;
|
||||
q->tail->next = n;
|
||||
q->tail = n;
|
||||
} else {
|
||||
// the message occurs somewhere between the head and tail
|
||||
MessageNode *node = q->head;
|
||||
while (node != NULL) {
|
||||
if (msg_getTimestamp(m) < msg_getTimestamp(node->next->m)) {
|
||||
MessageNode *r = node->next;
|
||||
node->next = n;
|
||||
n->next = r;
|
||||
n->prev = node;
|
||||
r->prev = n;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
return n->m;
|
||||
} else {
|
||||
// add a message to the head
|
||||
return mq_addMessage(q, m, let, sendMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void mq_pop(HvMessageQueue *q) {
|
||||
if (mq_hasMessage(q)) {
|
||||
MessageNode *n = q->head;
|
||||
|
||||
mp_freeMessage(&q->mp, n->m);
|
||||
n->m = NULL;
|
||||
|
||||
n->let = 0;
|
||||
n->sendMessage = NULL;
|
||||
|
||||
q->head = n->next;
|
||||
if (q->head == NULL) {
|
||||
q->tail = NULL;
|
||||
} else {
|
||||
q->head->prev = NULL;
|
||||
}
|
||||
n->next = q->pool;
|
||||
n->prev = NULL;
|
||||
q->pool = n;
|
||||
}
|
||||
}
|
||||
|
||||
bool mq_removeMessage(HvMessageQueue *q, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (mq_hasMessage(q)) {
|
||||
if (mq_node_getMessage(q->head) == m) { // msg in head node
|
||||
// only remove the message if sendMessage is the same as the stored one,
|
||||
// if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer
|
||||
if (sendMessage == NULL || q->head->sendMessage == sendMessage) {
|
||||
mq_pop(q);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MessageNode *prevNode = q->head;
|
||||
MessageNode *currNode = q->head->next;
|
||||
while ((currNode != NULL) && (currNode->m != m)) {
|
||||
prevNode = currNode;
|
||||
currNode = currNode->next;
|
||||
}
|
||||
if (currNode != NULL) {
|
||||
if (sendMessage == NULL || currNode->sendMessage == sendMessage) {
|
||||
mp_freeMessage(&q->mp, m);
|
||||
currNode->m = NULL;
|
||||
currNode->let = 0;
|
||||
currNode->sendMessage = NULL;
|
||||
if (currNode == q->tail) { // msg in tail node
|
||||
prevNode->next = NULL;
|
||||
q->tail = prevNode;
|
||||
} else { // msg in middle node
|
||||
prevNode->next = currNode->next;
|
||||
currNode->next->prev = prevNode;
|
||||
}
|
||||
currNode->next = (q->pool == NULL) ? NULL : q->pool;
|
||||
currNode->prev = NULL;
|
||||
q->pool = currNode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mq_clear(HvMessageQueue *q) {
|
||||
while (mq_hasMessage(q)) {
|
||||
mq_pop(q);
|
||||
}
|
||||
}
|
||||
|
||||
void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp) {
|
||||
MessageNode *n = q->tail;
|
||||
while (n != NULL && timestamp <= msg_getTimestamp(n->m)) {
|
||||
// free the node's message
|
||||
mp_freeMessage(&q->mp, n->m);
|
||||
n->m = NULL;
|
||||
n->let = 0;
|
||||
n->sendMessage = NULL;
|
||||
|
||||
// the tail points at the previous node
|
||||
q->tail = n->prev;
|
||||
|
||||
// put the node back in the pool
|
||||
n->next = q->pool;
|
||||
n->prev = NULL;
|
||||
if (q->pool != NULL) q->pool->prev = n;
|
||||
q->pool = n;
|
||||
|
||||
// update the tail node
|
||||
n = q->tail;
|
||||
}
|
||||
|
||||
if (q->tail == NULL) q->head = NULL;
|
||||
}
|
||||
101
delay_simple/c/HvMessageQueue.h
Normal file
101
delay_simple/c/HvMessageQueue.h
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 _MESSAGE_QUEUE_H_
|
||||
#define _MESSAGE_QUEUE_H_
|
||||
|
||||
#include "HvMessage.h"
|
||||
#include "HvMessagePool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
class HeavyContextInterface;
|
||||
#else
|
||||
typedef struct HeavyContextInterface HeavyContextInterface;
|
||||
#endif
|
||||
|
||||
typedef struct MessageNode {
|
||||
struct MessageNode *prev; // doubly linked list
|
||||
struct MessageNode *next;
|
||||
HvMessage *m;
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *);
|
||||
int let;
|
||||
} MessageNode;
|
||||
|
||||
/** A doubly linked list containing scheduled messages. */
|
||||
typedef struct HvMessageQueue {
|
||||
MessageNode *head; // the head of the queue
|
||||
MessageNode *tail; // the tail of the queue
|
||||
MessageNode *pool; // the head of the reserve pool
|
||||
HvMessagePool mp;
|
||||
} HvMessageQueue;
|
||||
|
||||
hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB);
|
||||
|
||||
void mq_free(HvMessageQueue *q);
|
||||
|
||||
int mq_size(HvMessageQueue *q);
|
||||
|
||||
static inline HvMessage *mq_node_getMessage(MessageNode *n) {
|
||||
return n->m;
|
||||
}
|
||||
|
||||
static inline int mq_node_getLet(MessageNode *n) {
|
||||
return n->let;
|
||||
}
|
||||
|
||||
static inline bool mq_hasMessage(HvMessageQueue *q) {
|
||||
return (q->head != NULL);
|
||||
}
|
||||
|
||||
// true if there is a message and it occurs before (<) timestamp
|
||||
static inline bool mq_hasMessageBefore(HvMessageQueue *const q, const hv_uint32_t timestamp) {
|
||||
return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp);
|
||||
}
|
||||
|
||||
static inline MessageNode *mq_peek(HvMessageQueue *q) {
|
||||
return q->head;
|
||||
}
|
||||
|
||||
/** Appends the message to the end of the queue. */
|
||||
HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Insert in ascending order the message acccording to its timestamp. */
|
||||
HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Pop the message at the head of the queue (and free its memory). */
|
||||
void mq_pop(HvMessageQueue *q);
|
||||
|
||||
/** Remove a message from the queue (and free its memory) */
|
||||
bool mq_removeMessage(HvMessageQueue *q, HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Clears (and frees) all messages in the queue. */
|
||||
void mq_clear(HvMessageQueue *q);
|
||||
|
||||
/** Removes all messages occuring at or after the given timestamp. */
|
||||
void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _MESSAGE_QUEUE_H_
|
||||
77
delay_simple/c/HvSignalTabread.c
Normal file
77
delay_simple/c/HvSignalTabread.c
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvSignalTabread.h"
|
||||
|
||||
hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads) {
|
||||
o->table = table;
|
||||
o->head = 0;
|
||||
o->forceAlignedLoads = forceAlignedLoads;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (o->table != NULL) {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_BANG: o->head = 0; break;
|
||||
case HV_MSG_FLOAT: {
|
||||
hv_uint32_t h = (hv_uint32_t) hv_abs_f(msg_getFloat(m,0));
|
||||
if (msg_getFloat(m,0) < 0.0f) {
|
||||
// if input is negative, wrap around the end of the table
|
||||
h = hTable_getSize(o->table) - h;
|
||||
}
|
||||
o->head = o->forceAlignedLoads ? (h & ~HV_N_SIMD_MASK) : h;
|
||||
|
||||
// output new head
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) o->head);
|
||||
sendMessage(_c, 1, n);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabhead
|
||||
#endif
|
||||
|
||||
void sTabhead_onMessage(HeavyContextInterface *_c, SignalTabhead *o, const HvMessage *m) {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
}
|
||||
|
||||
hv_size_t sTabhead_init(SignalTabhead *o, HvTable *table) {
|
||||
o->table = table;
|
||||
return 0;
|
||||
}
|
||||
183
delay_simple/c/HvSignalTabread.h
Normal file
183
delay_simple/c/HvSignalTabread.h
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_SIGNAL_TABREAD_H_
|
||||
#define _HEAVY_SIGNAL_TABREAD_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct SignalTabread {
|
||||
HvTable *table; // the table to read
|
||||
hv_uint32_t head;
|
||||
bool forceAlignedLoads; // false by default, true if using __hv_tabread_f
|
||||
} SignalTabread;
|
||||
|
||||
// random access to a table
|
||||
hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabread - Random Access
|
||||
#endif
|
||||
|
||||
static inline void __hv_tabread_if(SignalTabread *o, hv_bIni_t bIn, hv_bOutf_t bOut) {
|
||||
const float *const b = hTable_getBuffer(o->table);
|
||||
#if HV_SIMD_AVX
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn;
|
||||
|
||||
hv_assert(i[0] >= 0 && i[0] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && i[1] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && i[2] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && i[3] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[4] >= 0 && i[4] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[5] >= 0 && i[5] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[6] >= 0 && i[6] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[7] >= 0 && i[7] < hTable_getAllocated(o->table));
|
||||
|
||||
*bOut = _mm256_set_ps(b[i[7]], b[i[6]], b[i[5]], b[i[4]], b[i[3]], b[i[2]], b[i[1]], b[i[0]]);
|
||||
#elif HV_SIMD_SSE
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn;
|
||||
|
||||
hv_assert(i[0] >= 0 && ((hv_uint32_t) i[0]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && ((hv_uint32_t) i[1]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && ((hv_uint32_t) i[2]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && ((hv_uint32_t) i[3]) < hTable_getAllocated(o->table));
|
||||
|
||||
*bOut = _mm_set_ps(b[i[3]], b[i[2]], b[i[1]], b[i[0]]);
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert((bIn[0] >= 0) && (bIn[0] < hTable_getAllocated(o->table)));
|
||||
hv_assert((bIn[1] >= 0) && (bIn[1] < hTable_getAllocated(o->table)));
|
||||
hv_assert((bIn[2] >= 0) && (bIn[2] < hTable_getAllocated(o->table)));
|
||||
hv_assert((bIn[3] >= 0) && (bIn[3] < hTable_getAllocated(o->table)));
|
||||
|
||||
*bOut = (float32x4_t) {b[bIn[0]], b[bIn[1]], b[bIn[2]], b[bIn[3]]};
|
||||
#else // HV_SIMD_NONE
|
||||
hv_assert(bIn >= 0 && ((hv_uint32_t) bIn < hTable_getAllocated(o->table)));
|
||||
|
||||
*bOut = b[bIn];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabread - Linear Access
|
||||
#endif
|
||||
|
||||
// this tabread never stops reading. It is mainly intended for linear reads that loop around a table.
|
||||
static inline void __hv_tabread_f(SignalTabread *o, hv_bOutf_t bOut) {
|
||||
hv_assert((o->head + HV_N_SIMD) <= hTable_getAllocated(o->table)); // assert that we always read within the table bounds
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_load_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_load_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vld1q_f32(hTable_getBuffer(o->table) + head);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = *(hTable_getBuffer(o->table) + head);
|
||||
#endif
|
||||
o->head = head + HV_N_SIMD;
|
||||
}
|
||||
|
||||
// unaligned linear tabread, as above
|
||||
static inline void __hv_tabreadu_f(SignalTabread *o, hv_bOutf_t bOut) {
|
||||
hv_assert((o->head + HV_N_SIMD) <= hTable_getAllocated(o->table)); // assert that we always read within the table bounds
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_loadu_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_loadu_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vld1q_f32(hTable_getBuffer(o->table) + head);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = *(hTable_getBuffer(o->table) + head);
|
||||
#endif
|
||||
o->head = head + HV_N_SIMD;
|
||||
}
|
||||
|
||||
// this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
|
||||
static inline void __hv_tabread_stoppable_f(SignalTabread *o, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = _mm256_setzero_ps();
|
||||
} else {
|
||||
*bOut = _mm256_load_ps(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#elif HV_SIMD_SSE
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = _mm_setzero_ps();
|
||||
} else {
|
||||
*bOut = _mm_load_ps(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#elif HV_SIMD_NEON
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = vdupq_n_f32(0.0f);
|
||||
} else {
|
||||
*bOut = vld1q_f32(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#else // HV_SIMD_NONE
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = 0.0f;
|
||||
} else {
|
||||
*bOut = *(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabhead
|
||||
#endif
|
||||
|
||||
typedef struct SignalTabhead {
|
||||
HvTable *table;
|
||||
} SignalTabhead;
|
||||
|
||||
hv_size_t sTabhead_init(SignalTabhead *o, HvTable *table);
|
||||
|
||||
static inline void __hv_tabhead_f(SignalTabhead *o, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_set1_ps((float) hTable_getHead(o->table));
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_set1_ps((float) hTable_getHead(o->table));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vdupq_n_f32((float32_t) hTable_getHead(o->table));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (float) hTable_getHead(o->table);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sTabhead_onMessage(HeavyContextInterface *_c, SignalTabhead *o, const HvMessage *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_SIGNAL_TABREAD_H_
|
||||
54
delay_simple/c/HvSignalTabwrite.c
Normal file
54
delay_simple/c/HvSignalTabwrite.c
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvSignalTabwrite.h"
|
||||
|
||||
hv_size_t sTabwrite_init(SignalTabwrite *o, HvTable *table) {
|
||||
o->table = table;
|
||||
o->head = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sTabwrite_onMessage(HeavyContextInterface *_c, SignalTabwrite *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
// inlet 0 is the signal inlet
|
||||
case 1: {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_BANG: o->head = 0; break;
|
||||
case HV_MSG_FLOAT: {
|
||||
o->head = (msg_getFloat(m,0) >= 0.0f) ? (hv_uint32_t) msg_getFloat(m,0) : HV_TABWRITE_STOPPED;
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL: {
|
||||
if (msg_compareSymbol(m, 0, "stop")) {
|
||||
o->head = HV_TABWRITE_STOPPED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
147
delay_simple/c/HvSignalTabwrite.h
Normal file
147
delay_simple/c/HvSignalTabwrite.h
Normal file
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_SIGNAL_TABWRITE_H_
|
||||
#define _HEAVY_SIGNAL_TABWRITE_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HV_TABWRITE_STOPPED -1 // ~0x0
|
||||
|
||||
typedef struct SignalTabwrite {
|
||||
HvTable *table;
|
||||
hv_uint32_t head; // local write head. Where this object has most recently written to the table.
|
||||
} SignalTabwrite;
|
||||
|
||||
hv_size_t sTabwrite_init(SignalTabwrite *o, HvTable *table);
|
||||
|
||||
void sTabwrite_onMessage(HeavyContextInterface *_c, SignalTabwrite *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
// linear write to table
|
||||
static inline void __hv_tabwrite_f(SignalTabwrite *o, hv_bInf_t bIn) {
|
||||
hv_assert((o->head + HV_N_SIMD) <= hTable_getSize(o->table)); // assert that the table bounds are respected
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_store_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_store_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(hTable_getBuffer(o->table) + head, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*(hTable_getBuffer(o->table) + head) = bIn;
|
||||
#endif
|
||||
head += HV_N_SIMD;
|
||||
o->head = head; // update local write head
|
||||
hTable_setHead(o->table, head); // update the remote write head (e.g. for use by vd~)
|
||||
}
|
||||
|
||||
// linear unaligned write to table
|
||||
static inline void __hv_tabwriteu_f(SignalTabwrite *o, hv_bInf_t bIn) {
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_storeu_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_storeu_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(hTable_getBuffer(o->table) + head, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*(hTable_getBuffer(o->table) + head) = bIn;
|
||||
#endif
|
||||
head += HV_N_SIMD;
|
||||
o->head = head; // update local write head
|
||||
hTable_setHead(o->table, head); // update remote write head
|
||||
}
|
||||
|
||||
// this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
|
||||
// Stores are unaligned, which can be slow but allows any indicies to be written to.
|
||||
// TODO(mhroth): this is not stopping!
|
||||
static inline void __hv_tabwrite_stoppable_f(SignalTabwrite *o, hv_bInf_t bIn) {
|
||||
if (o->head != HV_TABWRITE_STOPPED) {
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_storeu_ps(hTable_getBuffer(o->table) + o->head, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_storeu_ps(hTable_getBuffer(o->table) + o->head, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(hTable_getBuffer(o->table) + o->head, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*(hTable_getBuffer(o->table) + o->head) = bIn;
|
||||
#endif
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
}
|
||||
|
||||
// random write to table
|
||||
static inline void __hv_tabwrite_if(SignalTabwrite *o, hv_bIni_t bIn0, hv_bInf_t bIn1) {
|
||||
float *const b = hTable_getBuffer(o->table);
|
||||
#if HV_SIMD_AVX
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn0;
|
||||
const float *const f = (float *) &bIn1;
|
||||
|
||||
hv_assert(i[0] >= 0 && i[0] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && i[1] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && i[2] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && i[3] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[4] >= 0 && i[4] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[5] >= 0 && i[5] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[6] >= 0 && i[6] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[7] >= 0 && i[7] < hTable_getAllocated(o->table));
|
||||
|
||||
b[i[0]] = f[0];
|
||||
b[i[1]] = f[1];
|
||||
b[i[2]] = f[2];
|
||||
b[i[3]] = f[3];
|
||||
b[i[4]] = f[4];
|
||||
b[i[5]] = f[5];
|
||||
b[i[6]] = f[6];
|
||||
b[i[7]] = f[7];
|
||||
#elif HV_SIMD_SSE
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn0;
|
||||
const float *const f = (float *) &bIn1;
|
||||
|
||||
hv_assert(i[0] >= 0 && ((hv_uint32_t) i[0]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && ((hv_uint32_t) i[1]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && ((hv_uint32_t) i[2]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && ((hv_uint32_t) i[3]) < hTable_getAllocated(o->table));
|
||||
|
||||
b[i[0]] = f[0];
|
||||
b[i[1]] = f[1];
|
||||
b[i[2]] = f[2];
|
||||
b[i[3]] = f[3];
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert((vgetq_lane_s32(bIn0,0) >= 0) && (vgetq_lane_s32(bIn0,0) < hTable_getSize(o->table)));
|
||||
hv_assert((vgetq_lane_s32(bIn0,1) >= 0) && (vgetq_lane_s32(bIn0,1) < hTable_getSize(o->table)));
|
||||
hv_assert((vgetq_lane_s32(bIn0,2) >= 0) && (vgetq_lane_s32(bIn0,2) < hTable_getSize(o->table)));
|
||||
hv_assert((vgetq_lane_s32(bIn0,3) >= 0) && (vgetq_lane_s32(bIn0,3) < hTable_getSize(o->table)));
|
||||
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 0), bIn1, 0);
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 1), bIn1, 1);
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 2), bIn1, 2);
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 3), bIn1, 3);
|
||||
#else // HV_SIMD_NONE
|
||||
b[bIn0] = bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_SIGNAL_TABWRITE_H_
|
||||
75
delay_simple/c/HvSignalVar.c
Normal file
75
delay_simple/c/HvSignalVar.c
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvSignalVar.h"
|
||||
|
||||
// __var~f
|
||||
|
||||
static void sVarf_update(SignalVarf *o, float k, float step, bool reverse) {
|
||||
#if HV_SIMD_AVX
|
||||
if (reverse) o->v = _mm256_setr_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
else o->v = _mm256_set_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
#elif HV_SIMD_SSE
|
||||
if (reverse) o->v = _mm_setr_ps(k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
else o->v = _mm_set_ps(k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
#elif HV_SIMD_NEON
|
||||
if (reverse) o->v = (float32x4_t) {3.0f*step+k, 2.0f*step+k, step+k, k};
|
||||
else o->v = (float32x4_t) {k, step+k, 2.0f*step+k, 3.0f*step+k};
|
||||
#else // HV_SIMD_NONE
|
||||
o->v = k;
|
||||
#endif
|
||||
}
|
||||
|
||||
hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse) {
|
||||
sVarf_update(o, k, step, reverse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m) {
|
||||
if (msg_isFloat(m,0)) {
|
||||
sVarf_update(o, msg_getFloat(m,0), msg_isFloat(m,1) ? msg_getFloat(m,1) : 0.0f, msg_getNumElements(m) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// __var~i
|
||||
|
||||
static void sVari_update(SignalVari *o, int k, int step, bool reverse) {
|
||||
#if HV_SIMD_AVX
|
||||
if (reverse) o->v = _mm256_setr_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k);
|
||||
else o->v = _mm256_set_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k);
|
||||
#elif HV_SIMD_SSE
|
||||
if (reverse) o->v = _mm_setr_epi32(k+3*step, k+2*step, k+step, k);
|
||||
else o->v = _mm_set_epi32(k+3*step, k+2*step, k+step, k);
|
||||
#elif HV_SIMD_NEON
|
||||
if (reverse) o->v = (int32x4_t) {3*step+k, 2*step+k, step+k, k};
|
||||
else o->v = (int32x4_t) {k, step+k, 2*step+k, 3*step+k};
|
||||
#else // HV_SIMD_NEON
|
||||
o->v = k;
|
||||
#endif
|
||||
}
|
||||
|
||||
hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse) {
|
||||
sVari_update(o, k, step, reverse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m) {
|
||||
if (msg_isFloat(m,0)) {
|
||||
sVari_update(o, (int) msg_getFloat(m,0), msg_isFloat(m,1) ? (int) msg_getFloat(m,1) : 0, msg_getNumElements(m) == 3);
|
||||
}
|
||||
}
|
||||
94
delay_simple/c/HvSignalVar.h
Normal file
94
delay_simple/c/HvSignalVar.h
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_SIGNAL_VAR_H_
|
||||
#define _HEAVY_SIGNAL_VAR_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// __var~f, __varread~f, __varwrite~f
|
||||
|
||||
typedef struct SignalVarf {
|
||||
hv_bufferf_t v;
|
||||
} SignalVarf;
|
||||
|
||||
hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse);
|
||||
|
||||
static inline void __hv_varread_f(SignalVarf *o, hv_bOutf_t bOut) {
|
||||
*bOut = o->v;
|
||||
}
|
||||
|
||||
static inline void __hv_varwrite_f(SignalVarf *o, hv_bInf_t bIn) {
|
||||
o->v = bIn;
|
||||
}
|
||||
|
||||
void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m);
|
||||
|
||||
|
||||
|
||||
// __var~i, __varread~i, __varwrite~i
|
||||
|
||||
typedef struct SignalVari {
|
||||
hv_bufferi_t v;
|
||||
} SignalVari;
|
||||
|
||||
hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse);
|
||||
|
||||
static inline void __hv_varread_i(SignalVari *o, hv_bOuti_t bOut) {
|
||||
*bOut = o->v;
|
||||
}
|
||||
|
||||
static inline void __hv_varwrite_i(SignalVari *o, hv_bIni_t bIn) {
|
||||
o->v = bIn;
|
||||
}
|
||||
|
||||
void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m);
|
||||
|
||||
|
||||
|
||||
// __var_k~f, __var_k~i
|
||||
|
||||
#if HV_SIMD_AVX
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_h,_g,_f,_e,_d,_c,_b,_a)
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_a,_b,_c,_d,_e,_f,_g,_h)
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_h,_g,_f,_e,_d,_c,_b,_a)
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_a,_b,_c,_d,_e,_f,_g,_h)
|
||||
#elif HV_SIMD_SSE
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_d,_c,_b,_a)
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_a,_b,_c,_d)
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_d,_c,_b,_a)
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_a,_b,_c,_d)
|
||||
#elif HV_SIMD_NEON
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_a,_b,_c,_d})
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_d,_c,_b,_a})
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_a,_b,_c,_d})
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_d,_c,_b,_a})
|
||||
#else // HV_SIMD_NONE
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_SIGNAL_VAR_H_
|
||||
110
delay_simple/c/HvTable.c
Normal file
110
delay_simple/c/HvTable.c
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvTable.h"
|
||||
#include "HvMessage.h"
|
||||
|
||||
hv_size_t hTable_init(HvTable *o, int length) {
|
||||
o->length = length;
|
||||
// true size of the table is always an integer multple of HV_N_SIMD
|
||||
o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
|
||||
// add an extra length for mirroring
|
||||
o->allocated = o->size + HV_N_SIMD;
|
||||
o->head = 0;
|
||||
hv_size_t numBytes = o->allocated * sizeof(float);
|
||||
o->buffer = (float *) hv_malloc(numBytes);
|
||||
hv_assert(o->buffer != NULL);
|
||||
hv_memclear(o->buffer, numBytes);
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
hv_size_t hTable_initWithData(HvTable *o, int length, const float *data) {
|
||||
o->length = length;
|
||||
o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
|
||||
o->allocated = o->size + HV_N_SIMD;
|
||||
o->head = 0;
|
||||
hv_size_t numBytes = o->size * sizeof(float);
|
||||
o->buffer = (float *) hv_malloc(numBytes);
|
||||
hv_assert(o->buffer != NULL);
|
||||
hv_memclear(o->buffer, numBytes);
|
||||
hv_memcpy(o->buffer, data, length*sizeof(float));
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) {
|
||||
o->length = length;
|
||||
o->size = length;
|
||||
o->allocated = length;
|
||||
o->buffer = data;
|
||||
o->head = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hTable_free(HvTable *o) {
|
||||
hv_free(o->buffer);
|
||||
}
|
||||
|
||||
int hTable_resize(HvTable *o, hv_uint32_t newLength) {
|
||||
// TODO(mhroth): update context with memory allocated by table
|
||||
// NOTE(mhroth): mirrored bytes are not necessarily carried over
|
||||
const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
|
||||
if (newSize == o->size) return 0; // early exit if no change in size
|
||||
const hv_uint32_t oldSizeBytes = (hv_uint32_t) (o->size * sizeof(float));
|
||||
const hv_uint32_t newAllocated = newSize + HV_N_SIMD;
|
||||
const hv_uint32_t newAllocatedBytes = (hv_uint32_t) (newAllocated * sizeof(float));
|
||||
|
||||
float *b = (float *) hv_realloc(o->buffer, newAllocatedBytes);
|
||||
hv_assert(b != NULL); // error while reallocing!
|
||||
// ensure that hv_realloc has given us a correctly aligned buffer
|
||||
if ((((hv_uintptr_t) (const void *) b) & ((0x1<<HV_N_SIMD)-1)) == 0) {
|
||||
if (newSize > o->size) {
|
||||
hv_memclear(b + o->size, (newAllocated - o->size) * sizeof(float)); // clear new parts of the buffer
|
||||
}
|
||||
o->buffer = b;
|
||||
} else {
|
||||
// if not, we have to re-malloc ourselves
|
||||
char *c = (char *) hv_malloc(newAllocatedBytes);
|
||||
hv_assert(c != NULL); // error while allocating new buffer!
|
||||
if (newAllocatedBytes > oldSizeBytes) {
|
||||
hv_memcpy(c, b, oldSizeBytes);
|
||||
hv_memclear(c + oldSizeBytes, newAllocatedBytes - oldSizeBytes);
|
||||
} else {
|
||||
hv_memcpy(c, b, newAllocatedBytes);
|
||||
}
|
||||
hv_free(b);
|
||||
o->buffer = (float *) c;
|
||||
}
|
||||
o->length = newLength;
|
||||
o->size = newSize;
|
||||
o->allocated = newAllocated;
|
||||
return (int) (newAllocated - oldSizeBytes - (HV_N_SIMD*sizeof(float)));
|
||||
}
|
||||
|
||||
void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) {
|
||||
hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space
|
||||
|
||||
// send out the new size of the table
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o));
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
|
||||
else if (msg_compareSymbol(m,0,"mirror")) {
|
||||
hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float));
|
||||
}
|
||||
}
|
||||
88
delay_simple/c/HvTable.h
Normal file
88
delay_simple/c/HvTable.h
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_TABLE_H_
|
||||
#define _HEAVY_TABLE_H_
|
||||
|
||||
#include "HvHeavy.h"
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct HvTable {
|
||||
float *buffer;
|
||||
// the number of values that the table is requested to have
|
||||
hv_uint32_t length;
|
||||
|
||||
// the number of usable values that the table actually has
|
||||
// this is always an even multiple of HV_N_SIMD
|
||||
hv_uint32_t size;
|
||||
|
||||
// Note that the true size of the table is (size + HV_N_SIMD),
|
||||
// with the trailing values used by the system, e.g. to create a circular
|
||||
// buffer
|
||||
hv_uint32_t allocated;
|
||||
|
||||
hv_uint32_t head; // the most recently written point
|
||||
} HvTable;
|
||||
|
||||
hv_size_t hTable_init(HvTable *o, int length);
|
||||
|
||||
hv_size_t hTable_initWithData(HvTable *o, int length, const float *data);
|
||||
|
||||
hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data);
|
||||
|
||||
void hTable_free(HvTable *o);
|
||||
|
||||
int hTable_resize(HvTable *o, hv_uint32_t newLength);
|
||||
|
||||
void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
static inline float *hTable_getBuffer(HvTable *o) {
|
||||
return o->buffer;
|
||||
}
|
||||
|
||||
// the user-requested length of the table (number of floats)
|
||||
static inline hv_uint32_t hTable_getLength(HvTable *o) {
|
||||
return o->length;
|
||||
}
|
||||
|
||||
// the usable length of the table (an even multiple of HV_N_SIMD)
|
||||
static inline hv_uint32_t hTable_getSize(HvTable *o) {
|
||||
return o->size;
|
||||
}
|
||||
|
||||
// the number of floats allocated to this table (usually size + HV_N_SIMD)
|
||||
static inline hv_uint32_t hTable_getAllocated(HvTable *o) {
|
||||
return o->allocated;
|
||||
}
|
||||
|
||||
static inline hv_uint32_t hTable_getHead(HvTable *o) {
|
||||
return o->head;
|
||||
}
|
||||
|
||||
static inline void hTable_setHead(HvTable *o, hv_uint32_t head) {
|
||||
o->head = head;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_TABLE_H_
|
||||
54
delay_simple/c/HvUtils.c
Normal file
54
delay_simple/c/HvUtils.c
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvUtils.h"
|
||||
|
||||
hv_uint32_t hv_string_to_hash(const char *str) {
|
||||
// this hash is based MurmurHash2
|
||||
// http://en.wikipedia.org/wiki/MurmurHash
|
||||
// https://sites.google.com/site/murmurhash/
|
||||
static const hv_uint32_t n = 0x5bd1e995;
|
||||
static const hv_int32_t r = 24;
|
||||
|
||||
if (str == NULL) return 0;
|
||||
|
||||
hv_uint32_t len = (hv_uint32_t) hv_strlen(str);
|
||||
hv_uint32_t x = len; // seed (0) ^ len
|
||||
|
||||
while (len >= 4) {
|
||||
#if HV_EMSCRIPTEN
|
||||
hv_uint32_t k = str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24);
|
||||
#else
|
||||
hv_uint32_t k = *((hv_uint32_t *) str);
|
||||
#endif
|
||||
k *= n;
|
||||
k ^= (k >> r);
|
||||
k *= n;
|
||||
x *= n;
|
||||
x ^= k;
|
||||
str += 4; len -= 4;
|
||||
}
|
||||
switch (len) {
|
||||
case 3: x ^= (str[2] << 16);
|
||||
case 2: x ^= (str[1] << 8);
|
||||
case 1: x ^= str[0]; x *= n;
|
||||
default: break;
|
||||
}
|
||||
x ^= (x >> 13);
|
||||
x *= n;
|
||||
x ^= (x >> 15);
|
||||
return x;
|
||||
}
|
||||
317
delay_simple/c/HvUtils.h
Normal file
317
delay_simple/c/HvUtils.h
Normal file
@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 || _MSC_VER
|
||||
#define HV_WIN 1
|
||||
#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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// type definitions
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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 <immintrin.h>
|
||||
#elif HV_SIMD_NEON
|
||||
#include <arm_neon.h>
|
||||
#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 <string.h>
|
||||
#define hv_strlen(a) strlen(a)
|
||||
#define hv_strcmp(a, b) strcmp(a, b)
|
||||
#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__)
|
||||
#if HV_WIN
|
||||
#define hv_strncpy(_dst, _src, _len) strncpy_s(_dst, _len, _src, _TRUNCATE)
|
||||
#else
|
||||
#define hv_strncpy(_dst, _src, _len) strncpy(_dst, _src, _len)
|
||||
#endif
|
||||
|
||||
// Memory management
|
||||
#define hv_memcpy(a, b, c) memcpy(a, b, c)
|
||||
#define hv_memclear(a, b) memset(a, 0, b)
|
||||
#if HV_WIN
|
||||
#include <malloc.h>
|
||||
#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_realloc(a, b) realloc(a, b)
|
||||
#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 <mm_malloc.h>
|
||||
#define hv_malloc(_n) _mm_malloc(_n, 32)
|
||||
#define hv_free(x) _mm_free(x)
|
||||
#elif HV_SIMD_SSE
|
||||
#include <mm_malloc.h>
|
||||
#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
|
||||
#else
|
||||
#include <alloca.h>
|
||||
#define hv_alloca(_n) alloca(_n)
|
||||
#define hv_realloc(a, b) realloc(a, b)
|
||||
#if HV_SIMD_AVX
|
||||
#define hv_malloc(_n) aligned_alloc(32, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#elif HV_SIMD_SSE
|
||||
#define hv_malloc(_n) aligned_alloc(16, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#elif HV_SIMD_NEON
|
||||
#if HV_ANDROID
|
||||
#define hv_malloc(_n) memalign(16, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#else
|
||||
#define hv_malloc(_n) aligned_alloc(16, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#endif
|
||||
#else // HV_SIMD_NONE
|
||||
#define hv_malloc(_n) malloc(_n)
|
||||
#define hv_free(_n) free(_n)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Assert
|
||||
#include <assert.h>
|
||||
#define hv_assert(e) assert(e)
|
||||
|
||||
// Export and Inline
|
||||
#if HV_WIN
|
||||
#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
|
||||
#include <math.h>
|
||||
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)
|
||||
#define hv_sin_f(a) sinf(a)
|
||||
#define hv_sinh_f(a) sinhf(a)
|
||||
#define hv_cos_f(a) cosf(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_exp_f(a) expf(a)
|
||||
#define hv_abs_f(a) fabsf(a)
|
||||
#define hv_sqrt_f(a) sqrtf(a)
|
||||
#define hv_log_f(a) logf(a)
|
||||
#define hv_ceil_f(a) ceilf(a)
|
||||
#define hv_floor_f(a) floorf(a)
|
||||
#define hv_round_f(a) roundf(a)
|
||||
#define hv_pow_f(a, b) powf(a, b)
|
||||
#if HV_EMSCRIPTEN
|
||||
#define hv_fma_f(a, b, c) ((a*b)+c) // emscripten does not support fmaf (yet?)
|
||||
#else
|
||||
#define hv_fma_f(a, b, c) fmaf(a, b, c)
|
||||
#endif
|
||||
#if HV_WIN
|
||||
// finds ceil(log2(x))
|
||||
#include <intrin.h>
|
||||
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 <windows.h>
|
||||
#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 __cplusplus
|
||||
#include <atomic>
|
||||
#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(<stdatomic.h>)
|
||||
#include <stdatomic.h>
|
||||
#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_
|
||||
1
delay_simple/hv/dpf_delay_simple.hv.json
Normal file
1
delay_simple/hv/dpf_delay_simple.hv.json
Normal file
File diff suppressed because one or more lines are too long
1
delay_simple/ir/delay_simple.heavy.ir.json
Normal file
1
delay_simple/ir/delay_simple.heavy.ir.json
Normal file
File diff suppressed because one or more lines are too long
27
delay_simple/plugin/README.md
Normal file
27
delay_simple/plugin/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Distrho Plugin Format
|
||||
|
||||
This output is for the Distrho Plugin Format ([DPF](https://github.com/DISTRHO/DPF)), and can be used to build LV2, VST2 and jack standalone versions of your Heavy code.
|
||||
|
||||
# Build Instructions
|
||||
|
||||
Make sure you have a (recent) DPF in the root of your output directory
|
||||
|
||||
```bash
|
||||
$ cd <out_dir>
|
||||
$ git clone https://github.com/DISTRHO/DPF.git dpf
|
||||
```
|
||||
|
||||
Then compile the plugins from the source folder:
|
||||
|
||||
```bash
|
||||
$ make
|
||||
```
|
||||
|
||||
This will result in an `bin/` folder with all binary assets.
|
||||
|
||||
* LV2 - move `bin/<plugin>.lv2/` folder to your local `~/.lv2/` dir
|
||||
* VST2 - move `bin/<plugin>-vst.so`, can be placed directly into your `~/.vst/` dir
|
||||
|
||||
## Jack
|
||||
|
||||
The Jack binary can be executed in place and used to test functionality `./bin/<plugin>`. Currently there is no UI, so this is not recommended. You will have to be running jack in order to use this.
|
||||
1
delay_simple/plugin/build.json
Normal file
1
delay_simple/plugin/build.json
Normal file
@ -0,0 +1 @@
|
||||
{"linux": {"x64": {"args": [["-j"]], "projectDir": ["linux"], "binaryDir": ["build", "linux", "x64", "release"]}}}
|
||||
52
delay_simple/plugin/source/DistrhoPluginInfo.h
Normal file
52
delay_simple/plugin/source/DistrhoPluginInfo.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define DISTRHO_PLUGIN_NAME "delay_simple"
|
||||
|
||||
#define DISTRHO_PLUGIN_URI "http://wasted.audio/lv2/plugin/delay_simple"
|
||||
|
||||
#define DISTRHO_PLUGIN_NUM_INPUTS 2
|
||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2
|
||||
#define DISTRHO_PLUGIN_IS_SYNTH 0
|
||||
#define DISTRHO_PLUGIN_HAS_UI 0
|
||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1
|
||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 0
|
||||
#define DISTRHO_PLUGIN_WANT_STATE 0
|
||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1
|
||||
#define DISTRHO_PLUGIN_WANT_FULL_STATE 0
|
||||
#define DISTRHO_PLUGIN_WANT_MIDI_INPUT 0
|
||||
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0
|
||||
|
||||
// for level monitoring
|
||||
#define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0
|
||||
264
delay_simple/plugin/source/HeavyContext.cpp
Normal file
264
delay_simple/plugin/source/HeavyContext.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HeavyContext.hpp"
|
||||
#include "HvTable.h"
|
||||
|
||||
void defaultSendHook(HeavyContextInterface *context,
|
||||
const char *sendName, hv_uint32_t sendHash, const HvMessage *msg) {
|
||||
HeavyContext *thisContext = reinterpret_cast<HeavyContext *>(context);
|
||||
const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(msg) - sizeof(HvMessage);
|
||||
ReceiverMessagePair *p = reinterpret_cast<ReceiverMessagePair *>(hLp_getWriteBuffer(&thisContext->outQueue, numBytes));
|
||||
if (p != nullptr) {
|
||||
p->receiverHash = sendHash;
|
||||
msg_copyToBuffer(msg, (char *) &p->msg, msg_getSize(msg));
|
||||
hLp_produce(&thisContext->outQueue, numBytes);
|
||||
} else {
|
||||
hv_assert(false &&
|
||||
"::defaultSendHook - The out message queue is full and cannot accept more messages until they "
|
||||
"have been processed. Try increasing the outQueueKb size in the new_with_options() constructor.");
|
||||
}
|
||||
}
|
||||
|
||||
HeavyContext::HeavyContext(double sampleRate, int poolKb, int inQueueKb, int outQueueKb) :
|
||||
sampleRate(sampleRate) {
|
||||
|
||||
hv_assert(sampleRate > 0.0); // sample rate must be positive
|
||||
hv_assert(poolKb > 0);
|
||||
hv_assert(inQueueKb > 0);
|
||||
hv_assert(outQueueKb >= 0);
|
||||
|
||||
blockStartTimestamp = 0;
|
||||
printHook = nullptr;
|
||||
userData = nullptr;
|
||||
|
||||
// if outQueueKb is positive, then the outQueue is allocated and the default sendhook is set.
|
||||
// Otherwise outQueue and the sendhook are set to NULL.
|
||||
sendHook = (outQueueKb > 0) ? &defaultSendHook : nullptr;
|
||||
|
||||
HV_SPINLOCK_RELEASE(inQueueLock);
|
||||
HV_SPINLOCK_RELEASE(outQueueLock);
|
||||
|
||||
numBytes = sizeof(HeavyContext);
|
||||
|
||||
numBytes += mq_initWithPoolSize(&mq, poolKb);
|
||||
numBytes += hLp_init(&inQueue, inQueueKb * 1024);
|
||||
numBytes += hLp_init(&outQueue, outQueueKb * 1024); // outQueueKb value of 0 sets everything to NULL
|
||||
}
|
||||
|
||||
HeavyContext::~HeavyContext() {
|
||||
mq_free(&mq);
|
||||
hLp_free(&inQueue);
|
||||
hLp_free(&outQueue);
|
||||
}
|
||||
|
||||
bool HeavyContext::sendBangToReceiver(hv_uint32_t receiverHash) {
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithBang(m, 0);
|
||||
bool success = sendMessageToReceiver(receiverHash, 0.0, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendFloatToReceiver(hv_uint32_t receiverHash, float f) {
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(m, 0, f);
|
||||
bool success = sendMessageToReceiver(receiverHash, 0.0, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendSymbolToReceiver(hv_uint32_t receiverHash, const char *s) {
|
||||
hv_assert(s != nullptr);
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithSymbol(m, 0, (char *) s);
|
||||
bool success = sendMessageToReceiver(receiverHash, 0.0, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
|
||||
hv_assert(delayMs >= 0.0);
|
||||
hv_assert(format != nullptr);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int numElem = (int) hv_strlen(format);
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
|
||||
msg_init(m, numElem, blockStartTimestamp + (hv_uint32_t) (hv_max_d(0.0, delayMs)*getSampleRate()/1000.0));
|
||||
for (int i = 0; i < numElem; i++) {
|
||||
switch (format[i]) {
|
||||
case 'b': msg_setBang(m, i); break;
|
||||
case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
|
||||
case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
|
||||
case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
bool success = sendMessageToReceiver(receiverHash, delayMs, m);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool HeavyContext::sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
|
||||
hv_assert(delayMs >= 0.0);
|
||||
hv_assert(m != nullptr);
|
||||
|
||||
const hv_uint32_t timestamp = blockStartTimestamp +
|
||||
(hv_uint32_t) (hv_max_d(0.0, delayMs)*(getSampleRate()/1000.0));
|
||||
|
||||
ReceiverMessagePair *p = nullptr;
|
||||
HV_SPINLOCK_ACQUIRE(inQueueLock);
|
||||
const hv_uint32_t numBytes = sizeof(ReceiverMessagePair) + msg_getSize(m) - sizeof(HvMessage);
|
||||
p = (ReceiverMessagePair *) hLp_getWriteBuffer(&inQueue, numBytes);
|
||||
if (p != nullptr) {
|
||||
p->receiverHash = receiverHash;
|
||||
msg_copyToBuffer(m, (char *) &p->msg, msg_getSize(m));
|
||||
msg_setTimestamp(&p->msg, timestamp);
|
||||
hLp_produce(&inQueue, numBytes);
|
||||
} else {
|
||||
hv_assert(false &&
|
||||
"::sendMessageToReceiver - The input message queue is full and cannot accept more messages until they "
|
||||
"have been processed. Try increasing the inQueueKb size in the new_with_options() constructor.");
|
||||
}
|
||||
HV_SPINLOCK_RELEASE(inQueueLock);
|
||||
return (p != nullptr);
|
||||
}
|
||||
|
||||
bool HeavyContext::cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
return mq_removeMessage(&mq, m, sendMessage);
|
||||
}
|
||||
|
||||
HvMessage *HeavyContext::scheduleMessageForObject(const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex) {
|
||||
HvMessage *n = mq_addMessageByTimestamp(&mq, m, letIndex, sendMessage);
|
||||
return n;
|
||||
}
|
||||
|
||||
float *HeavyContext::getBufferForTable(hv_uint32_t tableHash) {
|
||||
HvTable *t = getTableForHash(tableHash);
|
||||
if (t != nullptr) {
|
||||
return hTable_getBuffer(t);
|
||||
} else return nullptr;
|
||||
}
|
||||
|
||||
int HeavyContext::getLengthForTable(hv_uint32_t tableHash) {
|
||||
HvTable *t = getTableForHash(tableHash);
|
||||
if (t != nullptr) {
|
||||
return hTable_getLength(t);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
bool HeavyContext::setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
|
||||
HvTable *t = getTableForHash(tableHash);
|
||||
if (t != nullptr) {
|
||||
hTable_resize(t, newSampleLength);
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
void HeavyContext::lockAcquire() {
|
||||
HV_SPINLOCK_ACQUIRE(inQueueLock);
|
||||
}
|
||||
|
||||
bool HeavyContext::lockTry() {
|
||||
HV_SPINLOCK_TRY(inQueueLock);
|
||||
}
|
||||
|
||||
void HeavyContext::lockRelease() {
|
||||
HV_SPINLOCK_RELEASE(inQueueLock);
|
||||
}
|
||||
|
||||
void HeavyContext::setInputMessageQueueSize(int inQueueKb) {
|
||||
hv_assert(inQueueKb > 0);
|
||||
hLp_free(&inQueue);
|
||||
hLp_init(&inQueue, inQueueKb*1024);
|
||||
}
|
||||
|
||||
void HeavyContext::setOutputMessageQueueSize(int outQueueKb) {
|
||||
hv_assert(outQueueKb > 0);
|
||||
hLp_free(&outQueue);
|
||||
hLp_init(&outQueue, outQueueKb*1024);
|
||||
}
|
||||
|
||||
bool HeavyContext::getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) {
|
||||
*destinationHash = 0;
|
||||
ReceiverMessagePair *p = nullptr;
|
||||
hv_assert((sendHook == &defaultSendHook) &&
|
||||
"::getNextSentMessage - this function won't do anything if the msg outQueue "
|
||||
"size is 0, or you've overriden the default sendhook.");
|
||||
if (sendHook == &defaultSendHook) {
|
||||
HV_SPINLOCK_ACQUIRE(outQueueLock);
|
||||
if (hLp_hasData(&outQueue)) {
|
||||
hv_uint32_t numBytes = 0;
|
||||
p = reinterpret_cast<ReceiverMessagePair *>(hLp_getReadBuffer(&outQueue, &numBytes));
|
||||
hv_assert((p != nullptr) && "::getNextSentMessage - something bad happened.");
|
||||
hv_assert(numBytes >= sizeof(ReceiverMessagePair));
|
||||
hv_assert((numBytes <= msgLengthBytes) &&
|
||||
"::getNextSentMessage - the sent message is bigger than the message "
|
||||
"passed to handle it.");
|
||||
*destinationHash = p->receiverHash;
|
||||
hv_memcpy(outMsg, &p->msg, numBytes);
|
||||
hLp_consume(&outQueue);
|
||||
}
|
||||
HV_SPINLOCK_RELEASE(outQueueLock);
|
||||
}
|
||||
return (p != nullptr);
|
||||
}
|
||||
|
||||
hv_uint32_t HeavyContext::getHashForString(const char *str) {
|
||||
return hv_string_to_hash(str);
|
||||
}
|
||||
|
||||
HvTable *_hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return reinterpret_cast<HeavyContext *>(c)->getTableForHash(tableHash);
|
||||
}
|
||||
|
||||
void _hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
|
||||
hv_assert(c != nullptr);
|
||||
reinterpret_cast<HeavyContext *>(c)->scheduleMessageForReceiver(receiverHash, m);
|
||||
}
|
||||
|
||||
HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex) {
|
||||
hv_assert(c != nullptr);
|
||||
HvMessage *n = reinterpret_cast<HeavyContext *>(c)->scheduleMessageForObject(
|
||||
m, sendMessage, letIndex);
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
return _hv_table_get(c, tableHash);
|
||||
}
|
||||
|
||||
void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m) {
|
||||
_hv_scheduleMessageForReceiver(c, receiverHash, m);
|
||||
}
|
||||
|
||||
HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex) {
|
||||
return _hv_scheduleMessageForObject(c, m, sendMessage, letIndex);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
107
delay_simple/plugin/source/HeavyContext.hpp
Normal file
107
delay_simple/plugin/source/HeavyContext.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTEXT_H_
|
||||
#define _HEAVY_CONTEXT_H_
|
||||
|
||||
#include "HeavyContextInterface.hpp"
|
||||
#include "HvLightPipe.h"
|
||||
#include "HvMessageQueue.h"
|
||||
#include "HvMath.h"
|
||||
|
||||
struct HvTable;
|
||||
|
||||
class HeavyContext : public HeavyContextInterface {
|
||||
|
||||
public:
|
||||
HeavyContext(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
|
||||
virtual ~HeavyContext();
|
||||
|
||||
int getSize() override { return (int) numBytes; }
|
||||
|
||||
double getSampleRate() override { return sampleRate; }
|
||||
|
||||
hv_uint32_t getCurrentSample() override { return blockStartTimestamp; }
|
||||
float samplesToMilliseconds(hv_uint32_t numSamples) override { return (float) (1000.0*numSamples/sampleRate); }
|
||||
hv_uint32_t millisecondsToSamples(float ms) override { return (hv_uint32_t) (hv_max_f(0.0f,ms)*sampleRate/1000.0); }
|
||||
|
||||
void setUserData(void *x) override { userData = x; }
|
||||
void *getUserData() override { return userData; }
|
||||
|
||||
// hook management
|
||||
void setSendHook(HvSendHook_t *f) override { sendHook = f; }
|
||||
HvSendHook_t *getSendHook() override { return sendHook; }
|
||||
|
||||
void setPrintHook(HvPrintHook_t *f) override { printHook = f; }
|
||||
HvPrintHook_t *getPrintHook() override { return printHook; }
|
||||
|
||||
// message scheduling
|
||||
bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) override;
|
||||
bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) override;
|
||||
bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) override;
|
||||
bool sendBangToReceiver(hv_uint32_t receiverHash) override;
|
||||
bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) override;
|
||||
bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) override;
|
||||
|
||||
// table manipulation
|
||||
float *getBufferForTable(hv_uint32_t tableHash) override;
|
||||
int getLengthForTable(hv_uint32_t tableHash) override;
|
||||
bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) override;
|
||||
|
||||
// lock control
|
||||
void lockAcquire() override;
|
||||
bool lockTry() override;
|
||||
void lockRelease() override;
|
||||
|
||||
// message queue management
|
||||
void setInputMessageQueueSize(int inQueueKb) override;
|
||||
void setOutputMessageQueueSize(int outQueueKb) override;
|
||||
bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLength) override;
|
||||
|
||||
// utility functions
|
||||
static hv_uint32_t getHashForString(const char *str);
|
||||
|
||||
protected:
|
||||
virtual HvTable *getTableForHash(hv_uint32_t tableHash) = 0;
|
||||
friend HvTable *_hv_table_get(HeavyContextInterface *, hv_uint32_t);
|
||||
|
||||
virtual void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) = 0;
|
||||
friend void _hv_scheduleMessageForReceiver(HeavyContextInterface *, hv_uint32_t, HvMessage *);
|
||||
|
||||
HvMessage *scheduleMessageForObject(const HvMessage *,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int);
|
||||
friend HvMessage *_hv_scheduleMessageForObject(HeavyContextInterface *, const HvMessage *,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int);
|
||||
|
||||
friend void defaultSendHook(HeavyContextInterface *, const char *, hv_uint32_t, const HvMessage *);
|
||||
|
||||
// object state
|
||||
double sampleRate;
|
||||
hv_uint32_t blockStartTimestamp;
|
||||
hv_size_t numBytes;
|
||||
HvMessageQueue mq;
|
||||
HvSendHook_t *sendHook;
|
||||
HvPrintHook_t *printHook;
|
||||
void *userData;
|
||||
HvLightPipe inQueue;
|
||||
HvLightPipe outQueue;
|
||||
hv_atomic_bool inQueueLock;
|
||||
hv_atomic_bool outQueueLock;
|
||||
};
|
||||
|
||||
#endif // _HEAVY_CONTEXT_H_
|
||||
291
delay_simple/plugin/source/HeavyContextInterface.hpp
Normal file
291
delay_simple/plugin/source/HeavyContextInterface.hpp
Normal file
@ -0,0 +1,291 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTEXT_INTERFACE_H_
|
||||
#define _HEAVY_CONTEXT_INTERFACE_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifndef _HEAVY_DECLARATIONS_
|
||||
#define _HEAVY_DECLARATIONS_
|
||||
|
||||
class HeavyContextInterface;
|
||||
struct HvMessage;
|
||||
|
||||
typedef enum {
|
||||
HV_PARAM_TYPE_PARAMETER_IN,
|
||||
HV_PARAM_TYPE_PARAMETER_OUT,
|
||||
HV_PARAM_TYPE_EVENT_IN,
|
||||
HV_PARAM_TYPE_EVENT_OUT
|
||||
} HvParameterType;
|
||||
|
||||
typedef struct HvParameterInfo {
|
||||
const char *name; // the human readable parameter name
|
||||
hv_uint32_t hash; // an integer identified used by heavy for this parameter
|
||||
HvParameterType type; // type of this parameter
|
||||
float minVal; // the minimum value of this parameter
|
||||
float maxVal; // the maximum value of this parameter
|
||||
float defaultVal; // the default value of this parameter
|
||||
} HvParameterInfo;
|
||||
|
||||
typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
|
||||
typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
|
||||
|
||||
#endif // _HEAVY_DECLARATIONS_
|
||||
|
||||
|
||||
|
||||
class HeavyContextInterface {
|
||||
|
||||
public:
|
||||
HeavyContextInterface() {}
|
||||
virtual ~HeavyContextInterface() {};
|
||||
|
||||
/** Returns the read-only user-assigned name of this patch. */
|
||||
virtual const char *getName() = 0;
|
||||
|
||||
/** Returns the number of input channels with which this context has been configured. */
|
||||
virtual int getNumInputChannels() = 0;
|
||||
|
||||
/** Returns the number of output channels with which this context has been configured. */
|
||||
virtual int getNumOutputChannels() = 0;
|
||||
|
||||
/**
|
||||
* Returns the total size in bytes of the context.
|
||||
* This value may change if tables are resized.
|
||||
*/
|
||||
virtual int getSize() = 0;
|
||||
|
||||
/** Returns the sample rate with which this context has been configured. */
|
||||
virtual double getSampleRate() = 0;
|
||||
|
||||
/** Returns the current patch time in samples. This value is always exact. */
|
||||
virtual hv_uint32_t getCurrentSample() = 0;
|
||||
virtual float samplesToMilliseconds(hv_uint32_t numSamples) = 0;
|
||||
|
||||
/** Converts milliseconds to samples. Input is limited to non-negative range. */
|
||||
virtual hv_uint32_t millisecondsToSamples(float ms) = 0;
|
||||
|
||||
/** Sets a user-definable value. This value is never manipulated by Heavy. */
|
||||
virtual void setUserData(void *x) = 0;
|
||||
|
||||
/** Returns the user-defined data. */
|
||||
virtual void *getUserData() = 0;
|
||||
|
||||
/**
|
||||
* Set the send hook. The function is called whenever a message is sent to any send object.
|
||||
* Messages returned by this function should NEVER be freed. If the message must persist, call
|
||||
* hv_msg_copy() first.
|
||||
*/
|
||||
virtual void setSendHook(HvSendHook_t *f) = 0;
|
||||
|
||||
/** Returns the send hook, or NULL if unset. */
|
||||
virtual HvSendHook_t *getSendHook() = 0;
|
||||
|
||||
/** Set the print hook. The function is called whenever a message is sent to a print object. */
|
||||
virtual void setPrintHook(HvPrintHook_t *f) = 0;
|
||||
|
||||
/** Returns the print hook, or NULL if unset. */
|
||||
virtual HvPrintHook_t *getPrintHook() = 0;
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [[LLLL][RRRR]]
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
virtual int process(float **inputBuffers, float **outputBuffer, int n) = 0;
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LLLLRRRR]
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
virtual int processInline(float *inputBuffers, float *outputBuffer, int n) = 0;
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LRLRLRLR]
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
virtual int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) = 0;
|
||||
|
||||
/**
|
||||
* Sends a formatted message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendMessageToReceiver(hv_uint32_t receiverHash, double delayMs, HvMessage *m) = 0;
|
||||
|
||||
/**
|
||||
* Sends a formatted message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendMessageToReceiverV(hv_uint32_t receiverHash, double delayMs, const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* A convenience function to send a float to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendFloatToReceiver(hv_uint32_t receiverHash, float f) = 0;
|
||||
|
||||
/**
|
||||
* A convenience function to send a bang to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendBangToReceiver(hv_uint32_t receiverHash) = 0;
|
||||
|
||||
/**
|
||||
* A convenience function to send a symbol to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
virtual bool sendSymbolToReceiver(hv_uint32_t receiverHash, const char *symbol) = 0;
|
||||
|
||||
/**
|
||||
* Cancels a previously scheduled message.
|
||||
*
|
||||
* @param sendMessage May be NULL.
|
||||
*/
|
||||
virtual bool cancelMessage(HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)=nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Returns information about each parameter such as name, hash, and range.
|
||||
* The total number of parameters is always returned.
|
||||
*
|
||||
* @param index The parameter index.
|
||||
* @param info A pointer to a HvParameterInfo struct. May be null.
|
||||
*
|
||||
* @return The total number of parameters.
|
||||
*/
|
||||
virtual int getParameterInfo(int index, HvParameterInfo *info) = 0;
|
||||
|
||||
/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
|
||||
virtual float *getBufferForTable(hv_uint32_t tableHash) = 0;
|
||||
|
||||
/** Returns the length of this table in samples. */
|
||||
virtual int getLengthForTable(hv_uint32_t tableHash) = 0;
|
||||
|
||||
/**
|
||||
* Resizes the table to the given length.
|
||||
*
|
||||
* Existing contents are copied to the new table. Remaining space is cleared
|
||||
* if the table is longer than the original, truncated otherwise.
|
||||
*
|
||||
* @param tableHash The table identifier.
|
||||
* @param newSampleLength The new length of the table, in samples.
|
||||
*
|
||||
* @return False if the table could not be found. True otherwise.
|
||||
*/
|
||||
virtual bool setLengthForTable(hv_uint32_t tableHash, hv_uint32_t newSampleLength) = 0;
|
||||
|
||||
/**
|
||||
* Acquire the input message queue lock.
|
||||
*
|
||||
* This function will block until the message lock as been acquired.
|
||||
* Typical applications will not require the use of this function.
|
||||
*/
|
||||
virtual void lockAcquire() = 0;
|
||||
|
||||
/**
|
||||
* Try to acquire the input message queue lock.
|
||||
*
|
||||
* If the lock has been acquired, hv_lock_release() must be called to release it.
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @return Returns true if the lock has been acquired, false otherwise.
|
||||
*/
|
||||
virtual bool lockTry() = 0;
|
||||
|
||||
/**
|
||||
* Release the input message queue lock.
|
||||
*
|
||||
* Typical applications will not require the use of this function.
|
||||
*/
|
||||
virtual void lockRelease() = 0;
|
||||
|
||||
/**
|
||||
* Set the size of the input message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
*
|
||||
* @param inQueueKb Must be positive i.e. at least one.
|
||||
*/
|
||||
virtual void setInputMessageQueueSize(int inQueueKb) = 0;
|
||||
|
||||
/**
|
||||
* Set the size of the output message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
* Only the default sendhook uses the outgoing message queue. If the default
|
||||
* sendhook is not being used, then this function is not useful.
|
||||
*
|
||||
* @param outQueueKb Must be postive i.e. at least one.
|
||||
*/
|
||||
virtual void setOutputMessageQueueSize(int outQueueKb) = 0;
|
||||
|
||||
/**
|
||||
* Get the next message in the outgoing queue, will also consume the message.
|
||||
* Returns false if there are no messages.
|
||||
*
|
||||
* @param destinationHash a hash of the name of the receiver the message was sent to.
|
||||
* @param outMsg message pointer that is filled by the next message contents.
|
||||
* @param msgLengthBytes max length of outMsg in bytes.
|
||||
*
|
||||
* @return True if there is a message in the outgoing queue.
|
||||
*/
|
||||
virtual bool getNextSentMessage(hv_uint32_t *destinationHash, HvMessage *outMsg, hv_size_t msgLengthBytes) = 0;
|
||||
|
||||
/** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
|
||||
static hv_uint32_t getHashForString(const char *str);
|
||||
};
|
||||
|
||||
#endif // _HEAVY_CONTEXT_INTERFACE_H_
|
||||
568
delay_simple/plugin/source/HeavyDPF_delay_simple.cpp
Normal file
568
delay_simple/plugin/source/HeavyDPF_delay_simple.cpp
Normal file
@ -0,0 +1,568 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Heavy_delay_simple.h"
|
||||
#include "HeavyDPF_delay_simple.hpp"
|
||||
#include <set>
|
||||
|
||||
|
||||
#define HV_LV2_NUM_PARAMETERS 5
|
||||
|
||||
#define HV_HASH_NOTEIN 0x67E37CA3
|
||||
#define HV_HASH_CTLIN 0x41BE0f9C
|
||||
#define HV_HASH_PGMIN 0x2E1EA03D
|
||||
#define HV_HASH_TOUCHIN 0x553925BD
|
||||
#define HV_HASH_BENDIN 0x3083F0F7
|
||||
#define HV_HASH_MIDIIN 0x149631bE
|
||||
#define HV_HASH_MIDIREALTIMEIN 0x6FFF0BCF
|
||||
|
||||
#define HV_HASH_NOTEOUT 0xD1D4AC2
|
||||
#define HV_HASH_CTLOUT 0xE5e2A040
|
||||
#define HV_HASH_PGMOUT 0x8753E39E
|
||||
#define HV_HASH_TOUCHOUT 0x476D4387
|
||||
#define HV_HASH_BENDOUT 0xE8458013
|
||||
#define HV_HASH_MIDIOUT 0x6511DE55
|
||||
#define HV_HASH_MIDIOUTPORT 0x165707E4
|
||||
|
||||
#define MIDI_RT_CLOCK 0xF8
|
||||
#define MIDI_RT_START 0xFA
|
||||
#define MIDI_RT_CONTINUE 0xFB
|
||||
#define MIDI_RT_STOP 0xFC
|
||||
#define MIDI_RT_ACTIVESENSE 0xFE
|
||||
#define MIDI_RT_RESET 0xFF
|
||||
|
||||
// midi realtime messages
|
||||
std::set<int> mrtSet {
|
||||
MIDI_RT_CLOCK,
|
||||
MIDI_RT_START,
|
||||
MIDI_RT_CONTINUE,
|
||||
MIDI_RT_STOP,
|
||||
MIDI_RT_RESET
|
||||
};
|
||||
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Heavy Send and Print hooks
|
||||
|
||||
static void hvSendHookFunc(HeavyContextInterface *c, const char *sendName, uint32_t sendHash, const HvMessage *m)
|
||||
{
|
||||
HeavyDPF_delay_simple* plugin = (HeavyDPF_delay_simple*)c->getUserData();
|
||||
if (plugin != nullptr)
|
||||
{
|
||||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
|
||||
plugin->handleMidiSend(sendHash, m);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void hvPrintHookFunc(HeavyContextInterface *c, const char *printLabel, const char *msgString, const HvMessage *m)
|
||||
{
|
||||
char buf[64];
|
||||
char* dst = buf;
|
||||
int len = strnlen(printLabel, 48);
|
||||
dst = strncpy(dst, printLabel, len);
|
||||
dst = strcpy(dst, " ");
|
||||
dst = strncpy(dst, msgString, 63-len);
|
||||
printf("> %s \n", buf);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Main DPF plugin class
|
||||
|
||||
HeavyDPF_delay_simple::HeavyDPF_delay_simple()
|
||||
: Plugin(HV_LV2_NUM_PARAMETERS, 0, 0)
|
||||
{
|
||||
|
||||
_parameters[0] = 0.25f;
|
||||
|
||||
_parameters[1] = 500.0f;
|
||||
|
||||
_parameters[2] = 0.75f;
|
||||
|
||||
_parameters[3] = 0.75f;
|
||||
|
||||
_parameters[4] = 0.75f;
|
||||
|
||||
|
||||
_context = hv_delay_simple_new_with_options(getSampleRate(), 10, 5, 2);
|
||||
_context->setUserData(this);
|
||||
_context->setSendHook(&hvSendHookFunc);
|
||||
_context->setPrintHook(&hvPrintHookFunc);
|
||||
|
||||
|
||||
// ensure that the new context has the current parameters
|
||||
for (int i = 0; i < HV_LV2_NUM_PARAMETERS; ++i) {
|
||||
setParameterValue(i, _parameters[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HeavyDPF_delay_simple::~HeavyDPF_delay_simple() {
|
||||
hv_delay_simple_free(_context);
|
||||
}
|
||||
|
||||
void HeavyDPF_delay_simple::initParameter(uint32_t index, Parameter& parameter)
|
||||
{
|
||||
|
||||
// initialise parameters with defaults
|
||||
switch (index)
|
||||
{
|
||||
|
||||
case paramDelay_Feedback:
|
||||
parameter.name = "Delay Feedback";
|
||||
parameter.symbol = "delay_feedback";
|
||||
parameter.hints = kParameterIsAutomable
|
||||
;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 0.25f;
|
||||
break;
|
||||
|
||||
case paramDelay_Time:
|
||||
parameter.name = "Delay Time";
|
||||
parameter.symbol = "delay_time";
|
||||
parameter.hints = kParameterIsAutomable
|
||||
;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 5000.0f;
|
||||
parameter.ranges.def = 500.0f;
|
||||
break;
|
||||
|
||||
case paramDry_Volume:
|
||||
parameter.name = "Dry Volume";
|
||||
parameter.symbol = "dry_volume";
|
||||
parameter.hints = kParameterIsAutomable
|
||||
;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 0.75f;
|
||||
break;
|
||||
|
||||
case paramGain:
|
||||
parameter.name = "Gain";
|
||||
parameter.symbol = "gain";
|
||||
parameter.hints = kParameterIsAutomable
|
||||
;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 0.75f;
|
||||
break;
|
||||
|
||||
case paramWet_Volume:
|
||||
parameter.name = "Wet Volume";
|
||||
parameter.symbol = "wet_volume";
|
||||
parameter.hints = kParameterIsAutomable
|
||||
;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 0.75f;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Internal data
|
||||
|
||||
float HeavyDPF_delay_simple::getParameterValue(uint32_t index) const
|
||||
{
|
||||
|
||||
return _parameters[index];
|
||||
|
||||
}
|
||||
|
||||
void HeavyDPF_delay_simple::setParameterValue(uint32_t index, float value)
|
||||
{
|
||||
|
||||
switch (index) {
|
||||
|
||||
case 0: {
|
||||
_context->sendFloatToReceiver(
|
||||
Heavy_delay_simple::Parameter::In::DELAY_FEEDBACK,
|
||||
value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
_context->sendFloatToReceiver(
|
||||
Heavy_delay_simple::Parameter::In::DELAY_TIME,
|
||||
value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
_context->sendFloatToReceiver(
|
||||
Heavy_delay_simple::Parameter::In::DRY_VOLUME,
|
||||
value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
_context->sendFloatToReceiver(
|
||||
Heavy_delay_simple::Parameter::In::GAIN,
|
||||
value);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
_context->sendFloatToReceiver(
|
||||
Heavy_delay_simple::Parameter::In::WET_VOLUME,
|
||||
value);
|
||||
break;
|
||||
}
|
||||
|
||||
default: return;
|
||||
}
|
||||
_parameters[index] = value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Process
|
||||
|
||||
// void HeavyDPF_delay_simple::activate()
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// void HeavyDPF_delay_simple::deactivate()
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
|
||||
// -------------------------------------------------------------------
|
||||
// Midi Input handler
|
||||
|
||||
void HeavyDPF_delay_simple::handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
|
||||
{
|
||||
// Realtime events
|
||||
const TimePosition& timePos(getTimePosition());
|
||||
bool reset = false;
|
||||
|
||||
if (timePos.playing)
|
||||
{
|
||||
if (timePos.frame == 0)
|
||||
{
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0,
|
||||
"ff", (float) MIDI_RT_RESET);
|
||||
reset = true;
|
||||
}
|
||||
|
||||
if (! this->wasPlaying)
|
||||
{
|
||||
if (timePos.frame == 0)
|
||||
{
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0,
|
||||
"ff", (float) MIDI_RT_START);
|
||||
}
|
||||
if (! reset)
|
||||
{
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0,
|
||||
"ff", (float) MIDI_RT_CONTINUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this->wasPlaying)
|
||||
{
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 0,
|
||||
"ff", (float) MIDI_RT_STOP);
|
||||
}
|
||||
this->wasPlaying = timePos.playing;
|
||||
|
||||
// sending clock ticks
|
||||
if (timePos.playing && timePos.bbt.valid)
|
||||
{
|
||||
float samplesPerBeat = 60 * getSampleRate() / timePos.bbt.beatsPerMinute;
|
||||
float samplesPerTick = samplesPerBeat / 24.0;
|
||||
|
||||
/* get state */
|
||||
double nextClockTick = this->nextClockTick;
|
||||
double sampleAtCycleStart = this->sampleAtCycleStart;
|
||||
double sampleAtCycleEnd = sampleAtCycleStart + frames;
|
||||
|
||||
while (nextClockTick < sampleAtCycleEnd) {
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 1000*(nextClockTick - sampleAtCycleStart)/getSampleRate(),
|
||||
"ff", (float) MIDI_RT_CLOCK);
|
||||
nextClockTick += samplesPerTick;
|
||||
}
|
||||
|
||||
/* save variables for next cycle */
|
||||
this->sampleAtCycleStart = sampleAtCycleEnd;
|
||||
this->nextClockTick = nextClockTick;
|
||||
}
|
||||
|
||||
// Midi events
|
||||
for (uint32_t i=0; i < midiEventCount; ++i)
|
||||
{
|
||||
int status = midiEvents[i].data[0];
|
||||
int command = status & 0xF0;
|
||||
int channel = status & 0x0F;
|
||||
int data1 = midiEvents[i].data[1];
|
||||
int data2 = midiEvents[i].data[2];
|
||||
|
||||
// raw [midiin] messages
|
||||
int dataSize = *(&midiEvents[i].data + 1) - midiEvents[i].data;
|
||||
|
||||
for (int i = 0; i < dataSize; ++i) {
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIIN, 1000.0*timePos.frame/getSampleRate(), "ff",
|
||||
(float) midiEvents[i].data[i],
|
||||
(float) channel);
|
||||
}
|
||||
|
||||
if(mrtSet.find(status) != mrtSet.end())
|
||||
{
|
||||
_context->sendMessageToReceiverV(HV_HASH_MIDIREALTIMEIN, 1000.0*timePos.frame/getSampleRate(),
|
||||
"ff", (float) status);
|
||||
}
|
||||
|
||||
// typical midi messages
|
||||
switch (command) {
|
||||
case 0x80: { // note off
|
||||
_context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*timePos.frame/getSampleRate(), "fff",
|
||||
(float) data1, // pitch
|
||||
(float) 0, // velocity
|
||||
(float) channel);
|
||||
break;
|
||||
}
|
||||
case 0x90: { // note on
|
||||
_context->sendMessageToReceiverV(HV_HASH_NOTEIN, 1000.0*timePos.frame/getSampleRate(), "fff",
|
||||
(float) data1, // pitch
|
||||
(float) data2, // velocity
|
||||
(float) channel);
|
||||
break;
|
||||
}
|
||||
case 0xB0: { // control change
|
||||
_context->sendMessageToReceiverV(HV_HASH_CTLIN, 1000.0*timePos.frame/getSampleRate(), "fff",
|
||||
(float) data2, // value
|
||||
(float) data1, // cc number
|
||||
(float) channel);
|
||||
break;
|
||||
}
|
||||
case 0xC0: { // program change
|
||||
_context->sendMessageToReceiverV(HV_HASH_PGMIN, 1000.0*timePos.frame/getSampleRate(), "ff",
|
||||
(float) data1,
|
||||
(float) channel);
|
||||
break;
|
||||
}
|
||||
case 0xD0: { // aftertouch
|
||||
_context->sendMessageToReceiverV(HV_HASH_TOUCHIN, 1000.0*timePos.frame/getSampleRate(), "ff",
|
||||
(float) data1,
|
||||
(float) channel);
|
||||
break;
|
||||
}
|
||||
case 0xE0: { // pitch bend
|
||||
// combine 7bit lsb and msb into 32bit int
|
||||
hv_uint32_t value = (((hv_uint32_t) data2) << 7) | ((hv_uint32_t) data1);
|
||||
_context->sendMessageToReceiverV(HV_HASH_BENDIN, 1000.0*timePos.frame/getSampleRate(), "ff",
|
||||
(float) value,
|
||||
(float) channel);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
|
||||
// -------------------------------------------------------------------
|
||||
// Midi Send handler
|
||||
|
||||
void HeavyDPF_delay_simple::handleMidiSend(uint32_t sendHash, const HvMessage *m)
|
||||
{
|
||||
MidiEvent midiSendEvent;
|
||||
midiSendEvent.frame = 0;
|
||||
midiSendEvent.dataExt = nullptr;
|
||||
|
||||
switch(sendHash){
|
||||
case HV_HASH_NOTEOUT: // __hv_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);
|
||||
ch %= 16; // drop any pd "ports"
|
||||
|
||||
midiSendEvent.size = 3;
|
||||
if (velocity > 0){
|
||||
midiSendEvent.data[0] = 0x90 | ch; // noteon
|
||||
} else {
|
||||
midiSendEvent.data[0] = 0x80 | ch; // noteoff
|
||||
}
|
||||
midiSendEvent.data[1] = note;
|
||||
midiSendEvent.data[2] = velocity;
|
||||
|
||||
writeMidiEvent(midiSendEvent);
|
||||
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);
|
||||
ch %= 16;
|
||||
|
||||
midiSendEvent.size = 3;
|
||||
midiSendEvent.data[0] = 0xB0 | ch; // send CC
|
||||
midiSendEvent.data[1] = cc;
|
||||
midiSendEvent.data[2] = value;
|
||||
|
||||
writeMidiEvent(midiSendEvent);
|
||||
break;
|
||||
}
|
||||
case HV_HASH_PGMOUT:
|
||||
{
|
||||
uint8_t pgm = hv_msg_getFloat(m, 0);
|
||||
uint8_t ch = hv_msg_getFloat(m, 1);
|
||||
ch %= 16;
|
||||
|
||||
midiSendEvent.size = 2;
|
||||
midiSendEvent.data[0] = 0xC0 | ch; // send Program Change
|
||||
midiSendEvent.data[1] = pgm;
|
||||
|
||||
writeMidiEvent(midiSendEvent);
|
||||
break;
|
||||
}
|
||||
case HV_HASH_TOUCHOUT:
|
||||
{
|
||||
uint8_t value = hv_msg_getFloat(m, 0);
|
||||
uint8_t ch = hv_msg_getFloat(m, 1);
|
||||
ch %= 16;
|
||||
|
||||
midiSendEvent.size = 2;
|
||||
midiSendEvent.data[0] = 0xD0 | ch; // send Touch
|
||||
midiSendEvent.data[1] = value;
|
||||
|
||||
writeMidiEvent(midiSendEvent);
|
||||
break;
|
||||
}
|
||||
case HV_HASH_BENDOUT:
|
||||
{
|
||||
uint16_t value = hv_msg_getFloat(m, 0);
|
||||
uint8_t lsb = value & 0x7F;
|
||||
uint8_t msb = (value >> 7) & 0x7F;
|
||||
uint8_t ch = hv_msg_getFloat(m, 1);
|
||||
ch %= 16;
|
||||
|
||||
midiSendEvent.size = 3;
|
||||
midiSendEvent.data[0] = 0xE0 | ch; // send Bend
|
||||
midiSendEvent.data[1] = lsb;
|
||||
midiSendEvent.data[2] = msb;
|
||||
|
||||
writeMidiEvent(midiSendEvent);
|
||||
break;
|
||||
}
|
||||
case HV_HASH_MIDIOUT: // __hv_midiout
|
||||
{
|
||||
const uint8_t numElements = m->numElements;
|
||||
if (numElements <=4 )
|
||||
{
|
||||
for (int i = 0; i < numElements; ++i)
|
||||
{
|
||||
midiSendEvent.data[i] = hv_msg_getFloat(m, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("> we do not support sysex yet \n");
|
||||
break;
|
||||
}
|
||||
|
||||
// unsigned char* rawData = new unsigned char;
|
||||
// for (int i = 0; i < numElements; ++i) {
|
||||
// rawData[i] = (uint8_t) hv_msg_getFloat(m, i);
|
||||
// printf("> data: %d \n", rawData[i]);
|
||||
// }
|
||||
|
||||
midiSendEvent.size = numElements;
|
||||
// midiSendEvent.dataExt = (const uint8_t *) rawData;
|
||||
|
||||
writeMidiEvent(midiSendEvent);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// DPF Plugin run() loop
|
||||
|
||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
|
||||
void HeavyDPF_delay_simple::run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
|
||||
{
|
||||
handleMidiInput(frames, midiEvents, midiEventCount);
|
||||
#else
|
||||
void HeavyDPF_delay_simple::run(const float** inputs, float** outputs, uint32_t frames)
|
||||
{
|
||||
#endif
|
||||
_context->process((float**)inputs, outputs, frames);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Callbacks
|
||||
|
||||
void HeavyDPF_delay_simple::sampleRateChanged(double newSampleRate)
|
||||
{
|
||||
hv_delay_simple_free(_context);
|
||||
|
||||
_context = hv_delay_simple_new_with_options(getSampleRate(), 10, 5, 2);
|
||||
_context->setUserData(this);
|
||||
_context->setSendHook(&hvSendHookFunc);
|
||||
_context->setPrintHook(&hvPrintHookFunc);
|
||||
|
||||
|
||||
// ensure that the new context has the current parameters
|
||||
for (int i = 0; i < HV_LV2_NUM_PARAMETERS; ++i) {
|
||||
setParameterValue(i, _parameters[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/* Plugin entry point, called by DPF to create a new plugin instance. */
|
||||
|
||||
Plugin* createPlugin()
|
||||
{
|
||||
return new HeavyDPF_delay_simple();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
||||
167
delay_simple/plugin/source/HeavyDPF_delay_simple.hpp
Normal file
167
delay_simple/plugin/source/HeavyDPF_delay_simple.hpp
Normal file
@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HEAVY_LV2_DELAY_SIMPLE_
|
||||
#define _HEAVY_LV2_DELAY_SIMPLE_
|
||||
|
||||
#include "DistrhoPlugin.hpp"
|
||||
#include "DistrhoPluginInfo.h"
|
||||
#include "Heavy_delay_simple.hpp"
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
static void hvSendHookFunc(HeavyContextInterface *c, const char *sendName, uint32_t sendHash, const HvMessage *m);
|
||||
static void hvPrintHookFunc(HeavyContextInterface *c, const char *printLabel, const char *msgString, const HvMessage *m);
|
||||
|
||||
class HeavyDPF_delay_simple : public Plugin
|
||||
{
|
||||
public:
|
||||
enum Parameters
|
||||
{
|
||||
|
||||
paramDelay_Feedback,
|
||||
|
||||
paramDelay_Time,
|
||||
|
||||
paramDry_Volume,
|
||||
|
||||
paramGain,
|
||||
|
||||
paramWet_Volume,
|
||||
|
||||
};
|
||||
|
||||
HeavyDPF_delay_simple();
|
||||
~HeavyDPF_delay_simple() override;
|
||||
|
||||
void handleMidiInput(uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount);
|
||||
void handleMidiSend(uint32_t sendHash, const HvMessage *m);
|
||||
|
||||
protected:
|
||||
// -------------------------------------------------------------------
|
||||
// Information
|
||||
|
||||
const char* getLabel() const noexcept override
|
||||
{
|
||||
return "delay_simple";
|
||||
}
|
||||
|
||||
|
||||
const char* getDescription() const override
|
||||
{
|
||||
return "Simple Delay";
|
||||
}
|
||||
|
||||
|
||||
const char* getMaker() const noexcept override
|
||||
{
|
||||
|
||||
return "Wasted Audio";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* getLicense() const noexcept override
|
||||
{
|
||||
|
||||
return "ISC";
|
||||
|
||||
}
|
||||
|
||||
uint32_t getVersion() const noexcept override
|
||||
{
|
||||
|
||||
return d_version(0, 0, 1);
|
||||
|
||||
}
|
||||
|
||||
int64_t getUniqueId() const noexcept override
|
||||
{
|
||||
return int64_t( 0x9D74795E );
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Init
|
||||
|
||||
void initParameter(uint32_t index, Parameter& parameter) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Internal data
|
||||
|
||||
float getParameterValue(uint32_t index) const override;
|
||||
void setParameterValue(uint32_t index, float value) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Process
|
||||
|
||||
// void activate() override;
|
||||
// void deactivate() override;
|
||||
|
||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
|
||||
void run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override;
|
||||
#else
|
||||
void run(const float** inputs, float** outputs, uint32_t frames) override;
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Callbacks
|
||||
|
||||
void sampleRateChanged(double newSampleRate) override;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
// parameters
|
||||
float _parameters[5]; // in range of [0,1]
|
||||
|
||||
|
||||
// transport values
|
||||
bool wasPlaying;
|
||||
float samplesProcessed;
|
||||
double nextClockTick;
|
||||
double sampleAtCycleStart;
|
||||
|
||||
// heavy context
|
||||
HeavyContextInterface *_context;
|
||||
|
||||
// HeavyDPF_delay_simple<float> fdelay_simple;
|
||||
|
||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(HeavyDPF_delay_simple)
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
||||
|
||||
#endif // _HEAVY_LV2_DELAY_SIMPLE_
|
||||
659
delay_simple/plugin/source/Heavy_delay_simple.cpp
Normal file
659
delay_simple/plugin/source/Heavy_delay_simple.cpp
Normal file
@ -0,0 +1,659 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Heavy_delay_simple.hpp"
|
||||
|
||||
#include <new>
|
||||
|
||||
#define Context(_c) static_cast<Heavy_delay_simple *>(_c)
|
||||
|
||||
|
||||
/*
|
||||
* C Functions
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
HV_EXPORT HeavyContextInterface *hv_delay_simple_new(double sampleRate) {
|
||||
// allocate aligned memory
|
||||
void *ptr = hv_malloc(sizeof(Heavy_delay_simple));
|
||||
// ensure non-null
|
||||
if (!ptr) return nullptr;
|
||||
// call constructor
|
||||
new(ptr) Heavy_delay_simple(sampleRate);
|
||||
return Context(ptr);
|
||||
}
|
||||
|
||||
HV_EXPORT HeavyContextInterface *hv_delay_simple_new_with_options(double sampleRate,
|
||||
int poolKb, int inQueueKb, int outQueueKb) {
|
||||
// allocate aligned memory
|
||||
void *ptr = hv_malloc(sizeof(Heavy_delay_simple));
|
||||
// ensure non-null
|
||||
if (!ptr) return nullptr;
|
||||
// call constructor
|
||||
new(ptr) Heavy_delay_simple(sampleRate, poolKb, inQueueKb, outQueueKb);
|
||||
return Context(ptr);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_delay_simple_free(HeavyContextInterface *instance) {
|
||||
// call destructor
|
||||
Context(instance)->~Heavy_delay_simple();
|
||||
// free memory
|
||||
hv_free(instance);
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Class Functions
|
||||
*/
|
||||
|
||||
Heavy_delay_simple::Heavy_delay_simple(double sampleRate, int poolKb, int inQueueKb, int outQueueKb)
|
||||
: HeavyContext(sampleRate, poolKb, inQueueKb, outQueueKb) {
|
||||
numBytes += sTabread_init(&sTabread_OJVVdLuf, &hTable_TFqOKFso, true);
|
||||
numBytes += sTabwrite_init(&sTabwrite_kTfJPrs1, &hTable_TFqOKFso);
|
||||
numBytes += cVar_init_f(&cVar_4cpXTaBY, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_fRPZcVCt, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_Om7ifKfd, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_LnHfGF8V, 0.0f);
|
||||
numBytes += cVar_init_f(&cVar_mOyup5ir, 0.0f);
|
||||
numBytes += cDelay_init(this, &cDelay_OFD5iAqe, 0.0f);
|
||||
numBytes += cDelay_init(this, &cDelay_EI4kKdvf, 0.0f);
|
||||
numBytes += hTable_init(&hTable_TFqOKFso, 256);
|
||||
numBytes += cTabhead_init(&cTabhead_zhu6BFdy, &hTable_TFqOKFso);
|
||||
numBytes += cVar_init_s(&cVar_nONxuBGP, "del-delay1012");
|
||||
numBytes += cDelay_init(this, &cDelay_FTWI9Lbr, 0.0f);
|
||||
numBytes += cDelay_init(this, &cDelay_4Y58Ksfn, 0.0f);
|
||||
numBytes += cBinop_init(&cBinop_kd9uMvnd, 0.0f); // __mul
|
||||
numBytes += cBinop_init(&cBinop_99kJjPmN, 0.0f); // __sub
|
||||
numBytes += cBinop_init(&cBinop_khIQbSXe, 0.0f); // __max
|
||||
numBytes += cBinop_init(&cBinop_HsqyfMPx, 0.0f); // __sub
|
||||
numBytes += sVarf_init(&sVarf_DXN3F4mN, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_o7lB6W7R, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_4RDRwlaL, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_vL8TEPN9, 0.0f, 0.0f, false);
|
||||
numBytes += sVarf_init(&sVarf_eLw9NCKn, 0.0f, 0.0f, false);
|
||||
|
||||
// schedule a message to trigger all loadbangs via the __hv_init receiver
|
||||
scheduleMessageForReceiver(0xCE5CC65B, msg_initWithBang(HV_MESSAGE_ON_STACK(1), 0));
|
||||
}
|
||||
|
||||
Heavy_delay_simple::~Heavy_delay_simple() {
|
||||
hTable_free(&hTable_TFqOKFso);
|
||||
}
|
||||
|
||||
HvTable *Heavy_delay_simple::getTableForHash(hv_uint32_t tableHash) {switch (tableHash) {
|
||||
case 0x4678FF81: return &hTable_TFqOKFso; // del-delay1012
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) {
|
||||
switch (receiverHash) {
|
||||
case 0x36377AA9: { // Delay_Feedback
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_LQwqfjMo_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xEE78D101: { // Delay_Time
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_UQL9KHRi_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0x5EFB46D2: { // Dry_Volume
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_SIoX2X2C_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0x677821DA: { // Gain
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_eGza5oBR_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xEA49B5A: { // Wet_Volume
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_ex2b75Oc_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xCE5CC65B: { // __hv_init
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_AJBhI0kX_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xD8A3CB65: { // dfeed1
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_iG7Q7Uzr_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xAEFD47D3: { // dryvol
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_kJYDDgog_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0x37BBAC62: { // dtime1
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_kE9u8lIG_sendMessage);
|
||||
break;
|
||||
}
|
||||
case 0xCA9AE94A: { // dvol1
|
||||
mq_addMessageByTimestamp(&mq, m, 0, &cReceive_pzAN0z6v_sendMessage);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
int Heavy_delay_simple::getParameterInfo(int index, HvParameterInfo *info) {
|
||||
if (info != nullptr) {
|
||||
switch (index) {
|
||||
case 0: {
|
||||
info->name = "Delay_Feedback";
|
||||
info->hash = 0x36377AA9;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.25f;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
info->name = "Delay_Time";
|
||||
info->hash = 0xEE78D101;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 5000.0f;
|
||||
info->defaultVal = 500.0f;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
info->name = "Dry_Volume";
|
||||
info->hash = 0x5EFB46D2;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.75f;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
info->name = "Gain";
|
||||
info->hash = 0x677821DA;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.75f;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
info->name = "Wet_Volume";
|
||||
info->hash = 0xEA49B5A;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 1.0f;
|
||||
info->defaultVal = 0.75f;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
info->name = "invalid parameter index";
|
||||
info->hash = 0;
|
||||
info->type = HvParameterType::HV_PARAM_TYPE_PARAMETER_IN;
|
||||
info->minVal = 0.0f;
|
||||
info->maxVal = 0.0f;
|
||||
info->defaultVal = 0.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Send Function Implementations
|
||||
*/
|
||||
|
||||
|
||||
void Heavy_delay_simple::cVar_4cpXTaBY_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_wldZJDJM_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_fRPZcVCt_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_dFhbvIPr_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_Om7ifKfd_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_4A35hG1G_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_LnHfGF8V_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_eLw9NCKn, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_mOyup5ir_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cSend_jiugLxbD_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_hdrV3jKk_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "samplerate");
|
||||
cSystem_onMessage(_c, NULL, 0, m, &cSystem_B288dglo_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSystem_B288dglo_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_DIVIDE, 1000.0f, 0, m, &cBinop_NAf7xjjy_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_OFD5iAqe_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_OFD5iAqe, m);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_EI4kKdvf, 0, m, &cDelay_EI4kKdvf_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_OFD5iAqe, 0, m, &cDelay_OFD5iAqe_sendMessage);
|
||||
sTabwrite_onMessage(_c, &Context(_c)->sTabwrite_kTfJPrs1, 1, m, NULL);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_EI4kKdvf_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_EI4kKdvf, m);
|
||||
cMsg_o1Fk4mWr_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_4MyuHNhK_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_clwxczYs_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::hTable_TFqOKFso_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_DlDeZMFB_sendMessage(_c, 0, m);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_OFD5iAqe, 2, m, &cDelay_OFD5iAqe_sendMessage);
|
||||
cCast_onMessage(_c, HV_CAST_BANG, 0, m, &cCast_g87DeymK_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_clwxczYs_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(2);
|
||||
msg_init(m, 2, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "resize");
|
||||
msg_setElementToFrom(m, 1, n, 0);
|
||||
hTable_onMessage(_c, &Context(_c)->hTable_TFqOKFso, 0, m, &hTable_TFqOKFso_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_NAf7xjjy_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_MULTIPLY, 5000.0f, 0, m, &cBinop_4MyuHNhK_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_o1Fk4mWr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "mirror");
|
||||
hTable_onMessage(_c, &Context(_c)->hTable_TFqOKFso, 0, m, &hTable_TFqOKFso_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cCast_g87DeymK_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_OFD5iAqe, 0, m, &cDelay_OFD5iAqe_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_DlDeZMFB_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setFloat(m, 0, static_cast<float>(HV_N_SIMD));
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_EI4kKdvf, 2, m, &cDelay_EI4kKdvf_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cTabhead_zhu6BFdy_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_99kJjPmN, HV_BINOP_SUBTRACT, 0, m, &cBinop_99kJjPmN_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_c68iDIVD_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "samplerate");
|
||||
cSystem_onMessage(_c, NULL, 0, m, &cSystem_LlBI3RTT_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSystem_LlBI3RTT_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_DIVIDE, 1000.0f, 0, m, &cBinop_qp875S9R_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cVar_nONxuBGP_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_2Y6gSDxh_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_FTWI9Lbr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_FTWI9Lbr, m);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 0, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
sTabread_onMessage(_c, &Context(_c)->sTabread_OJVVdLuf, 0, m, &sTabread_OJVVdLuf_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cDelay_4Y58Ksfn_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const m) {
|
||||
cDelay_clearExecutingMessage(&Context(_c)->cDelay_4Y58Ksfn, m);
|
||||
sTabread_onMessage(_c, &Context(_c)->sTabread_OJVVdLuf, 0, m, &sTabread_OJVVdLuf_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 0, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::sTabread_OJVVdLuf_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_HsqyfMPx, HV_BINOP_SUBTRACT, 0, m, &cBinop_HsqyfMPx_sendMessage);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_kd9uMvnd_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_khIQbSXe, HV_BINOP_MAX, 0, m, &cBinop_khIQbSXe_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_qp875S9R_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_kd9uMvnd, HV_BINOP_MULTIPLY, 0, m, &cBinop_kd9uMvnd_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_99kJjPmN_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_60hMCcpx_sendMessage(_c, 0, m);
|
||||
sTabread_onMessage(_c, &Context(_c)->sTabread_OJVVdLuf, 0, m, &sTabread_OJVVdLuf_sendMessage);
|
||||
cCast_onMessage(_c, HV_CAST_BANG, 0, m, &cCast_zoAHkSwC_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSystem_kPqFOU4H_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_HsqyfMPx, HV_BINOP_SUBTRACT, 1, m, &cBinop_HsqyfMPx_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 2, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_2Y6gSDxh_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(3);
|
||||
msg_init(m, 3, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "table");
|
||||
msg_setElementToFrom(m, 1, n, 0);
|
||||
msg_setSymbol(m, 2, "size");
|
||||
cSystem_onMessage(_c, NULL, 0, m, &cSystem_kPqFOU4H_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_60hMCcpx_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setSymbol(m, 0, "clear");
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_FTWI9Lbr, 0, m, &cDelay_FTWI9Lbr_sendMessage);
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_4Y58Ksfn, 0, m, &cDelay_4Y58Ksfn_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cMsg_2y7SxePc_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *const n) {
|
||||
HvMessage *m = nullptr;
|
||||
m = HV_MESSAGE_ON_STACK(1);
|
||||
msg_init(m, 1, msg_getTimestamp(n));
|
||||
msg_setFloat(m, 0, static_cast<float>(HV_N_SIMD));
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_khIQbSXe, HV_BINOP_MAX, 1, m, &cBinop_khIQbSXe_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_khIQbSXe_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_99kJjPmN, HV_BINOP_SUBTRACT, 1, m, &cBinop_99kJjPmN_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cCast_zoAHkSwC_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_FTWI9Lbr, 0, m, &cDelay_FTWI9Lbr_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_H69XkGIL_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cDelay_onMessage(_c, &Context(_c)->cDelay_FTWI9Lbr, 2, m, &cDelay_FTWI9Lbr_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cBinop_HsqyfMPx_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_k_onMessage(_c, NULL, HV_BINOP_MULTIPLY, -1.0f, 0, m, &cBinop_H69XkGIL_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cCast_spzeS2Y3_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_nONxuBGP, 0, m, &cVar_nONxuBGP_sendMessage);
|
||||
cMsg_c68iDIVD_sendMessage(_c, 0, m);
|
||||
cTabhead_onMessage(_c, &Context(_c)->cTabhead_zhu6BFdy, 0, m, &cTabhead_zhu6BFdy_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_wldZJDJM_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_kE9u8lIG_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_dFhbvIPr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_pzAN0z6v_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_4A35hG1G_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_iG7Q7Uzr_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cSend_jiugLxbD_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cReceive_kJYDDgog_sendMessage(_c, 0, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_kE9u8lIG_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cBinop_onMessage(_c, &Context(_c)->cBinop_kd9uMvnd, HV_BINOP_MULTIPLY, 1, m, &cBinop_kd9uMvnd_sendMessage);
|
||||
cCast_onMessage(_c, HV_CAST_BANG, 0, m, &cCast_spzeS2Y3_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_pzAN0z6v_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_o7lB6W7R, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_iG7Q7Uzr_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_4RDRwlaL, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_kJYDDgog_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
sVarf_onMessage(_c, &Context(_c)->sVarf_vL8TEPN9, m);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_AJBhI0kX_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cMsg_hdrV3jKk_sendMessage(_c, 0, m);
|
||||
cMsg_2y7SxePc_sendMessage(_c, 0, m);
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_nONxuBGP, 0, m, &cVar_nONxuBGP_sendMessage);
|
||||
cMsg_c68iDIVD_sendMessage(_c, 0, m);
|
||||
cTabhead_onMessage(_c, &Context(_c)->cTabhead_zhu6BFdy, 0, m, &cTabhead_zhu6BFdy_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_eGza5oBR_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_LnHfGF8V, 0, m, &cVar_LnHfGF8V_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_SIoX2X2C_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_mOyup5ir, 0, m, &cVar_mOyup5ir_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_UQL9KHRi_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_4cpXTaBY, 0, m, &cVar_4cpXTaBY_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_ex2b75Oc_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_fRPZcVCt, 0, m, &cVar_fRPZcVCt_sendMessage);
|
||||
}
|
||||
|
||||
void Heavy_delay_simple::cReceive_LQwqfjMo_sendMessage(HeavyContextInterface *_c, int letIn, const HvMessage *m) {
|
||||
cVar_onMessage(_c, &Context(_c)->cVar_Om7ifKfd, 0, m, &cVar_Om7ifKfd_sendMessage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Context Process Implementation
|
||||
*/
|
||||
|
||||
int Heavy_delay_simple::process(float **inputBuffers, float **outputBuffers, int n) {
|
||||
while (hLp_hasData(&inQueue)) {
|
||||
hv_uint32_t numBytes = 0;
|
||||
ReceiverMessagePair *p = reinterpret_cast<ReceiverMessagePair *>(hLp_getReadBuffer(&inQueue, &numBytes));
|
||||
hv_assert(numBytes >= sizeof(ReceiverMessagePair));
|
||||
scheduleMessageForReceiver(p->receiverHash, &p->msg);
|
||||
hLp_consume(&inQueue);
|
||||
}
|
||||
const int n4 = n & ~HV_N_SIMD_MASK; // ensure that the block size is a multiple of HV_N_SIMD
|
||||
|
||||
// temporary signal vars
|
||||
hv_bufferf_t Bf0, Bf1, Bf2, Bf3;
|
||||
|
||||
// input and output vars
|
||||
hv_bufferf_t O0, O1;
|
||||
hv_bufferf_t I0, I1;
|
||||
|
||||
// declare and init the zero buffer
|
||||
hv_bufferf_t ZERO; __hv_zero_f(VOf(ZERO));
|
||||
|
||||
hv_uint32_t nextBlock = blockStartTimestamp;
|
||||
for (int n = 0; n < n4; n += HV_N_SIMD) {
|
||||
|
||||
// process all of the messages for this block
|
||||
nextBlock += HV_N_SIMD;
|
||||
while (mq_hasMessageBefore(&mq, nextBlock)) {
|
||||
MessageNode *const node = mq_peek(&mq);
|
||||
node->sendMessage(this, node->let, node->m);
|
||||
mq_pop(&mq);
|
||||
}
|
||||
|
||||
// load input buffers
|
||||
__hv_load_f(inputBuffers[0]+n, VOf(I0));
|
||||
__hv_load_f(inputBuffers[1]+n, VOf(I1));
|
||||
|
||||
// zero output buffers
|
||||
__hv_zero_f(VOf(O0));
|
||||
__hv_zero_f(VOf(O1));
|
||||
|
||||
// process all signal functions
|
||||
__hv_add_f(VIf(I0), VIf(I1), VOf(Bf0));
|
||||
__hv_varread_f(&sVarf_eLw9NCKn, VOf(Bf1));
|
||||
__hv_mul_f(VIf(Bf0), VIf(Bf1), VOf(Bf1));
|
||||
__hv_tabread_f(&sTabread_OJVVdLuf, VOf(Bf0));
|
||||
__hv_varread_f(&sVarf_o7lB6W7R, VOf(Bf2));
|
||||
__hv_varread_f(&sVarf_vL8TEPN9, VOf(Bf3));
|
||||
__hv_mul_f(VIf(Bf1), VIf(Bf3), VOf(Bf3));
|
||||
__hv_fma_f(VIf(Bf0), VIf(Bf2), VIf(Bf3), VOf(Bf3));
|
||||
__hv_varread_f(&sVarf_DXN3F4mN, VOf(Bf2));
|
||||
__hv_add_f(VIf(Bf1), VIf(Bf2), VOf(Bf2));
|
||||
__hv_tabwrite_f(&sTabwrite_kTfJPrs1, VIf(Bf2));
|
||||
__hv_varread_f(&sVarf_4RDRwlaL, VOf(Bf2));
|
||||
__hv_mul_f(VIf(Bf0), VIf(Bf2), VOf(Bf2));
|
||||
__hv_varwrite_f(&sVarf_DXN3F4mN, VIf(Bf2));
|
||||
__hv_add_f(VIf(Bf3), VIf(O0), VOf(O0));
|
||||
__hv_add_f(VIf(Bf3), VIf(O1), VOf(O1));
|
||||
|
||||
// save output vars to output buffer
|
||||
__hv_store_f(outputBuffers[0]+n, VIf(O0));
|
||||
__hv_store_f(outputBuffers[1]+n, VIf(O1));
|
||||
}
|
||||
|
||||
blockStartTimestamp = nextBlock;
|
||||
|
||||
return n4; // return the number of frames processed
|
||||
}
|
||||
|
||||
int Heavy_delay_simple::processInline(float *inputBuffers, float *outputBuffers, int n4) {
|
||||
hv_assert(!(n4 & HV_N_SIMD_MASK)); // ensure that n4 is a multiple of HV_N_SIMD
|
||||
|
||||
// define the heavy input buffer for 2 channel(s)
|
||||
float **const bIn = reinterpret_cast<float **>(hv_alloca(2*sizeof(float *)));
|
||||
bIn[0] = inputBuffers+(0*n4);
|
||||
bIn[1] = inputBuffers+(1*n4);
|
||||
|
||||
// define the heavy output buffer for 2 channel(s)
|
||||
float **const bOut = reinterpret_cast<float **>(hv_alloca(2*sizeof(float *)));
|
||||
bOut[0] = outputBuffers+(0*n4);
|
||||
bOut[1] = outputBuffers+(1*n4);
|
||||
|
||||
int n = process(bIn, bOut, n4);
|
||||
return n;
|
||||
}
|
||||
|
||||
int Heavy_delay_simple::processInlineInterleaved(float *inputBuffers, float *outputBuffers, int n4) {
|
||||
hv_assert(n4 & ~HV_N_SIMD_MASK); // ensure that n4 is a multiple of HV_N_SIMD
|
||||
|
||||
// define the heavy input buffer for 2 channel(s), uninterleave
|
||||
float *const bIn = reinterpret_cast<float *>(hv_alloca(2*n4*sizeof(float)));
|
||||
#if HV_SIMD_SSE || HV_SIMD_AVX
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
__m128 a = _mm_load_ps(inputBuffers+i); // LRLR
|
||||
__m128 b = _mm_load_ps(inputBuffers+4+i); // LRLR
|
||||
__m128 x = _mm_shuffle_ps(a, b, _MM_SHUFFLE(2,0,2,0)); // LLLL
|
||||
__m128 y = _mm_shuffle_ps(a, b, _MM_SHUFFLE(3,1,3,1)); // RRRR
|
||||
_mm_store_ps(bIn+j, x);
|
||||
_mm_store_ps(bIn+n4+j, y);
|
||||
}
|
||||
#elif HV_SIMD_NEON
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
float32x4x2_t a = vld2q_f32(inputBuffers+i); // load and uninterleave
|
||||
vst1q_f32(bIn+j, a.val[0]);
|
||||
vst1q_f32(bIn+n4+j, a.val[1]);
|
||||
}
|
||||
#else // HV_SIMD_NONE
|
||||
for (int j = 0; j < n4; ++j) {
|
||||
bIn[0*n4+j] = inputBuffers[0+2*j];
|
||||
bIn[1*n4+j] = inputBuffers[1+2*j];
|
||||
}
|
||||
#endif
|
||||
|
||||
// define the heavy output buffer for 2 channel(s)
|
||||
float *const bOut = reinterpret_cast<float *>(hv_alloca(2*n4*sizeof(float)));
|
||||
|
||||
int n = processInline(bIn, bOut, n4);
|
||||
|
||||
// interleave the heavy output into the output buffer
|
||||
#if HV_SIMD_AVX
|
||||
for (int i = 0, j = 0; j < n4; j += 8, i += 16) {
|
||||
__m256 x = _mm256_load_ps(bOut+j); // LLLLLLLL
|
||||
__m256 y = _mm256_load_ps(bOut+n4+j); // RRRRRRRR
|
||||
__m256 a = _mm256_unpacklo_ps(x, y); // LRLRLRLR
|
||||
__m256 b = _mm256_unpackhi_ps(x, y); // LRLRLRLR
|
||||
_mm256_store_ps(outputBuffers+i, a);
|
||||
_mm256_store_ps(outputBuffers+8+i, b);
|
||||
}
|
||||
#elif HV_SIMD_SSE
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
__m128 x = _mm_load_ps(bOut+j); // LLLL
|
||||
__m128 y = _mm_load_ps(bOut+n4+j); // RRRR
|
||||
__m128 a = _mm_unpacklo_ps(x, y); // LRLR
|
||||
__m128 b = _mm_unpackhi_ps(x, y); // LRLR
|
||||
_mm_store_ps(outputBuffers+i, a);
|
||||
_mm_store_ps(outputBuffers+4+i, b);
|
||||
}
|
||||
#elif HV_SIMD_NEON
|
||||
// https://community.arm.com/groups/processors/blog/2012/03/13/coding-for-neon--part-5-rearranging-vectors
|
||||
for (int i = 0, j = 0; j < n4; j += 4, i += 8) {
|
||||
float32x4_t x = vld1q_f32(bOut+j);
|
||||
float32x4_t y = vld1q_f32(bOut+n4+j);
|
||||
float32x4x2_t z = {x, y};
|
||||
vst2q_f32(outputBuffers+i, z); // interleave and store
|
||||
}
|
||||
#else // HV_SIMD_NONE
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < n4; ++j) {
|
||||
outputBuffers[i+2*j] = bOut[i*n4+j];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
85
delay_simple/plugin/source/Heavy_delay_simple.h
Normal file
85
delay_simple/plugin/source/Heavy_delay_simple.h
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HEAVY_DELAY_SIMPLE_H_
|
||||
#define _HEAVY_DELAY_SIMPLE_H_
|
||||
|
||||
#include "HvHeavy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Context
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
HV_DELAY_SIMPLE_PARAM_IN_DELAY_FEEDBACK = 0x36377AA9, // Delay_Feedback
|
||||
HV_DELAY_SIMPLE_PARAM_IN_DELAY_TIME = 0xEE78D101, // Delay_Time
|
||||
HV_DELAY_SIMPLE_PARAM_IN_DRY_VOLUME = 0x5EFB46D2, // Dry_Volume
|
||||
HV_DELAY_SIMPLE_PARAM_IN_GAIN = 0x677821DA, // Gain
|
||||
HV_DELAY_SIMPLE_PARAM_IN_WET_VOLUME = 0xEA49B5A, // Wet_Volume
|
||||
} Hv_delay_simple_ParameterIn;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new patch instance.
|
||||
* Sample rate should be positive and in Hertz, e.g. 44100.0.
|
||||
*/
|
||||
HeavyContextInterface *hv_delay_simple_new(double sampleRate);
|
||||
|
||||
/**
|
||||
* Creates a new patch instance.
|
||||
* @param sampleRate Sample rate should be positive (> 0) and in Hertz, e.g. 48000.0.
|
||||
* @param poolKb Pool size is in kilobytes, and determines the maximum amount of memory
|
||||
* allocated to messages at any time. By default this is 10 KB.
|
||||
* @param inQueueKb The size of the input message queue in kilobytes. It determines the
|
||||
* amount of memory dedicated to holding scheduled messages between calls to
|
||||
* process(). Default is 2 KB.
|
||||
* @param outQueueKb The size of the output message queue in kilobytes. It determines the
|
||||
* amount of memory dedicated to holding scheduled messages to the default sendHook.
|
||||
* See getNextSentMessage() for info on accessing these messages. Default is 0 KB.
|
||||
*/
|
||||
HeavyContextInterface *hv_delay_simple_new_with_options(double sampleRate, int poolKb, int inQueueKb, int outQueueKb);
|
||||
|
||||
/**
|
||||
* Free the patch instance.
|
||||
*/
|
||||
void hv_delay_simple_free(HeavyContextInterface *instance);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_DELAY_SIMPLE_H_
|
||||
162
delay_simple/plugin/source/Heavy_delay_simple.hpp
Normal file
162
delay_simple/plugin/source/Heavy_delay_simple.hpp
Normal file
@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Enzien Audio, Ltd.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the phrase "powered by heavy",
|
||||
* the heavy logo, and a hyperlink to https://enzienaudio.com, all in a visible
|
||||
* form.
|
||||
*
|
||||
* 2.1 If the Application is distributed in a store system (for example,
|
||||
* the Apple "App Store" or "Google Play"), the phrase "powered by heavy"
|
||||
* shall be included in the app description or the copyright text as well as
|
||||
* the in the app itself. The heavy logo will shall be visible in the app
|
||||
* itself as well.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HEAVY_CONTEXT_DELAY_SIMPLE_HPP_
|
||||
#define _HEAVY_CONTEXT_DELAY_SIMPLE_HPP_
|
||||
|
||||
// object includes
|
||||
#include "HeavyContext.hpp"
|
||||
#include "HvControlTabhead.h"
|
||||
#include "HvSignalVar.h"
|
||||
#include "HvTable.h"
|
||||
#include "HvControlBinop.h"
|
||||
#include "HvSignalTabwrite.h"
|
||||
#include "HvControlDelay.h"
|
||||
#include "HvMath.h"
|
||||
#include "HvSignalTabread.h"
|
||||
#include "HvControlSystem.h"
|
||||
#include "HvControlVar.h"
|
||||
#include "HvControlCast.h"
|
||||
|
||||
class Heavy_delay_simple : public HeavyContext {
|
||||
|
||||
public:
|
||||
Heavy_delay_simple(double sampleRate, int poolKb=10, int inQueueKb=2, int outQueueKb=0);
|
||||
~Heavy_delay_simple();
|
||||
|
||||
const char *getName() override { return "delay_simple"; }
|
||||
int getNumInputChannels() override { return 2; }
|
||||
int getNumOutputChannels() override { return 2; }
|
||||
|
||||
int process(float **inputBuffers, float **outputBuffer, int n) override;
|
||||
int processInline(float *inputBuffers, float *outputBuffer, int n) override;
|
||||
int processInlineInterleaved(float *inputBuffers, float *outputBuffer, int n) override;
|
||||
|
||||
int getParameterInfo(int index, HvParameterInfo *info) override;
|
||||
struct Parameter {
|
||||
struct In {
|
||||
enum ParameterIn : hv_uint32_t {
|
||||
DELAY_FEEDBACK = 0x36377AA9, // Delay_Feedback
|
||||
DELAY_TIME = 0xEE78D101, // Delay_Time
|
||||
DRY_VOLUME = 0x5EFB46D2, // Dry_Volume
|
||||
GAIN = 0x677821DA, // Gain
|
||||
WET_VOLUME = 0xEA49B5A, // Wet_Volume
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
private:
|
||||
HvTable *getTableForHash(hv_uint32_t tableHash) override;
|
||||
void scheduleMessageForReceiver(hv_uint32_t receiverHash, HvMessage *m) override;
|
||||
|
||||
// static sendMessage functions
|
||||
static void cVar_4cpXTaBY_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_fRPZcVCt_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_Om7ifKfd_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_LnHfGF8V_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_mOyup5ir_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_hdrV3jKk_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSystem_B288dglo_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_OFD5iAqe_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_EI4kKdvf_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_4MyuHNhK_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void hTable_TFqOKFso_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_clwxczYs_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_NAf7xjjy_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_o1Fk4mWr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cCast_g87DeymK_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_DlDeZMFB_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cTabhead_zhu6BFdy_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_c68iDIVD_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSystem_LlBI3RTT_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cVar_nONxuBGP_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_FTWI9Lbr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cDelay_4Y58Ksfn_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void sTabread_OJVVdLuf_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_kd9uMvnd_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_qp875S9R_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_99kJjPmN_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSystem_kPqFOU4H_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_2Y6gSDxh_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_60hMCcpx_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cMsg_2y7SxePc_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_khIQbSXe_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cCast_zoAHkSwC_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_H69XkGIL_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cBinop_HsqyfMPx_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cCast_spzeS2Y3_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_wldZJDJM_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_dFhbvIPr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_4A35hG1G_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cSend_jiugLxbD_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_kE9u8lIG_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_pzAN0z6v_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_iG7Q7Uzr_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_kJYDDgog_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_AJBhI0kX_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_eGza5oBR_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_SIoX2X2C_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_UQL9KHRi_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_ex2b75Oc_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
static void cReceive_LQwqfjMo_sendMessage(HeavyContextInterface *, int, const HvMessage *);
|
||||
|
||||
// objects
|
||||
SignalTabread sTabread_OJVVdLuf;
|
||||
SignalTabwrite sTabwrite_kTfJPrs1;
|
||||
ControlVar cVar_4cpXTaBY;
|
||||
ControlVar cVar_fRPZcVCt;
|
||||
ControlVar cVar_Om7ifKfd;
|
||||
ControlVar cVar_LnHfGF8V;
|
||||
ControlVar cVar_mOyup5ir;
|
||||
ControlDelay cDelay_OFD5iAqe;
|
||||
ControlDelay cDelay_EI4kKdvf;
|
||||
ControlBinop cBinop_4MyuHNhK;
|
||||
HvTable hTable_TFqOKFso;
|
||||
ControlBinop cBinop_NAf7xjjy;
|
||||
ControlTabhead cTabhead_zhu6BFdy;
|
||||
ControlVar cVar_nONxuBGP;
|
||||
ControlDelay cDelay_FTWI9Lbr;
|
||||
ControlDelay cDelay_4Y58Ksfn;
|
||||
ControlBinop cBinop_kd9uMvnd;
|
||||
ControlBinop cBinop_qp875S9R;
|
||||
ControlBinop cBinop_99kJjPmN;
|
||||
ControlBinop cBinop_khIQbSXe;
|
||||
ControlBinop cBinop_H69XkGIL;
|
||||
ControlBinop cBinop_HsqyfMPx;
|
||||
SignalVarf sVarf_DXN3F4mN;
|
||||
SignalVarf sVarf_o7lB6W7R;
|
||||
SignalVarf sVarf_4RDRwlaL;
|
||||
SignalVarf sVarf_vL8TEPN9;
|
||||
SignalVarf sVarf_eLw9NCKn;
|
||||
};
|
||||
|
||||
#endif // _HEAVY_CONTEXT_DELAY_SIMPLE_HPP_
|
||||
100
delay_simple/plugin/source/HvControlBinop.c
Normal file
100
delay_simple/plugin/source/HvControlBinop.c
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlBinop.h"
|
||||
|
||||
hv_size_t cBinop_init(ControlBinop *o, float k) {
|
||||
o->k = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float cBinop_perform_op(BinopType op, float f, float k) {
|
||||
switch (op) {
|
||||
case HV_BINOP_ADD: return f + k;
|
||||
case HV_BINOP_SUBTRACT: return f - k;
|
||||
case HV_BINOP_MULTIPLY: return f * k;
|
||||
case HV_BINOP_DIVIDE: return (k != 0.0f) ? (f/k) : 0.0f;
|
||||
case HV_BINOP_INT_DIV: {
|
||||
const int ik = (int) k;
|
||||
return (ik != 0) ? (float) (((int) f) / ik) : 0.0f;
|
||||
}
|
||||
case HV_BINOP_MOD_BIPOLAR: {
|
||||
const int ik = (int) k;
|
||||
return (ik != 0) ? (float) (((int) f) % ik) : 0.0f;
|
||||
}
|
||||
case HV_BINOP_MOD_UNIPOLAR: {
|
||||
f = (k == 0.0f) ? 0.0f : (float) ((int) f % (int) k);
|
||||
return (f < 0.0f) ? f + hv_abs_f(k) : f;
|
||||
}
|
||||
case HV_BINOP_BIT_LEFTSHIFT: return (float) (((int) f) << ((int) k));
|
||||
case HV_BINOP_BIT_RIGHTSHIFT: return (float) (((int) f) >> ((int) k));
|
||||
case HV_BINOP_BIT_AND: return (float) ((int) f & (int) k);
|
||||
case HV_BINOP_BIT_XOR: return (float) ((int) f ^ (int) k);
|
||||
case HV_BINOP_BIT_OR: return (float) ((int) f | (int) k);
|
||||
case HV_BINOP_EQ: return (f == k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_NEQ: return (f != k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_LOGICAL_AND: return ((f == 0.0f) || (k == 0.0f)) ? 0.0f : 1.0f;
|
||||
case HV_BINOP_LOGICAL_OR: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : 1.0f;
|
||||
case HV_BINOP_LESS_THAN: return (f < k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_LESS_THAN_EQL: return (f <= k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_GREATER_THAN: return (f > k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_GREATER_THAN_EQL: return (f >= k) ? 1.0f : 0.0f;
|
||||
case HV_BINOP_MAX: return hv_max_f(f, k);
|
||||
case HV_BINOP_MIN: return hv_min_f(f, k);
|
||||
case HV_BINOP_POW: return (f > 0.0f) ? hv_pow_f(f, k) : 0.0f;
|
||||
case HV_BINOP_ATAN2: return ((f == 0.0f) && (k == 0.0f)) ? 0.0f : hv_atan2_f(f, k);
|
||||
default: return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void cBinop_onMessage(HeavyContextInterface *_c, ControlBinop *o, BinopType op, int letIn,
|
||||
const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
// Note(joe): supporting Pd's ability to perform operations of packs
|
||||
// of floats is likely to not be supported in the future.
|
||||
if (msg_isFloat(m, 1)) o->k = msg_getFloat(m, 1);
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
float f = cBinop_perform_op(op, msg_getFloat(m, 0), o->k);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), f);
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
o->k = msg_getFloat(m, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void cBinop_k_onMessage(HeavyContextInterface *_c, void *o, BinopType op, float k,
|
||||
int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
// NOTE(mhroth): Heavy does not support sending bangs to binop objects to return the previous output
|
||||
float f = (msg_isFloat(m, 1)) ? msg_getFloat(m, 1) : k;
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
f = cBinop_perform_op(op, msg_getFloat(m, 0), f);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), f);
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
}
|
||||
71
delay_simple/plugin/source/HvControlBinop.h
Normal file
71
delay_simple/plugin/source/HvControlBinop.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_BINOP_H_
|
||||
#define _HEAVY_CONTROL_BINOP_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum BinopType {
|
||||
HV_BINOP_ADD,
|
||||
HV_BINOP_SUBTRACT,
|
||||
HV_BINOP_MULTIPLY,
|
||||
HV_BINOP_DIVIDE,
|
||||
HV_BINOP_INT_DIV,
|
||||
HV_BINOP_MOD_BIPOLAR,
|
||||
HV_BINOP_MOD_UNIPOLAR,
|
||||
HV_BINOP_BIT_LEFTSHIFT,
|
||||
HV_BINOP_BIT_RIGHTSHIFT,
|
||||
HV_BINOP_BIT_AND,
|
||||
HV_BINOP_BIT_XOR,
|
||||
HV_BINOP_BIT_OR,
|
||||
HV_BINOP_EQ,
|
||||
HV_BINOP_NEQ,
|
||||
HV_BINOP_LOGICAL_AND,
|
||||
HV_BINOP_LOGICAL_OR,
|
||||
HV_BINOP_LESS_THAN,
|
||||
HV_BINOP_LESS_THAN_EQL,
|
||||
HV_BINOP_GREATER_THAN,
|
||||
HV_BINOP_GREATER_THAN_EQL,
|
||||
HV_BINOP_MAX,
|
||||
HV_BINOP_MIN,
|
||||
HV_BINOP_POW,
|
||||
HV_BINOP_ATAN2
|
||||
} BinopType;
|
||||
|
||||
typedef struct ControlBinop {
|
||||
float k;
|
||||
} ControlBinop;
|
||||
|
||||
hv_size_t cBinop_init(ControlBinop *o, float k);
|
||||
|
||||
void cBinop_onMessage(HeavyContextInterface *_c, ControlBinop *o, BinopType op, int letIn,
|
||||
const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
void cBinop_k_onMessage(HeavyContextInterface *_c, void *o, BinopType op, float k,
|
||||
int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_BINOP_H_
|
||||
60
delay_simple/plugin/source/HvControlCast.c
Normal file
60
delay_simple/plugin/source/HvControlCast.c
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlCast.h"
|
||||
|
||||
void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (castType) {
|
||||
case HV_CAST_BANG: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithBang(n, msg_getTimestamp(m));
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_CAST_FLOAT: {
|
||||
if (msg_isFloat(m, 0)) {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), msg_getFloat(m, 0));
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HV_CAST_SYMBOL: {
|
||||
switch (msg_getType(m, 0)) {
|
||||
case HV_MSG_BANG: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithSymbol(n, msg_getTimestamp(m), "bang");
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_FLOAT: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithSymbol(n, msg_getTimestamp(m), "float");
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL: {
|
||||
sendMessage(_c, 0, m);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
39
delay_simple/plugin/source/HvControlCast.h
Normal file
39
delay_simple/plugin/source/HvControlCast.h
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_CAST_H_
|
||||
#define _HEAVY_CONTROL_CAST_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum CastType {
|
||||
HV_CAST_BANG,
|
||||
HV_CAST_FLOAT,
|
||||
HV_CAST_SYMBOL
|
||||
} CastType;
|
||||
|
||||
void cCast_onMessage(HeavyContextInterface *_c, CastType castType, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_CAST_H_
|
||||
92
delay_simple/plugin/source/HvControlDelay.c
Normal file
92
delay_simple/plugin/source/HvControlDelay.c
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlDelay.h"
|
||||
|
||||
hv_size_t cDelay_init(HeavyContextInterface *_c, ControlDelay *o, float delayMs) {
|
||||
o->delay = hv_millisecondsToSamples(_c, delayMs);
|
||||
hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cDelay_onMessage(HeavyContextInterface *_c, ControlDelay *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (msg_compareSymbol(m, 0, "flush")) {
|
||||
// send all messages immediately
|
||||
for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) {
|
||||
HvMessage *n = o->msgs[i];
|
||||
if (n != NULL) {
|
||||
msg_setTimestamp(n, msg_getTimestamp(m)); // update the timestamp to now
|
||||
sendMessage(_c, 0, n); // send the message
|
||||
hv_cancelMessage(_c, n, sendMessage); // then clear it
|
||||
// NOTE(mhroth): there may be a problem here if a flushed message causes a clear message to return
|
||||
// to this object in the same step
|
||||
}
|
||||
}
|
||||
hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *));
|
||||
} else if (msg_compareSymbol(m, 0, "clear")) {
|
||||
// cancel (clear) all (pending) messages
|
||||
for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) {
|
||||
HvMessage *n = o->msgs[i];
|
||||
if (n != NULL) {
|
||||
hv_cancelMessage(_c, n, sendMessage);
|
||||
}
|
||||
}
|
||||
hv_memclear(o->msgs, __HV_DELAY_MAX_MESSAGES*sizeof(HvMessage *));
|
||||
} else {
|
||||
hv_uint32_t ts = msg_getTimestamp(m);
|
||||
msg_setTimestamp((HvMessage *) m, ts+o->delay); // update the timestamp to set the delay
|
||||
int i;
|
||||
for (i = 0; i < __HV_DELAY_MAX_MESSAGES; i++) {
|
||||
if (o->msgs[i] == NULL) {
|
||||
o->msgs[i] = hv_scheduleMessageForObject(_c, m, sendMessage, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hv_assert((i < __HV_DELAY_MAX_MESSAGES) && // scheduled message limit reached
|
||||
"[__delay] cannot track any more messages. Try increasing the size of __HV_DELAY_MAX_MESSAGES.");
|
||||
msg_setTimestamp((HvMessage *) m, ts); // return to the original timestamp
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isFloat(m,0)) {
|
||||
// set delay in milliseconds (cannot be negative!)
|
||||
o->delay = hv_millisecondsToSamples(_c, msg_getFloat(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
if (msg_isFloat(m,0)) {
|
||||
// set delay in samples (cannot be negative!)
|
||||
o->delay = (hv_uint32_t) hv_max_f(0.0f, msg_getFloat(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void cDelay_clearExecutingMessage(ControlDelay *o, const HvMessage *m) {
|
||||
for (int i = 0; i < __HV_DELAY_MAX_MESSAGES; ++i) {
|
||||
if (o->msgs[i] == m) {
|
||||
o->msgs[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
delay_simple/plugin/source/HvControlDelay.h
Normal file
44
delay_simple/plugin/source/HvControlDelay.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_DELAY_H_
|
||||
#define _HEAVY_CONTROL_DELAY_H_
|
||||
|
||||
#define __HV_DELAY_MAX_MESSAGES 8
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ControlDelay {
|
||||
hv_uint32_t delay; // delay in samples
|
||||
HvMessage *msgs[__HV_DELAY_MAX_MESSAGES];
|
||||
} ControlDelay;
|
||||
|
||||
hv_size_t cDelay_init(HeavyContextInterface *_c, ControlDelay *o, float delayMs);
|
||||
|
||||
void cDelay_onMessage(HeavyContextInterface *_c, ControlDelay *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
void cDelay_clearExecutingMessage(ControlDelay *o, const HvMessage *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_DELAY_H_
|
||||
46
delay_simple/plugin/source/HvControlSystem.c
Normal file
46
delay_simple/plugin/source/HvControlSystem.c
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlSystem.h"
|
||||
|
||||
void cSystem_onMessage(HeavyContextInterface *_c, void *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
if (msg_compareSymbol(m, 0, "samplerate")) {
|
||||
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getSampleRate(_c));
|
||||
} else if (msg_compareSymbol(m, 0, "numInputChannels")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getNumInputChannels(_c));
|
||||
} else if (msg_compareSymbol(m, 0, "numOutputChannels")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hv_getNumOutputChannels(_c));
|
||||
} else if (msg_compareSymbol(m, 0, "currentTime")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) msg_getTimestamp(m));
|
||||
} else if (msg_compareSymbol(m, 0, "table")) {
|
||||
// NOTE(mhroth): no need to check message format for symbols as table lookup will fail otherwise
|
||||
HvTable *table = hv_table_get(_c, msg_getHash(m,1));
|
||||
if (table != NULL) {
|
||||
if (msg_compareSymbol(m, 2, "length")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getLength(table));
|
||||
} else if (msg_compareSymbol(m, 2, "size")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(table));
|
||||
} else if (msg_compareSymbol(m, 2, "head")) {
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(table));
|
||||
} else return;
|
||||
} else return;
|
||||
} else return;
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
33
delay_simple/plugin/source/HvControlSystem.h
Normal file
33
delay_simple/plugin/source/HvControlSystem.h
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_SYSTEM_H_
|
||||
#define _HEAVY_CONTROL_SYSTEM_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cSystem_onMessage(HeavyContextInterface *_c, void *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_SYSTEM_H_
|
||||
45
delay_simple/plugin/source/HvControlTabhead.c
Normal file
45
delay_simple/plugin/source/HvControlTabhead.c
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlTabhead.h"
|
||||
|
||||
hv_size_t cTabhead_init(ControlTabhead *o, HvTable *table) {
|
||||
o->table = table;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cTabhead_onMessage(HeavyContextInterface *_c, ControlTabhead *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (msg_getType(m,0) == HV_MSG_BANG) {
|
||||
// get current head of table
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getHead(o->table));
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
// set a new table
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
39
delay_simple/plugin/source/HvControlTabhead.h
Normal file
39
delay_simple/plugin/source/HvControlTabhead.h
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_TABHEAD_H_
|
||||
#define _HEAVY_CONTROL_TABHEAD_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ControlTabhead {
|
||||
struct HvTable *table;
|
||||
} ControlTabhead;
|
||||
|
||||
hv_size_t cTabhead_init(ControlTabhead *o, struct HvTable *table);
|
||||
|
||||
void cTabhead_onMessage(HeavyContextInterface *_c, ControlTabhead *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_TABHEAD_H_
|
||||
83
delay_simple/plugin/source/HvControlVar.c
Normal file
83
delay_simple/plugin/source/HvControlVar.c
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvControlVar.h"
|
||||
|
||||
hv_size_t cVar_init_f(ControlVar *o, float k) {
|
||||
o->e.type = HV_MSG_FLOAT;
|
||||
o->e.data.f = k;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hv_size_t cVar_init_s(ControlVar *o, const char *s) {
|
||||
o->e.type = HV_MSG_HASH;
|
||||
o->e.data.h = hv_string_to_hash(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cVar_free(ControlVar *o) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void cVar_onMessage(HeavyContextInterface *_c, ControlVar *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_BANG: {
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
if (o->e.type == HV_MSG_FLOAT) msg_initWithFloat(n, msg_getTimestamp(m), o->e.data.f);
|
||||
else if (o->e.type == HV_MSG_HASH) msg_initWithHash(n, msg_getTimestamp(m), o->e.data.h);
|
||||
else return;
|
||||
sendMessage(_c, 0, n);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_FLOAT: {
|
||||
o->e.type = HV_MSG_FLOAT;
|
||||
o->e.data.f = msg_getFloat(m,0);
|
||||
sendMessage(_c, 0, m);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL:
|
||||
case HV_MSG_HASH: {
|
||||
o->e.type = HV_MSG_HASH;
|
||||
o->e.data.h = msg_getHash(m,0);
|
||||
sendMessage(_c, 0, m);
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_FLOAT: {
|
||||
o->e.type = HV_MSG_FLOAT;
|
||||
o->e.data.f = msg_getFloat(m,0);
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL:
|
||||
case HV_MSG_HASH: {
|
||||
o->e.type = HV_MSG_HASH;
|
||||
o->e.data.h = msg_getHash(m,0);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
43
delay_simple/plugin/source/HvControlVar.h
Normal file
43
delay_simple/plugin/source/HvControlVar.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_CONTROL_VAR_H_
|
||||
#define _HEAVY_CONTROL_VAR_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ControlVar {
|
||||
Element e; // type is only every HV_MSG_FLOAT or HV_MSG_HASH
|
||||
} ControlVar;
|
||||
|
||||
hv_size_t cVar_init_f(ControlVar *o, float k);
|
||||
|
||||
hv_size_t cVar_init_s(ControlVar *o, const char *s);
|
||||
|
||||
void cVar_free(ControlVar *o);
|
||||
|
||||
void cVar_onMessage(HeavyContextInterface *_c, ControlVar *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_CONTROL_VAR_H_
|
||||
318
delay_simple/plugin/source/HvHeavy.cpp
Normal file
318
delay_simple/plugin/source/HvHeavy.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HeavyContext.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Table
|
||||
#endif
|
||||
|
||||
HV_EXPORT bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->setLengthForTable(tableHash, newSampleLength);
|
||||
}
|
||||
|
||||
HV_EXPORT float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getBufferForTable(tableHash);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getLengthForTable(tableHash);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Message
|
||||
#endif
|
||||
|
||||
HV_EXPORT hv_size_t hv_msg_getByteSize(hv_uint32_t numElements) {
|
||||
return msg_getCoreSize(numElements);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp) {
|
||||
msg_init(m, numElements, timestamp);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_size_t hv_msg_getNumElements(const HvMessage *m) {
|
||||
return msg_getNumElements(m);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_msg_getTimestamp(const HvMessage *m) {
|
||||
return msg_getTimestamp(m);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
|
||||
msg_setTimestamp(m, timestamp);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isBang(const HvMessage *const m, int i) {
|
||||
return msg_isBang(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setBang(HvMessage *m, int i) {
|
||||
msg_setBang(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isFloat(const HvMessage *const m, int i) {
|
||||
return msg_isFloat(m, i);
|
||||
}
|
||||
|
||||
HV_EXPORT float hv_msg_getFloat(const HvMessage *const m, int i) {
|
||||
return msg_getFloat(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setFloat(HvMessage *m, int i, float f) {
|
||||
msg_setFloat(m,i,f);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isSymbol(const HvMessage *const m, int i) {
|
||||
return msg_isSymbol(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT const char *hv_msg_getSymbol(const HvMessage *const m, int i) {
|
||||
return msg_getSymbol(m,i);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_setSymbol(HvMessage *m, int i, const char *s) {
|
||||
msg_setSymbol(m,i,s);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_isHash(const HvMessage *const m, int i) {
|
||||
return msg_isHash(m, i);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i) {
|
||||
return msg_getHash(m, i);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt) {
|
||||
return msg_hasFormat(m, fmt);
|
||||
}
|
||||
|
||||
HV_EXPORT char *hv_msg_toString(const HvMessage *const m) {
|
||||
return msg_toString(m);
|
||||
}
|
||||
|
||||
HV_EXPORT HvMessage *hv_msg_copy(const HvMessage *const m) {
|
||||
return msg_copy(m);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_msg_free(HvMessage *m) {
|
||||
msg_free(m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Common
|
||||
#endif
|
||||
|
||||
HV_EXPORT int hv_getSize(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return (int) c->getSize();
|
||||
}
|
||||
|
||||
HV_EXPORT double hv_getSampleRate(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getSampleRate();
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_getNumInputChannels(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getNumInputChannels();
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_getNumOutputChannels(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getNumOutputChannels();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setPrintHook(f);
|
||||
}
|
||||
|
||||
HV_EXPORT HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getPrintHook();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setSendHook(f);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_stringToHash(const char *s) {
|
||||
return hv_string_to_hash(s);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendBangToReceiver(receiverHash);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, float x) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendFloatToReceiver(receiverHash, x);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendSymbolToReceiver(receiverHash, s);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendMessageToReceiverV(
|
||||
HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...) {
|
||||
hv_assert(c != nullptr);
|
||||
hv_assert(delayMs >= 0.0);
|
||||
hv_assert(format != nullptr);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
const int numElem = (int) hv_strlen(format);
|
||||
HvMessage *m = HV_MESSAGE_ON_STACK(numElem);
|
||||
msg_init(m, numElem, c->getCurrentSample() + (hv_uint32_t) (hv_max_d(0.0, delayMs)*c->getSampleRate()/1000.0));
|
||||
for (int i = 0; i < numElem; i++) {
|
||||
switch (format[i]) {
|
||||
case 'b': msg_setBang(m, i); break;
|
||||
case 'f': msg_setFloat(m, i, (float) va_arg(ap, double)); break;
|
||||
case 'h': msg_setHash(m, i, (int) va_arg(ap, int)); break;
|
||||
case 's': msg_setSymbol(m, i, (char *) va_arg(ap, char *)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return c->sendMessageToReceiver(receiverHash, delayMs, m);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_sendMessageToReceiver(
|
||||
HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->sendMessageToReceiver(receiverHash, delayMs, m);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
hv_assert(c != nullptr);
|
||||
c->cancelMessage(m, sendMessage);
|
||||
}
|
||||
|
||||
HV_EXPORT const char *hv_getName(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getName();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setUserData(HeavyContextInterface *c, void *userData) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setUserData(userData);
|
||||
}
|
||||
|
||||
HV_EXPORT void *hv_getUserData(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getUserData();
|
||||
}
|
||||
|
||||
HV_EXPORT double hv_getCurrentTime(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return (double) c->samplesToMilliseconds(c->getCurrentSample());
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getCurrentSample();
|
||||
}
|
||||
|
||||
HV_EXPORT float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->samplesToMilliseconds(numSamples);
|
||||
}
|
||||
|
||||
HV_EXPORT hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->millisecondsToSamples(ms);
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->getParameterInfo(index, info);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_lock_acquire(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
c->lockAcquire();
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_lock_try(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->lockTry();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_lock_release(HeavyContextInterface *c) {
|
||||
hv_assert(c != nullptr);
|
||||
c->lockRelease();
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setInputMessageQueueSize(inQueueKb);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb) {
|
||||
hv_assert(c != nullptr);
|
||||
c->setOutputMessageQueueSize(outQueueKb);
|
||||
}
|
||||
|
||||
HV_EXPORT bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength) {
|
||||
hv_assert(c != nullptr);
|
||||
hv_assert(destinationHash != nullptr);
|
||||
hv_assert(outMsg != nullptr);
|
||||
return c->getNextSentMessage(destinationHash, outMsg, msgLength);
|
||||
}
|
||||
|
||||
|
||||
#if !HV_WIN
|
||||
#pragma mark - Heavy Common
|
||||
#endif
|
||||
|
||||
HV_EXPORT int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->process(inputBuffers, outputBuffers, n);
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->processInline(inputBuffers, outputBuffers, n);
|
||||
}
|
||||
|
||||
HV_EXPORT int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n) {
|
||||
hv_assert(c != nullptr);
|
||||
return c->processInlineInterleaved(inputBuffers, outputBuffers, n);
|
||||
}
|
||||
|
||||
HV_EXPORT void hv_delete(HeavyContextInterface *c) {
|
||||
delete c;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
413
delay_simple/plugin/source/HvHeavy.h
Normal file
413
delay_simple/plugin/source/HvHeavy.h
Normal file
@ -0,0 +1,413 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_H_
|
||||
#define _HEAVY_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _HEAVY_DECLARATIONS_
|
||||
#define _HEAVY_DECLARATIONS_
|
||||
|
||||
#ifdef __cplusplus
|
||||
class HeavyContextInterface;
|
||||
#else
|
||||
typedef struct HeavyContextInterface HeavyContextInterface;
|
||||
#endif
|
||||
|
||||
typedef struct HvMessage HvMessage;
|
||||
|
||||
typedef enum {
|
||||
HV_PARAM_TYPE_PARAMETER_IN,
|
||||
HV_PARAM_TYPE_PARAMETER_OUT,
|
||||
HV_PARAM_TYPE_EVENT_IN,
|
||||
HV_PARAM_TYPE_EVENT_OUT
|
||||
} HvParameterType;
|
||||
|
||||
typedef struct HvParameterInfo {
|
||||
const char *name; // the human readable parameter name
|
||||
hv_uint32_t hash; // an integer identified used by heavy for this parameter
|
||||
HvParameterType type; // type of this parameter
|
||||
float minVal; // the minimum value of this parameter
|
||||
float maxVal; // the maximum value of this parameter
|
||||
float defaultVal; // the default value of this parameter
|
||||
} HvParameterInfo;
|
||||
|
||||
typedef void (HvSendHook_t) (HeavyContextInterface *context, const char *sendName, hv_uint32_t sendHash, const HvMessage *msg);
|
||||
typedef void (HvPrintHook_t) (HeavyContextInterface *context, const char *printName, const char *str, const HvMessage *msg);
|
||||
|
||||
#endif // _HEAVY_DECLARATIONS_
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Context
|
||||
#endif
|
||||
|
||||
/** Deletes a patch instance. */
|
||||
void hv_delete(HeavyContextInterface *c);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Process
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an array of float channel arrays.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [[LLLL][RRRR]]
|
||||
* This function support in-place processing.
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
int hv_process(HeavyContextInterface *c, float **inputBuffers, float **outputBuffers, int n);
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an uninterleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LLLLRRRR]
|
||||
* This function support in-place processing.
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
int hv_processInline(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
|
||||
|
||||
/**
|
||||
* Processes one block of samples for a patch instance. The buffer format is an interleaved float array of channels.
|
||||
* If the context has not input or output channels, the respective argument may be NULL.
|
||||
* The number of samples to to tbe processed should be a multiple of 1, 4, or 8, depending on if
|
||||
* no, SSE or NEON, or AVX optimisation is being used, respectively.
|
||||
* e.g. [LRLRLRLR]
|
||||
* This function support in-place processing.
|
||||
*
|
||||
* @return The number of samples processed.
|
||||
*
|
||||
* This function is NOT thread-safe. It is assumed that only the audio thread will execute this function.
|
||||
*/
|
||||
int hv_processInlineInterleaved(HeavyContextInterface *c, float *inputBuffers, float *outputBuffers, int n);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Common
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the total size in bytes of the context.
|
||||
* This value may change if tables are resized.
|
||||
*/
|
||||
int hv_getSize(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the sample rate with which this context has been configured. */
|
||||
double hv_getSampleRate(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the number of input channels with which this context has been configured. */
|
||||
int hv_getNumInputChannels(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the number of output channels with which this context has been configured. */
|
||||
int hv_getNumOutputChannels(HeavyContextInterface *c);
|
||||
|
||||
/** Set the print hook. The function is called whenever a message is sent to a print object. */
|
||||
void hv_setPrintHook(HeavyContextInterface *c, HvPrintHook_t *f);
|
||||
|
||||
/** Returns the print hook, or NULL. */
|
||||
HvPrintHook_t *hv_getPrintHook(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Set the send hook. The function is called whenever a message is sent to any send object.
|
||||
* Messages returned by this function should NEVER be freed. If the message must persist, call
|
||||
* hv_msg_copy() first.
|
||||
*/
|
||||
void hv_setSendHook(HeavyContextInterface *c, HvSendHook_t *f);
|
||||
|
||||
/** Returns a 32-bit hash of any string. Returns 0 if string is NULL. */
|
||||
hv_uint32_t hv_stringToHash(const char *s);
|
||||
|
||||
/**
|
||||
* A convenience function to send a bang to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendBangToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash);
|
||||
|
||||
/**
|
||||
* A convenience function to send a float to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendFloatToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, const float x);
|
||||
|
||||
/**
|
||||
* A convenience function to send a symbol to a receiver to be processed immediately.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendSymbolToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, char *s);
|
||||
|
||||
/**
|
||||
* Sends a formatted message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendMessageToReceiverV(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, const char *format, ...);
|
||||
|
||||
/**
|
||||
* Sends a message to a receiver that can be scheduled for the future.
|
||||
* The receiver is addressed with its hash, which can also be determined using hv_stringToHash().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* @return True if the message was accepted. False if the message could not fit onto
|
||||
* the message queue to be processed this block.
|
||||
*/
|
||||
bool hv_sendMessageToReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, HvMessage *m);
|
||||
|
||||
/**
|
||||
* Cancels a previously scheduled message.
|
||||
*
|
||||
* @param sendMessage May be NULL.
|
||||
*/
|
||||
void hv_cancelMessage(HeavyContextInterface *c, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Returns the read-only user-assigned name of this patch. */
|
||||
const char *hv_getName(HeavyContextInterface *c);
|
||||
|
||||
/** Sets a user-definable value. This value is never manipulated by Heavy. */
|
||||
void hv_setUserData(HeavyContextInterface *c, void *userData);
|
||||
|
||||
/** Returns the user-defined data. */
|
||||
void *hv_getUserData(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the current patch time in milliseconds. This value may have rounding errors. */
|
||||
double hv_getCurrentTime(HeavyContextInterface *c);
|
||||
|
||||
/** Returns the current patch time in samples. This value is always exact. */
|
||||
hv_uint32_t hv_getCurrentSample(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Returns information about each parameter such as name, hash, and range.
|
||||
* The total number of parameters is always returned.
|
||||
*
|
||||
* @param index The parameter index.
|
||||
* @param info A pointer to a HvParameterInfo struct. May be null.
|
||||
*
|
||||
* @return The total number of parameters.
|
||||
*/
|
||||
int hv_getParameterInfo(HeavyContextInterface *c, int index, HvParameterInfo *info);
|
||||
|
||||
/** */
|
||||
float hv_samplesToMilliseconds(HeavyContextInterface *c, hv_uint32_t numSamples);
|
||||
|
||||
/** Converts milliseconds to samples. Input is limited to non-negative range. */
|
||||
hv_uint32_t hv_millisecondsToSamples(HeavyContextInterface *c, float ms);
|
||||
|
||||
/**
|
||||
* Acquire the input message queue lock.
|
||||
*
|
||||
* This function will block until the message lock as been acquired.
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
*/
|
||||
void hv_lock_acquire(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Try to acquire the input message queue lock.
|
||||
*
|
||||
* If the lock has been acquired, hv_lock_release() must be called to release it.
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
*
|
||||
* @return Returns true if the lock has been acquired, false otherwise.
|
||||
*/
|
||||
bool hv_lock_try(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Release the input message queue lock.
|
||||
*
|
||||
* Typical applications will not require the use of this function.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
*/
|
||||
void hv_lock_release(HeavyContextInterface *c);
|
||||
|
||||
/**
|
||||
* Set the size of the input message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
* @param inQueueKb Must be positive i.e. at least one.
|
||||
*/
|
||||
void hv_setInputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t inQueueKb);
|
||||
|
||||
/**
|
||||
* Set the size of the output message queue in kilobytes.
|
||||
*
|
||||
* The buffer is reset and all existing contents are lost on resize.
|
||||
* Only the default sendhook uses the outgoing message queue. If the default
|
||||
* sendhook is not being used, then this function is not useful.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
* @param outQueueKb Must be postive i.e. at least one.
|
||||
*/
|
||||
void hv_setOutputMessageQueueSize(HeavyContextInterface *c, hv_uint32_t outQueueKb);
|
||||
|
||||
/**
|
||||
* Get the next message in the outgoing queue, will also consume the message.
|
||||
* Returns false if there are no messages.
|
||||
*
|
||||
* @param c A Heavy context.
|
||||
* @param destinationHash a hash of the name of the receiver the message was sent to.
|
||||
* @param outMsg message pointer that is filled by the next message contents.
|
||||
* @param msgLength length of outMsg in bytes.
|
||||
*
|
||||
* @return True if there is a message in the outgoing queue.
|
||||
*/
|
||||
bool hv_getNextSentMessage(HeavyContextInterface *c, hv_uint32_t *destinationHash, HvMessage *outMsg, hv_uint32_t msgLength);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Message
|
||||
#endif
|
||||
|
||||
typedef struct HvMessage HvMessage;
|
||||
|
||||
/** Returns the total size in bytes of a HvMessage with a number of elements on the heap. */
|
||||
unsigned long hv_msg_getByteSize(hv_uint32_t numElements);
|
||||
|
||||
/** Initialise a HvMessage structure with the number of elements and a timestamp (in samples). */
|
||||
void hv_msg_init(HvMessage *m, int numElements, hv_uint32_t timestamp);
|
||||
|
||||
/** Returns the number of elements in this message. */
|
||||
unsigned long hv_msg_getNumElements(const HvMessage *m);
|
||||
|
||||
/** Returns the time at which this message exists (in samples). */
|
||||
hv_uint32_t hv_msg_getTimestamp(const HvMessage *m);
|
||||
|
||||
/** Set the time at which this message should be executed (in samples). */
|
||||
void hv_msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp);
|
||||
|
||||
/** Returns true of the indexed element is a bang. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isBang(const HvMessage *const m, int i);
|
||||
|
||||
/** Sets the indexed element to a bang. Index is not bounds checked. */
|
||||
void hv_msg_setBang(HvMessage *m, int i);
|
||||
|
||||
/** Returns true of the indexed element is a float. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isFloat(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns the indexed element as a float value. Index is not bounds checked. */
|
||||
float hv_msg_getFloat(const HvMessage *const m, int i);
|
||||
|
||||
/** Sets the indexed element to float value. Index is not bounds checked. */
|
||||
void hv_msg_setFloat(HvMessage *m, int i, float f);
|
||||
|
||||
/** Returns true of the indexed element is a symbol. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isSymbol(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns the indexed element as a symbol value. Index is not bounds checked. */
|
||||
const char *hv_msg_getSymbol(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns true of the indexed element is a hash. False otherwise. Index is not bounds checked. */
|
||||
bool hv_msg_isHash(const HvMessage *const m, int i);
|
||||
|
||||
/** Returns the indexed element as a hash value. Index is not bounds checked. */
|
||||
hv_uint32_t hv_msg_getHash(const HvMessage *const m, int i);
|
||||
|
||||
/** Sets the indexed element to symbol value. Index is not bounds checked. */
|
||||
void hv_msg_setSymbol(HvMessage *m, int i, const char *s);
|
||||
|
||||
/**
|
||||
* Returns true if the message has the given format, in number of elements and type. False otherwise.
|
||||
* Valid element types are:
|
||||
* 'b': bang
|
||||
* 'f': float
|
||||
* 's': symbol
|
||||
*
|
||||
* For example, a message with three floats would have a format of "fff". A single bang is "b".
|
||||
* A message with two symbols is "ss". These types can be mixed and matched in any way.
|
||||
*/
|
||||
bool hv_msg_hasFormat(const HvMessage *const m, const char *fmt);
|
||||
|
||||
/**
|
||||
* Returns a basic string representation of the message.
|
||||
* The character array MUST be deallocated by the caller.
|
||||
*/
|
||||
char *hv_msg_toString(const HvMessage *const m);
|
||||
|
||||
/** Copy a message onto the stack. The message persists. */
|
||||
HvMessage *hv_msg_copy(const HvMessage *const m);
|
||||
|
||||
/** Free a copied message. */
|
||||
void hv_msg_free(HvMessage *m);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Heavy Table
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Resizes the table to the given length.
|
||||
*
|
||||
* Existing contents are copied to the new table. Remaining space is cleared
|
||||
* if the table is longer than the original, truncated otherwise.
|
||||
*
|
||||
* @param tableHash The table identifier.
|
||||
* @param newSampleLength The new length of the table, in samples. Must be positive.
|
||||
*
|
||||
* @return False if the table could not be found. True otherwise.
|
||||
*/
|
||||
bool hv_table_setLength(HeavyContextInterface *c, hv_uint32_t tableHash, hv_uint32_t newSampleLength);
|
||||
|
||||
/** Returns a pointer to the raw buffer backing this table. DO NOT free it. */
|
||||
float *hv_table_getBuffer(HeavyContextInterface *c, hv_uint32_t tableHash);
|
||||
|
||||
/** Returns the length of this table in samples. */
|
||||
hv_uint32_t hv_table_getLength(HeavyContextInterface *c, hv_uint32_t tableHash);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_H_
|
||||
51
delay_simple/plugin/source/HvHeavyInternal.h
Normal file
51
delay_simple/plugin/source/HvHeavyInternal.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_INTERNAL_H_
|
||||
#define _HEAVY_INTERNAL_H_
|
||||
|
||||
#include "HvHeavy.h"
|
||||
#include "HvUtils.h"
|
||||
#include "HvTable.h"
|
||||
#include "HvMessage.h"
|
||||
#include "HvMath.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
HvTable *hv_table_get(HeavyContextInterface *c, hv_uint32_t tableHash);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void hv_scheduleMessageForReceiver(HeavyContextInterface *c, hv_uint32_t receiverHash, HvMessage *m);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
HvMessage *hv_scheduleMessageForObject(HeavyContextInterface *c, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *),
|
||||
int letIndex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
136
delay_simple/plugin/source/HvLightPipe.c
Normal file
136
delay_simple/plugin/source/HvLightPipe.c
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvLightPipe.h"
|
||||
|
||||
#if __SSE__ || HV_SIMD_SSE
|
||||
#include <xmmintrin.h>
|
||||
#define hv_sfence() _mm_sfence()
|
||||
#elif __arm__ || HV_SIMD_NEON
|
||||
#if __ARM_ACLE
|
||||
#include <arm_acle.h>
|
||||
// https://msdn.microsoft.com/en-us/library/hh875058.aspx#BarrierRestrictions
|
||||
// http://doxygen.reactos.org/d8/d47/armintr_8h_a02be7ec76ca51842bc90d9b466b54752.html
|
||||
#define hv_sfence() __dmb(0xE) /* _ARM_BARRIER_ST */
|
||||
#elif defined(__GNUC__)
|
||||
#define hv_sfence() __asm__ volatile ("dmb 0xE":::"memory")
|
||||
#else
|
||||
// http://stackoverflow.com/questions/19965076/gcc-memory-barrier-sync-synchronize-vs-asm-volatile-memory
|
||||
#define hv_sfence() __sync_synchronize()
|
||||
#endif
|
||||
#elif HV_WIN
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208(v=vs.85).aspx
|
||||
#define hv_sfence() _WriteBarrier()
|
||||
#else
|
||||
#define hv_sfence() __asm__ volatile("" : : : "memory")
|
||||
#endif
|
||||
|
||||
#define HLP_STOP 0
|
||||
#define HLP_LOOP 0xFFFFFFFF
|
||||
#define HLP_SET_UINT32_AT_BUFFER(a, b) (*((hv_uint32_t *) (a)) = (b))
|
||||
#define HLP_GET_UINT32_AT_BUFFER(a) (*((hv_uint32_t *) (a)))
|
||||
|
||||
hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes) {
|
||||
if (numBytes > 0) {
|
||||
q->buffer = (char *) hv_malloc(numBytes);
|
||||
hv_assert(q->buffer != NULL);
|
||||
HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
|
||||
} else {
|
||||
q->buffer = NULL;
|
||||
}
|
||||
q->writeHead = q->buffer;
|
||||
q->readHead = q->buffer;
|
||||
q->len = numBytes;
|
||||
q->remainingBytes = numBytes;
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
void hLp_free(HvLightPipe *q) {
|
||||
hv_free(q->buffer);
|
||||
}
|
||||
|
||||
hv_uint32_t hLp_hasData(HvLightPipe *q) {
|
||||
hv_uint32_t x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
if (x == HLP_LOOP) {
|
||||
q->readHead = q->buffer;
|
||||
x = HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t bytesToWrite) {
|
||||
char *const readHead = q->readHead;
|
||||
char *const oldWriteHead = q->writeHead;
|
||||
const hv_uint32_t totalByteRequirement = bytesToWrite + 2*sizeof(hv_uint32_t);
|
||||
|
||||
// check if there is enough space to write the data in the remaining
|
||||
// length of the buffer
|
||||
if (totalByteRequirement <= q->remainingBytes) {
|
||||
char *const newWriteHead = oldWriteHead + sizeof(hv_uint32_t) + bytesToWrite;
|
||||
|
||||
// check if writing would overwrite existing data in the pipe (return NULL if so)
|
||||
if ((oldWriteHead < readHead) && (newWriteHead >= readHead)) return NULL;
|
||||
else return (oldWriteHead + sizeof(hv_uint32_t));
|
||||
} else {
|
||||
// there isn't enough space, try looping around to the start
|
||||
if (totalByteRequirement <= q->len) {
|
||||
if ((oldWriteHead < readHead) || ((q->buffer + totalByteRequirement) > readHead)) {
|
||||
return NULL; // overwrite condition
|
||||
} else {
|
||||
q->writeHead = q->buffer;
|
||||
q->remainingBytes = q->len;
|
||||
HLP_SET_UINT32_AT_BUFFER(q->buffer, HLP_STOP);
|
||||
hv_sfence();
|
||||
HLP_SET_UINT32_AT_BUFFER(oldWriteHead, HLP_LOOP);
|
||||
return q->buffer + sizeof(hv_uint32_t);
|
||||
}
|
||||
} else {
|
||||
return NULL; // there isn't enough space to write the data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes) {
|
||||
hv_assert(q->remainingBytes >= (numBytes + 2*sizeof(hv_uint32_t)));
|
||||
q->remainingBytes -= (sizeof(hv_uint32_t) + numBytes);
|
||||
char *const oldWriteHead = q->writeHead;
|
||||
q->writeHead += (sizeof(hv_uint32_t) + numBytes);
|
||||
HLP_SET_UINT32_AT_BUFFER(q->writeHead, HLP_STOP);
|
||||
|
||||
// save everything before this point to memory
|
||||
hv_sfence();
|
||||
|
||||
// then save this
|
||||
HLP_SET_UINT32_AT_BUFFER(oldWriteHead, numBytes);
|
||||
}
|
||||
|
||||
char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes) {
|
||||
*numBytes = HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
char *const readBuffer = q->readHead + sizeof(hv_uint32_t);
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
void hLp_consume(HvLightPipe *q) {
|
||||
hv_assert(HLP_GET_UINT32_AT_BUFFER(q->readHead) != HLP_STOP);
|
||||
q->readHead += sizeof(hv_uint32_t) + HLP_GET_UINT32_AT_BUFFER(q->readHead);
|
||||
}
|
||||
|
||||
void hLp_reset(HvLightPipe *q) {
|
||||
q->writeHead = q->buffer;
|
||||
q->readHead = q->buffer;
|
||||
q->remainingBytes = q->len;
|
||||
memset(q->buffer, 0, q->len);
|
||||
}
|
||||
104
delay_simple/plugin/source/HvLightPipe.h
Normal file
104
delay_simple/plugin/source/HvLightPipe.h
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_LIGHTPIPE_H_
|
||||
#define _HEAVY_LIGHTPIPE_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This pipe assumes that there is only one producer thread and one consumer
|
||||
* thread. This data structure does not support any other configuration.
|
||||
*/
|
||||
typedef struct HvLightPipe {
|
||||
char *buffer;
|
||||
char *writeHead;
|
||||
char *readHead;
|
||||
hv_uint32_t len;
|
||||
hv_uint32_t remainingBytes; // total bytes from write head to end
|
||||
} HvLightPipe;
|
||||
|
||||
/**
|
||||
* Initialise the pipe with a given length, in bytes.
|
||||
* @return Returns the size of the pipe in bytes.
|
||||
*/
|
||||
hv_uint32_t hLp_init(HvLightPipe *q, hv_uint32_t numBytes);
|
||||
|
||||
/**
|
||||
* Frees the internal buffer.
|
||||
* @param q The light pipe.
|
||||
*/
|
||||
void hLp_free(HvLightPipe *q);
|
||||
|
||||
/**
|
||||
* Indicates if data is available for reading.
|
||||
* @param q The light pipe.
|
||||
*
|
||||
* @return Returns the number of bytes available for reading. Zero if no bytes
|
||||
* are available.
|
||||
*/
|
||||
hv_uint32_t hLp_hasData(HvLightPipe *q);
|
||||
|
||||
/**
|
||||
* Returns a pointer to a location in the pipe where numBytes can be written.
|
||||
*
|
||||
* @param numBytes The number of bytes to be written.
|
||||
* @return A pointer to a location where those bytes can be written. Returns
|
||||
* NULL if no more space is available. Successive calls to this
|
||||
* function may eventually return a valid pointer because the readhead
|
||||
* has been advanced on another thread.
|
||||
*/
|
||||
char *hLp_getWriteBuffer(HvLightPipe *q, hv_uint32_t numBytes);
|
||||
|
||||
/**
|
||||
* Indicates to the pipe how many bytes have been written.
|
||||
*
|
||||
* @param numBytes The number of bytes written. In general this should be the
|
||||
* same value as was passed to the preceeding call to
|
||||
* hLp_getWriteBuffer().
|
||||
*/
|
||||
void hLp_produce(HvLightPipe *q, hv_uint32_t numBytes);
|
||||
|
||||
/**
|
||||
* Returns the current read buffer, indicating the number of bytes available
|
||||
* for reading.
|
||||
* @param q The light pipe.
|
||||
* @param numBytes This value will be filled with the number of bytes available
|
||||
* for reading.
|
||||
*
|
||||
* @return A pointer to the read buffer.
|
||||
*/
|
||||
char *hLp_getReadBuffer(HvLightPipe *q, hv_uint32_t *numBytes);
|
||||
|
||||
/**
|
||||
* Indicates that the next set of bytes have been read and are no longer needed.
|
||||
* @param q The light pipe.
|
||||
*/
|
||||
void hLp_consume(HvLightPipe *q);
|
||||
|
||||
// resets the queue to it's initialised state
|
||||
// This should be done when only one thread is accessing the pipe.
|
||||
void hLp_reset(HvLightPipe *q);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_LIGHTPIPE_H_
|
||||
724
delay_simple/plugin/source/HvMath.h
Normal file
724
delay_simple/plugin/source/HvMath.h
Normal file
@ -0,0 +1,724 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_MATH_H_
|
||||
#define _HEAVY_MATH_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
// https://software.intel.com/sites/landingpage/IntrinsicsGuide/
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/ARM-NEON-Intrinsics.html
|
||||
// http://codesuppository.blogspot.co.uk/2015/02/sse2neonh-porting-guide-and-header-file.html
|
||||
|
||||
static inline void __hv_zero_f(hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_setzero_ps();
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_setzero_ps();
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vdupq_n_f32(0.0f);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_zero_i(hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_setzero_si256();
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_setzero_si128();
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vdupq_n_s32(0);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_load_f(float *bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_load_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_load_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vld1q_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = *bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_store_f(float *bOut, hv_bInf_t bIn) {
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_store_ps(bOut, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_store_ps(bOut, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(bOut, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_log2_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_log2_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
// https://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||
__m128i a = _mm_castps_si128(bIn);
|
||||
__m128i b = _mm_srli_epi32(a, 23);
|
||||
__m128i c = _mm_sub_epi32(b, _mm_set1_epi32(127)); // exponent (int)
|
||||
__m128 d = _mm_cvtepi32_ps(c); // exponent (float)
|
||||
__m128i e = _mm_or_si128(_mm_andnot_si128(_mm_set1_epi32(0xFF800000), a), _mm_set1_epi32(0x3F800000));
|
||||
__m128 f = _mm_castsi128_ps(e); // 1+m (float)
|
||||
__m128 g = _mm_add_ps(d, f); // e + 1 + m
|
||||
__m128 h = _mm_add_ps(g, _mm_set1_ps(-0.9569643f)); // e + 1 + m + (sigma-1)
|
||||
*bOut = h;
|
||||
#elif HV_SIMD_NEON
|
||||
int32x4_t a = vreinterpretq_s32_f32(bIn);
|
||||
int32x4_t b = vshrq_n_s32(a, 23);
|
||||
int32x4_t c = vsubq_s32(b, vdupq_n_s32(127));
|
||||
float32x4_t d = vcvtq_f32_s32(c);
|
||||
int32x4_t e = vorrq_s32(vbicq_s32(a, vdupq_n_s32(0xFF800000)), vdupq_n_s32(0x3F800000));
|
||||
float32x4_t f = vreinterpretq_f32_s32(e);
|
||||
float32x4_t g = vaddq_f32(d, f);
|
||||
float32x4_t h = vaddq_f32(g, vdupq_n_f32(-0.9569643f));
|
||||
*bOut = h;
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 1.442695040888963f * hv_log_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOTE(mhroth): this is a pretty ghetto implementation
|
||||
static inline void __hv_cos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_set_ps(
|
||||
hv_cos_f(bIn[7]), hv_cos_f(bIn[6]), hv_cos_f(bIn[5]), hv_cos_f(bIn[4]),
|
||||
hv_cos_f(bIn[3]), hv_cos_f(bIn[2]), hv_cos_f(bIn[1]), hv_cos_f(bIn[0]));
|
||||
#elif HV_SIMD_SSE
|
||||
const float *const b = (float *) &bIn;
|
||||
*bOut = _mm_set_ps(hv_cos_f(b[3]), hv_cos_f(b[2]), hv_cos_f(b[1]), hv_cos_f(b[0]));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = (float32x4_t) {hv_cos_f(bIn[0]), hv_cos_f(bIn[1]), hv_cos_f(bIn[2]), hv_cos_f(bIn[3])};
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_cos_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_acos_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_acos_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_acos_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_acos_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_acos_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_cosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_cosh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_cosh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_cosh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_cosh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_acosh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_acosh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_acosh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_acosh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_acosh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_sin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_sin_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_sin_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_sin_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_sin_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_asin_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_asin_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_asin_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_asin_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_asin_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_sinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_sinh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_sinh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_sinh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_sinh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_asinh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_asinh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_asinh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_asinh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_asinh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_tan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_tan_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_tan_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_tan_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_tan_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_atan_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_atan_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_atan_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_atan_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_atan_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_atan2_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_atan2_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_atan2_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_atan2_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_atan2_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_tanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_tanh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_tanh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_tanh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_tanh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_atanh_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
hv_assert(0); // __hv_atanh_f() not implemented
|
||||
#elif HV_SIMD_SSE
|
||||
hv_assert(0); // __hv_atanh_f() not implemented
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert(0); // __hv_atanh_f() not implemented
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_atanh_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_sqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_sqrt_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_sqrt_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
const float32x4_t y = vrsqrteq_f32(bIn);
|
||||
*bOut = vmulq_f32(bIn, vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y)); // numerical results may be inexact
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_sqrt_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_rsqrt_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_rsqrt_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_rsqrt_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
const float32x4_t y = vrsqrteq_f32(bIn);
|
||||
*bOut = vmulq_f32(vrsqrtsq_f32(vmulq_f32(bIn, y), y), y); // numerical results may be inexact
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = 1.0f/hv_sqrt_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_abs_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_andnot_ps(_mm256_set1_ps(-0.0f), bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_andnot_ps(_mm_set1_ps(-0.0f), bIn); // == 1 << 31
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vabsq_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_abs_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_neg_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_xor_ps(bIn, _mm256_set1_ps(-0.0f));
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_xor_ps(bIn, _mm_set1_ps(-0.0f));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vnegq_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn * -1.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_exp_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
|
||||
_mm256_store_ps(b, bIn);
|
||||
*bOut = _mm256_set_ps(
|
||||
hv_exp_f(b[7]), hv_exp_f(b[6]), hv_exp_f(b[5]), hv_exp_f(b[4]),
|
||||
hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
|
||||
#elif HV_SIMD_SSE
|
||||
float *const b = (float *) hv_alloca(HV_N_SIMD*sizeof(float));
|
||||
_mm_store_ps(b, bIn);
|
||||
*bOut = _mm_set_ps(hv_exp_f(b[3]), hv_exp_f(b[2]), hv_exp_f(b[1]), hv_exp_f(b[0]));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = (float32x4_t) {
|
||||
hv_exp_f(bIn[0]),
|
||||
hv_exp_f(bIn[1]),
|
||||
hv_exp_f(bIn[2]),
|
||||
hv_exp_f(bIn[3])};
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_exp_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_ceil_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_ceil_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_ceil_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vrndpq_f32(bIn);
|
||||
#else
|
||||
// A slow NEON implementation of __hv_ceil_f() is being used because
|
||||
// the necessary intrinsic cannot be found. It is only available in ARMv8.
|
||||
*bOut = (float32x4_t) {hv_ceil_f(bIn[0]), hv_ceil_f(bIn[1]), hv_ceil_f(bIn[2]), hv_ceil_f(bIn[3])};
|
||||
#endif // vrndpq_f32
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_ceil_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_floor_f(hv_bInf_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_floor_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_floor_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vrndmq_f32(bIn);
|
||||
#else
|
||||
// A slow implementation of __hv_floor_f() is being used because
|
||||
// the necessary intrinsic cannot be found. It is only available from ARMv8.
|
||||
*bOut = (float32x4_t) {hv_floor_f(bIn[0]), hv_floor_f(bIn[1]), hv_floor_f(bIn[2]), hv_floor_f(bIn[3])};
|
||||
#endif // vrndmq_f32
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_floor_f(bIn);
|
||||
#endif
|
||||
}
|
||||
|
||||
// __add~f
|
||||
static inline void __hv_add_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_add_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_add_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vaddq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 + bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __add~i
|
||||
static inline void __hv_add_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_add_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_add_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_add_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vaddq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 + bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __sub~f
|
||||
static inline void __hv_sub_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_sub_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_sub_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vsubq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 - bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __mul~f
|
||||
static inline void __hv_mul_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_mul_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_mul_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmulq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 * bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __*~i
|
||||
static inline void __hv_mul_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_mullo_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_mullo_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_mullo_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmulq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = bIn0 * bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __cast~if
|
||||
static inline void __hv_cast_if(hv_bIni_t bIn, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cvtepi32_ps(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cvtepi32_ps(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vcvtq_f32_s32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (float) bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
// __cast~fi
|
||||
static inline void __hv_cast_fi(hv_bInf_t bIn, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cvtps_epi32(bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cvtps_epi32(bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vcvtq_s32_f32(bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (int) bIn;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_div_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m256 a = _mm256_cmp_ps(bIn1, _mm256_setzero_ps(), _CMP_EQ_OQ);
|
||||
__m256 b = _mm256_div_ps(bIn0, bIn1);
|
||||
*bOut = _mm256_andnot_ps(a, b);
|
||||
#elif HV_SIMD_SSE
|
||||
__m128 a = _mm_cmpeq_ps(bIn1, _mm_setzero_ps());
|
||||
__m128 b = _mm_div_ps(bIn0, bIn1);
|
||||
*bOut = _mm_andnot_ps(a, b);
|
||||
#elif HV_SIMD_NEON
|
||||
uint32x4_t a = vceqq_f32(bIn1, vdupq_n_f32(0.0f));
|
||||
float32x4_t b = vmulq_f32(bIn0, vrecpeq_f32(bIn1)); // NOTE(mhroth): numerical results may be inexact
|
||||
*bOut = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(b), a));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn1 != 0.0f) ? (bIn0 / bIn1) : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_min_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_min_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_min_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vminq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_min_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_min_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_min_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_min_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_min_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vminq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_min_i(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_max_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_max_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_max_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmaxq_f32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_max_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_max_i(hv_bIni_t bIn0, hv_bIni_t bIn1, hv_bOuti_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
__m128i x = _mm_max_epi32(_mm256_castsi256_si128(bIn0), _mm256_castsi256_si128(bIn1));
|
||||
__m128i y = _mm_max_epi32(_mm256_extractf128_si256(bIn0, 1), _mm256_extractf128_si256(bIn1, 1));
|
||||
*bOut = _mm256_insertf128_si256(_mm256_castsi128_si256(x), y, 1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_max_epi32(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vmaxq_s32(bIn0, bIn1);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_max_i(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_pow_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
float *b = (float *) hv_alloca(16*sizeof(float));
|
||||
_mm256_store_ps(b, bIn0);
|
||||
_mm256_store_ps(b+8, bIn1);
|
||||
*bOut = _mm256_set_ps(
|
||||
hv_pow_f(b[7], b[7]),
|
||||
hv_pow_f(b[6], b[6]),
|
||||
hv_pow_f(b[5], b[5]),
|
||||
hv_pow_f(b[4], b[4]),
|
||||
hv_pow_f(b[3], b[3]),
|
||||
hv_pow_f(b[2], b[2]),
|
||||
hv_pow_f(b[1], b[1]),
|
||||
hv_pow_f(b[0], b[0]));
|
||||
#elif HV_SIMD_SSE
|
||||
float *b = (float *) hv_alloca(8*sizeof(float));
|
||||
_mm_store_ps(b, bIn0);
|
||||
_mm_store_ps(b+4, bIn1);
|
||||
*bOut = _mm_set_ps(
|
||||
hv_pow_f(b[3], b[7]),
|
||||
hv_pow_f(b[2], b[6]),
|
||||
hv_pow_f(b[1], b[5]),
|
||||
hv_pow_f(b[0], b[4]));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = (float32x4_t) {
|
||||
hv_pow_f(bIn0[0], bIn1[0]),
|
||||
hv_pow_f(bIn0[1], bIn1[1]),
|
||||
hv_pow_f(bIn0[2], bIn1[2]),
|
||||
hv_pow_f(bIn0[3], bIn1[3])};
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_pow_f(bIn0, bIn1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_gt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GT_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmpgt_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcgtq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 > bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_gte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_GE_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmpge_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcgeq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 >= bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_lt_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LT_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmplt_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcltq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 < bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_lte_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_LE_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmple_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vcleq_f32(bIn0, bIn1));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 <= bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_neq_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_cmp_ps(bIn0, bIn1, _CMP_NEQ_OQ);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_cmpneq_ps(bIn0, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(bIn0, bIn1)));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 != bIn1) ? 1.0f : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_or_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_or_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_or_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
|
||||
#else // HV_SIMD_NONE
|
||||
if (bIn0 == 0.0f && bIn1 == 0.0f) *bOut = 0.0f;
|
||||
else if (bIn0 == 0.0f) *bOut = bIn1;
|
||||
else if (bIn1 == 0.0f) *bOut = bIn0;
|
||||
else hv_assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_and_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_and_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_and_ps(bIn1, bIn0);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(bIn1), vreinterpretq_u32_f32(bIn0)));
|
||||
#else // HV_SIMD_NONE
|
||||
if (bIn0 == 0.0f || bIn1 == 0.0f) *bOut = 0.0f;
|
||||
else if (bIn0 == 1.0f) *bOut = bIn1;
|
||||
else if (bIn1 == 1.0f) *bOut = bIn0;
|
||||
else hv_assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __hv_andnot_f(hv_bInf_t bIn0_mask, hv_bInf_t bIn1, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_andnot_ps(bIn0_mask, bIn1);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_andnot_ps(bIn0_mask, bIn1);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vreinterpretq_f32_s32(vbicq_s32(vreinterpretq_s32_f32(bIn1), vreinterpretq_s32_f32(bIn0_mask)));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0_mask == 0.0f) ? bIn1 : 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
// bOut = (bIn0 * bIn1) + bIn2
|
||||
static inline void __hv_fma_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm256_fmadd_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm256_add_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_SSE
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm_fmadd_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm_add_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vfmaq_f32(bIn2, bIn0, bIn1);
|
||||
#else
|
||||
// NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
|
||||
*bOut = vaddq_f32(vmulq_f32(bIn0, bIn1), bIn2);
|
||||
#endif
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = hv_fma_f(bIn0, bIn1, bIn2);
|
||||
#endif
|
||||
}
|
||||
|
||||
// bOut = (bIn0 * bIn1) - bIn2
|
||||
static inline void __hv_fms_f(hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bInf_t bIn2, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm256_fmsub_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm256_sub_ps(_mm256_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_SSE
|
||||
#if HV_SIMD_FMA
|
||||
*bOut = _mm_fmsub_ps(bIn0, bIn1, bIn2);
|
||||
#else
|
||||
*bOut = _mm_sub_ps(_mm_mul_ps(bIn0, bIn1), bIn2);
|
||||
#endif // HV_SIMD_FMA
|
||||
#elif HV_SIMD_NEON
|
||||
#if __ARM_ARCH >= 8
|
||||
*bOut = vfmsq_f32(bIn2, bIn0, bIn1);
|
||||
#else
|
||||
// NOTE(mhroth): it turns out, fma SUUUUCKS on lesser ARM architectures
|
||||
*bOut = vsubq_f32(vmulq_f32(bIn0, bIn1), bIn2);
|
||||
#endif
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (bIn0 * bIn1) - bIn2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _HEAVY_MATH_H_
|
||||
199
delay_simple/plugin/source/HvMessage.c
Normal file
199
delay_simple/plugin/source/HvMessage.c
Normal file
@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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"
|
||||
|
||||
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] = hv_snprintf(NULL, 0, "%s", "bang") + 1; break;
|
||||
case HV_MSG_FLOAT: len[i] = hv_snprintf(NULL, 0, "%g", msg_getFloat(m, i)) + 1; break;
|
||||
case HV_MSG_SYMBOL: len[i] = hv_snprintf(NULL, 0, "%s", msg_getSymbol(m, i)) + 1; break;
|
||||
case HV_MSG_HASH: len[i] = hv_snprintf(NULL, 0, "0x%X", msg_getHash(m, i)) + 1; 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));
|
||||
hv_assert(finalString != NULL);
|
||||
int pos = 0;
|
||||
for (int i = 0; i < msg_getNumElements(m); i++) {
|
||||
// put a string representation of each atom into the final string
|
||||
switch (msg_getType(m, i)) {
|
||||
case HV_MSG_BANG: hv_snprintf(finalString+pos, len[i], "%s", "bang"); break;
|
||||
case HV_MSG_FLOAT: hv_snprintf(finalString+pos, len[i], "%g", msg_getFloat(m, i)); break;
|
||||
case HV_MSG_SYMBOL: hv_snprintf(finalString+pos, len[i], "%s", msg_getSymbol(m, i)); break;
|
||||
case HV_MSG_HASH: hv_snprintf(finalString+pos, len[i], "0x%X", msg_getHash(m, i)); break;
|
||||
default: break;
|
||||
}
|
||||
pos += len[i];
|
||||
finalString[pos-1] = 32; // ASCII space
|
||||
}
|
||||
finalString[size-1] = '\0'; // ensure that the string is null terminated
|
||||
return finalString;
|
||||
}
|
||||
183
delay_simple/plugin/source/HvMessage.h
Normal file
183
delay_simple/plugin/source/HvMessage.h
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_MESSAGE_H_
|
||||
#define _HEAVY_MESSAGE_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum ElementType {
|
||||
HV_MSG_BANG = 0,
|
||||
HV_MSG_FLOAT = 1,
|
||||
HV_MSG_SYMBOL = 2,
|
||||
HV_MSG_HASH = 3
|
||||
} ElementType;
|
||||
|
||||
typedef struct Element {
|
||||
ElementType type;
|
||||
union {
|
||||
float f; // float
|
||||
const char *s; // symbol
|
||||
hv_uint32_t h; // hash
|
||||
} data;
|
||||
} Element;
|
||||
|
||||
typedef struct HvMessage {
|
||||
hv_uint32_t timestamp; // the sample at which this message should be processed
|
||||
hv_uint16_t numElements;
|
||||
hv_uint16_t numBytes; // the total number of bytes that this message occupies in memory, including strings
|
||||
Element elem;
|
||||
} HvMessage;
|
||||
|
||||
typedef struct ReceiverMessagePair {
|
||||
hv_uint32_t receiverHash;
|
||||
HvMessage msg;
|
||||
} ReceiverMessagePair;
|
||||
|
||||
#define HV_MESSAGE_ON_STACK(_x) (HvMessage *) hv_alloca(msg_getCoreSize(_x))
|
||||
|
||||
/** Returns the number of bytes that this message consumes in memory, not including strings. */
|
||||
static inline hv_size_t msg_getCoreSize(hv_size_t numElements) {
|
||||
hv_assert(numElements > 0);
|
||||
return sizeof(HvMessage) + ((numElements-1) * sizeof(Element));
|
||||
}
|
||||
|
||||
HvMessage *msg_copy(const HvMessage *m);
|
||||
|
||||
/** Copies the message into the given buffer. The buffer must be at least as large as msg_getNumHeapBytes(). */
|
||||
void msg_copyToBuffer(const HvMessage *m, char *buffer, hv_size_t len);
|
||||
|
||||
void msg_setElementToFrom(HvMessage *n, int indexN, const HvMessage *const m, int indexM);
|
||||
|
||||
/** Frees a message on the heap. Does nothing if argument is NULL. */
|
||||
void msg_free(HvMessage *m);
|
||||
|
||||
HvMessage *msg_init(HvMessage *m, hv_size_t numElements, hv_uint32_t timestamp);
|
||||
|
||||
HvMessage *msg_initWithFloat(HvMessage *m, hv_uint32_t timestamp, float f);
|
||||
|
||||
HvMessage *msg_initWithBang(HvMessage *m, hv_uint32_t timestamp);
|
||||
|
||||
HvMessage *msg_initWithSymbol(HvMessage *m, hv_uint32_t timestamp, const char *s);
|
||||
|
||||
HvMessage *msg_initWithHash(HvMessage *m, hv_uint32_t timestamp, hv_uint32_t h);
|
||||
|
||||
static inline hv_uint32_t msg_getTimestamp(const HvMessage *m) {
|
||||
return m->timestamp;
|
||||
}
|
||||
|
||||
static inline void msg_setTimestamp(HvMessage *m, hv_uint32_t timestamp) {
|
||||
m->timestamp = timestamp;
|
||||
}
|
||||
|
||||
static inline int msg_getNumElements(const HvMessage *m) {
|
||||
return (int) m->numElements;
|
||||
}
|
||||
|
||||
/** Returns the total number of bytes this message consumes in memory. */
|
||||
static inline hv_uint32_t msg_getSize(const HvMessage *m) {
|
||||
return m->numBytes;
|
||||
}
|
||||
|
||||
static inline ElementType msg_getType(const HvMessage *m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
return (&(m->elem)+index)->type;
|
||||
}
|
||||
|
||||
static inline void msg_setBang(HvMessage *m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
(&(m->elem)+index)->type = HV_MSG_BANG;
|
||||
(&(m->elem)+index)->data.s = NULL;
|
||||
}
|
||||
|
||||
static inline bool msg_isBang(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_BANG) : false;
|
||||
}
|
||||
|
||||
static inline void msg_setFloat(HvMessage *m, int index, float f) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
(&(m->elem)+index)->type = HV_MSG_FLOAT;
|
||||
(&(m->elem)+index)->data.f = f;
|
||||
}
|
||||
|
||||
static inline float msg_getFloat(const HvMessage *const m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
return (&(m->elem)+index)->data.f;
|
||||
}
|
||||
|
||||
static inline bool msg_isFloat(const HvMessage *const m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m,index) == HV_MSG_FLOAT) : false;
|
||||
}
|
||||
|
||||
static inline void msg_setHash(HvMessage *m, int index, hv_uint32_t h) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
(&(m->elem)+index)->type = HV_MSG_HASH;
|
||||
(&(m->elem)+index)->data.h = h;
|
||||
}
|
||||
|
||||
static inline bool msg_isHash(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_HASH) : false;
|
||||
}
|
||||
|
||||
/** Returns true if the element is a hash or symbol. False otherwise. */
|
||||
static inline bool msg_isHashLike(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? ((msg_getType(m, index) == HV_MSG_HASH) || (msg_getType(m, index) == HV_MSG_SYMBOL)) : false;
|
||||
}
|
||||
|
||||
/** Returns a 32-bit hash of the given element. */
|
||||
hv_uint32_t msg_getHash(const HvMessage *const m, int i);
|
||||
|
||||
static inline void msg_setSymbol(HvMessage *m, int index, const char *s) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
hv_assert(s != NULL);
|
||||
(&(m->elem)+index)->type = HV_MSG_SYMBOL;
|
||||
(&(m->elem)+index)->data.s = s;
|
||||
// NOTE(mhroth): if the same message container is reused and string reset,
|
||||
// then the message size will be overcounted
|
||||
m->numBytes += (hv_uint16_t) (hv_strlen(s) + 1); // also count '\0'
|
||||
}
|
||||
|
||||
static inline const char *msg_getSymbol(const HvMessage *m, int index) {
|
||||
hv_assert(index < msg_getNumElements(m)); // invalid index
|
||||
return (&(m->elem)+index)->data.s;
|
||||
}
|
||||
|
||||
static inline bool msg_isSymbol(const HvMessage *m, int index) {
|
||||
return (index < msg_getNumElements(m)) ? (msg_getType(m, index) == HV_MSG_SYMBOL) : false;
|
||||
}
|
||||
|
||||
bool msg_compareSymbol(const HvMessage *m, int i, const char *s);
|
||||
|
||||
/** Returns 1 if the element i_m of message m is equal to element i_n of message n. */
|
||||
bool msg_equalsElement(const HvMessage *m, int i_m, const HvMessage *n, int i_n);
|
||||
|
||||
bool msg_hasFormat(const HvMessage *m, const char *fmt);
|
||||
|
||||
/**
|
||||
* Create a string representation of the message. Suitable for use by the print object.
|
||||
* The resulting string must be freed by the caller.
|
||||
*/
|
||||
char *msg_toString(const HvMessage *msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_MESSAGE_H_
|
||||
144
delay_simple/plugin/source/HvMessagePool.c
Normal file
144
delay_simple/plugin/source/HvMessagePool.c
Normal file
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvMessagePool.h"
|
||||
#include "HvMessage.h"
|
||||
|
||||
// the number of bytes reserved at a time from the pool
|
||||
#define MP_BLOCK_SIZE_BYTES 512
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - MessageList
|
||||
#endif
|
||||
|
||||
typedef struct MessageListNode {
|
||||
char *p;
|
||||
struct MessageListNode *next;
|
||||
} MessageListNode;
|
||||
|
||||
static inline bool ml_hasAvailable(HvMessagePoolList *ml) {
|
||||
return (ml->head != NULL);
|
||||
}
|
||||
|
||||
static char *ml_pop(HvMessagePoolList *ml) {
|
||||
MessageListNode *n = ml->head;
|
||||
ml->head = n->next;
|
||||
n->next = ml->pool;
|
||||
ml->pool = n;
|
||||
char *const p = n->p;
|
||||
n->p = NULL; // set to NULL to make it clear that this node does not have a valid buffer
|
||||
return p;
|
||||
}
|
||||
|
||||
/** Push a MessageListNode with the given pointer onto the head of the queue. */
|
||||
static void ml_push(HvMessagePoolList *ml, void *p) {
|
||||
MessageListNode *n = NULL;
|
||||
if (ml->pool != NULL) {
|
||||
// take an empty MessageListNode from the pool
|
||||
n = ml->pool;
|
||||
ml->pool = n->next;
|
||||
} else {
|
||||
// a MessageListNode is not available, allocate one
|
||||
n = (MessageListNode *) hv_malloc(sizeof(MessageListNode));
|
||||
hv_assert(n != NULL);
|
||||
}
|
||||
n->p = (char *) p;
|
||||
n->next = ml->head;
|
||||
ml->head = n; // push to the front of the queue
|
||||
}
|
||||
|
||||
static void ml_free(HvMessagePoolList *ml) {
|
||||
if (ml != NULL) {
|
||||
while (ml_hasAvailable(ml)) {
|
||||
ml_pop(ml);
|
||||
}
|
||||
while (ml->pool != NULL) {
|
||||
MessageListNode *n = ml->pool;
|
||||
ml->pool = n->next;
|
||||
hv_free(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - HvMessagePool
|
||||
#endif
|
||||
|
||||
static hv_size_t mp_messagelistIndexForSize(hv_size_t byteSize) {
|
||||
return (hv_size_t) hv_max_i((hv_min_max_log2((hv_uint32_t) byteSize) - 5), 0);
|
||||
}
|
||||
|
||||
hv_size_t mp_init(HvMessagePool *mp, hv_size_t numKB) {
|
||||
mp->bufferSize = numKB * 1024;
|
||||
mp->buffer = (char *) hv_malloc(mp->bufferSize);
|
||||
hv_assert(mp->buffer != NULL);
|
||||
mp->bufferIndex = 0;
|
||||
|
||||
// initialise all message lists
|
||||
for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
|
||||
mp->lists[i].head = NULL;
|
||||
mp->lists[i].pool = NULL;
|
||||
}
|
||||
|
||||
return mp->bufferSize;
|
||||
}
|
||||
|
||||
void mp_free(HvMessagePool *mp) {
|
||||
hv_free(mp->buffer);
|
||||
for (int i = 0; i < MP_NUM_MESSAGE_LISTS; i++) {
|
||||
ml_free(&mp->lists[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_freeMessage(HvMessagePool *mp, HvMessage *m) {
|
||||
const hv_size_t b = msg_getSize(m); // the number of bytes that a message occupies in memory
|
||||
const hv_size_t i = mp_messagelistIndexForSize(b); // the HvMessagePoolList index in the pool
|
||||
HvMessagePoolList *ml = &mp->lists[i];
|
||||
const hv_size_t chunkSize = 32 << i;
|
||||
hv_memclear(m, chunkSize); // clear the chunk, just in case
|
||||
ml_push(ml, m);
|
||||
}
|
||||
|
||||
HvMessage *mp_addMessage(HvMessagePool *mp, const HvMessage *m) {
|
||||
const hv_size_t b = msg_getSize(m);
|
||||
// determine the message list index to allocate data from based on the msg size
|
||||
// smallest chunk size is 32 bytes
|
||||
const hv_size_t i = mp_messagelistIndexForSize(b);
|
||||
|
||||
hv_assert(i < MP_NUM_MESSAGE_LISTS); // how many chunk sizes do we want to support? 32, 64, 128, 256 at the moment
|
||||
HvMessagePoolList *ml = &mp->lists[i];
|
||||
const hv_size_t chunkSize = 32 << i;
|
||||
|
||||
if (ml_hasAvailable(ml)) {
|
||||
char *buf = ml_pop(ml);
|
||||
msg_copyToBuffer(m, buf, chunkSize);
|
||||
return (HvMessage *) buf;
|
||||
} else {
|
||||
// if no appropriately sized buffer is immediately available, increase the size of the used buffer
|
||||
const hv_size_t newIndex = mp->bufferIndex + MP_BLOCK_SIZE_BYTES;
|
||||
hv_assert((newIndex <= mp->bufferSize) &&
|
||||
"The message pool buffer size has been exceeded. The context cannot store more messages. "
|
||||
"Try using the new_with_options() initialiser with a larger pool size (default is 10KB).");
|
||||
|
||||
for (hv_size_t j = mp->bufferIndex; j < newIndex; j += chunkSize) {
|
||||
ml_push(ml, mp->buffer + j); // push new nodes onto the list with chunk pointers
|
||||
}
|
||||
mp->bufferIndex = newIndex;
|
||||
char *buf = ml_pop(ml);
|
||||
msg_copyToBuffer(m, buf, chunkSize);
|
||||
return (HvMessage *) buf;
|
||||
}
|
||||
}
|
||||
67
delay_simple/plugin/source/HvMessagePool.h
Normal file
67
delay_simple/plugin/source/HvMessagePool.h
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 _MESSAGE_POOL_H_
|
||||
#define _MESSAGE_POOL_H_
|
||||
|
||||
#include "HvUtils.h"
|
||||
|
||||
#define MP_NUM_MESSAGE_LISTS 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct HvMessagePoolList {
|
||||
struct MessageListNode *head; // list of currently available blocks
|
||||
struct MessageListNode *pool; // list of currently used blocks
|
||||
} HvMessagePoolList;
|
||||
|
||||
typedef struct HvMessagePool {
|
||||
char *buffer; // the buffer of all messages
|
||||
hv_size_t bufferSize; // in bytes
|
||||
hv_size_t bufferIndex; // the number of total reserved bytes
|
||||
|
||||
HvMessagePoolList lists[MP_NUM_MESSAGE_LISTS];
|
||||
} HvMessagePool;
|
||||
|
||||
/**
|
||||
* The HvMessagePool is a basic memory management system. It reserves a large block of memory at initialisation
|
||||
* and proceeds to divide this block into smaller chunks (usually 512 bytes) as they are needed. These chunks are
|
||||
* further divided into 32, 64, 128, or 256 sections. Each of these sections is managed by a HvMessagePoolList (MPL).
|
||||
* An MPL is a linked-list data structure which is initialised such that its own pool of listnodes is filled with nodes
|
||||
* that point at each subblock (e.g. each 32-byte block of a 512-block chunk).
|
||||
*
|
||||
* HvMessagePool is loosely inspired by TCMalloc. http://goog-perftools.sourceforge.net/doc/tcmalloc.html
|
||||
*/
|
||||
|
||||
hv_size_t mp_init(struct HvMessagePool *mp, hv_size_t numKB);
|
||||
|
||||
void mp_free(struct HvMessagePool *mp);
|
||||
|
||||
/**
|
||||
* Adds a message to the pool and returns a pointer to the copy. Returns NULL
|
||||
* if no space was available in the pool.
|
||||
*/
|
||||
struct HvMessage *mp_addMessage(struct HvMessagePool *mp, const struct HvMessage *m);
|
||||
|
||||
void mp_freeMessage(struct HvMessagePool *mp, struct HvMessage *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _MESSAGE_POOL_H_
|
||||
215
delay_simple/plugin/source/HvMessageQueue.c
Normal file
215
delay_simple/plugin/source/HvMessageQueue.c
Normal file
@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvMessageQueue.h"
|
||||
|
||||
hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB) {
|
||||
hv_assert(poolSizeKB > 0);
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
q->pool = NULL;
|
||||
return mp_init(&q->mp, poolSizeKB);
|
||||
}
|
||||
|
||||
void mq_free(HvMessageQueue *q) {
|
||||
mq_clear(q);
|
||||
while (q->pool != NULL) {
|
||||
MessageNode *n = q->pool;
|
||||
q->pool = q->pool->next;
|
||||
hv_free(n);
|
||||
}
|
||||
mp_free(&q->mp);
|
||||
}
|
||||
|
||||
static MessageNode *mq_getOrCreateNodeFromPool(HvMessageQueue *q) {
|
||||
if (q->pool == NULL) {
|
||||
// if necessary, create a new empty node
|
||||
q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode));
|
||||
hv_assert(q->pool != NULL);
|
||||
q->pool->next = NULL;
|
||||
}
|
||||
MessageNode *node = q->pool;
|
||||
q->pool = q->pool->next;
|
||||
return node;
|
||||
}
|
||||
|
||||
int mq_size(HvMessageQueue *q) {
|
||||
int size = 0;
|
||||
MessageNode *n = q->head;
|
||||
while (n != NULL) {
|
||||
++size;
|
||||
n = n->next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
MessageNode *node = mq_getOrCreateNodeFromPool(q);
|
||||
node->m = mp_addMessage(&q->mp, m);
|
||||
node->let = let;
|
||||
node->sendMessage = sendMessage;
|
||||
node->prev = NULL;
|
||||
node->next = NULL;
|
||||
|
||||
if (q->tail != NULL) {
|
||||
// the list already contains elements
|
||||
q->tail->next = node;
|
||||
node->prev = q->tail;
|
||||
q->tail = node;
|
||||
} else {
|
||||
// the list is empty
|
||||
node->prev = NULL;
|
||||
q->head = node;
|
||||
q->tail = node;
|
||||
}
|
||||
return mq_node_getMessage(node);
|
||||
}
|
||||
|
||||
HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (mq_hasMessage(q)) {
|
||||
MessageNode *n = mq_getOrCreateNodeFromPool(q);
|
||||
n->m = mp_addMessage(&q->mp, m);
|
||||
n->let = let;
|
||||
n->sendMessage = sendMessage;
|
||||
|
||||
if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) {
|
||||
// the message occurs before the current head
|
||||
n->next = q->head;
|
||||
q->head->prev = n;
|
||||
n->prev = NULL;
|
||||
q->head = n;
|
||||
} else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) {
|
||||
// the message occurs after the current tail
|
||||
n->next = NULL;
|
||||
n->prev = q->tail;
|
||||
q->tail->next = n;
|
||||
q->tail = n;
|
||||
} else {
|
||||
// the message occurs somewhere between the head and tail
|
||||
MessageNode *node = q->head;
|
||||
while (node != NULL) {
|
||||
if (msg_getTimestamp(m) < msg_getTimestamp(node->next->m)) {
|
||||
MessageNode *r = node->next;
|
||||
node->next = n;
|
||||
n->next = r;
|
||||
n->prev = node;
|
||||
r->prev = n;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
return n->m;
|
||||
} else {
|
||||
// add a message to the head
|
||||
return mq_addMessage(q, m, let, sendMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void mq_pop(HvMessageQueue *q) {
|
||||
if (mq_hasMessage(q)) {
|
||||
MessageNode *n = q->head;
|
||||
|
||||
mp_freeMessage(&q->mp, n->m);
|
||||
n->m = NULL;
|
||||
|
||||
n->let = 0;
|
||||
n->sendMessage = NULL;
|
||||
|
||||
q->head = n->next;
|
||||
if (q->head == NULL) {
|
||||
q->tail = NULL;
|
||||
} else {
|
||||
q->head->prev = NULL;
|
||||
}
|
||||
n->next = q->pool;
|
||||
n->prev = NULL;
|
||||
q->pool = n;
|
||||
}
|
||||
}
|
||||
|
||||
bool mq_removeMessage(HvMessageQueue *q, HvMessage *m, void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (mq_hasMessage(q)) {
|
||||
if (mq_node_getMessage(q->head) == m) { // msg in head node
|
||||
// only remove the message if sendMessage is the same as the stored one,
|
||||
// if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer
|
||||
if (sendMessage == NULL || q->head->sendMessage == sendMessage) {
|
||||
mq_pop(q);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
MessageNode *prevNode = q->head;
|
||||
MessageNode *currNode = q->head->next;
|
||||
while ((currNode != NULL) && (currNode->m != m)) {
|
||||
prevNode = currNode;
|
||||
currNode = currNode->next;
|
||||
}
|
||||
if (currNode != NULL) {
|
||||
if (sendMessage == NULL || currNode->sendMessage == sendMessage) {
|
||||
mp_freeMessage(&q->mp, m);
|
||||
currNode->m = NULL;
|
||||
currNode->let = 0;
|
||||
currNode->sendMessage = NULL;
|
||||
if (currNode == q->tail) { // msg in tail node
|
||||
prevNode->next = NULL;
|
||||
q->tail = prevNode;
|
||||
} else { // msg in middle node
|
||||
prevNode->next = currNode->next;
|
||||
currNode->next->prev = prevNode;
|
||||
}
|
||||
currNode->next = (q->pool == NULL) ? NULL : q->pool;
|
||||
currNode->prev = NULL;
|
||||
q->pool = currNode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mq_clear(HvMessageQueue *q) {
|
||||
while (mq_hasMessage(q)) {
|
||||
mq_pop(q);
|
||||
}
|
||||
}
|
||||
|
||||
void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp) {
|
||||
MessageNode *n = q->tail;
|
||||
while (n != NULL && timestamp <= msg_getTimestamp(n->m)) {
|
||||
// free the node's message
|
||||
mp_freeMessage(&q->mp, n->m);
|
||||
n->m = NULL;
|
||||
n->let = 0;
|
||||
n->sendMessage = NULL;
|
||||
|
||||
// the tail points at the previous node
|
||||
q->tail = n->prev;
|
||||
|
||||
// put the node back in the pool
|
||||
n->next = q->pool;
|
||||
n->prev = NULL;
|
||||
if (q->pool != NULL) q->pool->prev = n;
|
||||
q->pool = n;
|
||||
|
||||
// update the tail node
|
||||
n = q->tail;
|
||||
}
|
||||
|
||||
if (q->tail == NULL) q->head = NULL;
|
||||
}
|
||||
101
delay_simple/plugin/source/HvMessageQueue.h
Normal file
101
delay_simple/plugin/source/HvMessageQueue.h
Normal file
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 _MESSAGE_QUEUE_H_
|
||||
#define _MESSAGE_QUEUE_H_
|
||||
|
||||
#include "HvMessage.h"
|
||||
#include "HvMessagePool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
class HeavyContextInterface;
|
||||
#else
|
||||
typedef struct HeavyContextInterface HeavyContextInterface;
|
||||
#endif
|
||||
|
||||
typedef struct MessageNode {
|
||||
struct MessageNode *prev; // doubly linked list
|
||||
struct MessageNode *next;
|
||||
HvMessage *m;
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *);
|
||||
int let;
|
||||
} MessageNode;
|
||||
|
||||
/** A doubly linked list containing scheduled messages. */
|
||||
typedef struct HvMessageQueue {
|
||||
MessageNode *head; // the head of the queue
|
||||
MessageNode *tail; // the tail of the queue
|
||||
MessageNode *pool; // the head of the reserve pool
|
||||
HvMessagePool mp;
|
||||
} HvMessageQueue;
|
||||
|
||||
hv_size_t mq_initWithPoolSize(HvMessageQueue *q, hv_size_t poolSizeKB);
|
||||
|
||||
void mq_free(HvMessageQueue *q);
|
||||
|
||||
int mq_size(HvMessageQueue *q);
|
||||
|
||||
static inline HvMessage *mq_node_getMessage(MessageNode *n) {
|
||||
return n->m;
|
||||
}
|
||||
|
||||
static inline int mq_node_getLet(MessageNode *n) {
|
||||
return n->let;
|
||||
}
|
||||
|
||||
static inline bool mq_hasMessage(HvMessageQueue *q) {
|
||||
return (q->head != NULL);
|
||||
}
|
||||
|
||||
// true if there is a message and it occurs before (<) timestamp
|
||||
static inline bool mq_hasMessageBefore(HvMessageQueue *const q, const hv_uint32_t timestamp) {
|
||||
return mq_hasMessage(q) && (msg_getTimestamp(mq_node_getMessage(q->head)) < timestamp);
|
||||
}
|
||||
|
||||
static inline MessageNode *mq_peek(HvMessageQueue *q) {
|
||||
return q->head;
|
||||
}
|
||||
|
||||
/** Appends the message to the end of the queue. */
|
||||
HvMessage *mq_addMessage(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Insert in ascending order the message acccording to its timestamp. */
|
||||
HvMessage *mq_addMessageByTimestamp(HvMessageQueue *q, const HvMessage *m, int let,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Pop the message at the head of the queue (and free its memory). */
|
||||
void mq_pop(HvMessageQueue *q);
|
||||
|
||||
/** Remove a message from the queue (and free its memory) */
|
||||
bool mq_removeMessage(HvMessageQueue *q, HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
/** Clears (and frees) all messages in the queue. */
|
||||
void mq_clear(HvMessageQueue *q);
|
||||
|
||||
/** Removes all messages occuring at or after the given timestamp. */
|
||||
void mq_clearAfter(HvMessageQueue *q, const hv_uint32_t timestamp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _MESSAGE_QUEUE_H_
|
||||
77
delay_simple/plugin/source/HvSignalTabread.c
Normal file
77
delay_simple/plugin/source/HvSignalTabread.c
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvSignalTabread.h"
|
||||
|
||||
hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads) {
|
||||
o->table = table;
|
||||
o->head = 0;
|
||||
o->forceAlignedLoads = forceAlignedLoads;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
case 0: {
|
||||
if (o->table != NULL) {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_BANG: o->head = 0; break;
|
||||
case HV_MSG_FLOAT: {
|
||||
hv_uint32_t h = (hv_uint32_t) hv_abs_f(msg_getFloat(m,0));
|
||||
if (msg_getFloat(m,0) < 0.0f) {
|
||||
// if input is negative, wrap around the end of the table
|
||||
h = hTable_getSize(o->table) - h;
|
||||
}
|
||||
o->head = o->forceAlignedLoads ? (h & ~HV_N_SIMD_MASK) : h;
|
||||
|
||||
// output new head
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) o->head);
|
||||
sendMessage(_c, 1, n);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabhead
|
||||
#endif
|
||||
|
||||
void sTabhead_onMessage(HeavyContextInterface *_c, SignalTabhead *o, const HvMessage *m) {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
}
|
||||
|
||||
hv_size_t sTabhead_init(SignalTabhead *o, HvTable *table) {
|
||||
o->table = table;
|
||||
return 0;
|
||||
}
|
||||
183
delay_simple/plugin/source/HvSignalTabread.h
Normal file
183
delay_simple/plugin/source/HvSignalTabread.h
Normal file
@ -0,0 +1,183 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_SIGNAL_TABREAD_H_
|
||||
#define _HEAVY_SIGNAL_TABREAD_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct SignalTabread {
|
||||
HvTable *table; // the table to read
|
||||
hv_uint32_t head;
|
||||
bool forceAlignedLoads; // false by default, true if using __hv_tabread_f
|
||||
} SignalTabread;
|
||||
|
||||
// random access to a table
|
||||
hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads);
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabread - Random Access
|
||||
#endif
|
||||
|
||||
static inline void __hv_tabread_if(SignalTabread *o, hv_bIni_t bIn, hv_bOutf_t bOut) {
|
||||
const float *const b = hTable_getBuffer(o->table);
|
||||
#if HV_SIMD_AVX
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn;
|
||||
|
||||
hv_assert(i[0] >= 0 && i[0] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && i[1] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && i[2] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && i[3] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[4] >= 0 && i[4] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[5] >= 0 && i[5] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[6] >= 0 && i[6] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[7] >= 0 && i[7] < hTable_getAllocated(o->table));
|
||||
|
||||
*bOut = _mm256_set_ps(b[i[7]], b[i[6]], b[i[5]], b[i[4]], b[i[3]], b[i[2]], b[i[1]], b[i[0]]);
|
||||
#elif HV_SIMD_SSE
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn;
|
||||
|
||||
hv_assert(i[0] >= 0 && ((hv_uint32_t) i[0]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && ((hv_uint32_t) i[1]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && ((hv_uint32_t) i[2]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && ((hv_uint32_t) i[3]) < hTable_getAllocated(o->table));
|
||||
|
||||
*bOut = _mm_set_ps(b[i[3]], b[i[2]], b[i[1]], b[i[0]]);
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert((bIn[0] >= 0) && (bIn[0] < hTable_getAllocated(o->table)));
|
||||
hv_assert((bIn[1] >= 0) && (bIn[1] < hTable_getAllocated(o->table)));
|
||||
hv_assert((bIn[2] >= 0) && (bIn[2] < hTable_getAllocated(o->table)));
|
||||
hv_assert((bIn[3] >= 0) && (bIn[3] < hTable_getAllocated(o->table)));
|
||||
|
||||
*bOut = (float32x4_t) {b[bIn[0]], b[bIn[1]], b[bIn[2]], b[bIn[3]]};
|
||||
#else // HV_SIMD_NONE
|
||||
hv_assert(bIn >= 0 && ((hv_uint32_t) bIn < hTable_getAllocated(o->table)));
|
||||
|
||||
*bOut = b[bIn];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabread - Linear Access
|
||||
#endif
|
||||
|
||||
// this tabread never stops reading. It is mainly intended for linear reads that loop around a table.
|
||||
static inline void __hv_tabread_f(SignalTabread *o, hv_bOutf_t bOut) {
|
||||
hv_assert((o->head + HV_N_SIMD) <= hTable_getAllocated(o->table)); // assert that we always read within the table bounds
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_load_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_load_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vld1q_f32(hTable_getBuffer(o->table) + head);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = *(hTable_getBuffer(o->table) + head);
|
||||
#endif
|
||||
o->head = head + HV_N_SIMD;
|
||||
}
|
||||
|
||||
// unaligned linear tabread, as above
|
||||
static inline void __hv_tabreadu_f(SignalTabread *o, hv_bOutf_t bOut) {
|
||||
hv_assert((o->head + HV_N_SIMD) <= hTable_getAllocated(o->table)); // assert that we always read within the table bounds
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_loadu_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_loadu_ps(hTable_getBuffer(o->table) + head);
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vld1q_f32(hTable_getBuffer(o->table) + head);
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = *(hTable_getBuffer(o->table) + head);
|
||||
#endif
|
||||
o->head = head + HV_N_SIMD;
|
||||
}
|
||||
|
||||
// this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
|
||||
static inline void __hv_tabread_stoppable_f(SignalTabread *o, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = _mm256_setzero_ps();
|
||||
} else {
|
||||
*bOut = _mm256_load_ps(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#elif HV_SIMD_SSE
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = _mm_setzero_ps();
|
||||
} else {
|
||||
*bOut = _mm_load_ps(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#elif HV_SIMD_NEON
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = vdupq_n_f32(0.0f);
|
||||
} else {
|
||||
*bOut = vld1q_f32(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#else // HV_SIMD_NONE
|
||||
if (o->head == ~0x0) {
|
||||
*bOut = 0.0f;
|
||||
} else {
|
||||
*bOut = *(hTable_getBuffer(o->table) + o->head);
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
|
||||
|
||||
#if HV_APPLE
|
||||
#pragma mark - Tabhead
|
||||
#endif
|
||||
|
||||
typedef struct SignalTabhead {
|
||||
HvTable *table;
|
||||
} SignalTabhead;
|
||||
|
||||
hv_size_t sTabhead_init(SignalTabhead *o, HvTable *table);
|
||||
|
||||
static inline void __hv_tabhead_f(SignalTabhead *o, hv_bOutf_t bOut) {
|
||||
#if HV_SIMD_AVX
|
||||
*bOut = _mm256_set1_ps((float) hTable_getHead(o->table));
|
||||
#elif HV_SIMD_SSE
|
||||
*bOut = _mm_set1_ps((float) hTable_getHead(o->table));
|
||||
#elif HV_SIMD_NEON
|
||||
*bOut = vdupq_n_f32((float32_t) hTable_getHead(o->table));
|
||||
#else // HV_SIMD_NONE
|
||||
*bOut = (float) hTable_getHead(o->table);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sTabhead_onMessage(HeavyContextInterface *_c, SignalTabhead *o, const HvMessage *m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_SIGNAL_TABREAD_H_
|
||||
54
delay_simple/plugin/source/HvSignalTabwrite.c
Normal file
54
delay_simple/plugin/source/HvSignalTabwrite.c
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvSignalTabwrite.h"
|
||||
|
||||
hv_size_t sTabwrite_init(SignalTabwrite *o, HvTable *table) {
|
||||
o->table = table;
|
||||
o->head = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sTabwrite_onMessage(HeavyContextInterface *_c, SignalTabwrite *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
switch (letIn) {
|
||||
// inlet 0 is the signal inlet
|
||||
case 1: {
|
||||
switch (msg_getType(m,0)) {
|
||||
case HV_MSG_BANG: o->head = 0; break;
|
||||
case HV_MSG_FLOAT: {
|
||||
o->head = (msg_getFloat(m,0) >= 0.0f) ? (hv_uint32_t) msg_getFloat(m,0) : HV_TABWRITE_STOPPED;
|
||||
break;
|
||||
}
|
||||
case HV_MSG_SYMBOL: {
|
||||
if (msg_compareSymbol(m, 0, "stop")) {
|
||||
o->head = HV_TABWRITE_STOPPED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
if (msg_isHashLike(m,0)) {
|
||||
o->table = hv_table_get(_c, msg_getHash(m,0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
147
delay_simple/plugin/source/HvSignalTabwrite.h
Normal file
147
delay_simple/plugin/source/HvSignalTabwrite.h
Normal file
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_SIGNAL_TABWRITE_H_
|
||||
#define _HEAVY_SIGNAL_TABWRITE_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HV_TABWRITE_STOPPED -1 // ~0x0
|
||||
|
||||
typedef struct SignalTabwrite {
|
||||
HvTable *table;
|
||||
hv_uint32_t head; // local write head. Where this object has most recently written to the table.
|
||||
} SignalTabwrite;
|
||||
|
||||
hv_size_t sTabwrite_init(SignalTabwrite *o, HvTable *table);
|
||||
|
||||
void sTabwrite_onMessage(HeavyContextInterface *_c, SignalTabwrite *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
// linear write to table
|
||||
static inline void __hv_tabwrite_f(SignalTabwrite *o, hv_bInf_t bIn) {
|
||||
hv_assert((o->head + HV_N_SIMD) <= hTable_getSize(o->table)); // assert that the table bounds are respected
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_store_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_store_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(hTable_getBuffer(o->table) + head, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*(hTable_getBuffer(o->table) + head) = bIn;
|
||||
#endif
|
||||
head += HV_N_SIMD;
|
||||
o->head = head; // update local write head
|
||||
hTable_setHead(o->table, head); // update the remote write head (e.g. for use by vd~)
|
||||
}
|
||||
|
||||
// linear unaligned write to table
|
||||
static inline void __hv_tabwriteu_f(SignalTabwrite *o, hv_bInf_t bIn) {
|
||||
hv_uint32_t head = o->head;
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_storeu_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_storeu_ps(hTable_getBuffer(o->table) + head, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(hTable_getBuffer(o->table) + head, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*(hTable_getBuffer(o->table) + head) = bIn;
|
||||
#endif
|
||||
head += HV_N_SIMD;
|
||||
o->head = head; // update local write head
|
||||
hTable_setHead(o->table, head); // update remote write head
|
||||
}
|
||||
|
||||
// this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
|
||||
// Stores are unaligned, which can be slow but allows any indicies to be written to.
|
||||
// TODO(mhroth): this is not stopping!
|
||||
static inline void __hv_tabwrite_stoppable_f(SignalTabwrite *o, hv_bInf_t bIn) {
|
||||
if (o->head != HV_TABWRITE_STOPPED) {
|
||||
#if HV_SIMD_AVX
|
||||
_mm256_storeu_ps(hTable_getBuffer(o->table) + o->head, bIn);
|
||||
#elif HV_SIMD_SSE
|
||||
_mm_storeu_ps(hTable_getBuffer(o->table) + o->head, bIn);
|
||||
#elif HV_SIMD_NEON
|
||||
vst1q_f32(hTable_getBuffer(o->table) + o->head, bIn);
|
||||
#else // HV_SIMD_NONE
|
||||
*(hTable_getBuffer(o->table) + o->head) = bIn;
|
||||
#endif
|
||||
o->head += HV_N_SIMD;
|
||||
}
|
||||
}
|
||||
|
||||
// random write to table
|
||||
static inline void __hv_tabwrite_if(SignalTabwrite *o, hv_bIni_t bIn0, hv_bInf_t bIn1) {
|
||||
float *const b = hTable_getBuffer(o->table);
|
||||
#if HV_SIMD_AVX
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn0;
|
||||
const float *const f = (float *) &bIn1;
|
||||
|
||||
hv_assert(i[0] >= 0 && i[0] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && i[1] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && i[2] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && i[3] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[4] >= 0 && i[4] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[5] >= 0 && i[5] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[6] >= 0 && i[6] < hTable_getAllocated(o->table));
|
||||
hv_assert(i[7] >= 0 && i[7] < hTable_getAllocated(o->table));
|
||||
|
||||
b[i[0]] = f[0];
|
||||
b[i[1]] = f[1];
|
||||
b[i[2]] = f[2];
|
||||
b[i[3]] = f[3];
|
||||
b[i[4]] = f[4];
|
||||
b[i[5]] = f[5];
|
||||
b[i[6]] = f[6];
|
||||
b[i[7]] = f[7];
|
||||
#elif HV_SIMD_SSE
|
||||
const hv_int32_t *const i = (hv_int32_t *) &bIn0;
|
||||
const float *const f = (float *) &bIn1;
|
||||
|
||||
hv_assert(i[0] >= 0 && ((hv_uint32_t) i[0]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[1] >= 0 && ((hv_uint32_t) i[1]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[2] >= 0 && ((hv_uint32_t) i[2]) < hTable_getAllocated(o->table));
|
||||
hv_assert(i[3] >= 0 && ((hv_uint32_t) i[3]) < hTable_getAllocated(o->table));
|
||||
|
||||
b[i[0]] = f[0];
|
||||
b[i[1]] = f[1];
|
||||
b[i[2]] = f[2];
|
||||
b[i[3]] = f[3];
|
||||
#elif HV_SIMD_NEON
|
||||
hv_assert((vgetq_lane_s32(bIn0,0) >= 0) && (vgetq_lane_s32(bIn0,0) < hTable_getSize(o->table)));
|
||||
hv_assert((vgetq_lane_s32(bIn0,1) >= 0) && (vgetq_lane_s32(bIn0,1) < hTable_getSize(o->table)));
|
||||
hv_assert((vgetq_lane_s32(bIn0,2) >= 0) && (vgetq_lane_s32(bIn0,2) < hTable_getSize(o->table)));
|
||||
hv_assert((vgetq_lane_s32(bIn0,3) >= 0) && (vgetq_lane_s32(bIn0,3) < hTable_getSize(o->table)));
|
||||
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 0), bIn1, 0);
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 1), bIn1, 1);
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 2), bIn1, 2);
|
||||
vst1q_lane_f32(b + vgetq_lane_s32(bIn0, 3), bIn1, 3);
|
||||
#else // HV_SIMD_NONE
|
||||
b[bIn0] = bIn1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_SIGNAL_TABWRITE_H_
|
||||
75
delay_simple/plugin/source/HvSignalVar.c
Normal file
75
delay_simple/plugin/source/HvSignalVar.c
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvSignalVar.h"
|
||||
|
||||
// __var~f
|
||||
|
||||
static void sVarf_update(SignalVarf *o, float k, float step, bool reverse) {
|
||||
#if HV_SIMD_AVX
|
||||
if (reverse) o->v = _mm256_setr_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
else o->v = _mm256_set_ps(k+7.0f*step, k+6.0f*step, k+5.0f*step, k+4.0f*step, k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
#elif HV_SIMD_SSE
|
||||
if (reverse) o->v = _mm_setr_ps(k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
else o->v = _mm_set_ps(k+3.0f*step, k+2.0f*step, k+step, k);
|
||||
#elif HV_SIMD_NEON
|
||||
if (reverse) o->v = (float32x4_t) {3.0f*step+k, 2.0f*step+k, step+k, k};
|
||||
else o->v = (float32x4_t) {k, step+k, 2.0f*step+k, 3.0f*step+k};
|
||||
#else // HV_SIMD_NONE
|
||||
o->v = k;
|
||||
#endif
|
||||
}
|
||||
|
||||
hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse) {
|
||||
sVarf_update(o, k, step, reverse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m) {
|
||||
if (msg_isFloat(m,0)) {
|
||||
sVarf_update(o, msg_getFloat(m,0), msg_isFloat(m,1) ? msg_getFloat(m,1) : 0.0f, msg_getNumElements(m) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// __var~i
|
||||
|
||||
static void sVari_update(SignalVari *o, int k, int step, bool reverse) {
|
||||
#if HV_SIMD_AVX
|
||||
if (reverse) o->v = _mm256_setr_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k);
|
||||
else o->v = _mm256_set_epi32(k+7*step, k+6*step, k+5*step, k+4*step, k+3*step, k+2*step, k+step, k);
|
||||
#elif HV_SIMD_SSE
|
||||
if (reverse) o->v = _mm_setr_epi32(k+3*step, k+2*step, k+step, k);
|
||||
else o->v = _mm_set_epi32(k+3*step, k+2*step, k+step, k);
|
||||
#elif HV_SIMD_NEON
|
||||
if (reverse) o->v = (int32x4_t) {3*step+k, 2*step+k, step+k, k};
|
||||
else o->v = (int32x4_t) {k, step+k, 2*step+k, 3*step+k};
|
||||
#else // HV_SIMD_NEON
|
||||
o->v = k;
|
||||
#endif
|
||||
}
|
||||
|
||||
hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse) {
|
||||
sVari_update(o, k, step, reverse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m) {
|
||||
if (msg_isFloat(m,0)) {
|
||||
sVari_update(o, (int) msg_getFloat(m,0), msg_isFloat(m,1) ? (int) msg_getFloat(m,1) : 0, msg_getNumElements(m) == 3);
|
||||
}
|
||||
}
|
||||
94
delay_simple/plugin/source/HvSignalVar.h
Normal file
94
delay_simple/plugin/source/HvSignalVar.h
Normal file
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_SIGNAL_VAR_H_
|
||||
#define _HEAVY_SIGNAL_VAR_H_
|
||||
|
||||
#include "HvHeavyInternal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// __var~f, __varread~f, __varwrite~f
|
||||
|
||||
typedef struct SignalVarf {
|
||||
hv_bufferf_t v;
|
||||
} SignalVarf;
|
||||
|
||||
hv_size_t sVarf_init(SignalVarf *o, float k, float step, bool reverse);
|
||||
|
||||
static inline void __hv_varread_f(SignalVarf *o, hv_bOutf_t bOut) {
|
||||
*bOut = o->v;
|
||||
}
|
||||
|
||||
static inline void __hv_varwrite_f(SignalVarf *o, hv_bInf_t bIn) {
|
||||
o->v = bIn;
|
||||
}
|
||||
|
||||
void sVarf_onMessage(HeavyContextInterface *_c, SignalVarf *o, const HvMessage *m);
|
||||
|
||||
|
||||
|
||||
// __var~i, __varread~i, __varwrite~i
|
||||
|
||||
typedef struct SignalVari {
|
||||
hv_bufferi_t v;
|
||||
} SignalVari;
|
||||
|
||||
hv_size_t sVari_init(SignalVari *o, int k, int step, bool reverse);
|
||||
|
||||
static inline void __hv_varread_i(SignalVari *o, hv_bOuti_t bOut) {
|
||||
*bOut = o->v;
|
||||
}
|
||||
|
||||
static inline void __hv_varwrite_i(SignalVari *o, hv_bIni_t bIn) {
|
||||
o->v = bIn;
|
||||
}
|
||||
|
||||
void sVari_onMessage(HeavyContextInterface *_c, SignalVari *o, const HvMessage *m);
|
||||
|
||||
|
||||
|
||||
// __var_k~f, __var_k~i
|
||||
|
||||
#if HV_SIMD_AVX
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_h,_g,_f,_e,_d,_c,_b,_a)
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_epi32(_a,_b,_c,_d,_e,_f,_g,_h)
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_h,_g,_f,_e,_d,_c,_b,_a)
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm256_set_ps(_a,_b,_c,_d,_e,_f,_g,_h)
|
||||
#elif HV_SIMD_SSE
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_d,_c,_b,_a)
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_epi32(_a,_b,_c,_d)
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_d,_c,_b,_a)
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_mm_set_ps(_a,_b,_c,_d)
|
||||
#elif HV_SIMD_NEON
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_a,_b,_c,_d})
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((int32x4_t) {_d,_c,_b,_a})
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_a,_b,_c,_d})
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=((float32x4_t) {_d,_c,_b,_a})
|
||||
#else // HV_SIMD_NONE
|
||||
#define __hv_var_k_i(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#define __hv_var_k_i_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#define __hv_var_k_f(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#define __hv_var_k_f_r(_z,_a,_b,_c,_d,_e,_f,_g,_h) *_z=_a
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_SIGNAL_VAR_H_
|
||||
110
delay_simple/plugin/source/HvTable.c
Normal file
110
delay_simple/plugin/source/HvTable.c
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvTable.h"
|
||||
#include "HvMessage.h"
|
||||
|
||||
hv_size_t hTable_init(HvTable *o, int length) {
|
||||
o->length = length;
|
||||
// true size of the table is always an integer multple of HV_N_SIMD
|
||||
o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
|
||||
// add an extra length for mirroring
|
||||
o->allocated = o->size + HV_N_SIMD;
|
||||
o->head = 0;
|
||||
hv_size_t numBytes = o->allocated * sizeof(float);
|
||||
o->buffer = (float *) hv_malloc(numBytes);
|
||||
hv_assert(o->buffer != NULL);
|
||||
hv_memclear(o->buffer, numBytes);
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
hv_size_t hTable_initWithData(HvTable *o, int length, const float *data) {
|
||||
o->length = length;
|
||||
o->size = (length + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
|
||||
o->allocated = o->size + HV_N_SIMD;
|
||||
o->head = 0;
|
||||
hv_size_t numBytes = o->size * sizeof(float);
|
||||
o->buffer = (float *) hv_malloc(numBytes);
|
||||
hv_assert(o->buffer != NULL);
|
||||
hv_memclear(o->buffer, numBytes);
|
||||
hv_memcpy(o->buffer, data, length*sizeof(float));
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data) {
|
||||
o->length = length;
|
||||
o->size = length;
|
||||
o->allocated = length;
|
||||
o->buffer = data;
|
||||
o->head = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hTable_free(HvTable *o) {
|
||||
hv_free(o->buffer);
|
||||
}
|
||||
|
||||
int hTable_resize(HvTable *o, hv_uint32_t newLength) {
|
||||
// TODO(mhroth): update context with memory allocated by table
|
||||
// NOTE(mhroth): mirrored bytes are not necessarily carried over
|
||||
const hv_uint32_t newSize = (newLength + HV_N_SIMD_MASK) & ~HV_N_SIMD_MASK;
|
||||
if (newSize == o->size) return 0; // early exit if no change in size
|
||||
const hv_uint32_t oldSizeBytes = (hv_uint32_t) (o->size * sizeof(float));
|
||||
const hv_uint32_t newAllocated = newSize + HV_N_SIMD;
|
||||
const hv_uint32_t newAllocatedBytes = (hv_uint32_t) (newAllocated * sizeof(float));
|
||||
|
||||
float *b = (float *) hv_realloc(o->buffer, newAllocatedBytes);
|
||||
hv_assert(b != NULL); // error while reallocing!
|
||||
// ensure that hv_realloc has given us a correctly aligned buffer
|
||||
if ((((hv_uintptr_t) (const void *) b) & ((0x1<<HV_N_SIMD)-1)) == 0) {
|
||||
if (newSize > o->size) {
|
||||
hv_memclear(b + o->size, (newAllocated - o->size) * sizeof(float)); // clear new parts of the buffer
|
||||
}
|
||||
o->buffer = b;
|
||||
} else {
|
||||
// if not, we have to re-malloc ourselves
|
||||
char *c = (char *) hv_malloc(newAllocatedBytes);
|
||||
hv_assert(c != NULL); // error while allocating new buffer!
|
||||
if (newAllocatedBytes > oldSizeBytes) {
|
||||
hv_memcpy(c, b, oldSizeBytes);
|
||||
hv_memclear(c + oldSizeBytes, newAllocatedBytes - oldSizeBytes);
|
||||
} else {
|
||||
hv_memcpy(c, b, newAllocatedBytes);
|
||||
}
|
||||
hv_free(b);
|
||||
o->buffer = (float *) c;
|
||||
}
|
||||
o->length = newLength;
|
||||
o->size = newSize;
|
||||
o->allocated = newAllocated;
|
||||
return (int) (newAllocated - oldSizeBytes - (HV_N_SIMD*sizeof(float)));
|
||||
}
|
||||
|
||||
void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *)) {
|
||||
if (msg_compareSymbol(m,0,"resize") && msg_isFloat(m,1) && msg_getFloat(m,1) >= 0.0f) {
|
||||
hTable_resize(o, (int) hv_ceil_f(msg_getFloat(m,1))); // apply ceil to ensure that tables always have enough space
|
||||
|
||||
// send out the new size of the table
|
||||
HvMessage *n = HV_MESSAGE_ON_STACK(1);
|
||||
msg_initWithFloat(n, msg_getTimestamp(m), (float) hTable_getSize(o));
|
||||
sendMessage(_c, 0, n);
|
||||
}
|
||||
|
||||
else if (msg_compareSymbol(m,0,"mirror")) {
|
||||
hv_memcpy(o->buffer+o->size, o->buffer, HV_N_SIMD*sizeof(float));
|
||||
}
|
||||
}
|
||||
88
delay_simple/plugin/source/HvTable.h
Normal file
88
delay_simple/plugin/source/HvTable.h
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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_TABLE_H_
|
||||
#define _HEAVY_TABLE_H_
|
||||
|
||||
#include "HvHeavy.h"
|
||||
#include "HvUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct HvTable {
|
||||
float *buffer;
|
||||
// the number of values that the table is requested to have
|
||||
hv_uint32_t length;
|
||||
|
||||
// the number of usable values that the table actually has
|
||||
// this is always an even multiple of HV_N_SIMD
|
||||
hv_uint32_t size;
|
||||
|
||||
// Note that the true size of the table is (size + HV_N_SIMD),
|
||||
// with the trailing values used by the system, e.g. to create a circular
|
||||
// buffer
|
||||
hv_uint32_t allocated;
|
||||
|
||||
hv_uint32_t head; // the most recently written point
|
||||
} HvTable;
|
||||
|
||||
hv_size_t hTable_init(HvTable *o, int length);
|
||||
|
||||
hv_size_t hTable_initWithData(HvTable *o, int length, const float *data);
|
||||
|
||||
hv_size_t hTable_initWithFinalData(HvTable *o, int length, float *data);
|
||||
|
||||
void hTable_free(HvTable *o);
|
||||
|
||||
int hTable_resize(HvTable *o, hv_uint32_t newLength);
|
||||
|
||||
void hTable_onMessage(HeavyContextInterface *_c, HvTable *o, int letIn, const HvMessage *m,
|
||||
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *));
|
||||
|
||||
static inline float *hTable_getBuffer(HvTable *o) {
|
||||
return o->buffer;
|
||||
}
|
||||
|
||||
// the user-requested length of the table (number of floats)
|
||||
static inline hv_uint32_t hTable_getLength(HvTable *o) {
|
||||
return o->length;
|
||||
}
|
||||
|
||||
// the usable length of the table (an even multiple of HV_N_SIMD)
|
||||
static inline hv_uint32_t hTable_getSize(HvTable *o) {
|
||||
return o->size;
|
||||
}
|
||||
|
||||
// the number of floats allocated to this table (usually size + HV_N_SIMD)
|
||||
static inline hv_uint32_t hTable_getAllocated(HvTable *o) {
|
||||
return o->allocated;
|
||||
}
|
||||
|
||||
static inline hv_uint32_t hTable_getHead(HvTable *o) {
|
||||
return o->head;
|
||||
}
|
||||
|
||||
static inline void hTable_setHead(HvTable *o, hv_uint32_t head) {
|
||||
o->head = head;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _HEAVY_TABLE_H_
|
||||
54
delay_simple/plugin/source/HvUtils.c
Normal file
54
delay_simple/plugin/source/HvUtils.c
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 "HvUtils.h"
|
||||
|
||||
hv_uint32_t hv_string_to_hash(const char *str) {
|
||||
// this hash is based MurmurHash2
|
||||
// http://en.wikipedia.org/wiki/MurmurHash
|
||||
// https://sites.google.com/site/murmurhash/
|
||||
static const hv_uint32_t n = 0x5bd1e995;
|
||||
static const hv_int32_t r = 24;
|
||||
|
||||
if (str == NULL) return 0;
|
||||
|
||||
hv_uint32_t len = (hv_uint32_t) hv_strlen(str);
|
||||
hv_uint32_t x = len; // seed (0) ^ len
|
||||
|
||||
while (len >= 4) {
|
||||
#if HV_EMSCRIPTEN
|
||||
hv_uint32_t k = str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24);
|
||||
#else
|
||||
hv_uint32_t k = *((hv_uint32_t *) str);
|
||||
#endif
|
||||
k *= n;
|
||||
k ^= (k >> r);
|
||||
k *= n;
|
||||
x *= n;
|
||||
x ^= k;
|
||||
str += 4; len -= 4;
|
||||
}
|
||||
switch (len) {
|
||||
case 3: x ^= (str[2] << 16);
|
||||
case 2: x ^= (str[1] << 8);
|
||||
case 1: x ^= str[0]; x *= n;
|
||||
default: break;
|
||||
}
|
||||
x ^= (x >> 13);
|
||||
x *= n;
|
||||
x ^= (x >> 15);
|
||||
return x;
|
||||
}
|
||||
317
delay_simple/plugin/source/HvUtils.h
Normal file
317
delay_simple/plugin/source/HvUtils.h
Normal file
@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Copyright (c) 2014-2018 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 || _MSC_VER
|
||||
#define HV_WIN 1
|
||||
#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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// type definitions
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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 <immintrin.h>
|
||||
#elif HV_SIMD_NEON
|
||||
#include <arm_neon.h>
|
||||
#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 <string.h>
|
||||
#define hv_strlen(a) strlen(a)
|
||||
#define hv_strcmp(a, b) strcmp(a, b)
|
||||
#define hv_snprintf(a, b, c, ...) snprintf(a, b, c, __VA_ARGS__)
|
||||
#if HV_WIN
|
||||
#define hv_strncpy(_dst, _src, _len) strncpy_s(_dst, _len, _src, _TRUNCATE)
|
||||
#else
|
||||
#define hv_strncpy(_dst, _src, _len) strncpy(_dst, _src, _len)
|
||||
#endif
|
||||
|
||||
// Memory management
|
||||
#define hv_memcpy(a, b, c) memcpy(a, b, c)
|
||||
#define hv_memclear(a, b) memset(a, 0, b)
|
||||
#if HV_WIN
|
||||
#include <malloc.h>
|
||||
#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_realloc(a, b) realloc(a, b)
|
||||
#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 <mm_malloc.h>
|
||||
#define hv_malloc(_n) _mm_malloc(_n, 32)
|
||||
#define hv_free(x) _mm_free(x)
|
||||
#elif HV_SIMD_SSE
|
||||
#include <mm_malloc.h>
|
||||
#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
|
||||
#else
|
||||
#include <alloca.h>
|
||||
#define hv_alloca(_n) alloca(_n)
|
||||
#define hv_realloc(a, b) realloc(a, b)
|
||||
#if HV_SIMD_AVX
|
||||
#define hv_malloc(_n) aligned_alloc(32, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#elif HV_SIMD_SSE
|
||||
#define hv_malloc(_n) aligned_alloc(16, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#elif HV_SIMD_NEON
|
||||
#if HV_ANDROID
|
||||
#define hv_malloc(_n) memalign(16, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#else
|
||||
#define hv_malloc(_n) aligned_alloc(16, _n)
|
||||
#define hv_free(x) free(x)
|
||||
#endif
|
||||
#else // HV_SIMD_NONE
|
||||
#define hv_malloc(_n) malloc(_n)
|
||||
#define hv_free(_n) free(_n)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Assert
|
||||
#include <assert.h>
|
||||
#define hv_assert(e) assert(e)
|
||||
|
||||
// Export and Inline
|
||||
#if HV_WIN
|
||||
#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
|
||||
#include <math.h>
|
||||
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)
|
||||
#define hv_sin_f(a) sinf(a)
|
||||
#define hv_sinh_f(a) sinhf(a)
|
||||
#define hv_cos_f(a) cosf(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_exp_f(a) expf(a)
|
||||
#define hv_abs_f(a) fabsf(a)
|
||||
#define hv_sqrt_f(a) sqrtf(a)
|
||||
#define hv_log_f(a) logf(a)
|
||||
#define hv_ceil_f(a) ceilf(a)
|
||||
#define hv_floor_f(a) floorf(a)
|
||||
#define hv_round_f(a) roundf(a)
|
||||
#define hv_pow_f(a, b) powf(a, b)
|
||||
#if HV_EMSCRIPTEN
|
||||
#define hv_fma_f(a, b, c) ((a*b)+c) // emscripten does not support fmaf (yet?)
|
||||
#else
|
||||
#define hv_fma_f(a, b, c) fmaf(a, b, c)
|
||||
#endif
|
||||
#if HV_WIN
|
||||
// finds ceil(log2(x))
|
||||
#include <intrin.h>
|
||||
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 <windows.h>
|
||||
#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 __cplusplus
|
||||
#include <atomic>
|
||||
#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(<stdatomic.h>)
|
||||
#include <stdatomic.h>
|
||||
#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_
|
||||
24
delay_simple/plugin/source/Makefile
Normal file
24
delay_simple/plugin/source/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
NAME = delay_simple
|
||||
|
||||
FILES_DSP = $(wildcard *.cpp)
|
||||
FILES_DSP += $(wildcard *.c)
|
||||
|
||||
include ../../../dpf/Makefile.plugins.mk
|
||||
|
||||
LINK_FLAGS += -lpthread
|
||||
CFLAGS += -Wno-unused-parameter
|
||||
CXXFLAGS += -Wno-unused-parameter
|
||||
|
||||
|
||||
|
||||
TARGETS += lv2_dsp
|
||||
|
||||
TARGETS += vst2
|
||||
|
||||
TARGETS += vst3
|
||||
|
||||
TARGETS += jack
|
||||
|
||||
|
||||
|
||||
all: $(TARGETS)
|
||||
1
dpf
Submodule
1
dpf
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ac803f5991e1adac6581658a346250d4246e59b6
|
||||
17
dpf_delay_simple.json
Normal file
17
dpf_delay_simple.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"dpf": {
|
||||
"dpf_path": "../dpf",
|
||||
"project": true,
|
||||
"description": "Simple Delay",
|
||||
"maker": "Wasted Audio",
|
||||
"license": "ISC",
|
||||
"midi_input": 0,
|
||||
"midi_output": 0,
|
||||
"plugin_formats": [
|
||||
"lv2_dsp",
|
||||
"vst2",
|
||||
"vst3",
|
||||
"jack"
|
||||
]
|
||||
}
|
||||
}
|
||||
39
dpf_delay_simple.pd
Normal file
39
dpf_delay_simple.pd
Normal file
@ -0,0 +1,39 @@
|
||||
#N canvas 295 300 807 373 12;
|
||||
#X obj 88 247 dac~;
|
||||
#X obj 89 39 adc~;
|
||||
#X obj 373 160 s dtime1;
|
||||
#X obj 376 133 hsl 128 15 0 5000 0 0 empty empty empty -2 -8 0 10 -262144
|
||||
-1 -1 0 1;
|
||||
#X obj 449 192 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144
|
||||
-1 -1 0 1;
|
||||
#X obj 523 250 hsl 128 15 0 0.95 0 0 empty empty empty -2 -8 0 10 -262144
|
||||
-1 -1 0 1;
|
||||
#X obj 446 219 s dvol1;
|
||||
#X obj 520 277 s dfeed1;
|
||||
#X obj 100 140 *~;
|
||||
#X obj 156 112 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144
|
||||
-1 -1 0 1;
|
||||
#X obj 376 64 s dryvol;
|
||||
#X obj 379 37 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144
|
||||
-1 -1 0 1;
|
||||
#X obj 99 169 examples/delay_simple 1;
|
||||
#X obj 153 84 r Gain @hv_param 0 1 0.75;
|
||||
#X obj 376 8 r Dry_Volume @hv_param 0 1 0.75;
|
||||
#X obj 373 104 r Delay_Time @hv_param 0 5000 500;
|
||||
#X obj 446 163 r Wet_Volume @hv_param 0 1 0.75;
|
||||
#X obj 520 221 r Delay_Feedback @hv_param 0 1 0.25;
|
||||
#X connect 1 0 8 0;
|
||||
#X connect 1 1 8 0;
|
||||
#X connect 3 0 2 0;
|
||||
#X connect 4 0 6 0;
|
||||
#X connect 5 0 7 0;
|
||||
#X connect 8 0 12 0;
|
||||
#X connect 9 0 8 1;
|
||||
#X connect 11 0 10 0;
|
||||
#X connect 12 0 0 0;
|
||||
#X connect 12 0 0 1;
|
||||
#X connect 13 0 9 0;
|
||||
#X connect 14 0 11 0;
|
||||
#X connect 15 0 3 0;
|
||||
#X connect 16 0 4 0;
|
||||
#X connect 17 0 5 0;
|
||||
Loading…
Reference in New Issue
Block a user