mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-23 13:44:36 +02:00
change injector from cube to sphere
This commit is contained in:
parent
c55b6a20d7
commit
3f7fbb5c1e
6 changed files with 117 additions and 77 deletions
|
@ -160,68 +160,100 @@ int main(int argc, const char* argv[]) {
|
||||||
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||||
int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||||
|
|
||||||
|
bool insideSphericalInjector = false;
|
||||||
|
|
||||||
if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) {
|
if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) {
|
||||||
float distanceToAgent = sqrtf(powf(agentPosition.x - otherAgentPosition.x, 2) +
|
float distanceToAgent = glm::distance(agentPosition, otherAgentPosition);
|
||||||
powf(agentPosition.y - otherAgentPosition.y, 2) +
|
|
||||||
powf(agentPosition.z - otherAgentPosition.z, 2));
|
float minCoefficient = 1.0f;
|
||||||
|
|
||||||
|
if (otherAgentBuffer->getRadius() == 0 || distanceToAgent > otherAgentBuffer->getRadius()) {
|
||||||
|
// this is either not a spherical source, or the listener is outside the sphere
|
||||||
|
|
||||||
|
if (otherAgentBuffer->getRadius() > 0) {
|
||||||
|
// this is a spherical source - the distance used for the coefficient
|
||||||
|
// needs to be the closest point on the boundary to the source
|
||||||
|
|
||||||
|
// multiply the normalized vector between the center of the sphere
|
||||||
|
// and the position of the source by the radius to get the
|
||||||
|
// closest point on the boundary of the sphere to the source
|
||||||
|
glm::vec3 difference = agentPosition - otherAgentPosition;
|
||||||
|
glm::vec3 closestPoint = glm::normalize(difference) * otherAgentBuffer->getRadius();
|
||||||
|
|
||||||
|
// for the other calculations the agent position is the closest point on the sphere
|
||||||
|
otherAgentPosition = closestPoint;
|
||||||
|
|
||||||
|
// ovveride the distance to the agent with the distance to the point on the
|
||||||
|
// boundary of the sphere
|
||||||
|
distanceToAgent = glm::distance(agentPosition, closestPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the distance coefficient using the distance to this agent
|
||||||
|
minCoefficient = std::min(1.0f,
|
||||||
|
powf(0.3, (logf(DISTANCE_SCALE * distanceToAgent) /
|
||||||
|
logf(2.5)) - 1));
|
||||||
|
} else {
|
||||||
|
insideSphericalInjector = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float minCoefficient = std::min(1.0f,
|
|
||||||
powf(0.3,
|
|
||||||
(logf(DISTANCE_SCALE * distanceToAgent) / logf(2.5))
|
|
||||||
- 1));
|
|
||||||
distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient;
|
distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!insideSphericalInjector) {
|
||||||
// get the angle from the right-angle triangle
|
// off-axis attenuation and spatialization of audio is not performed
|
||||||
float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z),
|
// if the listener is inside a spherical injector
|
||||||
fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI);
|
|
||||||
float absoluteAngleToSource = 0;
|
// get the angle from the right-angle triangle
|
||||||
bearingRelativeAngleToSource = 0;
|
float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z),
|
||||||
|
fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI);
|
||||||
// find the angle we need for calculation based on the orientation of the triangle
|
float absoluteAngleToSource = 0;
|
||||||
if (otherAgentPosition.x > agentPosition.x) {
|
bearingRelativeAngleToSource = 0;
|
||||||
if (otherAgentPosition.z > agentPosition.z) {
|
|
||||||
absoluteAngleToSource = -90 + triangleAngle;
|
// find the angle we need for calculation based on the orientation of the triangle
|
||||||
|
if (otherAgentPosition.x > agentPosition.x) {
|
||||||
|
if (otherAgentPosition.z > agentPosition.z) {
|
||||||
|
absoluteAngleToSource = -90 + triangleAngle;
|
||||||
|
} else {
|
||||||
|
absoluteAngleToSource = -90 - triangleAngle;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
absoluteAngleToSource = -90 - triangleAngle;
|
if (otherAgentPosition.z > agentPosition.z) {
|
||||||
|
absoluteAngleToSource = 90 - triangleAngle;
|
||||||
|
} else {
|
||||||
|
absoluteAngleToSource = 90 + triangleAngle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (otherAgentPosition.z > agentPosition.z) {
|
bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing();
|
||||||
absoluteAngleToSource = 90 - triangleAngle;
|
|
||||||
} else {
|
if (bearingRelativeAngleToSource > 180) {
|
||||||
absoluteAngleToSource = 90 + triangleAngle;
|
bearingRelativeAngleToSource -= 360;
|
||||||
|
} else if (bearingRelativeAngleToSource < -180) {
|
||||||
|
bearingRelativeAngleToSource += 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing();
|
||||||
|
|
||||||
|
if (angleOfDelivery > 180) {
|
||||||
|
angleOfDelivery -= 360;
|
||||||
|
} else if (angleOfDelivery < -180) {
|
||||||
|
angleOfDelivery += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
|
||||||
|
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f));
|
||||||
|
|
||||||
|
attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex]
|
||||||
|
* otherAgentBuffer->getAttenuationRatio()
|
||||||
|
* offAxisCoefficient;
|
||||||
|
|
||||||
|
bearingRelativeAngleToSource *= (M_PI / 180);
|
||||||
|
|
||||||
|
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
|
||||||
|
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||||
|
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing();
|
|
||||||
|
|
||||||
if (bearingRelativeAngleToSource > 180) {
|
|
||||||
bearingRelativeAngleToSource -= 360;
|
|
||||||
} else if (bearingRelativeAngleToSource < -180) {
|
|
||||||
bearingRelativeAngleToSource += 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing();
|
|
||||||
|
|
||||||
if (angleOfDelivery > 180) {
|
|
||||||
angleOfDelivery -= 360;
|
|
||||||
} else if (angleOfDelivery < -180) {
|
|
||||||
angleOfDelivery += 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
|
|
||||||
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f));
|
|
||||||
|
|
||||||
attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex]
|
|
||||||
* otherAgentBuffer->getAttenuationRatio()
|
|
||||||
* offAxisCoefficient;
|
|
||||||
|
|
||||||
bearingRelativeAngleToSource *= (M_PI / 180);
|
|
||||||
|
|
||||||
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
|
|
||||||
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
|
||||||
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f
|
int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f
|
||||||
|
|
|
@ -36,25 +36,25 @@ const char *allowedParameters = ":rb::t::c::a::f::d::s:";
|
||||||
float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
unsigned char volume = DEFAULT_INJECTOR_VOLUME;
|
unsigned char volume = DEFAULT_INJECTOR_VOLUME;
|
||||||
float triggerDistance = 0.0f;
|
float triggerDistance = 0.0f;
|
||||||
float cubeSideLength = 0.0f;
|
float radius = 0.0f;
|
||||||
|
|
||||||
void usage(void) {
|
void usage(void) {
|
||||||
std::cout << "High Fidelity - Interface audio injector" << std::endl;
|
std::cout << "High Fidelity - Interface audio injector" << std::endl;
|
||||||
std::cout << " -r Random sleep mode. If not specified will default to constant loop." << std::endl;
|
std::cout << " -s Random sleep mode. If not specified will default to constant loop." << std::endl;
|
||||||
std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl;
|
std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl;
|
||||||
std::cout << " -t FLOAT Max. number of seconds to sleep. Only valid in random sleep mode. Default 2.0" << std::endl;
|
std::cout << " -t FLOAT Max. number of seconds to sleep. Only valid in random sleep mode. Default 2.0" << std::endl;
|
||||||
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
|
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
|
||||||
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
|
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
|
||||||
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
|
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
|
||||||
std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl;
|
std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl;
|
||||||
std::cout << " -s FLOAT Length of side of cube audio source. If not specified injected audio is point source" << std::endl;
|
std::cout << " -r FLOAT Radius for spherical source. If not specified injected audio is point source" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool processParameters(int parameterCount, char* parameterData[]) {
|
bool processParameters(int parameterCount, char* parameterData[]) {
|
||||||
int p;
|
int p;
|
||||||
while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) {
|
while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) {
|
||||||
switch (p) {
|
switch (p) {
|
||||||
case 'r':
|
case 's':
|
||||||
::loopAudio = false;
|
::loopAudio = false;
|
||||||
std::cout << "[DEBUG] Random sleep mode enabled" << std::endl;
|
std::cout << "[DEBUG] Random sleep mode enabled" << std::endl;
|
||||||
break;
|
break;
|
||||||
|
@ -94,9 +94,9 @@ bool processParameters(int parameterCount, char* parameterData[]) {
|
||||||
::triggerDistance = atof(optarg);
|
::triggerDistance = atof(optarg);
|
||||||
std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl;
|
std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 'r':
|
||||||
::cubeSideLength = atof(optarg);
|
::radius = atof(optarg);
|
||||||
std::cout << "[DEBUG] Cube side length: " << optarg << std::endl;
|
std::cout << "[DEBUG] Injector radius: " << optarg << std::endl;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
@ -170,9 +170,9 @@ int main(int argc, char* argv[]) {
|
||||||
injector.setBearing(*(::floatArguments + 3));
|
injector.setBearing(*(::floatArguments + 3));
|
||||||
injector.setVolume(::volume);
|
injector.setVolume(::volume);
|
||||||
|
|
||||||
if (::cubeSideLength > 0) {
|
if (::radius > 0) {
|
||||||
// if we were passed a cube side length, give that to the injector
|
// if we were passed a cube side length, give that to the injector
|
||||||
injector.setCubeSideLength(::cubeSideLength);
|
injector.setRadius(::radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the callback for agent data creation
|
// register the callback for agent data creation
|
||||||
|
|
|
@ -19,7 +19,7 @@ const int MAX_INJECTOR_VOLUME = 0xFF;
|
||||||
|
|
||||||
AudioInjector::AudioInjector(const char* filename) :
|
AudioInjector::AudioInjector(const char* filename) :
|
||||||
_position(),
|
_position(),
|
||||||
_cubeSideLength(0.0f),
|
_radius(0.0f),
|
||||||
_bearing(0),
|
_bearing(0),
|
||||||
_volume(MAX_INJECTOR_VOLUME),
|
_volume(MAX_INJECTOR_VOLUME),
|
||||||
_indexOfNextSlot(0),
|
_indexOfNextSlot(0),
|
||||||
|
@ -49,7 +49,7 @@ AudioInjector::AudioInjector(const char* filename) :
|
||||||
AudioInjector::AudioInjector(int maxNumSamples) :
|
AudioInjector::AudioInjector(int maxNumSamples) :
|
||||||
_numTotalSamples(maxNumSamples),
|
_numTotalSamples(maxNumSamples),
|
||||||
_position(),
|
_position(),
|
||||||
_cubeSideLength(0.0f),
|
_radius(0.0f),
|
||||||
_bearing(0),
|
_bearing(0),
|
||||||
_volume(MAX_INJECTOR_VOLUME),
|
_volume(MAX_INJECTOR_VOLUME),
|
||||||
_indexOfNextSlot(0),
|
_indexOfNextSlot(0),
|
||||||
|
@ -72,13 +72,19 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
|
||||||
timeval startTime;
|
timeval startTime;
|
||||||
|
|
||||||
// calculate the number of bytes required for additional data
|
// calculate the number of bytes required for additional data
|
||||||
int leadingBytes = sizeof(PACKET_HEADER) + sizeof(_streamIdentifier)
|
int leadingBytes = sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND) + sizeof(_streamIdentifier)
|
||||||
+ sizeof(_position) + sizeof(_bearing) + sizeof(_volume);
|
+ sizeof(_position) + sizeof(_bearing) + sizeof(_volume);
|
||||||
|
|
||||||
|
if (_radius > 0) {
|
||||||
|
// we'll need 4 extra bytes if the cube side length is being sent as well
|
||||||
|
leadingBytes += sizeof(_radius);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
|
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
|
||||||
|
|
||||||
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
|
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
|
||||||
// add the correct command for point source or cube of sound
|
// add the correct command for point source or cube of sound
|
||||||
dataPacket[1] = (_cubeSideLength > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND;
|
dataPacket[1] = (_radius > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND;
|
||||||
unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND);
|
unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND);
|
||||||
|
|
||||||
// copy the identifier for this injector
|
// copy the identifier for this injector
|
||||||
|
@ -88,11 +94,11 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
|
||||||
memcpy(currentPacketPtr, &_position, sizeof(_position));
|
memcpy(currentPacketPtr, &_position, sizeof(_position));
|
||||||
currentPacketPtr += sizeof(_position);
|
currentPacketPtr += sizeof(_position);
|
||||||
|
|
||||||
if (_cubeSideLength > 0) {
|
if (_radius > 0) {
|
||||||
// if we have a cube half height we need to send it here
|
// if we have a cube half height we need to send it here
|
||||||
// this tells the mixer how much volume the injected audio will occupy
|
// this tells the mixer how much volume the injected audio will occupy
|
||||||
memcpy(currentPacketPtr, &_cubeSideLength, sizeof(_cubeSideLength));
|
memcpy(currentPacketPtr, &_radius, sizeof(_radius));
|
||||||
currentPacketPtr += sizeof(_cubeSideLength);
|
currentPacketPtr += sizeof(_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
*currentPacketPtr = _volume;
|
*currentPacketPtr = _volume;
|
||||||
|
|
|
@ -39,8 +39,8 @@ public:
|
||||||
float getBearing() const { return _bearing; }
|
float getBearing() const { return _bearing; }
|
||||||
void setBearing(float bearing) { _bearing = bearing; }
|
void setBearing(float bearing) { _bearing = bearing; }
|
||||||
|
|
||||||
float getCubeSideLength() const { return _cubeSideLength; }
|
float getRadius() const { return _radius; }
|
||||||
void setCubeSideLength(float cubeSideLength) { _cubeSideLength = cubeSideLength; }
|
void setRadius(float radius) { _radius = radius; }
|
||||||
|
|
||||||
void addSample(const int16_t sample);
|
void addSample(const int16_t sample);
|
||||||
void addSamples(int16_t* sampleBuffer, int numSamples);
|
void addSamples(int16_t* sampleBuffer, int numSamples);
|
||||||
|
@ -49,7 +49,7 @@ private:
|
||||||
int16_t* _audioSampleArray;
|
int16_t* _audioSampleArray;
|
||||||
int _numTotalSamples;
|
int _numTotalSamples;
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
float _cubeSideLength;
|
float _radius;
|
||||||
float _bearing;
|
float _bearing;
|
||||||
unsigned char _volume;
|
unsigned char _volume;
|
||||||
int _indexOfNextSlot;
|
int _indexOfNextSlot;
|
||||||
|
|
|
@ -17,7 +17,7 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) :
|
||||||
AgentData(NULL),
|
AgentData(NULL),
|
||||||
_ringBufferLengthSamples(ringSamples),
|
_ringBufferLengthSamples(ringSamples),
|
||||||
_bufferLengthSamples(bufferSamples),
|
_bufferLengthSamples(bufferSamples),
|
||||||
_cubeSideLength(0.0f),
|
_radius(0.0f),
|
||||||
_endOfLastWrite(NULL),
|
_endOfLastWrite(NULL),
|
||||||
_started(false),
|
_started(false),
|
||||||
_shouldBeAddedToMix(false),
|
_shouldBeAddedToMix(false),
|
||||||
|
@ -53,13 +53,13 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&_position, dataBuffer, sizeof(_position));
|
memcpy(&_position, dataBuffer, sizeof(_position));
|
||||||
dataBuffer += (sizeof(_position));
|
dataBuffer += sizeof(_position);
|
||||||
|
|
||||||
if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO && sourceBuffer[1] == INJECT_AUDIO_AT_CUBE_COMMAND) {
|
if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO && sourceBuffer[1] == INJECT_AUDIO_AT_CUBE_COMMAND) {
|
||||||
// this is audio that needs to be injected as a volume (cube)
|
// this is audio that needs to be injected as a volume (cube)
|
||||||
// parse out the cubeHalfHeight sent by the client
|
// parse out the cubeHalfHeight sent by the client
|
||||||
memcpy(&_cubeSideLength, dataBuffer, sizeof(_cubeSideLength));
|
memcpy(&_radius, dataBuffer, sizeof(_radius));
|
||||||
dataBuffer += (sizeof(_cubeSideLength));
|
dataBuffer += sizeof(_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int attenuationByte = *(dataBuffer++);
|
unsigned int attenuationByte = *(dataBuffer++);
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
~AudioRingBuffer();
|
~AudioRingBuffer();
|
||||||
|
|
||||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||||
|
|
||||||
|
float getRadius() const { return _radius; }
|
||||||
|
|
||||||
int16_t* getNextOutput() const { return _nextOutput; }
|
int16_t* getNextOutput() const { return _nextOutput; }
|
||||||
void setNextOutput(int16_t* nextOutput) { _nextOutput = nextOutput; }
|
void setNextOutput(int16_t* nextOutput) { _nextOutput = nextOutput; }
|
||||||
|
@ -56,7 +58,7 @@ private:
|
||||||
int _ringBufferLengthSamples;
|
int _ringBufferLengthSamples;
|
||||||
int _bufferLengthSamples;
|
int _bufferLengthSamples;
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
float _cubeSideLength;
|
float _radius;
|
||||||
float _attenuationRatio;
|
float _attenuationRatio;
|
||||||
float _bearing;
|
float _bearing;
|
||||||
int16_t* _nextOutput;
|
int16_t* _nextOutput;
|
||||||
|
|
Loading…
Reference in a new issue