mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 17:54:00 +02:00
Merge pull request #3489 from Atlante45/radio_js
AudioInjector stereo fix
This commit is contained in:
commit
60d6a0bf0d
7 changed files with 50 additions and 20 deletions
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
|
||||
|
||||
var modelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/entities/radio/Speakers2Finished.fbx";
|
||||
var modelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/models/entities/radio/Speakers.fbx";
|
||||
var soundURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/FamilyStereo.raw";
|
||||
|
||||
var AudioRotationOffset = Quat.fromPitchYawRollDegrees(0, -90, 0);
|
||||
|
@ -20,7 +20,7 @@ audioOptions.loop = true;
|
|||
audioOptions.isStereo = true;
|
||||
var injector = null;
|
||||
|
||||
var sound = new Sound(soundURL);
|
||||
var sound = new Sound(soundURL, audioOptions.isStereo);
|
||||
|
||||
var entity = null;
|
||||
var properties = null;
|
||||
|
@ -31,14 +31,16 @@ function update() {
|
|||
print("Sound file downloaded");
|
||||
var position = Vec3.sum(MyAvatar.position,
|
||||
Vec3.multiplyQbyV(MyAvatar.orientation,
|
||||
{ x: 0, y: 0.3, z: -1 }));
|
||||
{ x: 0, y: -0.3, z: -2 }));
|
||||
var rotation = Quat.multiply(MyAvatar.orientation,
|
||||
Quat.fromPitchYawRollDegrees(0, -90, 0));
|
||||
entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
position: position,
|
||||
rotation: rotation,
|
||||
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
|
||||
dimensions: { x: 0.391,
|
||||
y: 1.000,
|
||||
z: 1.701 },
|
||||
modelURL: modelURL
|
||||
});
|
||||
properties = Entities.getEntityProperties(entity);
|
||||
|
|
|
@ -78,11 +78,13 @@ void AudioInjector::injectAudio() {
|
|||
|
||||
// pack the position for injected audio
|
||||
int positionOptionOffset = injectAudioPacket.size();
|
||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getPosition()), sizeof(_options.getPosition()));
|
||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getPosition()),
|
||||
sizeof(_options.getPosition()));
|
||||
|
||||
// pack our orientation for injected audio
|
||||
int orientationOptionOffset = injectAudioPacket.size();
|
||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getOrientation()), sizeof(_options.getOrientation()));
|
||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.getOrientation()),
|
||||
sizeof(_options.getOrientation()));
|
||||
|
||||
// pack zero for radius
|
||||
float radius = 0;
|
||||
|
@ -103,7 +105,7 @@ void AudioInjector::injectAudio() {
|
|||
quint16 outgoingInjectedAudioSequenceNumber = 0;
|
||||
while (_currentSendPosition < soundByteArray.size() && !_shouldStop) {
|
||||
|
||||
int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
|
||||
int bytesToCopy = std::min(((_options.isStereo()) ? 2 : 1) * NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL,
|
||||
soundByteArray.size() - _currentSendPosition);
|
||||
memcpy(injectAudioPacket.data() + positionOptionOffset,
|
||||
&_options.getPosition(),
|
||||
|
@ -116,10 +118,12 @@ void AudioInjector::injectAudio() {
|
|||
injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy);
|
||||
|
||||
// pack the sequence number
|
||||
memcpy(injectAudioPacket.data() + numPreSequenceNumberBytes, &outgoingInjectedAudioSequenceNumber, sizeof(quint16));
|
||||
memcpy(injectAudioPacket.data() + numPreSequenceNumberBytes,
|
||||
&outgoingInjectedAudioSequenceNumber, sizeof(quint16));
|
||||
|
||||
// copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet
|
||||
memcpy(injectAudioPacket.data() + numPreAudioDataBytes, soundByteArray.data() + _currentSendPosition, bytesToCopy);
|
||||
memcpy(injectAudioPacket.data() + numPreAudioDataBytes,
|
||||
soundByteArray.data() + _currentSendPosition, bytesToCopy);
|
||||
|
||||
// grab our audio mixer from the NodeList, if it exists
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions* injectorOptions) {
|
||||
|
||||
if (sound->isStereo()) {
|
||||
const_cast<AudioInjectorOptions*>(injectorOptions)->setIsStereo(true);
|
||||
}
|
||||
AudioInjector* injector = new AudioInjector(sound, *injectorOptions);
|
||||
|
||||
QThread* injectorThread = new QThread();
|
||||
|
|
|
@ -30,7 +30,9 @@ InjectedAudioStream::InjectedAudioStream(const QUuid& streamIdentifier, const In
|
|||
|
||||
const uchar MAX_INJECTOR_VOLUME = 255;
|
||||
|
||||
int InjectedAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) {
|
||||
int InjectedAudioStream::parseStreamProperties(PacketType type,
|
||||
const QByteArray& packetAfterSeqNum,
|
||||
int& numAudioSamples) {
|
||||
// setup a data stream to read from this packet
|
||||
QDataStream packetStream(packetAfterSeqNum);
|
||||
|
||||
|
@ -38,6 +40,9 @@ int InjectedAudioStream::parseStreamProperties(PacketType type, const QByteArray
|
|||
packetStream.skipRawData(NUM_BYTES_RFC4122_UUID);
|
||||
|
||||
packetStream >> _isStereo;
|
||||
if (isStereo()) {
|
||||
_ringBuffer.resizeForFrameSize(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO);
|
||||
}
|
||||
|
||||
// pull the loopback flag and set our boolean
|
||||
uchar shouldLoopback;
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
|
||||
// procedural audio version of Sound
|
||||
Sound::Sound(float volume, float frequency, float duration, float decay, QObject* parent) :
|
||||
QObject(parent)
|
||||
QObject(parent),
|
||||
_isStereo(false)
|
||||
{
|
||||
static char monoAudioData[MAX_PACKET_SIZE];
|
||||
static int16_t* monoAudioSamples = (int16_t*)(monoAudioData);
|
||||
|
@ -69,8 +70,9 @@ Sound::Sound(float volume, float frequency, float duration, float decay, QObject
|
|||
}
|
||||
}
|
||||
|
||||
Sound::Sound(const QUrl& sampleURL, QObject* parent) :
|
||||
Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) :
|
||||
QObject(parent),
|
||||
_isStereo(isStereo),
|
||||
_hasDownloaded(false)
|
||||
{
|
||||
// assume we have a QApplication or QCoreApplication instance and use the
|
||||
|
@ -82,12 +84,14 @@ Sound::Sound(const QUrl& sampleURL, QObject* parent) :
|
|||
|
||||
QNetworkReply* soundDownload = networkAccessManager.get(QNetworkRequest(sampleURL));
|
||||
connect(soundDownload, &QNetworkReply::finished, this, &Sound::replyFinished);
|
||||
connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
|
||||
connect(soundDownload, SIGNAL(error(QNetworkReply::NetworkError)),
|
||||
this, SLOT(replyError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
||||
Sound::Sound(const QByteArray byteArray, QObject* parent) :
|
||||
QObject(parent),
|
||||
_byteArray(byteArray),
|
||||
_isStereo(false),
|
||||
_hasDownloaded(true)
|
||||
{
|
||||
}
|
||||
|
@ -149,11 +153,20 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
|||
int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data();
|
||||
int16_t* destinationSamples = (int16_t*) _byteArray.data();
|
||||
|
||||
for (int i = 1; i < numSourceSamples; i += 2) {
|
||||
if (i + 1 >= numSourceSamples) {
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 2) + (sourceSamples[i] / 2);
|
||||
} else {
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 4) + (sourceSamples[i] / 2) + (sourceSamples[i + 1] / 4);
|
||||
|
||||
if (_isStereo) {
|
||||
for (int i = 0; i < numSourceSamples; i += 4) {
|
||||
destinationSamples[i / 2] = (sourceSamples[i] / 2) + (sourceSamples[i + 2] / 2);
|
||||
destinationSamples[(i / 2) + 1] = (sourceSamples[i + 1] / 2) + (sourceSamples[i + 3] / 2);
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < numSourceSamples; i += 2) {
|
||||
if (i + 1 >= numSourceSamples) {
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 2) + (sourceSamples[i] / 2);
|
||||
} else {
|
||||
destinationSamples[(i - 1) / 2] = (sourceSamples[i - 1] / 4) + (sourceSamples[i] / 2)
|
||||
+ (sourceSamples[i + 1] / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,17 +20,19 @@ class Sound : public QObject {
|
|||
|
||||
Q_PROPERTY(bool downloaded READ hasDownloaded)
|
||||
public:
|
||||
Sound(const QUrl& sampleURL, QObject* parent = NULL);
|
||||
Sound(const QUrl& sampleURL, bool isStereo = false, QObject* parent = NULL);
|
||||
Sound(float volume, float frequency, float duration, float decay, QObject* parent = NULL);
|
||||
Sound(const QByteArray byteArray, QObject* parent = NULL);
|
||||
void append(const QByteArray byteArray);
|
||||
|
||||
bool isStereo() const { return _isStereo; }
|
||||
bool hasDownloaded() const { return _hasDownloaded; }
|
||||
|
||||
const QByteArray& getByteArray() { return _byteArray; }
|
||||
|
||||
private:
|
||||
QByteArray _byteArray;
|
||||
bool _isStereo;
|
||||
bool _hasDownloaded;
|
||||
|
||||
void trimFrames();
|
||||
|
|
|
@ -48,7 +48,8 @@ EntityScriptingInterface ScriptEngine::_entityScriptingInterface;
|
|||
|
||||
static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
QUrl soundURL = QUrl(context->argument(0).toString());
|
||||
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL), QScriptEngine::ScriptOwnership);
|
||||
bool isStereo = context->argument(1).toBool();
|
||||
QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL, isStereo), QScriptEngine::ScriptOwnership);
|
||||
|
||||
return soundScriptValue;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue