From a0a5530641a5f968cc0f381c49f6e79c3a4cda8f Mon Sep 17 00:00:00 2001 From: NextPrior Date: Tue, 10 Jun 2014 22:04:39 -0700 Subject: [PATCH 01/42] Initial reverb implementation Conflicts: interface/CMakeLists.txt interface/src/Audio.cpp interface/src/Audio.h libraries/script-engine/src/ScriptEngine.cpp --- cmake/modules/FindGverb.cmake | 38 ++ examples/audioReverbOff.js | 12 + examples/audioReverbOn.js | 32 ++ interface/CMakeLists.txt | 9 + interface/external/gverb/CMakeLists.txt | 2 + .../external/gverb/include/ladspa-util.h | 234 +++++++++++ interface/external/gverb/include/lv2.h | 392 ++++++++++++++++++ interface/external/gverb/src/gverb.c | 207 +++++++++ interface/external/gverb/src/gverb.h | 234 +++++++++++ interface/external/gverb/src/gverbdsp.c | 130 ++++++ interface/external/gverb/src/gverbdsp.h | 85 ++++ interface/src/Audio.cpp | 173 +++++++- interface/src/Audio.h | 17 + .../AudioDeviceScriptingInterface.cpp | 8 + .../scripting/AudioDeviceScriptingInterface.h | 2 + libraries/audio/src/AudioEffectOptions.cpp | 12 + libraries/audio/src/AudioEffectOptions.h | 99 +++++ libraries/script-engine/src/ScriptEngine.cpp | 4 + 18 files changed, 1689 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/FindGverb.cmake create mode 100644 examples/audioReverbOff.js create mode 100644 examples/audioReverbOn.js create mode 100644 interface/external/gverb/CMakeLists.txt create mode 100644 interface/external/gverb/include/ladspa-util.h create mode 100644 interface/external/gverb/include/lv2.h create mode 100644 interface/external/gverb/src/gverb.c create mode 100644 interface/external/gverb/src/gverb.h create mode 100644 interface/external/gverb/src/gverbdsp.c create mode 100644 interface/external/gverb/src/gverbdsp.h create mode 100644 libraries/audio/src/AudioEffectOptions.cpp create mode 100644 libraries/audio/src/AudioEffectOptions.h diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake new file mode 100644 index 0000000000..904813c007 --- /dev/null +++ b/cmake/modules/FindGverb.cmake @@ -0,0 +1,38 @@ +# FindGVerb.cmake +# +# Try to find the Gverb library. +# +# You must provide a GVERB_ROOT_DIR which contains src and include directories +# +# Once done this will define +# +# GVERB_FOUND - system found Gverb +# GVERB_INCLUDE_DIRS - the Gverb include directory +# +# Copyright 2014 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +if (GVERB_INCLUDE_DIRS) + # in cache already + set(GVERB_FOUND TRUE) +else () + find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/src) + + if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) + endif (GVERB_INCLUDE_DIRS) + + if (GVERB_FOUND) + if (NOT GVERB_FIND_QUIETLY) + message(STATUS "Found Gverb... ${GVERB_LIBRARIES}") + endif (NOT GVERB_FIND_QUIETLY) + else () + if (GVERB_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Gverb") + endif (GVERB_FIND_REQUIRED) + endif () + +endif () diff --git a/examples/audioReverbOff.js b/examples/audioReverbOff.js new file mode 100644 index 0000000000..1076a825a7 --- /dev/null +++ b/examples/audioReverbOff.js @@ -0,0 +1,12 @@ +// +// audioReverbOff.js +// examples +// +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// +AudioDevice.setReverb(false); +print("Reberb is now off."); diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js new file mode 100644 index 0000000000..6d43c31943 --- /dev/null +++ b/examples/audioReverbOn.js @@ -0,0 +1,32 @@ +// +// audioReverbOn.js +// examples +// +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings +var audioOptions = new AudioEffectOptions(); + +// Square Meters +audioOptions.maxRoomSize = 50; +audioOptions.roomSize = 50; + +// Seconds +audioOptions.reverbTime = 4; + +// Between 0 - 1 +audioOptions.damping = 0.50; +audioOptions.inputBandwidth = 0.75; + +// dB +audioOptions.earlyLevel = -22; +audioOptions.tailLevel = -28; +audioOptions.dryLevel = 0; +audioOptions.wetLevel = 6; + +AudioDevice.setReverbOptions(audioOptions); +AudioDevice.setReverb(true); +print("Reverb is now on with the updated options."); diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 16ca977bae..3caa7c470e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -14,6 +14,9 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) +# As Gverb is currently the only reverb library, it's required. +find_package(Gverb REQUIRED) + if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -167,6 +170,12 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () +if (GVERB_FOUND) + add_subdirectory(${GVERB_ROOT_DIR}) + include_directories(${GVERB_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} gverb) +endif (GVERB_FOUND) + # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") include_directories("${OPENSSL_INCLUDE_DIR}") diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt new file mode 100644 index 0000000000..140b45b727 --- /dev/null +++ b/interface/external/gverb/CMakeLists.txt @@ -0,0 +1,2 @@ +cmake_minimum_required(VERSION 2.8) +add_library(gverb include/ladspa-util.h include/lv2.h src/gverb.h src/gverb.c src/gverbdsp.h src/gverbdsp.c) diff --git a/interface/external/gverb/include/ladspa-util.h b/interface/external/gverb/include/ladspa-util.h new file mode 100644 index 0000000000..149d0aaacd --- /dev/null +++ b/interface/external/gverb/include/ladspa-util.h @@ -0,0 +1,234 @@ +/* Some misc util functions for audio DSP work, written by Steve Harris, + * December 2000 + * + * steve@plugin.org.uk + */ + +#ifndef LADSPA_UTIL_H +#define LADSPA_UTIL_H + +#include +#include +#include + +#define buffer_write(a, b) a=(b) + +// 16.16 fixpoint +typedef union { + int32_t all; + struct { +#ifdef WORDS_BIGENDIAN + int16_t in; + uint16_t fr; +#else + uint16_t fr; + int16_t in; +#endif + } part; +} fixp16; + +// 32.32 fixpoint +typedef union { + int64_t all; + struct { +#ifdef WORDS_BIGENDIAN + int32_t in; + uint32_t fr; +#else + uint32_t fr; + int32_t in; +#endif + } part; +} fixp32; + +/* 32 bit "pointer cast" union */ +typedef union { + float f; + int32_t i; +} ls_pcast32; + +// Sometimes it doesn't get defined, even though it eists and C99 is declared +long int lrintf (float x); + +// 1.0 / ln(2) +#define LN2R 1.442695041f + +/* detet floating point denormal numbers by comparing them to the smallest + * normal, crap, but reliable */ +#define DN_CHECK(x, l) if (fabs(x) < 1e-38) printf("DN: "l"\n") + +// Denormalise floats, only actually needed for PIII and recent PowerPC +//#define FLUSH_TO_ZERO(fv) (((*(unsigned int*)&(fv))&0x7f800000)==0)?0.0f:(fv) + +static inline float flush_to_zero(float f) +{ + ls_pcast32 v; + + v.f = f; + + // original: return (v.i & 0x7f800000) == 0 ? 0.0f : f; + // version from Tim Blechmann + return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f; +} + +static inline void round_to_zero(volatile float *f) +{ + *f += 1e-18; + *f -= 1e-18; +} + +/* A set of branchless clipping operations from Laurent de Soras */ + +static inline float f_max(float x, float a) +{ + x -= a; + x += fabs(x); + x *= 0.5; + x += a; + + return x; +} + +static inline float f_min(float x, float b) +{ + x = b - x; + x += fabs(x); + x *= 0.5; + x = b - x; + + return x; +} + +static inline float f_clamp(float x, float a, float b) +{ + const float x1 = fabs(x - a); + const float x2 = fabs(x - b); + + x = x1 + a + b; + x -= x2; + x *= 0.5; + + return x; +} + +// Limit a value to be l<=v<=u +#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) + +// Truncate-to-zero modulo (ANSI C doesn't specify) will only work +// if -m < v < 2m +#define MOD(v,m) (v<0?v+m:(v>=m?v-m:v)) + +// Truncate-to-zero modulo (ANSI C doesn't specify) will only work +// if v > -m and v < m +#define NEG_MOD(v,m) ((v)<0?((v)+(m)):(v)) + +// Convert a value in dB's to a coefficent +#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) +#define CO_DB(v) (20.0f * log10f(v)) + +// Linearly interpolate [ = a * (1 - f) + b * f] +#define LIN_INTERP(f,a,b) ((a) + (f) * ((b) - (a))) + +// Cubic interpolation function +static inline float cube_interp(const float fr, const float inm1, const float + in, const float inp1, const float inp2) +{ + return in + 0.5f * fr * (inp1 - inm1 + + fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 + + fr * (3.0f * (in - inp1) - inm1 + inp2))); +} + +/* fast sin^2 aproxiamtion, adapted from jan AT rpgfan's posting to the + * music-dsp list */ +static inline float f_sin_sq(float angle) +{ + const float asqr = angle * angle; + float result = -2.39e-08f; + + result *= asqr; + result += 2.7526e-06f; + result *= asqr; + result -= 1.98409e-04f; + result *= asqr; + result += 8.3333315e-03f; + result *= asqr; + result -= 1.666666664e-01f; + result *= asqr; + result += 1.0f; + result *= angle; + + return result * result; +} + +#ifdef HAVE_LRINTF + +#define f_round(f) lrintf(f) + +#else + +// Round float to int using IEEE int* hack +static inline int f_round(float f) +{ + ls_pcast32 p; + + p.f = f; + p.f += (3<<22); + + return p.i - 0x4b400000; +} + +#endif + +// Truncate float to int +static inline int f_trunc(float f) +{ + return f_round(floorf(f)); +} + +/* Andrew Simper's pow(2, x) aproximation from the music-dsp list */ + +#if 0 + +/* original */ +static inline float f_pow2(float x) +{ + long *px = (long*)(&x); // store address of float as long pointer + const float tx = (x-0.5f) + (3<<22); // temporary value for truncation + const long lx = *((long*)&tx) - 0x4b400000; // integer power of 2 + const float dx = x-(float)(lx); // float remainder of power of 2 + + x = 1.0f + dx*(0.6960656421638072f + // cubic apporoximation of 2^x + dx*(0.224494337302845f + // for x in the range [0, 1] + dx*(0.07944023841053369f))); + *px += (lx<<23); // add integer power of 2 to exponent + + return x; +} + +#else + +/* union version */ +static inline float f_pow2(float x) +{ + ls_pcast32 *px, tx, lx; + float dx; + + px = (ls_pcast32 *)&x; // store address of float as long pointer + tx.f = (x-0.5f) + (3<<22); // temporary value for truncation + lx.i = tx.i - 0x4b400000; // integer power of 2 + dx = x - (float)lx.i; // float remainder of power of 2 + + x = 1.0f + dx * (0.6960656421638072f + // cubic apporoximation of 2^x + dx * (0.224494337302845f + // for x in the range [0, 1] + dx * (0.07944023841053369f))); + (*px).i += (lx.i << 23); // add integer power of 2 to exponent + + return (*px).f; +} + +#endif + +/* Fast exponentiation function, y = e^x */ +#define f_exp(x) f_pow2(x * LN2R) + +#endif diff --git a/interface/external/gverb/include/lv2.h b/interface/external/gverb/include/lv2.h new file mode 100644 index 0000000000..d5257824c6 --- /dev/null +++ b/interface/external/gverb/include/lv2.h @@ -0,0 +1,392 @@ +/* LV2 - LADSPA (Linux Audio Developer's Simple Plugin API) Version 2 + * Revision 1 + * + * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + * Stefan Westerfeld. + * Copyright (C) 2006-2008 Steve Harris, Dave Robillard. + * + * This header is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, + * or (at your option) any later version. + * + * This header is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + * USA. + */ + +#ifndef LV2_H_INCLUDED +#define LV2_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ************************************************************************* */ + + +/** @file lv2.h + * + * Revision: 1 + * + * == Overview == + * + * There are a large number of open source and free software synthesis + * packages in use or development at this time. This API ('LV2') + * attempts to give programmers the ability to write simple 'plugin' + * audio processors in C/C++ and link them dynamically ('plug') into + * a range of these packages ('hosts'). It should be possible for any + * host and any plugin to communicate completely through this interface. + * + * This API is deliberately as short and simple as possible. + * The information required to use a plugin is in a companion data + * (RDF) file. The shared library portion of the API (defined in this + * header) does not contain enough information to make use of the plugin + * possible - the data file is mandatory. + * + * Plugins are expected to distinguish between control rate and audio + * rate data (or other types of data defined by extensions). Plugins have + * 'ports' that are inputs or outputs and each plugin is 'run' for a 'block' + * corresponding to a short time interval measured in samples. Audio rate + * data is communicated using arrays with one element per sample processed, + * allowing a block of audio to be processed by the plugin in a single + * pass. Control rate data is communicated using single values. Control + * rate data has a single value at the start of a call to the 'run()' + * function, and may be considered to remain this value for its duration. + * Thus the 'control rate' is determined by the block size, controlled by + * the host. The plugin may assume that all its input and output ports have + * been connected to the relevant data location (see the 'connect_port()' + * function below) before it is asked to run, unless the port has been set + * 'connection optional' in the plugin's data file. + * + * Plugins will reside in shared object files suitable for dynamic linking + * by dlopen() and family. The file will provide a number of 'plugin + * types' that can be used to instantiate actual plugins (sometimes known + * as 'plugin instances') that can be connected together to perform tasks. + * The host can access these plugin types using the lv2_descriptor() + * function. + * + * This API contains very limited error-handling. + * + * == Threading rules == + * + * Certain hosts may need to call the functions provided by a plugin from + * multiple threads. For this to be safe, the plugin must be written so that + * those functions can be executed simultaneously without problems. + * To facilitate this, the functions provided by a plugin are divided into + * classes: + * + * - Discovery class: lv2_descriptor(), extension_data() + * - Instantiation class: instantiate(), cleanup(), activate(), deactivate() + * - Audio class: run(), connect_port() + * + * Extensions to this specification which add new functions MUST declare in + * which of these classes the functions belong, or define new classes for them. + * The rules that hosts must follow are these: + * + * - When a function from the Discovery class is running, no other + * functions in the same shared object file may run. + * - When a function from the Instantiation class is running for a plugin + * instance, no other functions for that instance may run. + * - When a function is running for a plugin instance, no other + * function in the same class may run for that instance. + * + * Any simultaneous calls that are not explicitly forbidden by these rules + * are allowed. For example, a host may call run() for two different plugin + * instances simultaneously. + */ + + +/* ************************************************************************* */ + + +/** Plugin Handle. + * + * This plugin handle indicates a particular instance of the plugin + * concerned. It is valid to compare this to NULL (0 for C++) but + * otherwise the host MUST NOT attempt to interpret it. The plugin + * may use it to reference internal instance data. */ +typedef void * LV2_Handle; + + +/* ************************************************************************* */ + + +/** Feature data. + * + * These are passed to a plugin's instantiate method to represent a special + * feature the host has which the plugin may depend on. This is to allow + * extensions to the LV2 specification without causing any breakage. + * Extensions may specify what data needs to be passed here. The base + * LV2 specification does not define any features; hosts are not required + * to use this facility. */ +typedef struct _LV2_Feature { + /** A globally unique, case-sensitive identifier for this feature. + * + * This MUST be defined in the specification of any LV2 extension which + * defines a host feature. */ + const char * URI; + + /** Pointer to arbitrary data. + * + * This is to allow hosts to pass data to a plugin (simple values, data + * structures, function pointers, etc) as part of a 'feature'. The LV2 + * specification makes no restrictions on the contents of this data. + * The data here MUST be cleary defined by the LV2 extension which defines + * this feature. + * If no data is required, this may be set to NULL. */ + void * data; +} LV2_Feature; + + +/* ************************************************************************* */ + + +/** Descriptor for a Type of Plugin. + * + * This structure is used to describe a plugin type. It provides a number + * of functions to instantiate it, link it to buffers and run it. */ +typedef struct _LV2_Descriptor { + + /** A globally unique, case-sensitive identifier for this plugin type. + * + * All plugins with the same URI MUST be compatible in terms of 'port + * signature', meaning they have the same number of ports, same port + * shortnames, and roughly the same functionality. URIs should + * probably contain a version number (or similar) for this reason. + * + * Rationale: When serializing session/patch/etc files, hosts MUST + * refer to a loaded plugin by the plugin URI only. In the future + * loading a plugin with this URI MUST yield a plugin with the + * same ports (etc) which is 100% compatible. */ + const char * URI; + + /** Function pointer that instantiates a plugin. + * + * A handle is returned indicating the new plugin instance. The + * instantiation function accepts a sample rate as a parameter as well + * as the plugin descriptor from which this instantiate function was + * found. This function must return NULL if instantiation fails. + * + * bundle_path is a string of the path to the LV2 bundle which contains + * this plugin binary. It MUST include the trailing directory separator + * (e.g. '/') so that BundlePath + filename gives the path to a file + * in the bundle. + * + * features is a NULL terminated array of LV2_Feature structs which + * represent the features the host supports. Plugins may refuse to + * instantiate if required features are not found here (however hosts + * SHOULD NOT use this as a discovery mechanism, instead reading the + * data file before attempting to instantiate the plugin). This array + * must always exist; if a host has no features, it MUST pass a single + * element array containing NULL (to simplify plugins). + * + * Note that instance initialisation should generally occur in + * activate() rather than here. If a host calls instantiate, it MUST + * call cleanup() at some point in the future. */ + LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor, + double sample_rate, + const char * bundle_path, + const LV2_Feature *const * features); + + /** Function pointer that connects a port on a plugin instance to a memory + * location where the block of data for the port will be read/written. + * + * The data location is expected to be of the type defined in the + * plugin's data file (e.g. an array of float for an lv2:AudioPort). + * Memory issues are managed by the host. The plugin must read/write + * the data at these locations every time run() is called, data + * present at the time of this connection call MUST NOT be + * considered meaningful. + * + * The host MUST NOT try to connect a data buffer to a port index + * that is not defined in the RDF data for the plugin. If it does, + * the plugin's behaviour is undefined. + * + * connect_port() may be called more than once for a plugin instance + * to allow the host to change the buffers that the plugin is reading + * or writing. These calls may be made before or after activate() + * or deactivate() calls. Note that there may be realtime constraints + * on connect_port (see lv2:hardRTCapable in lv2.ttl). + * + * connect_port() MUST be called at least once for each port before + * run() is called. The plugin must pay careful attention to the block + * size passed to the run function as the block allocated may only just + * be large enough to contain the block of data (typically samples), and + * is not guaranteed to be constant. + * + * Plugin writers should be aware that the host may elect to use the + * same buffer for more than one port and even use the same buffer for + * both input and output (see lv2:inPlaceBroken in lv2.ttl). + * However, overlapped buffers or use of a single buffer for both + * audio and control data may result in unexpected behaviour. + * + * If the plugin has the feature lv2:hardRTCapable then there are + * various things that the plugin MUST NOT do within the connect_port() + * function (see lv2.ttl). */ + void (*connect_port)(LV2_Handle instance, + uint32_t port, + void * data_location); + + /** Function pointer that initialises a plugin instance and activates + * it for use. + * + * This is separated from instantiate() to aid real-time support and so + * that hosts can reinitialise a plugin instance by calling deactivate() + * and then activate(). In this case the plugin instance must reset all + * state information dependent on the history of the plugin instance + * except for any data locations provided by connect_port(). If there + * is nothing for activate() to do then the plugin writer may provide + * a NULL rather than an empty function. + * + * When present, hosts MUST call this function once before run() + * is called for the first time. This call SHOULD be made as close + * to the run() call as possible and indicates to real-time plugins + * that they are now live, however plugins MUST NOT rely on a prompt + * call to run() after activate(). activate() may not be called again + * unless deactivate() is called first (after which activate() may be + * called again, followed by deactivate, etc. etc.). If a host calls + * activate, it MUST call deactivate at some point in the future. + * + * Note that connect_port() may be called before or after a call to + * activate(). */ + void (*activate)(LV2_Handle instance); + + /** Function pointer that runs a plugin instance for a block. + * + * Two parameters are required: the first is a handle to the particular + * instance to be run and the second indicates the block size (in + * samples) for which the plugin instance may run. + * + * Note that if an activate() function exists then it must be called + * before run(). If deactivate() is called for a plugin instance then + * the plugin instance may not be reused until activate() has been + * called again. + * + * If the plugin has the feature lv2:hardRTCapable then there are + * various things that the plugin MUST NOT do within the run() + * function (see lv2.ttl). */ + void (*run)(LV2_Handle instance, + uint32_t sample_count); + + /** This is the counterpart to activate() (see above). If there is + * nothing for deactivate() to do then the plugin writer may provide + * a NULL rather than an empty function. + * + * Hosts must deactivate all activated units after they have been run() + * for the last time. This call SHOULD be made as close to the last + * run() call as possible and indicates to real-time plugins that + * they are no longer live, however plugins MUST NOT rely on prompt + * deactivation. Note that connect_port() may be called before or + * after a call to deactivate(). + * + * Note that deactivation is not similar to pausing as the plugin + * instance will be reinitialised when activate() is called to reuse it. + * Hosts MUST NOT call deactivate() unless activate() was previously + * called. */ + void (*deactivate)(LV2_Handle instance); + + /** This is the counterpart to instantiate() (see above). Once an instance + * of a plugin has been finished with it can be deleted using this + * function. The instance handle passed ceases to be valid after + * this call. + * + * If activate() was called for a plugin instance then a corresponding + * call to deactivate() MUST be made before cleanup() is called. + * Hosts MUST NOT call cleanup() unless instantiate() was previously + * called. */ + void (*cleanup)(LV2_Handle instance); + + /** Function pointer that can be used to return additional instance data for + * a plugin defined by some extenion (e.g. a struct containing additional + * function pointers). + * + * The actual type and meaning of the returned object MUST be specified + * precisely by the extension if it defines any extra data. If a particular + * extension does not define extra instance data, this function MUST return + * NULL for that extension's URI. If a plugin does not support any + * extensions that define extra instance data, this function pointer may be + * set to NULL rather than providing an empty function. + * + * The only parameter is the URI of the extension. The plugin MUST return + * NULL if it does not support the extension, but hosts SHOULD NOT use this + * as a discovery method (e.g. hosts should only call this function for + * extensions known to be supported by the plugin from the data file). + * + * The host is never responsible for freeing the returned value. + * + * NOTE: This function should return a struct (likely containing function + * pointers) and NOT a direct function pointer. Standard C and C++ do not + * allow type casts from void* to a function pointer type. To provide + * additional functions a struct should be returned containing the extra + * function pointers (which is valid standard code, and a much better idea + * for extensibility anyway). */ + const void* (*extension_data)(const char * uri); + +} LV2_Descriptor; + + +/* ****************************************************************** */ + + +/** Accessing Plugin Types. + * + * The exact mechanism by which plugins are loaded is host-dependent, + * however all most hosts will need to know is the URI of the plugin they + * wish to load. The environment variable LV2_PATH, if present, should + * contain a colon-separated path indicating directories (containing + * plugin bundle subdirectories) that should be searched (in order) + * for plugins. It is expected that hosts will use a library to provide + * this functionality. + * + * A plugin programmer must include a function called "lv2_descriptor" + * with the following function prototype within the shared object + * file. This function will have C-style linkage (if you are using + * C++ this is taken care of by the 'extern "C"' clause at the top of + * the file). + * + * A host will find the plugin shared object file by one means or another, + * find the lv2_descriptor() function, call it, and proceed from there. + * + * Plugin types are accessed by index (not ID) using values from 0 + * upwards. Out of range indexes must result in this function returning + * NULL, so the plugin count can be determined by checking for the least + * index that results in NULL being returned. Index has no meaning, + * hosts MUST NOT depend on it remaining constant (ie when serialising) + * in any way. */ +const LV2_Descriptor * lv2_descriptor(uint32_t index); + + +/** Datatype corresponding to the lv2_descriptor() function. */ +typedef const LV2_Descriptor * +(*LV2_Descriptor_Function)(uint32_t index); + + +/* ******************************************************************** */ + + +/* Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded + * by the host as a symbol from the dynamic library. + */ +#ifdef WIN32 +#define LV2_SYMBOL_EXPORT __declspec(dllexport) +#else +#define LV2_SYMBOL_EXPORT +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* LV2_H_INCLUDED */ + diff --git a/interface/external/gverb/src/gverb.c b/interface/external/gverb/src/gverb.c new file mode 100644 index 0000000000..e3980232bc --- /dev/null +++ b/interface/external/gverb/src/gverb.c @@ -0,0 +1,207 @@ +/* + + Copyright (C) 1999 Juhana Sadeharju + kouhia at nic.funet.fi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + + +#include +#include +#include +#include +#include "gverbdsp.h" +#include "gverb.h" +#include "../include/ladspa-util.h" + +ty_gverb *gverb_new(int srate, float maxroomsize, float roomsize, + float revtime, + float damping, float spread, + float inputbandwidth, float earlylevel, + float taillevel) +{ + ty_gverb *p; + float ga,gb,gt; + int i,n; + float r; + float diffscale; + int a,b,c,cc,d,dd,e; + float spread1,spread2; + + p = (ty_gverb *)malloc(sizeof(ty_gverb)); + p->rate = srate; + p->fdndamping = damping; + p->maxroomsize = maxroomsize; + p->roomsize = roomsize; + p->revtime = revtime; + p->earlylevel = earlylevel; + p->taillevel = taillevel; + + p->maxdelay = p->rate*p->maxroomsize/340.0; + p->largestdelay = p->rate*p->roomsize/340.0; + + + /* Input damper */ + + p->inputbandwidth = inputbandwidth; + p->inputdamper = damper_make(1.0 - p->inputbandwidth); + + + /* FDN section */ + + + p->fdndels = (ty_fixeddelay **)calloc(FDNORDER, sizeof(ty_fixeddelay *)); + for(i = 0; i < FDNORDER; i++) { + p->fdndels[i] = fixeddelay_make((int)p->maxdelay+1000); + } + p->fdngains = (float *)calloc(FDNORDER, sizeof(float)); + p->fdnlens = (int *)calloc(FDNORDER, sizeof(int)); + + p->fdndamps = (ty_damper **)calloc(FDNORDER, sizeof(ty_damper *)); + for(i = 0; i < FDNORDER; i++) { + p->fdndamps[i] = damper_make(p->fdndamping); + } + + ga = 60.0; + gt = p->revtime; + ga = powf(10.0f,-ga/20.0f); + n = p->rate*gt; + p->alpha = pow((double)ga, 1.0/(double)n); + + gb = 0.0; + for(i = 0; i < FDNORDER; i++) { + if (i == 0) gb = 1.000000*p->largestdelay; + if (i == 1) gb = 0.816490*p->largestdelay; + if (i == 2) gb = 0.707100*p->largestdelay; + if (i == 3) gb = 0.632450*p->largestdelay; + +#if 0 + p->fdnlens[i] = nearest_prime((int)gb, 0.5); +#else + p->fdnlens[i] = f_round(gb); +#endif + p->fdngains[i] = -powf((float)p->alpha,p->fdnlens[i]); + } + + p->d = (float *)calloc(FDNORDER, sizeof(float)); + p->u = (float *)calloc(FDNORDER, sizeof(float)); + p->f = (float *)calloc(FDNORDER, sizeof(float)); + + /* Diffuser section */ + + diffscale = (float)p->fdnlens[3]/(210+159+562+410); + spread1 = spread; + spread2 = 3.0*spread; + + b = 210; + r = 0.125541; + a = spread1*r; + c = 210+159+a; + cc = c-b; + r = 0.854046; + a = spread2*r; + d = 210+159+562+a; + dd = d-c; + e = 1341-d; + + p->ldifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); + p->ldifs[0] = diffuser_make((int)(diffscale*b),0.75); + p->ldifs[1] = diffuser_make((int)(diffscale*cc),0.75); + p->ldifs[2] = diffuser_make((int)(diffscale*dd),0.625); + p->ldifs[3] = diffuser_make((int)(diffscale*e),0.625); + + b = 210; + r = -0.568366; + a = spread1*r; + c = 210+159+a; + cc = c-b; + r = -0.126815; + a = spread2*r; + d = 210+159+562+a; + dd = d-c; + e = 1341-d; + + p->rdifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); + p->rdifs[0] = diffuser_make((int)(diffscale*b),0.75); + p->rdifs[1] = diffuser_make((int)(diffscale*cc),0.75); + p->rdifs[2] = diffuser_make((int)(diffscale*dd),0.625); + p->rdifs[3] = diffuser_make((int)(diffscale*e),0.625); + + + + /* Tapped delay section */ + + p->tapdelay = fixeddelay_make(44000); + p->taps = (int *)calloc(FDNORDER, sizeof(int)); + p->tapgains = (float *)calloc(FDNORDER, sizeof(float)); + + p->taps[0] = 5+0.410*p->largestdelay; + p->taps[1] = 5+0.300*p->largestdelay; + p->taps[2] = 5+0.155*p->largestdelay; + p->taps[3] = 5+0.000*p->largestdelay; + + for(i = 0; i < FDNORDER; i++) { + p->tapgains[i] = pow(p->alpha,(double)p->taps[i]); + } + + return(p); +} + +void gverb_free(ty_gverb *p) +{ + int i; + + damper_free(p->inputdamper); + for(i = 0; i < FDNORDER; i++) { + fixeddelay_free(p->fdndels[i]); + damper_free(p->fdndamps[i]); + diffuser_free(p->ldifs[i]); + diffuser_free(p->rdifs[i]); + } + free(p->fdndels); + free(p->fdngains); + free(p->fdnlens); + free(p->fdndamps); + free(p->d); + free(p->u); + free(p->f); + free(p->ldifs); + free(p->rdifs); + free(p->taps); + free(p->tapgains); + fixeddelay_free(p->tapdelay); + free(p); +} + +void gverb_flush(ty_gverb *p) +{ + int i; + + damper_flush(p->inputdamper); + for(i = 0; i < FDNORDER; i++) { + fixeddelay_flush(p->fdndels[i]); + damper_flush(p->fdndamps[i]); + diffuser_flush(p->ldifs[i]); + diffuser_flush(p->rdifs[i]); + } + memset(p->d, 0, FDNORDER * sizeof(float)); + memset(p->u, 0, FDNORDER * sizeof(float)); + memset(p->f, 0, FDNORDER * sizeof(float)); + fixeddelay_flush(p->tapdelay); +} + +/* swh: other functions are now in the .h file for inlining */ diff --git a/interface/external/gverb/src/gverb.h b/interface/external/gverb/src/gverb.h new file mode 100644 index 0000000000..21bc1c3fef --- /dev/null +++ b/interface/external/gverb/src/gverb.h @@ -0,0 +1,234 @@ +/* + + Copyright (C) 1999 Juhana Sadeharju + kouhia at nic.funet.fi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef GVERB_H +#define GVERB_H + +#include +#include +#include +#include "gverbdsp.h" +#include "gverb.h" +#include "../include/ladspa-util.h" + +#define FDNORDER 4 + +typedef struct { + int rate; + float inputbandwidth; + float taillevel; + float earlylevel; + ty_damper *inputdamper; + float maxroomsize; + float roomsize; + float revtime; + float maxdelay; + float largestdelay; + ty_fixeddelay **fdndels; + float *fdngains; + int *fdnlens; + ty_damper **fdndamps; + float fdndamping; + ty_diffuser **ldifs; + ty_diffuser **rdifs; + ty_fixeddelay *tapdelay; + int *taps; + float *tapgains; + float *d; + float *u; + float *f; + double alpha; +} ty_gverb; + + +ty_gverb *gverb_new(int, float, float, float, float, float, float, float, float); +void gverb_free(ty_gverb *); +void gverb_flush(ty_gverb *); +static void gverb_do(ty_gverb *, float, float *, float *); +static void gverb_set_roomsize(ty_gverb *, float); +static void gverb_set_revtime(ty_gverb *, float); +static void gverb_set_damping(ty_gverb *, float); +static void gverb_set_inputbandwidth(ty_gverb *, float); +static void gverb_set_earlylevel(ty_gverb *, float); +static void gverb_set_taillevel(ty_gverb *, float); + +/* + * This FDN reverb can be made smoother by setting matrix elements at the + * diagonal and near of it to zero or nearly zero. By setting diagonals to zero + * means we remove the effect of the parallel comb structure from the + * reverberation. A comb generates uniform impulse stream to the reverberation + * impulse response, and thus it is not good. By setting near diagonal elements + * to zero means we remove delay sequences having consequtive delays of the + * similar lenths, when the delays are in sorted in length with respect to + * matrix element index. The matrix described here could be generated by + * differencing Rocchesso's circulant matrix at max diffuse value and at low + * diffuse value (approaching parallel combs). + * + * Example 1: + * Set a(k,k), for all k, equal to 0. + * + * Example 2: + * Set a(k,k), a(k,k-1) and a(k,k+1) equal to 0. + * + * Example 3: The transition to zero gains could be smooth as well. + * a(k,k-1) and a(k,k+1) could be 0.3, and a(k,k-2) and a(k,k+2) could + * be 0.5, say. + */ + +static inline void gverb_fdnmatrix(float *a, float *b) +{ + const float dl0 = a[0], dl1 = a[1], dl2 = a[2], dl3 = a[3]; + + b[0] = 0.5f*(+dl0 + dl1 - dl2 - dl3); + b[1] = 0.5f*(+dl0 - dl1 - dl2 + dl3); + b[2] = 0.5f*(-dl0 + dl1 - dl2 + dl3); + b[3] = 0.5f*(+dl0 + dl1 + dl2 + dl3); +} + +static inline void gverb_do(ty_gverb *p, float x, float *yl, float *yr) +{ + float z; + unsigned int i; + float lsum,rsum,sum,sign; + + if ((x != x) || fabsf(x) > 100000.0f) { + x = 0.0f; + } + + z = damper_do(p->inputdamper, x); + + z = diffuser_do(p->ldifs[0],z); + + for(i = 0; i < FDNORDER; i++) { + p->u[i] = p->tapgains[i]*fixeddelay_read(p->tapdelay,p->taps[i]); + } + fixeddelay_write(p->tapdelay,z); + + for(i = 0; i < FDNORDER; i++) { + p->d[i] = damper_do(p->fdndamps[i], + p->fdngains[i]*fixeddelay_read(p->fdndels[i], + p->fdnlens[i])); + } + + sum = 0.0f; + sign = 1.0f; + for(i = 0; i < FDNORDER; i++) { + sum += sign*(p->taillevel*p->d[i] + p->earlylevel*p->u[i]); + sign = -sign; + } + sum += x*p->earlylevel; + lsum = sum; + rsum = sum; + + gverb_fdnmatrix(p->d,p->f); + + for(i = 0; i < FDNORDER; i++) { + fixeddelay_write(p->fdndels[i],p->u[i]+p->f[i]); + } + + lsum = diffuser_do(p->ldifs[1],lsum); + lsum = diffuser_do(p->ldifs[2],lsum); + lsum = diffuser_do(p->ldifs[3],lsum); + rsum = diffuser_do(p->rdifs[1],rsum); + rsum = diffuser_do(p->rdifs[2],rsum); + rsum = diffuser_do(p->rdifs[3],rsum); + + *yl = lsum; + *yr = rsum; +} + +static inline void gverb_set_roomsize(ty_gverb *p, const float a) +{ + unsigned int i; + + if (a <= 1.0 || (a != a)) { + p->roomsize = 1.0; + } else { + p->roomsize = a; + } + p->largestdelay = p->rate * p->roomsize * 0.00294f; + + p->fdnlens[0] = f_round(1.000000f*p->largestdelay); + p->fdnlens[1] = f_round(0.816490f*p->largestdelay); + p->fdnlens[2] = f_round(0.707100f*p->largestdelay); + p->fdnlens[3] = f_round(0.632450f*p->largestdelay); + for(i = 0; i < FDNORDER; i++) { + p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); + } + + p->taps[0] = 5+f_round(0.410f*p->largestdelay); + p->taps[1] = 5+f_round(0.300f*p->largestdelay); + p->taps[2] = 5+f_round(0.155f*p->largestdelay); + p->taps[3] = 5+f_round(0.000f*p->largestdelay); + + for(i = 0; i < FDNORDER; i++) { + p->tapgains[i] = powf((float)p->alpha, p->taps[i]); + } + +} + +static inline void gverb_set_revtime(ty_gverb *p,float a) +{ + float ga,gt; + double n; + unsigned int i; + + p->revtime = a; + + ga = 60.0; + gt = p->revtime; + ga = powf(10.0f,-ga/20.0f); + n = p->rate*gt; + p->alpha = (double)powf(ga,1.0f/n); + + for(i = 0; i < FDNORDER; i++) { + p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); + } + +} + +static inline void gverb_set_damping(ty_gverb *p,float a) +{ + unsigned int i; + + p->fdndamping = a; + for(i = 0; i < FDNORDER; i++) { + damper_set(p->fdndamps[i],p->fdndamping); + } +} + +static inline void gverb_set_inputbandwidth(ty_gverb *p,float a) +{ + p->inputbandwidth = a; + damper_set(p->inputdamper,1.0 - p->inputbandwidth); +} + +static inline void gverb_set_earlylevel(ty_gverb *p,float a) +{ + p->earlylevel = a; +} + +static inline void gverb_set_taillevel(ty_gverb *p,float a) +{ + p->taillevel = a; +} + +#endif diff --git a/interface/external/gverb/src/gverbdsp.c b/interface/external/gverb/src/gverbdsp.c new file mode 100644 index 0000000000..05a90f897e --- /dev/null +++ b/interface/external/gverb/src/gverbdsp.c @@ -0,0 +1,130 @@ + + +/* + + Copyright (C) 1999 Juhana Sadeharju + kouhia at nic.funet.fi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#include +#include +#include +#include + +#include "gverbdsp.h" + +#define TRUE 1 +#define FALSE 0 + +ty_diffuser *diffuser_make(int size, float coeff) +{ + ty_diffuser *p; + int i; + + p = (ty_diffuser *)malloc(sizeof(ty_diffuser)); + p->size = size; + p->coeff = coeff; + p->idx = 0; + p->buf = (float *)malloc(size*sizeof(float)); + for (i = 0; i < size; i++) p->buf[i] = 0.0; + return(p); +} + +void diffuser_free(ty_diffuser *p) +{ + free(p->buf); + free(p); +} + +void diffuser_flush(ty_diffuser *p) +{ + memset(p->buf, 0, p->size * sizeof(float)); +} + +ty_damper *damper_make(float damping) +{ + ty_damper *p; + + p = (ty_damper *)malloc(sizeof(ty_damper)); + p->damping = damping; + p->delay = 0.0f; + return(p); +} + +void damper_free(ty_damper *p) +{ + free(p); +} + +void damper_flush(ty_damper *p) +{ + p->delay = 0.0f; +} + +ty_fixeddelay *fixeddelay_make(int size) +{ + ty_fixeddelay *p; + int i; + + p = (ty_fixeddelay *)malloc(sizeof(ty_fixeddelay)); + p->size = size; + p->idx = 0; + p->buf = (float *)malloc(size*sizeof(float)); + for (i = 0; i < size; i++) p->buf[i] = 0.0; + return(p); +} + +void fixeddelay_free(ty_fixeddelay *p) +{ + free(p->buf); + free(p); +} + +void fixeddelay_flush(ty_fixeddelay *p) +{ + memset(p->buf, 0, p->size * sizeof(float)); +} + +int isprime(int n) +{ + unsigned int i; + const unsigned int lim = (int)sqrtf((float)n); + + if (n == 2) return(TRUE); + if ((n & 1) == 0) return(FALSE); + for(i = 3; i <= lim; i += 2) + if ((n % i) == 0) return(FALSE); + return(TRUE); +} + +int nearest_prime(int n, float rerror) + /* relative error; new prime will be in range + * [n-n*rerror, n+n*rerror]; + */ +{ + int bound,k; + + if (isprime(n)) return(n); + /* assume n is large enough and n*rerror enough smaller than n */ + bound = n*rerror; + for(k = 1; k <= bound; k++) { + if (isprime(n+k)) return(n+k); + if (isprime(n-k)) return(n-k); + } + return(-1); +} diff --git a/interface/external/gverb/src/gverbdsp.h b/interface/external/gverb/src/gverbdsp.h new file mode 100644 index 0000000000..8b8b41d169 --- /dev/null +++ b/interface/external/gverb/src/gverbdsp.h @@ -0,0 +1,85 @@ + +#ifndef GVERBDSP_H +#define GVERBDSP_H + +#include "../include/ladspa-util.h" + +typedef struct { + int size; + int idx; + float *buf; +} ty_fixeddelay; + +typedef struct { + int size; + float coeff; + int idx; + float *buf; +} ty_diffuser; + +typedef struct { + float damping; + float delay; +} ty_damper; + +ty_diffuser *diffuser_make(int, float); +void diffuser_free(ty_diffuser *); +void diffuser_flush(ty_diffuser *); +//float diffuser_do(ty_diffuser *, float); + +ty_damper *damper_make(float); +void damper_free(ty_damper *); +void damper_flush(ty_damper *); +//void damper_set(ty_damper *, float); +//float damper_do(ty_damper *, float); + +ty_fixeddelay *fixeddelay_make(int); +void fixeddelay_free(ty_fixeddelay *); +void fixeddelay_flush(ty_fixeddelay *); +//float fixeddelay_read(ty_fixeddelay *, int); +//void fixeddelay_write(ty_fixeddelay *, float); + +int isprime(int); +int nearest_prime(int, float); + +static inline float diffuser_do(ty_diffuser *p, float x) +{ + float y,w; + + w = x - p->buf[p->idx]*p->coeff; + w = flush_to_zero(w); + y = p->buf[p->idx] + w*p->coeff; + p->buf[p->idx] = w; + p->idx = (p->idx + 1) % p->size; + return(y); +} + +static inline float fixeddelay_read(ty_fixeddelay *p, int n) +{ + int i; + + i = (p->idx - n + p->size) % p->size; + return(p->buf[i]); +} + +static inline void fixeddelay_write(ty_fixeddelay *p, float x) +{ + p->buf[p->idx] = x; + p->idx = (p->idx + 1) % p->size; +} + +static inline void damper_set(ty_damper *p, float damping) +{ + p->damping = damping; +} + +static inline float damper_do(ty_damper *p, float x) +{ + float y; + + y = x*(1.0-p->damping) + p->delay*p->damping; + p->delay = y; + return(y); +} + +#endif diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 365064e979..7a55302310 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -123,11 +123,14 @@ Audio::Audio(QObject* parent) : memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); // Create the noise sample array _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; - + connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedSilence, this, &Audio::addStereoSilenceToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedLastFrameRepeatedWithFade, this, &Audio::addLastFrameRepeatedWithFadeToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedStereoSamples, this, &Audio::addStereoSamplesToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedSamples, Qt::DirectConnection); + + // Initialize GVerb + initGverb(); } void Audio::init(QGLWidget *parent) { @@ -489,6 +492,70 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } +void Audio::initGverb() { + // Initialize a new gverb instance + _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions.getMaxRoomSize(), _reverbOptions.getRoomSize(), _reverbOptions.getReverbTime(), + _reverbOptions.getDamping(), _reverbOptions.getSpread(), _reverbOptions.getInputBandwidth(), _reverbOptions.getEarlyLevel(), + _reverbOptions.getTailLevel()); + + // Configure the instance (these functions are not super well named - they actually set several internal variables) + gverb_set_roomsize(_gverb, _reverbOptions.getRoomSize()); + gverb_set_revtime(_gverb, _reverbOptions.getReverbTime()); + gverb_set_damping(_gverb, _reverbOptions.getDamping()); + gverb_set_inputbandwidth(_gverb, _reverbOptions.getInputBandwidth()); + gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions.getEarlyLevel())); + gverb_set_taillevel(_gverb, DB_CO(_reverbOptions.getTailLevel())); +} + +void Audio::setReverbOptions(const AudioEffectOptions* options) { + // Save the new options + _reverbOptions.setMaxRoomSize(options->getMaxRoomSize()); + _reverbOptions.setRoomSize(options->getRoomSize()); + _reverbOptions.setReverbTime(options->getReverbTime()); + _reverbOptions.setDamping(options->getDamping()); + _reverbOptions.setSpread(options->getSpread()); + _reverbOptions.setInputBandwidth(options->getInputBandwidth()); + _reverbOptions.setEarlyLevel(options->getEarlyLevel()); + _reverbOptions.setTailLevel(options->getTailLevel()); + + _reverbOptions.setDryLevel(options->getDryLevel()); + _reverbOptions.setWetLevel(options->getWetLevel()); + + // Apply them to the reverb instance(s) + initGverb(); +} + +void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { + float dryFraction = DB_CO(_reverbOptions.getDryLevel()); + float wetFraction = DB_CO(_reverbOptions.getWetLevel()); + + float lValue,rValue; + for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { + // Run GVerb + float value = (float)samplesData[sample]; + gverb_do(_gverb, value, &lValue, &rValue); + + // Mix, accounting for clipping, the left and right channels. Ignore the rest. + for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { + if (j == sample) { + // left channel + int lResult = (int)(samplesData[j] * dryFraction + lValue * wetFraction); + if (lResult > 32767) lResult = 32767; + if (lResult < -32768) lResult = -32768; + samplesData[j] = (int16_t)lResult; + } else if (j == (sample + 1)) { + // right channel + int rResult = (int)(samplesData[j] * dryFraction + rValue * wetFraction); + if (rResult > 32767) rResult = 32767; + if (rResult < -32768) rResult = -32768; + samplesData[j] = (int16_t)rResult; + } else { + // ignore channels above 2 + } + } + } +} + void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; @@ -1060,6 +1127,110 @@ void Audio::toggleStereoInput() { } } +void Audio::processReceivedAudio(const QByteArray& audioByteArray) { + _ringBuffer.parseData(audioByteArray); + + float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float) _outputFormat.sampleRate()) + * (_desiredOutputFormat.channelCount() / (float) _outputFormat.channelCount()); + + if (!_ringBuffer.isStarved() && _audioOutput && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { + // we don't have any audio data left in the output buffer + // we just starved + //qDebug() << "Audio output just starved."; + _ringBuffer.setIsStarved(true); + _numFramesDisplayStarve = 10; + } + + // if there is anything in the ring buffer, decide what to do + if (_ringBuffer.samplesAvailable() > 0) { + + int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); + int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; + + QByteArray outputBuffer; + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + + int numSamplesNeededToStartPlayback = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2); + + if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(numSamplesNeededToStartPlayback)) { + // We are still waiting for enough samples to begin playback + // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; + } else { + // We are either already playing back, or we have enough audio to start playing back. + //qDebug() << "pushing " << numNetworkOutputSamples; + _ringBuffer.setIsStarved(false); + + int16_t* ringBufferSamples = new int16_t[numNetworkOutputSamples]; + if (_processSpatialAudio) { + unsigned int sampleTime = _spatialAudioStart; + QByteArray buffer; + buffer.resize(numNetworkOutputSamples * sizeof(int16_t)); + + _ringBuffer.readSamples((int16_t*)buffer.data(), numNetworkOutputSamples); + // Accumulate direct transmission of audio from sender to receiver + if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { + emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); + addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); + } + + // Send audio off for spatial processing + emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); + + // copy the samples we'll resample from the spatial audio ring buffer - this also + // pushes the read pointer of the spatial audio ring buffer forwards + _spatialAudioRingBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); + + // Advance the start point for the next packet of audio to arrive + _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); + } else { + // copy the samples we'll resample from the ring buffer - this also + // pushes the read pointer of the ring buffer forwards + _ringBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); + } + + // copy the packet from the RB to the output + linearResampling(ringBufferSamples, + (int16_t*) outputBuffer.data(), + numNetworkOutputSamples, + numDeviceOutputSamples, + _desiredOutputFormat, _outputFormat); + + if(_reverb) { + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); + } + + if (_outputDevice) { + _outputDevice->write(outputBuffer); + } + + if (_scopeEnabled && !_scopeEnabledPause) { + unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); + int16_t* samples = ringBufferSamples; + for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { + + unsigned int audioChannel = 0; + addBufferToScope( + _scopeOutputLeft, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + audioChannel = 1; + addBufferToScope( + _scopeOutputRight, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; + _scopeOutputOffset %= _samplesPerScope; + samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; + } + } + + delete[] ringBufferSamples; + } + } +} + void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { // zero out the locally injected audio in preparation for audio procedural sounds diff --git a/interface/src/Audio.h b/interface/src/Audio.h index e94e5ab16c..548ae19143 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -44,6 +44,14 @@ #include #include "MixedProcessedAudioStream.h" +#include "AudioEffectOptions.h" +#include +#include + +extern "C" { + #include + #include +} static const int NUM_AUDIO_CHANNELS = 2; @@ -160,6 +168,8 @@ public slots: float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } + void setReverb(bool reverb) { _reverb = reverb; } + void setReverbOptions(const AudioEffectOptions* options); const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; } const QHash& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; } @@ -231,6 +241,9 @@ private: int _proceduralEffectSample; bool _muted; bool _localEcho; + bool _reverb; + AudioEffectOptions _reverbOptions; + ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; GLuint _boxTextureId; @@ -250,6 +263,10 @@ private: // 2. Mix with the audio input void processProceduralAudio(int16_t* monoInput, int numSamples); + // Adds Reverb + void initGverb(); + void addReverb(int16_t* samples, int numSamples, QAudioFormat& format); + // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index 688b0942d5..bcb5fc308d 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -70,3 +70,11 @@ float AudioDeviceScriptingInterface::getInputVolume() { void AudioDeviceScriptingInterface::setInputVolume(float volume) { Application::getInstance()->getAudio()->setInputVolume(volume); } + +void AudioDeviceScriptingInterface::setReverb(bool reverb) { + Application::getInstance()->getAudio()->setReverb(reverb); +} + +void AudioDeviceScriptingInterface::setReverbOptions(const AudioEffectOptions* options) { + Application::getInstance()->getAudio()->setReverbOptions(options); +} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index 62f1153a0b..45bdbc92e2 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -39,6 +39,8 @@ public slots: float getInputVolume(); void setInputVolume(float volume); + void setReverb(bool reverb); + void setReverbOptions(const AudioEffectOptions* options); }; #endif // hifi_AudioDeviceScriptingInterface_h diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp new file mode 100644 index 0000000000..d2200d8d5e --- /dev/null +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -0,0 +1,12 @@ +// +// AudioEffectOptions.cpp +// hifi +// + +#include "AudioEffectOptions.h" + +AudioEffectOptions::AudioEffectOptions() { } + +QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { + return engine->newQObject(new AudioEffectOptions()); +} diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h new file mode 100644 index 0000000000..81a47de08c --- /dev/null +++ b/libraries/audio/src/AudioEffectOptions.h @@ -0,0 +1,99 @@ +// +// AudioEffectOptions.h +// hifi +// + +#ifndef __hifi__AudioEffectOptions__ +#define __hifi__AudioEffectOptions__ + +#include +#include +#include + +class AudioEffectOptions : public QObject { + Q_OBJECT + + // Meters Square + Q_PROPERTY(float maxRoomSize READ getMaxRoomSize WRITE setMaxRoomSize) + Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize) + + // Seconds + Q_PROPERTY(float reverbTime READ getReverbTime WRITE setReverbTime) + + // Ratio between 0 and 1 + Q_PROPERTY(float damping READ getDamping WRITE setDamping) + + // (?) Does not appear to be set externally very often + Q_PROPERTY(float spread READ getSpread WRITE setSpread) + + // Ratio between 0 and 1 + Q_PROPERTY(float inputBandwidth READ getInputBandwidth WRITE setInputBandwidth) + + // in dB + Q_PROPERTY(float earlyLevel READ getEarlyLevel WRITE setEarlyLevel) + Q_PROPERTY(float tailLevel READ getTailLevel WRITE setTailLevel) + Q_PROPERTY(float dryLevel READ getDryLevel WRITE setDryLevel) + Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) + +public: + AudioEffectOptions(); + + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + + float getRoomSize() const { return _roomSize; } + void setRoomSize(float roomSize ) { _roomSize = roomSize; } + + float getMaxRoomSize() const { return _maxRoomSize; } + void setMaxRoomSize(float maxRoomSize ) { _maxRoomSize = maxRoomSize; } + + float getReverbTime() const { return _reverbTime; } + void setReverbTime(float reverbTime ) { _reverbTime = reverbTime; } + + float getDamping() const { return _damping; } + void setDamping(float damping ) { _damping = damping; } + + float getSpread() const { return _spread; } + void setSpread(float spread ) { _spread = spread; } + + float getInputBandwidth() const { return _inputBandwidth; } + void setInputBandwidth(float inputBandwidth ) { _inputBandwidth = inputBandwidth; } + + float getEarlyLevel() const { return _earlyLevel; } + void setEarlyLevel(float earlyLevel ) { _earlyLevel = earlyLevel; } + + float getTailLevel() const { return _tailLevel; } + void setTailLevel(float tailLevel ) { _tailLevel = tailLevel; } + + float getDryLevel() const { return _dryLevel; } + void setDryLevel(float dryLevel) { _dryLevel = dryLevel; } + + float getWetLevel() const { return _wetLevel; } + void setWetLevel(float wetLevel) { _wetLevel = wetLevel; } + +private: + // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings + + // Meters Square + float _maxRoomSize = 50.0f; + float _roomSize = 50.0f; + + // Seconds + float _reverbTime = 4.0f; + + // Ratio between 0 and 1 + float _damping = 0.5f; + + // ? (Does not appear to be set externally very often) + float _spread = 15.0f; + + // Ratio between 0 and 1 + float _inputBandwidth = 0.75f; + + // dB + float _earlyLevel = -22.0f; + float _tailLevel = -28.0f; + float _dryLevel = 0.0f; + float _wetLevel = 6.0f; +}; + +#endif /* defined(__hifi__AudioEffectOptions__) */ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 51789aec3a..f3d202cccc 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -41,6 +41,7 @@ #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" +#include "AudioEffectOptions.h" VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface; @@ -276,6 +277,9 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); + + QScriptValue audioEffectOptionsConstructorValue = _engine.newFunction(AudioEffectOptions::constructor); + _engine.globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); From f09dc1aeaca81fc1a2c8af81f10021c6bb35440b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 14 Oct 2014 15:17:31 -0700 Subject: [PATCH 02/42] remove deprecated _engine member from ScriptEngine --- libraries/script-engine/src/ScriptEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index f3d202cccc..8b80dc9b24 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -278,8 +278,8 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); - QScriptValue audioEffectOptionsConstructorValue = _engine.newFunction(AudioEffectOptions::constructor); - _engine.globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); + QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); + globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); From 954be926e1114612cfa2536b94d77a0ba4239593 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 14 Oct 2014 15:48:43 -0700 Subject: [PATCH 03/42] Fix cmake --- cmake/modules/FindGverb.cmake | 4 ++-- interface/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 904813c007..80aca29b93 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -27,11 +27,11 @@ else () if (GVERB_FOUND) if (NOT GVERB_FIND_QUIETLY) - message(STATUS "Found Gverb... ${GVERB_LIBRARIES}") + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") endif (NOT GVERB_FIND_QUIETLY) else () if (GVERB_FIND_REQUIRED) - message(FATAL_ERROR "Could not find Gverb") + message(FATAL_ERROR "Could NOT find Gverb") endif (GVERB_FIND_REQUIRED) endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 3caa7c470e..8674dd484a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2") +set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "GVERB") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) From 0f128509d80b79b3e05b0d487249dd73ade660a4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 16 Oct 2014 10:58:19 -0700 Subject: [PATCH 04/42] removed old processReceivedAudio method --- interface/src/Audio.cpp | 108 ++-------------------------------------- 1 file changed, 4 insertions(+), 104 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7a55302310..7fdfa61e84 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -951,6 +951,10 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); + + if(_reverb) { + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); + } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { @@ -1127,110 +1131,6 @@ void Audio::toggleStereoInput() { } } -void Audio::processReceivedAudio(const QByteArray& audioByteArray) { - _ringBuffer.parseData(audioByteArray); - - float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float) _outputFormat.sampleRate()) - * (_desiredOutputFormat.channelCount() / (float) _outputFormat.channelCount()); - - if (!_ringBuffer.isStarved() && _audioOutput && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { - // we don't have any audio data left in the output buffer - // we just starved - //qDebug() << "Audio output just starved."; - _ringBuffer.setIsStarved(true); - _numFramesDisplayStarve = 10; - } - - // if there is anything in the ring buffer, decide what to do - if (_ringBuffer.samplesAvailable() > 0) { - - int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); - int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; - - QByteArray outputBuffer; - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); - - int numSamplesNeededToStartPlayback = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2); - - if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(numSamplesNeededToStartPlayback)) { - // We are still waiting for enough samples to begin playback - // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; - } else { - // We are either already playing back, or we have enough audio to start playing back. - //qDebug() << "pushing " << numNetworkOutputSamples; - _ringBuffer.setIsStarved(false); - - int16_t* ringBufferSamples = new int16_t[numNetworkOutputSamples]; - if (_processSpatialAudio) { - unsigned int sampleTime = _spatialAudioStart; - QByteArray buffer; - buffer.resize(numNetworkOutputSamples * sizeof(int16_t)); - - _ringBuffer.readSamples((int16_t*)buffer.data(), numNetworkOutputSamples); - // Accumulate direct transmission of audio from sender to receiver - if (Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal)) { - emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); - addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); - } - - // Send audio off for spatial processing - emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); - - // copy the samples we'll resample from the spatial audio ring buffer - this also - // pushes the read pointer of the spatial audio ring buffer forwards - _spatialAudioRingBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); - - // Advance the start point for the next packet of audio to arrive - _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); - } else { - // copy the samples we'll resample from the ring buffer - this also - // pushes the read pointer of the ring buffer forwards - _ringBuffer.readSamples(ringBufferSamples, numNetworkOutputSamples); - } - - // copy the packet from the RB to the output - linearResampling(ringBufferSamples, - (int16_t*) outputBuffer.data(), - numNetworkOutputSamples, - numDeviceOutputSamples, - _desiredOutputFormat, _outputFormat); - - if(_reverb) { - addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); - } - - if (_outputDevice) { - _outputDevice->write(outputBuffer); - } - - if (_scopeEnabled && !_scopeEnabledPause) { - unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); - int16_t* samples = ringBufferSamples; - for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { - - unsigned int audioChannel = 0; - addBufferToScope( - _scopeOutputLeft, - _scopeOutputOffset, - samples, audioChannel, numAudioChannels); - - audioChannel = 1; - addBufferToScope( - _scopeOutputRight, - _scopeOutputOffset, - samples, audioChannel, numAudioChannels); - - _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; - _scopeOutputOffset %= _samplesPerScope; - samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; - } - } - - delete[] ringBufferSamples; - } - } -} - void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { // zero out the locally injected audio in preparation for audio procedural sounds From ea7c2e2fa37c2ee715a5f33712061962003cd24d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 16 Oct 2014 15:28:24 -0700 Subject: [PATCH 05/42] Added reverb settings to DS settings --- .../resources/describe-settings.json | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index b8bc783aa1..bb331b63eb 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -154,6 +154,33 @@ "placeholder": "0.18" } ] + }, + { + "name": "reverb", + "type": "table", + "label": "Reverb Settings", + "help": "In this table you can set custom reverb values for each audio zones", + "numbered": true, + "columns": [ + { + "name": "zone", + "label": "Zone", + "can_set": true, + "placeholder": "Audio_Zone" + }, + { + "name": "reverb_time", + "label": "Reverb Time", + "can_set": true, + "placeholder": "(in sec)" + }, + { + "name": "wet_level", + "label": "Wet Level", + "can_set": true, + "placeholder": "(in db)" + } + ] } ] }, From 26b1e8fc29b874b92311120849e15099c352c18c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 16 Oct 2014 22:46:40 -0700 Subject: [PATCH 06/42] grab reverb settings on mixer side --- assignment-client/src/audio/AudioMixer.cpp | 33 ++++++++++++++++++++++ assignment-client/src/audio/AudioMixer.h | 8 +++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8caf4ddf09..6f709f2ec8 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -1033,6 +1033,39 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } + + const QString REVERB = "reverb"; + if (audioEnvGroupObject[REVERB].isArray()) { + const QJsonArray& reverb = audioEnvGroupObject[REVERB].toArray(); + + const QString ZONE = "zone"; + const QString REVERB_TIME = "reverb_time"; + const QString WET_LEVEL = "wet_level"; + for (int i = 0; i < reverb.count(); ++i) { + QJsonObject reverbObject = reverb[i].toObject(); + + if (reverbObject.contains(ZONE) && + reverbObject.contains(REVERB_TIME) && + reverbObject.contains(WET_LEVEL)) { + + bool okReverbTime, okWetLevel; + QString zone = reverbObject.value(ZONE).toString(); + float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime); + float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); + + if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { + + ReverbSettings settings; + settings.zone = zone; + settings.reverbTime = reverbTime; + settings.wetLevel = wetLevel; + + _zoneReverbSettings.push_back(settings); + qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; + } + } + } + } } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 3cfa5443a8..ff976dec61 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -82,7 +82,13 @@ private: float coefficient; }; QVector _zonesSettings; - + struct ReverbSettings { + QString zone; + float reverbTime; + float wetLevel; + }; + QVector _zoneReverbSettings; + static InboundAudioStream::Settings _streamSettings; static bool _printStreamStats; From 37b47b52d376f4a33342eec11d92dbfdf8b86379 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 11:49:57 -0700 Subject: [PATCH 07/42] Stream reverb settings from mixer to interface --- assignment-client/src/audio/AudioMixer.cpp | 28 ++++++++++++++++++++-- interface/src/Audio.cpp | 22 +++++++++++++---- libraries/audio/src/InboundAudioStream.cpp | 21 +++++++++++++--- libraries/audio/src/InboundAudioStream.h | 9 +++++++ 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 6f709f2ec8..f4e0ed2466 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -428,8 +428,8 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l } int AudioMixer::prepareMixForListeningNode(Node* node) { - AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream(); - AudioMixerClientData* listenerNodeData = (AudioMixerClientData*)node->getLinkedData(); + AvatarAudioStream* nodeAudioStream = static_cast(node->getLinkedData())->getAvatarAudioStream(); + AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); // zero out the client mix for this node memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -730,6 +730,30 @@ void AudioMixer::run() { memcpy(dataAt, &sequence, sizeof(quint16)); dataAt += sizeof(quint16); + // Pack stream properties + for (int i = 0; i < _zoneReverbSettings.size(); ++i) { + glm::vec3 streamPosition = static_cast(node->getLinkedData())->getAvatarAudioStream()->getPosition(); + if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { + bool hasReverb = true; + float reverbTime = _zoneReverbSettings[i].reverbTime; + float wetLevel = _zoneReverbSettings[i].wetLevel; + + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + memcpy(dataAt, &reverbTime, sizeof(float)); + dataAt += sizeof(float); + memcpy(dataAt, &wetLevel, sizeof(float)); + dataAt += sizeof(float); + + qDebug() << "Out" << sequence << reverbTime << wetLevel; + } else { + bool hasReverb = false; + memcpy(dataAt, &hasReverb, sizeof(bool)); + dataAt += sizeof(bool); + } + } + + // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7fdfa61e84..e566ce77b9 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -787,7 +787,6 @@ void Audio::handleAudioInput() { NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); - if (_recorder && _recorder.data()->isRecording()) { _recorder.data()->record(reinterpret_cast(networkAudioSamples), numNetworkBytes); } @@ -907,12 +906,10 @@ void Audio::addLastFrameRepeatedWithFadeToScope(int samplesPerChannel) { } void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { - const int numNetworkOutputSamples = inputBuffer.size() / sizeof(int16_t); const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples; @@ -952,13 +949,28 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - if(_reverb) { + if (_receivedAudioStream.hasReverb()) { + bool reverbChanged = false; + + if (_reverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { + _reverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); + reverbChanged = true; + } + if (_reverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { + _reverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); + reverbChanged = true; + } + if (reverbChanged) { + initGverb(); + } + } + + if(_reverb || _receivedAudioStream.hasReverb()) { addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { - if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio _receivedAudioStream.parseData(audioByteArray); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index dda57d87da..e92e7c32d6 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -44,7 +44,8 @@ InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacit _framesAvailableStat(), _currentJitterBufferFrames(0), _timeGapStatsForStatsPacket(0, STATS_FOR_STATS_PACKET_WINDOW_SECONDS), - _repetitionWithFade(settings._repetitionWithFade) + _repetitionWithFade(settings._repetitionWithFade), + _hasReverb(false) { } @@ -162,9 +163,23 @@ int InboundAudioStream::parseData(const QByteArray& packet) { } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { + int read = 0; + if (type == PacketTypeMixedAudio) { + memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool)); + read += sizeof(bool); + + if (_hasReverb) { + memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); + read += sizeof(float); + qDebug() << "In" << _reverbTime << _wetLevel; + } + } + // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); - return 0; + numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t); + return read; } int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index a395b1c6c8..3e69db0afb 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -154,6 +154,10 @@ public: int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } + + bool hasReverb() const { return _hasReverb; } + float getRevebTime() const { return _reverbTime; } + float getWetLevel() const { return _wetLevel; } public slots: /// This function should be called every second for all the stats to function properly. If dynamic jitter buffers @@ -243,6 +247,11 @@ protected: MovingMinMaxAvg _timeGapStatsForStatsPacket; bool _repetitionWithFade; + + // Reverb properties + bool _hasReverb; + float _reverbTime; + float _wetLevel; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); From ce949b73508b98e1029be9862e97ea4e60ff1db0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 12:11:29 -0700 Subject: [PATCH 08/42] Coding Standard default values --- libraries/audio/src/AudioEffectOptions.cpp | 13 ++++++++++++- libraries/audio/src/AudioEffectOptions.h | 20 ++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index d2200d8d5e..4653085d5e 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -5,7 +5,18 @@ #include "AudioEffectOptions.h" -AudioEffectOptions::AudioEffectOptions() { } +AudioEffectOptions::AudioEffectOptions() : + _maxRoomSize(50.0f), + _roomSize(50.0f), + _reverbTime(4.0f), + _damping(0.5f), + _spread(15.0f), + _inputBandwidth(0.75f), + _earlyLevel(-22.0f), + _tailLevel(-28.0f), + _dryLevel(0.0f), + _wetLevel(6.0f) { +} QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { return engine->newQObject(new AudioEffectOptions()); diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 81a47de08c..18965f3a91 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -74,26 +74,26 @@ private: // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings // Meters Square - float _maxRoomSize = 50.0f; - float _roomSize = 50.0f; + float _maxRoomSize; + float _roomSize; // Seconds - float _reverbTime = 4.0f; + float _reverbTime; // Ratio between 0 and 1 - float _damping = 0.5f; + float _damping; // ? (Does not appear to be set externally very often) - float _spread = 15.0f; + float _spread; // Ratio between 0 and 1 - float _inputBandwidth = 0.75f; + float _inputBandwidth; // dB - float _earlyLevel = -22.0f; - float _tailLevel = -28.0f; - float _dryLevel = 0.0f; - float _wetLevel = 6.0f; + float _earlyLevel; + float _tailLevel; + float _dryLevel; + float _wetLevel; }; #endif /* defined(__hifi__AudioEffectOptions__) */ From 997f1db8359634a8efa56f8db0e67315aa1bb1de Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 13:37:49 -0700 Subject: [PATCH 09/42] handle JSON for audioEffectOptions args --- libraries/audio/src/AudioEffectOptions.cpp | 46 +++++++++++++++++++++- libraries/audio/src/AudioEffectOptions.h | 2 +- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 4653085d5e..dbe9b51e5b 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -5,7 +5,18 @@ #include "AudioEffectOptions.h" -AudioEffectOptions::AudioEffectOptions() : +static const QString MAX_ROOM_SIZE_HANDLE = "maxRoomSize"; +static const QString ROOM_SIZE_HANDLE = "roomSize"; +static const QString REVERB_TIME_HANDLE = "reverbTime"; +static const QString DAMPIMG_HANDLE = "damping"; +static const QString SPREAD_HANDLE = "spread"; +static const QString INPUT_BANDWIDTH_HANDLE = "inputBandwidth"; +static const QString EARLY_LEVEL_HANDLE = "earlyLevel"; +static const QString TAIL_LEVEL_HANDLE = "tailLevel"; +static const QString DRY_LEVEL_HANDLE = "dryLevel"; +static const QString WET_LEVEL_HANDLE = "wetLevel"; + +AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : _maxRoomSize(50.0f), _roomSize(50.0f), _reverbTime(4.0f), @@ -16,8 +27,39 @@ AudioEffectOptions::AudioEffectOptions() : _tailLevel(-28.0f), _dryLevel(0.0f), _wetLevel(6.0f) { + if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { + _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); + } + if (arguments.property(ROOM_SIZE_HANDLE).isNumber()) { + _roomSize = arguments.property(ROOM_SIZE_HANDLE).toNumber(); + } + if (arguments.property(REVERB_TIME_HANDLE).isNumber()) { + _reverbTime = arguments.property(REVERB_TIME_HANDLE).toNumber(); + } + if (arguments.property(DAMPIMG_HANDLE).isNumber()) { + _damping = arguments.property(DAMPIMG_HANDLE).toNumber(); + } + if (arguments.property(SPREAD_HANDLE).isNumber()) { + _spread = arguments.property(SPREAD_HANDLE).toNumber(); + } + if (arguments.property(INPUT_BANDWIDTH_HANDLE).isNumber()) { + _inputBandwidth = arguments.property(INPUT_BANDWIDTH_HANDLE).toNumber(); + } + if (arguments.property(EARLY_LEVEL_HANDLE).isNumber()) { + _earlyLevel = arguments.property(EARLY_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(TAIL_LEVEL_HANDLE).isNumber()) { + _tailLevel = arguments.property(TAIL_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(DRY_LEVEL_HANDLE).isNumber()) { + _dryLevel = arguments.property(DRY_LEVEL_HANDLE).toNumber(); + } + if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { + _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); + } + } QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { - return engine->newQObject(new AudioEffectOptions()); + return engine->newQObject(new AudioEffectOptions(context->argument(0))); } diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 18965f3a91..b3db9fd0f7 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -36,7 +36,7 @@ class AudioEffectOptions : public QObject { Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) public: - AudioEffectOptions(); + AudioEffectOptions(QScriptValue arguments = QScriptValue()); static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); From 5a11104bdf92ee0ac6eaa45a68a8ad56deeaa09c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 13:45:16 -0700 Subject: [PATCH 10/42] Updated script --- examples/audioReverbOff.js | 12 ----------- examples/audioReverbOn.js | 43 ++++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 30 deletions(-) delete mode 100644 examples/audioReverbOff.js diff --git a/examples/audioReverbOff.js b/examples/audioReverbOff.js deleted file mode 100644 index 1076a825a7..0000000000 --- a/examples/audioReverbOff.js +++ /dev/null @@ -1,12 +0,0 @@ -// -// audioReverbOff.js -// examples -// -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -// -AudioDevice.setReverb(false); -print("Reberb is now off."); diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js index 6d43c31943..479f5bba74 100644 --- a/examples/audioReverbOn.js +++ b/examples/audioReverbOn.js @@ -8,25 +8,32 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings -var audioOptions = new AudioEffectOptions(); - -// Square Meters -audioOptions.maxRoomSize = 50; -audioOptions.roomSize = 50; - -// Seconds -audioOptions.reverbTime = 4; - -// Between 0 - 1 -audioOptions.damping = 0.50; -audioOptions.inputBandwidth = 0.75; - -// dB -audioOptions.earlyLevel = -22; -audioOptions.tailLevel = -28; -audioOptions.dryLevel = 0; -audioOptions.wetLevel = 6; +var audioOptions = new AudioEffectOptions({ + // Square Meters + maxRoomSize: 50, + roomSize: 50, + + // Seconds + reverbTime: 4, + + // Between 0 - 1 + damping: 0.50, + inputBandwidth: 0.75, + + // dB + earlyLevel: -22, + tailLevel: -28, + dryLevel: 0, + wetLevel: 6 +}); AudioDevice.setReverbOptions(audioOptions); AudioDevice.setReverb(true); print("Reverb is now on with the updated options."); + +function scriptEnding() { + AudioDevice.setReverb(false); + print("Reberb is now off."); +} + +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From 6f9557fe672200bba31211a33b3939c9df9f0ae4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 15:06:02 -0700 Subject: [PATCH 11/42] Do not destroy script reverb settings --- assignment-client/src/audio/AudioMixer.cpp | 2 - interface/src/Audio.cpp | 84 ++++++++++++---------- interface/src/Audio.h | 4 +- libraries/audio/src/AudioEffectOptions.cpp | 20 +++++- libraries/audio/src/AudioEffectOptions.h | 2 + libraries/audio/src/InboundAudioStream.cpp | 1 - 6 files changed, 69 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f4e0ed2466..9b91dd8c1e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -744,8 +744,6 @@ void AudioMixer::run() { dataAt += sizeof(float); memcpy(dataAt, &wetLevel, sizeof(float)); dataAt += sizeof(float); - - qDebug() << "Out" << sequence << reverbTime << wetLevel; } else { bool hasReverb = false; memcpy(dataAt, &hasReverb, sizeof(bool)); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index e566ce77b9..ff41da6e81 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -494,40 +494,43 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { void Audio::initGverb() { // Initialize a new gverb instance - _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions.getMaxRoomSize(), _reverbOptions.getRoomSize(), _reverbOptions.getReverbTime(), - _reverbOptions.getDamping(), _reverbOptions.getSpread(), _reverbOptions.getInputBandwidth(), _reverbOptions.getEarlyLevel(), - _reverbOptions.getTailLevel()); + _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), + _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), + _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), + _reverbOptions->getTailLevel()); // Configure the instance (these functions are not super well named - they actually set several internal variables) - gverb_set_roomsize(_gverb, _reverbOptions.getRoomSize()); - gverb_set_revtime(_gverb, _reverbOptions.getReverbTime()); - gverb_set_damping(_gverb, _reverbOptions.getDamping()); - gverb_set_inputbandwidth(_gverb, _reverbOptions.getInputBandwidth()); - gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions.getEarlyLevel())); - gverb_set_taillevel(_gverb, DB_CO(_reverbOptions.getTailLevel())); + gverb_set_roomsize(_gverb, _reverbOptions->getRoomSize()); + gverb_set_revtime(_gverb, _reverbOptions->getReverbTime()); + gverb_set_damping(_gverb, _reverbOptions->getDamping()); + gverb_set_inputbandwidth(_gverb, _reverbOptions->getInputBandwidth()); + gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions->getEarlyLevel())); + gverb_set_taillevel(_gverb, DB_CO(_reverbOptions->getTailLevel())); } void Audio::setReverbOptions(const AudioEffectOptions* options) { // Save the new options - _reverbOptions.setMaxRoomSize(options->getMaxRoomSize()); - _reverbOptions.setRoomSize(options->getRoomSize()); - _reverbOptions.setReverbTime(options->getReverbTime()); - _reverbOptions.setDamping(options->getDamping()); - _reverbOptions.setSpread(options->getSpread()); - _reverbOptions.setInputBandwidth(options->getInputBandwidth()); - _reverbOptions.setEarlyLevel(options->getEarlyLevel()); - _reverbOptions.setTailLevel(options->getTailLevel()); + _scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize()); + _scriptReverbOptions.setRoomSize(options->getRoomSize()); + _scriptReverbOptions.setReverbTime(options->getReverbTime()); + _scriptReverbOptions.setDamping(options->getDamping()); + _scriptReverbOptions.setSpread(options->getSpread()); + _scriptReverbOptions.setInputBandwidth(options->getInputBandwidth()); + _scriptReverbOptions.setEarlyLevel(options->getEarlyLevel()); + _scriptReverbOptions.setTailLevel(options->getTailLevel()); - _reverbOptions.setDryLevel(options->getDryLevel()); - _reverbOptions.setWetLevel(options->getWetLevel()); + _scriptReverbOptions.setDryLevel(options->getDryLevel()); + _scriptReverbOptions.setWetLevel(options->getWetLevel()); - // Apply them to the reverb instance(s) - initGverb(); + if (_reverbOptions == &_scriptReverbOptions) { + // Apply them to the reverb instance(s) + initGverb(); + } } void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { - float dryFraction = DB_CO(_reverbOptions.getDryLevel()); - float wetFraction = DB_CO(_reverbOptions.getWetLevel()); + float dryFraction = DB_CO(_reverbOptions->getDryLevel()); + float wetFraction = DB_CO(_reverbOptions->getWetLevel()); float lValue,rValue; for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { @@ -949,23 +952,26 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - if (_receivedAudioStream.hasReverb()) { - bool reverbChanged = false; - - if (_reverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { - _reverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); - reverbChanged = true; - } - if (_reverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { - _reverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - reverbChanged = true; - } - if (reverbChanged) { - initGverb(); - } - } - if(_reverb || _receivedAudioStream.hasReverb()) { + if (_receivedAudioStream.hasReverb()) { + _reverbOptions = &_zoneReverbOptions; + + bool reverbChanged = false; + if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { + _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); + reverbChanged = true; + } + if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { + _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); + reverbChanged = true; + } + if (reverbChanged) { + initGverb(); + } + } else { + _reverbOptions = &_scriptReverbOptions; + } + addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 7390a3c28c..900b6ce0d6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -241,7 +241,9 @@ private: bool _muted; bool _localEcho; bool _reverb; - AudioEffectOptions _reverbOptions; + AudioEffectOptions _scriptReverbOptions; + AudioEffectOptions _zoneReverbOptions; + AudioEffectOptions* _reverbOptions; ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index dbe9b51e5b..8f1acd7ec0 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -57,7 +57,25 @@ AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); } - +} + +AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) { + *this = other; +} + +AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &other) { + _maxRoomSize = other._maxRoomSize; + _roomSize = other._roomSize; + _reverbTime = other._reverbTime; + _damping = other._damping; + _spread = other._spread; + _inputBandwidth = other._inputBandwidth; + _earlyLevel = other._earlyLevel; + _tailLevel = other._tailLevel; + _dryLevel = other._dryLevel; + _wetLevel = other._wetLevel; + + return *this; } QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index b3db9fd0f7..ae99face0f 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -37,6 +37,8 @@ class AudioEffectOptions : public QObject { public: AudioEffectOptions(QScriptValue arguments = QScriptValue()); + AudioEffectOptions(const AudioEffectOptions &other); + AudioEffectOptions& operator=(const AudioEffectOptions &other); static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index e92e7c32d6..59578951f8 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -173,7 +173,6 @@ int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& read += sizeof(float); memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); read += sizeof(float); - qDebug() << "In" << _reverbTime << _wetLevel; } } From 94f66ef37a12585a822cf465aa29d9b7bd2b3214 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 15:35:01 -0700 Subject: [PATCH 12/42] Reverb logic tweaks --- interface/src/Audio.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index ff41da6e81..527703f7a4 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,6 +92,8 @@ Audio::Audio(QObject* parent) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _muted(false), + _reverb(false), + _reverbOptions(&_scriptReverbOptions), _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), @@ -531,7 +533,7 @@ void Audio::setReverbOptions(const AudioEffectOptions* options) { void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { float dryFraction = DB_CO(_reverbOptions->getDryLevel()); float wetFraction = DB_CO(_reverbOptions->getWetLevel()); - + float lValue,rValue; for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { // Run GVerb @@ -953,10 +955,9 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou _desiredOutputFormat, _outputFormat); if(_reverb || _receivedAudioStream.hasReverb()) { + bool reverbChanged = false; if (_receivedAudioStream.hasReverb()) { - _reverbOptions = &_zoneReverbOptions; - bool reverbChanged = false; if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); reverbChanged = true; @@ -965,13 +966,19 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); reverbChanged = true; } - if (reverbChanged) { - initGverb(); + + if (_reverbOptions != &_zoneReverbOptions) { + _reverbOptions = &_zoneReverbOptions; + reverbChanged = true; } - } else { + } else if (_reverbOptions != &_scriptReverbOptions) { _reverbOptions = &_scriptReverbOptions; + reverbChanged = true; } + if (reverbChanged) { + initGverb(); + } addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } From 585403629615859f635dfbc894ad93d963967051 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 16:02:59 -0700 Subject: [PATCH 13/42] cmake fix for ubuntu --- interface/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1d86e7601b..1c9c68ec5f 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "GVERB") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) From 7c54da033cb1b87917564e0f3c73cfac5e02d43d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 16:29:19 -0700 Subject: [PATCH 14/42] Changed reverb time label --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index a34b854b8e..026fe252b2 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -170,7 +170,7 @@ }, { "name": "reverb_time", - "label": "Reverb Time", + "label": "Reverb Decay Time", "can_set": true, "placeholder": "(in sec)" }, From ee4c7c25bfb7672073b54ee987315c1aaf621142 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 16:50:49 -0700 Subject: [PATCH 15/42] Header fix --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e1459d4f2c..bab3e0ce4a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include "ScriptEngine.h" #include "TypedArrays.h" #include "XMLHttpRequestClass.h" -#include "AudioEffectOptions.h" VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; EntityScriptingInterface ScriptEngine::_entityScriptingInterface; From 9a7ca8b1324e96634c22d0e674f2ef53f81e74ac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Oct 2014 17:23:58 -0700 Subject: [PATCH 16/42] Fix header --- libraries/audio/src/AudioEffectOptions.cpp | 7 ++++++- libraries/audio/src/AudioEffectOptions.h | 13 +++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 8f1acd7ec0..480779afd2 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -1,6 +1,11 @@ // // AudioEffectOptions.cpp -// hifi +// libraries/audio/src +// +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "AudioEffectOptions.h" diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index ae99face0f..97aac7c82c 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -1,10 +1,15 @@ // // AudioEffectOptions.h -// hifi +// libraries/audio/src +// +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef __hifi__AudioEffectOptions__ -#define __hifi__AudioEffectOptions__ +#ifndef hifi_AudioEffectOptions_h +#define hifi_AudioEffectOptions_h #include #include @@ -98,4 +103,4 @@ private: float _wetLevel; }; -#endif /* defined(__hifi__AudioEffectOptions__) */ +#endif // hifi_AudioEffectOptions_h From d81158f941760be32fdc59697dd7c54c8ae7c76c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 21 Oct 2014 17:45:21 -0700 Subject: [PATCH 17/42] Remove Gverb source code --- interface/external/gverb/CMakeLists.txt | 2 - .../external/gverb/include/ladspa-util.h | 234 ----------- interface/external/gverb/include/lv2.h | 392 ------------------ interface/external/gverb/src/gverb.c | 207 --------- interface/external/gverb/src/gverb.h | 234 ----------- interface/external/gverb/src/gverbdsp.c | 130 ------ interface/external/gverb/src/gverbdsp.h | 85 ---- 7 files changed, 1284 deletions(-) delete mode 100644 interface/external/gverb/CMakeLists.txt delete mode 100644 interface/external/gverb/include/ladspa-util.h delete mode 100644 interface/external/gverb/include/lv2.h delete mode 100644 interface/external/gverb/src/gverb.c delete mode 100644 interface/external/gverb/src/gverb.h delete mode 100644 interface/external/gverb/src/gverbdsp.c delete mode 100644 interface/external/gverb/src/gverbdsp.h diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt deleted file mode 100644 index 140b45b727..0000000000 --- a/interface/external/gverb/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -add_library(gverb include/ladspa-util.h include/lv2.h src/gverb.h src/gverb.c src/gverbdsp.h src/gverbdsp.c) diff --git a/interface/external/gverb/include/ladspa-util.h b/interface/external/gverb/include/ladspa-util.h deleted file mode 100644 index 149d0aaacd..0000000000 --- a/interface/external/gverb/include/ladspa-util.h +++ /dev/null @@ -1,234 +0,0 @@ -/* Some misc util functions for audio DSP work, written by Steve Harris, - * December 2000 - * - * steve@plugin.org.uk - */ - -#ifndef LADSPA_UTIL_H -#define LADSPA_UTIL_H - -#include -#include -#include - -#define buffer_write(a, b) a=(b) - -// 16.16 fixpoint -typedef union { - int32_t all; - struct { -#ifdef WORDS_BIGENDIAN - int16_t in; - uint16_t fr; -#else - uint16_t fr; - int16_t in; -#endif - } part; -} fixp16; - -// 32.32 fixpoint -typedef union { - int64_t all; - struct { -#ifdef WORDS_BIGENDIAN - int32_t in; - uint32_t fr; -#else - uint32_t fr; - int32_t in; -#endif - } part; -} fixp32; - -/* 32 bit "pointer cast" union */ -typedef union { - float f; - int32_t i; -} ls_pcast32; - -// Sometimes it doesn't get defined, even though it eists and C99 is declared -long int lrintf (float x); - -// 1.0 / ln(2) -#define LN2R 1.442695041f - -/* detet floating point denormal numbers by comparing them to the smallest - * normal, crap, but reliable */ -#define DN_CHECK(x, l) if (fabs(x) < 1e-38) printf("DN: "l"\n") - -// Denormalise floats, only actually needed for PIII and recent PowerPC -//#define FLUSH_TO_ZERO(fv) (((*(unsigned int*)&(fv))&0x7f800000)==0)?0.0f:(fv) - -static inline float flush_to_zero(float f) -{ - ls_pcast32 v; - - v.f = f; - - // original: return (v.i & 0x7f800000) == 0 ? 0.0f : f; - // version from Tim Blechmann - return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f; -} - -static inline void round_to_zero(volatile float *f) -{ - *f += 1e-18; - *f -= 1e-18; -} - -/* A set of branchless clipping operations from Laurent de Soras */ - -static inline float f_max(float x, float a) -{ - x -= a; - x += fabs(x); - x *= 0.5; - x += a; - - return x; -} - -static inline float f_min(float x, float b) -{ - x = b - x; - x += fabs(x); - x *= 0.5; - x = b - x; - - return x; -} - -static inline float f_clamp(float x, float a, float b) -{ - const float x1 = fabs(x - a); - const float x2 = fabs(x - b); - - x = x1 + a + b; - x -= x2; - x *= 0.5; - - return x; -} - -// Limit a value to be l<=v<=u -#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) - -// Truncate-to-zero modulo (ANSI C doesn't specify) will only work -// if -m < v < 2m -#define MOD(v,m) (v<0?v+m:(v>=m?v-m:v)) - -// Truncate-to-zero modulo (ANSI C doesn't specify) will only work -// if v > -m and v < m -#define NEG_MOD(v,m) ((v)<0?((v)+(m)):(v)) - -// Convert a value in dB's to a coefficent -#define DB_CO(g) ((g) > -90.0f ? powf(10.0f, (g) * 0.05f) : 0.0f) -#define CO_DB(v) (20.0f * log10f(v)) - -// Linearly interpolate [ = a * (1 - f) + b * f] -#define LIN_INTERP(f,a,b) ((a) + (f) * ((b) - (a))) - -// Cubic interpolation function -static inline float cube_interp(const float fr, const float inm1, const float - in, const float inp1, const float inp2) -{ - return in + 0.5f * fr * (inp1 - inm1 + - fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 + - fr * (3.0f * (in - inp1) - inm1 + inp2))); -} - -/* fast sin^2 aproxiamtion, adapted from jan AT rpgfan's posting to the - * music-dsp list */ -static inline float f_sin_sq(float angle) -{ - const float asqr = angle * angle; - float result = -2.39e-08f; - - result *= asqr; - result += 2.7526e-06f; - result *= asqr; - result -= 1.98409e-04f; - result *= asqr; - result += 8.3333315e-03f; - result *= asqr; - result -= 1.666666664e-01f; - result *= asqr; - result += 1.0f; - result *= angle; - - return result * result; -} - -#ifdef HAVE_LRINTF - -#define f_round(f) lrintf(f) - -#else - -// Round float to int using IEEE int* hack -static inline int f_round(float f) -{ - ls_pcast32 p; - - p.f = f; - p.f += (3<<22); - - return p.i - 0x4b400000; -} - -#endif - -// Truncate float to int -static inline int f_trunc(float f) -{ - return f_round(floorf(f)); -} - -/* Andrew Simper's pow(2, x) aproximation from the music-dsp list */ - -#if 0 - -/* original */ -static inline float f_pow2(float x) -{ - long *px = (long*)(&x); // store address of float as long pointer - const float tx = (x-0.5f) + (3<<22); // temporary value for truncation - const long lx = *((long*)&tx) - 0x4b400000; // integer power of 2 - const float dx = x-(float)(lx); // float remainder of power of 2 - - x = 1.0f + dx*(0.6960656421638072f + // cubic apporoximation of 2^x - dx*(0.224494337302845f + // for x in the range [0, 1] - dx*(0.07944023841053369f))); - *px += (lx<<23); // add integer power of 2 to exponent - - return x; -} - -#else - -/* union version */ -static inline float f_pow2(float x) -{ - ls_pcast32 *px, tx, lx; - float dx; - - px = (ls_pcast32 *)&x; // store address of float as long pointer - tx.f = (x-0.5f) + (3<<22); // temporary value for truncation - lx.i = tx.i - 0x4b400000; // integer power of 2 - dx = x - (float)lx.i; // float remainder of power of 2 - - x = 1.0f + dx * (0.6960656421638072f + // cubic apporoximation of 2^x - dx * (0.224494337302845f + // for x in the range [0, 1] - dx * (0.07944023841053369f))); - (*px).i += (lx.i << 23); // add integer power of 2 to exponent - - return (*px).f; -} - -#endif - -/* Fast exponentiation function, y = e^x */ -#define f_exp(x) f_pow2(x * LN2R) - -#endif diff --git a/interface/external/gverb/include/lv2.h b/interface/external/gverb/include/lv2.h deleted file mode 100644 index d5257824c6..0000000000 --- a/interface/external/gverb/include/lv2.h +++ /dev/null @@ -1,392 +0,0 @@ -/* LV2 - LADSPA (Linux Audio Developer's Simple Plugin API) Version 2 - * Revision 1 - * - * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, - * Stefan Westerfeld. - * Copyright (C) 2006-2008 Steve Harris, Dave Robillard. - * - * This header is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, - * or (at your option) any later version. - * - * This header is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - * USA. - */ - -#ifndef LV2_H_INCLUDED -#define LV2_H_INCLUDED - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* ************************************************************************* */ - - -/** @file lv2.h - * - * Revision: 1 - * - * == Overview == - * - * There are a large number of open source and free software synthesis - * packages in use or development at this time. This API ('LV2') - * attempts to give programmers the ability to write simple 'plugin' - * audio processors in C/C++ and link them dynamically ('plug') into - * a range of these packages ('hosts'). It should be possible for any - * host and any plugin to communicate completely through this interface. - * - * This API is deliberately as short and simple as possible. - * The information required to use a plugin is in a companion data - * (RDF) file. The shared library portion of the API (defined in this - * header) does not contain enough information to make use of the plugin - * possible - the data file is mandatory. - * - * Plugins are expected to distinguish between control rate and audio - * rate data (or other types of data defined by extensions). Plugins have - * 'ports' that are inputs or outputs and each plugin is 'run' for a 'block' - * corresponding to a short time interval measured in samples. Audio rate - * data is communicated using arrays with one element per sample processed, - * allowing a block of audio to be processed by the plugin in a single - * pass. Control rate data is communicated using single values. Control - * rate data has a single value at the start of a call to the 'run()' - * function, and may be considered to remain this value for its duration. - * Thus the 'control rate' is determined by the block size, controlled by - * the host. The plugin may assume that all its input and output ports have - * been connected to the relevant data location (see the 'connect_port()' - * function below) before it is asked to run, unless the port has been set - * 'connection optional' in the plugin's data file. - * - * Plugins will reside in shared object files suitable for dynamic linking - * by dlopen() and family. The file will provide a number of 'plugin - * types' that can be used to instantiate actual plugins (sometimes known - * as 'plugin instances') that can be connected together to perform tasks. - * The host can access these plugin types using the lv2_descriptor() - * function. - * - * This API contains very limited error-handling. - * - * == Threading rules == - * - * Certain hosts may need to call the functions provided by a plugin from - * multiple threads. For this to be safe, the plugin must be written so that - * those functions can be executed simultaneously without problems. - * To facilitate this, the functions provided by a plugin are divided into - * classes: - * - * - Discovery class: lv2_descriptor(), extension_data() - * - Instantiation class: instantiate(), cleanup(), activate(), deactivate() - * - Audio class: run(), connect_port() - * - * Extensions to this specification which add new functions MUST declare in - * which of these classes the functions belong, or define new classes for them. - * The rules that hosts must follow are these: - * - * - When a function from the Discovery class is running, no other - * functions in the same shared object file may run. - * - When a function from the Instantiation class is running for a plugin - * instance, no other functions for that instance may run. - * - When a function is running for a plugin instance, no other - * function in the same class may run for that instance. - * - * Any simultaneous calls that are not explicitly forbidden by these rules - * are allowed. For example, a host may call run() for two different plugin - * instances simultaneously. - */ - - -/* ************************************************************************* */ - - -/** Plugin Handle. - * - * This plugin handle indicates a particular instance of the plugin - * concerned. It is valid to compare this to NULL (0 for C++) but - * otherwise the host MUST NOT attempt to interpret it. The plugin - * may use it to reference internal instance data. */ -typedef void * LV2_Handle; - - -/* ************************************************************************* */ - - -/** Feature data. - * - * These are passed to a plugin's instantiate method to represent a special - * feature the host has which the plugin may depend on. This is to allow - * extensions to the LV2 specification without causing any breakage. - * Extensions may specify what data needs to be passed here. The base - * LV2 specification does not define any features; hosts are not required - * to use this facility. */ -typedef struct _LV2_Feature { - /** A globally unique, case-sensitive identifier for this feature. - * - * This MUST be defined in the specification of any LV2 extension which - * defines a host feature. */ - const char * URI; - - /** Pointer to arbitrary data. - * - * This is to allow hosts to pass data to a plugin (simple values, data - * structures, function pointers, etc) as part of a 'feature'. The LV2 - * specification makes no restrictions on the contents of this data. - * The data here MUST be cleary defined by the LV2 extension which defines - * this feature. - * If no data is required, this may be set to NULL. */ - void * data; -} LV2_Feature; - - -/* ************************************************************************* */ - - -/** Descriptor for a Type of Plugin. - * - * This structure is used to describe a plugin type. It provides a number - * of functions to instantiate it, link it to buffers and run it. */ -typedef struct _LV2_Descriptor { - - /** A globally unique, case-sensitive identifier for this plugin type. - * - * All plugins with the same URI MUST be compatible in terms of 'port - * signature', meaning they have the same number of ports, same port - * shortnames, and roughly the same functionality. URIs should - * probably contain a version number (or similar) for this reason. - * - * Rationale: When serializing session/patch/etc files, hosts MUST - * refer to a loaded plugin by the plugin URI only. In the future - * loading a plugin with this URI MUST yield a plugin with the - * same ports (etc) which is 100% compatible. */ - const char * URI; - - /** Function pointer that instantiates a plugin. - * - * A handle is returned indicating the new plugin instance. The - * instantiation function accepts a sample rate as a parameter as well - * as the plugin descriptor from which this instantiate function was - * found. This function must return NULL if instantiation fails. - * - * bundle_path is a string of the path to the LV2 bundle which contains - * this plugin binary. It MUST include the trailing directory separator - * (e.g. '/') so that BundlePath + filename gives the path to a file - * in the bundle. - * - * features is a NULL terminated array of LV2_Feature structs which - * represent the features the host supports. Plugins may refuse to - * instantiate if required features are not found here (however hosts - * SHOULD NOT use this as a discovery mechanism, instead reading the - * data file before attempting to instantiate the plugin). This array - * must always exist; if a host has no features, it MUST pass a single - * element array containing NULL (to simplify plugins). - * - * Note that instance initialisation should generally occur in - * activate() rather than here. If a host calls instantiate, it MUST - * call cleanup() at some point in the future. */ - LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor, - double sample_rate, - const char * bundle_path, - const LV2_Feature *const * features); - - /** Function pointer that connects a port on a plugin instance to a memory - * location where the block of data for the port will be read/written. - * - * The data location is expected to be of the type defined in the - * plugin's data file (e.g. an array of float for an lv2:AudioPort). - * Memory issues are managed by the host. The plugin must read/write - * the data at these locations every time run() is called, data - * present at the time of this connection call MUST NOT be - * considered meaningful. - * - * The host MUST NOT try to connect a data buffer to a port index - * that is not defined in the RDF data for the plugin. If it does, - * the plugin's behaviour is undefined. - * - * connect_port() may be called more than once for a plugin instance - * to allow the host to change the buffers that the plugin is reading - * or writing. These calls may be made before or after activate() - * or deactivate() calls. Note that there may be realtime constraints - * on connect_port (see lv2:hardRTCapable in lv2.ttl). - * - * connect_port() MUST be called at least once for each port before - * run() is called. The plugin must pay careful attention to the block - * size passed to the run function as the block allocated may only just - * be large enough to contain the block of data (typically samples), and - * is not guaranteed to be constant. - * - * Plugin writers should be aware that the host may elect to use the - * same buffer for more than one port and even use the same buffer for - * both input and output (see lv2:inPlaceBroken in lv2.ttl). - * However, overlapped buffers or use of a single buffer for both - * audio and control data may result in unexpected behaviour. - * - * If the plugin has the feature lv2:hardRTCapable then there are - * various things that the plugin MUST NOT do within the connect_port() - * function (see lv2.ttl). */ - void (*connect_port)(LV2_Handle instance, - uint32_t port, - void * data_location); - - /** Function pointer that initialises a plugin instance and activates - * it for use. - * - * This is separated from instantiate() to aid real-time support and so - * that hosts can reinitialise a plugin instance by calling deactivate() - * and then activate(). In this case the plugin instance must reset all - * state information dependent on the history of the plugin instance - * except for any data locations provided by connect_port(). If there - * is nothing for activate() to do then the plugin writer may provide - * a NULL rather than an empty function. - * - * When present, hosts MUST call this function once before run() - * is called for the first time. This call SHOULD be made as close - * to the run() call as possible and indicates to real-time plugins - * that they are now live, however plugins MUST NOT rely on a prompt - * call to run() after activate(). activate() may not be called again - * unless deactivate() is called first (after which activate() may be - * called again, followed by deactivate, etc. etc.). If a host calls - * activate, it MUST call deactivate at some point in the future. - * - * Note that connect_port() may be called before or after a call to - * activate(). */ - void (*activate)(LV2_Handle instance); - - /** Function pointer that runs a plugin instance for a block. - * - * Two parameters are required: the first is a handle to the particular - * instance to be run and the second indicates the block size (in - * samples) for which the plugin instance may run. - * - * Note that if an activate() function exists then it must be called - * before run(). If deactivate() is called for a plugin instance then - * the plugin instance may not be reused until activate() has been - * called again. - * - * If the plugin has the feature lv2:hardRTCapable then there are - * various things that the plugin MUST NOT do within the run() - * function (see lv2.ttl). */ - void (*run)(LV2_Handle instance, - uint32_t sample_count); - - /** This is the counterpart to activate() (see above). If there is - * nothing for deactivate() to do then the plugin writer may provide - * a NULL rather than an empty function. - * - * Hosts must deactivate all activated units after they have been run() - * for the last time. This call SHOULD be made as close to the last - * run() call as possible and indicates to real-time plugins that - * they are no longer live, however plugins MUST NOT rely on prompt - * deactivation. Note that connect_port() may be called before or - * after a call to deactivate(). - * - * Note that deactivation is not similar to pausing as the plugin - * instance will be reinitialised when activate() is called to reuse it. - * Hosts MUST NOT call deactivate() unless activate() was previously - * called. */ - void (*deactivate)(LV2_Handle instance); - - /** This is the counterpart to instantiate() (see above). Once an instance - * of a plugin has been finished with it can be deleted using this - * function. The instance handle passed ceases to be valid after - * this call. - * - * If activate() was called for a plugin instance then a corresponding - * call to deactivate() MUST be made before cleanup() is called. - * Hosts MUST NOT call cleanup() unless instantiate() was previously - * called. */ - void (*cleanup)(LV2_Handle instance); - - /** Function pointer that can be used to return additional instance data for - * a plugin defined by some extenion (e.g. a struct containing additional - * function pointers). - * - * The actual type and meaning of the returned object MUST be specified - * precisely by the extension if it defines any extra data. If a particular - * extension does not define extra instance data, this function MUST return - * NULL for that extension's URI. If a plugin does not support any - * extensions that define extra instance data, this function pointer may be - * set to NULL rather than providing an empty function. - * - * The only parameter is the URI of the extension. The plugin MUST return - * NULL if it does not support the extension, but hosts SHOULD NOT use this - * as a discovery method (e.g. hosts should only call this function for - * extensions known to be supported by the plugin from the data file). - * - * The host is never responsible for freeing the returned value. - * - * NOTE: This function should return a struct (likely containing function - * pointers) and NOT a direct function pointer. Standard C and C++ do not - * allow type casts from void* to a function pointer type. To provide - * additional functions a struct should be returned containing the extra - * function pointers (which is valid standard code, and a much better idea - * for extensibility anyway). */ - const void* (*extension_data)(const char * uri); - -} LV2_Descriptor; - - -/* ****************************************************************** */ - - -/** Accessing Plugin Types. - * - * The exact mechanism by which plugins are loaded is host-dependent, - * however all most hosts will need to know is the URI of the plugin they - * wish to load. The environment variable LV2_PATH, if present, should - * contain a colon-separated path indicating directories (containing - * plugin bundle subdirectories) that should be searched (in order) - * for plugins. It is expected that hosts will use a library to provide - * this functionality. - * - * A plugin programmer must include a function called "lv2_descriptor" - * with the following function prototype within the shared object - * file. This function will have C-style linkage (if you are using - * C++ this is taken care of by the 'extern "C"' clause at the top of - * the file). - * - * A host will find the plugin shared object file by one means or another, - * find the lv2_descriptor() function, call it, and proceed from there. - * - * Plugin types are accessed by index (not ID) using values from 0 - * upwards. Out of range indexes must result in this function returning - * NULL, so the plugin count can be determined by checking for the least - * index that results in NULL being returned. Index has no meaning, - * hosts MUST NOT depend on it remaining constant (ie when serialising) - * in any way. */ -const LV2_Descriptor * lv2_descriptor(uint32_t index); - - -/** Datatype corresponding to the lv2_descriptor() function. */ -typedef const LV2_Descriptor * -(*LV2_Descriptor_Function)(uint32_t index); - - -/* ******************************************************************** */ - - -/* Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded - * by the host as a symbol from the dynamic library. - */ -#ifdef WIN32 -#define LV2_SYMBOL_EXPORT __declspec(dllexport) -#else -#define LV2_SYMBOL_EXPORT -#endif - - -#ifdef __cplusplus -} -#endif - -#endif /* LV2_H_INCLUDED */ - diff --git a/interface/external/gverb/src/gverb.c b/interface/external/gverb/src/gverb.c deleted file mode 100644 index e3980232bc..0000000000 --- a/interface/external/gverb/src/gverb.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - - Copyright (C) 1999 Juhana Sadeharju - kouhia at nic.funet.fi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - - -#include -#include -#include -#include -#include "gverbdsp.h" -#include "gverb.h" -#include "../include/ladspa-util.h" - -ty_gverb *gverb_new(int srate, float maxroomsize, float roomsize, - float revtime, - float damping, float spread, - float inputbandwidth, float earlylevel, - float taillevel) -{ - ty_gverb *p; - float ga,gb,gt; - int i,n; - float r; - float diffscale; - int a,b,c,cc,d,dd,e; - float spread1,spread2; - - p = (ty_gverb *)malloc(sizeof(ty_gverb)); - p->rate = srate; - p->fdndamping = damping; - p->maxroomsize = maxroomsize; - p->roomsize = roomsize; - p->revtime = revtime; - p->earlylevel = earlylevel; - p->taillevel = taillevel; - - p->maxdelay = p->rate*p->maxroomsize/340.0; - p->largestdelay = p->rate*p->roomsize/340.0; - - - /* Input damper */ - - p->inputbandwidth = inputbandwidth; - p->inputdamper = damper_make(1.0 - p->inputbandwidth); - - - /* FDN section */ - - - p->fdndels = (ty_fixeddelay **)calloc(FDNORDER, sizeof(ty_fixeddelay *)); - for(i = 0; i < FDNORDER; i++) { - p->fdndels[i] = fixeddelay_make((int)p->maxdelay+1000); - } - p->fdngains = (float *)calloc(FDNORDER, sizeof(float)); - p->fdnlens = (int *)calloc(FDNORDER, sizeof(int)); - - p->fdndamps = (ty_damper **)calloc(FDNORDER, sizeof(ty_damper *)); - for(i = 0; i < FDNORDER; i++) { - p->fdndamps[i] = damper_make(p->fdndamping); - } - - ga = 60.0; - gt = p->revtime; - ga = powf(10.0f,-ga/20.0f); - n = p->rate*gt; - p->alpha = pow((double)ga, 1.0/(double)n); - - gb = 0.0; - for(i = 0; i < FDNORDER; i++) { - if (i == 0) gb = 1.000000*p->largestdelay; - if (i == 1) gb = 0.816490*p->largestdelay; - if (i == 2) gb = 0.707100*p->largestdelay; - if (i == 3) gb = 0.632450*p->largestdelay; - -#if 0 - p->fdnlens[i] = nearest_prime((int)gb, 0.5); -#else - p->fdnlens[i] = f_round(gb); -#endif - p->fdngains[i] = -powf((float)p->alpha,p->fdnlens[i]); - } - - p->d = (float *)calloc(FDNORDER, sizeof(float)); - p->u = (float *)calloc(FDNORDER, sizeof(float)); - p->f = (float *)calloc(FDNORDER, sizeof(float)); - - /* Diffuser section */ - - diffscale = (float)p->fdnlens[3]/(210+159+562+410); - spread1 = spread; - spread2 = 3.0*spread; - - b = 210; - r = 0.125541; - a = spread1*r; - c = 210+159+a; - cc = c-b; - r = 0.854046; - a = spread2*r; - d = 210+159+562+a; - dd = d-c; - e = 1341-d; - - p->ldifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); - p->ldifs[0] = diffuser_make((int)(diffscale*b),0.75); - p->ldifs[1] = diffuser_make((int)(diffscale*cc),0.75); - p->ldifs[2] = diffuser_make((int)(diffscale*dd),0.625); - p->ldifs[3] = diffuser_make((int)(diffscale*e),0.625); - - b = 210; - r = -0.568366; - a = spread1*r; - c = 210+159+a; - cc = c-b; - r = -0.126815; - a = spread2*r; - d = 210+159+562+a; - dd = d-c; - e = 1341-d; - - p->rdifs = (ty_diffuser **)calloc(4, sizeof(ty_diffuser *)); - p->rdifs[0] = diffuser_make((int)(diffscale*b),0.75); - p->rdifs[1] = diffuser_make((int)(diffscale*cc),0.75); - p->rdifs[2] = diffuser_make((int)(diffscale*dd),0.625); - p->rdifs[3] = diffuser_make((int)(diffscale*e),0.625); - - - - /* Tapped delay section */ - - p->tapdelay = fixeddelay_make(44000); - p->taps = (int *)calloc(FDNORDER, sizeof(int)); - p->tapgains = (float *)calloc(FDNORDER, sizeof(float)); - - p->taps[0] = 5+0.410*p->largestdelay; - p->taps[1] = 5+0.300*p->largestdelay; - p->taps[2] = 5+0.155*p->largestdelay; - p->taps[3] = 5+0.000*p->largestdelay; - - for(i = 0; i < FDNORDER; i++) { - p->tapgains[i] = pow(p->alpha,(double)p->taps[i]); - } - - return(p); -} - -void gverb_free(ty_gverb *p) -{ - int i; - - damper_free(p->inputdamper); - for(i = 0; i < FDNORDER; i++) { - fixeddelay_free(p->fdndels[i]); - damper_free(p->fdndamps[i]); - diffuser_free(p->ldifs[i]); - diffuser_free(p->rdifs[i]); - } - free(p->fdndels); - free(p->fdngains); - free(p->fdnlens); - free(p->fdndamps); - free(p->d); - free(p->u); - free(p->f); - free(p->ldifs); - free(p->rdifs); - free(p->taps); - free(p->tapgains); - fixeddelay_free(p->tapdelay); - free(p); -} - -void gverb_flush(ty_gverb *p) -{ - int i; - - damper_flush(p->inputdamper); - for(i = 0; i < FDNORDER; i++) { - fixeddelay_flush(p->fdndels[i]); - damper_flush(p->fdndamps[i]); - diffuser_flush(p->ldifs[i]); - diffuser_flush(p->rdifs[i]); - } - memset(p->d, 0, FDNORDER * sizeof(float)); - memset(p->u, 0, FDNORDER * sizeof(float)); - memset(p->f, 0, FDNORDER * sizeof(float)); - fixeddelay_flush(p->tapdelay); -} - -/* swh: other functions are now in the .h file for inlining */ diff --git a/interface/external/gverb/src/gverb.h b/interface/external/gverb/src/gverb.h deleted file mode 100644 index 21bc1c3fef..0000000000 --- a/interface/external/gverb/src/gverb.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - - Copyright (C) 1999 Juhana Sadeharju - kouhia at nic.funet.fi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#ifndef GVERB_H -#define GVERB_H - -#include -#include -#include -#include "gverbdsp.h" -#include "gverb.h" -#include "../include/ladspa-util.h" - -#define FDNORDER 4 - -typedef struct { - int rate; - float inputbandwidth; - float taillevel; - float earlylevel; - ty_damper *inputdamper; - float maxroomsize; - float roomsize; - float revtime; - float maxdelay; - float largestdelay; - ty_fixeddelay **fdndels; - float *fdngains; - int *fdnlens; - ty_damper **fdndamps; - float fdndamping; - ty_diffuser **ldifs; - ty_diffuser **rdifs; - ty_fixeddelay *tapdelay; - int *taps; - float *tapgains; - float *d; - float *u; - float *f; - double alpha; -} ty_gverb; - - -ty_gverb *gverb_new(int, float, float, float, float, float, float, float, float); -void gverb_free(ty_gverb *); -void gverb_flush(ty_gverb *); -static void gverb_do(ty_gverb *, float, float *, float *); -static void gverb_set_roomsize(ty_gverb *, float); -static void gverb_set_revtime(ty_gverb *, float); -static void gverb_set_damping(ty_gverb *, float); -static void gverb_set_inputbandwidth(ty_gverb *, float); -static void gverb_set_earlylevel(ty_gverb *, float); -static void gverb_set_taillevel(ty_gverb *, float); - -/* - * This FDN reverb can be made smoother by setting matrix elements at the - * diagonal and near of it to zero or nearly zero. By setting diagonals to zero - * means we remove the effect of the parallel comb structure from the - * reverberation. A comb generates uniform impulse stream to the reverberation - * impulse response, and thus it is not good. By setting near diagonal elements - * to zero means we remove delay sequences having consequtive delays of the - * similar lenths, when the delays are in sorted in length with respect to - * matrix element index. The matrix described here could be generated by - * differencing Rocchesso's circulant matrix at max diffuse value and at low - * diffuse value (approaching parallel combs). - * - * Example 1: - * Set a(k,k), for all k, equal to 0. - * - * Example 2: - * Set a(k,k), a(k,k-1) and a(k,k+1) equal to 0. - * - * Example 3: The transition to zero gains could be smooth as well. - * a(k,k-1) and a(k,k+1) could be 0.3, and a(k,k-2) and a(k,k+2) could - * be 0.5, say. - */ - -static inline void gverb_fdnmatrix(float *a, float *b) -{ - const float dl0 = a[0], dl1 = a[1], dl2 = a[2], dl3 = a[3]; - - b[0] = 0.5f*(+dl0 + dl1 - dl2 - dl3); - b[1] = 0.5f*(+dl0 - dl1 - dl2 + dl3); - b[2] = 0.5f*(-dl0 + dl1 - dl2 + dl3); - b[3] = 0.5f*(+dl0 + dl1 + dl2 + dl3); -} - -static inline void gverb_do(ty_gverb *p, float x, float *yl, float *yr) -{ - float z; - unsigned int i; - float lsum,rsum,sum,sign; - - if ((x != x) || fabsf(x) > 100000.0f) { - x = 0.0f; - } - - z = damper_do(p->inputdamper, x); - - z = diffuser_do(p->ldifs[0],z); - - for(i = 0; i < FDNORDER; i++) { - p->u[i] = p->tapgains[i]*fixeddelay_read(p->tapdelay,p->taps[i]); - } - fixeddelay_write(p->tapdelay,z); - - for(i = 0; i < FDNORDER; i++) { - p->d[i] = damper_do(p->fdndamps[i], - p->fdngains[i]*fixeddelay_read(p->fdndels[i], - p->fdnlens[i])); - } - - sum = 0.0f; - sign = 1.0f; - for(i = 0; i < FDNORDER; i++) { - sum += sign*(p->taillevel*p->d[i] + p->earlylevel*p->u[i]); - sign = -sign; - } - sum += x*p->earlylevel; - lsum = sum; - rsum = sum; - - gverb_fdnmatrix(p->d,p->f); - - for(i = 0; i < FDNORDER; i++) { - fixeddelay_write(p->fdndels[i],p->u[i]+p->f[i]); - } - - lsum = diffuser_do(p->ldifs[1],lsum); - lsum = diffuser_do(p->ldifs[2],lsum); - lsum = diffuser_do(p->ldifs[3],lsum); - rsum = diffuser_do(p->rdifs[1],rsum); - rsum = diffuser_do(p->rdifs[2],rsum); - rsum = diffuser_do(p->rdifs[3],rsum); - - *yl = lsum; - *yr = rsum; -} - -static inline void gverb_set_roomsize(ty_gverb *p, const float a) -{ - unsigned int i; - - if (a <= 1.0 || (a != a)) { - p->roomsize = 1.0; - } else { - p->roomsize = a; - } - p->largestdelay = p->rate * p->roomsize * 0.00294f; - - p->fdnlens[0] = f_round(1.000000f*p->largestdelay); - p->fdnlens[1] = f_round(0.816490f*p->largestdelay); - p->fdnlens[2] = f_round(0.707100f*p->largestdelay); - p->fdnlens[3] = f_round(0.632450f*p->largestdelay); - for(i = 0; i < FDNORDER; i++) { - p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); - } - - p->taps[0] = 5+f_round(0.410f*p->largestdelay); - p->taps[1] = 5+f_round(0.300f*p->largestdelay); - p->taps[2] = 5+f_round(0.155f*p->largestdelay); - p->taps[3] = 5+f_round(0.000f*p->largestdelay); - - for(i = 0; i < FDNORDER; i++) { - p->tapgains[i] = powf((float)p->alpha, p->taps[i]); - } - -} - -static inline void gverb_set_revtime(ty_gverb *p,float a) -{ - float ga,gt; - double n; - unsigned int i; - - p->revtime = a; - - ga = 60.0; - gt = p->revtime; - ga = powf(10.0f,-ga/20.0f); - n = p->rate*gt; - p->alpha = (double)powf(ga,1.0f/n); - - for(i = 0; i < FDNORDER; i++) { - p->fdngains[i] = -powf((float)p->alpha, p->fdnlens[i]); - } - -} - -static inline void gverb_set_damping(ty_gverb *p,float a) -{ - unsigned int i; - - p->fdndamping = a; - for(i = 0; i < FDNORDER; i++) { - damper_set(p->fdndamps[i],p->fdndamping); - } -} - -static inline void gverb_set_inputbandwidth(ty_gverb *p,float a) -{ - p->inputbandwidth = a; - damper_set(p->inputdamper,1.0 - p->inputbandwidth); -} - -static inline void gverb_set_earlylevel(ty_gverb *p,float a) -{ - p->earlylevel = a; -} - -static inline void gverb_set_taillevel(ty_gverb *p,float a) -{ - p->taillevel = a; -} - -#endif diff --git a/interface/external/gverb/src/gverbdsp.c b/interface/external/gverb/src/gverbdsp.c deleted file mode 100644 index 05a90f897e..0000000000 --- a/interface/external/gverb/src/gverbdsp.c +++ /dev/null @@ -1,130 +0,0 @@ - - -/* - - Copyright (C) 1999 Juhana Sadeharju - kouhia at nic.funet.fi - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - */ - -#include -#include -#include -#include - -#include "gverbdsp.h" - -#define TRUE 1 -#define FALSE 0 - -ty_diffuser *diffuser_make(int size, float coeff) -{ - ty_diffuser *p; - int i; - - p = (ty_diffuser *)malloc(sizeof(ty_diffuser)); - p->size = size; - p->coeff = coeff; - p->idx = 0; - p->buf = (float *)malloc(size*sizeof(float)); - for (i = 0; i < size; i++) p->buf[i] = 0.0; - return(p); -} - -void diffuser_free(ty_diffuser *p) -{ - free(p->buf); - free(p); -} - -void diffuser_flush(ty_diffuser *p) -{ - memset(p->buf, 0, p->size * sizeof(float)); -} - -ty_damper *damper_make(float damping) -{ - ty_damper *p; - - p = (ty_damper *)malloc(sizeof(ty_damper)); - p->damping = damping; - p->delay = 0.0f; - return(p); -} - -void damper_free(ty_damper *p) -{ - free(p); -} - -void damper_flush(ty_damper *p) -{ - p->delay = 0.0f; -} - -ty_fixeddelay *fixeddelay_make(int size) -{ - ty_fixeddelay *p; - int i; - - p = (ty_fixeddelay *)malloc(sizeof(ty_fixeddelay)); - p->size = size; - p->idx = 0; - p->buf = (float *)malloc(size*sizeof(float)); - for (i = 0; i < size; i++) p->buf[i] = 0.0; - return(p); -} - -void fixeddelay_free(ty_fixeddelay *p) -{ - free(p->buf); - free(p); -} - -void fixeddelay_flush(ty_fixeddelay *p) -{ - memset(p->buf, 0, p->size * sizeof(float)); -} - -int isprime(int n) -{ - unsigned int i; - const unsigned int lim = (int)sqrtf((float)n); - - if (n == 2) return(TRUE); - if ((n & 1) == 0) return(FALSE); - for(i = 3; i <= lim; i += 2) - if ((n % i) == 0) return(FALSE); - return(TRUE); -} - -int nearest_prime(int n, float rerror) - /* relative error; new prime will be in range - * [n-n*rerror, n+n*rerror]; - */ -{ - int bound,k; - - if (isprime(n)) return(n); - /* assume n is large enough and n*rerror enough smaller than n */ - bound = n*rerror; - for(k = 1; k <= bound; k++) { - if (isprime(n+k)) return(n+k); - if (isprime(n-k)) return(n-k); - } - return(-1); -} diff --git a/interface/external/gverb/src/gverbdsp.h b/interface/external/gverb/src/gverbdsp.h deleted file mode 100644 index 8b8b41d169..0000000000 --- a/interface/external/gverb/src/gverbdsp.h +++ /dev/null @@ -1,85 +0,0 @@ - -#ifndef GVERBDSP_H -#define GVERBDSP_H - -#include "../include/ladspa-util.h" - -typedef struct { - int size; - int idx; - float *buf; -} ty_fixeddelay; - -typedef struct { - int size; - float coeff; - int idx; - float *buf; -} ty_diffuser; - -typedef struct { - float damping; - float delay; -} ty_damper; - -ty_diffuser *diffuser_make(int, float); -void diffuser_free(ty_diffuser *); -void diffuser_flush(ty_diffuser *); -//float diffuser_do(ty_diffuser *, float); - -ty_damper *damper_make(float); -void damper_free(ty_damper *); -void damper_flush(ty_damper *); -//void damper_set(ty_damper *, float); -//float damper_do(ty_damper *, float); - -ty_fixeddelay *fixeddelay_make(int); -void fixeddelay_free(ty_fixeddelay *); -void fixeddelay_flush(ty_fixeddelay *); -//float fixeddelay_read(ty_fixeddelay *, int); -//void fixeddelay_write(ty_fixeddelay *, float); - -int isprime(int); -int nearest_prime(int, float); - -static inline float diffuser_do(ty_diffuser *p, float x) -{ - float y,w; - - w = x - p->buf[p->idx]*p->coeff; - w = flush_to_zero(w); - y = p->buf[p->idx] + w*p->coeff; - p->buf[p->idx] = w; - p->idx = (p->idx + 1) % p->size; - return(y); -} - -static inline float fixeddelay_read(ty_fixeddelay *p, int n) -{ - int i; - - i = (p->idx - n + p->size) % p->size; - return(p->buf[i]); -} - -static inline void fixeddelay_write(ty_fixeddelay *p, float x) -{ - p->buf[p->idx] = x; - p->idx = (p->idx + 1) % p->size; -} - -static inline void damper_set(ty_damper *p, float damping) -{ - p->damping = damping; -} - -static inline float damper_do(ty_damper *p, float x) -{ - float y; - - y = x*(1.0-p->damping) + p->delay*p->damping; - p->delay = y; - return(y); -} - -#endif From e9d3729238b24a87318ae1549d4d14f414070464 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 10:30:46 -0700 Subject: [PATCH 18/42] Remove unnecessary header --- interface/src/Audio.h | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 900b6ce0d6..3b7c2eef03 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -49,7 +49,6 @@ extern "C" { #include - #include } static const int NUM_AUDIO_CHANNELS = 2; From 52dacaab02468e6c806b7df05ac17a88ccc49c6c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:36:44 -0700 Subject: [PATCH 19/42] Update entity editing to force SPACE_LOCAL for single-selection --- examples/libraries/entitySelectionTool.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index b70c2187c2..7815946fd1 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -78,6 +78,8 @@ SelectionManager = (function() { that.worldDimensions = null; that.worldPosition = null; } else if (that.selections.length == 1) { + SelectionDisplay.setSpaceMode(SPACE_LOCAL); + var properties = Entities.getEntityProperties(that.selections[0]); that.localDimensions = properties.dimensions; that.localPosition = properties.position; From 078d14ae58d560f9d36f2157d7f8f39e6931cb87 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:36:58 -0700 Subject: [PATCH 20/42] Fix rotation overlay size with multi-selection --- examples/libraries/entitySelectionTool.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 7815946fd1..0153f7fc3d 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -624,8 +624,8 @@ SelectionDisplay = (function () { } - var diagonal = (Vec3.length(properties.dimensions) / 2) * 1.1; - var halfDimensions = Vec3.multiply(properties.dimensions, 0.5); + var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; + var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); innerRadius = diagonal; outerRadius = diagonal * 1.15; var innerActive = false; From 5b9806dc0dd9bb419421c4345f45c2d2e0902309 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:37:17 -0700 Subject: [PATCH 21/42] Fix deletion with multi-selection --- examples/libraries/entitySelectionTool.js | 2 +- examples/newEditEntities.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 0153f7fc3d..f4f068742f 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -927,7 +927,7 @@ SelectionDisplay = (function () { }; that.updateHandles = function(entityID) { - if (!entitySelected) { + if (SelectionManager.selections.length == 0) { that.setOverlaysVisible(false); return; } diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 9b46cdaf3f..402ad94417 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -608,9 +608,12 @@ function handeMenuEvent(menuItem) { } else if (menuItem == "Delete") { if (entitySelected) { print(" Delete Entity.... selectedEntityID="+ selectedEntityID); - Entities.deleteEntity(selectedEntityID); + for (var i = 0; i < selectionManager.selections.length; i++) { + Entities.deleteEntity(selectionManager.selections[i]); + } selectionDisplay.unselect(selectedEntityID); entitySelected = false; + selectionManager.clearSelections(); } else { print(" Delete Entity.... not holding..."); } @@ -653,7 +656,7 @@ Controller.keyReleaseEvent.connect(function (event) { if (event.text == "`") { handeMenuEvent("Edit Properties..."); } - if (event.text == "BACKSPACE") { + if (event.text == "BACKSPACE" || event.text == "DELETE") { handeMenuEvent("Delete"); } else if (event.text == "TAB") { selectionDisplay.toggleSpaceMode(); From 0bda7699a66d5c0dc53f15a4182715a3397d67e9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 10:38:24 -0700 Subject: [PATCH 22/42] Disable properties menu with multi-selection --- examples/newEditEntities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 402ad94417..ae0d018b14 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -621,7 +621,7 @@ function handeMenuEvent(menuItem) { // good place to put the properties dialog editModelID = -1; - if (entitySelected) { + if (selectionManager.selections.length == 1) { print(" Edit Properties.... selectedEntityID="+ selectedEntityID); editModelID = selectedEntityID; } else { From 1739cf019d0a0d2ad104f24a2c7aee572bae1708 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 11:35:51 -0700 Subject: [PATCH 23/42] Gverb library CMakeLists --- interface/external/gverb/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 interface/external/gverb/CMakeLists.txt diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt new file mode 100644 index 0000000000..7913348e1d --- /dev/null +++ b/interface/external/gverb/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +set(TARGET_NAME gverb) +project(${TARGET_NAME}) + +# grab the implementation and header files +file(GLOB GVERB_SRCS src/*.c) + +include_directories(include) + +add_library(${TARGET_NAME} ${GVERB_SRCS}) From e496304f7ef1e96bef4c49ebd9cfbffeb37f5d21 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 11:36:23 -0700 Subject: [PATCH 24/42] Changed include dir --- cmake/modules/FindGverb.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 80aca29b93..8990009b59 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -19,7 +19,7 @@ if (GVERB_INCLUDE_DIRS) # in cache already set(GVERB_FOUND TRUE) else () - find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/src) + find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/include) if (GVERB_INCLUDE_DIRS) set(GVERB_FOUND TRUE) From ccc8e0d876c9addf5d0470aa269d2d736dd6c170 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 12:56:44 -0700 Subject: [PATCH 25/42] Statically link gverb --- cmake/modules/FindGverb.cmake | 29 +++++++++++++------------ interface/CMakeLists.txt | 14 +++++++----- interface/external/gverb/CMakeLists.txt | 11 ---------- interface/src/Audio.h | 1 + 4 files changed, 24 insertions(+), 31 deletions(-) delete mode 100644 interface/external/gverb/CMakeLists.txt diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 8990009b59..f71e1256a2 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -13,26 +13,27 @@ # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# +# if (GVERB_INCLUDE_DIRS) # in cache already set(GVERB_FOUND TRUE) else () - find_path(GVERB_INCLUDE_DIRS gverb.h ${GVERB_ROOT_DIR}/include) - if (GVERB_INCLUDE_DIRS) - set(GVERB_FOUND TRUE) - endif (GVERB_INCLUDE_DIRS) +include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("gverb") - if (GVERB_FOUND) - if (NOT GVERB_FIND_QUIETLY) - message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") - endif (NOT GVERB_FIND_QUIETLY) - else () - if (GVERB_FIND_REQUIRED) - message(FATAL_ERROR "Could NOT find Gverb") - endif (GVERB_FIND_REQUIRED) - endif () +find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) +find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) + +if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) +endif (GVERB_INCLUDE_DIRS) + +if (GVERB_FOUND) + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") +else () + message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") +endif () endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1c9c68ec5f..d0868aebcd 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -14,9 +14,17 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) + # As Gverb is currently the only reverb library, it's required. find_package(Gverb REQUIRED) +if (GVERB_FOUND) + file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) + include_directories(${GVERB_INCLUDE_DIRS}) + add_library(Gverb ${GVERB_SRCS}) +message(STATUS "Gverb srcs: ${GVERB_SRCS}") +endif (GVERB_FOUND) + if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -169,12 +177,6 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () -if (GVERB_FOUND) - add_subdirectory(${GVERB_ROOT_DIR}) - include_directories(${GVERB_INCLUDE_DIRS}) - target_link_libraries(${TARGET_NAME} gverb) -endif (GVERB_FOUND) - # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") diff --git a/interface/external/gverb/CMakeLists.txt b/interface/external/gverb/CMakeLists.txt deleted file mode 100644 index 7913348e1d..0000000000 --- a/interface/external/gverb/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(TARGET_NAME gverb) -project(${TARGET_NAME}) - -# grab the implementation and header files -file(GLOB GVERB_SRCS src/*.c) - -include_directories(include) - -add_library(${TARGET_NAME} ${GVERB_SRCS}) diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 3b7c2eef03..900b6ce0d6 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -49,6 +49,7 @@ extern "C" { #include + #include } static const int NUM_AUDIO_CHANNELS = 2; From e69bc22222c1c8fc1c9b36d275ed23c0c82afe32 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 12:56:55 -0700 Subject: [PATCH 26/42] Fix for streaming crash. --- .../metavoxels/src/DatagramSequencer.cpp | 2 +- libraries/metavoxels/src/DatagramSequencer.h | 3 ++ .../metavoxels/src/MetavoxelClientManager.cpp | 40 ++++++++++++++----- .../metavoxels/src/MetavoxelClientManager.h | 7 +++- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index be3d684a3d..d97ed67644 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -301,10 +301,10 @@ void DatagramSequencer::clearReliableChannel(QObject* object) { void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { // stop acknowledging the recorded packets while (!_receiveRecords.isEmpty() && _receiveRecords.first().packetNumber <= record.lastReceivedPacketNumber) { + emit receiveAcknowledged(0); const ReceiveRecord& received = _receiveRecords.first(); _inputStream.persistReadMappings(received.mappings); _receivedHighPriorityMessages -= received.newHighPriorityMessages; - emit receiveAcknowledged(0); _receiveRecords.removeFirst(); } _outputStream.persistWriteMappings(record.mappings); diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 9a1f5a4ae0..02fbd0f365 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -108,6 +108,9 @@ public: /// Returns the intput channel at the specified index, creating it if necessary. ReliableChannel* getReliableInputChannel(int index = 0); + /// Returns a reference to the stored receive mappings at the specified index. + const Bitstream::ReadMappings& getReadMappings(int index) const { return _receiveRecords.at(index).mappings; } + /// Adds stats for all reliable channels to the referenced variables. void addReliableChannelStats(int& sendProgress, int& sendTotal, int& receiveProgress, int& receiveTotal) const; diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 09164d72c4..cc5d7ef29d 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -188,7 +188,9 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater Endpoint(node, new PacketRecord(), new PacketRecord()), _updater(updater), _reliableDeltaChannel(NULL), - _reliableDeltaID(0) { + _reliableDeltaID(0), + _dummyInputStream(_dummyDataStream), + _dummyPacketNumber(0) { connect(_sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX), SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); @@ -234,9 +236,9 @@ PacketRecord* MetavoxelClient::getAcknowledgedReceiveRecord(int packetNumber) co if (lastAcknowledged->getPacketNumber() == packetNumber) { return lastAcknowledged; } - foreach (PacketRecord* record, _clearedReceiveRecords) { - if (record->getPacketNumber() == packetNumber) { - return record; + foreach (const ClearedReceiveRecord& record, _clearedReceiveRecords) { + if (record.first->getPacketNumber() == packetNumber) { + return record.first; } } return NULL; @@ -257,8 +259,8 @@ void MetavoxelClient::recordReceive() { } _clearedSendRecords.clear(); - foreach (PacketRecord* record, _clearedReceiveRecords) { - delete record; + foreach (const ClearedReceiveRecord& record, _clearedReceiveRecords) { + delete record.first; } _clearedReceiveRecords.clear(); } @@ -273,10 +275,16 @@ void MetavoxelClient::clearSendRecordsBefore(int index) { } void MetavoxelClient::clearReceiveRecordsBefore(int index) { + // copy the mappings on first call per packet + if (_sequencer.getIncomingPacketNumber() > _dummyPacketNumber) { + _dummyPacketNumber = _sequencer.getIncomingPacketNumber(); + _dummyInputStream.copyPersistentMappings(_sequencer.getInputStream()); + } + // move to cleared list QList::iterator end = _receiveRecords.begin() + index + 1; for (QList::const_iterator it = _receiveRecords.begin(); it != end; it++) { - _clearedReceiveRecords.append(*it); + _clearedReceiveRecords.append(ClearedReceiveRecord(*it, _sequencer.getReadMappings(index))); } _receiveRecords.erase(_receiveRecords.begin(), end); } @@ -289,7 +297,6 @@ void MetavoxelClient::writeUpdateMessage(Bitstream& out) { void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { - PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); if (_reliableDeltaChannel) { MetavoxelData reference = _remoteData; MetavoxelLOD referenceLOD = _remoteDataLOD; @@ -299,6 +306,7 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { _reliableDeltaChannel = NULL; } else { + PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); in.reset(); @@ -319,8 +327,6 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { MetavoxelDeltaPendingMessage pending = message.value(); if (pending.id > _reliableDeltaID) { _reliableDeltaID = pending.id; - _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); - _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); PacketRecord* sendRecord = getAcknowledgedSendRecord(pending.receivedPacketNumber); if (!sendRecord) { qWarning() << "Missing send record for delta" << pending.receivedPacketNumber; @@ -334,6 +340,20 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } _remoteDataLOD = receiveRecord->getLOD(); _remoteData = receiveRecord->getData(); + + _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); + if (receiveRecord == getLastAcknowledgedReceiveRecord()) { + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); + + } else { + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_dummyInputStream); + foreach (const ClearedReceiveRecord& record, _clearedReceiveRecords) { + _reliableDeltaChannel->getBitstream().persistReadMappings(record.second); + if (record.first == receiveRecord) { + break; + } + } + } } } else { Endpoint::handleMessage(message, in); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 0a32f2986d..adab59e0ff 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -145,8 +145,13 @@ protected: MetavoxelData _dataCopy; QReadWriteLock _dataCopyLock; + QDataStream _dummyDataStream; + Bitstream _dummyInputStream; + int _dummyPacketNumber; QList _clearedSendRecords; - QList _clearedReceiveRecords; + + typedef QPair ClearedReceiveRecord; + QList _clearedReceiveRecords; }; #endif // hifi_MetavoxelClientManager_h From ad2eb0896432a8f35dd719b69ca736a9de0c20da Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 13:11:45 -0700 Subject: [PATCH 27/42] Correctly link in cmake --- cmake/modules/FindGverb.cmake | 5 ++--- interface/CMakeLists.txt | 14 +++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index f71e1256a2..175c216359 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -32,8 +32,7 @@ endif (GVERB_INCLUDE_DIRS) if (GVERB_FOUND) message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") -else () +else (GVERB_FOUND) message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") -endif () +endif (GVERB_FOUND) -endif () diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d0868aebcd..a150a308e0 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -18,13 +18,6 @@ find_package(Qt5LinguistToolsMacros) # As Gverb is currently the only reverb library, it's required. find_package(Gverb REQUIRED) -if (GVERB_FOUND) - file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) - include_directories(${GVERB_INCLUDE_DIRS}) - add_library(Gverb ${GVERB_SRCS}) -message(STATUS "Gverb srcs: ${GVERB_SRCS}") -endif (GVERB_FOUND) - if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -177,6 +170,13 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () +if (GVERB_FOUND) + file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) + include_directories(${GVERB_INCLUDE_DIRS}) + add_library(gverb STATIC ${GVERB_SRCS}) + target_link_libraries(${TARGET_NAME} gverb) +endif (GVERB_FOUND) + # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") From fc9010dd6b218246a9cb2b0f8064951131d9bfa1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 13:38:49 -0700 Subject: [PATCH 28/42] missing endif --- cmake/modules/FindGverb.cmake | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 175c216359..1d234b69e2 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -18,21 +18,22 @@ if (GVERB_INCLUDE_DIRS) # in cache already set(GVERB_FOUND TRUE) -else () +else (GVERB_INCLUDE_DIRS) -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("gverb") + include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") + hifi_library_search_hints("gverb") -find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) -find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) + find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) + find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) -if (GVERB_INCLUDE_DIRS) - set(GVERB_FOUND TRUE) -endif (GVERB_INCLUDE_DIRS) + if (GVERB_INCLUDE_DIRS) + set(GVERB_FOUND TRUE) + endif (GVERB_INCLUDE_DIRS) -if (GVERB_FOUND) - message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") -else (GVERB_FOUND) - message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") -endif (GVERB_FOUND) + if (GVERB_FOUND) + message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") + else (GVERB_FOUND) + message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") + endif (GVERB_FOUND) +endif(GVERB_INCLUDE_DIR) \ No newline at end of file From bd4e8a172d0d67489f11b42d2b2ab17a396e66ed Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 13:40:58 -0700 Subject: [PATCH 29/42] typo --- cmake/modules/FindGverb.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake index 1d234b69e2..549c23c8a9 100644 --- a/cmake/modules/FindGverb.cmake +++ b/cmake/modules/FindGverb.cmake @@ -36,4 +36,4 @@ else (GVERB_INCLUDE_DIRS) message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") endif (GVERB_FOUND) -endif(GVERB_INCLUDE_DIR) \ No newline at end of file +endif(GVERB_INCLUDE_DIRS) \ No newline at end of file From 345a9f02f78c43502dfecc5a2bde1f9e66072386 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 14:30:20 -0700 Subject: [PATCH 30/42] Upload fix. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 6 +++--- assignment-client/src/metavoxels/MetavoxelServer.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 3cf01bdc9f..81e86dbf11 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -237,8 +237,7 @@ void MetavoxelSession::update() { // go back to the beginning with the current packet and note that there's a delta pending _sequencer.getOutputStream().getUnderlying().device()->seek(start); - MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(), - _sequencer.getIncomingPacketNumber() }; + MetavoxelDeltaPendingMessage msg = { ++_reliableDeltaID, sendRecord->getPacketNumber(), _lodPacketNumber }; out << (_reliableDeltaMessage = QVariant::fromValue(msg)); _sequencer.endPacket(); @@ -265,7 +264,8 @@ void MetavoxelSession::handleMessage(const QVariant& message) { if (userType == ClientStateMessage::Type) { ClientStateMessage state = message.value(); _lod = state.lod; - + _lodPacketNumber = _sequencer.getIncomingPacketNumber(); + } else if (userType == MetavoxelEditMessage::Type) { QMetaObject::invokeMethod(_sender->getServer(), "applyEdit", Q_ARG(const MetavoxelEditMessage&, message.value())); diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index 840041e0f0..a4facb5426 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -127,6 +127,7 @@ private: MetavoxelSender* _sender; MetavoxelLOD _lod; + int _lodPacketNumber; ReliableChannel* _reliableDeltaChannel; int _reliableDeltaReceivedOffset; From 14555c4534a2b96607c9ccdc7e40f011180bdc2f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 14:54:04 -0700 Subject: [PATCH 31/42] Add UndoStackScriptingInterface and support when editing entities --- examples/libraries/entitySelectionTool.js | 59 +++++++++++++++++-- examples/newEditEntities.js | 2 +- interface/src/Application.cpp | 4 ++ interface/src/Application.h | 4 ++ .../src/UndoStackScriptingInterface.cpp | 46 +++++++++++++++ .../src/UndoStackScriptingInterface.h | 47 +++++++++++++++ 6 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 libraries/script-engine/src/UndoStackScriptingInterface.cpp create mode 100644 libraries/script-engine/src/UndoStackScriptingInterface.h diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index f4f068742f..f1a94dbdd7 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -845,7 +845,7 @@ SelectionDisplay = (function () { Overlays.editOverlay(grabberMoveUp, { visible: translateHandlesVisible, position: { x: boundsCenter.x, y: top + grabberMoveUpOffset, z: boundsCenter.z } }); - that.updateHandles(entityID); + that.updateHandles(); Overlays.editOverlay(baseOfEntityProjectionOverlay, @@ -926,18 +926,17 @@ SelectionDisplay = (function () { entitySelected = false; }; - that.updateHandles = function(entityID) { + that.updateHandles = function() { + // print("Updating handles"); if (SelectionManager.selections.length == 0) { that.setOverlaysVisible(false); return; } - var properties = Entities.getEntityProperties(entityID); - var rotation, dimensions, position; if (spaceMode == SPACE_LOCAL) { - rotation = properties.rotation; + rotation = SelectionManager.localRotation; dimensions = SelectionManager.localDimensions; position = SelectionManager.localPosition; } else { @@ -1097,6 +1096,44 @@ SelectionDisplay = (function () { entitySelected = false; }; + function applyEntityProperties(data) { + for (var i = 0; i < data.length; i++) { + var entityID = data[i].entityID; + var properties = data[i].properties; + Entities.editEntity(entityID, properties); + } + selectionManager._update(); + }; + + // For currently selected entities, push a command to the UndoStack that uses the current entity properties for the + // redo command, and the saved properties for the undo command. + function pushCommandForSelections() { + var undoData = []; + var redoData = []; + for (var i = 0; i < SelectionManager.selections.length; i++) { + var entityID = SelectionManager.selections[i]; + var initialProperties = SelectionManager.savedProperties[entityID.id]; + var currentProperties = Entities.getEntityProperties(entityID); + undoData.push({ + entityID: entityID, + properties: { + position: initialProperties.position, + rotation: initialProperties.rotation, + dimensions: initialProperties.dimensions, + }, + }); + redoData.push({ + entityID: entityID, + properties: { + position: currentProperties.position, + rotation: currentProperties.rotation, + dimensions: currentProperties.dimensions, + }, + }); + } + UndoStack.pushCommand(applyEntityProperties, undoData, applyEntityProperties, redoData); + } + var lastXZPick = null; var translateXZTool = { mode: 'TRANSLATE_XZ', @@ -1116,6 +1153,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1174,6 +1213,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1336,6 +1377,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }; @@ -1498,6 +1541,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1604,6 +1649,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { @@ -1708,6 +1755,8 @@ SelectionDisplay = (function () { var initialProperties = SelectionManager.savedProperties[entityID.id]; Entities.editEntity(entityID, initialProperties); } + } else { + pushCommandForSelections(); } }, onMove: function(event) { diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index ae0d018b14..4d5abaf254 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -35,7 +35,7 @@ var entityPropertyDialogBox = EntityPropertyDialogBox; Script.include("libraries/entityCameraTool.js"); var entityCameraTool = new EntityCameraTool(); -selectionManager.setEventListener(selectionDisplay.updateHandles()); +selectionManager.setEventListener(selectionDisplay.updateHandles); var windowDimensions = Controller.getViewportDimensions(); var toolIconUrl = HIFI_PUBLIC_BUCKET + "images/tools/"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 145222cd3c..6cd9d00364 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,6 +172,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _nodeBoundsDisplay(this), _previousScriptLocation(), _applicationOverlay(), + _undoStack(), + _undoStackScriptingInterface(&_undoStack), _runningScriptsWidget(NULL), _runningScriptsWidgetWasVisible(false), _trayIcon(new QSystemTrayIcon(_window)), @@ -3810,6 +3812,8 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser scriptEngine->registerGlobalObject("Joysticks", &JoystickScriptingInterface::getInstance()); qScriptRegisterMetaType(scriptEngine, joystickToScriptValue, joystickFromScriptValue); + scriptEngine->registerGlobalObject("UndoStack", &_undoStackScriptingInterface); + #ifdef HAVE_RTMIDI scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); #endif diff --git a/interface/src/Application.h b/interface/src/Application.h index 64c7032403..4779f9c810 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -91,6 +91,9 @@ #include "voxels/VoxelSystem.h" +#include "UndoStackScriptingInterface.h" + + class QAction; class QActionGroup; class QGLWidget; @@ -450,6 +453,7 @@ private: int _numChangedSettings; QUndoStack _undoStack; + UndoStackScriptingInterface _undoStackScriptingInterface; glm::vec3 _gravity; diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp new file mode 100644 index 0000000000..42efe99c92 --- /dev/null +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -0,0 +1,46 @@ +// +// UndoStackScriptingInterface.cpp +// libraries/script-engine/src +// +// Created by Ryan Huffman on 10/22/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +#include "UndoStackScriptingInterface.h" + +UndoStackScriptingInterface::UndoStackScriptingInterface(QUndoStack* undoStack) : _undoStack(undoStack) { +} + +void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScriptValue undoData, + QScriptValue redoFunction, QScriptValue redoData) { + ScriptUndoCommand* undoCommand = new ScriptUndoCommand(undoFunction, undoData, redoFunction, redoData); + qDebug() << "Pushing command"; + _undoStack->push(undoCommand); +} + +ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, + QScriptValue redoFunction, QScriptValue redoData) : + _undoFunction(undoFunction), + _undoData(undoData), + _redoFunction(redoFunction), + _redoData(redoData) { +} + +void ScriptUndoCommand::undo() { + QScriptValueList args; + args << _undoData; + _undoFunction.call(QScriptValue(), args); +} + +void ScriptUndoCommand::redo() { + QScriptValueList args; + args << _redoData; + _redoFunction.call(QScriptValue(), args); +} diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.h b/libraries/script-engine/src/UndoStackScriptingInterface.h new file mode 100644 index 0000000000..9ab822ff80 --- /dev/null +++ b/libraries/script-engine/src/UndoStackScriptingInterface.h @@ -0,0 +1,47 @@ +// +// UndoStackScriptingInterface.h +// libraries/script-engine/src +// +// Created by Ryan Huffman on 10/22/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_UndoStackScriptingInterface_h +#define hifi_UndoStackScriptingInterface_h + +#include +#include +#include + +class UndoStackScriptingInterface : public QObject { + Q_OBJECT +public: + UndoStackScriptingInterface(QUndoStack* undoStack); + +public slots: + void pushCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData); + +private: + QUndoStack* _undoStack; +}; + +class ScriptUndoCommand : public QUndoCommand { +public: + ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData); + + virtual void undo(); + virtual void redo(); + virtual bool mergeWith(const QUndoCommand* command) { return false; } + virtual int id() const { return -1; } + +private: + QScriptValue _undoFunction; + QScriptValue _undoData; + QScriptValue _redoFunction; + QScriptValue _redoData; +}; + +#endif // hifi_UndoStackScriptingInterface_h From 70f72f94042a4a655046896cfdfe7ccc974dfbf6 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 22 Oct 2014 15:09:43 -0700 Subject: [PATCH 32/42] can warp at any yaw angle --- examples/headMove.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 236130e23d..831e77a723 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -64,7 +64,6 @@ function activateWarp() { var TRIGGER_PULLBACK_DISTANCE = 0.04; var WATCH_AVATAR_DISTANCE = 1.5; -var MAX_WARP_YAW = 40.0; var MAX_PULLBACK_YAW = 5.0; var sound = new Sound("http://public.highfidelity.io/sounds/Footsteps/FootstepW2Right-12db.wav"); @@ -72,7 +71,7 @@ function playSound() { var options = new AudioInjectionOptions(); var position = MyAvatar.position; options.position = position; - options.volume = 0.5; + options.volume = 1.0; Audio.playSound(sound, options); } @@ -89,7 +88,7 @@ function updateWarp() { var deltaPitch = MyAvatar.getHeadFinalPitch() - headStartFinalPitch; deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw; - willMove = (!watchAvatar && (Math.abs(deltaYaw) < MAX_WARP_YAW) && (keyDownTime > WARP_START_TIME)); + willMove = (!watchAvatar && (keyDownTime > WARP_START_TIME)); if (willMove) { //var distance = Math.pow((deltaPitch - WARP_PITCH_DEAD_ZONE) * WARP_SENSITIVITY, 2.0); From ac8d947cb1d38db06b92b00cfc29517b75381c23 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Oct 2014 15:18:49 -0700 Subject: [PATCH 33/42] Update ScriptUndoCommand to run on ScriptEngine thread --- .../src/UndoStackScriptingInterface.cpp | 20 +++++++++++++++---- .../src/UndoStackScriptingInterface.h | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.cpp b/libraries/script-engine/src/UndoStackScriptingInterface.cpp index 42efe99c92..ed0f4d563d 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.cpp +++ b/libraries/script-engine/src/UndoStackScriptingInterface.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -20,9 +21,11 @@ UndoStackScriptingInterface::UndoStackScriptingInterface(QUndoStack* undoStack) void UndoStackScriptingInterface::pushCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData) { - ScriptUndoCommand* undoCommand = new ScriptUndoCommand(undoFunction, undoData, redoFunction, redoData); - qDebug() << "Pushing command"; - _undoStack->push(undoCommand); + if (undoFunction.engine()) { + ScriptUndoCommand* undoCommand = new ScriptUndoCommand(undoFunction, undoData, redoFunction, redoData); + undoCommand->moveToThread(undoFunction.engine()->thread()); + _undoStack->push(undoCommand); + } } ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, @@ -34,12 +37,21 @@ ScriptUndoCommand::ScriptUndoCommand(QScriptValue undoFunction, QScriptValue und } void ScriptUndoCommand::undo() { + QMetaObject::invokeMethod(this, "doUndo"); +} + +void ScriptUndoCommand::redo() { + QMetaObject::invokeMethod(this, "doRedo"); +} + +void ScriptUndoCommand::doUndo() { QScriptValueList args; args << _undoData; _undoFunction.call(QScriptValue(), args); } -void ScriptUndoCommand::redo() { + +void ScriptUndoCommand::doRedo() { QScriptValueList args; args << _redoData; _redoFunction.call(QScriptValue(), args); diff --git a/libraries/script-engine/src/UndoStackScriptingInterface.h b/libraries/script-engine/src/UndoStackScriptingInterface.h index 9ab822ff80..835e5dfff4 100644 --- a/libraries/script-engine/src/UndoStackScriptingInterface.h +++ b/libraries/script-engine/src/UndoStackScriptingInterface.h @@ -28,7 +28,8 @@ private: QUndoStack* _undoStack; }; -class ScriptUndoCommand : public QUndoCommand { +class ScriptUndoCommand : public QObject, public QUndoCommand { + Q_OBJECT public: ScriptUndoCommand(QScriptValue undoFunction, QScriptValue undoData, QScriptValue redoFunction, QScriptValue redoData); @@ -37,6 +38,10 @@ public: virtual bool mergeWith(const QUndoCommand* command) { return false; } virtual int id() const { return -1; } +public slots: + void doUndo(); + void doRedo(); + private: QScriptValue _undoFunction; QScriptValue _undoData; From a48811777e0db7297df1e6e17e29a31cede93f13 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 15:26:16 -0700 Subject: [PATCH 34/42] Script engine audio dependency --- libraries/script-engine/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 7073280ee5..166ee8c50e 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library(Gui Network Script Widgets) include_glm() -link_hifi_libraries(shared octree voxels fbx entities animation) +link_hifi_libraries(shared octree voxels fbx entities animation audio) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() From 7b0f1477a1a3d5b29f1eeab56f43612175a65baf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Oct 2014 15:28:04 -0700 Subject: [PATCH 35/42] expose AvatarList to Interface SE, add avatarWithDisplayName method --- interface/src/Application.cpp | 3 ++- libraries/avatars/src/AvatarData.h | 2 ++ libraries/avatars/src/AvatarHashMap.cpp | 10 +++++++--- libraries/avatars/src/AvatarHashMap.h | 2 ++ libraries/script-engine/src/ScriptEngine.cpp | 12 ++++++++++-- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 145222cd3c..99c23f526b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3766,8 +3766,9 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser // AvatarManager has some custom types AvatarManager::registerMetaTypes(scriptEngine); - // hook our avatar object into this script engine + // hook our avatar and avatar hash map object into this script engine scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features + scriptEngine->setAvatarHashMap(&_avatarManager, "AvatarList"); CameraScriptableObject* cameraScriptable = new CameraScriptableObject(&_myCamera, &_viewFrustum); scriptEngine->registerGlobalObject("Camera", cameraScriptable); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fd4052974..29682da286 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -381,6 +381,8 @@ private: AvatarData& operator= (const AvatarData&); }; +Q_DECLARE_METATYPE(AvatarData*) + class JointData { public: bool valid; diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index f996fc2bad..b74205c6b6 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -21,6 +21,7 @@ AvatarHashMap::AvatarHashMap() : connect(NodeList::getInstance(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged); } + AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) { qDebug() << "Removing Avatar with UUID" << iterator.key() << "from AvatarHashMap."; return _avatarHash.erase(iterator); @@ -53,7 +54,10 @@ void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const } bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { - + return avatarWithDisplayName(displayName) == NULL ? false : true; +} + +AvatarData* AvatarHashMap::avatarWithDisplayName(const QString& displayName) { AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { AvatarSharedPointer sharedAvatar = avatarIterator.value(); @@ -62,7 +66,7 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { // check if this avatar should still be around if (!shouldKillAvatar(sharedAvatar)) { // we have a match, return true - return true; + return sharedAvatar.data(); } else { // we should remove this avatar, do that now erase(avatarIterator); @@ -75,7 +79,7 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { } // return false, no match - return false; + return NULL; } AvatarSharedPointer AvatarHashMap::newSharedAvatar() { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index d52c656bc1..03b0bf887c 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -21,6 +21,7 @@ #include "AvatarData.h" typedef QSharedPointer AvatarSharedPointer; +typedef QWeakPointer AvatarWeakPointer; typedef QHash AvatarHash; class AvatarHashMap : public QObject { @@ -34,6 +35,7 @@ public: public slots: void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer& mixerWeakPointer); bool containsAvatarWithDisplayName(const QString& displayName); + AvatarData* avatarWithDisplayName(const QString& displayname); private slots: void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index eb5dd07ffb..93da900055 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -63,7 +63,15 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ return QScriptValue(); } -QScriptValue injectorToScriptValue(QScriptEngine *engine, AudioInjector* const &in) { +QScriptValue avatarDataToScriptValue(QScriptEngine* engine, AvatarData* const &in) { + return engine->newQObject(in); +} + +void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { + out = qobject_cast(object.toQObject()); +} + +QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const &in) { return engine->newQObject(in); } @@ -272,7 +280,7 @@ void ScriptEngine::init() { qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue); - + qScriptRegisterMetaType(this, avatarDataToScriptValue, avatarDataFromScriptValue); qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue); registerGlobalObject("Script", this); From 8ccbfcf69581182faf1f2888610916a38cc89386 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 16:41:41 -0700 Subject: [PATCH 36/42] code cleanup --- assignment-client/src/audio/AudioMixer.cpp | 5 ++--- interface/src/Audio.cpp | 8 ++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9b91dd8c1e..fbd414f6c1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -732,7 +732,8 @@ void AudioMixer::run() { // Pack stream properties for (int i = 0; i < _zoneReverbSettings.size(); ++i) { - glm::vec3 streamPosition = static_cast(node->getLinkedData())->getAvatarAudioStream()->getPosition(); + AudioMixerClientData* data = static_cast(node->getLinkedData()); + glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { bool hasReverb = true; float reverbTime = _zoneReverbSettings[i].reverbTime; @@ -751,7 +752,6 @@ void AudioMixer::run() { } } - // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; @@ -1076,7 +1076,6 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { - ReverbSettings settings; settings.zone = zone; settings.reverbTime = reverbTime; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 527703f7a4..dd84eb3211 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -544,15 +544,11 @@ void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioF for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { if (j == sample) { // left channel - int lResult = (int)(samplesData[j] * dryFraction + lValue * wetFraction); - if (lResult > 32767) lResult = 32767; - if (lResult < -32768) lResult = -32768; + int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -32768, 32767); samplesData[j] = (int16_t)lResult; } else if (j == (sample + 1)) { // right channel - int rResult = (int)(samplesData[j] * dryFraction + rValue * wetFraction); - if (rResult > 32767) rResult = 32767; - if (rResult < -32768) rResult = -32768; + int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -32768, 32767); samplesData[j] = (int16_t)rResult; } else { // ignore channels above 2 From 38d50a76ebae9dc7a15aecdb1632ab62491eb92c Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Oct 2014 16:47:40 -0700 Subject: [PATCH 37/42] Add IsFacingAvatar getter and setter to Text3DOverlay --- interface/src/ui/overlays/Text3DOverlay.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index 855890e493..c49116ee0c 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -32,6 +32,7 @@ public: float getTopMargin() const { return _topMargin; } float getRightMargin() const { return _rightMargin; } float getBottomMargin() const { return _bottomMargin; } + bool getIsFacingAvatar() const { return _isFacingAvatar; } xColor getBackgroundColor(); // setters @@ -41,6 +42,7 @@ public: void setTopMargin(float margin) { _topMargin = margin; } void setRightMargin(float margin) { _rightMargin = margin; } void setBottomMargin(float margin) { _bottomMargin = margin; } + void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; } virtual void setProperties(const QScriptValue& properties); From 93a0eb18bd4c1db02c5af2ab652cd737b12cdab1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 22 Oct 2014 16:50:02 -0700 Subject: [PATCH 38/42] Added readme --- interface/external/gverb/readme.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 interface/external/gverb/readme.txt diff --git a/interface/external/gverb/readme.txt b/interface/external/gverb/readme.txt new file mode 100644 index 0000000000..aa2fe8a602 --- /dev/null +++ b/interface/external/gverb/readme.txt @@ -0,0 +1,15 @@ + +Instructions for adding the Gverb library to Interface +(This is a required library) +Clément Brisset, Octobre 22nd, 2014 + +1. Go to https://github.com/highfidelity/gverb + Or download the sources directly via this link: + https://github.com/highfidelity/gverb/archive/master.zip + +2. Extract the archive + +3. Place the directories “include” and “src” in interface/external/gverb + (Normally next to this readme) + +4. Clear your build directory, run cmake, build and you should be all set. \ No newline at end of file From 0e3495986de948e588f98792683ea72349448e04 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Oct 2014 16:58:10 -0700 Subject: [PATCH 39/42] Add countdown to HMD calibration billboard --- interface/src/devices/OculusManager.cpp | 19 +++++++++++-------- interface/src/devices/OculusManager.h | 6 ++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 62894510c2..709080e354 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -66,8 +66,6 @@ glm::vec3 OculusManager::_calibrationPosition; glm::quat OculusManager::_calibrationOrientation; quint64 OculusManager::_calibrationStartTime; int OculusManager::_calibrationMessage = NULL; -QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://hifi-public.s3.amazonaws.com/images/hold-to-calibrate.svg"; -float OculusManager::CALIBRATION_BILLBOARD_SCALE = 2.f; #endif @@ -191,7 +189,7 @@ void OculusManager::disconnect() { } #ifdef HAVE_LIBOVR -void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { +void OculusManager::positionCalibrationBillboard(Text3DOverlay* billboard) { glm::quat headOrientation = Application::getInstance()->getAvatar()->getHeadOrientation(); headOrientation.x = 0; headOrientation.z = 0; @@ -204,8 +202,9 @@ void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) { #ifdef HAVE_LIBOVR void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { + static QString instructionMessage = "Hold still to calibrate"; static QString progressMessage; - static BillboardOverlay* billboard; + static Text3DOverlay* billboard; switch (_calibrationState) { @@ -235,9 +234,13 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { if (!_calibrationMessage) { qDebug() << "Hold still to calibrate HMD"; - billboard = new BillboardOverlay(); - billboard->setURL(CALIBRATION_BILLBOARD_URL); - billboard->setScale(CALIBRATION_BILLBOARD_SCALE); + billboard = new Text3DOverlay(); + billboard->setDimensions(glm::vec2(2.0f, 1.25f)); + billboard->setTopMargin(0.35f); + billboard->setLeftMargin(0.28f); + billboard->setText(instructionMessage); + billboard->setAlpha(0.5f); + billboard->setLineHeight(0.1f); billboard->setIsFacingAvatar(false); positionCalibrationBillboard(billboard); @@ -275,7 +278,7 @@ void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) { } else { progressMessage += "."; } - //qDebug() << progressMessage; // Progress message ready for 3D text overlays. + billboard->setText(instructionMessage + "\n\n" + progressMessage); } } } else { diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index dfe4a212b6..20e43d572c 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -18,7 +18,7 @@ #endif #include "renderer/ProgramObject.h" -#include "ui/overlays/BillboardOverlay.h" +#include "ui/overlays/Text3DOverlay.h" const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f; @@ -111,7 +111,7 @@ private: WAITING_FOR_ZERO_HELD, CALIBRATED }; - static void positionCalibrationBillboard(BillboardOverlay* billboard); + static void positionCalibrationBillboard(Text3DOverlay* message); static float CALIBRATION_DELTA_MINIMUM_LENGTH; static float CALIBRATION_DELTA_MINIMUM_ANGLE; static float CALIBRATION_ZERO_MAXIMUM_LENGTH; @@ -123,8 +123,6 @@ private: static glm::quat _calibrationOrientation; static quint64 _calibrationStartTime; static int _calibrationMessage; - static QString CALIBRATION_BILLBOARD_URL; - static float CALIBRATION_BILLBOARD_SCALE; #endif From 8e67c5f53485b016d66dc5d47f7f06d69cc26267 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Oct 2014 17:35:28 -0700 Subject: [PATCH 40/42] don't erase from the AvatarHashMap on the wrong thread --- libraries/avatars/src/AvatarHashMap.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index b74205c6b6..4f69eb2e3d 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -58,27 +58,21 @@ bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) { } AvatarData* AvatarHashMap::avatarWithDisplayName(const QString& displayName) { - AvatarHash::iterator avatarIterator = _avatarHash.begin(); - while (avatarIterator != _avatarHash.end()) { - AvatarSharedPointer sharedAvatar = avatarIterator.value(); - if (avatarIterator.value()->getDisplayName() == displayName) { + foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) { + if (sharedAvatar->getDisplayName() == displayName) { // this is a match // check if this avatar should still be around if (!shouldKillAvatar(sharedAvatar)) { - // we have a match, return true + // we have a match, return the AvatarData return sharedAvatar.data(); } else { - // we should remove this avatar, do that now - erase(avatarIterator); + // we should remove this avatar, but we might not be on a thread that is allowed + // so we just return NULL to the caller + return NULL; } - - break; - } else { - ++avatarIterator; } } - - // return false, no match + return NULL; } From 271c01ad030dd4c2b24953320297c2f8d0d7aa40 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 17:44:56 -0700 Subject: [PATCH 41/42] Fix for digging into converted heightfields. --- libraries/metavoxels/src/MetavoxelMessages.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 299ffbbb80..d9c60f3f12 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -701,8 +701,7 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) { int sizeY = (int)overlap.maximum.y - minY + 1; int sizeZ = (int)overlap.maximum.z - minZ + 1; - QRgb rgb = _color.rgba(); - bool flipped = (qAlpha(rgb) == 0); + bool flipped = false; float step = 1.0f / scale; glm::vec3 position(0.0f, 0.0f, info.minimum.z + minZ * step); if (_spanner->hasOwnColors()) { @@ -720,6 +719,8 @@ int VoxelMaterialSpannerEditVisitor::visit(MetavoxelInfo& info) { } } } else { + QRgb rgb = _color.rgba(); + flipped = (qAlpha(rgb) == 0); for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX, *endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA, position.z += step) { position.y = info.minimum.y + minY * step; From b1b7114e66f437ee23fbd20d62164b94ca2d4348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Wed, 22 Oct 2014 22:46:37 -0700 Subject: [PATCH 42/42] Revert "Reverb" --- assignment-client/src/audio/AudioMixer.cpp | 58 +--------- assignment-client/src/audio/AudioMixer.h | 8 +- cmake/modules/FindGverb.cmake | 39 ------- .../resources/describe-settings.json | 27 ----- examples/audioReverbOn.js | 39 ------- interface/CMakeLists.txt | 13 +-- interface/external/gverb/readme.txt | 15 --- interface/src/Audio.cpp | 102 +---------------- interface/src/Audio.h | 19 ---- .../AudioDeviceScriptingInterface.cpp | 8 -- .../scripting/AudioDeviceScriptingInterface.h | 2 - libraries/audio/src/AudioEffectOptions.cpp | 88 --------------- libraries/audio/src/AudioEffectOptions.h | 106 ------------------ libraries/audio/src/InboundAudioStream.cpp | 20 +--- libraries/audio/src/InboundAudioStream.h | 9 -- libraries/script-engine/CMakeLists.txt | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 4 - 17 files changed, 13 insertions(+), 546 deletions(-) delete mode 100644 cmake/modules/FindGverb.cmake delete mode 100644 examples/audioReverbOn.js delete mode 100644 interface/external/gverb/readme.txt delete mode 100644 libraries/audio/src/AudioEffectOptions.cpp delete mode 100644 libraries/audio/src/AudioEffectOptions.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index fbd414f6c1..8caf4ddf09 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -428,8 +428,8 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l } int AudioMixer::prepareMixForListeningNode(Node* node) { - AvatarAudioStream* nodeAudioStream = static_cast(node->getLinkedData())->getAvatarAudioStream(); - AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); + AvatarAudioStream* nodeAudioStream = ((AudioMixerClientData*) node->getLinkedData())->getAvatarAudioStream(); + AudioMixerClientData* listenerNodeData = (AudioMixerClientData*)node->getLinkedData(); // zero out the client mix for this node memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -730,28 +730,6 @@ void AudioMixer::run() { memcpy(dataAt, &sequence, sizeof(quint16)); dataAt += sizeof(quint16); - // Pack stream properties - for (int i = 0; i < _zoneReverbSettings.size(); ++i) { - AudioMixerClientData* data = static_cast(node->getLinkedData()); - glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); - if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { - bool hasReverb = true; - float reverbTime = _zoneReverbSettings[i].reverbTime; - float wetLevel = _zoneReverbSettings[i].wetLevel; - - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); - memcpy(dataAt, &reverbTime, sizeof(float)); - dataAt += sizeof(float); - memcpy(dataAt, &wetLevel, sizeof(float)); - dataAt += sizeof(float); - } else { - bool hasReverb = false; - memcpy(dataAt, &hasReverb, sizeof(bool)); - dataAt += sizeof(bool); - } - } - // pack mixed audio samples memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; @@ -1055,38 +1033,6 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } - - const QString REVERB = "reverb"; - if (audioEnvGroupObject[REVERB].isArray()) { - const QJsonArray& reverb = audioEnvGroupObject[REVERB].toArray(); - - const QString ZONE = "zone"; - const QString REVERB_TIME = "reverb_time"; - const QString WET_LEVEL = "wet_level"; - for (int i = 0; i < reverb.count(); ++i) { - QJsonObject reverbObject = reverb[i].toObject(); - - if (reverbObject.contains(ZONE) && - reverbObject.contains(REVERB_TIME) && - reverbObject.contains(WET_LEVEL)) { - - bool okReverbTime, okWetLevel; - QString zone = reverbObject.value(ZONE).toString(); - float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime); - float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); - - if (okReverbTime && okWetLevel && _audioZones.contains(zone)) { - ReverbSettings settings; - settings.zone = zone; - settings.reverbTime = reverbTime; - settings.wetLevel = wetLevel; - - _zoneReverbSettings.push_back(settings); - qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; - } - } - } - } } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index ff976dec61..3cfa5443a8 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -82,13 +82,7 @@ private: float coefficient; }; QVector _zonesSettings; - struct ReverbSettings { - QString zone; - float reverbTime; - float wetLevel; - }; - QVector _zoneReverbSettings; - + static InboundAudioStream::Settings _streamSettings; static bool _printStreamStats; diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake deleted file mode 100644 index 549c23c8a9..0000000000 --- a/cmake/modules/FindGverb.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# FindGVerb.cmake -# -# Try to find the Gverb library. -# -# You must provide a GVERB_ROOT_DIR which contains src and include directories -# -# Once done this will define -# -# GVERB_FOUND - system found Gverb -# GVERB_INCLUDE_DIRS - the Gverb include directory -# -# Copyright 2014 High Fidelity, Inc. -# -# Distributed under the Apache License, Version 2.0. -# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# - -if (GVERB_INCLUDE_DIRS) - # in cache already - set(GVERB_FOUND TRUE) -else (GVERB_INCLUDE_DIRS) - - include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") - hifi_library_search_hints("gverb") - - find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) - find_path(GVERB_SRC_DIRS gverb.c PATH_SUFFIXES src HINTS ${GVERB_SEARCH_DIRS}) - - if (GVERB_INCLUDE_DIRS) - set(GVERB_FOUND TRUE) - endif (GVERB_INCLUDE_DIRS) - - if (GVERB_FOUND) - message(STATUS "Found Gverb: ${GVERB_INCLUDE_DIRS}") - else (GVERB_FOUND) - message(FATAL_ERROR "Could NOT find Gverb. Read ./interface/externals/gverb/readme.txt") - endif (GVERB_FOUND) - -endif(GVERB_INCLUDE_DIRS) \ No newline at end of file diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 026fe252b2..2c33897d07 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -154,33 +154,6 @@ "placeholder": "0.18" } ] - }, - { - "name": "reverb", - "type": "table", - "label": "Reverb Settings", - "help": "In this table you can set custom reverb values for each audio zones", - "numbered": true, - "columns": [ - { - "name": "zone", - "label": "Zone", - "can_set": true, - "placeholder": "Audio_Zone" - }, - { - "name": "reverb_time", - "label": "Reverb Decay Time", - "can_set": true, - "placeholder": "(in sec)" - }, - { - "name": "wet_level", - "label": "Wet Level", - "can_set": true, - "placeholder": "(in db)" - } - ] } ] }, diff --git a/examples/audioReverbOn.js b/examples/audioReverbOn.js deleted file mode 100644 index 479f5bba74..0000000000 --- a/examples/audioReverbOn.js +++ /dev/null @@ -1,39 +0,0 @@ -// -// audioReverbOn.js -// examples -// -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings -var audioOptions = new AudioEffectOptions({ - // Square Meters - maxRoomSize: 50, - roomSize: 50, - - // Seconds - reverbTime: 4, - - // Between 0 - 1 - damping: 0.50, - inputBandwidth: 0.75, - - // dB - earlyLevel: -22, - tailLevel: -28, - dryLevel: 0, - wetLevel: 6 -}); - -AudioDevice.setReverbOptions(audioOptions); -AudioDevice.setReverb(true); -print("Reverb is now on with the updated options."); - -function scriptEnding() { - AudioDevice.setReverb(false); - print("Reberb is now off."); -} - -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index a150a308e0..db5aa64210 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2" "Gverb") +set(OPTIONAL_EXTERNALS "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp" "SDL2") foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) @@ -14,10 +14,6 @@ endforeach() find_package(Qt5LinguistTools REQUIRED) find_package(Qt5LinguistToolsMacros) - -# As Gverb is currently the only reverb library, it's required. -find_package(Gverb REQUIRED) - if (DEFINED ENV{JOB_ID}) set(BUILD_SEQ $ENV{JOB_ID}) else () @@ -170,13 +166,6 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP AND WIN32) add_definitions(-DQXMPP_STATIC) endif () -if (GVERB_FOUND) - file(GLOB GVERB_SRCS ${GVERB_SRC_DIRS}/*.c) - include_directories(${GVERB_INCLUDE_DIRS}) - add_library(gverb STATIC ${GVERB_SRCS}) - target_link_libraries(${TARGET_NAME} gverb) -endif (GVERB_FOUND) - # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") diff --git a/interface/external/gverb/readme.txt b/interface/external/gverb/readme.txt deleted file mode 100644 index aa2fe8a602..0000000000 --- a/interface/external/gverb/readme.txt +++ /dev/null @@ -1,15 +0,0 @@ - -Instructions for adding the Gverb library to Interface -(This is a required library) -Clément Brisset, Octobre 22nd, 2014 - -1. Go to https://github.com/highfidelity/gverb - Or download the sources directly via this link: - https://github.com/highfidelity/gverb/archive/master.zip - -2. Extract the archive - -3. Place the directories “include” and “src” in interface/external/gverb - (Normally next to this readme) - -4. Clear your build directory, run cmake, build and you should be all set. \ No newline at end of file diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index dd84eb3211..365064e979 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,8 +92,6 @@ Audio::Audio(QObject* parent) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _muted(false), - _reverb(false), - _reverbOptions(&_scriptReverbOptions), _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), @@ -125,14 +123,11 @@ Audio::Audio(QObject* parent) : memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); // Create the noise sample array _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; - + connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedSilence, this, &Audio::addStereoSilenceToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedLastFrameRepeatedWithFade, this, &Audio::addLastFrameRepeatedWithFadeToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::addedStereoSamples, this, &Audio::addStereoSamplesToScope, Qt::DirectConnection); connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &Audio::processReceivedSamples, Qt::DirectConnection); - - // Initialize GVerb - initGverb(); } void Audio::init(QGLWidget *parent) { @@ -494,69 +489,6 @@ bool Audio::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } -void Audio::initGverb() { - // Initialize a new gverb instance - _gverb = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), - _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), - _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), - _reverbOptions->getTailLevel()); - - // Configure the instance (these functions are not super well named - they actually set several internal variables) - gverb_set_roomsize(_gverb, _reverbOptions->getRoomSize()); - gverb_set_revtime(_gverb, _reverbOptions->getReverbTime()); - gverb_set_damping(_gverb, _reverbOptions->getDamping()); - gverb_set_inputbandwidth(_gverb, _reverbOptions->getInputBandwidth()); - gverb_set_earlylevel(_gverb, DB_CO(_reverbOptions->getEarlyLevel())); - gverb_set_taillevel(_gverb, DB_CO(_reverbOptions->getTailLevel())); -} - -void Audio::setReverbOptions(const AudioEffectOptions* options) { - // Save the new options - _scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize()); - _scriptReverbOptions.setRoomSize(options->getRoomSize()); - _scriptReverbOptions.setReverbTime(options->getReverbTime()); - _scriptReverbOptions.setDamping(options->getDamping()); - _scriptReverbOptions.setSpread(options->getSpread()); - _scriptReverbOptions.setInputBandwidth(options->getInputBandwidth()); - _scriptReverbOptions.setEarlyLevel(options->getEarlyLevel()); - _scriptReverbOptions.setTailLevel(options->getTailLevel()); - - _scriptReverbOptions.setDryLevel(options->getDryLevel()); - _scriptReverbOptions.setWetLevel(options->getWetLevel()); - - if (_reverbOptions == &_scriptReverbOptions) { - // Apply them to the reverb instance(s) - initGverb(); - } -} - -void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioFormat) { - float dryFraction = DB_CO(_reverbOptions->getDryLevel()); - float wetFraction = DB_CO(_reverbOptions->getWetLevel()); - - float lValue,rValue; - for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { - // Run GVerb - float value = (float)samplesData[sample]; - gverb_do(_gverb, value, &lValue, &rValue); - - // Mix, accounting for clipping, the left and right channels. Ignore the rest. - for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { - if (j == sample) { - // left channel - int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -32768, 32767); - samplesData[j] = (int16_t)lResult; - } else if (j == (sample + 1)) { - // right channel - int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -32768, 32767); - samplesData[j] = (int16_t)rResult; - } else { - // ignore channels above 2 - } - } - } -} - void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; @@ -788,6 +720,7 @@ void Audio::handleAudioInput() { NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); + if (_recorder && _recorder.data()->isRecording()) { _recorder.data()->record(reinterpret_cast(networkAudioSamples), numNetworkBytes); } @@ -907,10 +840,12 @@ void Audio::addLastFrameRepeatedWithFadeToScope(int samplesPerChannel) { } void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer) { + const int numNetworkOutputSamples = inputBuffer.size() / sizeof(int16_t); const int numDeviceOutputSamples = numNetworkOutputSamples * (_outputFormat.sampleRate() * _outputFormat.channelCount()) / (_desiredOutputFormat.sampleRate() * _desiredOutputFormat.channelCount()); + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples; @@ -949,37 +884,10 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); - - if(_reverb || _receivedAudioStream.hasReverb()) { - bool reverbChanged = false; - if (_receivedAudioStream.hasReverb()) { - - if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { - _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); - reverbChanged = true; - } - if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { - _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - reverbChanged = true; - } - - if (_reverbOptions != &_zoneReverbOptions) { - _reverbOptions = &_zoneReverbOptions; - reverbChanged = true; - } - } else if (_reverbOptions != &_scriptReverbOptions) { - _reverbOptions = &_scriptReverbOptions; - reverbChanged = true; - } - - if (reverbChanged) { - initGverb(); - } - addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); - } } void Audio::addReceivedAudioToStream(const QByteArray& audioByteArray) { + if (_audioOutput) { // Audio output must exist and be correctly set up if we're going to process received audio _receivedAudioStream.parseData(audioByteArray); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 900b6ce0d6..e397f9564b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -43,14 +43,6 @@ #include #include "MixedProcessedAudioStream.h" -#include "AudioEffectOptions.h" -#include -#include - -extern "C" { - #include - #include -} static const int NUM_AUDIO_CHANNELS = 2; @@ -167,8 +159,6 @@ public slots: float getInputVolume() const { return (_audioInput) ? _audioInput->volume() : 0.0f; } void setInputVolume(float volume) { if (_audioInput) _audioInput->setVolume(volume); } - void setReverb(bool reverb) { _reverb = reverb; } - void setReverbOptions(const AudioEffectOptions* options); const AudioStreamStats& getAudioMixerAvatarStreamAudioStats() const { return _audioMixerAvatarStreamAudioStats; } const QHash& getAudioMixerInjectedStreamAudioStatsMap() const { return _audioMixerInjectedStreamAudioStatsMap; } @@ -240,11 +230,6 @@ private: int _proceduralEffectSample; bool _muted; bool _localEcho; - bool _reverb; - AudioEffectOptions _scriptReverbOptions; - AudioEffectOptions _zoneReverbOptions; - AudioEffectOptions* _reverbOptions; - ty_gverb *_gverb; GLuint _micTextureId; GLuint _muteTextureId; GLuint _boxTextureId; @@ -264,10 +249,6 @@ private: // 2. Mix with the audio input void processProceduralAudio(int16_t* monoInput, int numSamples); - // Adds Reverb - void initGverb(); - void addReverb(int16_t* samples, int numSamples, QAudioFormat& format); - // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.cpp b/interface/src/scripting/AudioDeviceScriptingInterface.cpp index bcb5fc308d..688b0942d5 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.cpp +++ b/interface/src/scripting/AudioDeviceScriptingInterface.cpp @@ -70,11 +70,3 @@ float AudioDeviceScriptingInterface::getInputVolume() { void AudioDeviceScriptingInterface::setInputVolume(float volume) { Application::getInstance()->getAudio()->setInputVolume(volume); } - -void AudioDeviceScriptingInterface::setReverb(bool reverb) { - Application::getInstance()->getAudio()->setReverb(reverb); -} - -void AudioDeviceScriptingInterface::setReverbOptions(const AudioEffectOptions* options) { - Application::getInstance()->getAudio()->setReverbOptions(options); -} diff --git a/interface/src/scripting/AudioDeviceScriptingInterface.h b/interface/src/scripting/AudioDeviceScriptingInterface.h index 45bdbc92e2..62f1153a0b 100644 --- a/interface/src/scripting/AudioDeviceScriptingInterface.h +++ b/interface/src/scripting/AudioDeviceScriptingInterface.h @@ -39,8 +39,6 @@ public slots: float getInputVolume(); void setInputVolume(float volume); - void setReverb(bool reverb); - void setReverbOptions(const AudioEffectOptions* options); }; #endif // hifi_AudioDeviceScriptingInterface_h diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp deleted file mode 100644 index 480779afd2..0000000000 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// -// AudioEffectOptions.cpp -// libraries/audio/src -// -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "AudioEffectOptions.h" - -static const QString MAX_ROOM_SIZE_HANDLE = "maxRoomSize"; -static const QString ROOM_SIZE_HANDLE = "roomSize"; -static const QString REVERB_TIME_HANDLE = "reverbTime"; -static const QString DAMPIMG_HANDLE = "damping"; -static const QString SPREAD_HANDLE = "spread"; -static const QString INPUT_BANDWIDTH_HANDLE = "inputBandwidth"; -static const QString EARLY_LEVEL_HANDLE = "earlyLevel"; -static const QString TAIL_LEVEL_HANDLE = "tailLevel"; -static const QString DRY_LEVEL_HANDLE = "dryLevel"; -static const QString WET_LEVEL_HANDLE = "wetLevel"; - -AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : - _maxRoomSize(50.0f), - _roomSize(50.0f), - _reverbTime(4.0f), - _damping(0.5f), - _spread(15.0f), - _inputBandwidth(0.75f), - _earlyLevel(-22.0f), - _tailLevel(-28.0f), - _dryLevel(0.0f), - _wetLevel(6.0f) { - if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { - _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); - } - if (arguments.property(ROOM_SIZE_HANDLE).isNumber()) { - _roomSize = arguments.property(ROOM_SIZE_HANDLE).toNumber(); - } - if (arguments.property(REVERB_TIME_HANDLE).isNumber()) { - _reverbTime = arguments.property(REVERB_TIME_HANDLE).toNumber(); - } - if (arguments.property(DAMPIMG_HANDLE).isNumber()) { - _damping = arguments.property(DAMPIMG_HANDLE).toNumber(); - } - if (arguments.property(SPREAD_HANDLE).isNumber()) { - _spread = arguments.property(SPREAD_HANDLE).toNumber(); - } - if (arguments.property(INPUT_BANDWIDTH_HANDLE).isNumber()) { - _inputBandwidth = arguments.property(INPUT_BANDWIDTH_HANDLE).toNumber(); - } - if (arguments.property(EARLY_LEVEL_HANDLE).isNumber()) { - _earlyLevel = arguments.property(EARLY_LEVEL_HANDLE).toNumber(); - } - if (arguments.property(TAIL_LEVEL_HANDLE).isNumber()) { - _tailLevel = arguments.property(TAIL_LEVEL_HANDLE).toNumber(); - } - if (arguments.property(DRY_LEVEL_HANDLE).isNumber()) { - _dryLevel = arguments.property(DRY_LEVEL_HANDLE).toNumber(); - } - if (arguments.property(WET_LEVEL_HANDLE).isNumber()) { - _wetLevel = arguments.property(WET_LEVEL_HANDLE).toNumber(); - } -} - -AudioEffectOptions::AudioEffectOptions(const AudioEffectOptions &other) { - *this = other; -} - -AudioEffectOptions& AudioEffectOptions::operator=(const AudioEffectOptions &other) { - _maxRoomSize = other._maxRoomSize; - _roomSize = other._roomSize; - _reverbTime = other._reverbTime; - _damping = other._damping; - _spread = other._spread; - _inputBandwidth = other._inputBandwidth; - _earlyLevel = other._earlyLevel; - _tailLevel = other._tailLevel; - _dryLevel = other._dryLevel; - _wetLevel = other._wetLevel; - - return *this; -} - -QScriptValue AudioEffectOptions::constructor(QScriptContext* context, QScriptEngine* engine) { - return engine->newQObject(new AudioEffectOptions(context->argument(0))); -} diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h deleted file mode 100644 index 97aac7c82c..0000000000 --- a/libraries/audio/src/AudioEffectOptions.h +++ /dev/null @@ -1,106 +0,0 @@ -// -// AudioEffectOptions.h -// libraries/audio/src -// -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_AudioEffectOptions_h -#define hifi_AudioEffectOptions_h - -#include -#include -#include - -class AudioEffectOptions : public QObject { - Q_OBJECT - - // Meters Square - Q_PROPERTY(float maxRoomSize READ getMaxRoomSize WRITE setMaxRoomSize) - Q_PROPERTY(float roomSize READ getRoomSize WRITE setRoomSize) - - // Seconds - Q_PROPERTY(float reverbTime READ getReverbTime WRITE setReverbTime) - - // Ratio between 0 and 1 - Q_PROPERTY(float damping READ getDamping WRITE setDamping) - - // (?) Does not appear to be set externally very often - Q_PROPERTY(float spread READ getSpread WRITE setSpread) - - // Ratio between 0 and 1 - Q_PROPERTY(float inputBandwidth READ getInputBandwidth WRITE setInputBandwidth) - - // in dB - Q_PROPERTY(float earlyLevel READ getEarlyLevel WRITE setEarlyLevel) - Q_PROPERTY(float tailLevel READ getTailLevel WRITE setTailLevel) - Q_PROPERTY(float dryLevel READ getDryLevel WRITE setDryLevel) - Q_PROPERTY(float wetLevel READ getWetLevel WRITE setWetLevel) - -public: - AudioEffectOptions(QScriptValue arguments = QScriptValue()); - AudioEffectOptions(const AudioEffectOptions &other); - AudioEffectOptions& operator=(const AudioEffectOptions &other); - - static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); - - float getRoomSize() const { return _roomSize; } - void setRoomSize(float roomSize ) { _roomSize = roomSize; } - - float getMaxRoomSize() const { return _maxRoomSize; } - void setMaxRoomSize(float maxRoomSize ) { _maxRoomSize = maxRoomSize; } - - float getReverbTime() const { return _reverbTime; } - void setReverbTime(float reverbTime ) { _reverbTime = reverbTime; } - - float getDamping() const { return _damping; } - void setDamping(float damping ) { _damping = damping; } - - float getSpread() const { return _spread; } - void setSpread(float spread ) { _spread = spread; } - - float getInputBandwidth() const { return _inputBandwidth; } - void setInputBandwidth(float inputBandwidth ) { _inputBandwidth = inputBandwidth; } - - float getEarlyLevel() const { return _earlyLevel; } - void setEarlyLevel(float earlyLevel ) { _earlyLevel = earlyLevel; } - - float getTailLevel() const { return _tailLevel; } - void setTailLevel(float tailLevel ) { _tailLevel = tailLevel; } - - float getDryLevel() const { return _dryLevel; } - void setDryLevel(float dryLevel) { _dryLevel = dryLevel; } - - float getWetLevel() const { return _wetLevel; } - void setWetLevel(float wetLevel) { _wetLevel = wetLevel; } - -private: - // http://wiki.audacityteam.org/wiki/GVerb#Instant_Reverberb_settings - - // Meters Square - float _maxRoomSize; - float _roomSize; - - // Seconds - float _reverbTime; - - // Ratio between 0 and 1 - float _damping; - - // ? (Does not appear to be set externally very often) - float _spread; - - // Ratio between 0 and 1 - float _inputBandwidth; - - // dB - float _earlyLevel; - float _tailLevel; - float _dryLevel; - float _wetLevel; -}; - -#endif // hifi_AudioEffectOptions_h diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 59578951f8..dda57d87da 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -44,8 +44,7 @@ InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacit _framesAvailableStat(), _currentJitterBufferFrames(0), _timeGapStatsForStatsPacket(0, STATS_FOR_STATS_PACKET_WINDOW_SECONDS), - _repetitionWithFade(settings._repetitionWithFade), - _hasReverb(false) + _repetitionWithFade(settings._repetitionWithFade) { } @@ -163,22 +162,9 @@ int InboundAudioStream::parseData(const QByteArray& packet) { } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { - int read = 0; - if (type == PacketTypeMixedAudio) { - memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool)); - read += sizeof(bool); - - if (_hasReverb) { - memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float)); - read += sizeof(float); - } - } - // mixed audio packets do not have any info between the seq num and the audio data. - numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t); - return read; + numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t); + return 0; } int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 3e69db0afb..a395b1c6c8 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -154,10 +154,6 @@ public: int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); } - - bool hasReverb() const { return _hasReverb; } - float getRevebTime() const { return _reverbTime; } - float getWetLevel() const { return _wetLevel; } public slots: /// This function should be called every second for all the stats to function properly. If dynamic jitter buffers @@ -247,11 +243,6 @@ protected: MovingMinMaxAvg _timeGapStatsForStatsPacket; bool _repetitionWithFade; - - // Reverb properties - bool _hasReverb; - float _reverbTime; - float _wetLevel; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 166ee8c50e..7073280ee5 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_library(Gui Network Script Widgets) include_glm() -link_hifi_libraries(shared octree voxels fbx entities animation audio) +link_hifi_libraries(shared octree voxels fbx entities animation) # call macro to link our dependencies and bubble them up via a property on our target link_shared_dependencies() diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 660a6ec560..93da900055 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -278,9 +277,6 @@ void ScriptEngine::init() { QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); - - QScriptValue audioEffectOptionsConstructorValue = newFunction(AudioEffectOptions::constructor); - globalObject().setProperty("AudioEffectOptions", audioEffectOptionsConstructorValue); qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); qScriptRegisterMetaType(this, inputControllerToScriptValue, inputControllerFromScriptValue);