/** * 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 fixed formatted message of two floats 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_sendMessageToReceiverFF(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, double data1, double data2); /** * Sends a fixed formatted message of three floats 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_sendMessageToReceiverFFF(HeavyContextInterface *c, hv_uint32_t receiverHash, double delayMs, double data1, double data2, double data3); /** * 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_